簡體   English   中英

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

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

我有以下基於cryptojs的javascript加密/解密函數,它們工作得很好。

我使用隨機鹽,隨機iv值和特定密碼,同時使用cryptpjs加密消息。 我重復使用相同的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)

我不知道該怎么做

感謝Duncan的迅速回應和建議。 我正在給出對我有用的完整解決方案,以造福他人。

用於解密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;
}

這部分代碼是錯誤的:

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

128/32值是錯誤的。 您需要用128192256 目前你有相當於4 ,這似乎導致PBKDF2函數沒有輸出。

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

最后,您需要指定CBC模式和PKCS#5填充以匹配您的Javascript代碼。 所以將行改為:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM