sm-crypto-v2 1.2.2 → 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 +14 -0
- package/README.md +53 -9
- package/benchmark/index.js +29 -0
- package/benchmark/package.json +19 -0
- package/benchmark/pnpm-lock.yaml +28 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.js +81 -29
- package/dist/index.mjs +81 -29
- package/package.json +1 -1
- package/src/sm2/ec.ts +15 -10
- package/src/sm2/index.ts +4 -1
- package/src/sm2/kx.ts +76 -0
- package/src/sm2/utils.ts +6 -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.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
|
+
|
12
|
+
## [1.3.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.2.2...v1.3.0) (2023-06-07)
|
13
|
+
|
14
|
+
|
15
|
+
### Features
|
16
|
+
|
17
|
+
* **sm2:** add benchmark and optimize rng pooling ([b162377](https://github.com/Cubelrti/sm-crypto-v2/commit/b1623774cc4374deea61499f13790c5e8b17041a))
|
18
|
+
|
5
19
|
### [1.2.2](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.2.1...v1.2.2) (2023-06-07)
|
6
20
|
|
7
21
|
|
package/README.md
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
# sm-crypto-v2
|
2
2
|
|
3
|
-
[](https://
|
3
|
+
[](https://www.npmjs.com/package/sm-crypto-v2)
|
4
4
|
[](https://github.com/cubelrti/sm-crypto-v2/actions)
|
5
5
|
[](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
|
-
-
|
13
|
-
-
|
14
|
-
- 移除原有 `jsbn` 依赖,改用原生 BigInt
|
15
|
-
-
|
16
|
-
-
|
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
|
|
@@ -37,10 +37,12 @@ privateKey = keypair.privateKey // 私钥
|
|
37
37
|
const compressedPublicKey = sm2.compressPublicKeyHex(publicKey) // compressedPublicKey 和 publicKey 等价
|
38
38
|
sm2.comparePublicKeyHex(publicKey, compressedPublicKey) // 判断公钥是否等价
|
39
39
|
|
40
|
-
// 自定义随机数,参数会直接透传给
|
40
|
+
// 自定义随机数,参数会直接透传给 BigInt 构造器
|
41
41
|
// 注意:开发者使用自定义随机数,需要自行确保传入的随机数符合密码学安全
|
42
42
|
let keypair2 = sm2.generateKeyPairHex('123123123123123')
|
43
|
-
|
43
|
+
|
44
|
+
// 初始化随机数池,在某些场景下可能会用到
|
45
|
+
await sm2.initRNGPool()
|
44
46
|
|
45
47
|
let verifyResult = sm2.verifyPublicKey(publicKey) // 验证公钥
|
46
48
|
verifyResult = sm2.verifyPublicKey(compressedPublicKey) // 验证公钥
|
@@ -161,6 +163,24 @@ let decryptData = sm4.decrypt(encryptData, key, {padding: 'none', output: 'array
|
|
161
163
|
let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 解密,cbc 模式
|
162
164
|
```
|
163
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
|
+
|
164
184
|
## 其他实现
|
165
185
|
|
166
186
|
* 原 js 版本:[https://github.com/JuneAndGreen/sm-crypto](https://github.com/JuneAndGreen/sm-crypto)
|
@@ -168,6 +188,30 @@ let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba9876543
|
|
168
188
|
* java 实现(感谢 @antherd 提供):[https://github.com/antherd/sm-crypto](https://github.com/antherd/sm-crypto)
|
169
189
|
* dart 实现(感谢 @luckykellan 提供):[https://github.com/luckykellan/dart_sm](https://github.com/luckykellan/dart_sm)
|
170
190
|
|
191
|
+
## 性能
|
192
|
+
|
193
|
+
CPU: Apple M1 Pro
|
194
|
+
|
195
|
+
```
|
196
|
+
❯ npm run bench
|
197
|
+
|
198
|
+
> benchmark@0.1.0 bench
|
199
|
+
> node index.js
|
200
|
+
|
201
|
+
Benchmarking
|
202
|
+
|
203
|
+
=== sm-crypto ===
|
204
|
+
sm2 generateKeyPair x 134 ops/sec @ 7ms/op ± 4.12% (min: 6ms, max: 21ms)
|
205
|
+
sm2 encrypt x 71 ops/sec @ 14ms/op
|
206
|
+
sm2 sign x 139 ops/sec @ 7ms/op
|
207
|
+
sm2 verify x 70 ops/sec @ 14ms/op
|
208
|
+
=== sm-crypto-v2 ===
|
209
|
+
sm2 generateKeyPair x 2,835 ops/sec @ 352μs/op ± 6.34% (min: 286μs, max: 1ms)
|
210
|
+
sm2 encrypt x 253 ops/sec @ 3ms/op ± 2.11% (min: 3ms, max: 24ms)
|
211
|
+
sm2 sign x 3,186 ops/sec @ 313μs/op ± 1.26% (min: 277μs, max: 854μs)
|
212
|
+
sm2 verify x 258 ops/sec @ 3ms/op
|
213
|
+
```
|
214
|
+
|
171
215
|
## 协议
|
172
216
|
|
173
217
|
MIT
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { run, mark, utils } from 'micro-bmark';
|
2
|
+
import * as sm from 'sm-crypto'
|
3
|
+
import * as smV2 from 'sm-crypto-v2'
|
4
|
+
|
5
|
+
const msg = 'Hello world~!'
|
6
|
+
|
7
|
+
const keypair = smV2.sm2.generateKeyPairHex('12345678901234567890')
|
8
|
+
|
9
|
+
run(async () => {
|
10
|
+
await smV2.sm2.initRNGPool()
|
11
|
+
const sig = smV2.sm2.doSignature(msg, keypair.privateKey, { publicKey: keypair.publicKey})
|
12
|
+
|
13
|
+
const RAM = false
|
14
|
+
console.log();
|
15
|
+
if (RAM) utils.logMem();
|
16
|
+
console.log('=== sm-crypto ===')
|
17
|
+
await mark('sm2 generateKeyPair', 100, () => sm.sm2.generateKeyPairHex())
|
18
|
+
await mark('sm2 encrypt', 500, () => sm.sm2.doEncrypt(msg, keypair.publicKey));
|
19
|
+
await mark('sm2 sign', 500, () => sm.sm2.doSignature(msg, keypair.privateKey, { publicKey: keypair.publicKey}));
|
20
|
+
await mark('sm2 verify', 500, () => sm.sm2.doVerifySignature(msg, sig, keypair.publicKey));
|
21
|
+
if (RAM) utils.logMem();
|
22
|
+
if (RAM) utils.logMem();
|
23
|
+
console.log('=== sm-crypto-v2 ===')
|
24
|
+
await mark('sm2 generateKeyPair', 100, () => smV2.sm2.generateKeyPairHex())
|
25
|
+
await mark('sm2 encrypt', 500, () => smV2.sm2.doEncrypt(msg, keypair.publicKey));
|
26
|
+
await mark('sm2 sign', 500, () => smV2.sm2.doSignature(msg, keypair.privateKey, { publicKey: keypair.publicKey}));
|
27
|
+
await mark('sm2 verify', 500, () => smV2.sm2.doVerifySignature(msg, sig, keypair.publicKey));
|
28
|
+
if (RAM) utils.logMem();
|
29
|
+
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"name": "benchmark",
|
3
|
+
"private": true,
|
4
|
+
"version": "0.1.0",
|
5
|
+
"description": "benchmarks",
|
6
|
+
"main": "index.js",
|
7
|
+
"type": "module",
|
8
|
+
"scripts": {
|
9
|
+
"bench": "node index.js"
|
10
|
+
},
|
11
|
+
"keywords": [],
|
12
|
+
"author": "",
|
13
|
+
"license": "MIT",
|
14
|
+
"dependencies": {
|
15
|
+
"micro-bmark": "^0.3.1",
|
16
|
+
"sm-crypto": "^0.3.12",
|
17
|
+
"sm-crypto-v2": "^1.2.2"
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
lockfileVersion: '6.0'
|
2
|
+
|
3
|
+
dependencies:
|
4
|
+
micro-bmark:
|
5
|
+
specifier: ^0.3.1
|
6
|
+
version: 0.3.1
|
7
|
+
sm-crypto:
|
8
|
+
specifier: ^0.3.12
|
9
|
+
version: 0.3.12
|
10
|
+
sm-crypto-v2:
|
11
|
+
specifier: ^1.2.2
|
12
|
+
version: link:..
|
13
|
+
|
14
|
+
packages:
|
15
|
+
|
16
|
+
/jsbn@1.1.0:
|
17
|
+
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
|
18
|
+
dev: false
|
19
|
+
|
20
|
+
/micro-bmark@0.3.1:
|
21
|
+
resolution: {integrity: sha512-bNaKObD4yPAAPrpEqp5jO6LJ2sEFgLoFSmRjEY809mJ62+2AehI/K3+RlVpN3Oo92RHpgC2RQhj6b1Tb4dmo+w==}
|
22
|
+
dev: false
|
23
|
+
|
24
|
+
/sm-crypto@0.3.12:
|
25
|
+
resolution: {integrity: sha512-272PBzB4PYaBdeGa41TH9ZlMGLPVRmS36Gs4FjmHwXIdihQypAbhhFWZTaa/3de69q2KfMme1M5O2W5+spAdrg==}
|
26
|
+
dependencies:
|
27
|
+
jsbn: 1.1.0
|
28
|
+
dev: false
|
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
|
*/
|
@@ -39,6 +40,10 @@ declare function verifyPublicKey(publicKey: string): boolean;
|
|
39
40
|
declare function comparePublicKeyHex(publicKey1: string, publicKey2: string): boolean;
|
40
41
|
declare function concatArray(...arrays: Uint8Array[]): Uint8Array;
|
41
42
|
|
43
|
+
declare function initRNGPool(): Promise<void>;
|
44
|
+
|
45
|
+
declare function calculateSharedKey(keypairA: KeyPair, ephemeralKeypairA: KeyPair, publicKeyB: string, ephemeralPublicKeyB: string, idA: string | undefined, idB: string | undefined, sharedKeyLength: number): Uint8Array;
|
46
|
+
|
42
47
|
/**
|
43
48
|
* 加密
|
44
49
|
*/
|
@@ -100,6 +105,9 @@ declare const index$2_doVerifySignature: typeof doVerifySignature;
|
|
100
105
|
declare const index$2_getHash: typeof getHash;
|
101
106
|
declare const index$2_getPublicKeyFromPrivateKey: typeof getPublicKeyFromPrivateKey;
|
102
107
|
declare const index$2_getPoint: typeof getPoint;
|
108
|
+
declare const index$2_initRNGPool: typeof initRNGPool;
|
109
|
+
declare const index$2_calculateSharedKey: typeof calculateSharedKey;
|
110
|
+
type index$2_KeyPair = KeyPair;
|
103
111
|
declare const index$2_generateKeyPairHex: typeof generateKeyPairHex;
|
104
112
|
declare const index$2_compressPublicKeyHex: typeof compressPublicKeyHex;
|
105
113
|
declare const index$2_utf8ToHex: typeof utf8ToHex;
|
@@ -120,6 +128,9 @@ declare namespace index$2 {
|
|
120
128
|
index$2_getHash as getHash,
|
121
129
|
index$2_getPublicKeyFromPrivateKey as getPublicKeyFromPrivateKey,
|
122
130
|
index$2_getPoint as getPoint,
|
131
|
+
index$2_initRNGPool as initRNGPool,
|
132
|
+
index$2_calculateSharedKey as calculateSharedKey,
|
133
|
+
index$2_KeyPair as KeyPair,
|
123
134
|
index$2_generateKeyPairHex as generateKeyPairHex,
|
124
135
|
index$2_compressPublicKeyHex as compressPublicKeyHex,
|
125
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,
|
@@ -49,6 +50,7 @@ __export(sm2_exports, {
|
|
49
50
|
getPoint: () => getPoint,
|
50
51
|
getPublicKeyFromPrivateKey: () => getPublicKeyFromPrivateKey,
|
51
52
|
hexToArray: () => hexToArray,
|
53
|
+
initRNGPool: () => initRNGPool,
|
52
54
|
leftPad: () => leftPad2,
|
53
55
|
utf8ToHex: () => utf8ToHex,
|
54
56
|
verifyPublicKey: () => verifyPublicKey
|
@@ -359,11 +361,14 @@ function sm32(input, options) {
|
|
359
361
|
}
|
360
362
|
|
361
363
|
// src/sm2/ec.ts
|
362
|
-
var DEFAULT_PRNG_POOL_SIZE =
|
364
|
+
var DEFAULT_PRNG_POOL_SIZE = 16384;
|
363
365
|
var prngPool = new Uint8Array(0);
|
364
|
-
|
365
|
-
|
366
|
+
var _syncCrypto;
|
367
|
+
async function initRNGPool() {
|
368
|
+
if ("crypto" in globalThis) {
|
369
|
+
_syncCrypto = globalThis.crypto;
|
366
370
|
return;
|
371
|
+
}
|
367
372
|
if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
|
368
373
|
return;
|
369
374
|
if ("wx" in globalThis) {
|
@@ -381,29 +386,30 @@ async function FillPRNGPoolIfNeeded() {
|
|
381
386
|
/* webpackIgnore: true */
|
382
387
|
"crypto"
|
383
388
|
);
|
389
|
+
_syncCrypto = crypto.webcrypto;
|
384
390
|
const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
|
385
|
-
|
391
|
+
_syncCrypto.getRandomValues(array);
|
386
392
|
prngPool = array;
|
387
393
|
} catch (error) {
|
388
394
|
throw new Error("no available csprng, abort.");
|
389
395
|
}
|
390
396
|
}
|
391
397
|
}
|
392
|
-
|
398
|
+
initRNGPool();
|
393
399
|
function consumePool(length) {
|
394
400
|
if (prngPool.length > length) {
|
395
401
|
const prng = prngPool.slice(0, length);
|
396
402
|
prngPool = prngPool.slice(length);
|
397
|
-
|
403
|
+
initRNGPool();
|
398
404
|
return prng;
|
399
405
|
} else {
|
400
|
-
throw new Error("random number pool is insufficient, prevent getting too long random values or too often.");
|
406
|
+
throw new Error("random number pool is not ready or insufficient, prevent getting too long random values or too often.");
|
401
407
|
}
|
402
408
|
}
|
403
409
|
function randomBytes(length = 0) {
|
404
410
|
const array = new Uint8Array(length);
|
405
|
-
if (
|
406
|
-
return
|
411
|
+
if (_syncCrypto) {
|
412
|
+
return _syncCrypto.getRandomValues(array);
|
407
413
|
} else {
|
408
414
|
const result = consumePool(length);
|
409
415
|
return result;
|
@@ -539,19 +545,65 @@ function concatArray(...arrays) {
|
|
539
545
|
|
540
546
|
// src/sm2/index.ts
|
541
547
|
var mod2 = __toESM(require("@noble/curves/abstract/modular"));
|
548
|
+
var utils4 = __toESM(require("@noble/curves/abstract/utils"));
|
549
|
+
|
550
|
+
// src/sm2/kx.ts
|
542
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
|
543
595
|
var C1C2C3 = 0;
|
544
596
|
function doEncrypt(msg, publicKey, cipherMode = 1) {
|
545
597
|
const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
|
546
598
|
const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
547
599
|
const keypair = generateKeyPairHex();
|
548
|
-
const k =
|
600
|
+
const k = utils4.hexToNumber(keypair.privateKey);
|
549
601
|
let c1 = keypair.publicKey;
|
550
602
|
if (c1.length > 128)
|
551
603
|
c1 = c1.substring(c1.length - 128);
|
552
604
|
const p = publicKeyPoint.multiply(k);
|
553
|
-
const x2 = hexToArray(leftPad2(
|
554
|
-
const y2 = hexToArray(leftPad2(
|
605
|
+
const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
|
606
|
+
const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
|
555
607
|
const c3 = arrayToHex(Array.from(sm3(concatArray(x2, msgArr, y2))));
|
556
608
|
let ct = 1;
|
557
609
|
let offset = 0;
|
@@ -574,7 +626,7 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
|
|
574
626
|
function doDecrypt(encryptData, privateKey, cipherMode = 1, {
|
575
627
|
output = "string"
|
576
628
|
} = {}) {
|
577
|
-
const privateKeyInteger =
|
629
|
+
const privateKeyInteger = utils4.hexToNumber(privateKey);
|
578
630
|
let c3 = encryptData.substring(128, 128 + 64);
|
579
631
|
let c2 = encryptData.substring(128 + 64);
|
580
632
|
if (cipherMode === C1C2C3) {
|
@@ -584,8 +636,8 @@ function doDecrypt(encryptData, privateKey, cipherMode = 1, {
|
|
584
636
|
const msg = hexToArray(c2);
|
585
637
|
const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
|
586
638
|
const p = c1.multiply(privateKeyInteger);
|
587
|
-
const x2 = hexToArray(leftPad2(
|
588
|
-
const y2 = hexToArray(leftPad2(
|
639
|
+
const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
|
640
|
+
const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
|
589
641
|
let ct = 1;
|
590
642
|
let offset = 0;
|
591
643
|
let t = new Uint8Array();
|
@@ -621,8 +673,8 @@ function doSignature(msg, privateKey, options = {}) {
|
|
621
673
|
publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey);
|
622
674
|
hashHex = getHash(hashHex, publicKey, userId);
|
623
675
|
}
|
624
|
-
const dA =
|
625
|
-
const e =
|
676
|
+
const dA = utils4.hexToNumber(privateKey);
|
677
|
+
const e = utils4.hexToNumber(hashHex);
|
626
678
|
let k = null;
|
627
679
|
let r = null;
|
628
680
|
let s = null;
|
@@ -641,7 +693,7 @@ function doSignature(msg, privateKey, options = {}) {
|
|
641
693
|
} while (s === ZERO);
|
642
694
|
if (der)
|
643
695
|
return encodeDer(r, s);
|
644
|
-
return leftPad2(
|
696
|
+
return leftPad2(utils4.numberToHexUnpadded(r), 64) + leftPad2(utils4.numberToHexUnpadded(s), 64);
|
645
697
|
}
|
646
698
|
function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
647
699
|
let hashHex;
|
@@ -662,11 +714,11 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
662
714
|
r = decodeDerObj.r;
|
663
715
|
s = decodeDerObj.s;
|
664
716
|
} else {
|
665
|
-
r =
|
666
|
-
s =
|
717
|
+
r = utils4.hexToNumber(signHex.substring(0, 64));
|
718
|
+
s = utils4.hexToNumber(signHex.substring(64));
|
667
719
|
}
|
668
720
|
const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
669
|
-
const e =
|
721
|
+
const e = utils4.hexToNumber(hashHex);
|
670
722
|
const t = mod2.mod(r + s, sm2Curve.CURVE.n);
|
671
723
|
if (t === ZERO)
|
672
724
|
return false;
|
@@ -676,10 +728,10 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
676
728
|
}
|
677
729
|
function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
678
730
|
userId = utf8ToHex(userId);
|
679
|
-
const a = leftPad2(
|
680
|
-
const b = leftPad2(
|
681
|
-
const gx = leftPad2(
|
682
|
-
const gy = leftPad2(
|
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);
|
683
735
|
let px;
|
684
736
|
let py;
|
685
737
|
if (publicKey.length === 128) {
|
@@ -687,8 +739,8 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
|
687
739
|
py = publicKey.substring(64, 128);
|
688
740
|
} else {
|
689
741
|
const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
690
|
-
px = leftPad2(
|
691
|
-
py = leftPad2(
|
742
|
+
px = leftPad2(utils4.numberToHexUnpadded(point.x), 64);
|
743
|
+
py = leftPad2(utils4.numberToHexUnpadded(point.y), 64);
|
692
744
|
}
|
693
745
|
const data = hexToArray(userId + a + b + gx + gy + px + py);
|
694
746
|
const entl = userId.length * 4;
|
@@ -697,13 +749,13 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
|
697
749
|
}
|
698
750
|
function getPublicKeyFromPrivateKey(privateKey) {
|
699
751
|
const pubKey = sm2Curve.getPublicKey(privateKey, false);
|
700
|
-
const pubPad = leftPad2(
|
752
|
+
const pubPad = leftPad2(utils4.bytesToHex(pubKey), 64);
|
701
753
|
return pubPad;
|
702
754
|
}
|
703
755
|
function getPoint() {
|
704
756
|
const keypair = generateKeyPairHex();
|
705
757
|
const PA = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
|
706
|
-
const k =
|
758
|
+
const k = utils4.hexToNumber(keypair.privateKey);
|
707
759
|
return {
|
708
760
|
...keypair,
|
709
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,
|
@@ -21,6 +22,7 @@ __export(sm2_exports, {
|
|
21
22
|
getPoint: () => getPoint,
|
22
23
|
getPublicKeyFromPrivateKey: () => getPublicKeyFromPrivateKey,
|
23
24
|
hexToArray: () => hexToArray,
|
25
|
+
initRNGPool: () => initRNGPool,
|
24
26
|
leftPad: () => leftPad2,
|
25
27
|
utf8ToHex: () => utf8ToHex,
|
26
28
|
verifyPublicKey: () => verifyPublicKey
|
@@ -331,11 +333,14 @@ function sm32(input, options) {
|
|
331
333
|
}
|
332
334
|
|
333
335
|
// src/sm2/ec.ts
|
334
|
-
var DEFAULT_PRNG_POOL_SIZE =
|
336
|
+
var DEFAULT_PRNG_POOL_SIZE = 16384;
|
335
337
|
var prngPool = new Uint8Array(0);
|
336
|
-
|
337
|
-
|
338
|
+
var _syncCrypto;
|
339
|
+
async function initRNGPool() {
|
340
|
+
if ("crypto" in globalThis) {
|
341
|
+
_syncCrypto = globalThis.crypto;
|
338
342
|
return;
|
343
|
+
}
|
339
344
|
if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
|
340
345
|
return;
|
341
346
|
if ("wx" in globalThis) {
|
@@ -353,29 +358,30 @@ async function FillPRNGPoolIfNeeded() {
|
|
353
358
|
/* webpackIgnore: true */
|
354
359
|
"crypto"
|
355
360
|
);
|
361
|
+
_syncCrypto = crypto.webcrypto;
|
356
362
|
const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
|
357
|
-
|
363
|
+
_syncCrypto.getRandomValues(array);
|
358
364
|
prngPool = array;
|
359
365
|
} catch (error) {
|
360
366
|
throw new Error("no available csprng, abort.");
|
361
367
|
}
|
362
368
|
}
|
363
369
|
}
|
364
|
-
|
370
|
+
initRNGPool();
|
365
371
|
function consumePool(length) {
|
366
372
|
if (prngPool.length > length) {
|
367
373
|
const prng = prngPool.slice(0, length);
|
368
374
|
prngPool = prngPool.slice(length);
|
369
|
-
|
375
|
+
initRNGPool();
|
370
376
|
return prng;
|
371
377
|
} else {
|
372
|
-
throw new Error("random number pool is insufficient, prevent getting too long random values or too often.");
|
378
|
+
throw new Error("random number pool is not ready or insufficient, prevent getting too long random values or too often.");
|
373
379
|
}
|
374
380
|
}
|
375
381
|
function randomBytes(length = 0) {
|
376
382
|
const array = new Uint8Array(length);
|
377
|
-
if (
|
378
|
-
return
|
383
|
+
if (_syncCrypto) {
|
384
|
+
return _syncCrypto.getRandomValues(array);
|
379
385
|
} else {
|
380
386
|
const result = consumePool(length);
|
381
387
|
return result;
|
@@ -511,19 +517,65 @@ function concatArray(...arrays) {
|
|
511
517
|
|
512
518
|
// src/sm2/index.ts
|
513
519
|
import * as mod2 from "@noble/curves/abstract/modular";
|
520
|
+
import * as utils4 from "@noble/curves/abstract/utils";
|
521
|
+
|
522
|
+
// src/sm2/kx.ts
|
514
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
|
515
567
|
var C1C2C3 = 0;
|
516
568
|
function doEncrypt(msg, publicKey, cipherMode = 1) {
|
517
569
|
const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
|
518
570
|
const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
519
571
|
const keypair = generateKeyPairHex();
|
520
|
-
const k =
|
572
|
+
const k = utils4.hexToNumber(keypair.privateKey);
|
521
573
|
let c1 = keypair.publicKey;
|
522
574
|
if (c1.length > 128)
|
523
575
|
c1 = c1.substring(c1.length - 128);
|
524
576
|
const p = publicKeyPoint.multiply(k);
|
525
|
-
const x2 = hexToArray(leftPad2(
|
526
|
-
const y2 = hexToArray(leftPad2(
|
577
|
+
const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
|
578
|
+
const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
|
527
579
|
const c3 = arrayToHex(Array.from(sm3(concatArray(x2, msgArr, y2))));
|
528
580
|
let ct = 1;
|
529
581
|
let offset = 0;
|
@@ -546,7 +598,7 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
|
|
546
598
|
function doDecrypt(encryptData, privateKey, cipherMode = 1, {
|
547
599
|
output = "string"
|
548
600
|
} = {}) {
|
549
|
-
const privateKeyInteger =
|
601
|
+
const privateKeyInteger = utils4.hexToNumber(privateKey);
|
550
602
|
let c3 = encryptData.substring(128, 128 + 64);
|
551
603
|
let c2 = encryptData.substring(128 + 64);
|
552
604
|
if (cipherMode === C1C2C3) {
|
@@ -556,8 +608,8 @@ function doDecrypt(encryptData, privateKey, cipherMode = 1, {
|
|
556
608
|
const msg = hexToArray(c2);
|
557
609
|
const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
|
558
610
|
const p = c1.multiply(privateKeyInteger);
|
559
|
-
const x2 = hexToArray(leftPad2(
|
560
|
-
const y2 = hexToArray(leftPad2(
|
611
|
+
const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
|
612
|
+
const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
|
561
613
|
let ct = 1;
|
562
614
|
let offset = 0;
|
563
615
|
let t = new Uint8Array();
|
@@ -593,8 +645,8 @@ function doSignature(msg, privateKey, options = {}) {
|
|
593
645
|
publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey);
|
594
646
|
hashHex = getHash(hashHex, publicKey, userId);
|
595
647
|
}
|
596
|
-
const dA =
|
597
|
-
const e =
|
648
|
+
const dA = utils4.hexToNumber(privateKey);
|
649
|
+
const e = utils4.hexToNumber(hashHex);
|
598
650
|
let k = null;
|
599
651
|
let r = null;
|
600
652
|
let s = null;
|
@@ -613,7 +665,7 @@ function doSignature(msg, privateKey, options = {}) {
|
|
613
665
|
} while (s === ZERO);
|
614
666
|
if (der)
|
615
667
|
return encodeDer(r, s);
|
616
|
-
return leftPad2(
|
668
|
+
return leftPad2(utils4.numberToHexUnpadded(r), 64) + leftPad2(utils4.numberToHexUnpadded(s), 64);
|
617
669
|
}
|
618
670
|
function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
619
671
|
let hashHex;
|
@@ -634,11 +686,11 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
634
686
|
r = decodeDerObj.r;
|
635
687
|
s = decodeDerObj.s;
|
636
688
|
} else {
|
637
|
-
r =
|
638
|
-
s =
|
689
|
+
r = utils4.hexToNumber(signHex.substring(0, 64));
|
690
|
+
s = utils4.hexToNumber(signHex.substring(64));
|
639
691
|
}
|
640
692
|
const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
641
|
-
const e =
|
693
|
+
const e = utils4.hexToNumber(hashHex);
|
642
694
|
const t = mod2.mod(r + s, sm2Curve.CURVE.n);
|
643
695
|
if (t === ZERO)
|
644
696
|
return false;
|
@@ -648,10 +700,10 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
|
|
648
700
|
}
|
649
701
|
function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
650
702
|
userId = utf8ToHex(userId);
|
651
|
-
const a = leftPad2(
|
652
|
-
const b = leftPad2(
|
653
|
-
const gx = leftPad2(
|
654
|
-
const gy = leftPad2(
|
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);
|
655
707
|
let px;
|
656
708
|
let py;
|
657
709
|
if (publicKey.length === 128) {
|
@@ -659,8 +711,8 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
|
659
711
|
py = publicKey.substring(64, 128);
|
660
712
|
} else {
|
661
713
|
const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
|
662
|
-
px = leftPad2(
|
663
|
-
py = leftPad2(
|
714
|
+
px = leftPad2(utils4.numberToHexUnpadded(point.x), 64);
|
715
|
+
py = leftPad2(utils4.numberToHexUnpadded(point.y), 64);
|
664
716
|
}
|
665
717
|
const data = hexToArray(userId + a + b + gx + gy + px + py);
|
666
718
|
const entl = userId.length * 4;
|
@@ -669,13 +721,13 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
|
|
669
721
|
}
|
670
722
|
function getPublicKeyFromPrivateKey(privateKey) {
|
671
723
|
const pubKey = sm2Curve.getPublicKey(privateKey, false);
|
672
|
-
const pubPad = leftPad2(
|
724
|
+
const pubPad = leftPad2(utils4.bytesToHex(pubKey), 64);
|
673
725
|
return pubPad;
|
674
726
|
}
|
675
727
|
function getPoint() {
|
676
728
|
const keypair = generateKeyPairHex();
|
677
729
|
const PA = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
|
678
|
-
const k =
|
730
|
+
const k = utils4.hexToNumber(keypair.privateKey);
|
679
731
|
return {
|
680
732
|
...keypair,
|
681
733
|
k,
|
package/package.json
CHANGED
package/src/sm2/ec.ts
CHANGED
@@ -19,11 +19,14 @@ declare module wx {
|
|
19
19
|
}): void;
|
20
20
|
}
|
21
21
|
|
22
|
-
const DEFAULT_PRNG_POOL_SIZE =
|
22
|
+
const DEFAULT_PRNG_POOL_SIZE = 16384
|
23
23
|
let prngPool = new Uint8Array(0)
|
24
|
-
|
25
|
-
async function
|
26
|
-
if ('crypto' in globalThis)
|
24
|
+
let _syncCrypto: typeof import('crypto')['webcrypto']
|
25
|
+
export async function initRNGPool() {
|
26
|
+
if ('crypto' in globalThis) {
|
27
|
+
_syncCrypto = globalThis.crypto
|
28
|
+
return // no need to use pooling
|
29
|
+
}
|
27
30
|
if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2) return // there is sufficient number
|
28
31
|
// we always populate full pool size
|
29
32
|
// since numbers may be consumed during micro tasks.
|
@@ -40,8 +43,9 @@ async function FillPRNGPoolIfNeeded() {
|
|
40
43
|
// check if node, use webcrypto if available
|
41
44
|
try {
|
42
45
|
const crypto = await import(/* webpackIgnore: true */ 'crypto');
|
46
|
+
_syncCrypto = crypto.webcrypto
|
43
47
|
const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
|
44
|
-
|
48
|
+
_syncCrypto.getRandomValues(array);
|
45
49
|
prngPool = array;
|
46
50
|
} catch (error) {
|
47
51
|
throw new Error('no available csprng, abort.');
|
@@ -49,24 +53,25 @@ async function FillPRNGPoolIfNeeded() {
|
|
49
53
|
}
|
50
54
|
}
|
51
55
|
|
52
|
-
|
56
|
+
initRNGPool()
|
53
57
|
|
54
58
|
function consumePool(length: number): Uint8Array {
|
55
59
|
if (prngPool.length > length) {
|
56
60
|
const prng = prngPool.slice(0, length)
|
57
61
|
prngPool = prngPool.slice(length)
|
58
|
-
|
62
|
+
initRNGPool()
|
59
63
|
return prng
|
60
64
|
} else {
|
61
|
-
throw new Error('random number pool is insufficient, prevent getting too long random values or too often.')
|
65
|
+
throw new Error('random number pool is not ready or insufficient, prevent getting too long random values or too often.')
|
62
66
|
}
|
63
67
|
}
|
64
68
|
|
65
69
|
export function randomBytes(length = 0): Uint8Array {
|
66
70
|
const array = new Uint8Array(length);
|
67
|
-
if (
|
68
|
-
return
|
71
|
+
if (_syncCrypto) {
|
72
|
+
return _syncCrypto.getRandomValues(array);
|
69
73
|
} else {
|
74
|
+
// no sync crypto available, use async pool
|
70
75
|
const result = consumePool(length)
|
71
76
|
return result
|
72
77
|
}
|
package/src/sm2/index.ts
CHANGED
@@ -2,12 +2,15 @@
|
|
2
2
|
import { encodeDer, decodeDer } from './asn1'
|
3
3
|
import { arrayToHex, arrayToUtf8, concatArray, generateKeyPairHex, hexToArray, leftPad, utf8ToHex } from './utils'
|
4
4
|
import { sm3 } from './sm3'
|
5
|
-
export * from './utils'
|
6
5
|
import * as mod from '@noble/curves/abstract/modular';
|
7
6
|
import * as utils from '@noble/curves/abstract/utils';
|
8
7
|
import { sm2Curve } from './ec';
|
9
8
|
import { ONE, ZERO } from './bn';
|
10
9
|
|
10
|
+
export * from './utils'
|
11
|
+
export { initRNGPool } from './ec'
|
12
|
+
export { calculateSharedKey } from './kx'
|
13
|
+
|
11
14
|
// const { G, curve, n } = generateEcparam()
|
12
15
|
const C1C2C3 = 0
|
13
16
|
|
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)
|