Estoy tratando de implementar una función en Java para calcular el valor de verificación de clave para una clave de cifrado AES de 128 bits. La clase AES128CBCEncryptor implementa AES/128/CBC con relleno ISO 9797-1 M2.
La única información que puedo encontrar en el algoritmo de valor de verificación de clave para AES dice que "el KCV para una clave AES se calcula cifrando 16 bytes, cada uno con el valor '01'". No especifica cómo se debe construir el IV.
Esto es lo que tengo hasta ahora, pero no está generando el resultado esperado:
public String computeAesCheckValue(String key) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IOException { AES128CBCEncryptor encryptor = new AES128CBCEncryptor(key); byte[] cleartext = new byte[16]; byte[] iv = new byte[16]; for (int i = 0; i < 16; i++) { cleartext[i] = (byte) 0x01; iv[i] = (byte) 0x00; } String kcv = encryptor.encrypt(new String(cleartext, "utf-8"), Hex.encodeHexString(iv)); return (kcv != null && kcv.length() >= 6) ? Hex.encodeHexString(kcv.getBytes()).substring(0, 6) : null; }¿Qué me estoy perdiendo?
Para un valor de verificación de clave (KCV), generalmente se usa el cifrado de bloque único, sin ningún modo como ECB o CBC. Como solo se utiliza un valor constante de 16 bytes, tampoco es necesario rellenar.
Si solo tiene una clase CBC que realiza el relleno ISO 9797-1 M2, entonces podría cifrar el valor estático de 01010101010101010101010101010101 (codificación hexadecimal de 16 bytes), utilizando un IV todo cero y tomando los primeros 16 bytes del resultado (eliminando 16 bytes de texto cifrado al final que es solo cifrado del relleno obligatorio).
Como puede ver en la imagen a continuación, debido a que el IV es todo cero, el XOR con el texto sin formato deja la entrada intacta, básicamente haciendo que el primer texto cifrado sea idéntico al cifrado directo con el cifrado de bloque.
Por WhiteTimberwolf (versión SVG) - versión PNG, dominio público, https://commons.wikimedia.org/w/index.php?curid=26434096
Sin embargo, como está usando Java, tiene más sentido usar un objeto Cipher usando el algoritmo "AES/ECB/NoPadding" y usarlo para encriptar el valor de 01010101010101010101010101010101 directamente. ECB no toma una vía intravenosa, por lo que se evita ese problema. Además, no es necesario tener en cuenta el relleno cuando se especifica "NoPadding" .
Si necesita menos bytes: generalmente se toman de la izquierda (índice más bajo) del resultado.
Tenga en cuenta que este tipo de KCV son algo peligrosos ya que muestran el texto cifrado de un bloque de texto sin formato en particular. En el peor de los casos, esto podría llevar a que un adversario descifre un bloque de texto cifrado, o que un esquema autenticado pierda sus propiedades de integridad/autenticación.
Comúnmente, los KCV están sobre un bloque de texto sin formato de ceros. El uso de un bloque de un solo valor hace que la posibilidad de que esto suceda sea más pequeña, pero esa posibilidad sigue siendo significativa.