AES 128bit Cross Platform (Java and C#) Encryption Compatibility
It seems quite a minor issue but doing cross platform encryption and decryption specifically AES was a bit a challenge for me. When you get it working it just seems like no big change to the original code you where working on but you wasted fruitless hours debugging. Just sharing so that another person doesn’t have to waste time wondering why same settings produce a different cipher and going through a number of unhelpful posts where it ” works on my machine”.
I initially used ISO 10126 padding, but that seemed to produce a different cipher in C# and Java. I decided to go with no padding which leads me to the cryptographic exception: Length of the data to decrypt is invalid. After some head banging I settled with PKCS7.
Same encoding of strings has to be used in java and c#, other wise you will end up having different ciphers in java and c#.
The java code below uses a base64 util class from android SDK but you can replace it like with one from apache commons
C# encryption utility
public RijndaelManaged GetRijndaelManaged(String secretKey) { var keyBytes = new byte[16]; var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey); Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length)); return new RijndaelManaged { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7, KeySize = 128, BlockSize = 128, Key = keyBytes, IV = keyBytes }; } public byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged) { return rijndaelManaged.CreateEncryptor() .TransformFinalBlock(plainBytes, 0, plainBytes.Length); } public byte[] Decrypt(byte[] encryptedData, RijndaelManaged rijndaelManaged) { return rijndaelManaged.CreateDecryptor() .TransformFinalBlock(encryptedData, 0, encryptedData.Length); } /// <summary> /// Encrypts plaintext using AES 128bit key and a Chain Block Cipher and returns a base64 encoded string /// </summary> /// <param name="plainText">Plain text to encrypt</param> /// <param name="key">Secret key</param> /// <returns>Base64 encoded string</returns> public String Encrypt(String plainText, String key) { var plainBytes = Encoding.UTF8.GetBytes(plainText); return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(key))); } /// <summary> /// Decrypts a base64 encoded string using the given key (AES 128bit key and a Chain Block Cipher) /// </summary> /// <param name="encryptedText">Base64 Encoded String</param> /// <param name="key">Secret Key</param> /// <returns>Decrypted String</returns> public String Decrypt(String encryptedText, String key) { var encryptedBytes = Convert.FromBase64String(encryptedText); return Encoding.UTF8.GetString(Decrypt(encryptedBytes, GetRijndaelManaged(key))); }
Java Encryption Utility
private final String characterEncoding = "UTF-8"; private final String cipherTransformation = "AES/CBC/PKCS5Padding"; private final String aesEncryptionAlgorithm = "AES"; public byte[] decrypt(byte[] cipherText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { Cipher cipher = Cipher.getInstance(cipherTransformation); SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm); IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector); cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy, ivParameterSpec); cipherText = cipher.doFinal(cipherText); return cipherText; } public byte[] encrypt(byte[] plainText, byte[] key, byte [] initialVector) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { Cipher cipher = Cipher.getInstance(cipherTransformation); SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm); IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); plainText = cipher.doFinal(plainText); return plainText; } private byte[] getKeyBytes(String key) throws UnsupportedEncodingException{ byte[] keyBytes= new byte[16]; byte[] parameterKeyBytes= key.getBytes(characterEncoding); System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length)); return keyBytes; } /// <summary> /// Encrypts plaintext using AES 128bit key and a Chain Block Cipher and returns a base64 encoded string /// </summary> /// <param name="plainText">Plain text to encrypt</param> /// <param name="key">Secret key</param> /// <returns>Base64 encoded string</returns> public String encrypt(String plainText, String key) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{ byte[] plainTextbytes = plainText.getBytes(characterEncoding); byte[] keyBytes = getKeyBytes(key); return Base64.encodeToString(encrypt(plainTextbytes,keyBytes, keyBytes), Base64.DEFAULT); } /// <summary> /// Decrypts a base64 encoded string using the given key (AES 128bit key and a Chain Block Cipher) /// </summary> /// <param name="encryptedText">Base64 Encoded String</param> /// <param name="key">Secret Key</param> /// <returns>Decrypted String</returns> public String decrypt(String encryptedText, String key) throws KeyException, GeneralSecurityException, GeneralSecurityException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException{ byte[] cipheredBytes = Base64.decode(encryptedText, Base64.DEFAULT); byte[] keyBytes = getKeyBytes(key); return new String(decrypt(cipheredBytes, keyBytes, keyBytes), characterEncoding); }
Hopefully this saves someone time.
Thanks a lot man. You saved my time. 🙂 It works like a charm.
This was very useful. Thanks for posting your solution.
Amazing, I spent a few hours trying to put this encryption to work between java and c#,
it’s working now, thanks to you.
Thank you, realy. =)
This is wonderful!!, thanks
Thanks for the post. It was very usefull.
Thank you so much… I have been struggling with this for ages!
Hi,
I’ve downloaded the apache commons 1.6 jar but there seems to be a problem with “Base64.DEFAULT” which is coming as undefined. Could you point me to the correct version of commons library or perhaps let me know the value of “Base64.DEFAULT” if its a constant.
Thanks,
Parmeet
sry, should have checked it first:
http://developer.android.com/reference/android/util/Base64.html#DEFAULT
Thank you so much!!! I had about a week struggling with this, THANK YOU.
can I get the same logic in javascript?
This work better than medicine…I was able to complete my small program in minutes; 128 and 256.
Thanks
TuKanSam
This worked great. Many thanks!
is it possible to implement the same logic in Objective C? please reply as soon as possible..
Am not acquainted with Objective C.
I’ve used Java code in android and .Net wcf service perfectly. Thank you very much!
Please any one help me that what will be in JAVA in line where Base64 is used in the above given code. Thanks for any help in this regards.
I have similar problem. I tried using
byte[] cipheredBytes = Base64.base64Decode(EncryptedText).getBytes()
But it gives me an exception javax.crypto.BadPaddingException: Given final block not properly padded.
did you find any solution for this?
It is not a good idea to use the encryption key as initialization vector (IV) for the cipher block chaining. Encryption key and IV should be seperate values. Take a (human readable) pass phrase string and feed it into a cryptographic hash function like SHA256/384/512 to get a sufficient number of key bytes for both, encryption key AND initialization vector. Use the first 16 bytes of the hash value as encryption key and the next 16 bytes as IV.
Hi,
This is an awesome document. Really very helpful.
I am trying to implement the same code for encryption in c# and decryption in java.
I am not able to find the same method to get the byte array for cipheredBytes like yours at line 51 i.e. byte[] cipheredBytes = Base64.decode(encryptedText, Base64.DEFAULT).
However I am using this method:
byte[] cipheredBytes = Base64.base64Decode(encryptedText).getBytes();
But I am getting an error
javax.crypto.BadPaddingException: Given final block not properly padded
How to implement the method like yours? What packege will I need to import for that?
Please help
I am facing the below errors pls give me a solutions
Exception in thread “main” java.lang.RuntimeException: Stub!
at android.util.Base64.encodeToString(Base64.java:8)
at com.security.packs.Encry.encrypt(Encry.java:87)
at com.security.packs.Encry.main(Encry.java:112)
Big thanks !!!
Wonderful)
As for the Base64.Default when not using the Android package, use the package org.apache.ws.security.util.Base64 and the method Base64.encode(encrypt(plainTextbytes,keyBytes, keyBytes)); (and obviously the counterpart decode…)
Thank you very much!
Nice solution solving all my Problems.
This also works with openssl.net which by default uses PKCS5Padding.
Thank you very much for this.
Thanks a lot! It’s a perfect solution.
Has anyone implemented this into a java applicatio
n yet?
Hi I have a problem to convert to C# from java. Please help me out.
javax.crypto.Cipher c = javax.crypto.Cipher.getInstance(“RSA/ECB/NOPADDING”);
javax.security.cert.X509Certificate pcert = javax.security.cert.X509Certificate.getInstance(cer.RawData);
c.init(javax.crypto.Cipher.ENCRYPT_MODE, pcert.getPublicKey());
byte[] pdecrypt = pdecrypt = c.doFinal(p);
I need the same thing but in C#
if we change RijndaelManaged to AesManged then the keys generated are not same in java and .net any solution?
and how to pass salt value in .net
Here is the Java encryption code and which is getting decrypted and woking fine:
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;
}
I tried to convert above code to c#.net but it was giving an exception saying that
javax.crypto.IllegalBlockSizeException: Data must not be longer than 256 bytes in java dcryption. Please suggest me anything wrong in my .net code mentioned below:
static byte[] doThis(string message)
{
X509Certificate2 cert = new X509Certificate2(@”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;
//Cipher encryptCipher = Cipher.getInstance(“RSA/ECB/PKCS1Padding”, “SunJCE”);
//encryptCipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
//byte[] messageACrypter = message.
//messageCrypte = encryptCipher.doFinal(messageACrypter);
}
You rock!
I’m serious you rock, you saved me crap loads of time
You are a life saver.. Thanks a ton.. Working perfectly..
Can I get the same algorithm in C?
Thanks man, saved me alot of time! 🙂
Thanks MAN !!!
Thanks man, your code works perfectly and saved my a lot of time..
You are great..:)
Perfect, Thank you a lot man.
Thanks so much. After weeks of frustration and misery. Waooooo You are a blessing. I have more than 25 webpages opened that I am reading to get this sorted out. This worked like magic
Thank you so much 🙂
Thank you so much, this save my time. I find any codes on google, but nothing work. u’re the best.
i want to use the oracle pl/sql package dbms_crypto to have the same result.
Can somebody help me ?
when i try to compile the testdh class with java encryption utility, i have this error :
14:48:10 Start Compiling 1 object(s) …
14:48:10 Executing ALTER JAVA SOURCE “testdh” COMPILE …
14:48:11 [0:0] testdh:49: cannot access org.apache.commons.codec.binary.Base64
14:48:11 [0:0] bad class file: null
14:48:11 [0:0] class file has wrong version 50.0, should be 49.0
14:48:11 [0:0] Please remove or make sure it appears in the correct subdirectory of the classpath.
14:48:11 [0:0] return Base64.encodeToString(encrypt(plainTextbytes,keyBytes, keyBytes), Base64.DEFAULT);
14:48:11 [0:0] ^
14:48:11 [0:0] 1 error
14:48:11 Compilation complete – 7 error(s) found
14:48:11 End Compiling 1 object(s)
Any idea ?
i try to encrypt via an Oarcle package and i have this error :
[1]: ORA-29532: Java call terminated by uncaught Java exception: java.lang.ExceptionInInitializerError
the error comes form this line in the java code :
Cipher cipher = Cipher.getInstance(cipherTransformation);
Can somebody help me ?
awesome dude. works perfectly
Excellent! Thank you I spent so many time trying to do this.
hi, i have aes encryption happning in android app and decription happening on java desktop application, which is not working, could you pls me the solution….
i cannt decrypt large file?? please help me! thks so much
Excellentttttt….. Thank You very much
Thanks for your work !!
Please refer to the following if you want to make it work in JAVA SE.
import java.util.Base64;
* Encrypt
return Base64.getEncoder().encodeToString(encrypt(plainTextbytes,keyBytes, keyBytes));
* Decrypt
return new String(decrypt(cipheredBytes, keyBytes, keyBytes), characterEncoding);
Thanks man!!
It’s not just save my time.
Thank you!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! I spent 2 days trying this, until your tutorial and ran at first time.
Thank you very much, you saved my life !
Thanks mate
Muchísimas gracias!!
Me ha sido de mucha ayuda para encriptar y desencriptar a través de un servicio web (C# -> Java, Java -> C#).
Tras buscar en muchísimas páginas y ejemplos este es el único que realmente me ha funcionado…
Saludos :D!!
I am trying to encrypt in java and decrypt in c# using query string.Any send coding for me or send a reference solution for me..
Thank u in advance..i am waiting:)
I am trying to encrypt in java and decrypt in asp.net.Any send coding for that
Advance in thanks
Thanks you so much Sir…… 🙂
Its working perfectly on Android & C#. Do you have similar code for Objective C?
No similar code for objective C
Very nice helped alot… thanksss
I get an error in c#..length of the data to decrypt is invalid…why is that so? is that related to blocksize because the encrypted data is 195bytes and block size in only 128???? is that so?
I am doing encryption in C# and while doing decryption in Java I am getting special characters in output. can someone share the java working decryption code (non andriod)
I am getting special characters in Java when trying to decrypt the encrypted C# value and also padding PKCS5Padding is not working.
Can Someone share the working Java code non-andriod
I dont see how that can be valid (c#). In case of java we hash secret and use derived hashed byte sequence for iv and key, whilst in c# we simply use plain secret text. That 2 never gonna match.
padding is invalid and cannot be removed
while decryption in C#
help me
is any compatible code or library is available for iOS in objective C or Swift
Thanks Joe. This saves after a whole day of toiling.
Honestly, man, you’re a hero. Saved my day.