sm-crypto-v2 1.8.0 → 1.9.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 +8 -0
- package/dist/index.d.mts +175 -0
- package/dist/index.d.ts +18 -47
- package/dist/index.js +13 -0
- package/dist/index.mjs +9 -0
- package/miniprogram_dist/index.d.ts +175 -0
- package/miniprogram_dist/index.js +3780 -0
- package/package.json +8 -4
- package/{tsup.config.ts → tsup.config.miniprogram.ts} +9 -4
- package/src/index.ts +0 -3
- package/src/sm2/asn1.ts +0 -210
- package/src/sm2/bn.ts +0 -4
- package/src/sm2/ec.ts +0 -24
- package/src/sm2/hmac.ts +0 -76
- package/src/sm2/index.ts +0 -319
- package/src/sm2/kx.ts +0 -83
- package/src/sm2/rng.ts +0 -77
- package/src/sm2/sm3.ts +0 -241
- package/src/sm2/utils.ts +0 -164
- package/src/sm3/index.ts +0 -72
- package/src/sm3/utils.ts +0 -117
- package/src/sm4/_slow.ts +0 -286
- package/src/sm4/index.ts +0 -322
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -22
- package/webpack.config.js +0 -26
package/src/sm2/kx.ts
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
import { field, sm2Curve } from './ec';
|
2
|
-
import { KeyPair, hexToArray, leftPad } from './utils';
|
3
|
-
import * as utils from '@noble/curves/abstract/utils';
|
4
|
-
import { sm3 } from './sm3';
|
5
|
-
import { EmptyArray, getZ } from '.';
|
6
|
-
|
7
|
-
|
8
|
-
// 用到的常数
|
9
|
-
const wPow2 = utils.hexToNumber('80000000000000000000000000000000')
|
10
|
-
const wPow2Sub1 = utils.hexToNumber('7fffffffffffffffffffffffffffffff')
|
11
|
-
|
12
|
-
// from sm2 sign part, extracted for code reusable.
|
13
|
-
function hkdf(z: Uint8Array, keylen: number) {
|
14
|
-
let msg = new Uint8Array(keylen)
|
15
|
-
let ct = 1
|
16
|
-
let offset = 0
|
17
|
-
let t = EmptyArray
|
18
|
-
const ctShift = new Uint8Array(4)
|
19
|
-
const nextT = () => {
|
20
|
-
// (1) Hai = hash(z || ct)
|
21
|
-
// (2) ct++
|
22
|
-
ctShift[0] = ct >> 24 & 0x00ff
|
23
|
-
ctShift[1] = ct >> 16 & 0x00ff
|
24
|
-
ctShift[2] = ct >> 8 & 0x00ff
|
25
|
-
ctShift[3] = ct & 0x00ff
|
26
|
-
t = sm3(utils.concatBytes(z, ctShift))
|
27
|
-
ct++
|
28
|
-
offset = 0
|
29
|
-
}
|
30
|
-
nextT() // 先生成 Ha1
|
31
|
-
|
32
|
-
for (let i = 0, len = msg.length; i < len; i++) {
|
33
|
-
// t = Ha1 || Ha2 || Ha3 || Ha4
|
34
|
-
if (offset === t.length) nextT()
|
35
|
-
|
36
|
-
// 输出 stream
|
37
|
-
msg[i] = t[offset++] & 0xff
|
38
|
-
}
|
39
|
-
return msg
|
40
|
-
}
|
41
|
-
|
42
|
-
export function calculateSharedKey(
|
43
|
-
keypairA: KeyPair,
|
44
|
-
ephemeralKeypairA: KeyPair,
|
45
|
-
publicKeyB: string,
|
46
|
-
ephemeralPublicKeyB: string,
|
47
|
-
sharedKeyLength: number,
|
48
|
-
isRecipient = false,
|
49
|
-
idA: string = '1234567812345678',
|
50
|
-
idB: string = '1234567812345678',
|
51
|
-
) {
|
52
|
-
const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey)
|
53
|
-
const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB)
|
54
|
-
// const PA = sm2Curve.ProjectivePoint.fromHex(keypairA.publicKey) // 用不到
|
55
|
-
const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB)
|
56
|
-
let ZA = getZ(keypairA.publicKey, idA)
|
57
|
-
let ZB = getZ(publicKeyB, idB)
|
58
|
-
if (isRecipient) {
|
59
|
-
[ZA, ZB] = [ZB, ZA];
|
60
|
-
}
|
61
|
-
const rA = utils.hexToNumber(ephemeralKeypairA.privateKey)
|
62
|
-
const dA = utils.hexToNumber(keypairA.privateKey)
|
63
|
-
// 1.先算 tA
|
64
|
-
const x1 = RA.x
|
65
|
-
// x1_ = 2^w + (x1 & (2^w - 1))
|
66
|
-
const x1_ = wPow2 + (x1 & wPow2Sub1)
|
67
|
-
// tA = (dA + x1b * rA) mod n
|
68
|
-
const tA = field.add(dA, field.mulN(x1_, rA))
|
69
|
-
|
70
|
-
// 2.算 U
|
71
|
-
// x2_ = 2^w + (x2 & (2^w - 1))
|
72
|
-
const x2 = RB.x
|
73
|
-
const x2_ = field.add(wPow2, (x2 & wPow2Sub1))
|
74
|
-
// U = [h * tA](PB + x2_ * RB)
|
75
|
-
const U = RB.multiply(x2_).add(PB).multiply(tA)
|
76
|
-
|
77
|
-
// 3.算 KDF
|
78
|
-
// KA = KDF(xU || yU || ZA || ZB, kLen)
|
79
|
-
const xU = hexToArray(leftPad(utils.numberToHexUnpadded(U.x), 64))
|
80
|
-
const yU = hexToArray(leftPad(utils.numberToHexUnpadded(U.y), 64))
|
81
|
-
const KA = hkdf(utils.concatBytes(xU, yU, ZA, ZB), sharedKeyLength)
|
82
|
-
return KA
|
83
|
-
}
|
package/src/sm2/rng.ts
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
// Secure RNG Generator wrapper
|
2
|
-
// 1. Use native sync API if available
|
3
|
-
// 2. Use async API and maintain number pool if available
|
4
|
-
// 3. Throw error if none of above available
|
5
|
-
// Web: globalThis.crypto
|
6
|
-
// Node: async import("crypto").webcrypto
|
7
|
-
// Mini Program: wx.getRandomValues
|
8
|
-
declare module wx {
|
9
|
-
function getRandomValues(options: {
|
10
|
-
length: number;
|
11
|
-
success: (res: { randomValues: ArrayBuffer }) => void;
|
12
|
-
}): void;
|
13
|
-
}
|
14
|
-
|
15
|
-
const DEFAULT_PRNG_POOL_SIZE = 16384
|
16
|
-
let prngPool = new Uint8Array(0)
|
17
|
-
let _syncCrypto: typeof import('crypto')['webcrypto']
|
18
|
-
export async function initRNGPool() {
|
19
|
-
if ('crypto' in globalThis) {
|
20
|
-
_syncCrypto = globalThis.crypto
|
21
|
-
return // no need to use pooling
|
22
|
-
}
|
23
|
-
if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2) return // there is sufficient number
|
24
|
-
// we always populate full pool size
|
25
|
-
// since numbers may be consumed during micro tasks.
|
26
|
-
if ('wx' in globalThis && 'getRandomValues' in globalThis.wx) {
|
27
|
-
prngPool = await new Promise(r => {
|
28
|
-
wx.getRandomValues({
|
29
|
-
length: DEFAULT_PRNG_POOL_SIZE,
|
30
|
-
success(res) {
|
31
|
-
r(new Uint8Array(res.randomValues));
|
32
|
-
}
|
33
|
-
});
|
34
|
-
});
|
35
|
-
} else {
|
36
|
-
// check if node or browser, use webcrypto if available
|
37
|
-
try {
|
38
|
-
// node 19+ and browser
|
39
|
-
if (globalThis.crypto) {
|
40
|
-
_syncCrypto = globalThis.crypto
|
41
|
-
} else {
|
42
|
-
// node below 19
|
43
|
-
const crypto = await import(/* webpackIgnore: true */ 'crypto');
|
44
|
-
_syncCrypto = crypto.webcrypto
|
45
|
-
}
|
46
|
-
const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
|
47
|
-
_syncCrypto.getRandomValues(array);
|
48
|
-
prngPool = array;
|
49
|
-
} catch (error) {
|
50
|
-
throw new Error('no available csprng, abort.');
|
51
|
-
}
|
52
|
-
}
|
53
|
-
}
|
54
|
-
|
55
|
-
initRNGPool()
|
56
|
-
|
57
|
-
function consumePool(length: number): Uint8Array {
|
58
|
-
if (prngPool.length > length) {
|
59
|
-
const prng = prngPool.slice(0, length)
|
60
|
-
prngPool = prngPool.slice(length)
|
61
|
-
initRNGPool()
|
62
|
-
return prng
|
63
|
-
} else {
|
64
|
-
throw new Error('random number pool is not ready or insufficient, prevent getting too long random values or too often.')
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
export function randomBytes(length = 0): Uint8Array {
|
69
|
-
const array = new Uint8Array(length);
|
70
|
-
if (_syncCrypto) {
|
71
|
-
return _syncCrypto.getRandomValues(array);
|
72
|
-
} else {
|
73
|
-
// no sync crypto available, use async pool
|
74
|
-
const result = consumePool(length)
|
75
|
-
return result
|
76
|
-
}
|
77
|
-
}
|
package/src/sm2/sm3.ts
DELETED
@@ -1,241 +0,0 @@
|
|
1
|
-
// import assert from './_assert.js';
|
2
|
-
import { Hash, createView, Input, toBytes, wrapConstructor } from '../sm3/utils.js';
|
3
|
-
|
4
|
-
const BoolA = (A: number, B: number, C: number) => ((A & B) | (A & C)) | (B & C)
|
5
|
-
const BoolB = (A: number, B: number, C: number) => ((A ^ B) ^ C)
|
6
|
-
const BoolC = (A: number, B: number, C: number) => (A & B) | ((~A) & C)
|
7
|
-
// Polyfill for Safari 14
|
8
|
-
function setBigUint64(view: DataView, byteOffset: number, value: bigint, isLE: boolean): void {
|
9
|
-
if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);
|
10
|
-
const _32n = BigInt(32);
|
11
|
-
const _u32_max = BigInt(0xffffffff);
|
12
|
-
const wh = Number((value >> _32n) & _u32_max);
|
13
|
-
const wl = Number(value & _u32_max);
|
14
|
-
const h = isLE ? 4 : 0;
|
15
|
-
const l = isLE ? 0 : 4;
|
16
|
-
view.setUint32(byteOffset + h, wh, isLE);
|
17
|
-
view.setUint32(byteOffset + l, wl, isLE);
|
18
|
-
}
|
19
|
-
|
20
|
-
/**
|
21
|
-
* 循环左移
|
22
|
-
*/
|
23
|
-
export function rotl(x: number, n: number) {
|
24
|
-
const s = n & 31
|
25
|
-
return (x << s) | (x >>> (32 - s))
|
26
|
-
}
|
27
|
-
|
28
|
-
/**
|
29
|
-
* 二进制异或运算
|
30
|
-
*/
|
31
|
-
function xor(x: Uint8Array, y: Uint8Array) {
|
32
|
-
const result = new Uint8Array(x.length)
|
33
|
-
for (let i = x.length - 1; i >= 0; i--) result[i] = (x[i] ^ y[i]) & 0xff
|
34
|
-
return result
|
35
|
-
}
|
36
|
-
|
37
|
-
/**
|
38
|
-
* 压缩函数中的置换函数 P0(X) = X xor (X <<< 9) xor (X <<< 17)
|
39
|
-
*/
|
40
|
-
function P0(X: number) {
|
41
|
-
return (X ^ rotl(X, 9)) ^ rotl(X, 17)
|
42
|
-
}
|
43
|
-
|
44
|
-
/**
|
45
|
-
* 消息扩展中的置换函数 P1(X) = X xor (X <<< 15) xor (X <<< 23)
|
46
|
-
*/
|
47
|
-
function P1(X: number) {
|
48
|
-
return (X ^ rotl(X, 15)) ^ rotl(X, 23)
|
49
|
-
}
|
50
|
-
|
51
|
-
// from noble-hashes (https://github.com/paulmillr/noble-hashes#hmac)
|
52
|
-
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
53
|
-
|
54
|
-
// Base SHA2 class (RFC 6234)
|
55
|
-
export abstract class SHA2<T extends SHA2<T>> extends Hash<T> {
|
56
|
-
protected abstract process(buf: DataView, offset: number): void;
|
57
|
-
protected abstract get(): number[];
|
58
|
-
protected abstract set(...args: number[]): void;
|
59
|
-
abstract destroy(): void;
|
60
|
-
protected abstract roundClean(): void;
|
61
|
-
// For partial updates less than block size
|
62
|
-
protected buffer: Uint8Array;
|
63
|
-
protected view: DataView;
|
64
|
-
protected finished = false;
|
65
|
-
protected length = 0;
|
66
|
-
protected pos = 0;
|
67
|
-
protected destroyed = false;
|
68
|
-
|
69
|
-
constructor(
|
70
|
-
readonly blockLen: number,
|
71
|
-
public outputLen: number,
|
72
|
-
readonly padOffset: number,
|
73
|
-
readonly isLE: boolean
|
74
|
-
) {
|
75
|
-
super();
|
76
|
-
this.buffer = new Uint8Array(blockLen);
|
77
|
-
this.view = createView(this.buffer);
|
78
|
-
}
|
79
|
-
update(data: Input): this {
|
80
|
-
const { view, buffer, blockLen } = this;
|
81
|
-
data = toBytes(data);
|
82
|
-
const len = data.length;
|
83
|
-
for (let pos = 0; pos < len; ) {
|
84
|
-
const take = Math.min(blockLen - this.pos, len - pos);
|
85
|
-
// Fast path: we have at least one block in input, cast it to view and process
|
86
|
-
if (take === blockLen) {
|
87
|
-
const dataView = createView(data);
|
88
|
-
for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);
|
89
|
-
continue;
|
90
|
-
}
|
91
|
-
buffer.set(data.subarray(pos, pos + take), this.pos);
|
92
|
-
this.pos += take;
|
93
|
-
pos += take;
|
94
|
-
if (this.pos === blockLen) {
|
95
|
-
this.process(view, 0);
|
96
|
-
this.pos = 0;
|
97
|
-
}
|
98
|
-
}
|
99
|
-
this.length += data.length;
|
100
|
-
this.roundClean();
|
101
|
-
return this;
|
102
|
-
}
|
103
|
-
digestInto(out: Uint8Array) {
|
104
|
-
this.finished = true;
|
105
|
-
// Padding
|
106
|
-
// We can avoid allocation of buffer for padding completely if it
|
107
|
-
// was previously not allocated here. But it won't change performance.
|
108
|
-
const { buffer, view, blockLen, isLE } = this;
|
109
|
-
let { pos } = this;
|
110
|
-
// append the bit '1' to the message
|
111
|
-
buffer[pos++] = 0b10000000;
|
112
|
-
this.buffer.subarray(pos).fill(0);
|
113
|
-
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
|
114
|
-
if (this.padOffset > blockLen - pos) {
|
115
|
-
this.process(view, 0);
|
116
|
-
pos = 0;
|
117
|
-
}
|
118
|
-
// Pad until full block byte with zeros
|
119
|
-
for (let i = pos; i < blockLen; i++) buffer[i] = 0;
|
120
|
-
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
|
121
|
-
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
|
122
|
-
// So we just write lowest 64 bits of that value.
|
123
|
-
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
|
124
|
-
this.process(view, 0);
|
125
|
-
const oview = createView(out);
|
126
|
-
const len = this.outputLen;
|
127
|
-
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
|
128
|
-
if (len % 4) throw new Error('_sha2: outputLen should be aligned to 32bit');
|
129
|
-
const outLen = len / 4;
|
130
|
-
const state = this.get();
|
131
|
-
if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');
|
132
|
-
for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);
|
133
|
-
}
|
134
|
-
digest() {
|
135
|
-
const { buffer, outputLen } = this;
|
136
|
-
this.digestInto(buffer);
|
137
|
-
const res = buffer.slice(0, outputLen);
|
138
|
-
this.destroy();
|
139
|
-
return res;
|
140
|
-
}
|
141
|
-
_cloneInto(to?: T): T {
|
142
|
-
to ||= new (this.constructor as any)() as T;
|
143
|
-
to.set(...this.get());
|
144
|
-
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
145
|
-
to.length = length;
|
146
|
-
to.pos = pos;
|
147
|
-
to.finished = finished;
|
148
|
-
to.destroyed = destroyed;
|
149
|
-
if (length % blockLen) to.buffer.set(buffer);
|
150
|
-
return to;
|
151
|
-
}
|
152
|
-
}
|
153
|
-
|
154
|
-
const IV = new Uint32Array([0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e])
|
155
|
-
const SM3_W = new Uint32Array(68)
|
156
|
-
const SM3_M = new Uint32Array(64)
|
157
|
-
|
158
|
-
const T1 = 0x79cc4519
|
159
|
-
const T2 = 0x7a879d8a
|
160
|
-
|
161
|
-
class SM3 extends SHA2<SM3> {
|
162
|
-
// We cannot use array here since array allows indexing by variable
|
163
|
-
// which means optimizer/compiler cannot use registers.
|
164
|
-
A = IV[0] | 0;
|
165
|
-
B = IV[1] | 0;
|
166
|
-
C = IV[2] | 0;
|
167
|
-
D = IV[3] | 0;
|
168
|
-
E = IV[4] | 0;
|
169
|
-
F = IV[5] | 0;
|
170
|
-
G = IV[6] | 0;
|
171
|
-
H = IV[7] | 0;
|
172
|
-
|
173
|
-
constructor() {
|
174
|
-
super(64, 32, 8, false);
|
175
|
-
}
|
176
|
-
protected get(): [number, number, number, number, number, number, number, number] {
|
177
|
-
const { A, B, C, D, E, F, G, H } = this;
|
178
|
-
return [A, B, C, D, E, F, G, H];
|
179
|
-
}
|
180
|
-
// prettier-ignore
|
181
|
-
protected set(
|
182
|
-
A: number, B: number, C: number, D: number, E: number, F: number, G: number, H: number
|
183
|
-
) {
|
184
|
-
this.A = A | 0;
|
185
|
-
this.B = B | 0;
|
186
|
-
this.C = C | 0;
|
187
|
-
this.D = D | 0;
|
188
|
-
this.E = E | 0;
|
189
|
-
this.F = F | 0;
|
190
|
-
this.G = G | 0;
|
191
|
-
this.H = H | 0;
|
192
|
-
}
|
193
|
-
protected process(view: DataView, offset: number): void {
|
194
|
-
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
|
195
|
-
for (let i = 0; i < 16; i++, offset += 4) SM3_W[i] = view.getUint32(offset, false);
|
196
|
-
for (let i = 16; i < 68; i++) {
|
197
|
-
SM3_W[i] = (P1((SM3_W[i- 16] ^ SM3_W[i - 9]) ^ rotl(SM3_W[i - 3], 15)) ^ rotl(SM3_W[i - 13], 7)) ^ SM3_W[i - 6]
|
198
|
-
}
|
199
|
-
for (let i = 0; i < 64; i++) {
|
200
|
-
SM3_M[i] = SM3_W[i] ^ SM3_W[i + 4]
|
201
|
-
}
|
202
|
-
// Compression function main loop, 64 rounds
|
203
|
-
let { A, B, C, D, E, F, G, H } = this;
|
204
|
-
for (let j = 0; j < 64; j++) {
|
205
|
-
let small = j >= 0 && j <= 15
|
206
|
-
let T = small ? T1 : T2
|
207
|
-
let SS1 = rotl(rotl(A, 12) + E + rotl(T, j), 7)
|
208
|
-
let SS2 = SS1 ^ rotl(A, 12)
|
209
|
-
|
210
|
-
let TT1 = ((small ? BoolB(A, B, C) : BoolA(A, B, C)) + D + SS2 + SM3_M[j]) | 0
|
211
|
-
let TT2 = ((small ? BoolB(E, F, G) : BoolC(E, F, G)) + H + SS1 + SM3_W[j]) | 0
|
212
|
-
|
213
|
-
D = C
|
214
|
-
C = rotl(B, 9)
|
215
|
-
B = A
|
216
|
-
A = TT1
|
217
|
-
H = G
|
218
|
-
G = rotl(F, 19)
|
219
|
-
F = E
|
220
|
-
E = P0(TT2)
|
221
|
-
}
|
222
|
-
// Add the compressed chunk to the current hash value
|
223
|
-
A = (A ^ this.A) | 0;
|
224
|
-
B = (B ^ this.B) | 0;
|
225
|
-
C = (C ^ this.C) | 0;
|
226
|
-
D = (D ^ this.D) | 0;
|
227
|
-
E = (E ^ this.E) | 0;
|
228
|
-
F = (F ^ this.F) | 0;
|
229
|
-
G = (G ^ this.G) | 0;
|
230
|
-
H = (H ^ this.H) | 0;
|
231
|
-
this.set(A, B, C, D, E, F, G, H);
|
232
|
-
}
|
233
|
-
protected roundClean() {
|
234
|
-
SM3_W.fill(0);
|
235
|
-
}
|
236
|
-
destroy() {
|
237
|
-
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
238
|
-
this.buffer.fill(0);
|
239
|
-
}
|
240
|
-
}
|
241
|
-
export const sm3 = wrapConstructor(() => new SM3());
|
package/src/sm2/utils.ts
DELETED
@@ -1,164 +0,0 @@
|
|
1
|
-
/* eslint-disable no-bitwise, no-mixed-operators, no-use-before-define, max-len */
|
2
|
-
import * as utils from '@noble/curves/abstract/utils';
|
3
|
-
|
4
|
-
import { sm2Curve, sm2Fp } from './ec';
|
5
|
-
import { mod } from '@noble/curves/abstract/modular';
|
6
|
-
import { ONE, TWO, ZERO } from './bn';
|
7
|
-
|
8
|
-
export interface KeyPair {
|
9
|
-
privateKey: string
|
10
|
-
publicKey: string
|
11
|
-
}
|
12
|
-
|
13
|
-
/**
|
14
|
-
* 生成密钥对:publicKey = privateKey * G
|
15
|
-
*/
|
16
|
-
export function generateKeyPairHex(str?: string): KeyPair {
|
17
|
-
const privateKey = str ? utils.numberToBytesBE((mod(BigInt(str), ONE) + ONE), 32) : sm2Curve.utils.randomPrivateKey()
|
18
|
-
// const random = typeof a === 'string' ? new BigInteger(a, b) :
|
19
|
-
// a ? new BigInteger(a, b!, c!) : new BigInteger(n.bitLength(), rng)
|
20
|
-
// const d = random.mod(n.subtract(BigInteger.ONE)).add(BigInteger.ONE) // 随机数
|
21
|
-
// const privateKey = leftPad(d.toString(16), 64)
|
22
|
-
|
23
|
-
// const P = G!.multiply(d) // P = dG,p 为公钥,d 为私钥
|
24
|
-
// const Px = leftPad(P.getX().toBigInteger().toString(16), 64)
|
25
|
-
// const Py = leftPad(P.getY().toBigInteger().toString(16), 64)
|
26
|
-
// const publicKey = '04' + Px + Py
|
27
|
-
const publicKey = sm2Curve.getPublicKey(privateKey, false);
|
28
|
-
const privPad = leftPad(utils.bytesToHex(privateKey), 64)
|
29
|
-
const pubPad = leftPad(utils.bytesToHex(publicKey), 64)
|
30
|
-
return {privateKey: privPad, publicKey: pubPad}
|
31
|
-
}
|
32
|
-
|
33
|
-
/**
|
34
|
-
* 生成压缩公钥
|
35
|
-
*/
|
36
|
-
export function compressPublicKeyHex(s: string) {
|
37
|
-
if (s.length !== 130) throw new Error('Invalid public key to compress')
|
38
|
-
|
39
|
-
const len = (s.length - 2) / 2
|
40
|
-
const xHex = s.substring(2, 2 + len)
|
41
|
-
const y = utils.hexToNumber(s.substring(len + 2, len + len + 2))
|
42
|
-
|
43
|
-
let prefix = '03'
|
44
|
-
if (mod(y, TWO) === ZERO) prefix = '02'
|
45
|
-
return prefix + xHex
|
46
|
-
}
|
47
|
-
|
48
|
-
/**
|
49
|
-
* utf8串转16进制串
|
50
|
-
*/
|
51
|
-
export function utf8ToHex(input: string) {
|
52
|
-
input = decodeURIComponent(encodeURIComponent(input))
|
53
|
-
|
54
|
-
const length = input.length
|
55
|
-
|
56
|
-
// 转换到字数组
|
57
|
-
const words = new Uint32Array((length >>> 2) + 1)
|
58
|
-
for (let i = 0; i < length; i++) {
|
59
|
-
words[i >>> 2] |= (input.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8)
|
60
|
-
}
|
61
|
-
|
62
|
-
// 转换到16进制
|
63
|
-
const hexChars: string[]= []
|
64
|
-
for (let i = 0; i < length; i++) {
|
65
|
-
const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
|
66
|
-
hexChars.push((bite >>> 4).toString(16))
|
67
|
-
hexChars.push((bite & 0x0f).toString(16))
|
68
|
-
}
|
69
|
-
|
70
|
-
return hexChars.join('')
|
71
|
-
}
|
72
|
-
|
73
|
-
/**
|
74
|
-
* 补全16进制字符串
|
75
|
-
*/
|
76
|
-
export function leftPad(input: string, num: number) {
|
77
|
-
if (input.length >= num) return input
|
78
|
-
|
79
|
-
return (new Array(num - input.length + 1)).join('0') + input
|
80
|
-
}
|
81
|
-
|
82
|
-
/**
|
83
|
-
* 转成16进制串
|
84
|
-
*/
|
85
|
-
export function arrayToHex(arr: number[]) {
|
86
|
-
return arr.map(item => {
|
87
|
-
const hex = item.toString(16)
|
88
|
-
return hex.length === 1 ? '0' + hex : hex
|
89
|
-
}).join('')
|
90
|
-
}
|
91
|
-
|
92
|
-
/**
|
93
|
-
* 转成utf8串
|
94
|
-
*/
|
95
|
-
export function arrayToUtf8(arr: Uint8Array) {
|
96
|
-
const str: string[] = []
|
97
|
-
for (let i = 0, len = arr.length; i < len; i++) {
|
98
|
-
if (arr[i] >= 0xf0 && arr[i] <= 0xf7) {
|
99
|
-
// 四字节
|
100
|
-
str.push(String.fromCodePoint(((arr[i] & 0x07) << 18) + ((arr[i + 1] & 0x3f) << 12) + ((arr[i + 2] & 0x3f) << 6) + (arr[i + 3] & 0x3f)))
|
101
|
-
i += 3
|
102
|
-
} else if (arr[i] >= 0xe0 && arr[i] <= 0xef) {
|
103
|
-
// 三字节
|
104
|
-
str.push(String.fromCodePoint(((arr[i] & 0x0f) << 12) + ((arr[i + 1] & 0x3f) << 6) + (arr[i + 2] & 0x3f)))
|
105
|
-
i += 2
|
106
|
-
} else if (arr[i] >= 0xc0 && arr[i] <= 0xdf) {
|
107
|
-
// 双字节
|
108
|
-
str.push(String.fromCodePoint(((arr[i] & 0x1f) << 6) + (arr[i + 1] & 0x3f)))
|
109
|
-
i++
|
110
|
-
} else {
|
111
|
-
// 单字节
|
112
|
-
str.push(String.fromCodePoint(arr[i]))
|
113
|
-
}
|
114
|
-
}
|
115
|
-
|
116
|
-
return str.join('')
|
117
|
-
}
|
118
|
-
|
119
|
-
/**
|
120
|
-
* 转成字节数组
|
121
|
-
*/
|
122
|
-
export function hexToArray(hexStr: string) {
|
123
|
-
let hexStrLength = hexStr.length
|
124
|
-
|
125
|
-
if (hexStrLength % 2 !== 0) {
|
126
|
-
hexStr = leftPad(hexStr, hexStrLength + 1)
|
127
|
-
}
|
128
|
-
|
129
|
-
hexStrLength = hexStr.length
|
130
|
-
const wordLength = hexStrLength / 2
|
131
|
-
const words = new Uint8Array(wordLength)
|
132
|
-
|
133
|
-
for (let i = 0; i < wordLength; i++) {
|
134
|
-
words[i] = (parseInt(hexStr.substring(i * 2, i * 2 + 2), 16))
|
135
|
-
}
|
136
|
-
return words
|
137
|
-
}
|
138
|
-
|
139
|
-
/**
|
140
|
-
* 验证公钥是否为椭圆曲线上的点
|
141
|
-
*/
|
142
|
-
export function verifyPublicKey(publicKey: string) {
|
143
|
-
const point = sm2Curve.ProjectivePoint.fromHex(publicKey)
|
144
|
-
if (!point) return false
|
145
|
-
try {
|
146
|
-
point.assertValidity()
|
147
|
-
return true
|
148
|
-
} catch (error) {
|
149
|
-
return false
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
/**
|
154
|
-
* 验证公钥是否等价,等价返回true
|
155
|
-
*/
|
156
|
-
export function comparePublicKeyHex(publicKey1: string, publicKey2: string) {
|
157
|
-
const point1 = sm2Curve.ProjectivePoint.fromHex(publicKey1)
|
158
|
-
if (!point1) return false
|
159
|
-
|
160
|
-
const point2 = sm2Curve.ProjectivePoint.fromHex(publicKey2)
|
161
|
-
if (!point2) return false
|
162
|
-
|
163
|
-
return point1.equals(point2)
|
164
|
-
}
|
package/src/sm3/index.ts
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
import { hmac } from '@/sm2/hmac'
|
2
|
-
import { sm3 as sm2sm3 } from '../sm2/sm3'
|
3
|
-
import { hexToArray } from '../sm2/utils'
|
4
|
-
import { bytesToHex } from './utils'
|
5
|
-
|
6
|
-
/**
|
7
|
-
* 补全16进制字符串
|
8
|
-
*/
|
9
|
-
// function leftPad(input, num) {
|
10
|
-
// if (input.length >= num) return input
|
11
|
-
|
12
|
-
// return (new Array(num - input.length + 1)).join('0') + input
|
13
|
-
// }
|
14
|
-
|
15
|
-
/**
|
16
|
-
* utf8 串转字节数组
|
17
|
-
*/
|
18
|
-
export function utf8ToArray(str: string) {
|
19
|
-
const arr: number[] = []
|
20
|
-
|
21
|
-
for (let i = 0, len = str.length; i < len; i++) {
|
22
|
-
const point = str.codePointAt(i)!
|
23
|
-
|
24
|
-
if (point <= 0x007f) {
|
25
|
-
// 单字节,标量值:00000000 00000000 0zzzzzzz
|
26
|
-
arr.push(point)
|
27
|
-
} else if (point <= 0x07ff) {
|
28
|
-
// 双字节,标量值:00000000 00000yyy yyzzzzzz
|
29
|
-
arr.push(0xc0 | (point >>> 6)) // 110yyyyy(0xc0-0xdf)
|
30
|
-
arr.push(0x80 | (point & 0x3f)) // 10zzzzzz(0x80-0xbf)
|
31
|
-
} else if (point <= 0xD7FF || (point >= 0xE000 && point <= 0xFFFF)) {
|
32
|
-
// 三字节:标量值:00000000 xxxxyyyy yyzzzzzz
|
33
|
-
arr.push(0xe0 | (point >>> 12)) // 1110xxxx(0xe0-0xef)
|
34
|
-
arr.push(0x80 | ((point >>> 6) & 0x3f)) // 10yyyyyy(0x80-0xbf)
|
35
|
-
arr.push(0x80 | (point & 0x3f)) // 10zzzzzz(0x80-0xbf)
|
36
|
-
} else if (point >= 0x010000 && point <= 0x10FFFF) {
|
37
|
-
// 四字节:标量值:000wwwxx xxxxyyyy yyzzzzzz
|
38
|
-
i++
|
39
|
-
arr.push((0xf0 | (point >>> 18) & 0x1c)) // 11110www(0xf0-0xf7)
|
40
|
-
arr.push((0x80 | ((point >>> 12) & 0x3f))) // 10xxxxxx(0x80-0xbf)
|
41
|
-
arr.push((0x80 | ((point >>> 6) & 0x3f))) // 10yyyyyy(0x80-0xbf)
|
42
|
-
arr.push((0x80 | (point & 0x3f))) // 10zzzzzz(0x80-0xbf)
|
43
|
-
} else {
|
44
|
-
// 五、六字节,暂时不支持
|
45
|
-
arr.push(point)
|
46
|
-
throw new Error('input is not supported')
|
47
|
-
}
|
48
|
-
}
|
49
|
-
|
50
|
-
return new Uint8Array(arr)
|
51
|
-
}
|
52
|
-
|
53
|
-
export function sm3(input: string | Uint8Array, options?: {
|
54
|
-
key: Uint8Array | string
|
55
|
-
mode?: 'hmac' | 'mac'
|
56
|
-
}) {
|
57
|
-
input = typeof input === 'string' ? utf8ToArray(input) : input
|
58
|
-
|
59
|
-
if (options) {
|
60
|
-
const mode = options.mode || 'hmac'
|
61
|
-
if (mode !== 'hmac') throw new Error('invalid mode')
|
62
|
-
|
63
|
-
let key = options.key
|
64
|
-
if (!key) throw new Error('invalid key')
|
65
|
-
|
66
|
-
key = typeof key === 'string' ? hexToArray(key) : key
|
67
|
-
return bytesToHex(hmac(sm2sm3, key, input));
|
68
|
-
}
|
69
|
-
return bytesToHex(sm2sm3(input))
|
70
|
-
}
|
71
|
-
|
72
|
-
export default sm3
|