javascript 中的 RSA 不再支持 ASCII/byte 数组

RSA in javascript no longer supports ASCII/byte arrays

我正在使用 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 时,这不再有效。充气城堡解密数据,但不是 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);
}

PKCS#1 padding函数在v1.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. 创建 rsa.js(和 rsa2.js)的修改版本,允许我禁用 utf-8 字符检测。
  3. (已编辑)更改代码以使用支持 PKCS#1 v2 (oaep) 的 defensivejs.com。

想法?

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

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

  3. 如果你真的想使用这个库(我反对它),可能最干净的方法是在你加密它之前发送十六进制编码的密钥("E0F8AD4092F81FC401E60ECB7F5B8F1A")并使确保收件人 hex 在解密后对其进行解码:这将解决 Wu 的 UTF-8 调整。你也可以使用 base64 encoding/decoding.

  4. SJCL 是一个更好的 JavaScript 加密库,您不太可能 运行 遇到这样的问题。据我所知,Wu 的代码是作为他出色的身份验证协议的 PoC 而设计的,而 SJCL 是为更广泛的用途而设计的,并由社区维护。