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 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
- let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode) // 加密结果
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, cipherMode?: number): 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, options?: {
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.substr(vIndexR, lR * 2);
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
- const x2 = point.x;
644
- const y = point.y;
645
- return sm2Fp.sqr(y) === sm2Fp.add(sm2Fp.addN(sm2Fp.mulN(x2, sm2Fp.sqrN(x2)), sm2Fp.mulN(x2, sm2Curve.CURVE.a)), sm2Curve.CURVE.b);
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 c3 = encryptData.substring(128, 128 + 64);
755
- let c2 = encryptData.substring(128 + 64);
756
- if (cipherMode === C1C2C3) {
757
- c3 = encryptData.substring(encryptData.length - 64);
758
- c2 = encryptData.substring(128, encryptData.length - 64);
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, publicKey, userId);
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.substr(vIndexR, lR * 2);
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
- const x2 = point.x;
616
- const y = point.y;
617
- return sm2Fp.sqr(y) === sm2Fp.add(sm2Fp.addN(sm2Fp.mulN(x2, sm2Fp.sqrN(x2)), sm2Fp.mulN(x2, sm2Curve.CURVE.a)), sm2Curve.CURVE.b);
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 c3 = encryptData.substring(128, 128 + 64);
727
- let c2 = encryptData.substring(128 + 64);
728
- if (cipherMode === C1C2C3) {
729
- c3 = encryptData.substring(encryptData.length - 64);
730
- c2 = encryptData.substring(128, encryptData.length - 64);
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, publicKey, userId);
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.6.0",
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.substr(vIndexR, lR * 2)
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, cipherMode = 1) {
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!.multiply(k)
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 c3 = encryptData.substring(128, 128 + 64)
89
- let c2 = encryptData.substring(128 + 64)
102
+ let c1: ProjPointType<bigint>
103
+ let c2: string
104
+ let c3: string
105
+
90
106
 
91
- if (cipherMode === C1C2C3) {
92
- c3 = encryptData.substring(encryptData.length - 64)
93
- c2 = encryptData.substring(128, encryptData.length - 64)
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, options: { der?: boolean, hash?: boolean, userId?: 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, publicKey, userId)
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
- const x = point.x
147
- const y = point.y
148
- // 验证 y^2 是否等于 x^3 + ax + b
149
- return sm2Fp.sqr(y) === sm2Fp.add(sm2Fp.addN(sm2Fp.mulN(x, sm2Fp.sqrN(x)), sm2Fp.mulN(x, sm2Curve.CURVE.a)), sm2Curve.CURVE.b)
145
+ try {
146
+ point.assertValidity()
147
+ return true
148
+ } catch (error) {
149
+ return false
150
+ }
150
151
  }
151
152
 
152
153
  /**
package/src/sm3/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { hmac } from '@/sm2/hmac'
2
2
  import { sm3 as sm2sm3 } from '../sm2/sm3'
3
- import { arrayToHex, hexToArray, leftPad } from '../sm2/utils'
3
+ import { hexToArray } from '../sm2/utils'
4
4
  import { bytesToHex } from './utils'
5
5
 
6
6
  /**