0%

JSEncrypt添加NOPadding填充

JSEncrypt添加NOPadding填充

JSEncrypt是一个加密库,支持RSA加密,但是只有PKCS1的填充模式

之前了解到NOPadding的填充是在明文前面填充字节0,如果我想实现的话就可以进行手动填充

打个断点进去

image-20241118201358518

结果在这直接return了,从这里进去

image-20241118201651343

导出了一个方法,这个方法是用来将 hex 的十六进制数据转换成 base64 编码

image-20241118202056572

继续进,getkey 方法是检验之前是否传入了key,不管,继续

image-20241118202319995

进入加密方法,这个是关键方法

maxLength 是检测最大字符长度,不用管他,PKSC1Padding 和 NOPadding 都需要这个数

经过 pkcs2 处理后进行判断是否有内容,有内容就进行加密,然后进行hex编码,再进行hex转base64将结果返回。

image-20241118202631605

这里就直接进PKSC1模式进行加密了,可以在这里加一个判断,让用户多传进来一个字符串,来判断模式,这样就可以二者兼得

开始尝试,依照pkcs写Nopadding照葫芦画瓢了

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
// NOPadding (type1, byte[0]) pad input string s to n byte[n] array, and return a bigint
// 入乡随俗了老铁
function nopkcs(s, n) {
if (n < s.length) {
console.error("Message too long for RSA")
return null;
}
var ba = [];
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;
}
}
// 前面的都一样,但是处理完数据之后,就该填充0了,这时候就不一样了
while (n > 0) {
ba[--n] = 0;
}
return new BigInteger(ba);
}

添一个判断model的逻辑

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
RSAKey.prototype.encrypt = function (text, model) {
var maxLength = (this.n.bitLength() + 7) >> 3;
var m;
// 还是保留默认是PKCS#1
if (model == "PKCSPadding" || model == undefined || model == null) {
m = pkcs1pad2(text, maxLength);
} else if (model == "NOPadding") {
m = nopkcs(text, maxLength)
} else {
console.error("Invalid padding model");
return null;
}

if (m == null) {
return null;
}
var c = this.doPublic(m);
if (c == null) {
return null;
}
var h = c.toString(16);
var length = h.length;
// fix zero before result
for (var i = 0; i < maxLength * 2 - length; i++) {
h = "0" + h;
}
return h;
};

更改传入值,可以发现这之只是改了加密,还没改解密,不着急,先让这个传入两个参数,base形式的就先放一放

image-20241118210735767

在相应的文件中更改,打断点调试的时候还是源代码,待我稍作思量,更益其巧

找到这个文件,上面有各个文件的信息啥的,代码没有被解析,怎么说呢,直接改吧

image-20241119145222944

调用时,多接收一个参数

image-20241118211817786

// 处理

1
2
3
4
5
6
判断方法
\n var m;\n // 还是保留默认的是PKCS#1\n if (model == 'PKCSPadding' || model == undefined || model == null) {/n m = pkcs1pad2(text, maxLength);/n } else if (model == 'NOPadding') {\n m = nopkcs(text, maxLength);\n } else {\n console.error('Invalid padding model');\n returm null;\n }


Nopadding填充操作
function nopkcs(s, n) {\n if (n < s.length) {\n console.error('Message too long for RSA');\n return null;\n }\n var ba = [];\n var i = s.length - 1;\n while (i >= 0 && n > 0) {\n var c = s.charCodeAt(i--);\n if (c < 128) {\n ba[--n] = c;\n }\n else if ((c > 127) && (c < 2024)) {\n ba[--n] = (c & 63) | 128;\n ba[--n] = (c >> 6) | 192;\n }\n else {\n ba[--n] = (c & 63) | 128;\n ba[--n] = ((c >> 6) & 63) | 128;\n ba[--n] = (c >> 12) | 224;\n } \n }\n // 前面的都一样,但是处理完数据之后,就改填充0了,这时候就比PKSC简单了\n while (--n > 0) {\n ba[--n] = 0;\n }\n return new _jsbn__WEBPACK_IMPORTED_MODULE_0__.BigInteger(ba);\n}

大功告成

image-20241119144624973

验证一下

无需多言,还有解密

image-20241119145500510

接下来写NOPadding的解密

和加密的套路差不多,先检验是否有私钥,然后获取 base64转hex 的方法,将密文转成hex

image-20241119153831614

然后就是重点了

image-20241119154429072

这个C是处理hex数据的和解密无关,m我也看了一下直接用就行,真正处理的在 return上,这样也省事了,开始微操

加一个判断,通过打断点发现,这个m比较短,也就是说很可能就是明文的一种编码,反复实验之后先将这个 BigInteger 类型的数据转换成 byte 数组,然后将byte数组转换成utf-8的数据,有点弯弯绕。

image-20241119165204122

1
2
3
4
5
6
7
8
>return m;
>BigInteger { '0': 53753142, '1': 201507, s: 0, t: 2 }

>return m.toByteArray();
>[ 49, 50, 51, 52, 53, 54 ]

>return String.fromCharCode.apply(null, m.toByteArray());
>123456

需要更改的位置有

这个是调试视图,去那一堆没解析的乱码里去改!就不放图片了

image-20241119165810685

如此这般,NOPadding填充模式就完成了