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

如何在java服务器端解密cryptojs AES加密消息?,java,encryption,aes,cryptojs,Java,Encryption,Aes,Cryptojs,我有以下基于cryptojs的javascript加密/解密函数,它们工作得非常好 在使用cryptpjs加密消息时,我使用随机salt、随机iv值和特定密码。我重复使用相同的salt、iv和密码来生成密钥,同时解密加密的消息 这部分很好用 function encrypt(){ var salt = CryptoJS.lib.WordArray.random(128/8); var iv = CryptoJS.lib.WordArray.random(128/8); consol

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

在使用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)
异常断点:SecretKeySpec.java:96,java.lang.IllegalArgumentException,空键 线程“main”java.lang.IllegalArgumentException中的异常:空键 在javax.crypto.spec.SecretKeySpec.(SecretKeySpec.java:96)
我不知道我应该怎么做

您的这部分代码是错误的:

KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, 100, 128/32);
//->---------------------------------------------------------------------^^^^^^^
128/32
值错误。您需要
128
192
256
。目前,您有相当于
4
,这似乎导致PBKDF2函数完全没有输出

此外,在Java中,您应该使用或类似的方法将十六进制转换为字节。目前您正在调用
getBytes()
,这是不对的

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

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

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

解密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;
}
publicstaticvoidmain(字符串args[])引发异常{
String password=“Secret Passphrase”;
字符串salt=“222f51f42e744981cf7ce4240eeffc3a”;
字符串iv=“2b69947b95f3a4bb422d1475b7dc90ea”;
字符串加密=“cqvxtmp2ecouzk+9Oy7OyGJ1M6d9rW2D/00Bzn9lkkehNra65nRZUkiCgA3qlpzL”;
字节[]saltBytes=hexStringToByteArray(salt);
byte[]ivBytes=hexStringToByteArray(iv);
IvParameterSpec IvParameterSpec=新的IvParameterSpec(ivBytes);
SecretKeySpec sKey=(SecretKeySpec)generateKeyFromPassword(密码,saltBytes);
System.out.println(解密(加密,sKey,ivParameterSpec));
}
public static SecretKey generateKeyFromPassword(字符串密码,字节[]saltBytes)引发GeneralSecurityException{
KeySpec KeySpec=new-PBEKeySpec(password.toCharArray(),saltBytes,100128);
SecretKeyFactory keyFactory=SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA1”);
SecretKey SecretKey=keyFactory.generateSecret(keySpec);
返回新的SecretKeySpec(secretKey.getEncoded(),“AES”);
}
公共静态字节[]hexStringToByteArray(字符串s){
int len=s.length();
字节[]数据=新字节[len/2];
对于(int i=0;i数据[i/2]=(字节)((Character.digit(s.charAt(i),16))当我做了您建议的更改时,它就工作了。感谢Duncan。我将提供完整的工作解决方案作为另一个答案。感谢heaps。您发现并修复了我的问题。我使用了您的Javascript代码(有问题)和Java代码(在这个答案中)作为示例,我已经实现了它。当密码、salt、iv和加密都像这个答案中那样硬编码时,Java代码成功地工作了。我也在客户端使用了您的javascript代码,但在js端似乎存在一些错误配置,如密钥大小等,因为我在Java wh中遇到了错误的填充异常解码javascript编码的数据。你能提供工作的javascript代码吗?。这是java中的“给定的最后一个块没有正确填充”错误