2014-01-13 71 views
3

我們遇到了一個奇怪的情況,即我們在Java中使用的加密方法會產生不同的輸出到openssl,儘管它們在配置中看起來相同。Java AES 128對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 = "abcdef".toCharArray(); 

public static String bytesToHex(byte[] bytes) 
{ 
    char[] hexChars = new char[bytes.length * 2]; 
    for (int j = 0; j < bytes.length; j++) 
    { 
     int v = bytes[j] & 0xFF; 
     hexChars[j * 2] = hexArray[v >>> 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 

我們是否失去了一些東西明顯?還是有一些隱藏的複雜性?

回答

0

這確實是提供了一個字符串或文件的問題的影響。如果您在Java代碼的末尾加上「\ n」,結果將與openSSL中的結果相同。

3

我相信不同的是填充,而不是實際的加密數據。

你試過解密字符串嗎?

我相信他們會表現得一樣。

爲什麼填充不同?因爲他們要麼以不同的方式實現它,要麼因爲一個人提供了一個文件,而另一個字符串,最後,當你閱讀它們時,它們不是同一個東西(例如,有一個EoF標記)。

BTW:既然是CBC,密碼塊鏈接,整個最後一塊被此填充差異