问题描述

近日,在实现api加密传输需求的过程中,需要使用jsencrypt进行公钥解密,但是jsencrypt原生不支持该功能,仅支持使用私钥解密

jsencrypt原生不支持使用公钥解密数据,但是可以通过对jsencrypt的源码进行修改,从而实现使用jsencrypt进行公钥解密的需求。

问题解决

  1. 首先,需要安装一个npm插件patch-package

    1
    npm install patch-package -D
  2. 进入你的node_modules目录下,根据如下路径找到rsa.js文件

  3. 进入jsencrypt/lib/lib/jsbn/rsa.js

  4. 在rsa.js文件中,第207行附近的RSAKey.prototype.decrypt方法中,将 this.doPrivate(c) 改为 this.doPublic(c)。如下代码所示。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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);
    };
  5. 同样在rsa.js文件中,找到第310行附近的pkcs1unpad2方法,并将这三行代码注释。参照如下代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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;
    }
  6. 保存修改后的rsa.js文件。

  7. 执行命令构建持久化补丁。

    1
    npx patch-package jsencrypt
  8. 完成后,你的相关修改就以补丁的形式保留在你的项目中了,及时是将代码与别人协作,或删除了node_modules重新拉取,都不会影响本次修改,除非你删除了补丁文件。

建议完成修改后,锁定一下jsencrypt的版本,以免出现较大更新后补丁失效。

到此就实现了jsencrypt使用公钥解密数据的功能。