Android Encryption BadPaddingException

I am making an Android application and I want to encrypt String before sending it to the database, and encrytpion is correct. The problem occurs when decrypting the string, because I get a BadPaddingException, and I don't know where the problem is. Here is the code:

public final static String HEX = "36A52C8FB7DF9A3F"; public static String encrypt(String seed, String cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext.getBytes()); return toHex(result); } public static String decrypt(String seed, String encrypted) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] enc = toByte(encrypted); byte[] result = decrypt(rawKey, enc); return new String(result); } public static String toHex(String txt) { return toHex(txt.getBytes()); } public static String fromHex(String hex) { return new String(toByte(hex)); } public static byte[] toByte(String hexString) { int len = hexString.length()/2; byte[] result = new byte[len]; for (int i = 0; i < len; i++) result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue(); return result; } public static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2*buf.length); for (int i = 0; i < buf.length; i++) { appendHex(result, buf[i]); } return result.toString(); } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); kgen.init(128, sr); // 192 and 256 bits may not be available SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f)); } 

I encrypt and decrypt using this code:

 String encrypted = encrypt(HEX, "some text"); String decrypted = decrypt(HEX, encrypted); 

Can anybody help me?

Thank you very much!

EDIT: The problem is not resolved, but I have a bit more information. First of all, I encrypt in a Java project, and I decrypt in an Android project. I tried to decrypt in the same Java project, and there is no problem, but if I try to decrypt in Android, it will not work. The problem is the getRawKey method (see kgen.generateKey () Comment):

JAVA:

 private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); //Seed: [51, 54, 65, 53, 50, 67, 56, 70, 66, 55, 68, 70, 57, 65, 51, 70] kgen.init(128, sr); // 192 and 256 bits may not be available SecretKey skey = kgen.generateKey(); //skey.key = [-97, -52, 45, -95, -64, -58, 16, -20, 124, -50, -104, 58, 23, -75, 88, 94] byte[] raw = skey.getEncoded(); return raw; } 

ANDROID:

 private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); //Seed: [51, 54, 65, 53, 50, 67, 56, 70, 66, 55, 68, 70, 57, 65, 51, 70] kgen.init(128, sr); // 192 and 256 bits may not be available SecretKey skey = kgen.generateKey(); //skey.key = [-114, 32, 16, -52, -81, 125, -88, 88, -76, 20, -117, -11, 33, -61, 32, -91] byte[] raw = skey.getEncoded(); return raw; } 

I am not an expert in the crypt, but how can it be possible that with the same seed I get a different key?

+4
source share
4 answers

I had some kind of problem. Decision:

 import java.io.UnsupportedEncodingException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; public class StringEncrypter { Cipher ecipher; Cipher dcipher; StringEncrypter(String password) { // 8-bytes Salt byte[] salt = { (byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32, (byte)0x56, (byte)0x34, (byte)0xE3, (byte)0x03 }; // Iteration count int iterationCount = 19; try { KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iterationCount); SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec); ecipher = Cipher.getInstance(key.getAlgorithm()); dcipher = Cipher.getInstance(key.getAlgorithm()); // Prepare the parameters to the cipthers AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount); ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec); } catch (InvalidAlgorithmParameterException e) { System.out.println("EXCEPTION: InvalidAlgorithmParameterException"); } catch (InvalidKeySpecException e) { System.out.println("EXCEPTION: InvalidKeySpecException"); } catch (NoSuchPaddingException e) { System.out.println("EXCEPTION: NoSuchPaddingException"); } catch (NoSuchAlgorithmException e) { System.out.println("EXCEPTION: NoSuchAlgorithmException"); } catch (InvalidKeyException e) { System.out.println("EXCEPTION: InvalidKeyException"); } } /** * Takes a single String as an argument and returns an Encrypted version * of that String. * @param str String to be encrypted * @return <code>String</code> Encrypted version of the provided String */ public byte[] encrypt(String str) { try { // Encode the string into bytes using utf-8 byte[] utf8 = str.getBytes("UTF8"); // Encrypt byte[] enc = ecipher.doFinal(utf8); // Encode bytes to base64 to get a string //return new sun.misc.BASE64Encoder().encode(enc); return enc; } catch (BadPaddingException e) { } catch (IllegalBlockSizeException e) { } catch (UnsupportedEncodingException e) { } return null; } /** * Takes a encrypted String as an argument, decrypts and returns the * decrypted String. * @param str Encrypted String to be decrypted * @return <code>String</code> Decrypted version of the provided String */ public String decrypt(byte[] dec) { try { // Decode base64 to get bytes //byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str); //byte[] dec = Base64Coder.decode(str); // Decrypt byte[] utf8 = dcipher.doFinal(dec); // Decode using utf-8 return new String(utf8, "UTF8"); } catch (BadPaddingException e) { } catch (IllegalBlockSizeException e) { } catch (UnsupportedEncodingException e) { } return null; } 

}

I found this solution here . This works great. But I'm really interested to know what the problem was with AES.

+3
source

From a general point of view, I think that BadPaddingException can be caused by the following reasons:

i> Incorrect data size for encryption algorithm.

ii> Different keys are used to encrypt and decrypt data.

+1
source

For those who want to use String and Base64 encoding for use with a database, you can use these (slightly overwritten) functions from Mike Keskinov (and xalien on Anddev.org).

 public String encrypt(String str) { try { // Encode the string into bytes using utf-8 byte[] utf8 = str.getBytes("UTF8"); // Encrypt byte[] enc = ecipher.doFinal(utf8); // Encode bytes to base64 to get a string return new String(Base64.encode(enc,0)); } catch (BadPaddingException e) { } catch (IllegalBlockSizeException e) { } catch (UnsupportedEncodingException e) { } return null; } public String decrypt(String str) { try { // Decode base64 to get bytes byte[] dec = Base64.decode(str, 0); // Decrypt byte[] utf8 = dcipher.doFinal(dec); // Decode using utf-8 return new String(utf8, "UTF8"); } catch (BadPaddingException e) { } catch (IllegalBlockSizeException e) { } catch (UnsupportedEncodingException e) { } return null; } 

Android Base64 built-in libraries are also used in this code, so there is no need to import additional external libraries.

Something that I did not understand at first was how to actually use this class from another class (my ignorance). Here is a simple example:

 StringEncrypter se = new StringEncrypter("mypass"); String decryptedString = se.decrypt(encryptedString); 

Another thing on Base64. I found that Base64 encoding appends the character '/ n' linefeed (0x0a) whenever a string is longer than 76 characters. This seriously violates the decryption results. To cut out these newlines, you can add something like:

 b64_enc_str = se.encrypt(plaintext_str); str = b64_enc_str.replace("/n",""); 

Hope this helps someone.

0
source

getRawKey assumes that the SecureRandom instance is a well-defined, deterministic pseudo-random number generator.

First of all, it is not defined; method "SHA1PRNG" not defined exactly. It can and has been changed even for the SUN provider itself.

Secondly, the fact that seeding a SecureRandom instance immediately after construction makes it deterministic is a specific SUN provider. In other words, other suppliers may choose to add seed to the entropy pool. This entropy pool may have already been seeded with values โ€‹โ€‹obtained from the operating system. This applies to many versions of Android. To explain this in unprofessional terms: the Android SecureRandom completely random, even if it is sown immediately after construction. This means that the getRawKey method on such systems always generates a new, completely random key.

So what is the solution? The solution is to store the key in a KeyStore or generate a key from a passphrase. In this case, you can use the PBKDF2 function (password derivation function based on password # 2) already present in java SE and Android:

 SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); // note, the third argument should be set to a value as high as possible // 10K is about the minimum nowadays KeySpec ks = new PBEKeySpec(password, salt, 1024, 128); SecretKey s = f.generateSecret(ks); Key k = new SecretKeySpec(s.getEncoded(),"AES"); 
0
source

Source: https://habr.com/ru/post/1338089/


All Articles