Java AES 128加密与openssl不同

我们遇到了一种奇怪的情况,我们在Java中使用的加密方法会产生不同的输出到openssl,尽管它们在配置上看起来相同。

使用相同的键和IV,文本“快速布朗狐狸跳过懒狗!” 加密到base64’d字符串……

openssl: A8cMRIrDVnBYj2+XEKaMOBQ1sufjptsAf58slR373JTeHGPWyRqJK+UQxvJ1B/1L

Java: A8cMRIrDVnBYj2+XEKaMOBQ1sufjptsAf58slR373JTEVySz5yJLGzGd7qsAkzuQ

这是我们的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 

这是我们的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); } 

oopenssl输出

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

Java输出

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

我们是否遗漏了明显的东西 还是有一些隐藏的复杂性?

确实是提供字符串或文件的问题。 如果在Java代码的末尾加上“\ n”,结果将与openSSL中的结果相同。

我认为区别在于填充,而不是实际的加密数据。

你试过解密字符串吗?

我相信他们会像现在一样出现。

为什么填充不同? 因为他们要么以不同的方式实现它,要么是因为提供了一个文件,而另一个是字符串,最后,当你读它们时,它们不是同一个东西(例如,一个有EoF标记)。

BTW:由于它是CBC,Cipher Block Chaining,因此填充差异会影响整个最后一个块