sm-crypto-v2 1.3.0 → 1.4.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,13 @@
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.4.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.3.0...v1.4.0) (2023-06-09)
6
+
7
+
8
+ ### Features
9
+
10
+ * **sm2:** add experimental key agreement ([cdd00b4](https://github.com/Cubelrti/sm-crypto-v2/commit/cdd00b4e42bb5072e1dcb6e0301b6a2f18f53614))
11
+
5
12
  ## [1.3.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.2.2...v1.3.0) (2023-06-07)
6
13
 
7
14
 
package/README.md CHANGED
@@ -1,19 +1,19 @@
1
1
  # sm-crypto-v2
2
2
 
3
- [![npm version](https://badge.fury.io/js/sm-crypto-v2.svg)](https://badge.fury.io/js/sm-crypto-v2)
3
+ [![npm version](https://badge.fury.io/js/sm-crypto-v2.svg)](https://www.npmjs.com/package/sm-crypto-v2)
4
4
  [![status](https://img.shields.io/github/actions/workflow/status/cubelrti/sm-crypto-v2/test.yml?branch=master)](https://github.com/cubelrti/sm-crypto-v2/actions)
5
5
  [![cov](https://cubelrti.github.io/sm-crypto-v2/badges/coverage.svg)](https://github.com/cubelrti/sm-crypto-v2/actions)
6
6
 
7
-
8
7
  国密算法 sm2、sm3 和 sm4 的 TypeScript 实现。参数支持 TypedArray,导出 esm/cjs。
9
8
 
10
9
  ## 特性
11
10
 
12
- - SM2 底层改用 `noble-curves`,性能提升接近4倍,[noble-curves 文档](https://github.com/paulmillr/noble-curves)
13
- - 完整的类型支持
14
- - 移除原有 `jsbn` 依赖,改用原生 BigInt 支持
15
- - 通过所有之前的单元测试,包括 SM2、SM3 和 SM4
16
- - 自动使用最优的安全随机数实现,不使用 `random` 和 `Date.now` 模拟
11
+ - 基于 [`noble-curves` Abstract API](https://github.com/paulmillr/noble-curves#abstract-api) 重构 SM2,性能提升近4倍。详见 [noble-curves 文档](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/)
12
+ - 📘 使用 TypeScript 实现,提供全面的类型支持
13
+ - 🔄 移除原有 `jsbn` 依赖,改用原生 BigInt
14
+ - ✔️ 通过全部历史单元测试,包括 SM2、SM3 和 SM4
15
+ - 🎲 自动选择最优的安全随机数实现,避免使用 `Math.random` 和 `Date.now` 进行模拟
16
+ - 📚 同时导出 ES Module 和 CommonJS 两种格式,可按需使用
17
17
 
18
18
  ## 安装
19
19
 
@@ -163,6 +163,24 @@ let decryptData = sm4.decrypt(encryptData, key, {padding: 'none', output: 'array
163
163
  let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 解密,cbc 模式
164
164
  ```
165
165
 
166
+ ### 密钥交换(实验性)
167
+
168
+ ```js
169
+ import { sm2 } from 'sm-crypto-v2'
170
+
171
+ const keyPairA = sm2.generateKeyPairHex() // A 的秘钥对
172
+ const keyPairB = sm2.generateKeyPairHex() // B 的秘钥对
173
+ const ephemeralKeypairA = sm2.generateKeyPairHex() // A 的临时秘钥对
174
+ const ephemeralKeypairB = sm2.generateKeyPairHex() // B 的临时秘钥对
175
+
176
+ // A 所需参数:A 的秘钥对,A 的临时秘钥对,B 的公钥,B 的临时秘钥公钥,AB 的身份ID,长度
177
+ const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, undefined, undefined, 233)
178
+ // A 所需参数:B 的秘钥对,B 的临时秘钥对,A 的公钥,A 的临时秘钥公钥,AB 的身份ID,长度
179
+ const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, undefined, undefined, 233)
180
+
181
+ // expect(sharedKeyFromA).toEqual(sharedKeyFromB) => true
182
+ ```
183
+
166
184
  ## 其他实现
167
185
 
168
186
  * 原 js 版本:[https://github.com/JuneAndGreen/sm-crypto](https://github.com/JuneAndGreen/sm-crypto)
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
+ interface KeyPair {
2
+ privateKey: string;
3
+ publicKey: string;
4
+ }
1
5
  /**
2
6
  * 生成密钥对:publicKey = privateKey * G
3
7
  */
4
- declare function generateKeyPairHex(str?: string): {
5
- privateKey: string;
6
- publicKey: string;
7
- };
8
+ declare function generateKeyPairHex(str?: string): KeyPair;
8
9
  /**
9
10
  * 生成压缩公钥
10
11
  */
@@ -41,6 +42,8 @@ declare function concatArray(...arrays: Uint8Array[]): Uint8Array;
41
42
 
42
43
  declare function initRNGPool(): Promise<void>;
43
44
 
45
+ declare function calculateSharedKey(keypairA: KeyPair, ephemeralKeypairA: KeyPair, publicKeyB: string, ephemeralPublicKeyB: string, idA: string | undefined, idB: string | undefined, sharedKeyLength: number): Uint8Array;
46
+
44
47
  /**
45
48
  * 加密
46
49
  */
@@ -103,6 +106,8 @@ declare const index$2_getHash: typeof getHash;
103
106
  declare const index$2_getPublicKeyFromPrivateKey: typeof getPublicKeyFromPrivateKey;
104
107
  declare const index$2_getPoint: typeof getPoint;
105
108
  declare const index$2_initRNGPool: typeof initRNGPool;
109
+ declare const index$2_calculateSharedKey: typeof calculateSharedKey;
110
+ type index$2_KeyPair = KeyPair;
106
111
  declare const index$2_generateKeyPairHex: typeof generateKeyPairHex;
107
112
  declare const index$2_compressPublicKeyHex: typeof compressPublicKeyHex;
108
113
  declare const index$2_utf8ToHex: typeof utf8ToHex;
@@ -124,6 +129,8 @@ declare namespace index$2 {
124
129
  index$2_getPublicKeyFromPrivateKey as getPublicKeyFromPrivateKey,
125
130
  index$2_getPoint as getPoint,
126
131
  index$2_initRNGPool as initRNGPool,
132
+ index$2_calculateSharedKey as calculateSharedKey,
133
+ index$2_KeyPair as KeyPair,
127
134
  index$2_generateKeyPairHex as generateKeyPairHex,
128
135
  index$2_compressPublicKeyHex as compressPublicKeyHex,
129
136
  index$2_utf8ToHex as utf8ToHex,
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ var sm2_exports = {};
37
37
  __export(sm2_exports, {
38
38
  arrayToHex: () => arrayToHex,
39
39
  arrayToUtf8: () => arrayToUtf8,
40
+ calculateSharedKey: () => calculateSharedKey,
40
41
  comparePublicKeyHex: () => comparePublicKeyHex,
41
42
  compressPublicKeyHex: () => compressPublicKeyHex,
42
43
  concatArray: () => concatArray,
@@ -544,19 +545,65 @@ function concatArray(...arrays) {
544
545
 
545
546
  // src/sm2/index.ts
546
547
  var mod2 = __toESM(require("@noble/curves/abstract/modular"));
548
+ var utils4 = __toESM(require("@noble/curves/abstract/utils"));
549
+
550
+ // src/sm2/kx.ts
547
551
  var utils3 = __toESM(require("@noble/curves/abstract/utils"));
552
+ var import_modular3 = require("@noble/curves/abstract/modular");
553
+ var field = (0, import_modular3.Field)(BigInt(sm2Curve.CURVE.n));
554
+ var wPow2 = utils3.hexToNumber("80000000000000000000000000000000");
555
+ var wPow2Sub1 = utils3.hexToNumber("7fffffffffffffffffffffffffffffff");
556
+ function hkdf(z, keylen) {
557
+ let t = new Uint8Array();
558
+ let msg = new Uint8Array(keylen);
559
+ let ct = 1;
560
+ let offset = 0;
561
+ const nextT = () => {
562
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 255, ct >> 16 & 255, ct >> 8 & 255, ct & 255]));
563
+ ct++;
564
+ offset = 0;
565
+ };
566
+ nextT();
567
+ for (let i = 0, len = msg.length; i < len; i++) {
568
+ if (offset === t.length)
569
+ nextT();
570
+ msg[i] = t[offset++] & 255;
571
+ }
572
+ return msg;
573
+ }
574
+ function calculateSharedKey(keypairA, ephemeralKeypairA, publicKeyB, ephemeralPublicKeyB, idA = "1234567812345678", idB = "1234567812345678", sharedKeyLength) {
575
+ const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey);
576
+ const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB);
577
+ const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB);
578
+ const ZA = hexToArray(idA);
579
+ const ZB = hexToArray(idB);
580
+ const rA = utils3.hexToNumber(ephemeralKeypairA.privateKey);
581
+ const dA = utils3.hexToNumber(keypairA.privateKey);
582
+ const x1 = RA.x;
583
+ const x1_ = field.add(wPow2, x1 & wPow2Sub1);
584
+ const tA = field.add(dA, field.mul(x1_, rA));
585
+ const x2 = RB.x;
586
+ const x2_ = field.add(wPow2, x2 & wPow2Sub1);
587
+ const U = RB.multiply(x2_).add(PB).multiply(tA);
588
+ const xU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.x), 64));
589
+ const yU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.y), 64));
590
+ const KA = hkdf(concatArray(xU, yU, ZA, ZB), sharedKeyLength);
591
+ return KA;
592
+ }
593
+
594
+ // src/sm2/index.ts
548
595
  var C1C2C3 = 0;
549
596
  function doEncrypt(msg, publicKey, cipherMode = 1) {
550
597
  const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
551
598
  const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
552
599
  const keypair = generateKeyPairHex();
553
- const k = utils3.hexToNumber(keypair.privateKey);
600
+ const k = utils4.hexToNumber(keypair.privateKey);
554
601
  let c1 = keypair.publicKey;
555
602
  if (c1.length > 128)
556
603
  c1 = c1.substring(c1.length - 128);
557
604
  const p = publicKeyPoint.multiply(k);
558
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
559
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
605
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
606
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
560
607
  const c3 = arrayToHex(Array.from(sm3(concatArray(x2, msgArr, y2))));
561
608
  let ct = 1;
562
609
  let offset = 0;
@@ -579,7 +626,7 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
579
626
  function doDecrypt(encryptData, privateKey, cipherMode = 1, {
580
627
  output = "string"
581
628
  } = {}) {
582
- const privateKeyInteger = utils3.hexToNumber(privateKey);
629
+ const privateKeyInteger = utils4.hexToNumber(privateKey);
583
630
  let c3 = encryptData.substring(128, 128 + 64);
584
631
  let c2 = encryptData.substring(128 + 64);
585
632
  if (cipherMode === C1C2C3) {
@@ -589,8 +636,8 @@ function doDecrypt(encryptData, privateKey, cipherMode = 1, {
589
636
  const msg = hexToArray(c2);
590
637
  const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
591
638
  const p = c1.multiply(privateKeyInteger);
592
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
593
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
639
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
640
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
594
641
  let ct = 1;
595
642
  let offset = 0;
596
643
  let t = new Uint8Array();
@@ -626,8 +673,8 @@ function doSignature(msg, privateKey, options = {}) {
626
673
  publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey);
627
674
  hashHex = getHash(hashHex, publicKey, userId);
628
675
  }
629
- const dA = utils3.hexToNumber(privateKey);
630
- const e = utils3.hexToNumber(hashHex);
676
+ const dA = utils4.hexToNumber(privateKey);
677
+ const e = utils4.hexToNumber(hashHex);
631
678
  let k = null;
632
679
  let r = null;
633
680
  let s = null;
@@ -646,7 +693,7 @@ function doSignature(msg, privateKey, options = {}) {
646
693
  } while (s === ZERO);
647
694
  if (der)
648
695
  return encodeDer(r, s);
649
- return leftPad2(utils3.numberToHexUnpadded(r), 64) + leftPad2(utils3.numberToHexUnpadded(s), 64);
696
+ return leftPad2(utils4.numberToHexUnpadded(r), 64) + leftPad2(utils4.numberToHexUnpadded(s), 64);
650
697
  }
651
698
  function doVerifySignature(msg, signHex, publicKey, options = {}) {
652
699
  let hashHex;
@@ -667,11 +714,11 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
667
714
  r = decodeDerObj.r;
668
715
  s = decodeDerObj.s;
669
716
  } else {
670
- r = utils3.hexToNumber(signHex.substring(0, 64));
671
- s = utils3.hexToNumber(signHex.substring(64));
717
+ r = utils4.hexToNumber(signHex.substring(0, 64));
718
+ s = utils4.hexToNumber(signHex.substring(64));
672
719
  }
673
720
  const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
674
- const e = utils3.hexToNumber(hashHex);
721
+ const e = utils4.hexToNumber(hashHex);
675
722
  const t = mod2.mod(r + s, sm2Curve.CURVE.n);
676
723
  if (t === ZERO)
677
724
  return false;
@@ -681,10 +728,10 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
681
728
  }
682
729
  function getHash(hashHex, publicKey, userId = "1234567812345678") {
683
730
  userId = utf8ToHex(userId);
684
- const a = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
685
- const b = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
686
- const gx = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
687
- const gy = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
731
+ const a = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
732
+ const b = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
733
+ const gx = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
734
+ const gy = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
688
735
  let px;
689
736
  let py;
690
737
  if (publicKey.length === 128) {
@@ -692,8 +739,8 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
692
739
  py = publicKey.substring(64, 128);
693
740
  } else {
694
741
  const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
695
- px = leftPad2(utils3.numberToHexUnpadded(point.x), 64);
696
- py = leftPad2(utils3.numberToHexUnpadded(point.y), 64);
742
+ px = leftPad2(utils4.numberToHexUnpadded(point.x), 64);
743
+ py = leftPad2(utils4.numberToHexUnpadded(point.y), 64);
697
744
  }
698
745
  const data = hexToArray(userId + a + b + gx + gy + px + py);
699
746
  const entl = userId.length * 4;
@@ -702,13 +749,13 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
702
749
  }
703
750
  function getPublicKeyFromPrivateKey(privateKey) {
704
751
  const pubKey = sm2Curve.getPublicKey(privateKey, false);
705
- const pubPad = leftPad2(utils3.bytesToHex(pubKey), 64);
752
+ const pubPad = leftPad2(utils4.bytesToHex(pubKey), 64);
706
753
  return pubPad;
707
754
  }
708
755
  function getPoint() {
709
756
  const keypair = generateKeyPairHex();
710
757
  const PA = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
711
- const k = utils3.hexToNumber(keypair.privateKey);
758
+ const k = utils4.hexToNumber(keypair.privateKey);
712
759
  return {
713
760
  ...keypair,
714
761
  k,
package/dist/index.mjs CHANGED
@@ -9,6 +9,7 @@ var sm2_exports = {};
9
9
  __export(sm2_exports, {
10
10
  arrayToHex: () => arrayToHex,
11
11
  arrayToUtf8: () => arrayToUtf8,
12
+ calculateSharedKey: () => calculateSharedKey,
12
13
  comparePublicKeyHex: () => comparePublicKeyHex,
13
14
  compressPublicKeyHex: () => compressPublicKeyHex,
14
15
  concatArray: () => concatArray,
@@ -516,19 +517,65 @@ function concatArray(...arrays) {
516
517
 
517
518
  // src/sm2/index.ts
518
519
  import * as mod2 from "@noble/curves/abstract/modular";
520
+ import * as utils4 from "@noble/curves/abstract/utils";
521
+
522
+ // src/sm2/kx.ts
519
523
  import * as utils3 from "@noble/curves/abstract/utils";
524
+ import { Field as Field2 } from "@noble/curves/abstract/modular";
525
+ var field = Field2(BigInt(sm2Curve.CURVE.n));
526
+ var wPow2 = utils3.hexToNumber("80000000000000000000000000000000");
527
+ var wPow2Sub1 = utils3.hexToNumber("7fffffffffffffffffffffffffffffff");
528
+ function hkdf(z, keylen) {
529
+ let t = new Uint8Array();
530
+ let msg = new Uint8Array(keylen);
531
+ let ct = 1;
532
+ let offset = 0;
533
+ const nextT = () => {
534
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 255, ct >> 16 & 255, ct >> 8 & 255, ct & 255]));
535
+ ct++;
536
+ offset = 0;
537
+ };
538
+ nextT();
539
+ for (let i = 0, len = msg.length; i < len; i++) {
540
+ if (offset === t.length)
541
+ nextT();
542
+ msg[i] = t[offset++] & 255;
543
+ }
544
+ return msg;
545
+ }
546
+ function calculateSharedKey(keypairA, ephemeralKeypairA, publicKeyB, ephemeralPublicKeyB, idA = "1234567812345678", idB = "1234567812345678", sharedKeyLength) {
547
+ const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey);
548
+ const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB);
549
+ const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB);
550
+ const ZA = hexToArray(idA);
551
+ const ZB = hexToArray(idB);
552
+ const rA = utils3.hexToNumber(ephemeralKeypairA.privateKey);
553
+ const dA = utils3.hexToNumber(keypairA.privateKey);
554
+ const x1 = RA.x;
555
+ const x1_ = field.add(wPow2, x1 & wPow2Sub1);
556
+ const tA = field.add(dA, field.mul(x1_, rA));
557
+ const x2 = RB.x;
558
+ const x2_ = field.add(wPow2, x2 & wPow2Sub1);
559
+ const U = RB.multiply(x2_).add(PB).multiply(tA);
560
+ const xU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.x), 64));
561
+ const yU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.y), 64));
562
+ const KA = hkdf(concatArray(xU, yU, ZA, ZB), sharedKeyLength);
563
+ return KA;
564
+ }
565
+
566
+ // src/sm2/index.ts
520
567
  var C1C2C3 = 0;
521
568
  function doEncrypt(msg, publicKey, cipherMode = 1) {
522
569
  const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
523
570
  const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
524
571
  const keypair = generateKeyPairHex();
525
- const k = utils3.hexToNumber(keypair.privateKey);
572
+ const k = utils4.hexToNumber(keypair.privateKey);
526
573
  let c1 = keypair.publicKey;
527
574
  if (c1.length > 128)
528
575
  c1 = c1.substring(c1.length - 128);
529
576
  const p = publicKeyPoint.multiply(k);
530
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
531
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
577
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
578
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
532
579
  const c3 = arrayToHex(Array.from(sm3(concatArray(x2, msgArr, y2))));
533
580
  let ct = 1;
534
581
  let offset = 0;
@@ -551,7 +598,7 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
551
598
  function doDecrypt(encryptData, privateKey, cipherMode = 1, {
552
599
  output = "string"
553
600
  } = {}) {
554
- const privateKeyInteger = utils3.hexToNumber(privateKey);
601
+ const privateKeyInteger = utils4.hexToNumber(privateKey);
555
602
  let c3 = encryptData.substring(128, 128 + 64);
556
603
  let c2 = encryptData.substring(128 + 64);
557
604
  if (cipherMode === C1C2C3) {
@@ -561,8 +608,8 @@ function doDecrypt(encryptData, privateKey, cipherMode = 1, {
561
608
  const msg = hexToArray(c2);
562
609
  const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
563
610
  const p = c1.multiply(privateKeyInteger);
564
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
565
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
611
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
612
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
566
613
  let ct = 1;
567
614
  let offset = 0;
568
615
  let t = new Uint8Array();
@@ -598,8 +645,8 @@ function doSignature(msg, privateKey, options = {}) {
598
645
  publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey);
599
646
  hashHex = getHash(hashHex, publicKey, userId);
600
647
  }
601
- const dA = utils3.hexToNumber(privateKey);
602
- const e = utils3.hexToNumber(hashHex);
648
+ const dA = utils4.hexToNumber(privateKey);
649
+ const e = utils4.hexToNumber(hashHex);
603
650
  let k = null;
604
651
  let r = null;
605
652
  let s = null;
@@ -618,7 +665,7 @@ function doSignature(msg, privateKey, options = {}) {
618
665
  } while (s === ZERO);
619
666
  if (der)
620
667
  return encodeDer(r, s);
621
- return leftPad2(utils3.numberToHexUnpadded(r), 64) + leftPad2(utils3.numberToHexUnpadded(s), 64);
668
+ return leftPad2(utils4.numberToHexUnpadded(r), 64) + leftPad2(utils4.numberToHexUnpadded(s), 64);
622
669
  }
623
670
  function doVerifySignature(msg, signHex, publicKey, options = {}) {
624
671
  let hashHex;
@@ -639,11 +686,11 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
639
686
  r = decodeDerObj.r;
640
687
  s = decodeDerObj.s;
641
688
  } else {
642
- r = utils3.hexToNumber(signHex.substring(0, 64));
643
- s = utils3.hexToNumber(signHex.substring(64));
689
+ r = utils4.hexToNumber(signHex.substring(0, 64));
690
+ s = utils4.hexToNumber(signHex.substring(64));
644
691
  }
645
692
  const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
646
- const e = utils3.hexToNumber(hashHex);
693
+ const e = utils4.hexToNumber(hashHex);
647
694
  const t = mod2.mod(r + s, sm2Curve.CURVE.n);
648
695
  if (t === ZERO)
649
696
  return false;
@@ -653,10 +700,10 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
653
700
  }
654
701
  function getHash(hashHex, publicKey, userId = "1234567812345678") {
655
702
  userId = utf8ToHex(userId);
656
- const a = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
657
- const b = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
658
- const gx = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
659
- const gy = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
703
+ const a = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
704
+ const b = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
705
+ const gx = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
706
+ const gy = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
660
707
  let px;
661
708
  let py;
662
709
  if (publicKey.length === 128) {
@@ -664,8 +711,8 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
664
711
  py = publicKey.substring(64, 128);
665
712
  } else {
666
713
  const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
667
- px = leftPad2(utils3.numberToHexUnpadded(point.x), 64);
668
- py = leftPad2(utils3.numberToHexUnpadded(point.y), 64);
714
+ px = leftPad2(utils4.numberToHexUnpadded(point.x), 64);
715
+ py = leftPad2(utils4.numberToHexUnpadded(point.y), 64);
669
716
  }
670
717
  const data = hexToArray(userId + a + b + gx + gy + px + py);
671
718
  const entl = userId.length * 4;
@@ -674,13 +721,13 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
674
721
  }
675
722
  function getPublicKeyFromPrivateKey(privateKey) {
676
723
  const pubKey = sm2Curve.getPublicKey(privateKey, false);
677
- const pubPad = leftPad2(utils3.bytesToHex(pubKey), 64);
724
+ const pubPad = leftPad2(utils4.bytesToHex(pubKey), 64);
678
725
  return pubPad;
679
726
  }
680
727
  function getPoint() {
681
728
  const keypair = generateKeyPairHex();
682
729
  const PA = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
683
- const k = utils3.hexToNumber(keypair.privateKey);
730
+ const k = utils4.hexToNumber(keypair.privateKey);
684
731
  return {
685
732
  ...keypair,
686
733
  k,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sm-crypto-v2",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "sm-crypto-v2",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/sm2/index.ts CHANGED
@@ -9,6 +9,7 @@ import { ONE, ZERO } from './bn';
9
9
 
10
10
  export * from './utils'
11
11
  export { initRNGPool } from './ec'
12
+ export { calculateSharedKey } from './kx'
12
13
 
13
14
  // const { G, curve, n } = generateEcparam()
14
15
  const C1C2C3 = 0
package/src/sm2/kx.ts ADDED
@@ -0,0 +1,76 @@
1
+ import { sm2Curve } from './ec';
2
+ import { KeyPair, concatArray, hexToArray, leftPad } from './utils';
3
+ import * as utils from '@noble/curves/abstract/utils';
4
+ import { Field } from '@noble/curves/abstract/modular';
5
+ import { sm3 } from './sm3';
6
+
7
+ export const field = Field(BigInt(sm2Curve.CURVE.n))
8
+
9
+ // 用到的常数
10
+ const wPow2 = utils.hexToNumber('80000000000000000000000000000000')
11
+ const wPow2Sub1 = utils.hexToNumber('7fffffffffffffffffffffffffffffff')
12
+
13
+ // from sm2 sign part, extracted for code reusable.
14
+ function hkdf(z: Uint8Array, keylen: number) {
15
+ let t = new Uint8Array() // 256 位
16
+ let msg = new Uint8Array(keylen)
17
+ let ct = 1
18
+ let offset = 0
19
+ const nextT = () => {
20
+ // (1) Hai = hash(z || ct)
21
+ // (2) ct++
22
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 0x00ff, ct >> 16 & 0x00ff, ct >> 8 & 0x00ff, ct & 0x00ff]))
23
+ ct++
24
+ offset = 0
25
+ }
26
+ nextT() // 先生成 Ha1
27
+
28
+ for (let i = 0, len = msg.length; i < len; i++) {
29
+ // t = Ha1 || Ha2 || Ha3 || Ha4
30
+ if (offset === t.length) nextT()
31
+
32
+ // c2 = msg ^ t
33
+ msg[i] = t[offset++] & 0xff
34
+ }
35
+ return msg
36
+ }
37
+
38
+
39
+ export function calculateSharedKey(
40
+ keypairA: KeyPair,
41
+ ephemeralKeypairA: KeyPair,
42
+ publicKeyB: string,
43
+ ephemeralPublicKeyB: string,
44
+ idA: string = '1234567812345678',
45
+ idB: string = '1234567812345678',
46
+ sharedKeyLength: number,
47
+ ) {
48
+ const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey)
49
+ const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB)
50
+ // const PA = sm2Curve.ProjectivePoint.fromHex(keypairA.publicKey) // 暂时用不到
51
+ const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB)
52
+ const ZA = hexToArray(idA)
53
+ const ZB = hexToArray(idB)
54
+ const rA = utils.hexToNumber(ephemeralKeypairA.privateKey)
55
+ const dA = utils.hexToNumber(keypairA.privateKey)
56
+ // 1.先算tA
57
+ const x1 = RA.x
58
+ // x1_ = 2^w + (x1 & (2^w - 1))
59
+ const x1_ = field.add(wPow2, (x1 & wPow2Sub1))
60
+ // tA = (dA + x1b * rA) mod n
61
+ const tA = field.add(dA, field.mul(x1_, rA))
62
+
63
+ // 2.算 U
64
+ // x2_ = 2^w + (x2 & (2^w - 1))
65
+ const x2 = RB.x
66
+ const x2_ = field.add(wPow2, (x2 & wPow2Sub1))
67
+ // U = [h * tA](PB + x2_ * RB)
68
+ const U = RB.multiply(x2_).add(PB).multiply(tA)
69
+
70
+ // 3.算 KDF
71
+ // KA = KDF(xU || yU || ZA || ZB, kLen)
72
+ const xU = hexToArray(leftPad(utils.numberToHexUnpadded(U.x), 64))
73
+ const yU = hexToArray(leftPad(utils.numberToHexUnpadded(U.y), 64))
74
+ const KA = hkdf(concatArray(xU, yU, ZA, ZB), sharedKeyLength)
75
+ return KA
76
+ }
package/src/sm2/utils.ts CHANGED
@@ -5,10 +5,15 @@ import { sm2Curve, sm2Fp } from './ec';
5
5
  import { mod } from '@noble/curves/abstract/modular';
6
6
  import { ONE, TWO, ZERO } from './bn';
7
7
 
8
+ export interface KeyPair {
9
+ privateKey: string
10
+ publicKey: string
11
+ }
12
+
8
13
  /**
9
14
  * 生成密钥对:publicKey = privateKey * G
10
15
  */
11
- export function generateKeyPairHex(str?: string) {
16
+ export function generateKeyPairHex(str?: string): KeyPair {
12
17
  const privateKey = str ? utils.numberToBytesBE((mod(BigInt(str), ONE) + ONE), 32) : sm2Curve.utils.randomPrivateKey()
13
18
  // const random = typeof a === 'string' ? new BigInteger(a, b) :
14
19
  // a ? new BigInteger(a, b!, c!) : new BigInteger(n.bitLength(), rng)