使用 Java 的 AES 加密和使用 Javascript 的解密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22607791/
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-08-13 16:49:23  来源:igfitidea点击:

AES encryption using Java and decryption using Javascript

javajavascriptencryptionaescryptojs

提问by rkj

I am making an application which needs Java based AES Encryption and JavaScript based decryption. I am using the following code for encryption as a basic form.

我正在制作一个需要基于 Java 的 AES 加密和基于 JavaScript 的解密的应用程序。我使用以下代码进行加密作为基本形式。

public class AESencrp {

  private static final String ALGO = "AES";
  private static final byte[] keyValue = 
      new byte[] { 'A', 'b', 'c', 'd', 'e', 'f', 'g',
      'h', 'i', 'j', 'k','l', 'm', 'n', 'o', 'p'};

  public static String encrypt(String Data) throws Exception {
    Key key = generateKey();
    Cipher c = Cipher.getInstance(ALGO);
    c.init(Cipher.ENCRYPT_MODE, key);
    byte[] encVal = c.doFinal(Data.getBytes());
    String encryptedValue = new BASE64Encoder().encode(encVal);
    return encryptedValue;
  }


  private static Key generateKey() throws Exception {
    Key key = new SecretKeySpec(keyValue, ALGO);
    return key;
  }
}

The JavaScript that I am trying to use to decrypt is

我试图用来解密的 JavaScript 是

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">   </script>

var decrypted = CryptoJS.AES.decrypt(encrypted,"Abcdefghijklmnop").toString(CryptoJS.enc.Utf8);

But the JavaScript decryption is not working. I am new to this, could someone tell me a way to solve without changing the Java code block ?

但是 JavaScript 解密不起作用。我对此很陌生,有人可以告诉我一种无需更改 Java 代码块即可解决的方法吗?

I tried Base-64 decoding my text like this:

我试过 Base-64 像这样解码我的文本:

var words  = CryptoJS.enc.Base64.parse(encrKey);
var base64 = CryptoJS.enc.Base64.stringify(words);
var decrypted = CryptoJS.AES.decrypt(base64, "Abcdefghijklmnop");
alert("dec :" +decrypted);

but still no good.

但还是不行。

I tried the solution suggested below to resolve possible padding issue but its not giving any solution.

我尝试了下面建议的解决方案来解决可能的填充问题,但没有给出任何解决方案。

var key = CryptoJS.enc.Base64.parse("QWJjZGVmZ2hpamtsbW5vcA==");
var decrypt = CryptoJS.AES.decrypt( encrKey, key, { mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7 } );

alert("dec :" +decrypt);

采纳答案by Oleg Estekhin

  1. Your Java code uses the 128-bit AES key while your JavaScript code uses the 256-bit AES key.

  2. Your Java code uses the "Abcdefghijklmnop".getBytes() as the actual key value, while your JavaScript code uses the "Abcdefghijklmnop" as the passphrase from which the actual key is derived.

  3. The default transformation for Java AES is AES/ECB/PKCS5Padding, while default transformation for CryptoJS is AES/CBC/PKCS7Padding.

  1. 您的 Java 代码使用 128 位 AES 密钥,而您的 JavaScript 代码使用 256 位 AES 密钥。

  2. 您的 Java 代码使用“Abcdefghijklmnop”.getBytes() 作为实际密钥值,而您的 JavaScript 代码使用“Abcdefghijklmnop”作为派生实际密钥的密码。

  3. Java AES 的默认转换是 AES/ECB/PKCS5Padding,而 CryptoJS 的默认转换是 AES/CBC/PKCS7Padding。

One way to fix your example is to fix the JavaScript side:

修复示例的一种方法是修复 JavaScript 端:

// this is Base64 representation of the Java counterpart
// byte[] keyValue = new byte[] { 'A', 'b', 'c', 'd', 'e', 'f', 'g',
//                'h', 'i', 'j', 'k','l', 'm', 'n', 'o', 'p'};
// String keyForJS = new BASE64Encoder().encode(keyValue);
var base64Key = "QWJjZGVmZ2hpamtsbW5vcA==";
console.log( "base64Key = " + base64Key );

// this is the actual key as a sequence of bytes
var key = CryptoJS.enc.Base64.parse(base64Key);
console.log( "key = " + key );

// this is the plain text
var plaintText = "Hello, World!";
console.log( "plaintText = " + plaintText );

// this is Base64-encoded encrypted data
var encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
});
console.log( "encryptedData = " + encryptedData );

// this is the decrypted data as a sequence of bytes
var decryptedData = CryptoJS.AES.decrypt( encryptedData, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
} );
console.log( "decryptedData = " + decryptedData );

// this is the decrypted data as a string
var decryptedText = decryptedData.toString( CryptoJS.enc.Utf8 );
console.log( "decryptedText = " + decryptedText );

回答by Pulkit Gupta

For Java and JavaScript to able to inter operate, it is essential that no defaults are used while creating Key or the Cipher. The iteration count, key length, padding, salt and IV should all be the same.

为了让 Java 和 JavaScript 能够互操作,在创建密钥或密码时不使用默认值是必不可少的。迭代次数、密钥长度、填充、salt 和 IV 都应该相同。

Reference: https://github.com/mpetersen/aes-example

参考:https: //github.com/mpetersen/aes-example

Sample code below:

示例代码如下:

Encrypting String in Java:

在 Java 中加密字符串:

    String keyValue = "Abcdefghijklmnop";     
    SecretKeyFactory factory =   SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(keyValue.toCharArray(), hex("dc0da04af8fee58593442bf834b30739"),
        1000, 128);

    Key key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
    Cipher c = Cipher.getInstance(“AES/CBC/PKCS5Padding”);
    c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(hex("dc0da04af8fee58593442bf834b30739")));

    byte[] encVal = c.doFinal("The Quick Brown Fox Jumped over the moon".getBytes());
    String base64EncodedEncryptedData = new String(Base64.encodeBase64(encVal));
    System.out.println(base64EncodedEncryptedData);

}

}

Decrypting the same string in JavaScript:

在 JavaScript 中解密相同的字符串:

var iterationCount = 1000;
var keySize = 128;
var encryptionKey  ="Abcdefghijklmnop";
var dataToDecrypt = "2DZqzpXzmCsKj4lfQY4d/exg9GAyyj0hVK97kPw5ZxMFs3jQiEQ6LLvUsBLdkA80" //The base64 encoded string output from Java;
var iv = "dc0da04af8fee58593442bf834b30739"
var salt = "dc0da04af8fee58593442bf834b30739"

var aesUtil = new AesUtil(keySize, iterationCount);
var plaintext =  aesUtil.decrypt(salt, iv, encryptionKey, dataToDecrypt);
console.log(plaintext);

**//AESUtil - Utility class for CryptoJS**
var AesUtil = function(keySize, iterationCount) {
 this.keySize = keySize / 32;
 this.iterationCount = iterationCount;
};

AesUtil.prototype.generateKey = function(salt, passPhrase) {
  var key = CryptoJS.PBKDF2(passPhrase, CryptoJS.enc.Hex.parse(salt),
  { keySize: this.keySize, iterations: this.iterationCount });
  return key;
}

AesUtil.prototype.decrypt = function(salt, iv, passPhrase, cipherText) {
  var key = this.generateKey(salt, passPhrase);
  var cipherParams = CryptoJS.lib.CipherParams.create({
    ciphertext: CryptoJS.enc.Base64.parse(cipherText)
  });
  var decrypted = CryptoJS.AES.decrypt(cipherParams,key,
  { iv: CryptoJS.enc.Hex.parse(iv) });
  return decrypted.toString(CryptoJS.enc.Utf8);
 }
}