java - Dado que el bloque final no está adecuadamente acolchado
exception encryption (2)
Estoy tratando de implementar un algoritmo de cifrado basado en contraseñas, pero obtengo esta excepción:
javax.crypto.BadPaddingException: dado que el bloque final no está correctamente rellenado
¿Cuál podría ser el problema? (Soy nuevo en Java)
Aquí está mi código:
public class PasswordCrypter {
private Key key;
public PasswordCrypter(String password) {
try{
KeyGenerator generator;
generator = KeyGenerator.getInstance("DES");
SecureRandom sec = new SecureRandom(password.getBytes());
generator.init(sec);
key = generator.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] encrypt(byte[] array) throws CrypterException {
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(array);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public byte[] decrypt(byte[] array) throws CrypterException{
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(array);
} catch(Exception e ){
e.printStackTrace();
}
return null;
}
}
(La prueba JUnit)
public class PasswordCrypterTest {
private static final byte[] MESSAGE = "Alpacas are awesome!".getBytes();
private PasswordCrypter[] passwordCrypters;
private byte[][] encryptedMessages;
@Before
public void setUp() {
passwordCrypters = new PasswordCrypter[] {
new PasswordCrypter("passwd"),
new PasswordCrypter("passwd"),
new PasswordCrypter("otherPasswd")
};
encryptedMessages = new byte[passwordCrypters.length][];
for (int i = 0; i < passwordCrypters.length; i++) {
encryptedMessages[i] = passwordCrypters[i].encrypt(MESSAGE);
}
}
@Test
public void testEncrypt() {
for (byte[] encryptedMessage : encryptedMessages) {
assertFalse(Arrays.equals(MESSAGE, encryptedMessage));
}
assertFalse(Arrays.equals(encryptedMessages[0], encryptedMessages[2]));
assertFalse(Arrays.equals(encryptedMessages[1], encryptedMessages[2]));
}
@Test
public void testDecrypt() {
for (int i = 0; i < passwordCrypters.length; i++) {
assertArrayEquals(MESSAGE, passwordCrypters[i].decrypt(encryptedMessages[i]));
}
assertArrayEquals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[1]));
assertArrayEquals(MESSAGE, passwordCrypters[1].decrypt(encryptedMessages[0]));
try {
assertFalse(Arrays.equals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[2])));
} catch (CrypterException e) {
// Anything goes as long as the above statement is not true.
}
try {
assertFalse(Arrays.equals(MESSAGE, passwordCrypters[2].decrypt(encryptedMessages[1])));
} catch (CrypterException e) {
// Anything goes as long as the above statement is not true.
}
}
}
Si intenta descifrar los datos acolchados de PKCS5 con la clave incorrecta, y luego eliminarlos (lo que hace la clase Cipher automáticamente), lo más probable es que obtenga la BadPaddingException (probablemente con algo menos de 255/256, alrededor de 99.61% ), debido a que el relleno tiene una estructura especial que se valida durante la descarga y muy pocas teclas producirán un relleno válido.
Entonces, si obtiene esta excepción, tómela y trátela como "clave incorrecta".
Esto también puede suceder cuando proporciona una contraseña incorrecta, que luego se utiliza para obtener la clave de un almacén de claves, o que se convierte en una clave mediante una función de generación de claves.
Por supuesto, el mal relleno también puede ocurrir si sus datos están dañados durante el transporte.
Dicho esto, hay algunos comentarios de seguridad sobre su esquema:
Para el cifrado basado en contraseña, debe usar un SecretKeyFactory y PBEKeySpec en lugar de usar un SecureRandom con KeyGenerator. La razón es que SecureRandom podría ser un algoritmo diferente en cada implementación de Java, dándole una clave diferente. SecretKeyFactory realiza la derivación de la clave de una manera definida (y de una manera que se considera segura, si selecciona el algoritmo correcto).
No use el modo ECB. Encripta cada bloque de forma independiente, lo que significa que los bloques de texto plano idénticos también proporcionan bloques de texto cifrado siempre idénticos.
Preferiblemente utilice un modo seguro de operación , como CBC (encadenamiento de bloques de cifrado) o CTR (contador). Alternativamente, use un modo que también incluya autenticación, como GCM (modo Galois-Counter) o CCM (Counter con CBC-MAC), consulte el siguiente punto.
Normalmente no solo desea confidencialidad, sino también autenticación, lo que garantiza que el mensaje no se altere. (Esto también evita los ataques de texto cifrado elegidos en su cifrado, es decir, ayuda a mantener la confidencialidad). Por lo tanto, agregue un MAC (código de autenticación de mensaje) a su mensaje o utilice un modo de cifrado que incluya autenticación (consulte el punto anterior).
DES tiene un tamaño de clave efectivo de solo 56 bits. Este espacio clave es bastante pequeño, puede ser forzado en algunas horas por un atacante dedicado. Si genera su clave con una contraseña, esto será aún más rápido. Además, DES tiene un tamaño de bloque de solo 64 bits, lo que agrega algunas debilidades más en los modos de encadenamiento. Utilice un algoritmo moderno como AES, que tiene un tamaño de bloque de 128 bits y un tamaño de clave de 128 bits (para la variante estándar).
dependiendo del algoritmo de criptografía que esté utilizando, puede que tenga que agregar algunos bytes de relleno al final antes de cifrar una matriz de bytes para que la longitud de la matriz de bytes sea múltiple del tamaño de bloque:
Específicamente en su caso, el esquema de relleno que eligió es PKCS5, que se describe aquí: http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_CJ_SYM__PAD.html
(Supongo que tiene el problema cuando intenta encriptar)
Puede elegir su esquema de relleno cuando crea una instancia del objeto Cipher. Los valores admitidos dependen del proveedor de seguridad que esté utilizando.
Por cierto, ¿está seguro de que quiere usar un mecanismo de cifrado simétrico para cifrar contraseñas? ¿No sería mejor una forma de hash? Si realmente necesita poder descifrar contraseñas, DES es una solución bastante débil, puede que le interese usar algo más fuerte como AES si necesita permanecer con un algoritmo simétrico.