【问题标题】:RSA in javascript no longer supports ASCII/byte arraysjavascript 中的 RSA 不再支持 ASCII/字节数组
【发布时间】:2016-09-07 15:09:07
【问题描述】:

我正在使用来自http://www-cs-students.stanford.edu/~tjw/jsbn/ 的 rsa.js v1.0 来加密浏览器中的 ASCII 字符串。该字符串实际上是一个 16 字节数组,其中包含一个双倍长度的 TripleDes 键。使用 rsa v1.0 可以。字节数组在服务器上被正确解密(使用 Bouncy Castle 或 Thales HSM)为 16 字节数组。

例如

var zpk = hex2a("E0F8AD4092F81FC401E60ECB7F5B8F1A");
var rsa = new RSAKey();
rsa.setPublic(modulus, exponent);
var res = rsa.encrypt(zpk);
if (res) {
    document.rsatest.zpkrsa.value = hex2b64(res);
}

移动 rsa.js v1.4 时,这不再有效。 Bouncy castle 对数据进行解密,但现在不是 16 字节数组,而是 25 字节数组。

我在 rsa.js 库中看到的主要区别在于 v1.1 发行说明:

在 PKCS1 编码和解码 JavaScript 字符串时,添加了对非 ASCII 字符的 utf-8 编码的支持。

v1.0 中的 PKCS#1 填充是:

// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
function pkcs1pad2(s, n) {
    if (n < s.length + 11) {
        alert("Message too long for RSA");
        return null;
    }
    var ba = new Array();
    var i = s.length - 1;
    while (i >= 0 && n > 0) ba[--n] = s.charCodeAt(i--);
    ba[--n] = 0;
    var rng = new SecureRandom();
    ...
    return new BigInteger(ba);
}

v1.1 及更高版本中的 PKCS#1 填充函数为:

// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
function pkcs1pad2(s,n) {
  if(n < s.length + 11) { // TODO: fix for utf-8
    console.error("Message too long for RSA");
    return null;
  }
  var ba = new Array();
  var i = s.length - 1;
  while(i >= 0 && n > 0) {
    var c = s.charCodeAt(i--);
    if(c < 128) { // encode using utf-8
      ba[--n] = c;
    }
    else if((c > 127) && (c < 2048)) {
      ba[--n] = (c & 63) | 128;
      ba[--n] = (c >> 6) | 192;
    }
    else {
      ba[--n] = (c & 63) | 128;
      ba[--n] = ((c >> 6) & 63) | 128;
      ba[--n] = (c >> 12) | 224;
    }
  }
  ba[--n] = 0;
  ...
  return new BigInteger(ba);
}

rsa.js v1.0 将每个字符视为 1 字节字符。从 v1.1 开始测试字符是否为多字节 utf-8。

看来我唯一的选择是:

  1. 坚持使用 rsa.js v1.0
  2. 创建允许我禁用 utf-8 字符检测的 rsa.js(和 rsa2.js)的修改版本。
  3. (已编辑)更改代码以使用支持 PKCS#1 v2 (oaep) 的 defencejs.com。

想法?

【问题讨论】:

  • 有趣,可能是实现的 PKCS 版本不同,这可能会引起很多麻烦。实际上,我强烈建议尝试使用 Stanford JavaScript Crypto Library 而不是 Wu 的这个库,因为我知道 SJCL 的使用和测试范围更广。
  • 是的,很确定 Wu 的库正在实现 PCKS #1 v1.5,这可能容易受到 Bleichenbacher 攻击。作为密码学家,我建议不要使用此代码!改用 SJCL!

标签: javascript encryption cryptography public-key-encryption jsbn


【解决方案1】:
  1. 此代码在两种情况下都实现了 PKCS #1 v1.5 填充,唯一的区别是对 utf-8 的支持。要使其与接收库一起工作,该库需要以与他对其进行编码相同的方式对内容进行解码。祝你好运,我认为你不会找到任何能做到这一点的东西。

  2. PKCS #1 v1.5 填充是insecure,这是由于 Daniel Bleichenbacher 在 1999 年左右说明的一次攻击。现在建议使用 PKCS #1 v2.x。吴的代码不支持这个。

  3. 1234563解密:这将解决 Wu 的 UTF-8 调整。您也可以使用 base64 编码/解码。
  4. SJCL 是一个更好的 JavaScript 加密库,您不太可能遇到这样的问题。据我所知,Wu 的代码被设计为他出色的身份验证协议的 PoC,而 SJCL 是为更普遍的用途而设计的,并且由社区维护。

【讨论】:

  • 不幸的是,看起来 SJCL 库不支持 RSA。 RSA 是必需的,因为解密设备是 Thales HSM Payshield 9000 (en.wikipedia.org/wiki/Hardware_security_module)。 HSM 确实支持 PKCS#1 v2 (OEAP)
  • 当前的实现只使用一次公钥/私钥对。一旦服务器接收到请求,信息就会被处理(成功或失败),然后密钥被删除而不是重复使用。基于这个用例,我推测 Bleichenbacher 的 CCA 攻击不适用,例如攻击者没有机会使用随机数据重试请求。
  • @andyvan 大便蝙蝠侠,你是对的!令人失望!您也可以考虑使用 Google 的库,但不确定它的使用难度或成熟度,请参阅:github.com/google/end-to-end/blob/master/src/javascript/crypto/…。如果密钥在失败时被擦除,则.你是对的,攻击不适用。
  • 有趣的是,似乎没有很多(任何?)js RSA 库不是基于 Tom Wu 的工作。我还没有找到任何支持 PKCS#1 v2 OAEP 的。该规范适用于所有志愿者:ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
  • @andyvan:很有趣。也许这就是我的人生目标(我对此很认真)。同时,我修改了上面对第 3 点的建议:不要使用 base64,只需以 Wu 的库所需的格式(我认为是数组?)传入十六进制编码(“E0F8AD4092F81FC401E60ECB7F5B8F1A”)。这在另一端很容易处理,尤其是 HSM:将这种十六进制编码转换回字节数组是微不足道的,而且您不需要外部库来完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
  • 2016-11-13
  • 2021-10-27
  • 2021-10-03
  • 2018-05-17
相关资源
最近更新 更多