we have existing encryption code in java and which is working absolutely fine.I am trying to create same encryption method in .net which is failing java decryption method saying bad padding exception. See the code details below:
Working Java Code:
Encryption:
private static byte[] doThis(String message) {
byte[] messageCrypte = null;
try {
// Certificate Input Stream
// LA SSL Certificate to be passed.
InputStream inStream = new FileInputStream(certificate);
// X509Certificate created
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
inStream.close();
// Getting Public key using Certficate
PublicKey rsaPublicKey = (PublicKey) cert.getPublicKey();
Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "SunJCE");
encryptCipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
byte[] messageACrypter = message.getBytes();
// Encrypted String
messageCrypte = encryptCipher.doFinal(messageACrypter);
} catch (Exception e) {
// TODO: Exception Handling
e.printStackTrace();
}
return messageCrypte;
}
Equivalent c# .Net code I am trying to use but I am getting bad padding exception form java decryption code.
static byte[] doThis(string message)
{
X509Certificate cert = new X509Certificate(#"C:\Data\abc-rsa-public-key-certificate.cer");
byte[] aa = cert.GetPublicKey();
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
byte[] Exponent = { 1, 0, 1 };
RSAKeyInfo = RSA.ExportParameters(false);
//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = aa;
//RSAKeyInfo.Exponent = Exponent;
RSA.ImportParameters(RSAKeyInfo);
byte[] bb = RSA.Encrypt(GetBytes(message), false);
return bb;
}
Java code for decryption
private String getDecryptedString(byte[] credentials, PrivateKey secretKey) throws NoSuchAlgorithmException,
NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException {
String decryptedString;
Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "SunJCE");
decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] messageDecrypte = decryptCipher.doFinal(credentials);
decryptedString = new String(messageDecrypte);
return decryptedString;
}
Here is the .net code:
public static string EncrypIt(string inputString, X509Certificate2 cert)
{
RSACryptoServiceProvider rsaservice = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] plaintext = Encoding.UTF8.GetBytes(inputString);
byte[] ciphertext = rsaservice.Encrypt(plaintext, false);
string cipherresult = Convert.ToBase64String(ciphertext);
return cipherresult;
}
Related
I am developing the post data request in c# and using AES GCM encryption and RSA encryption. As compared to the C# code with Node.js / Python for encryption, we found that C# AES GCM encryption does not have tag value in the method.
e.g How do I return below data in C# after encryption.
return {
key: aesKey,
cipher_text: encrypted,
tag,
iv
}
In Python and Node.js using JsEncrypt, forge.js.... and implementations are working fine. But, now developing the same client in the C#, do not find such libraries which I can use directly.
However, I found two classes in C# AesGcm and AesManaged for AES Encryption. But I think AesManages is only for AES not GCM encryption. Therefore, I am using AesGcm class in below example, but not sure.
The code executes the following steps:
Request client certificate from DSG.
Extract the public key from the certificate.
Encrypt PII with AES key.
Encrypt AES key with RSA public key.
Send wrapped key and PII payload to DSG tokenization.
class Program
{
static void Main(string[] args)
{
string _ApiKey = "--- YOUR API KEY ----";
string _SecretKey = " ---- YOUR SECRET KEY --------";
string jsonPlainText = "<JSON TExT>";
#region Certificate
string certificate = GetCertificate();
Certificate rawSigningCert = JsonConvert.DescrializeObject<Certificate>(certificate);
var certBytes = Encoding.UTF8.GetBytes(rawSigningCert.crt);
// X509Certificate2
var x509Certificate2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certBytes);
byte[] publicKey = x509Certificate2.GetPublicKey();
#endregion
#region AES GCM Encryption
byte[] aesGcmKey = new byte[16];
RandomNumberGenerator.Fill(aesGcmKey);
byte[] nonce = new byte[12];
RandomNumberGenerator.Fill(nonce);
byte[] tag = new byte[16];
byte[] dataToEncrypt = Encoding.UTF8.GetBytes(jsonPlainText);
byte[] cipherText = new byte[dataToEncrypt.Length];
using (AesGcm aesGcm = new AesGcm(aesGcmKey))
{
aesGcm.Encrypt(nonce, dataToEncrypt, cipherText, tag);
}
string encryptedCipher = Convert.ToBase64String(cipherText);
var keyString = Convert.ToBase64String(aesGcmKey);
var iVString = Convert.ToBase64String(nonce);
var tagString = Convert.ToBase64String(tag);
string aesGcmEncryptionString = string.Format("{0}:{1}:{2}", keyString, iVString, tagString);
#endregion
#region RSA Encryption
var rsa = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = rsa.ExportParameters(false);
RSAKeyInfo.Modulus = publicKey;
rsa.ImportParameters(RSAKeyInfo);
byte[] encryptedSymmetricKey = RSAEncrypt(Encoding.UTF8.GetBytes(aesGcmEncryptionString), RSAKeyInfo, false);
var enc_key = Convert.ToBase64String(encryptedSymmetricKey);
var requestBodyObject = new { message = encryptedCipher, enckey = enc_key };
string jsonRequestBody = JsonConvert.SerializeObject(requestBodyObject);
#endregion
#region Calculating Message Signature
Random random = new Random();
int ClientRequestId = random.Next(0, 99999999);
var time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
var rawSignature = _ApiKey + ClientRequestId + time + jsonRequestBody;
HMACSHA256 hashObject = new HMACSHA256(Encoding.UTF8.GetBytes(_SecretKey));
var signature = hashObject.ComputeHash(Encoding.UTF8.GetBytes(rawSignature));
var computedHmac = Convert.ToBase64String(signature);
#endregion
#region Make Request
try
{
var client = new RestClient("< API URL>");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("contentType", "application/json");
request.AddHeader("clientRequestId", ClientRequestId.ToString());
request.AddHeader("apiKey", _ApiKey);
request.AddHeader("timestamp", time.Tostring);
request.AddHeader("messageSignature", computedHmac);
request.AddJsonBody(jsonRequestBody);
request.RequestFormat = DataFormat.Json;
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
#endregion
}
static string GetCertificate()
{
string cer = string.Empty;
// Code to get certicate .crt from the service.
//"<GET CERTICATE HERE>";
return cer;
}
static public byte[] RSAEncrpt(byte[] data, RSAParameters keyInfo, bool doOAEPPadding)
{
byte[] encryptedData;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(keyInfo);
encryptedData = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);
}
return encryptedData;
}
}
class Certificate
{
public string crt { get; set; }
}
How I can trace each steps as service is responding with incorrect message signature. Any way to verify and trace the above code steps?
Help!
Thanks in advance
I'm working on encrypt/decrypt request/response on both angular 6 and .net core api side. I'm encrypting data in angular using AES and encrypting AES key using RSA public key and sending it to .net core api. I have created action filter to decrypt the request, and to decrypt the request first I have to decrypt the AES key using RSA private key but it is giving me an error while decrypting AES key using RSA private key:
ex {Org.BouncyCastle.Crypto.InvalidCipherTextException: block incorrect
at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(Byte[] input, Int32 inOff, Int32 inLen)
at Phyzii.Core.Api.Security.RSA.Decrypt(String cipherText)} System.Exception {Org.BouncyCastle.Crypto.InvalidCipherTextException}
Here is my RSA encryption code at angular side:
import JSEncrypt from 'jsencrypt';
encryptObj = new JSEncrypt();
transitionIn(data: any) {
this.aesSecretKey=this.makeUniqueKey(10);
console.log(this.aesSecretKey);
this.data.DATAOBJ = this.aesEncrypt(this.aesSecretKey, data);
this.encryptObj.setPublicKey(this.publicKeyClient);
this.data.KEY = this.encryptObj.encrypt(this.aesSecretKey);
return this.data;
}
Here is my RSA decryption code at C# side:
private static AsymmetricCipherKeyPair ReadPemFile(string flag)
{
string filePath = flag == "PUBLIC" ? "D:/Crypto/private_key.pem" : "D:/Crypto/private_key_server.pem";
AsymmetricCipherKeyPair keys;
using (var reader = File.OpenText(filePath))// file containing RSA PKCS1 private key
keys = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
AsymmetricKeyParameter private_key = keys.Private;
AsymmetricKeyParameter public_key = keys.Public;
return keys;
}
//cipherText = "gOItOryuGy0UXHfoNqo0omcXLIOS6dhLJas5zeDNA7MfvsHYwP4ccSWU9JwTrIRiYUq/NB9oRn62ZQ5ynDnsGXUmHfVT4oPxtQZE1fXTTMN5ycfgthegesmXoZMMcWxA/wnwjLAgE17MNaunKY307W+nyc3jEMT1QsWUoOBESo0="
public static string Decrypt(string cipherText)
{
try
{
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
AsymmetricCipherKeyPair keys = ReadPemFile("PRIVATE");
AsymmetricKeyParameter private_key = keys.Private;
// Pure mathematical RSA implementation
// RsaEngine eng = new RsaEngine();
// PKCS1 v1.5 paddings
// Pkcs1Encoding eng = new Pkcs1Encoding(new RsaEngine());
// PKCS1 OAEP paddings
Pkcs1Encoding eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false, private_key);
int length = cipherTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
List<byte> plainTextBytes = new List<byte>();
for (int chunkPosition = 0; chunkPosition < length; chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
plainTextBytes.AddRange(eng.ProcessBlock(cipherTextBytes, chunkPosition, chunkSize));
}
return Encoding.UTF8.GetString(plainTextBytes.ToArray());
}
catch (Exception ex)
{
throw ex;
}
}
and If i set true in Pkcs1Encoding Init
Pkcs1Encoding eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(true, private_key);
Then it is decrypting data in this format �����Ŧ���%�Rc��\u000e�\b\u0004����I�]&P~�+�뛡�^s�V�ʗ' \b��?Jv�F�ge\u001b�S���^�\u0002��v/|�vh�}�z�[A�}��\u0002u\\�Pp����\u0011k9\u001e\n�E\b�\u0003��\u001a#��}��y��\u000eTG�U\a�A_KV�\u007fs����?3���*/*\n\n~�w�Q��'��\a:���q��BH\u0004R�#c��'d�\u001f���\0 5\u007f���fs�<���\u0012\t����|�[\u0015\b+��8\u0003�[�v����Ǹ��8ځ\u001cԞv�{=���#-o\u0004�I\u0014J�\0#4`
which is incorrect,
what can be the issue?
The problem is the following:
I generate the key in Android (Xamarin.Droid):
public IPublicKey CreateKey(string keyID)
{
/*KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
keyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(
"key1",
KeyProperties.PURPOSE_SIGN)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
.build());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
Signature signature = Signature.getInstance("SHA256withRSA/PSS");
signature.initSign(keyPair.getPrivate());
// The key pair can also be obtained from the Android Keystore any time as follows:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
PrivateKey privateKey = (PrivateKey)keyStore.getKey("key1", null);
PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey();*/
//App.Current.MainPage.DisplayAlert("Info", "Creating a new key pair", "Ok");
// UTILIZANDO RSA
KeyPairGenerator kpg =
KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, KEYSTORE_NAME);
kpg.Initialize(
new KeyGenParameterSpec.Builder(keyID,
KeyStorePurpose.Sign)
.SetSignaturePaddings(KeyProperties.SignaturePaddingRsaPss)
.SetDigests(KeyProperties.DigestSha1)
.Build()
);
KeyPair keyPair = kpg.GenerateKeyPair();
Log.Debug(TAG, "New key created for fingerprint authentication");
return keyPair.Public;
}
Then i generate a signature:
KeyStore.PrivateKeyEntry PKentry =
(KeyStore.PrivateKeyEntry)_keystore.GetEntry(keyID, null);
IPublicKey pk = (IPublicKey)PKentry.Certificate.PublicKey;
//this.pk = pk;
privKey = PKentry.PrivateKey;
//cipher.Init(Cipher.EncryptMode, privKey);
//byte[] output = cipher.DoFinal(Encoding.UTF8.GetBytes(input));
//String s = new string(cipher.DoFinal(input));
// signature
Signature sig = Signature.GetInstance("SHA1withRSA/PSS");
sig.InitSign(privKey);
byte[] inputDataToSign = Encoding.UTF8.GetBytes(input);
sig.Update(inputDataToSign);
byte[] signatureBytes = sig.Sign();
And i send the key and the signature to a ASP.net wep API 2 server.
Client side response generation:
RegistrationResponse registrationResponse = new RegistrationResponse();
string fcparams = Utils.Base64Encode(JsonConvert.SerializeObject(finalChallengeParams));
registrationResponse.fcParams = fcparams;
byte[] signedData = sign(fcparams, registrationRequest.username, facetID);
registrationResponse.signedData = signedData;
registrationResponse.Base64key = convertPublicKeyToString(publicKey);
...
...
private string convertPublicKeyToString(IPublicKey publicKey)
{
string publicKeyString = Base64.EncodeToString(publicKey.GetEncoded(), 0);
return publicKeyString;
}
I send it using Refit Nugget.
And this is the code i use when i receive the HTTPRequest on server side:
[Route("regResponse/")]
[HttpPost]
public IHttpActionResult ProcessClientRegistrationResponse([FromBody] RegistrationResponse registrationResponse)
{
//byte[] publicKeyBytes = Convert.FromBase64String(registrationResponse.Base64key);
byte[] publicKeyBytes = registrationResponse.Base64key;
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
/*****/
string alg = rsa.SignatureAlgorithm;
byte[] signedData = registrationResponse.signedData;
byte[] fcParamsBytes = Encoding.UTF8.GetBytes(registrationResponse.fcParams);
RSACng rsaCng = new RSACng();
rsaCng.ImportParameters(rsaParameters);
SHA1Managed hash = new SHA1Managed();
byte[] hashedData;
hashedData = hash.ComputeHash(signedData);
/*********/
bool rsaCngDataOk1 = rsaCng.VerifyData(fcParamsBytes, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
bool rsaCngDataOk2 = rsaCng.VerifyData(fcParamsBytes, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
bool rsaCngDataOk3 = rsaCng.VerifyData(hashedData, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
bool rsaCngDataOk4 = rsaCng.VerifyData(hashedData, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
bool rsaCngHashOk1 = rsaCng.VerifyHash(hashedData, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pss);
bool dataOK1 = rsa.VerifyData(fcParamsBytes, new SHA1CryptoServiceProvider(), signedData);
bool dataOk2 = rsa.VerifyData(fcParamsBytes, signedData, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
bool hashOk = rsa.VerifyHash(hashedData, CryptoConfig.MapNameToOID("SHA1"), signedData);
return Ok(true);
}
EVERY bool is wrong. I think the problem is clearly on the public key.
The questions are,
does the method publickey.encode() do what i think? I think it converts my public key to a byte[] representation (source: Android developer Key Info)
do i convert the received byte[] representation of the key to a correct RSA key?
Is there any problem on algorithms? I don't think so but we never know...
I don't find the solution. I searched for ways to import public keys from strings in .net or c# and for ways to export Android Public key to string or byte[] but there's no much help for this concrete questions...
#James K Polk gave me the solution.
Apparently C# doesn't work well with PSS padding. I just had to change it to PKCS1. And i changed to digest algorithm too to SHA512.
I am trying to implement hybrid cryptosystem as mentioned in https://en.wikipedia.org/wiki/Hybrid_cryptosystem
At the moment I have implemented following algorithm
private void button1_Click(object sender, EventArgs e)
{
CspParameters cspParams = new CspParameters { ProviderType = 1 };
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(1024, cspParams);
string publicKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(false));
string privateKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(true));
string symmericKey = "Kamran12";
txtEncryptedData.Text = EncryptData(txtInputData.Text, symmericKey);
string encryptedsymmetrickey = EncryptData(symmericKey, publicKey); //error line
//string decryptsymmetrickey = encryptedsymmetrickey + privateKey;
//string decrypteddata = encryptedData + decryptsymmetrickey;
}
public string EncryptData(string data, string key)
{
string encryptedData = null;
byte[] buffer = Encoding.UTF8.GetBytes(data);
DESCryptoServiceProvider desCryptSrvckey = new DESCryptoServiceProvider
{
Key = new UTF8Encoding().GetBytes(key)
};
desCryptSrvckey.IV = desCryptSrvckey.Key;
using (MemoryStream stmCipherText = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(stmCipherText, desCryptSrvckey.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
cs.FlushFinalBlock();
encryptedData = Encoding.UTF8.GetString(stmCipherText.ToArray());
}
}
return encryptedData;
}
But getting error Specified key is not a valid size for this algorithm. at the time of encrypting the symmetric key
You are trying to encrypt using the (insecure) DES algorithm with an RSA public key. That's always going to fail, DESCryptoServiceProvider doesn't accept RSA keys. You'd need an RSACryptoServiceProvider for that.
You may want to consider using a specific library that already implements hybrid cryptography (PGP, CMS or one of the proprietary protocols). The way you are going at it your solution may run in the end, but it will not be secure.
I am trying to encrypt strings in .NET by using a RSA algorithm and decrypt the result in Java. At the moment, I have been able to do the opposite (Encrypt in Java, Decrypt in .NET).
Here I have my code that actually works (JAVA encryption):
byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String("big kitty dancing").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal( plainBytes );
String encryptedString = Base64.encode(cipherData);
return encryptedString;
And (.NET decryption)
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==</P><Q>yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==</Q><DP>ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==</DP><DQ>dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==</DQ><InverseQ>YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==</InverseQ><D>g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE=</D></RSAKeyValue>");
string data2Decrypt = "BaB21vY+RD/jiY3AAsb269fIWTEH38s0xLUfJ7CoVUgaQ6vYzB0tiJ1Ag9HNEdCcuZdGchhqnms8jpsqsHC1iKrz6QCLsgUU7VNWDfQqZYR6Rl/GwR0biK2STnOL+g06f/JUdixHOHOgROify1m8qppYo5plpOVMqYFzEMREMkM=";
byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt);
byte[] plain = rsa1.Decrypt(encyrptedBytes, false);
string decryptedString = System.Text.Encoding.UTF8.GetString(plain);
Console.WriteLine("SALIDA: " + decryptedString);
Now I want to do the opposite... But I get some errors like (the size of the key should be 128 bytes... etc) How should I do it?
Here I add the current non working code:
.NET
public string Encrypt(string text)
{
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>92jJJyzFBSx6gL4Y1YpALmc5CNjoE/wETjqb3ci2v0+3rZWvJKmKy1ZEdlXpyuvXVksJ6cMdUpNAkMknUk9pTQ==</P><Q>4kxkABZOXyDLryYGCGY0b8N0FIdu5BTCFDYEdcatxl/f7ZGDS1NgHJpUWxkVXFfHy2Y/GuDOIbpcwlsO739H+w==</Q><DP>5bNFvrdUHF+VRN45VFjNCcgQLeSkY5mBrdfASoNFGA29LM5iE5nNIMfxPCS7sQiRnq6Af6YFHVtVgJchiMvtqQ==</DP><DQ>j+ng1qVY5epnXlWiFIla45C7K6sNfIMvAcdwgq39KWEjeWPGyYqWXtpOtzh2eylf6Bx4GVHKBW0NPJTIJMsfLQ==</DQ><InverseQ>8uu0dfPVDqB2qFM1Vdi8hl+2uZtN7gjT2co1cEWy29HVYBZD0k9KKCf2PbkeuSfpgFpE70wW5Hrp8V7l/SwSOw==</InverseQ><D>MM/c18zroJ2Iqi9s5/asvUBF3pjO3NSEbFjFpP/NT6WdKimvECWPz2xT6NlV0Vc6tQaAAmtn7Bt+HPhfVdrA4/ysYVe3/6TWkPjW+bvAhMWu/ZqISx11/jPYSGD9g3ZXgUiqcQM8UbOjlswoq4fpheEXTB0xdVutDLpO3qgHN6k=</D></RSAKeyValue>");
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] textBytes = encoding.GetBytes(text);
byte[] encryptedOutput = rsa1.Encrypt(textBytes, false);
string outputB64 = Convert.ToBase64String(encryptedOutput);
Console.WriteLine(outputB64);
return outputB64;
}
Java
public static String Decrypt(String encodedString) throws IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException
{
byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec rsaPrivKey = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(rsaPrivKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
System.out.println(cipherData);
return cipherData.toString();
}
The last few lines of your Java decrypt code do not make sense. These lines are:
byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
System.out.println(cipherData);
return cipherData.toString();
You have to reverse the order of the steps you used to encrypt in .NET. First, you should Base64 decode the encoded string to get the cipher bytes. You did that, but you mislabeled the result as base64String. You probably should call this result cipherData. Second, you need to decrypt cipherData to get plain text. Third, you should create a string from plainbytes using the two-arg String constructor with the Charset for the second argument. Here is what the code should look like, or close to it.
byte[] cipherData = Base64.decode(encodedString);
byte[] plainBytes = cipher.doFinal(cipherData);
return new String(plainBytes, "UTF-8");
Finally, in Java every object has a toString() method but it doesn't always do what you want. For arrays the toString() method simply returns a representation of object id for that array, sort of the JVM equivalent of a memory address.
EDIT:
I missed that you are also using the wrong key in your decrypt code. Your are using the RSA public key, but you must instead use the RSA private key.
Here is the answer I couldn't post yesterday, related to the first answer to my post.
Well, I have tested the code and I have some problems. I have tried not to change anything unless it was completely necessary.
First I get an error here:
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
The "Entrust" crypto provider is not recognized... So I left just the first parameter. Then I get this error:
javax.crypto.BadPaddingException: Data must start with zero
I have tried through a WebService written in .NET which returns always byte arrays. Maybe there is some kind of problem in the translation. I know that I have to use Base64 numbers and (if I don't use AES) I have to break my Strings into pieces with the size of 128 bytes (limited by the RSA key).
I am still working on the problem to realize why I could encrypt in Java and decrypt in .NET but not the opposite.
Thanks again for your help!!
As you requested are hare some code snippets. RSA keys are from x509 certs.
Java RSA/AES:
// symmetric algorithm for data encryption
final String ALGORITHM = "AES";
// Padding for symmetric algorithm
final String PADDING_MODE = "/CBC/PKCS5Padding";
// character encoding
final String CHAR_ENCODING = "UTF-8";
// provider for the crypto
final String CRYPTO_PROVIDER = "Entrust";
// RSA algorithm used to encrypt symmetric key
final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
// symmetric key size (128, 192, 256) if using 192+ you must have the Java
// Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
// installed
int AES_KEY_SIZE = 256;
private byte[] encryptWithRSA(byte[] aesKey, X509Certificate cert)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// get the public key from the encryption certificate to encrypt with
PublicKey pubKey = cert.getPublicKey();
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
// set the cipher to use the public key
rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);
// encrypt the aesKey
return rsaCipher.doFinal(aesKey);
}
private AESEncryptedContents encryptWithAes(byte[] dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchProviderException {
// get the symmetric key generator
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
keyGen.init(AES_KEY_SIZE); // set the key size
// generate the key
SecretKey skey = keyGen.generateKey();
// convert to binary
byte[] rawAesKey = skey.getEncoded();
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to encrypt mode, with the generated key
aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
// get the initialization vector being used (to be returned)
byte[] aesIV = aesCipher.getIV();
// encrypt the data
byte[] encryptedData = aesCipher.doFinal(dataToEncrypt);
// package the aes key, IV, and encrypted data and return them
return new AESEncryptedContents(rawAesKey, aesIV, encryptedData);
}
private byte[] decryptWithAES(byte[] aesKey, byte[] aesIV,
byte[] encryptedData) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException,
NoSuchProviderException {
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to decrypt mode with the AES key, and IV
aesCipher.init(Cipher.DECRYPT_MODE, skeySpec,
new IvParameterSpec(aesIV));
// decrypt and return the data
byte[] decryptedData = aesCipher.doFinal(encryptedData);
return decryptedData;
}
private byte[] decryptWithRSA(byte[] encryptedAesKey, PrivateKey privKey)
throws IllegalBlockSizeException, BadPaddingException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, NoSuchProviderException {
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
// set the cipher to use the public key
rsaCipher.init(Cipher.DECRYPT_MODE, privKey);
// encrypt the aesKey
return rsaCipher.doFinal(encryptedAesKey);
}
C# .Net:
public byte[] encryptData(byte[] data, out byte[] encryptedAesKey, out byte[] aesIV) {
if (data == null)
throw new ArgumentNullException("data");
byte[] encryptedData; // data to return
// begin AES key generation
RijndaelManaged aesAlg = new RijndaelManaged();
aesAlg.KeySize = AES_KEY_SIZE;
aesAlg.GenerateKey();
aesAlg.GenerateIV();
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
// aes Key to be encrypted
byte[] aesKey = aesAlg.Key;
// aes IV that is passed back by reference
aesIV = aesAlg.IV;
//get a new RSA crypto service provider to encrypt the AES key with the certificates public key
using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider())
{
//add the certificates public key to the RSA crypto provider
rsaCSP.FromXmlString(encryptionCertificate.PublicKey.Key.ToXmlString(false));
//encrypt AES key with RSA Public key
//passed back by reference
encryptedAesKey = rsaCSP.Encrypt(aesKey, false);
//get an aes encryptor instance
ICryptoTransform aesEncryptor = aesAlg.CreateEncryptor();
encryptedData = encryptWithAes(aesEncryptor, data);
}
if (encryptedData == null)
throw new CryptographicException(
"Fatal error while encrypting with AES");
return encryptedData;
}
private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data) {
MemoryStream memStream = null; // stream to write encrypted data to
CryptoStream cryptoStream = null; // crypto stream to encrypted data
try {
memStream = new MemoryStream();
// initiate crypto stream telling it to write the encrypted data to
// the memory stream
cryptoStream = new CryptoStream(memStream, aesEncryptor,
CryptoStreamMode.Write);
// write the data to the memory stream
cryptoStream.Write(data, 0, data.Length);
} catch (Exception ee) {
// rethrow
throw new Exception("Error while encrypting with AES: ", ee);
} finally {
// close 'em
if (cryptoStream != null)
cryptoStream.Close();
if (memStream != null)
memStream.Close();
}
// return the encrypted data
return memStream.ToArray();
}