BadPaddingException в Android encrypt

Я делаю приложение для Android, и я хочу зашифровать String перед отправкой его в базу данных, а encrytpion – правильно. Проблема возникает при расшифровке строки, потому что я получаю исключение BadPaddingException, и я понятия не имею, где проблема. Вот код:

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)); } 

Я шифрую и расшифровываю с помощью этого кода:

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

Кто-нибудь может мне помочь?

Большое спасибо!!

EDIT: Проблема не решена, но у меня есть немного больше информации. Прежде всего, я шифрую в проекте Java, и я дешифрую в проекте Android. Я попытался расшифровать в одном проекте Java, и нет никаких проблем, но если я попытаюсь расшифровать в Android, это не сработает. Проблема заключается в методе getRawKey (см. Комментарий kgen.generateKey ()):

ЯВА:

 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; } 

Я не эксперт в склепе, но как может быть возможно, что с тем же семенем я получаю другой ключ?

У меня была какая-то проблема. Решение:

 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; } 

}

Я нашел это решение здесь . Это работает отлично. Но мне действительно интересно узнать, в чем была проблема с AES.

С общей точки зрения, я думаю, что BadPaddingException может быть вызвано следующими причинами:

I> Неверный размер данных для алгоритма шифрования.

Ii> Для шифрования и дешифрования данных используются разные ключи.

Хорошо, это была моя вина. Это была глупая ошибка, переменная HEX должна иметь значение «01234567989ABCDEF», и когда я копировал ключ в другой файл, я скопировал его в переменную HEX.

Извините всех и спасибо

EDIT: проблема не решена. Пожалуйста, посмотрите мой EDIT.

Для тех, кто хочет использовать кодировку String и Base64 для использования с базой данных, вы можете использовать эти (слегка перезаписанные) функции от Майка Кескинова (и xalien на 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, поэтому нет необходимости импортировать дополнительные внешние библиотеки.

Сначала я не понимал, как на самом деле использовать этот класс из другого класса (мое невежество). Вот простой пример:

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

Еще одна вещь на Base64. Я обнаружил сложный способ, которым кодировка Base64 добавляет символ «/ n» linefeed (0x0a) всякий раз, когда длина строки превышает 76 символов. Это серьезно нарушает результаты расшифровки. Чтобы вырезать эти символы новой строки, вы можете добавить что-то вроде:

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

Надеюсь, это помогает кому-то.

getRawKey предполагает, что экземпляр SecureRandom является хорошо определенным, детерминированным генератором SecureRandom чисел.

Прежде всего, она не определена; "SHA1PRNG" точно не определен. Он может – и был изменен даже для самого поставщика SUN.

Во-вторых, тот факт, что посев экземпляра SecureRandom непосредственно после построения делает его детерминированным, является специфическим поставщиком SUN. Другими словами, другие поставщики могут предпочесть добавить семя в энтропийный пул. Возможно, этот пул энтропии уже был высеян со значениями, полученными из операционной системы. Это относится ко многим версиям Android. Объяснить это в неспециалистских терминах: экземпляр Android SecureRandom полностью SecureRandom даже если он посеян непосредственно после строительства . Это означает, что метод getRawKey на таких системах всегда генерирует новый, полностью случайный ключ.

Так в чем же решение? Решение состоит в том, чтобы хранить ключ в KeyStore или генерировать ключ из кодовой фразы. В этом случае вы можете использовать функцию PBKDF2 (функция деривации пароля на основе пароля № 2), уже присутствующую в java SE и 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"); 
Intereting Posts
Как увеличить высоту ProgressBar в ICS / JB NullPointerException: попытка чтения из поля 'int android.view.View.mViewFlags' AudioTrack Android воспроизводит звуки из сырой папки Виджет android работает в том же процессе, что и приложение Android: Как сделать пусковую установку всегда открывать основное действие, а не активность ребенка? (или иным образом) «Приложение не установлено» при установке самозаверяющего apk на SD-карте Анимированный переход между активностью и другим Я не могу найти файл adb_usb.ini в папке .android? Могут ли быть запущены и разработаны автономные части реактивно-родного пакета автономно? Могу ли я остановить HTTPResponseCache, работая как общий кэш в отношении заголовков Cache-Control? Студия Android, как удалить папку со ссылками? Уведомление без ожидающего намерения Действие onNewIntent Null Pointer Exception Остановите мое приложение от сна (Cordova / Android) Студия Android не может разрешить общий символ, отсутствующий в пакете android.gms