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/src/sm3/utils.ts DELETED
@@ -1,117 +0,0 @@
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/_slow.ts DELETED
@@ -1,286 +0,0 @@
1
- // Slower version of SM4, for audit purpose.
2
- // This version is 3-4x slower than the unwrapped version.
3
-
4
- import { bytesToHex } from '@/sm3/utils'
5
- import { rotl } from '../sm2/sm3'
6
- import { arrayToHex, arrayToUtf8, hexToArray } from '../sm2/utils'
7
- import { utf8ToArray } from '../sm3'
8
-
9
- /* eslint-disable no-bitwise, no-mixed-operators, complexity */
10
- const DECRYPT = 0
11
- const ROUND = 32
12
- const BLOCK = 16
13
-
14
- const Sbox = Uint8Array.from([
15
- 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
16
- 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
17
- 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
18
- 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
19
- 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
20
- 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
21
- 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
22
- 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
23
- 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
24
- 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
25
- 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
26
- 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
27
- 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
28
- 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
29
- 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
30
- 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
31
- ])
32
-
33
- const CK = new Uint32Array([
34
- 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
35
- 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
36
- 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
37
- 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
38
- 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
39
- 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
40
- 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
41
- 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
42
- ])
43
-
44
- /**
45
- * 非线性变换
46
- */
47
- function byteSub(a: number) {
48
- return (Sbox[a >>> 24 & 0xFF] & 0xFF) << 24 |
49
- (Sbox[a >>> 16 & 0xFF] & 0xFF) << 16 |
50
- (Sbox[a >>> 8 & 0xFF] & 0xFF) << 8 |
51
- (Sbox[a & 0xFF] & 0xFF)
52
- }
53
-
54
- /**
55
- * 线性变换,加密/解密用
56
- */
57
- function l1(b: number) {
58
- return b ^ rotl(b, 2) ^ rotl(b, 10) ^ rotl(b, 18) ^ rotl(b, 24)
59
- }
60
-
61
- /**
62
- * 线性变换,生成轮密钥用
63
- */
64
- function l2(b: number) {
65
- return b ^ rotl(b, 13) ^ rotl(b, 23)
66
- }
67
-
68
- /**
69
- * 以一组 128 比特进行加密/解密操作
70
- */
71
- const x = new Uint32Array(4)
72
- const tmp = new Uint32Array(4)
73
- function sms4Crypt(input: Uint8Array, output: Uint8Array, roundKey: Uint32Array) {
74
- // 字节数组转成字数组(此处 1 字 = 32 比特)
75
- for (let i = 0; i < 4; i++) {
76
- tmp[0] = input[4 * i] & 0xff
77
- tmp[1] = input[4 * i + 1] & 0xff
78
- tmp[2] = input[4 * i + 2] & 0xff
79
- tmp[3] = input[4 * i + 3] & 0xff
80
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]
81
- }
82
-
83
- // x[i + 4] = x[i] ^ l1(byteSub(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ roundKey[i]))
84
- for (let r = 0, mid: number; r < 32; r += 4) {
85
- mid = x[1] ^ x[2] ^ x[3] ^ roundKey[r + 0]
86
- x[0] ^= l1(byteSub(mid)) // x[4]
87
-
88
- mid = x[2] ^ x[3] ^ x[0] ^ roundKey[r + 1]
89
- x[1] ^= l1(byteSub(mid)) // x[5]
90
-
91
- mid = x[3] ^ x[0] ^ x[1] ^ roundKey[r + 2]
92
- x[2] ^= l1(byteSub(mid)) // x[6]
93
-
94
- mid = x[0] ^ x[1] ^ x[2] ^ roundKey[r + 3]
95
- x[3] ^= l1(byteSub(mid)) // x[7]
96
- }
97
-
98
- // 反序变换
99
- for (let j = 0; j < 16; j += 4) {
100
- output[j] = x[3 - j / 4] >>> 24 & 0xff
101
- output[j + 1] = x[3 - j / 4] >>> 16 & 0xff
102
- output[j + 2] = x[3 - j / 4] >>> 8 & 0xff
103
- output[j + 3] = x[3 - j / 4] & 0xff
104
- }
105
- }
106
-
107
- /**
108
- * 密钥扩展算法
109
- */
110
- function sms4KeyExt(key: Uint8Array, roundKey: Uint32Array, cryptFlag: 0 | 1) {
111
-
112
- // 字节数组转成字数组(此处 1 字 = 32 比特)
113
- for (let i = 0; i < 4; i++) {
114
- tmp[0] = key[0 + 4 * i] & 0xff
115
- tmp[1] = key[1 + 4 * i] & 0xff
116
- tmp[2] = key[2 + 4 * i] & 0xff
117
- tmp[3] = key[3 + 4 * i] & 0xff
118
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]
119
- }
120
-
121
- // 与系统参数做异或
122
- x[0] ^= 0xa3b1bac6
123
- x[1] ^= 0x56aa3350
124
- x[2] ^= 0x677d9197
125
- x[3] ^= 0xb27022dc
126
-
127
- // roundKey[i] = x[i + 4] = x[i] ^ l2(byteSub(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ CK[i]))
128
- for (let r = 0, mid: number; r < 32; r += 4) {
129
- mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]
130
- roundKey[r + 0] = x[0] ^= l2(byteSub(mid)) // x[4]
131
-
132
- mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]
133
- roundKey[r + 1] = x[1] ^= l2(byteSub(mid)) // x[5]
134
-
135
- mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]
136
- roundKey[r + 2] = x[2] ^= l2(byteSub(mid)) // x[6]
137
-
138
- mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]
139
- roundKey[r + 3] = x[3] ^= l2(byteSub(mid)) // x[7]
140
- }
141
-
142
- // 解密时使用反序的轮密钥
143
- if (cryptFlag === DECRYPT) {
144
- for (let r = 0, mid: number; r < 16; r++) {
145
- mid = roundKey[r]
146
- roundKey[r] = roundKey[31 - r]
147
- roundKey[31 - r] = mid
148
- }
149
- }
150
- }
151
- export interface SM4Options {
152
- padding?: 'pkcs#7' | 'pkcs#5' | 'none' | null
153
- mode?: 'cbc' | 'ecb'
154
- iv?: Uint8Array | string
155
- output?: 'string' | 'array'
156
- }
157
-
158
- const blockOutput = new Uint8Array(16)
159
- export function sm4(inArray: Uint8Array | string, key: Uint8Array | string, cryptFlag: 0 | 1, options: SM4Options = {}) {
160
- let {
161
- padding = 'pkcs#7',
162
- mode,
163
- iv = new Uint8Array(16),
164
- output
165
- } = options
166
- if (mode === 'cbc') {
167
- // CBC 模式,默认走 ECB 模式
168
- if (typeof iv === 'string') iv = hexToArray(iv)
169
- if (iv.length !== (128 / 8)) {
170
- // iv 不是 128 比特
171
- throw new Error('iv is invalid')
172
- }
173
- }
174
-
175
- // 检查 key
176
- if (typeof key === 'string') key = hexToArray(key)
177
- if (key.length !== (128 / 8)) {
178
- // key 不是 128 比特
179
- throw new Error('key is invalid')
180
- }
181
-
182
- // 检查输入
183
- if (typeof inArray === 'string') {
184
- if (cryptFlag !== DECRYPT) {
185
- // 加密,输入为 utf8 串
186
- inArray = utf8ToArray(inArray)
187
- } else {
188
- // 解密,输入为 16 进制串
189
- inArray = hexToArray(inArray)
190
- }
191
- } else {
192
- inArray = Uint8Array.from(inArray)
193
- }
194
-
195
- // 新增填充,sm4 是 16 个字节一个分组,所以统一走到 pkcs#7
196
- if ((padding === 'pkcs#5' || padding === 'pkcs#7') && cryptFlag !== DECRYPT) {
197
- const paddingCount = BLOCK - inArray.length % BLOCK
198
- const newArray = new Uint8Array(inArray.length + paddingCount)
199
- newArray.set(inArray, 0)
200
- for (let i = 0; i < paddingCount; i++) newArray[inArray.length + i] = paddingCount
201
- inArray = newArray
202
- }
203
-
204
- // 生成轮密钥
205
- const roundKey = new Uint32Array(ROUND)
206
- sms4KeyExt(key, roundKey, cryptFlag)
207
-
208
- let outArray = new Uint8Array(inArray.length)
209
- let lastVector = iv as Uint8Array
210
- let restLen = inArray.length
211
- let point = 0
212
- while (restLen >= BLOCK) {
213
- const input = inArray.subarray(point, point + 16)
214
-
215
- if (mode === 'cbc') {
216
- for (let i = 0; i < BLOCK; i++) {
217
- if (cryptFlag !== DECRYPT) {
218
- // 加密过程在组加密前进行异或
219
- input[i] ^= lastVector[i]
220
- }
221
- }
222
- }
223
-
224
- sms4Crypt(input, blockOutput, roundKey)
225
-
226
-
227
- for (let i = 0; i < BLOCK; i++) {
228
- if (mode === 'cbc') {
229
- if (cryptFlag === DECRYPT) {
230
- // 解密过程在组解密后进行异或
231
- blockOutput[i] ^= lastVector[i]
232
- }
233
- }
234
-
235
- outArray[point + i] = blockOutput[i]
236
- }
237
-
238
- if (mode === 'cbc') {
239
- if (cryptFlag !== DECRYPT) {
240
- // 使用上一次输出作为加密向量
241
- lastVector = blockOutput
242
- } else {
243
- // 使用上一次输入作为解密向量
244
- lastVector = input
245
- }
246
- }
247
-
248
- restLen -= BLOCK
249
- point += BLOCK
250
- }
251
-
252
- // 去除填充,sm4 是 16 个字节一个分组,所以统一走到 pkcs#7
253
- if ((padding === 'pkcs#5' || padding === 'pkcs#7') && cryptFlag === DECRYPT) {
254
- const len = outArray.length
255
- const paddingCount = outArray[len - 1]
256
- for (let i = 1; i <= paddingCount; i++) {
257
- if (outArray[len - i] !== paddingCount) throw new Error('padding is invalid')
258
- }
259
- outArray = outArray.slice(0, len - paddingCount)
260
- }
261
-
262
- // 调整输出
263
- if (output !== 'array') {
264
- if (cryptFlag !== DECRYPT) {
265
- // 加密,输出转 16 进制串
266
- return bytesToHex(outArray)
267
- } else {
268
- // 解密,输出转 utf8 串
269
- return arrayToUtf8(outArray)
270
- }
271
- } else {
272
- return outArray
273
- }
274
- }
275
-
276
- export function encrypt(inArray: Uint8Array | string, key: Uint8Array | string, options?: { output: 'array' } | SM4Options): Uint8Array
277
- export function encrypt(inArray: Uint8Array | string, key: Uint8Array | string, options?: { output: 'string' } | SM4Options): string
278
- export function encrypt(inArray: Uint8Array | string, key: Uint8Array | string, options: SM4Options = {}) {
279
- return sm4(inArray, key, 1, options)
280
- }
281
-
282
- export function decrypt(inArray: Uint8Array | string, key: Uint8Array | string, options?: { output: 'array' } | SM4Options): Uint8Array
283
- export function decrypt(inArray: Uint8Array | string, key: Uint8Array | string, options?: { output: 'string' } | SM4Options): string
284
- export function decrypt(inArray: Uint8Array | string, key: Uint8Array | string, options: SM4Options = {}) {
285
- return sm4(inArray, key, 0, options)
286
- }