Skip to content

Commit

Permalink
fix decryptLong with Chinese and optimize encryptLong
Browse files Browse the repository at this point in the history
  • Loading branch information
Neo committed Aug 31, 2021
1 parent 4da237e commit b15dfb5
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 67 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ npm i wxmp-rsa -S
```

### 3、使用方式
小程序使用之前需先使用开发者工具构建npm
小程序使用之前需先使用开发者工具[构建npm](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html)
```js
// 导入包
import WxmpRsa from 'wxmp-rsa'
Expand Down Expand Up @@ -62,14 +62,16 @@ rsa.setPrivateKey(privateKey)
const originalStr = rsa.decryptLong(cryptStr)
console.log('解密后的原始数据:', originalStr)
```
其他api参考jsencrypt插件:https://github.com/travist/jsencrypt
其他api参考[jsencrypt](https://github.com/travist/jsencrypt)插件

### 4、注意事项
+ 填空方式默认`pkcs1`,目前暂不支持其它填空方式。
+ 之前版本中偶现的加密异常的问题已修复。
+ v2.0.1版本的解密存在问题:使用本插件解密中英文混杂的数据时可能出现部分中文乱码的情况,尚待修复。

### 5、测试
### 5、更新提示
+ 之前偶现的加密异常的问题已于v2.0.0+版本中修复。
+ 之前偶现的解密后部分中文乱码的问题已于v2.1.0+版本中修复。

### 6、测试对比
推荐两个第三方rsa工具,仅供参考。
+ 在线生成rsa公私钥:http://travistidwell.com/jsencrypt/demo/ (推荐1024长度的密钥)
+ 在线rsa加解密:http://www.toolzl.com/tools/testrsa.html (117超长加密,128超长解密)
36 changes: 7 additions & 29 deletions dist/JSEncrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,44 +86,22 @@ var JSEncrypt = /** @class */ (function () {
}
};
// 超长文本加密
JSEncrypt.prototype.encryptLong = function (text, count) {
var _this = this;
count = count || 0;
var res = '';
var maxLen = ((this.getKey().n.bitLength() + 7) >> 3) - 11;
if (text.length > maxLen) {
var textArr = text.match(new RegExp('.{1,' + Math.floor(maxLen / 3) + '}', 'g'));
textArr.forEach(function (v) {
res += _this.getKey().encrypt(v);
});
}
else {
res = this.getKey().encrypt(text);
}
JSEncrypt.prototype.encryptLong = function (str) {
try {
res = hex2b64(res);
return hex2b64(this.getKey().encryptLong(str));
}
catch (ex) {
return false;
}
return res;
};
// 超长文本解密
JSEncrypt.prototype.decryptLong = function (text) {
var _this = this;
var res = '';
var maxLen = (this.getKey().n.bitLength() + 7) >> 3;
var hexText = b64tohex(text);
if (hexText.length > maxLen) {
var hexTextArr = hexText.match(new RegExp('.{1,' + maxLen * 2 + '}', 'g'));
hexTextArr.forEach(function (v) {
res += _this.getKey().decrypt(v);
});
JSEncrypt.prototype.decryptLong = function (str) {
try {
return this.getKey().decryptLong(b64tohex(str));
}
else {
res = this.getKey().decrypt(hexText);
catch (ex) {
return false;
}
return res;
};
/**
* Proxy method for RSAKey object's sign.
Expand Down
98 changes: 98 additions & 0 deletions dist/lib/jsbn/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,65 @@ var RSAKey = /** @class */ (function () {
var digest = removeDigestHeader(unpadded);
return digest == digestMethod(text).toString();
};
RSAKey.prototype.encryptLong = function (text) {
var _this = this;
var res = '';
var maxLen = ((this.n.bitLength() + 7) >> 3) - 11;
var textArr = this.setSplitChn(text, maxLen);
textArr.forEach(function (v) {
res += _this.encrypt(v);
});
return res;
};
RSAKey.prototype.decryptLong = function (ctext) {
var res = '';
var maxLen = (this.n.bitLength() + 7) >> 3;
var splitMaxLen = maxLen * 2;
if (ctext.length > splitMaxLen) {
var ctextArr = ctext.match(new RegExp('.{1,' + splitMaxLen + '}', 'g')) || [];
var mArr = [];
for (var i = 0; i < ctextArr.length; i++) {
var c = parseBigInt(ctextArr[i], 16);
var m = this.doPrivate(c);
if (m == null) {
return null;
}
mArr.push(m);
}
res = pkcs1unpad2Long(mArr, maxLen);
}
else {
res = this.decrypt(ctext);
}
return res;
};
RSAKey.prototype.setSplitChn = function (str, maxLen, res) {
if (res === void 0) { res = []; }
var arr = str.split('');
var len = 0;
for (var i = 0; i < arr.length; i++) {
var charCode = arr[i].charCodeAt(0);
if (charCode <= 0x007f) {
len += 1;
}
else if (charCode <= 0x07ff) {
len += 2;
}
else if (charCode <= 0xffff) {
len += 3;
}
else {
len += 4;
}
if (len > maxLen) {
var currentStr = str.substring(0, i);
res.push(currentStr);
return this.setSplitChn(str.substring(i), maxLen, res);
}
}
res.push(str);
return res;
};
return RSAKey;
}());
export { RSAKey };
Expand Down Expand Up @@ -338,6 +397,45 @@ function pkcs1unpad2(d, n) {
}
return ret;
}
function pkcs1unpad2Long(dArr, n) {
var bArr = [];
for (var j = 0; j < dArr.length; j++) {
var d = dArr[j];
var b_1 = d.toByteArray();
var i_1 = 0;
while (i_1 < b_1.length && b_1[i_1] == 0) {
++i_1;
}
if (b_1.length - i_1 != n - 1 || b_1[i_1] != 2) {
return null;
}
++i_1;
while (b_1[i_1] != 0) {
if (++i_1 >= b_1.length) {
return null;
}
}
bArr = bArr.concat(b_1.slice(i_1 + 1));
}
var b = bArr;
var i = -1;
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;
}
// https://tools.ietf.org/html/rfc3447#page-43
var DIGEST_HEADERS = {
md2: "3020300c06082a864886f70d020205000410",
Expand Down
2 changes: 1 addition & 1 deletion dist/version.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": ""
"version": "3.2.1"
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wxmp-rsa",
"version": "2.0.1",
"version": "2.1.0",
"description": "兼容小程序环境的rsa加解密库,支持超长文本和中文字符",
"author": "neohan",
"main": "dist/index.js",
Expand Down
38 changes: 10 additions & 28 deletions src/JSEncrypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,42 +100,24 @@ export class JSEncrypt {
return false;
}
}

// 超长文本加密
public encryptLong (text: string, count?: number) {
count = count || 0
let res: string = ''
const maxLen = ((this.getKey().n.bitLength() + 7) >> 3) - 11
const splitMax = Math.floor(maxLen / 3)
if (text.length > splitMax) {
const textArr = text.match(new RegExp('.{1,' + splitMax + '}', 'g'))
textArr.forEach(v => {
res += this.getKey().encrypt(v)
})
} else {
res = this.getKey().encrypt(text)
}
public encryptLong (str: string) {
try {
res = hex2b64(res)
return hex2b64(this.getKey().encryptLong(str));
} catch (ex) {
return false
return false;
}
return res
}
// 超长文本解密
public decryptLong (text: string) {
let res: string = ''
const maxLen = (this.getKey().n.bitLength() + 7) >> 3
const hexText = b64tohex(text)
if (hexText.length > maxLen) {
const hexTextArr = hexText.match(new RegExp('.{1,' + maxLen * 2 + '}', 'g'))
hexTextArr.forEach(v => {
res += this.getKey().decrypt(v)
})
} else {
res = this.getKey().decrypt(hexText)
public decryptLong (str: string) {
try {
return this.getKey().decryptLong(b64tohex(str));
} catch (ex) {
return false;
}
return res
}

/**
* Proxy method for RSAKey object's sign.
* @param {string} str the string to sign
Expand Down
90 changes: 88 additions & 2 deletions src/lib/jsbn/rsa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,63 @@ export class RSAKey {
return digest == digestMethod(text).toString();
}

public encryptLong (text: string) {
let res = ''
const maxLen = ((this.n.bitLength() + 7) >> 3) - 11
const textArr = this.setSplitChn(text, maxLen)
textArr.forEach(v => {
res += this.encrypt(v)
})
return res
}
public decryptLong (ctext: string) {
let res = ''
const maxLen = (this.n.bitLength() + 7) >> 3
const splitMaxLen = maxLen * 2
if (ctext.length > splitMaxLen) {
const ctextArr = ctext.match(new RegExp('.{1,' + splitMaxLen + '}', 'g')) || []
const mArr = []
for (let i = 0; i < ctextArr.length; i++) {
const c = parseBigInt(ctextArr[i], 16);
const m = this.doPrivate(c);
if (m == null) { return null; }
mArr.push(m)
}
res = pkcs1unpad2Long(mArr, maxLen);
} else {
res = this.decrypt(ctext)
}
return res
}
private setSplitChn (str: string, maxLen: number, res: string[] = []): string[] {
const arr = str.split('')
let len = 0
for (let i = 0; i < arr.length; i++) {
const charCode = arr[i].charCodeAt(0)
if (charCode <= 0x007f) {
len += 1
} else if(charCode <= 0x07ff){
len += 2
} else if(charCode <= 0xffff){
len += 3
} else{
len += 4
}
if (len > maxLen) {
const currentStr = str.substring(0, i)
res.push(currentStr)
return this.setSplitChn(str.substring(i), maxLen, res)
}
}
res.push(str)
return res
}

//#endregion PUBLIC

public n:BigInteger;
protected n:BigInteger;
protected e:number;
public d:BigInteger;
protected d:BigInteger;
protected p:BigInteger;
protected q:BigInteger;
protected dmp1:BigInteger;
Expand Down Expand Up @@ -364,6 +416,40 @@ function pkcs1unpad2(d:BigInteger, n:number):string {
return ret;
}

function pkcs1unpad2Long (dArr: BigInteger[], n: number): string {
let bArr: number[] = []
for (let j = 0; j < dArr.length; j++) {
const d = dArr[j]
const b = d.toByteArray();
let 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; }
}
bArr = bArr.concat(b.slice(i + 1))
}
const b = bArr
let i = -1
let ret = "";
while (++i < b.length) {
const 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;
}

// https://tools.ietf.org/html/rfc3447#page-43
const DIGEST_HEADERS:{ [name:string]:string } = {
md2: "3020300c06082a864886f70d020205000410",
Expand Down

0 comments on commit b15dfb5

Please sign in to comment.