问题描述
近日,在实现api加密传输需求的过程中,需要使用jsencrypt进行公钥解密,但是jsencrypt原生不支持该功能,仅支持使用私钥解密。
jsencrypt原生不支持使用公钥解密数据,但是可以通过对jsencrypt的源码进行修改,从而实现jsencrypt使用公钥解密的需求。
问题解决
首先,需要进入你的node_modules目录下,根据如下路径找到rsa.js文件。
1. 进入jsencrypt/lib/lib/jsbn/rsa.js。
2. 在rsa.js文件中,第207行附近的RSAKey.prototype.decrypt方法中,将 this.doPrivate(c) 改为 this.doPublic(c)。如下代码所示。
RSAKey.prototype.decrypt = function (ctext) {
var c = parseBigInt(ctext, 16);
// 这里doPrivate修改为doPublic
// var m = this.doPrivate(c);
var m = this.doPublic(c);
if (m == null) {
return null;
}
return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3);
};
3. 同样在rsa.js文件中,找到第310行附近的pkcs1unpad2方法,并将这三行代码注释。参照如下代码。
function pkcs1unpad2(d, n) {
var b = d.toByteArray();
var i = 0;
while (i < b.length && b[i] == 0) {
++i;
}
// 这里将如下三行代码注释
// if (b.length - i != n - 1 || b[i] != 2) {
// return null;
// }
++i;
while (b[i] != 0) {
if (++i >= b.length) {
return null;
}
}
var ret = "";
while (++i < b.length) {
var c = b[i] & 255;
if (c < 128) { // utf-8 decode
ret += String.fromCharCode(c);
}
else if ((c > 191) && (c < 224)) {
ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63));
++i;
}
else {
ret += String.fromCharCode(((c & 15) << 12) | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63));
i += 2;
}
}
return ret;
}
4. 保存修改后的rsa.js文件,一般情况下不需要重新编译也可生效,如有问题就重新build或serve一下,需要注意的是,如果删除了node_modules文件夹,或重新安装了jsencrypt,或对jsencrypt进行了版本升级,该功能均会失效,需要重新修改。jsencrypt版本更新后文中的行号可能不准确,请依照方法名进行修改。如有问题可在评论区留言。
到此就实现了jsencrypt使用公钥解密数据的功能,修改完成后建议锁定jsencrypt版本。
备注
发现评论区反映有些人修改后有效,有些人修改后不生效,追加以下说明:
只有在使用Jetbrains系开发工具(IntelliJ IDEA、WebStorm),并且使用npm管理项目依赖时可以通过直接更改文件的方式使该修改生效,使用VSCode或使用pnpm等工具的,直接修改文件无法生效,需要使用patch-package工具对jsencrypt进行补丁操作。
操作如下:
1. 安装patch-package
npm install patch-package -D
2. 按照上述方法修改jsencrypt相关文件
3. 执行命令
npx patch-package jsencrypt
4. 运行或构建,查看修改是否生效