【问题标题】:AES CBC nodejs encryption and Java decryptionAES CBC nodejs 加密和Java解密
【发布时间】:2022-01-09 06:08:07
【问题描述】:

NodeJs: 我正在尝试使用 NodeJs 中的 AES CBC PKCS7 和 java 中的 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("$1SixteenBytes6$");
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("$1SixteenBytes6$".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()));

【问题讨论】:

  • 不应该是AES/CBC/PKCS7Padding吗?此外,您似乎将 16 个字节的密码作为 IV,然后解密整个内容?如果您的 CryptoJS 将 iv 附加到密码的开头,则密码不能包含 IV。通常虽然它会单独发送?
  • @zaitsman 在 Java PKCS7 和 PKCS5 中是相同的。关于IV,是的,这就是我的想法。在加密字符串中,如果您看到我将前 16 读为 IV,则在我的 java 代码中应该加上前缀。但是在 NodeJs 中,我需要在返回之前明确附加它吗?我认为 Crypto 会照顾好
  • 我会尝试对 IV 进行硬编码。如果您可以解密,您将知道您需要自己发送它。另外,回复:PKCS7 与 PKCS5 相同,严格来说并非如此:stackoverflow.com/questions/20770072/…
  • ...但是在 NodeJs 中我需要在返回之前明确附加它吗?我认为 Crypto 会小心... 在您的用例中,encrypted.toString() 包含 Base64 编码的密文 没有 IV!您必须自己进行连接。此外,在 Java 中,PKCS#5 在此上下文中表示 PKCS#7。
  • @Topaco 我做了 IV 和 cypherText 的串联,但错误消息没有变化。尝试了固定 IV,效果很好

标签: node.js encryption aes java-11


【解决方案1】:

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 中,即使进行了更改,您也建议加密的字符串看起来并不完整,并且无法在 Java 中解密。节点 Js:“Hello”被加密为“OThhODYzZDY1M2Q4YjBjNTZiMWUxYmM1NjlmMzFkYmbp9rKO5ux5gh9xpYiK6e8+”
  • @Pat - 请查看我的答案的编辑部分。
  • 感谢 CryptoJs 代码出现问题,正如您提到的,我使用的是 utf8。现在工作正常。
猜你喜欢
  • 2018-11-28
  • 1970-01-01
  • 2021-01-05
  • 2013-08-11
  • 2018-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多