Java AES 128 encriptado de forma diferente a openssl

Nos hemos encontrado con una situación extraña en la que el método de encriptación que estamos usando en Java produce un resultado diferente al de openssl, a pesar de que tienen una configuración idéntica.

Usando la misma tecla y IV, el texto “¡El rápido zorro castaño salta sobre el perro perezoso!” encripta a cadenas de base64 …

openssl: A8cMRIrDVnBYj2+XEKaMOBQ1sufjptsAf58slR373JTeHGPWyRqJK+UQxvJ1B/1L

Java: A8cMRIrDVnBYj2+XEKaMOBQ1sufjptsAf58slR373JTEVySz5yJLGzGd7qsAkzuQ

Esta es nuestra llamada de openssl …

 #!/bin/bash keySpec="D41D8CD98F00B2040000000000000000" ivSpec="03B13BBE886F00E00000000000000000" plainText="The quick BROWN fox jumps over the lazy dog!" echo "$plainText">plainText openssl aes-128-cbc -nosalt -K $keySpec -iv $ivSpec -e -in plainText -out cipherText base64 cipherText > cipherText.base64 printf "Encrypted hex dump = " xxd -p cipherText | tr -d '\n' printf "\n\n" printf "Encrypted base64 = " cat cipherText.base64 

Y esta es nuestra Java …

 private static void runEncryption() throws Exception { String plainText = "The quick BROWN fox jumps over the lazy dog!"; Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec keySpec = new SecretKeySpec(hexToBytes("D41D8CD98F00B2040000000000000000"), 0, 16, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(hexToBytes("03B13BBE886F00E00000000000000000")); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8")); String encryptedHexDump = bytesToHex(encrypted); String encryptedBase64 = new String(DatatypeConverter.printBase64Binary(encrypted)); System.out.println("Encrypted hex dump = " + encryptedHexDump); System.out.println(""); System.out.println("Encrypted base64 = " + encryptedBase64); } private static byte[] hexToBytes(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); return data; } final protected static char[] hexArray = "0123456789abcdef".toCharArray(); public static String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j >> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } 

salida oopenssl

 Encrypted hex dump = 03c70c448ac35670588f6f9710a68c381435b2e7e3a6db007f9f2c951dfbdc94de1c63d6c91a892be510c6f27507fd4b Encrypted base64 = A8cMRIrDVnBYj2+XEKaMOBQ1sufjptsAf58slR373JTeHGPWyRqJK+UQxvJ1B/1L 

Salida de Java

 Encrypted hex dump = 03c70c448ac35670588f6f9710a68c381435b2e7e3a6db007f9f2c951dfbdc94c45724b3e7224b1b319deeab00933b90 Encrypted base64 = A8cMRIrDVnBYj2+XEKaMOBQ1sufjptsAf58slR373JTEVySz5yJLGzGd7qsAkzuQ 

¿Nos estamos perdiendo algo obvio? ¿O hay alguna complejidad oculta?

De hecho, es un problema de proporcionar una cadena o un archivo. Si coloca una “\ n” al final de su código Java, el resultado será el mismo que en openSSL.

Creo que la diferencia es el relleno, no los datos cifrados reales.

¿Has intentado descifrar las cuerdas?

Creo que se mostrarán como lo mismo.

¿Por qué el relleno es diferente? porque lo están implementando de forma diferente, o porque uno tiene un archivo, mientras que el otro es una cadena, que al final, cuando los lees, no son lo mismo (uno tiene un marcador EoF, por ejemplo).

Por cierto: dado que es CBC, Cipher Block Chaining, todo el último bloque se ve afectado por esta diferencia de relleno