IllegalBlockSizeException al intentar cifrar y descifrar una cadena con AES

Tengo una clave codificada con la que quiero encriptar 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 que está capturando 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 IvParameterSpec .

Cuando encriptas una cadena con AES, obtienes una matriz de bytes. Intentando convertir esos bytes directamente a una cadena ( new String(cipher.doFinal(plaintextBytes)) ) causará todo tipo de problemas. Si necesita que el resultado 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 a una matriz de bytes antes de descifrar la matriz de bytes.

Además, no use 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 sienta demasiado flojo para investigar), aquí está el código de resultado para el cifrado y descifrado AES-256 que preparé, con la ayuda de la respuesta y los comentarios aceptados:

 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 que responde y trabaja 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; } 

Versión de Kotlin de la respuesta de @Oleksiy.