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
:
- Error: Error de ejecución de la tarea: ExecException: Proceso 'comando' C: \ Archivos de programa \ Java \ jdk1.7.0_79 \ bin \ java.exe terminado con valor de salida distinto de cero 2
- ¿Qué significa la sintaxis "final String ... args"?
- Creación de un archivo de encabezado para la clase de actividad de Android
- Cómo hacer un signo de infinito en Android?
- ¿Puedo hacer un juego HTML5 para Android?
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
.
- Android queryIntentActivities siempre devuelve la lista vacía
- Android LockScreen
- SimpleDateFormat: excepción de fecha incomparable
- ScheduledExecutorService o ScheduledThreadPoolExecutor
- Dos tipos de parámetros diferentes (cast Object to Type)
- Esta clase Handler debe ser estática o pueden producirse fugas: handler final
- AsyncSocket en java?
- ¿Es posible desactivar el modo silencioso de forma programática en android?
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; }
- Android – ionic – no hay plataformas añadidas a este proyecto
- Descartar DatePickerDialog al pulsar el botón Atrás