studio library example encrypt cipher aescrypt java android encryption aes

java - library - cipher android example



IllegalBlockSizeException al intentar cifrar y descifrar una cadena con AES (4)

Cuando encriptas una cadena con AES, obtienes una matriz de bytes. Intentar convertir esos bytes directamente en 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 nuevamente en 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.

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 estar detectando 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 .


En caso de que alguien esté interesado (o se sienta demasiado vago 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 los 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 la respuesta de Artjom B y funciona 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.

<script src="https://gist.github.com/kasim1011/a5a9644a60c33a4df3c29f4b34cf93a4.js"></script>

import android.util.Base64 import java.util.* import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec private const val algorithm = "AES" private const val tokenKey = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw" private const val padding = "AES/CBC/PKCS5Padding" private const val ivSize = 16 fun String.encryptAES(): String { val tokenBytes = tokenKey.toByteArray(Charsets.UTF_8) val secretKey = SecretKeySpec(tokenBytes, algorithm) val ivByteArray = ByteArray(ivSize) val iv = IvParameterSpec(ivByteArray) val cipher = Cipher.getInstance(padding) cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv) val cipherText = cipher.doFinal(toByteArray(Charsets.UTF_8)) val ivAndCipherText = getCombinedArray(ivByteArray, cipherText) return Base64.encodeToString(ivAndCipherText, Base64.NO_WRAP) } fun String.decryptAES(): String { val tokenBytes = tokenKey.toByteArray(Charsets.UTF_8) val secretKey = SecretKeySpec(tokenBytes, algorithm) val ivAndCipherText = Base64.decode(this, Base64.NO_WRAP) val cipherText = Arrays.copyOfRange(ivAndCipherText, ivSize, ivAndCipherText.size) val ivByteArray = Arrays.copyOfRange(ivAndCipherText, 0, ivSize) val iv = IvParameterSpec(ivByteArray) val cipher = Cipher.getInstance(padding) cipher.init(Cipher.DECRYPT_MODE, secretKey, iv) return cipher.doFinal(cipherText).toString(Charsets.UTF_8) } private fun getCombinedArray(one: ByteArray, two: ByteArray): ByteArray { val combined = ByteArray(one.size + two.size) for (i in combined.indices) { combined[i] = if (i < one.size) one[i] else two[i - one.size] } return combined }