2014-12-02 276 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

相关问题