2014-12-02 278 views
7

我有以下基於cryptojs的JavaScript加密/解密函數,它可以很好地工作。如何在java服務器端解密cryptojs AES加密消息?

我使用cryptpjs加密消息時使用隨機salt,隨機iv值和特定密碼。我重複使用相同的salt,iv和密碼來生成密鑰,同時解密加密的消息。

這部分工作得很好..

function encrypt(){ 
    var salt = CryptoJS.lib.WordArray.random(128/8); 
    var iv = CryptoJS.lib.WordArray.random(128/8); 
    console.log('salt '+ salt); 
    console.log('iv '+ iv); 
    var key128Bits = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 128/32 }); 
    console.log('key128Bits '+ key128Bits); 
    var key128Bits100Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 128/32, iterations: 100 }); 
    console.log('key128Bits100Iterations '+ key128Bits100Iterations); 
    var encrypted = CryptoJS.AES.encrypt("Message", key128Bits100Iterations, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); 
    console.log('encrypted '+ encrypted ); 
} 

function decrypt(){ 
    var salt = CryptoJS.enc.Hex.parse("4acfedc7dc72a9003a0dd721d7642bde"); 
    var iv = CryptoJS.enc.Hex.parse("69135769514102d0eded589ff874cacd"); 
    var encrypted = "PU7jfTmkyvD71ZtISKFcUQ=="; 
    console.log('salt '+ salt); 
    console.log('iv '+ iv); 
    var key = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 128/32, iterations: 100 }); 
    console.log('key '+ key); 
    var decrypt = CryptoJS.AES.decrypt(encrypted, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); 
    var ddd = decrypt.toString(CryptoJS.enc.Utf8); 
    console.log('ddd '+ddd); 
} 

但是當我嘗試解密的Java服務器端相同的加密文本的問題開始。 我想要加密的消息被我的java服務器代碼解密。 下面是我寫的Java代碼:

public static void main(String args[]) throws Exception{ 
    String password = "Secret Passphrase"; 
    String salt = "4acfedc7dc72a9003a0dd721d7642bde"; 
    String iv = "69135769514102d0eded589ff874cacd"; 
    String encrypted = "PU7jfTmkyvD71ZtISKFcUQ=="; 
    byte[] saltBytes = salt.getBytes(); //hexStringToByteArray(salt); 
    byte[] ivBytes = iv.getBytes();//hexStringToByteArray(iv); 
    IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);   
    SecretKeySpec sKey = (SecretKeySpec) generateKeyFromPassword(password, saltBytes); 
    System.out.println(decrypt(encrypted , sKey ,ivParameterSpec)); 
} 

public static SecretKey generateKeyFromPassword(String password, byte[] saltBytes) throws GeneralSecurityException { 

    KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, 100, 128/32); 
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    SecretKey secretKey = keyFactory.generateSecret(keySpec); 
    return new SecretKeySpec(secretKey.getEncoded(), "AES"); 
} 

public static String decrypt(String encryptedData, SecretKeySpec sKey, IvParameterSpec ivParameterSpec) throws Exception { 

    Cipher c = Cipher.getInstance("AES"); 
    c.init(Cipher.DECRYPT_MODE, sKey, ivParameterSpec); 
    byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData); 
    byte[] decValue = c.doFinal(decordedValue); 
    String decryptedValue = new String(decValue); 
    return decryptedValue; 
} 

,但我得到以下異常:

Exception breakpoint: SecretKeySpec.java:96, java.lang.IllegalArgumentException, Empty key 
Exception in thread "main" java.lang.IllegalArgumentException: Empty key 
at javax.crypto.spec.SecretKeySpec.<init>(SecretKeySpec.java:96) 

我不知道我該怎麼辦

回答

7

你的這部分代碼是錯誤的:

KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, 100, 128/32); 
//->---------------------------------------------------------------------^^^^^^^ 

128/32值是錯誤的。您需要128,192256。目前您有相當於4,這看起來根本不會導致PBKDF2函數的輸出。

此外,在Java中,您應該使用DatatypeConverter.parseHexBinary()或類似的將十六進制轉換爲字節。目前您只需撥打getBytes()這是不對的。

最後,您需要指定CBC模式和PKCS#5填充以匹配您的Javascript代碼。因此,將該行更改爲:

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
+1

那一刻我沒有你建議的修改,它的工作。謝謝鄧肯。我將提供完整的工作解決方案作爲另一個答案。感謝堆。你已經發現並解決了我的問題。 – user1455719 2014-12-02 23:11:33

6

感謝Duncan的快速響應和建議。爲了他人的利益,我正在爲我提供完整的解決方案。

Java代碼做cryptojs解密加密消息

public static void main(String args[]) throws Exception{ 

String password = "Secret Passphrase"; 
String salt = "222f51f42e744981cf7ce4240eeffc3a"; 
String iv = "2b69947b95f3a4bb422d1475b7dc90ea"; 
String encrypted = "CQVXTPM2ecOuZk+9Oy7OyGJ1M6d9rW2D/00Bzn9lkkehNra65nRZUkiCgA3qlpzL"; 

byte[] saltBytes = hexStringToByteArray(salt); 
byte[] ivBytes = hexStringToByteArray(iv); 
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);   
SecretKeySpec sKey = (SecretKeySpec) generateKeyFromPassword(password, saltBytes); 
System.out.println(decrypt(encrypted , sKey ,ivParameterSpec)); 

} 

public static SecretKey generateKeyFromPassword(String password, byte[] saltBytes) throws GeneralSecurityException { 

KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, 100, 128); 
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
SecretKey secretKey = keyFactory.generateSecret(keySpec); 

return new SecretKeySpec(secretKey.getEncoded(), "AES"); 
} 

public static byte[] hexStringToByteArray(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; 

} 

public static String decrypt(String encryptedData, SecretKeySpec sKey, IvParameterSpec ivParameterSpec) throws Exception { 

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
c.init(Cipher.DECRYPT_MODE, sKey, ivParameterSpec); 
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData); 
byte[] decValue = c.doFinal(decordedValue); 
String decryptedValue = new String(decValue); 

return decryptedValue; 
} 
+0

我已經使用你的Javascript代碼(有問題)和Java代碼(在這個答案中)作爲例子,我已經實現了它。 Java代碼在密碼,salt,iv和加密等硬編碼方式成功工作時就像在此答案中完成的一樣。我也使用你的JavaScript代碼爲客戶端,但它似乎有像js方面的一些錯誤配置像密鑰大小等等,因爲我得到了錯誤的JavaScript填充異常在解碼JavaScript編碼的數據。你可以提供工作JavaScript代碼.. – 2015-02-01 09:29:24

+0

它是「給定最終塊未正確填充」在Java錯誤 – 2015-02-01 09:40:23

相關問題