sm-crypto-v2 1.4.0 → 1.5.1

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/src/sm2/sm3.ts CHANGED
@@ -1,8 +1,21 @@
1
- import { concatArray } from './utils'
2
-
3
- // 消息扩展
4
- const W = new Uint32Array(68)
5
- const M = new Uint32Array(64) // W'
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
+ }
6
19
 
7
20
  /**
8
21
  * 循环左移
@@ -35,83 +48,167 @@ function P1(X: number) {
35
48
  return (X ^ rotl(X, 15)) ^ rotl(X, 23)
36
49
  }
37
50
 
38
- /**
39
- * sm3 本体
40
- */
41
- export function sm3(array: Uint8Array) {
42
- let len = array.length * 8
43
- // k 是满足 len + 1 + k = 448mod512 的最小的非负整数
44
- let k = len % 512
45
- // 如果 448 <= (512 % len) < 512,需要多补充 (len % 448) 比特'0'以满足总比特长度为512的倍数
46
- k = k >= 448 ? 512 - (k % 448) - 1 : 448 - k - 1
47
-
48
- // 填充
49
- const kArr = new Array((k - 7) / 8)
50
- const lenArr = new Array(8)
51
- for (let i = 0, len = kArr.length; i < len; i++) kArr[i] = 0
52
- for (let i = 0, len = lenArr.length; i < len; i++) lenArr[i] = 0
53
- let lenString = len.toString(2)
54
- for (let i = 7; i >= 0; i--) {
55
- if (lenString.length > 8) {
56
- const start = lenString.length - 8
57
- lenArr[i] = parseInt(lenString.substring(start), 2)
58
- lenString = lenString.substring(0, start)
59
- } else if (lenString.length > 0) {
60
- lenArr[i] = parseInt(lenString, 2)
61
- lenString = ''
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
+ }
62
98
  }
99
+ this.length += data.length;
100
+ this.roundClean();
101
+ return this;
63
102
  }
64
- const m = Uint8Array.from([...array, 0x80, ...kArr, ...lenArr])
65
- const dataView = new DataView(m.buffer, 0)
66
-
67
- // 迭代压缩
68
- const n = m.length / 64
69
- const V = new Uint32Array([0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e])
70
- for (let i = 0; i < n; i++) {
71
- W.fill(0)
72
- M.fill(0)
73
-
74
- // 将消息分组B划分为 16 个字 W0, W1,……,W15
75
- const start = 16 * i
76
- for (let j = 0; j < 16; j++) {
77
- W[j] = dataView.getUint32((start + j) * 4, false)
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;
78
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
+ }
79
153
 
80
- // W16 W67:W[j] <- P1(W[j−16] xor W[j−9] xor (W[j−3] <<< 15)) xor (W[j−13] <<< 7) xor W[j−6]
81
- for (let j = 16; j < 68; j++) {
82
- W[j] = (P1((W[j - 16] ^ W[j - 9]) ^ rotl(W[j - 3], 15)) ^ rotl(W[j - 13], 7)) ^ W[j - 6]
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]
83
198
  }
84
-
85
- // W′0 ~ W′63:W′[j] = W[j] xor W[j+4]
86
- for (let j = 0; j < 64; j++) {
87
- M[j] = W[j] ^ W[j + 4]
199
+ for (let i = 0; i < 64; i++) {
200
+ SM3_M[i] = SM3_W[i] ^ SM3_W[i + 4]
88
201
  }
89
-
90
- // 压缩
91
- const T1 = 0x79cc4519
92
- const T2 = 0x7a879d8a
93
- // 字寄存器
94
- let A = V[0]
95
- let B = V[1]
96
- let C = V[2]
97
- let D = V[3]
98
- let E = V[4]
99
- let F = V[5]
100
- let G = V[6]
101
- let H = V[7]
102
- // 中间变量
103
- let SS1: number
104
- let SS2: number
105
- let TT1: number
106
- let TT2: number
107
- let T: number
202
+ // Compression function main loop, 64 rounds
203
+ let { A, B, C, D, E, F, G, H } = this;
108
204
  for (let j = 0; j < 64; j++) {
109
- T = j >= 0 && j <= 15 ? T1 : T2
110
- SS1 = rotl(rotl(A, 12) + E + rotl(T, j), 7)
111
- SS2 = SS1 ^ rotl(A, 12)
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)
112
209
 
113
- TT1 = (j >= 0 && j <= 15 ? ((A ^ B) ^ C) : (((A & B) | (A & C)) | (B & C))) + D + SS2 + M[j]
114
- TT2 = (j >= 0 && j <= 15 ? ((E ^ F) ^ G) : ((E & F) | ((~E) & G))) + H + SS1 + W[j]
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
115
212
 
116
213
  D = C
117
214
  C = rotl(B, 9)
@@ -122,53 +219,23 @@ export function sm3(array: Uint8Array) {
122
219
  F = E
123
220
  E = P0(TT2)
124
221
  }
125
-
126
- V[0] ^= A
127
- V[1] ^= B
128
- V[2] ^= C
129
- V[3] ^= D
130
- V[4] ^= E
131
- V[5] ^= F
132
- V[6] ^= G
133
- V[7] ^= H
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);
134
232
  }
135
-
136
- // 转回 uint8
137
- const result = new Uint8Array(V.length * 4)
138
- for (let i = 0, len = V.length; i < len; i++) {
139
- const word = V[i]
140
- result[i * 4] = (word & 0xff000000) >>> 24
141
- result[i * 4 + 1] = (word & 0xff0000) >>> 16
142
- result[i * 4 + 2] = (word & 0xff00) >>> 8
143
- result[i * 4 + 3] = word & 0xff
233
+ protected roundClean() {
234
+ SM3_W.fill(0);
144
235
  }
145
-
146
- return result
147
- }
148
-
149
- /**
150
- * hmac 实现
151
- */
152
- const blockLen = 64
153
- const iPad = new Uint8Array(blockLen)
154
- const oPad = new Uint8Array(blockLen)
155
- for (let i = 0; i < blockLen; i++) {
156
- iPad[i] = 0x36
157
- oPad[i] = 0x5c
158
- }
159
-
160
- export function hmac(input: Uint8Array, key: Uint8Array) {
161
- // 密钥填充
162
- if (key.length > blockLen) key = sm3(key)
163
- while (key.length < blockLen) {
164
- const padKey = new Uint8Array(blockLen)
165
- padKey.set(key)
166
- key = padKey
236
+ destroy() {
237
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
238
+ this.buffer.fill(0);
167
239
  }
168
-
169
- const iPadKey = xor(key, iPad)
170
- const oPadKey = xor(key, oPad)
171
-
172
- const hash = sm3(concatArray(iPadKey, input))
173
- return sm3(concatArray(oPadKey, hash))
174
240
  }
241
+ export const sm3 = wrapConstructor(() => new SM3());
package/src/sm2/utils.ts CHANGED
@@ -146,9 +146,7 @@ export function verifyPublicKey(publicKey: string) {
146
146
  const x = point.x
147
147
  const y = point.y
148
148
  // 验证 y^2 是否等于 x^3 + ax + b
149
- // return y.square().equals(x.multiply(x.square()).add(x.multiply(curve.a)).add(curve.b))
150
- return sm2Fp.sqr(y) === sm2Fp.add(sm2Fp.add(sm2Fp.mul(x, sm2Fp.sqr(x)), sm2Fp.mul(x, sm2Curve.CURVE.a)), sm2Curve.CURVE.b)
151
- // return y ** 2n === (x ** 3n + sm2Curve.CURVE.a * x + sm2Curve.CURVE.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)
152
150
  }
153
151
 
154
152
  /**
@@ -163,23 +161,3 @@ export function comparePublicKeyHex(publicKey1: string, publicKey2: string) {
163
161
 
164
162
  return point1.equals(point2)
165
163
  }
166
-
167
-
168
- export function concatArray(...arrays: Uint8Array[]) {
169
- // sum of individual array lengths
170
- let totalLength = arrays.reduce((acc, value) => acc + value.length, 0);
171
-
172
- if (!arrays.length) return new Uint8Array();
173
-
174
- let result = new Uint8Array(totalLength);
175
-
176
- // for each array - copy it over result
177
- // next array is copied right after the previous one
178
- let length = 0;
179
- for (let array of arrays) {
180
- result.set(array, length);
181
- length += array.length;
182
- }
183
-
184
- return result;
185
- }
package/src/sm3/index.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { hmac, sm3 as sm2sm3 } from '../sm2/sm3'
1
+ import { hmac } from '@/sm2/hmac'
2
+ import { sm3 as sm2sm3 } from '../sm2/sm3'
2
3
  import { arrayToHex, hexToArray, leftPad } from '../sm2/utils'
4
+ import { bytesToHex } from './utils'
3
5
 
4
6
  /**
5
7
  * 补全16进制字符串
@@ -62,8 +64,9 @@ export function sm3(input: string | Uint8Array, options?: {
62
64
  if (!key) throw new Error('invalid key')
63
65
 
64
66
  key = typeof key === 'string' ? hexToArray(key) : key
65
- return arrayToHex(Array.from(hmac(input, key)))
67
+ return bytesToHex(hmac(sm2sm3, key, input));
66
68
  }
67
-
68
- return arrayToHex(Array.from(sm2sm3(input)))
69
+ return bytesToHex(sm2sm3(input))
69
70
  }
71
+
72
+ export default sm3
@@ -0,0 +1,117 @@
1
+ // prettier-ignore
2
+ export type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |
3
+ Uint16Array | Int16Array | Uint32Array | Int32Array;
4
+
5
+ const u8a = (a: any): a is Uint8Array => a instanceof Uint8Array;
6
+ // Cast array to different type
7
+ export const u8 = (arr: TypedArray) => new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
8
+ export const u32 = (arr: TypedArray) =>
9
+ new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
10
+
11
+ // Cast array to view
12
+ export const createView = (arr: TypedArray) =>
13
+ new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
14
+
15
+ // The rotate right (circular right shift) operation for uint32
16
+ export const rotr = (word: number, shift: number) => (word << (32 - shift)) | (word >>> shift);
17
+
18
+ // big-endian hardware is rare. Just in case someone still decides to run hashes:
19
+ // early-throw an error because we don't support BE yet.
20
+ export const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
21
+ if (!isLE) throw new Error('Non little-endian hardware is not supported');
22
+
23
+ const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
24
+ /**
25
+ * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
26
+ */
27
+ export function bytesToHex(bytes: Uint8Array): string {
28
+ if (!u8a(bytes)) throw new Error('Uint8Array expected');
29
+ // pre-caching improves the speed 6x
30
+ let hex = '';
31
+ for (let i = 0; i < bytes.length; i++) {
32
+ hex += hexes[bytes[i]];
33
+ }
34
+ return hex;
35
+ }
36
+
37
+ /**
38
+ * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
39
+ */
40
+ export function hexToBytes(hex: string): Uint8Array {
41
+ if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
42
+ const len = hex.length;
43
+ if (len % 2) throw new Error('padded hex string expected, got unpadded hex of length ' + len);
44
+ const array = new Uint8Array(len / 2);
45
+ for (let i = 0; i < array.length; i++) {
46
+ const j = i * 2;
47
+ const hexByte = hex.slice(j, j + 2);
48
+ const byte = Number.parseInt(hexByte, 16);
49
+ if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
50
+ array[i] = byte;
51
+ }
52
+ return array;
53
+ }
54
+
55
+ // Global symbols in both browsers and Node.js since v11
56
+ // See https://github.com/microsoft/TypeScript/issues/31535
57
+ declare const TextEncoder: any;
58
+
59
+ /**
60
+ * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
61
+ */
62
+ export function utf8ToBytes(str: string): Uint8Array {
63
+ if (typeof str !== 'string') throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
64
+ return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
65
+ }
66
+
67
+ export type Input = Uint8Array | string;
68
+ /**
69
+ * Normalizes (non-hex) string or Uint8Array to Uint8Array.
70
+ * Warning: when Uint8Array is passed, it would NOT get copied.
71
+ * Keep in mind for future mutable operations.
72
+ */
73
+ export function toBytes(data: Input): Uint8Array {
74
+ if (typeof data === 'string') data = utf8ToBytes(data);
75
+ if (!u8a(data)) throw new Error(`expected Uint8Array, got ${typeof data}`);
76
+ return data;
77
+ }
78
+
79
+
80
+ // For runtime check if class implements interface
81
+ export abstract class Hash<T extends Hash<T>> {
82
+ abstract blockLen: number; // Bytes per block
83
+ abstract outputLen: number; // Bytes in output
84
+ abstract update(buf: Input): this;
85
+ // Writes digest into buf
86
+ abstract digestInto(buf: Uint8Array): void;
87
+ abstract digest(): Uint8Array;
88
+ /**
89
+ * Resets internal state. Makes Hash instance unusable.
90
+ * Reset is impossible for keyed hashes if key is consumed into state. If digest is not consumed
91
+ * by user, they will need to manually call `destroy()` when zeroing is necessary.
92
+ */
93
+ abstract destroy(): void;
94
+ /**
95
+ * Clones hash instance. Unsafe: doesn't check whether `to` is valid. Can be used as `clone()`
96
+ * when no options are passed.
97
+ * Reasons to use `_cloneInto` instead of clone: 1) performance 2) reuse instance => all internal
98
+ * buffers are overwritten => causes buffer overwrite which is used for digest in some cases.
99
+ * There are no guarantees for clean-up because it's impossible in JS.
100
+ */
101
+ abstract _cloneInto(to?: T): T;
102
+ // Safe version that clones internal state
103
+ clone(): T {
104
+ return this._cloneInto();
105
+ }
106
+ }
107
+
108
+ export type CHash = ReturnType<typeof wrapConstructor>;
109
+
110
+ export function wrapConstructor<T extends Hash<T>>(hashCons: () => Hash<T>) {
111
+ const hashC = (msg: Input): Uint8Array => hashCons().update(toBytes(msg)).digest();
112
+ const tmp = hashCons();
113
+ hashC.outputLen = tmp.outputLen;
114
+ hashC.blockLen = tmp.blockLen;
115
+ hashC.create = () => hashCons();
116
+ return hashC;
117
+ }
package/src/sm4/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { bytesToHex } from '@/sm3/utils'
1
2
  import { rotl } from '../sm2/sm3'
2
3
  import { arrayToHex, arrayToUtf8, hexToArray } from '../sm2/utils'
3
4
  import { utf8ToArray } from '../sm3'
@@ -64,11 +65,10 @@ function l2(b: number) {
64
65
  /**
65
66
  * 以一组 128 比特进行加密/解密操作
66
67
  */
68
+ const x = new Uint32Array(4)
69
+ const tmp = new Uint32Array(4)
67
70
  function sms4Crypt(input: Uint8Array, output: Uint8Array, roundKey: Uint32Array) {
68
- const x = new Uint32Array(4)
69
-
70
71
  // 字节数组转成字数组(此处 1 字 = 32 比特)
71
- const tmp = new Uint32Array(4)
72
72
  for (let i = 0; i < 4; i++) {
73
73
  tmp[0] = input[4 * i] & 0xff
74
74
  tmp[1] = input[4 * i + 1] & 0xff
@@ -105,10 +105,8 @@ function sms4Crypt(input: Uint8Array, output: Uint8Array, roundKey: Uint32Array)
105
105
  * 密钥扩展算法
106
106
  */
107
107
  function sms4KeyExt(key: Uint8Array, roundKey: Uint32Array, cryptFlag: 0 | 1) {
108
- const x = new Uint32Array(4)
109
108
 
110
109
  // 字节数组转成字数组(此处 1 字 = 32 比特)
111
- const tmp = new Uint32Array(4)
112
110
  for (let i = 0; i < 4; i++) {
113
111
  tmp[0] = key[0 + 4 * i] & 0xff
114
112
  tmp[1] = key[1 + 4 * i] & 0xff
@@ -154,6 +152,7 @@ export interface SM4Options {
154
152
  output?: 'string' | 'array'
155
153
  }
156
154
 
155
+ const blockOutput = new Uint8Array(16)
157
156
  export function sm4(inArray: Uint8Array | string, key: Uint8Array | string, cryptFlag: 0 | 1, options: SM4Options = {}) {
158
157
  let {
159
158
  padding = 'pkcs#7',
@@ -208,8 +207,7 @@ export function sm4(inArray: Uint8Array | string, key: Uint8Array | string, cryp
208
207
  let restLen = inArray.length
209
208
  let point = 0
210
209
  while (restLen >= BLOCK) {
211
- const input = inArray.slice(point, point + 16)
212
- const output = new Uint8Array(16)
210
+ const input = inArray.subarray(point, point + 16)
213
211
 
214
212
  if (mode === 'cbc') {
215
213
  for (let i = 0; i < BLOCK; i++) {
@@ -220,24 +218,24 @@ export function sm4(inArray: Uint8Array | string, key: Uint8Array | string, cryp
220
218
  }
221
219
  }
222
220
 
223
- sms4Crypt(input, output, roundKey)
221
+ sms4Crypt(input, blockOutput, roundKey)
224
222
 
225
223
 
226
224
  for (let i = 0; i < BLOCK; i++) {
227
225
  if (mode === 'cbc') {
228
226
  if (cryptFlag === DECRYPT) {
229
227
  // 解密过程在组解密后进行异或
230
- output[i] ^= lastVector[i]
228
+ blockOutput[i] ^= lastVector[i]
231
229
  }
232
230
  }
233
231
 
234
- outArray[point + i] = output[i]
232
+ outArray[point + i] = blockOutput[i]
235
233
  }
236
234
 
237
235
  if (mode === 'cbc') {
238
236
  if (cryptFlag !== DECRYPT) {
239
237
  // 使用上一次输出作为加密向量
240
- lastVector = output
238
+ lastVector = blockOutput
241
239
  } else {
242
240
  // 使用上一次输入作为解密向量
243
241
  lastVector = input
@@ -262,7 +260,7 @@ export function sm4(inArray: Uint8Array | string, key: Uint8Array | string, cryp
262
260
  if (output !== 'array') {
263
261
  if (cryptFlag !== DECRYPT) {
264
262
  // 加密,输出转 16 进制串
265
- return arrayToHex(Array.from(outArray))
263
+ return bytesToHex(outArray)
266
264
  } else {
267
265
  // 解密,输出转 utf8 串
268
266
  return arrayToUtf8(outArray)
package/.babelrc DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "presets": ["es2015"]
3
- }