java 如何在java服务器端解密cryptojs AES加密消息?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27248644/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 11:29:48  来源:igfitidea点击:

How to decrypt a cryptojs AES encrypted message at the java server side?

javaencryptionaescryptojs

提问by user1455719

I have the following cryptojs based javascript encryption/decryption functions which works perfectly fine.

我有以下基于 cryptojs 的 javascript 加密/解密函数,它们工作得非常好。

I use a random salt, random iv value and a specific password while encrypting the message using cryptpjs. I reuse the same salt, iv and the password to generate the key while decrypting the encrypted message.

我在使用 cryptpjs 加密消息时使用随机盐、随机 iv 值和特定密码。我在解密加密消息时重复使用相同的盐、iv 和密码来生成密钥。

This part works well..

这部分效果很好..

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);
} 

But the issue starts when I try to decrypt the same encrypted text at the java server side. I want the encrypted message to be decrypted by my java server code. Here is the Java code that I wrote:

但是当我尝试在 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;
}

But I get the following exception:

但我收到以下异常:

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)

I have no idea what I should do

我不知道我应该做什么

采纳答案by Duncan Jones

This part of your code is wrong:

这部分代码是错误的:

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

The 128/32value is erroneous. You need either 128, 192or 256. Currently you have the equivalent of 4, which seems to result in no output at all from the PBKDF2 function.

128/32值是错误的。您需要128,192256。目前,您拥有相当于4,这似乎导致 PBKDF2 函数根本没有输出。

Also, in Java you should use DatatypeConverter.parseHexBinary(), or similar, to convert hex into bytes. Currently you are just calling getBytes()which isn't right.

此外,在 Java 中,您应该使用DatatypeConverter.parseHexBinary()或类似方法将十六进制转换为字节。目前你只是打电话getBytes(),这是不对的。

Finally, you need to specify CBC mode and PKCS#5 padding in order to match your Javascript code. So change the line to:

最后,您需要指定 CBC 模式和 PKCS#5 填充以匹配您的 Javascript 代码。因此,将行更改为:

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

回答by user1455719

Thanks to Duncan for the prompt response and advice. I am giving the complete solution that worked for me below for the benefit of others.

感谢 Duncan 的及时回复和建议。为了他人的利益,我在下面给出了对我有用的完整解决方案。

Java code to do the decryption of the cryptojs encrypted message

做cryptojs加密消息解密的Java代码

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;
}