IllegalBlockSizeException al intentar cifrar y descifrar una cadena con AES

Tengo una clave codificada con la que quiero cifrar una cadena antes de almacenarla en SharedPreferences . Este es el código que tengo hasta ahora:

 public class TokenEncryptor { private final static String TOKEN_KEY = "91a29fa7w46d8x41"; public static String encrypt(String plain) { try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]); SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES"); cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec); return new String(cipher.doFinal(plain.getBytes())); } catch (Exception e) { Ln.e(e); return null; } } public static String decrypt(String encoded) { try { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]); SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES"); cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec); return new String(cipher.doFinal(encoded.getBytes())); } catch (Exception e) { Ln.e(e); return null; } } } 

Parece ser captura de una excepción al final del método de decrypt :

javax.crypto.IllegalBlockSizeException: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

¿Alguien me puede apuntar en la dirección correcta? Tengo la sensación de que estoy haciendo algo mal instanciando IvParameterSpec .

Cuando cifra una cadena con AES, obtiene una matriz de bytes de nuevo. Tratar de convertir esos bytes directamente a una cadena ( new String(cipher.doFinal(plaintextBytes)) ) causará todo tipo de problemas. Si necesita que la salida de su método de cifrado sea una cadena, utilice Base64 lugar de intentar una conversión directa. En su método de descifrado, convierta la cadena Base64 en una matriz de bytes antes de descifrar la matriz de bytes.

Además, no utilice getBytes() ya que la salida depende de los valores predeterminados del sistema. Use getBytes("utf-8") o lo que sea. Eso elimina la ambigüedad.

En caso de que alguien esté interesado (o se siente demasiado perezoso para hacer su investigación), aquí está el código de resultado para el cifrado y descifrado AES-256 que reuní, con la ayuda de la respuesta aceptada y comentarios:

 public class TokenEncryptor { private final static String TOKEN_KEY = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw"; public static String encrypt(String plain) { try { byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv)); byte[] cipherText = cipher.doFinal(plain.getBytes("utf-8")); byte[] ivAndCipherText = getCombinedArray(iv, cipherText); return Base64.encodeToString(ivAndCipherText, Base64.NO_WRAP); } catch (Exception e) { Ln.e(e); return null; } } public static String decrypt(String encoded) { try { byte[] ivAndCipherText = Base64.decode(encoded, Base64.NO_WRAP); byte[] iv = Arrays.copyOfRange(ivAndCipherText, 0, 16); byte[] cipherText = Arrays.copyOfRange(ivAndCipherText, 16, ivAndCipherText.length); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv)); return new String(cipher.doFinal(cipherText), "utf-8"); } catch (Exception e) { Ln.e(e); return null; } } private static byte[] getCombinedArray(byte[] one, byte[] two) { byte[] combined = new byte[one.length + two.length]; for (int i = 0; i < combined.length; ++i) { combined[i] = i < one.length ? one[i] : two[i - one.length]; } return combined; } } 

Es una extensión de Artjom B respuesta y trabajando para mí.

 public String encryptMsg(String message, SecretKey secret) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { Cipher cipher = null; cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secret); byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8")); return Base64.encodeToString(cipherText, Base64.NO_WRAP); } public String decryptMsg(String cipherText, SecretKey secret) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException { Cipher cipher = null; cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secret); byte[] decode = Base64.decode(cipherText, Base64.NO_WRAP); String decryptString = new String(cipher.doFinal(decode), "UTF-8"); return decryptString; } 
  • Evitando! = Null utilizando un método en java
  • Error al abrir la base de datos / Error al cambiar la configuración regional de (base de datos) a 'en_US'
  • Método recursivo funciona en java con consola, pero no con android
  • ¿Cómo obtener un cuerpo de respuesta para la excepción de actualización?
  • ¿Android con maven? Apk desconocido
  • Cómo esperar a que Android runOnUiThread para ser terminado?
  • SQLite es sin tipo?
  • NullPointerException en FragmentManager
  • Cómo pasar un argumento a una prueba junit de android (pruebas parametrizadas)
  • Android - cambia el estado de un switch de forma programática sin activar OnCheckChanged listener
  • Sincronización de contactos con mi propia aplicación como skype o whatsapp
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.