【问题标题】:"Invalid AES Block Size" SJCL Decryption“无效的 AES 块大小”SJCL 解密
【发布时间】:2015-12-16 05:54:50
【问题描述】:

尝试使用使用 SJCL 的 RNCryptor-js 解密 AES。在记录每一端的所有步骤后,(另一端是RNCryptor-python)密钥、盐、HMAC 哈希,一切都匹配了。但是当我到达最后一步时:

var aes = new sjcl.cipher.aes(encryption_key);
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]()
var decrypted = aes.decrypt(ciphertext, iv);

我得到错误:

 sjcl.exception.invalid {toString: function, message: "invalid aes block size"}

这里是完整的代码:

PBKDF2:

this.KeyForPassword = function(password, salt) {

  var hmacSHA256 = function (password) {
      var hasher = new sjcl.misc.hmac(password, sjcl.hash.sha256);
      this.encrypt = function () {
          return hasher.encrypt.apply(hasher, arguments);
      };
  };
  return sjcl.misc.pbkdf2(password, salt, 10000, 32 * 8, hmacSHA256);
};

解密(接受十六进制输入):

this.decrypt = function(password, message, options) {

  message = sjcl.codec.hex.toBits(message);

  options = options || {};

  var version = sjcl.bitArray.extract(message, 0 * 8, 8);
  var options = sjcl.bitArray.extract(message, 1 * 8, 8);

  var encryption_salt = sjcl.bitArray.bitSlice(message, 2 * 8, 10 * 8);
  var encryption_key = _this.KeyForPassword(password, encryption_salt, "decryption");

  var hmac_salt = sjcl.bitArray.bitSlice(message, 10 * 8, 18 * 8);
  var hmac_key = _this.KeyForPassword(password, hmac_salt, "decryption");

  var iv = sjcl.bitArray.bitSlice(message, 18 * 8, 34 * 8);

  var ciphertext_end = sjcl.bitArray.bitLength(message) - (32 * 8);
  var ciphertext = sjcl.bitArray.bitSlice(message, 34 * 8, ciphertext_end);

  var hmac = sjcl.bitArray.bitSlice(message, ciphertext_end);
  var expected_hmac = new sjcl.misc.hmac(hmac_key).encrypt(sjcl.bitArray.bitSlice(message, 0, ciphertext_end));

  if (! sjcl.bitArray.equal(hmac, expected_hmac)) {
    throw new sjcl.exception.corrupt("HMAC mismatch or bad password.");
  }

  var aes = new sjcl.cipher.aes(encryption_key);
  sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]()
  var decrypted = aes.decrypt(ciphertext, iv);

  return decrypted;
}

在定义decrypted 的倒数第二个语句中引发错误。

我查看了 sjcl 异常,看起来它正在寻找长度为 4 的输入,我猜它是一个 WordArray。我只是不知道如何获得有效的输入。就像我说的那样,密文、iv、hmac 标记、盐都在 javascript 端被正确分割。可能只是编码问题。

这个错误似乎也只发生在 json 上(格式:'{"key":"value"}'),当我尝试像“Hello, world”这样的东西时,我得到了一个没有错误的 4 字数组。

有什么建议吗?

【问题讨论】:

  • 当您使用 JSON 时,如果您将代码设置为输出 ciphertext.length,那么长度是什么意思?
  • @WDS, ciphertext.length 为不同的 json 返回了不同的长度。较短的我得到 16,较长的:24,更长的:36。
  • 如果我使用 Crypto-JS 代替最后一个解密步骤,我不会收到任何错误,但我会得到一个空的 WordArray。
  • 我有点脱离我的元素,但似乎 Encrypt 和 Decrypt 函数一次只能处理一个块,并且您需要手动将密文拆分为单独的块,将每个块拆分为 4 个单词,一次将 4 个单词交给函数。 .NET 有方法可以在一组命令中处理任意长度的密文,但我猜你需要自己编写。作为测试,请尝试将您的密文 BitSlice 降低到 128 位并将其传递给解密函数。看看它是否会解密为纯文本的一部分。
  • 好主意。尝试了拆分,我得到了一个单词数组,但由于某种原因我无法对其进行编码。 CryptoJS 和 sjcl Utf8 字符串化似乎都不起作用

标签: javascript python encryption rncryptor sjcl


【解决方案1】:
 var decrypted = aes.decrypt(ciphertext, iv);

应该是

 var decrypted = sjcl.mode.cbc.decrypt(aes, ciphertext, iv);

我在 cbc.js (link to source) 中发生填充时也遇到了问题,结果我没有包含 bitArray.js (link) 其中包括一个重要的 xor 函数(不要与简单的 @ 混淆987654328@运营商)。

所以:包含 bitArray.js

输出也应该被编码:

return sjcl.codec.utf8String.fromBits(decrypted);

【讨论】:

  • 对于阅读本文的人:不要忘记参数必须以位为单位:var kbits = sjcl.codec.arrayBuffer.toBits(new Uint8Array(key).buffer); var aes = new sjcl.cipher.aes(kbits); var plainBinary = sjcl.mode.cbc.decrypt(aes, sjcl.codec.arrayBuffer.toBits(encryptedBinary.buffer), sjcl.codec.arrayBuffer.toBits(iv.buffer));
猜你喜欢
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 2015-02-20
  • 2021-05-26
相关资源
最近更新 更多