我正在使用来自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 会解密数据,但它现在是 25 字节数组,而不是 16 字节数组。
我可以在 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。
看来我唯一的选择是:
- 坚持使用 rsa.js v1.0
- 创建 rsa.js(和 rsa2.js)的修改版本,允许我禁用 utf-8 字符检测。
- (已编辑)更改代码以使用支持 PKCS#1 v2 (oaep) 的 defencejs.com。
想法?