AES CBC nodejs加密和Java解密
AES CBC nodejs encryption and Java decryption
节点:
我正在尝试在 java 中使用 NodeJs 中的 AES CBC PKCS7 和 PKCS5 解密文本。我收到错误消息:Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
已更新
encrypt() {
var key = 'ThirtyTwoBytes3$ThirtyTwoBytes3$';
var iv = CryptoJS.enc.Utf8.parse(CryptoJS.lib.WordArray.random(128 / 8));
let utf8Pass = CryptoJS.enc.Utf8.parse("Hello");
let encVal = CryptoJS.AES.encrypt(utf8Pass.toString(), key, {mode:
CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: iv});
return iv.concat(encVal.ciphertext).toString(CryptoJS.enc.Base64);
}
Java:
byte[] keyB = "ThirtyTwoBytes3$ThirtyTwoBytes3$".getBytes(StandardCharsets.UTF_8);
IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptedText.getBytes(), 0, 16);
SecretKeySpec key = new SecretKeySpec(keyB, "AES");
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
byte[] decryptedData = Base64.getDecoder().decode(encryptedText);
decryptedText = new String(Hex.decodeHex(new String(aesCBC.doFinal(decryptedData), StandardCharsets.UTF_8).toCharArray()));
固定 IV 工作正常
NodeJs
var encKey = CryptoJS.enc.Utf8.parse("ThirtyTwoBytes3$ThirtyTwoBytes3$");
var encKeyIv = CryptoJS.enc.Utf8.parse("SixteenBytes6$");
let utf8Pass = CryptoJS.enc.Utf8.parse("Hello");
let encVal = CryptoJS.AES.encrypt(utf8Pass.toString(), encKey, {mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: encKeyIv});
encVal.ciphertext.toString();
Java:
SecretKey key = new SecretKeySpec("ThirtyTwoBytes3$ThirtyTwoBytes3$".getBytes(), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec("SixteenBytes6$".getBytes());
byte[] decodeBase64 = Base64.decode(encVal);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
decString = new String(Hex.decodeHex(new String(cipher.doFinal(decodeBase64), "UTF-8").toCharArray()));
CryptoJS 部分存在一些问题,应用以下修复:
const iv = CryptoJS.lib.WordArray.random(128 / 8); // no UTF8 encoding, this corrupts the data
...
encrypted = iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64); // typo in ciphertext; use base64 encoding because of the built-in support in Java
return encrypted; // return the data
在Java密码中,IV和密文必须分开,例如:
import java.nio.ByteBuffer;
import java.util.Base64;
...
String ivCiphertextB64 = "zuXYG1IbUNsiQYSTBUCv+Rx37EpJTw9SWfhRkL3yw2GncOvBDNU+w6UdB+ovfL2LyiCMYF1ptiXvuWynngc76Q=="; // data from CryptoJS code
byte[] ivCiphertext = Base64.getDecoder().decode(ivCiphertextB64);
ByteBuffer bufIvCiphertext = ByteBuffer.wrap(ivCiphertext);
byte[] iv = new byte[16];
bufIvCiphertext.get(iv);
byte[] ciphertext = new byte[bufIvCiphertext.remaining()];
bufIvCiphertext.get(ciphertext);
...
iv
在new IvParameterSpec(iv)
中传递,ciphertext
在aesCBC.doFinal(ciphertext)
中传递。上面的密文解密为敏捷的棕狐跳过懒狗.
编辑:
关于您的评论:在您问题的修改后的 CryptoJS 代码中, random IV 仍然是 Utf8 编码的。这种 Utf8 编码是错误的,因为它破坏了随机数据(例如 here)并且需要如上所述进行更改。您将在下面找到完整的、有效的 CryptoJS 代码。使用此代码生成的密文可以使用修改后的 Java 代码进行解密。
function encrypt() {
const _key = CryptoJS.enc.Utf8.parse('ThirtyTwoBytes3$ThirtyTwoBytes3$');
const iv = CryptoJS.lib.WordArray.random(128 / 8);
let encrypted = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse('The quick brown fox jumps over the lazy dog'),
_key,
{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
}
);
encrypted = iv
.concat(encrypted.ciphertext)
.toString(CryptoJS.enc.Base64);
return encrypted;
}
document.getElementById("ct").innerHTML = encrypt();
<p style="font-family:'Courier New', monospace;" id="ct"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
节点:
我正在尝试在 java 中使用 NodeJs 中的 AES CBC PKCS7 和 PKCS5 解密文本。我收到错误消息:Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
已更新
encrypt() {
var key = 'ThirtyTwoBytes3$ThirtyTwoBytes3$';
var iv = CryptoJS.enc.Utf8.parse(CryptoJS.lib.WordArray.random(128 / 8));
let utf8Pass = CryptoJS.enc.Utf8.parse("Hello");
let encVal = CryptoJS.AES.encrypt(utf8Pass.toString(), key, {mode:
CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: iv});
return iv.concat(encVal.ciphertext).toString(CryptoJS.enc.Base64);
}
Java:
byte[] keyB = "ThirtyTwoBytes3$ThirtyTwoBytes3$".getBytes(StandardCharsets.UTF_8);
IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptedText.getBytes(), 0, 16);
SecretKeySpec key = new SecretKeySpec(keyB, "AES");
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
byte[] decryptedData = Base64.getDecoder().decode(encryptedText);
decryptedText = new String(Hex.decodeHex(new String(aesCBC.doFinal(decryptedData), StandardCharsets.UTF_8).toCharArray()));
固定 IV 工作正常
NodeJs
var encKey = CryptoJS.enc.Utf8.parse("ThirtyTwoBytes3$ThirtyTwoBytes3$");
var encKeyIv = CryptoJS.enc.Utf8.parse("SixteenBytes6$");
let utf8Pass = CryptoJS.enc.Utf8.parse("Hello");
let encVal = CryptoJS.AES.encrypt(utf8Pass.toString(), encKey, {mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: encKeyIv});
encVal.ciphertext.toString();
Java:
SecretKey key = new SecretKeySpec("ThirtyTwoBytes3$ThirtyTwoBytes3$".getBytes(), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec("SixteenBytes6$".getBytes());
byte[] decodeBase64 = Base64.decode(encVal);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
decString = new String(Hex.decodeHex(new String(cipher.doFinal(decodeBase64), "UTF-8").toCharArray()));
CryptoJS 部分存在一些问题,应用以下修复:
const iv = CryptoJS.lib.WordArray.random(128 / 8); // no UTF8 encoding, this corrupts the data
...
encrypted = iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64); // typo in ciphertext; use base64 encoding because of the built-in support in Java
return encrypted; // return the data
在Java密码中,IV和密文必须分开,例如:
import java.nio.ByteBuffer;
import java.util.Base64;
...
String ivCiphertextB64 = "zuXYG1IbUNsiQYSTBUCv+Rx37EpJTw9SWfhRkL3yw2GncOvBDNU+w6UdB+ovfL2LyiCMYF1ptiXvuWynngc76Q=="; // data from CryptoJS code
byte[] ivCiphertext = Base64.getDecoder().decode(ivCiphertextB64);
ByteBuffer bufIvCiphertext = ByteBuffer.wrap(ivCiphertext);
byte[] iv = new byte[16];
bufIvCiphertext.get(iv);
byte[] ciphertext = new byte[bufIvCiphertext.remaining()];
bufIvCiphertext.get(ciphertext);
...
iv
在new IvParameterSpec(iv)
中传递,ciphertext
在aesCBC.doFinal(ciphertext)
中传递。上面的密文解密为敏捷的棕狐跳过懒狗.
编辑:
关于您的评论:在您问题的修改后的 CryptoJS 代码中, random IV 仍然是 Utf8 编码的。这种 Utf8 编码是错误的,因为它破坏了随机数据(例如 here)并且需要如上所述进行更改。您将在下面找到完整的、有效的 CryptoJS 代码。使用此代码生成的密文可以使用修改后的 Java 代码进行解密。
function encrypt() {
const _key = CryptoJS.enc.Utf8.parse('ThirtyTwoBytes3$ThirtyTwoBytes3$');
const iv = CryptoJS.lib.WordArray.random(128 / 8);
let encrypted = CryptoJS.AES.encrypt(
CryptoJS.enc.Utf8.parse('The quick brown fox jumps over the lazy dog'),
_key,
{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
}
);
encrypted = iv
.concat(encrypted.ciphertext)
.toString(CryptoJS.enc.Base64);
return encrypted;
}
document.getElementById("ct").innerHTML = encrypt();
<p style="font-family:'Courier New', monospace;" id="ct"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>