sm-crypto-v2 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +19 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +81 -15
- package/dist/index.mjs +81 -15
- package/package.json +3 -1
- package/src/sm2/asn1.ts +50 -1
- package/src/sm2/index.ts +60 -17
- package/src/sm2/utils.ts +6 -5
- package/src/sm3/index.ts +1 -1
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,20 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
4
4
|
|
5
|
+
## [1.8.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.7.0...v1.8.0) (2023-12-15)
|
6
|
+
|
7
|
+
|
8
|
+
### Features
|
9
|
+
|
10
|
+
* **sm2:** support asn1 der encoded encryption/decryption ([f08b9fd](https://github.com/Cubelrti/sm-crypto-v2/commit/f08b9fd5b64a2a257d41694c1858d7a6b07326ae))
|
11
|
+
|
12
|
+
## [1.7.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.6.0...v1.7.0) (2023-07-17)
|
13
|
+
|
14
|
+
|
15
|
+
### Features
|
16
|
+
|
17
|
+
* **sm2:** support precompute sm2 point ([ae347bf](https://github.com/Cubelrti/sm-crypto-v2/commit/ae347bfff6c306318276a31f5958290ac7f07b9c))
|
18
|
+
|
5
19
|
## [1.6.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.5.1...v1.6.0) (2023-07-11)
|
6
20
|
|
7
21
|
|
package/README.md
CHANGED
@@ -57,9 +57,11 @@ verifyResult = sm2.verifyPublicKey(compressedPublicKey) // 验证公钥
|
|
57
57
|
```js
|
58
58
|
import { sm2 } from 'sm-crypto-v2'
|
59
59
|
const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3,默认为1
|
60
|
+
// 支持使用 asn1 对加密结果进行编码,在 options 参数中传入 { asn1: true } 即可,默认不开启
|
61
|
+
let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode, { asn1: false }) // 加密结果
|
60
62
|
|
61
|
-
|
62
|
-
let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode) // 解密结果
|
63
|
+
// 支持使用 asn1 对密文进行解码再解密,在 options 参数中传入 { asn1: true } 即可,默认不开启
|
64
|
+
let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode, { asn1: false }) // 解密结果
|
63
65
|
|
64
66
|
encryptData = sm2.doEncrypt(msgArray, publicKey, cipherMode) // 加密结果,输入数组
|
65
67
|
decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode, {output: 'array'}) // 解密结果,输出数组
|
@@ -127,6 +129,21 @@ import { sm2 } from 'sm-crypto-v2'
|
|
127
129
|
let point = sm2.getPoint() // 获取一个椭圆曲线点,可在sm2签名时传入
|
128
130
|
```
|
129
131
|
|
132
|
+
### 预计算公钥
|
133
|
+
|
134
|
+
```js
|
135
|
+
import { sm2 } from 'sm-crypto-v2'
|
136
|
+
let keypair = sm2.generateKeyPairHex()
|
137
|
+
|
138
|
+
const precomputedPublicKey = sm2.precomputePublicKey(keypair.publicKey)
|
139
|
+
// 加密和验签可以传入预计算后的点
|
140
|
+
let encryptData = sm2.doEncrypt(msgString, precomputedPublicKey, cipherMode) // 加密结果
|
141
|
+
let verifyResult4 = sm2.doVerifySignature(msg, sigValueHex4, precomputedPublicKey, {
|
142
|
+
hash: true,
|
143
|
+
}) // 验签结果
|
144
|
+
|
145
|
+
```
|
146
|
+
|
130
147
|
## sm3
|
131
148
|
|
132
149
|
```js
|
package/dist/index.d.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import { ProjPointType } from '@noble/curves/abstract/weierstrass';
|
2
|
+
|
1
3
|
interface KeyPair {
|
2
4
|
privateKey: string;
|
3
5
|
publicKey: string;
|
@@ -47,15 +49,19 @@ declare const EmptyArray: Uint8Array;
|
|
47
49
|
/**
|
48
50
|
* 加密
|
49
51
|
*/
|
50
|
-
declare function doEncrypt(msg: string | Uint8Array, publicKey: string
|
52
|
+
declare function doEncrypt(msg: string | Uint8Array, publicKey: string | ProjPointType<bigint>, cipherMode?: number, options?: {
|
53
|
+
asn1?: boolean;
|
54
|
+
}): string;
|
51
55
|
/**
|
52
56
|
* 解密
|
53
57
|
*/
|
54
58
|
declare function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
|
55
59
|
output: 'array';
|
60
|
+
asn1?: boolean;
|
56
61
|
}): Uint8Array;
|
57
62
|
declare function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
|
58
63
|
output: 'string';
|
64
|
+
asn1?: boolean;
|
59
65
|
}): string;
|
60
66
|
interface SignaturePoint {
|
61
67
|
k: bigint;
|
@@ -74,7 +80,7 @@ declare function doSignature(msg: Uint8Array | string, privateKey: string, optio
|
|
74
80
|
/**
|
75
81
|
* 验签
|
76
82
|
*/
|
77
|
-
declare function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string
|
83
|
+
declare function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string | ProjPointType<bigint>, options?: {
|
78
84
|
der?: boolean;
|
79
85
|
hash?: boolean;
|
80
86
|
userId?: string;
|
@@ -84,6 +90,14 @@ declare function getZ(publicKey: string, userId?: string): Uint8Array;
|
|
84
90
|
* sm3杂凑算法
|
85
91
|
*/
|
86
92
|
declare function getHash(hashHex: string | Uint8Array, publicKey: string, userId?: string): string;
|
93
|
+
/**
|
94
|
+
* 预计算公钥点,可用于提升加密性能
|
95
|
+
* @export
|
96
|
+
* @param {string} publicKey 公钥
|
97
|
+
* @param windowSize 计算窗口大小,默认为 8
|
98
|
+
* @returns {ProjPointType<bigint>} 预计算的点
|
99
|
+
*/
|
100
|
+
declare function precomputePublicKey(publicKey: string, windowSize?: number): ProjPointType<bigint>;
|
87
101
|
/**
|
88
102
|
* 计算公钥
|
89
103
|
*/
|
@@ -106,6 +120,7 @@ declare const index$1_doSignature: typeof doSignature;
|
|
106
120
|
declare const index$1_doVerifySignature: typeof doVerifySignature;
|
107
121
|
declare const index$1_getZ: typeof getZ;
|
108
122
|
declare const index$1_getHash: typeof getHash;
|
123
|
+
declare const index$1_precomputePublicKey: typeof precomputePublicKey;
|
109
124
|
declare const index$1_getPublicKeyFromPrivateKey: typeof getPublicKeyFromPrivateKey;
|
110
125
|
declare const index$1_getPoint: typeof getPoint;
|
111
126
|
declare const index$1_initRNGPool: typeof initRNGPool;
|
@@ -130,6 +145,7 @@ declare namespace index$1 {
|
|
130
145
|
index$1_doVerifySignature as doVerifySignature,
|
131
146
|
index$1_getZ as getZ,
|
132
147
|
index$1_getHash as getHash,
|
148
|
+
index$1_precomputePublicKey as precomputePublicKey,
|
133
149
|
index$1_getPublicKeyFromPrivateKey as getPublicKeyFromPrivateKey,
|
134
150
|
index$1_getPoint as getPoint,
|
135
151
|
index$1_initRNGPool as initRNGPool,
|
package/dist/index.js
CHANGED
@@ -53,6 +53,7 @@ __export(sm2_exports, {
|
|
53
53
|
hexToArray: () => hexToArray,
|
54
54
|
initRNGPool: () => initRNGPool,
|
55
55
|
leftPad: () => leftPad,
|
56
|
+
precomputePublicKey: () => precomputePublicKey,
|
56
57
|
utf8ToHex: () => utf8ToHex,
|
57
58
|
verifyPublicKey: () => verifyPublicKey
|
58
59
|
});
|
@@ -132,6 +133,19 @@ var DERInteger = class extends ASN1Object {
|
|
132
133
|
return this.v;
|
133
134
|
}
|
134
135
|
};
|
136
|
+
var DEROctetString = class extends ASN1Object {
|
137
|
+
constructor(s) {
|
138
|
+
super();
|
139
|
+
this.s = s;
|
140
|
+
this.t = "04";
|
141
|
+
if (s)
|
142
|
+
this.v = s.toLowerCase();
|
143
|
+
}
|
144
|
+
hV = "";
|
145
|
+
getValue() {
|
146
|
+
return this.v;
|
147
|
+
}
|
148
|
+
};
|
135
149
|
var DERSequence = class extends ASN1Object {
|
136
150
|
constructor(asn1Array) {
|
137
151
|
super();
|
@@ -166,11 +180,19 @@ function encodeDer(r, s) {
|
|
166
180
|
const derSeq = new DERSequence([derR, derS]);
|
167
181
|
return derSeq.getEncodedHex();
|
168
182
|
}
|
183
|
+
function encodeEnc(x2, y, hash, cipher) {
|
184
|
+
const derX = new DERInteger(x2);
|
185
|
+
const derY = new DERInteger(y);
|
186
|
+
const derHash = new DEROctetString(hash);
|
187
|
+
const derCipher = new DEROctetString(cipher);
|
188
|
+
const derSeq = new DERSequence([derX, derY, derHash, derCipher]);
|
189
|
+
return derSeq.getEncodedHex();
|
190
|
+
}
|
169
191
|
function decodeDer(input) {
|
170
192
|
const start = getStartOfV(input, 0);
|
171
193
|
const vIndexR = getStartOfV(input, start);
|
172
194
|
const lR = getL(input, start);
|
173
|
-
const vR = input.
|
195
|
+
const vR = input.substring(vIndexR, vIndexR + lR * 2);
|
174
196
|
const nextStart = vIndexR + vR.length;
|
175
197
|
const vIndexS = getStartOfV(input, nextStart);
|
176
198
|
const lS = getL(input, nextStart);
|
@@ -179,6 +201,23 @@ function decodeDer(input) {
|
|
179
201
|
const s = utils.hexToNumber(vS);
|
180
202
|
return { r, s };
|
181
203
|
}
|
204
|
+
function decodeEnc(input) {
|
205
|
+
function extractSequence(input2, start2) {
|
206
|
+
const vIndex = getStartOfV(input2, start2);
|
207
|
+
const length = getL(input2, start2);
|
208
|
+
const value = input2.substring(vIndex, vIndex + length * 2);
|
209
|
+
const nextStart = vIndex + value.length;
|
210
|
+
return { value, nextStart };
|
211
|
+
}
|
212
|
+
const start = getStartOfV(input, 0);
|
213
|
+
const { value: vR, nextStart: startS } = extractSequence(input, start);
|
214
|
+
const { value: vS, nextStart: startHash } = extractSequence(input, startS);
|
215
|
+
const { value: hash, nextStart: startCipher } = extractSequence(input, startHash);
|
216
|
+
const { value: cipher } = extractSequence(input, startCipher);
|
217
|
+
const x2 = utils.hexToNumber(vR);
|
218
|
+
const y = utils.hexToNumber(vS);
|
219
|
+
return { x: x2, y, hash, cipher };
|
220
|
+
}
|
182
221
|
|
183
222
|
// src/sm2/utils.ts
|
184
223
|
var utils2 = __toESM(require("@noble/curves/abstract/utils"));
|
@@ -640,9 +679,12 @@ function verifyPublicKey(publicKey) {
|
|
640
679
|
const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
641
680
|
if (!point)
|
642
681
|
return false;
|
643
|
-
|
644
|
-
|
645
|
-
|
682
|
+
try {
|
683
|
+
point.assertValidity();
|
684
|
+
return true;
|
685
|
+
} catch (error) {
|
686
|
+
return false;
|
687
|
+
}
|
646
688
|
}
|
647
689
|
function comparePublicKeyHex(publicKey1, publicKey2) {
|
648
690
|
const point1 = sm2Curve.ProjectivePoint.fromHex(publicKey1);
|
@@ -710,9 +752,9 @@ function calculateSharedKey(keypairA, ephemeralKeypairA, publicKeyB, ephemeralPu
|
|
710
752
|
// src/sm2/index.ts
|
711
753
|
var C1C2C3 = 0;
|
712
754
|
var EmptyArray = new Uint8Array();
|
713
|
-
function doEncrypt(msg, publicKey, cipherMode = 1) {
|
755
|
+
function doEncrypt(msg, publicKey, cipherMode = 1, options) {
|
714
756
|
const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
|
715
|
-
const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
757
|
+
const publicKeyPoint = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
|
716
758
|
const keypair = generateKeyPairHex();
|
717
759
|
const k = utils4.hexToNumber(keypair.privateKey);
|
718
760
|
let c1 = keypair.publicKey;
|
@@ -724,6 +766,11 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
|
|
724
766
|
const c3 = bytesToHex(sm3(utils4.concatBytes(x2, msgArr, y2)));
|
725
767
|
xorCipherStream(x2, y2, msgArr);
|
726
768
|
const c2 = bytesToHex(msgArr);
|
769
|
+
if (options?.asn1) {
|
770
|
+
const point = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
|
771
|
+
const encode = cipherMode === C1C2C3 ? encodeEnc(point.x, point.y, c2, c3) : encodeEnc(point.x, point.y, c3, c2);
|
772
|
+
return encode;
|
773
|
+
}
|
727
774
|
return cipherMode === C1C2C3 ? c1 + c2 + c3 : c1 + c3 + c2;
|
728
775
|
}
|
729
776
|
function xorCipherStream(x2, y2, msg) {
|
@@ -748,17 +795,31 @@ function xorCipherStream(x2, y2, msg) {
|
|
748
795
|
}
|
749
796
|
}
|
750
797
|
function doDecrypt(encryptData, privateKey, cipherMode = 1, {
|
751
|
-
output = "string"
|
798
|
+
output = "string",
|
799
|
+
asn1 = false
|
752
800
|
} = {}) {
|
753
801
|
const privateKeyInteger = utils4.hexToNumber(privateKey);
|
754
|
-
let
|
755
|
-
let c2
|
756
|
-
|
757
|
-
|
758
|
-
|
802
|
+
let c1;
|
803
|
+
let c2;
|
804
|
+
let c3;
|
805
|
+
if (asn1) {
|
806
|
+
const { x: x3, y, cipher, hash } = decodeEnc(encryptData);
|
807
|
+
c1 = sm2Curve.ProjectivePoint.fromAffine({ x: x3, y });
|
808
|
+
c3 = hash;
|
809
|
+
c2 = cipher;
|
810
|
+
if (cipherMode === C1C2C3) {
|
811
|
+
[c2, c3] = [c3, c2];
|
812
|
+
}
|
813
|
+
} else {
|
814
|
+
c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
|
815
|
+
c3 = encryptData.substring(128, 128 + 64);
|
816
|
+
c2 = encryptData.substring(128 + 64);
|
817
|
+
if (cipherMode === C1C2C3) {
|
818
|
+
c3 = encryptData.substring(encryptData.length - 64);
|
819
|
+
c2 = encryptData.substring(128, encryptData.length - 64);
|
820
|
+
}
|
759
821
|
}
|
760
822
|
const msg = hexToArray(c2);
|
761
|
-
const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
|
762
823
|
const p = c1.multiply(privateKeyInteger);
|
763
824
|
const x2 = hexToArray(leftPad(utils4.numberToHexUnpadded(p.x), 64));
|
764
825
|
const y2 = hexToArray(leftPad(utils4.numberToHexUnpadded(p.y), 64));
|
@@ -812,8 +873,9 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
812
873
|
der,
|
813
874
|
userId
|
814
875
|
} = options;
|
876
|
+
const publicKeyHex = typeof publicKey === "string" ? publicKey : publicKey.toHex(false);
|
815
877
|
if (hash) {
|
816
|
-
hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg,
|
878
|
+
hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg, publicKeyHex, userId);
|
817
879
|
} else {
|
818
880
|
hashHex = typeof msg === "string" ? utf8ToHex(msg) : arrayToHex(Array.from(msg));
|
819
881
|
}
|
@@ -827,7 +889,7 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
827
889
|
r = utils4.hexToNumber(signHex.substring(0, 64));
|
828
890
|
s = utils4.hexToNumber(signHex.substring(64));
|
829
891
|
}
|
830
|
-
const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
892
|
+
const PA = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
|
831
893
|
const e = utils4.hexToNumber(hashHex);
|
832
894
|
const t = field.add(r, s);
|
833
895
|
if (t === ZERO)
|
@@ -861,6 +923,10 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
|
861
923
|
const z = getZ(publicKey, userId);
|
862
924
|
return bytesToHex(sm3(utils4.concatBytes(z, typeof hashHex === "string" ? hexToArray(hashHex) : hashHex)));
|
863
925
|
}
|
926
|
+
function precomputePublicKey(publicKey, windowSize) {
|
927
|
+
const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
928
|
+
return sm2Curve.utils.precompute(windowSize, point);
|
929
|
+
}
|
864
930
|
function getPublicKeyFromPrivateKey(privateKey) {
|
865
931
|
const pubKey = sm2Curve.getPublicKey(privateKey, false);
|
866
932
|
const pubPad = leftPad(utils4.bytesToHex(pubKey), 64);
|
package/dist/index.mjs
CHANGED
@@ -25,6 +25,7 @@ __export(sm2_exports, {
|
|
25
25
|
hexToArray: () => hexToArray,
|
26
26
|
initRNGPool: () => initRNGPool,
|
27
27
|
leftPad: () => leftPad,
|
28
|
+
precomputePublicKey: () => precomputePublicKey,
|
28
29
|
utf8ToHex: () => utf8ToHex,
|
29
30
|
verifyPublicKey: () => verifyPublicKey
|
30
31
|
});
|
@@ -104,6 +105,19 @@ var DERInteger = class extends ASN1Object {
|
|
104
105
|
return this.v;
|
105
106
|
}
|
106
107
|
};
|
108
|
+
var DEROctetString = class extends ASN1Object {
|
109
|
+
constructor(s) {
|
110
|
+
super();
|
111
|
+
this.s = s;
|
112
|
+
this.t = "04";
|
113
|
+
if (s)
|
114
|
+
this.v = s.toLowerCase();
|
115
|
+
}
|
116
|
+
hV = "";
|
117
|
+
getValue() {
|
118
|
+
return this.v;
|
119
|
+
}
|
120
|
+
};
|
107
121
|
var DERSequence = class extends ASN1Object {
|
108
122
|
constructor(asn1Array) {
|
109
123
|
super();
|
@@ -138,11 +152,19 @@ function encodeDer(r, s) {
|
|
138
152
|
const derSeq = new DERSequence([derR, derS]);
|
139
153
|
return derSeq.getEncodedHex();
|
140
154
|
}
|
155
|
+
function encodeEnc(x2, y, hash, cipher) {
|
156
|
+
const derX = new DERInteger(x2);
|
157
|
+
const derY = new DERInteger(y);
|
158
|
+
const derHash = new DEROctetString(hash);
|
159
|
+
const derCipher = new DEROctetString(cipher);
|
160
|
+
const derSeq = new DERSequence([derX, derY, derHash, derCipher]);
|
161
|
+
return derSeq.getEncodedHex();
|
162
|
+
}
|
141
163
|
function decodeDer(input) {
|
142
164
|
const start = getStartOfV(input, 0);
|
143
165
|
const vIndexR = getStartOfV(input, start);
|
144
166
|
const lR = getL(input, start);
|
145
|
-
const vR = input.
|
167
|
+
const vR = input.substring(vIndexR, vIndexR + lR * 2);
|
146
168
|
const nextStart = vIndexR + vR.length;
|
147
169
|
const vIndexS = getStartOfV(input, nextStart);
|
148
170
|
const lS = getL(input, nextStart);
|
@@ -151,6 +173,23 @@ function decodeDer(input) {
|
|
151
173
|
const s = utils.hexToNumber(vS);
|
152
174
|
return { r, s };
|
153
175
|
}
|
176
|
+
function decodeEnc(input) {
|
177
|
+
function extractSequence(input2, start2) {
|
178
|
+
const vIndex = getStartOfV(input2, start2);
|
179
|
+
const length = getL(input2, start2);
|
180
|
+
const value = input2.substring(vIndex, vIndex + length * 2);
|
181
|
+
const nextStart = vIndex + value.length;
|
182
|
+
return { value, nextStart };
|
183
|
+
}
|
184
|
+
const start = getStartOfV(input, 0);
|
185
|
+
const { value: vR, nextStart: startS } = extractSequence(input, start);
|
186
|
+
const { value: vS, nextStart: startHash } = extractSequence(input, startS);
|
187
|
+
const { value: hash, nextStart: startCipher } = extractSequence(input, startHash);
|
188
|
+
const { value: cipher } = extractSequence(input, startCipher);
|
189
|
+
const x2 = utils.hexToNumber(vR);
|
190
|
+
const y = utils.hexToNumber(vS);
|
191
|
+
return { x: x2, y, hash, cipher };
|
192
|
+
}
|
154
193
|
|
155
194
|
// src/sm2/utils.ts
|
156
195
|
import * as utils2 from "@noble/curves/abstract/utils";
|
@@ -612,9 +651,12 @@ function verifyPublicKey(publicKey) {
|
|
612
651
|
const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
613
652
|
if (!point)
|
614
653
|
return false;
|
615
|
-
|
616
|
-
|
617
|
-
|
654
|
+
try {
|
655
|
+
point.assertValidity();
|
656
|
+
return true;
|
657
|
+
} catch (error) {
|
658
|
+
return false;
|
659
|
+
}
|
618
660
|
}
|
619
661
|
function comparePublicKeyHex(publicKey1, publicKey2) {
|
620
662
|
const point1 = sm2Curve.ProjectivePoint.fromHex(publicKey1);
|
@@ -682,9 +724,9 @@ function calculateSharedKey(keypairA, ephemeralKeypairA, publicKeyB, ephemeralPu
|
|
682
724
|
// src/sm2/index.ts
|
683
725
|
var C1C2C3 = 0;
|
684
726
|
var EmptyArray = new Uint8Array();
|
685
|
-
function doEncrypt(msg, publicKey, cipherMode = 1) {
|
727
|
+
function doEncrypt(msg, publicKey, cipherMode = 1, options) {
|
686
728
|
const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
|
687
|
-
const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
729
|
+
const publicKeyPoint = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
|
688
730
|
const keypair = generateKeyPairHex();
|
689
731
|
const k = utils4.hexToNumber(keypair.privateKey);
|
690
732
|
let c1 = keypair.publicKey;
|
@@ -696,6 +738,11 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
|
|
696
738
|
const c3 = bytesToHex(sm3(utils4.concatBytes(x2, msgArr, y2)));
|
697
739
|
xorCipherStream(x2, y2, msgArr);
|
698
740
|
const c2 = bytesToHex(msgArr);
|
741
|
+
if (options?.asn1) {
|
742
|
+
const point = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
|
743
|
+
const encode = cipherMode === C1C2C3 ? encodeEnc(point.x, point.y, c2, c3) : encodeEnc(point.x, point.y, c3, c2);
|
744
|
+
return encode;
|
745
|
+
}
|
699
746
|
return cipherMode === C1C2C3 ? c1 + c2 + c3 : c1 + c3 + c2;
|
700
747
|
}
|
701
748
|
function xorCipherStream(x2, y2, msg) {
|
@@ -720,17 +767,31 @@ function xorCipherStream(x2, y2, msg) {
|
|
720
767
|
}
|
721
768
|
}
|
722
769
|
function doDecrypt(encryptData, privateKey, cipherMode = 1, {
|
723
|
-
output = "string"
|
770
|
+
output = "string",
|
771
|
+
asn1 = false
|
724
772
|
} = {}) {
|
725
773
|
const privateKeyInteger = utils4.hexToNumber(privateKey);
|
726
|
-
let
|
727
|
-
let c2
|
728
|
-
|
729
|
-
|
730
|
-
|
774
|
+
let c1;
|
775
|
+
let c2;
|
776
|
+
let c3;
|
777
|
+
if (asn1) {
|
778
|
+
const { x: x3, y, cipher, hash } = decodeEnc(encryptData);
|
779
|
+
c1 = sm2Curve.ProjectivePoint.fromAffine({ x: x3, y });
|
780
|
+
c3 = hash;
|
781
|
+
c2 = cipher;
|
782
|
+
if (cipherMode === C1C2C3) {
|
783
|
+
[c2, c3] = [c3, c2];
|
784
|
+
}
|
785
|
+
} else {
|
786
|
+
c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
|
787
|
+
c3 = encryptData.substring(128, 128 + 64);
|
788
|
+
c2 = encryptData.substring(128 + 64);
|
789
|
+
if (cipherMode === C1C2C3) {
|
790
|
+
c3 = encryptData.substring(encryptData.length - 64);
|
791
|
+
c2 = encryptData.substring(128, encryptData.length - 64);
|
792
|
+
}
|
731
793
|
}
|
732
794
|
const msg = hexToArray(c2);
|
733
|
-
const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
|
734
795
|
const p = c1.multiply(privateKeyInteger);
|
735
796
|
const x2 = hexToArray(leftPad(utils4.numberToHexUnpadded(p.x), 64));
|
736
797
|
const y2 = hexToArray(leftPad(utils4.numberToHexUnpadded(p.y), 64));
|
@@ -784,8 +845,9 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
784
845
|
der,
|
785
846
|
userId
|
786
847
|
} = options;
|
848
|
+
const publicKeyHex = typeof publicKey === "string" ? publicKey : publicKey.toHex(false);
|
787
849
|
if (hash) {
|
788
|
-
hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg,
|
850
|
+
hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg, publicKeyHex, userId);
|
789
851
|
} else {
|
790
852
|
hashHex = typeof msg === "string" ? utf8ToHex(msg) : arrayToHex(Array.from(msg));
|
791
853
|
}
|
@@ -799,7 +861,7 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
799
861
|
r = utils4.hexToNumber(signHex.substring(0, 64));
|
800
862
|
s = utils4.hexToNumber(signHex.substring(64));
|
801
863
|
}
|
802
|
-
const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
864
|
+
const PA = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
|
803
865
|
const e = utils4.hexToNumber(hashHex);
|
804
866
|
const t = field.add(r, s);
|
805
867
|
if (t === ZERO)
|
@@ -833,6 +895,10 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
|
833
895
|
const z = getZ(publicKey, userId);
|
834
896
|
return bytesToHex(sm3(utils4.concatBytes(z, typeof hashHex === "string" ? hexToArray(hashHex) : hashHex)));
|
835
897
|
}
|
898
|
+
function precomputePublicKey(publicKey, windowSize) {
|
899
|
+
const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
900
|
+
return sm2Curve.utils.precompute(windowSize, point);
|
901
|
+
}
|
836
902
|
function getPublicKeyFromPrivateKey(privateKey) {
|
837
903
|
const pubKey = sm2Curve.getPublicKey(privateKey, false);
|
838
904
|
const pubPad = leftPad(utils4.bytesToHex(pubKey), 64);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "sm-crypto-v2",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.8.0",
|
4
4
|
"description": "sm-crypto-v2",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"module": "dist/index.mjs",
|
@@ -33,6 +33,7 @@
|
|
33
33
|
"@noble/curves": "^1.1.0"
|
34
34
|
},
|
35
35
|
"devDependencies": {
|
36
|
+
"@swc-node/register": "^1.6.6",
|
36
37
|
"@swc/core": "^1.3.62",
|
37
38
|
"@types/node": "^16",
|
38
39
|
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
@@ -40,6 +41,7 @@
|
|
40
41
|
"@vitest/coverage-c8": "^0.31.0",
|
41
42
|
"@vitest/coverage-istanbul": "^0.31.0",
|
42
43
|
"@vitest/expect": "^0.31.4",
|
44
|
+
"@vitest/runner": "^0.33.0",
|
43
45
|
"@vitest/ui": "^0.31.0",
|
44
46
|
"conventional-changelog-cli": "^2.2.2",
|
45
47
|
"eslint": "^8.15.0",
|
package/src/sm2/asn1.ts
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
import * as utils from '@noble/curves/abstract/utils';
|
4
4
|
import { ONE } from './bn';
|
5
|
+
import { utf8ToHex } from './utils';
|
5
6
|
|
6
7
|
export function bigintToValue(bigint: bigint) {
|
7
8
|
let h = bigint.toString(16)
|
@@ -81,6 +82,20 @@ class DERInteger extends ASN1Object {
|
|
81
82
|
}
|
82
83
|
}
|
83
84
|
|
85
|
+
class DEROctetString extends ASN1Object {
|
86
|
+
public hV: string = ''
|
87
|
+
constructor(public s: string) {
|
88
|
+
super()
|
89
|
+
|
90
|
+
this.t = '04' // octstr 标签说明
|
91
|
+
if (s) this.v = s.toLowerCase()
|
92
|
+
}
|
93
|
+
|
94
|
+
getValue() {
|
95
|
+
return this.v
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
84
99
|
class DERSequence extends ASN1Object {
|
85
100
|
public t = '30'
|
86
101
|
constructor(public asn1Array: ASN1Object[]) {
|
@@ -134,6 +149,14 @@ export function encodeDer(r: bigint, s: bigint) {
|
|
134
149
|
return derSeq.getEncodedHex()
|
135
150
|
}
|
136
151
|
|
152
|
+
export function encodeEnc(x: bigint, y: bigint, hash: string, cipher: string) {
|
153
|
+
const derX = new DERInteger(x)
|
154
|
+
const derY = new DERInteger(y)
|
155
|
+
const derHash = new DEROctetString(hash)
|
156
|
+
const derCipher = new DEROctetString(cipher)
|
157
|
+
const derSeq = new DERSequence([derX, derY, derHash, derCipher])
|
158
|
+
return derSeq.getEncodedHex()
|
159
|
+
}
|
137
160
|
/**
|
138
161
|
* 解析 ASN.1 der,针对 sm2 验签
|
139
162
|
*/
|
@@ -145,7 +168,7 @@ export function decodeDer(input: string) {
|
|
145
168
|
|
146
169
|
const vIndexR = getStartOfV(input, start)
|
147
170
|
const lR = getL(input, start)
|
148
|
-
const vR = input.
|
171
|
+
const vR = input.substring(vIndexR, vIndexR +lR * 2)
|
149
172
|
|
150
173
|
const nextStart = vIndexR + vR.length
|
151
174
|
const vIndexS = getStartOfV(input, nextStart)
|
@@ -159,3 +182,29 @@ export function decodeDer(input: string) {
|
|
159
182
|
|
160
183
|
return { r, s }
|
161
184
|
}
|
185
|
+
|
186
|
+
/**
|
187
|
+
* 解析 ASN.1 der,针对 sm2 加密
|
188
|
+
*/
|
189
|
+
export function decodeEnc(input: string) {
|
190
|
+
// Extracts a sequence from the input based on the current start index.
|
191
|
+
function extractSequence(input: string, start: number): { value: string; nextStart: number } {
|
192
|
+
const vIndex = getStartOfV(input, start);
|
193
|
+
const length = getL(input, start);
|
194
|
+
const value = input.substring(vIndex, vIndex + length * 2);
|
195
|
+
const nextStart = vIndex + value.length;
|
196
|
+
return { value, nextStart };
|
197
|
+
}
|
198
|
+
|
199
|
+
const start = getStartOfV(input, 0);
|
200
|
+
|
201
|
+
const { value: vR, nextStart: startS } = extractSequence(input, start);
|
202
|
+
const { value: vS, nextStart: startHash } = extractSequence(input, startS);
|
203
|
+
const { value: hash, nextStart: startCipher } = extractSequence(input, startHash);
|
204
|
+
const { value: cipher } = extractSequence(input, startCipher);
|
205
|
+
|
206
|
+
const x = utils.hexToNumber(vR);
|
207
|
+
const y = utils.hexToNumber(vS);
|
208
|
+
|
209
|
+
return { x, y, hash, cipher };
|
210
|
+
}
|
package/src/sm2/index.ts
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
/* eslint-disable no-use-before-define */
|
2
|
-
import { encodeDer, decodeDer } from './asn1'
|
2
|
+
import { encodeDer, decodeDer, encodeEnc, decodeEnc } from './asn1'
|
3
3
|
import { arrayToHex, arrayToUtf8, generateKeyPairHex, hexToArray, leftPad, utf8ToHex } from './utils'
|
4
4
|
import { sm3 } from './sm3'
|
5
5
|
import * as utils from '@noble/curves/abstract/utils';
|
6
6
|
import { field, sm2Curve } from './ec';
|
7
7
|
import { ONE, ZERO } from './bn';
|
8
8
|
import { bytesToHex } from '@/sm3/utils';
|
9
|
+
import { ProjPointType } from '@noble/curves/abstract/weierstrass';
|
9
10
|
|
10
11
|
export * from './utils'
|
11
12
|
export { initRNGPool } from './rng'
|
@@ -17,18 +18,22 @@ export const EmptyArray = new Uint8Array()
|
|
17
18
|
/**
|
18
19
|
* 加密
|
19
20
|
*/
|
20
|
-
export function doEncrypt(msg: string | Uint8Array, publicKey: string
|
21
|
+
export function doEncrypt(msg: string | Uint8Array, publicKey: string | ProjPointType<bigint>, cipherMode = 1, options?: {
|
22
|
+
asn1?: boolean // 使用 ASN.1 对 C1 编码
|
23
|
+
}) {
|
21
24
|
|
22
25
|
const msgArr = typeof msg === 'string' ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg)
|
23
|
-
const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey)
|
26
|
+
const publicKeyPoint = typeof publicKey === 'string' ? sm2Curve.ProjectivePoint.fromHex(publicKey) :
|
27
|
+
publicKey
|
24
28
|
|
25
29
|
const keypair = generateKeyPairHex()
|
26
30
|
const k = utils.hexToNumber(keypair.privateKey)
|
27
31
|
|
28
32
|
// c1 = k * G
|
29
33
|
let c1 = keypair.publicKey
|
34
|
+
|
30
35
|
if (c1.length > 128) c1 = c1.substring(c1.length - 128)
|
31
|
-
const p = publicKeyPoint
|
36
|
+
const p = publicKeyPoint.multiply(k)
|
32
37
|
|
33
38
|
// (x2, y2) = k * publicKey
|
34
39
|
const x2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.x), 64))
|
@@ -39,7 +44,13 @@ export function doEncrypt(msg: string | Uint8Array, publicKey: string, cipherMod
|
|
39
44
|
|
40
45
|
xorCipherStream(x2, y2, msgArr)
|
41
46
|
const c2 = bytesToHex(msgArr)
|
42
|
-
|
47
|
+
if (options?.asn1) {
|
48
|
+
const point = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey)
|
49
|
+
const encode = cipherMode === C1C2C3 ?
|
50
|
+
encodeEnc(point.x, point.y, c2, c3) :
|
51
|
+
encodeEnc(point.x, point.y, c3, c2)
|
52
|
+
return encode
|
53
|
+
}
|
43
54
|
return cipherMode === C1C2C3 ? c1 + c2 + c3 : c1 + c3 + c2
|
44
55
|
}
|
45
56
|
|
@@ -76,26 +87,45 @@ function xorCipherStream(x2: Uint8Array, y2: Uint8Array, msg: Uint8Array) {
|
|
76
87
|
*/
|
77
88
|
export function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
|
78
89
|
output: 'array'
|
90
|
+
asn1?: boolean
|
79
91
|
}): Uint8Array
|
80
92
|
export function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
|
81
|
-
output: 'string'
|
93
|
+
output: 'string',
|
94
|
+
asn1?: boolean
|
82
95
|
}): string
|
83
96
|
export function doDecrypt(encryptData: string, privateKey: string, cipherMode = 1, {
|
84
97
|
output = 'string',
|
98
|
+
asn1 = false,
|
85
99
|
} = {}) {
|
86
100
|
const privateKeyInteger = utils.hexToNumber(privateKey)
|
87
101
|
|
88
|
-
let
|
89
|
-
let c2
|
102
|
+
let c1: ProjPointType<bigint>
|
103
|
+
let c2: string
|
104
|
+
let c3: string
|
105
|
+
|
90
106
|
|
91
|
-
if (
|
92
|
-
|
93
|
-
|
107
|
+
if (asn1) {
|
108
|
+
const {x, y, cipher, hash} = decodeEnc(encryptData)
|
109
|
+
c1 = sm2Curve.ProjectivePoint.fromAffine({ x, y })
|
110
|
+
c3 = hash
|
111
|
+
c2 = cipher
|
112
|
+
if (cipherMode === C1C2C3) {
|
113
|
+
[c2, c3] = [c3, c2]
|
114
|
+
}
|
115
|
+
} else {
|
116
|
+
// c1c3c2
|
117
|
+
c1 = sm2Curve.ProjectivePoint.fromHex('04' + encryptData.substring(0, 128))!
|
118
|
+
c3 = encryptData.substring(128, 128 + 64)
|
119
|
+
c2 = encryptData.substring(128 + 64)
|
120
|
+
|
121
|
+
if (cipherMode === C1C2C3) {
|
122
|
+
c3 = encryptData.substring(encryptData.length - 64)
|
123
|
+
c2 = encryptData.substring(128, encryptData.length - 64)
|
124
|
+
}
|
94
125
|
}
|
126
|
+
|
95
127
|
|
96
128
|
const msg = hexToArray(c2)
|
97
|
-
const c1 = sm2Curve.ProjectivePoint.fromHex('04' + encryptData.substring(0, 128))!
|
98
|
-
|
99
129
|
const p = c1.multiply(privateKeyInteger)
|
100
130
|
const x2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.x), 64))
|
101
131
|
const y2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.y), 64))
|
@@ -103,7 +133,7 @@ export function doDecrypt(encryptData: string, privateKey: string, cipherMode =
|
|
103
133
|
xorCipherStream(x2, y2, msg)
|
104
134
|
// c3 = hash(x2 || msg || y2)
|
105
135
|
const checkC3 = arrayToHex(Array.from(sm3(utils.concatBytes(x2, msg, y2))))
|
106
|
-
|
136
|
+
|
107
137
|
if (checkC3 === c3.toLowerCase()) {
|
108
138
|
return output === 'array' ? msg : arrayToUtf8(msg)
|
109
139
|
} else {
|
@@ -165,16 +195,17 @@ export function doSignature(msg: Uint8Array | string, privateKey: string, option
|
|
165
195
|
/**
|
166
196
|
* 验签
|
167
197
|
*/
|
168
|
-
export function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string
|
198
|
+
export function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string | ProjPointType<bigint>, options: { der?: boolean, hash?: boolean, userId?: string } = {}) {
|
169
199
|
let hashHex: string
|
170
200
|
const {
|
171
201
|
hash,
|
172
202
|
der,
|
173
203
|
userId,
|
174
204
|
} = options
|
205
|
+
const publicKeyHex = typeof publicKey === 'string' ? publicKey : publicKey.toHex(false)
|
175
206
|
if (hash) {
|
176
207
|
// sm3杂凑
|
177
|
-
hashHex = getHash(typeof msg === 'string' ? utf8ToHex(msg) : msg,
|
208
|
+
hashHex = getHash(typeof msg === 'string' ? utf8ToHex(msg) : msg, publicKeyHex, userId)
|
178
209
|
} else {
|
179
210
|
hashHex = typeof msg === 'string' ? utf8ToHex(msg) : arrayToHex(Array.from(msg))
|
180
211
|
}
|
@@ -190,7 +221,7 @@ export function doVerifySignature(msg: string | Uint8Array, signHex: string, pub
|
|
190
221
|
s = utils.hexToNumber(signHex.substring(64))
|
191
222
|
}
|
192
223
|
|
193
|
-
const PA = sm2Curve.ProjectivePoint.fromHex(publicKey)
|
224
|
+
const PA = typeof publicKey === 'string' ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey
|
194
225
|
const e = utils.hexToNumber(hashHex)
|
195
226
|
|
196
227
|
// t = (r + s) mod n
|
@@ -250,6 +281,18 @@ export function getHash(hashHex: string | Uint8Array, publicKey: string, userId
|
|
250
281
|
return bytesToHex(sm3(utils.concatBytes(z, typeof hashHex === 'string' ? hexToArray(hashHex) : hashHex)))
|
251
282
|
}
|
252
283
|
|
284
|
+
/**
|
285
|
+
* 预计算公钥点,可用于提升加密性能
|
286
|
+
* @export
|
287
|
+
* @param {string} publicKey 公钥
|
288
|
+
* @param windowSize 计算窗口大小,默认为 8
|
289
|
+
* @returns {ProjPointType<bigint>} 预计算的点
|
290
|
+
*/
|
291
|
+
export function precomputePublicKey(publicKey: string, windowSize?: number) {
|
292
|
+
const point = sm2Curve.ProjectivePoint.fromHex(publicKey)
|
293
|
+
return sm2Curve.utils.precompute(windowSize, point)
|
294
|
+
}
|
295
|
+
|
253
296
|
/**
|
254
297
|
* 计算公钥
|
255
298
|
*/
|
package/src/sm2/utils.ts
CHANGED
@@ -142,11 +142,12 @@ export function hexToArray(hexStr: string) {
|
|
142
142
|
export function verifyPublicKey(publicKey: string) {
|
143
143
|
const point = sm2Curve.ProjectivePoint.fromHex(publicKey)
|
144
144
|
if (!point) return false
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
145
|
+
try {
|
146
|
+
point.assertValidity()
|
147
|
+
return true
|
148
|
+
} catch (error) {
|
149
|
+
return false
|
150
|
+
}
|
150
151
|
}
|
151
152
|
|
152
153
|
/**
|