sm-crypto-v2 1.5.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,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.7.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.6.0...v1.7.0) (2023-07-17)
6
+
7
+
8
+ ### Features
9
+
10
+ * **sm2:** support precompute sm2 point ([ae347bf](https://github.com/Cubelrti/sm-crypto-v2/commit/ae347bfff6c306318276a31f5958290ac7f07b9c))
11
+
12
+ ## [1.6.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.5.1...v1.6.0) (2023-07-11)
13
+
14
+
15
+ ### Features
16
+
17
+ * **sm4:** optimize sm4 ([031159c](https://github.com/Cubelrti/sm-crypto-v2/commit/031159c7e2889f01b499b9286ce1d93a5e55b151))
18
+
5
19
  ### [1.5.1](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.5.0...v1.5.1) (2023-06-28)
6
20
 
7
21
 
package/README.md CHANGED
@@ -127,6 +127,21 @@ import { sm2 } from 'sm-crypto-v2'
127
127
  let point = sm2.getPoint() // 获取一个椭圆曲线点,可在sm2签名时传入
128
128
  ```
129
129
 
130
+ ### 预计算公钥
131
+
132
+ ```js
133
+ import { sm2 } from 'sm-crypto-v2'
134
+ let keypair = sm2.generateKeyPairHex()
135
+
136
+ const precomputedPublicKey = sm2.precomputePublicKey(keypair.publicKey)
137
+ // 加密和验签可以传入预计算后的点
138
+ let encryptData = sm2.doEncrypt(msgString, precomputedPublicKey, cipherMode) // 加密结果
139
+ let verifyResult4 = sm2.doVerifySignature(msg, sigValueHex4, precomputedPublicKey, {
140
+ hash: true,
141
+ }) // 验签结果
142
+
143
+ ```
144
+
130
145
  ## sm3
131
146
 
132
147
  ```js
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ProjPointType } from '@noble/curves/abstract/weierstrass';
2
+
1
3
  interface KeyPair {
2
4
  privateKey: string;
3
5
  publicKey: string;
@@ -47,7 +49,7 @@ declare const EmptyArray: Uint8Array;
47
49
  /**
48
50
  * 加密
49
51
  */
50
- declare function doEncrypt(msg: string | Uint8Array, publicKey: string, cipherMode?: number): string;
52
+ declare function doEncrypt(msg: string | Uint8Array, publicKey: string | ProjPointType<bigint>, cipherMode?: number): string;
51
53
  /**
52
54
  * 解密
53
55
  */
@@ -74,7 +76,7 @@ declare function doSignature(msg: Uint8Array | string, privateKey: string, optio
74
76
  /**
75
77
  * 验签
76
78
  */
77
- declare function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string, options?: {
79
+ declare function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string | ProjPointType<bigint>, options?: {
78
80
  der?: boolean;
79
81
  hash?: boolean;
80
82
  userId?: string;
@@ -84,6 +86,14 @@ declare function getZ(publicKey: string, userId?: string): Uint8Array;
84
86
  * sm3杂凑算法
85
87
  */
86
88
  declare function getHash(hashHex: string | Uint8Array, publicKey: string, userId?: string): string;
89
+ /**
90
+ * 预计算公钥点,可用于提升加密性能
91
+ * @export
92
+ * @param {string} publicKey 公钥
93
+ * @param windowSize 计算窗口大小,默认为 8
94
+ * @returns {ProjPointType<bigint>} 预计算的点
95
+ */
96
+ declare function precomputePublicKey(publicKey: string, windowSize?: number): ProjPointType<bigint>;
87
97
  /**
88
98
  * 计算公钥
89
99
  */
@@ -106,6 +116,7 @@ declare const index$1_doSignature: typeof doSignature;
106
116
  declare const index$1_doVerifySignature: typeof doVerifySignature;
107
117
  declare const index$1_getZ: typeof getZ;
108
118
  declare const index$1_getHash: typeof getHash;
119
+ declare const index$1_precomputePublicKey: typeof precomputePublicKey;
109
120
  declare const index$1_getPublicKeyFromPrivateKey: typeof getPublicKeyFromPrivateKey;
110
121
  declare const index$1_getPoint: typeof getPoint;
111
122
  declare const index$1_initRNGPool: typeof initRNGPool;
@@ -130,6 +141,7 @@ declare namespace index$1 {
130
141
  index$1_doVerifySignature as doVerifySignature,
131
142
  index$1_getZ as getZ,
132
143
  index$1_getHash as getHash,
144
+ index$1_precomputePublicKey as precomputePublicKey,
133
145
  index$1_getPublicKeyFromPrivateKey as getPublicKeyFromPrivateKey,
134
146
  index$1_getPoint as getPoint,
135
147
  index$1_initRNGPool as initRNGPool,
package/dist/index.js CHANGED
@@ -53,6 +53,7 @@ __export(sm2_exports, {
53
53
  hexToArray: () => hexToArray,
54
54
  initRNGPool: () => initRNGPool,
55
55
  leftPad: () => leftPad,
56
+ precomputePublicKey: () => precomputePublicKey,
56
57
  utf8ToHex: () => utf8ToHex,
57
58
  verifyPublicKey: () => verifyPublicKey
58
59
  });
@@ -198,7 +199,7 @@ async function initRNGPool() {
198
199
  }
199
200
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
200
201
  return;
201
- if ("wx" in globalThis) {
202
+ if ("wx" in globalThis && "getRandomValues" in globalThis.wx) {
202
203
  prngPool = await new Promise((r) => {
203
204
  wx.getRandomValues({
204
205
  length: DEFAULT_PRNG_POOL_SIZE,
@@ -209,11 +210,15 @@ async function initRNGPool() {
209
210
  });
210
211
  } else {
211
212
  try {
212
- const crypto = await import(
213
- /* webpackIgnore: true */
214
- "crypto"
215
- );
216
- _syncCrypto = crypto.webcrypto;
213
+ if (globalThis.crypto) {
214
+ _syncCrypto = globalThis.crypto;
215
+ } else {
216
+ const crypto = await import(
217
+ /* webpackIgnore: true */
218
+ "crypto"
219
+ );
220
+ _syncCrypto = crypto.webcrypto;
221
+ }
217
222
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
218
223
  _syncCrypto.getRandomValues(array);
219
224
  prngPool = array;
@@ -636,9 +641,12 @@ function verifyPublicKey(publicKey) {
636
641
  const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
637
642
  if (!point)
638
643
  return false;
639
- const x2 = point.x;
640
- const y = point.y;
641
- return sm2Fp.sqr(y) === sm2Fp.add(sm2Fp.addN(sm2Fp.mulN(x2, sm2Fp.sqrN(x2)), sm2Fp.mulN(x2, sm2Curve.CURVE.a)), sm2Curve.CURVE.b);
644
+ try {
645
+ point.assertValidity();
646
+ return true;
647
+ } catch (error) {
648
+ return false;
649
+ }
642
650
  }
643
651
  function comparePublicKeyHex(publicKey1, publicKey2) {
644
652
  const point1 = sm2Curve.ProjectivePoint.fromHex(publicKey1);
@@ -708,7 +716,7 @@ var C1C2C3 = 0;
708
716
  var EmptyArray = new Uint8Array();
709
717
  function doEncrypt(msg, publicKey, cipherMode = 1) {
710
718
  const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
711
- const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
719
+ const publicKeyPoint = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
712
720
  const keypair = generateKeyPairHex();
713
721
  const k = utils4.hexToNumber(keypair.privateKey);
714
722
  let c1 = keypair.publicKey;
@@ -808,8 +816,9 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
808
816
  der,
809
817
  userId
810
818
  } = options;
819
+ const publicKeyHex = typeof publicKey === "string" ? publicKey : publicKey.toHex(false);
811
820
  if (hash) {
812
- hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg, publicKey, userId);
821
+ hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg, publicKeyHex, userId);
813
822
  } else {
814
823
  hashHex = typeof msg === "string" ? utf8ToHex(msg) : arrayToHex(Array.from(msg));
815
824
  }
@@ -823,7 +832,7 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
823
832
  r = utils4.hexToNumber(signHex.substring(0, 64));
824
833
  s = utils4.hexToNumber(signHex.substring(64));
825
834
  }
826
- const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
835
+ const PA = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
827
836
  const e = utils4.hexToNumber(hashHex);
828
837
  const t = field.add(r, s);
829
838
  if (t === ZERO)
@@ -857,6 +866,10 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
857
866
  const z = getZ(publicKey, userId);
858
867
  return bytesToHex(sm3(utils4.concatBytes(z, typeof hashHex === "string" ? hexToArray(hashHex) : hashHex)));
859
868
  }
869
+ function precomputePublicKey(publicKey, windowSize) {
870
+ const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
871
+ return sm2Curve.utils.precompute(windowSize, point);
872
+ }
860
873
  function getPublicKeyFromPrivateKey(privateKey) {
861
874
  const pubKey = sm2Curve.getPublicKey(privateKey, false);
862
875
  const pubPad = leftPad(utils4.bytesToHex(pubKey), 64);
@@ -1220,66 +1233,92 @@ var CK = new Uint32Array([
1220
1233
  function byteSub(a) {
1221
1234
  return (Sbox[a >>> 24 & 255] & 255) << 24 | (Sbox[a >>> 16 & 255] & 255) << 16 | (Sbox[a >>> 8 & 255] & 255) << 8 | Sbox[a & 255] & 255;
1222
1235
  }
1223
- function l1(b) {
1224
- return b ^ rotl(b, 2) ^ rotl(b, 10) ^ rotl(b, 18) ^ rotl(b, 24);
1225
- }
1226
- function l2(b) {
1227
- return b ^ rotl(b, 13) ^ rotl(b, 23);
1228
- }
1229
1236
  var x = new Uint32Array(4);
1230
1237
  var tmp = new Uint32Array(4);
1231
1238
  function sms4Crypt(input, output, roundKey) {
1232
- for (let i = 0; i < 4; i++) {
1233
- tmp[0] = input[4 * i] & 255;
1234
- tmp[1] = input[4 * i + 1] & 255;
1235
- tmp[2] = input[4 * i + 2] & 255;
1236
- tmp[3] = input[4 * i + 3] & 255;
1237
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
1238
- }
1239
- for (let r = 0, mid; r < 32; r += 4) {
1240
- mid = x[1] ^ x[2] ^ x[3] ^ roundKey[r + 0];
1241
- x[0] ^= l1(byteSub(mid));
1242
- mid = x[2] ^ x[3] ^ x[0] ^ roundKey[r + 1];
1243
- x[1] ^= l1(byteSub(mid));
1244
- mid = x[3] ^ x[0] ^ x[1] ^ roundKey[r + 2];
1245
- x[2] ^= l1(byteSub(mid));
1246
- mid = x[0] ^ x[1] ^ x[2] ^ roundKey[r + 3];
1247
- x[3] ^= l1(byteSub(mid));
1248
- }
1249
- for (let j = 0; j < 16; j += 4) {
1250
- output[j] = x[3 - j / 4] >>> 24 & 255;
1251
- output[j + 1] = x[3 - j / 4] >>> 16 & 255;
1252
- output[j + 2] = x[3 - j / 4] >>> 8 & 255;
1253
- output[j + 3] = x[3 - j / 4] & 255;
1239
+ let x0 = 0, x1 = 0, x2 = 0, x3 = 0, tmp0 = 0, tmp1 = 0, tmp2 = 0, tmp3 = 0;
1240
+ tmp0 = input[0] & 255;
1241
+ tmp1 = input[1] & 255;
1242
+ tmp2 = input[2] & 255;
1243
+ tmp3 = input[3] & 255;
1244
+ x0 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1245
+ tmp0 = input[4] & 255;
1246
+ tmp1 = input[5] & 255;
1247
+ tmp2 = input[6] & 255;
1248
+ tmp3 = input[7] & 255;
1249
+ x1 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1250
+ tmp0 = input[8] & 255;
1251
+ tmp1 = input[9] & 255;
1252
+ tmp2 = input[10] & 255;
1253
+ tmp3 = input[11] & 255;
1254
+ x2 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1255
+ tmp0 = input[12] & 255;
1256
+ tmp1 = input[13] & 255;
1257
+ tmp2 = input[14] & 255;
1258
+ tmp3 = input[15] & 255;
1259
+ x3 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1260
+ for (let r = 0; r < 32; r += 4) {
1261
+ tmp0 = x1 ^ x2 ^ x3 ^ roundKey[r];
1262
+ tmp0 = byteSub(tmp0);
1263
+ x0 ^= tmp0 ^ (tmp0 << 2 | tmp0 >>> 30) ^ (tmp0 << 10 | tmp0 >>> 22) ^ (tmp0 << 18 | tmp0 >>> 14) ^ (tmp0 << 24 | tmp0 >>> 8);
1264
+ tmp1 = x2 ^ x3 ^ x0 ^ roundKey[r + 1];
1265
+ tmp1 = byteSub(tmp1);
1266
+ x1 ^= tmp1 ^ (tmp1 << 2 | tmp1 >>> 30) ^ (tmp1 << 10 | tmp1 >>> 22) ^ (tmp1 << 18 | tmp1 >>> 14) ^ (tmp1 << 24 | tmp1 >>> 8);
1267
+ tmp2 = x3 ^ x0 ^ x1 ^ roundKey[r + 2];
1268
+ tmp2 = byteSub(tmp2);
1269
+ x2 ^= tmp2 ^ (tmp2 << 2 | tmp2 >>> 30) ^ (tmp2 << 10 | tmp2 >>> 22) ^ (tmp2 << 18 | tmp2 >>> 14) ^ (tmp2 << 24 | tmp2 >>> 8);
1270
+ tmp3 = x0 ^ x1 ^ x2 ^ roundKey[r + 3];
1271
+ tmp3 = byteSub(tmp3);
1272
+ x3 ^= tmp3 ^ (tmp3 << 2 | tmp3 >>> 30) ^ (tmp3 << 10 | tmp3 >>> 22) ^ (tmp3 << 18 | tmp3 >>> 14) ^ (tmp3 << 24 | tmp3 >>> 8);
1254
1273
  }
1274
+ output[0] = x3 >>> 24 & 255;
1275
+ output[1] = x3 >>> 16 & 255;
1276
+ output[2] = x3 >>> 8 & 255;
1277
+ output[3] = x3 & 255;
1278
+ output[4] = x2 >>> 24 & 255;
1279
+ output[5] = x2 >>> 16 & 255;
1280
+ output[6] = x2 >>> 8 & 255;
1281
+ output[7] = x2 & 255;
1282
+ output[8] = x1 >>> 24 & 255;
1283
+ output[9] = x1 >>> 16 & 255;
1284
+ output[10] = x1 >>> 8 & 255;
1285
+ output[11] = x1 & 255;
1286
+ output[12] = x0 >>> 24 & 255;
1287
+ output[13] = x0 >>> 16 & 255;
1288
+ output[14] = x0 >>> 8 & 255;
1289
+ output[15] = x0 & 255;
1255
1290
  }
1256
1291
  function sms4KeyExt(key, roundKey, cryptFlag) {
1257
- for (let i = 0; i < 4; i++) {
1258
- tmp[0] = key[0 + 4 * i] & 255;
1259
- tmp[1] = key[1 + 4 * i] & 255;
1260
- tmp[2] = key[2 + 4 * i] & 255;
1261
- tmp[3] = key[3 + 4 * i] & 255;
1262
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
1263
- }
1264
- x[0] ^= 2746333894;
1265
- x[1] ^= 1453994832;
1266
- x[2] ^= 1736282519;
1267
- x[3] ^= 2993693404;
1268
- for (let r = 0, mid; r < 32; r += 4) {
1269
- mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0];
1270
- roundKey[r + 0] = x[0] ^= l2(byteSub(mid));
1271
- mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1];
1272
- roundKey[r + 1] = x[1] ^= l2(byteSub(mid));
1273
- mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2];
1274
- roundKey[r + 2] = x[2] ^= l2(byteSub(mid));
1275
- mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3];
1276
- roundKey[r + 3] = x[3] ^= l2(byteSub(mid));
1292
+ let x0 = 0, x1 = 0, x2 = 0, x3 = 0, mid = 0;
1293
+ x0 = (key[0] & 255) << 24 | (key[1] & 255) << 16 | (key[2] & 255) << 8 | key[3] & 255;
1294
+ x1 = (key[4] & 255) << 24 | (key[5] & 255) << 16 | (key[6] & 255) << 8 | key[7] & 255;
1295
+ x2 = (key[8] & 255) << 24 | (key[9] & 255) << 16 | (key[10] & 255) << 8 | key[11] & 255;
1296
+ x3 = (key[12] & 255) << 24 | (key[13] & 255) << 16 | (key[14] & 255) << 8 | key[15] & 255;
1297
+ x0 ^= 2746333894;
1298
+ x1 ^= 1453994832;
1299
+ x2 ^= 1736282519;
1300
+ x3 ^= 2993693404;
1301
+ for (let r = 0; r < 32; r += 4) {
1302
+ mid = x1 ^ x2 ^ x3 ^ CK[r + 0];
1303
+ mid = byteSub(mid);
1304
+ x0 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1305
+ roundKey[r + 0] = x0;
1306
+ mid = x2 ^ x3 ^ x0 ^ CK[r + 1];
1307
+ mid = byteSub(mid);
1308
+ x1 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1309
+ roundKey[r + 1] = x1;
1310
+ mid = x3 ^ x0 ^ x1 ^ CK[r + 2];
1311
+ mid = byteSub(mid);
1312
+ x2 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1313
+ roundKey[r + 2] = x2;
1314
+ mid = x0 ^ x1 ^ x2 ^ CK[r + 3];
1315
+ mid = byteSub(mid);
1316
+ x3 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1317
+ roundKey[r + 3] = x3;
1277
1318
  }
1278
1319
  if (cryptFlag === DECRYPT) {
1279
- for (let r = 0, mid; r < 16; r++) {
1280
- mid = roundKey[r];
1281
- roundKey[r] = roundKey[31 - r];
1282
- roundKey[31 - r] = mid;
1320
+ for (let r = 0; r < 16; r++) {
1321
+ [roundKey[r], roundKey[31 - r]] = [roundKey[31 - r], roundKey[r]];
1283
1322
  }
1284
1323
  }
1285
1324
  }
package/dist/index.mjs CHANGED
@@ -25,6 +25,7 @@ __export(sm2_exports, {
25
25
  hexToArray: () => hexToArray,
26
26
  initRNGPool: () => initRNGPool,
27
27
  leftPad: () => leftPad,
28
+ precomputePublicKey: () => precomputePublicKey,
28
29
  utf8ToHex: () => utf8ToHex,
29
30
  verifyPublicKey: () => verifyPublicKey
30
31
  });
@@ -170,7 +171,7 @@ async function initRNGPool() {
170
171
  }
171
172
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
172
173
  return;
173
- if ("wx" in globalThis) {
174
+ if ("wx" in globalThis && "getRandomValues" in globalThis.wx) {
174
175
  prngPool = await new Promise((r) => {
175
176
  wx.getRandomValues({
176
177
  length: DEFAULT_PRNG_POOL_SIZE,
@@ -181,11 +182,15 @@ async function initRNGPool() {
181
182
  });
182
183
  } else {
183
184
  try {
184
- const crypto = await import(
185
- /* webpackIgnore: true */
186
- "crypto"
187
- );
188
- _syncCrypto = crypto.webcrypto;
185
+ if (globalThis.crypto) {
186
+ _syncCrypto = globalThis.crypto;
187
+ } else {
188
+ const crypto = await import(
189
+ /* webpackIgnore: true */
190
+ "crypto"
191
+ );
192
+ _syncCrypto = crypto.webcrypto;
193
+ }
189
194
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
190
195
  _syncCrypto.getRandomValues(array);
191
196
  prngPool = array;
@@ -608,9 +613,12 @@ function verifyPublicKey(publicKey) {
608
613
  const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
609
614
  if (!point)
610
615
  return false;
611
- const x2 = point.x;
612
- const y = point.y;
613
- return sm2Fp.sqr(y) === sm2Fp.add(sm2Fp.addN(sm2Fp.mulN(x2, sm2Fp.sqrN(x2)), sm2Fp.mulN(x2, sm2Curve.CURVE.a)), sm2Curve.CURVE.b);
616
+ try {
617
+ point.assertValidity();
618
+ return true;
619
+ } catch (error) {
620
+ return false;
621
+ }
614
622
  }
615
623
  function comparePublicKeyHex(publicKey1, publicKey2) {
616
624
  const point1 = sm2Curve.ProjectivePoint.fromHex(publicKey1);
@@ -680,7 +688,7 @@ var C1C2C3 = 0;
680
688
  var EmptyArray = new Uint8Array();
681
689
  function doEncrypt(msg, publicKey, cipherMode = 1) {
682
690
  const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
683
- const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
691
+ const publicKeyPoint = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
684
692
  const keypair = generateKeyPairHex();
685
693
  const k = utils4.hexToNumber(keypair.privateKey);
686
694
  let c1 = keypair.publicKey;
@@ -780,8 +788,9 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
780
788
  der,
781
789
  userId
782
790
  } = options;
791
+ const publicKeyHex = typeof publicKey === "string" ? publicKey : publicKey.toHex(false);
783
792
  if (hash) {
784
- hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg, publicKey, userId);
793
+ hashHex = getHash(typeof msg === "string" ? utf8ToHex(msg) : msg, publicKeyHex, userId);
785
794
  } else {
786
795
  hashHex = typeof msg === "string" ? utf8ToHex(msg) : arrayToHex(Array.from(msg));
787
796
  }
@@ -795,7 +804,7 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
795
804
  r = utils4.hexToNumber(signHex.substring(0, 64));
796
805
  s = utils4.hexToNumber(signHex.substring(64));
797
806
  }
798
- const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
807
+ const PA = typeof publicKey === "string" ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey;
799
808
  const e = utils4.hexToNumber(hashHex);
800
809
  const t = field.add(r, s);
801
810
  if (t === ZERO)
@@ -829,6 +838,10 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
829
838
  const z = getZ(publicKey, userId);
830
839
  return bytesToHex(sm3(utils4.concatBytes(z, typeof hashHex === "string" ? hexToArray(hashHex) : hashHex)));
831
840
  }
841
+ function precomputePublicKey(publicKey, windowSize) {
842
+ const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
843
+ return sm2Curve.utils.precompute(windowSize, point);
844
+ }
832
845
  function getPublicKeyFromPrivateKey(privateKey) {
833
846
  const pubKey = sm2Curve.getPublicKey(privateKey, false);
834
847
  const pubPad = leftPad(utils4.bytesToHex(pubKey), 64);
@@ -1192,66 +1205,92 @@ var CK = new Uint32Array([
1192
1205
  function byteSub(a) {
1193
1206
  return (Sbox[a >>> 24 & 255] & 255) << 24 | (Sbox[a >>> 16 & 255] & 255) << 16 | (Sbox[a >>> 8 & 255] & 255) << 8 | Sbox[a & 255] & 255;
1194
1207
  }
1195
- function l1(b) {
1196
- return b ^ rotl(b, 2) ^ rotl(b, 10) ^ rotl(b, 18) ^ rotl(b, 24);
1197
- }
1198
- function l2(b) {
1199
- return b ^ rotl(b, 13) ^ rotl(b, 23);
1200
- }
1201
1208
  var x = new Uint32Array(4);
1202
1209
  var tmp = new Uint32Array(4);
1203
1210
  function sms4Crypt(input, output, roundKey) {
1204
- for (let i = 0; i < 4; i++) {
1205
- tmp[0] = input[4 * i] & 255;
1206
- tmp[1] = input[4 * i + 1] & 255;
1207
- tmp[2] = input[4 * i + 2] & 255;
1208
- tmp[3] = input[4 * i + 3] & 255;
1209
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
1210
- }
1211
- for (let r = 0, mid; r < 32; r += 4) {
1212
- mid = x[1] ^ x[2] ^ x[3] ^ roundKey[r + 0];
1213
- x[0] ^= l1(byteSub(mid));
1214
- mid = x[2] ^ x[3] ^ x[0] ^ roundKey[r + 1];
1215
- x[1] ^= l1(byteSub(mid));
1216
- mid = x[3] ^ x[0] ^ x[1] ^ roundKey[r + 2];
1217
- x[2] ^= l1(byteSub(mid));
1218
- mid = x[0] ^ x[1] ^ x[2] ^ roundKey[r + 3];
1219
- x[3] ^= l1(byteSub(mid));
1220
- }
1221
- for (let j = 0; j < 16; j += 4) {
1222
- output[j] = x[3 - j / 4] >>> 24 & 255;
1223
- output[j + 1] = x[3 - j / 4] >>> 16 & 255;
1224
- output[j + 2] = x[3 - j / 4] >>> 8 & 255;
1225
- output[j + 3] = x[3 - j / 4] & 255;
1211
+ let x0 = 0, x1 = 0, x2 = 0, x3 = 0, tmp0 = 0, tmp1 = 0, tmp2 = 0, tmp3 = 0;
1212
+ tmp0 = input[0] & 255;
1213
+ tmp1 = input[1] & 255;
1214
+ tmp2 = input[2] & 255;
1215
+ tmp3 = input[3] & 255;
1216
+ x0 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1217
+ tmp0 = input[4] & 255;
1218
+ tmp1 = input[5] & 255;
1219
+ tmp2 = input[6] & 255;
1220
+ tmp3 = input[7] & 255;
1221
+ x1 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1222
+ tmp0 = input[8] & 255;
1223
+ tmp1 = input[9] & 255;
1224
+ tmp2 = input[10] & 255;
1225
+ tmp3 = input[11] & 255;
1226
+ x2 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1227
+ tmp0 = input[12] & 255;
1228
+ tmp1 = input[13] & 255;
1229
+ tmp2 = input[14] & 255;
1230
+ tmp3 = input[15] & 255;
1231
+ x3 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
1232
+ for (let r = 0; r < 32; r += 4) {
1233
+ tmp0 = x1 ^ x2 ^ x3 ^ roundKey[r];
1234
+ tmp0 = byteSub(tmp0);
1235
+ x0 ^= tmp0 ^ (tmp0 << 2 | tmp0 >>> 30) ^ (tmp0 << 10 | tmp0 >>> 22) ^ (tmp0 << 18 | tmp0 >>> 14) ^ (tmp0 << 24 | tmp0 >>> 8);
1236
+ tmp1 = x2 ^ x3 ^ x0 ^ roundKey[r + 1];
1237
+ tmp1 = byteSub(tmp1);
1238
+ x1 ^= tmp1 ^ (tmp1 << 2 | tmp1 >>> 30) ^ (tmp1 << 10 | tmp1 >>> 22) ^ (tmp1 << 18 | tmp1 >>> 14) ^ (tmp1 << 24 | tmp1 >>> 8);
1239
+ tmp2 = x3 ^ x0 ^ x1 ^ roundKey[r + 2];
1240
+ tmp2 = byteSub(tmp2);
1241
+ x2 ^= tmp2 ^ (tmp2 << 2 | tmp2 >>> 30) ^ (tmp2 << 10 | tmp2 >>> 22) ^ (tmp2 << 18 | tmp2 >>> 14) ^ (tmp2 << 24 | tmp2 >>> 8);
1242
+ tmp3 = x0 ^ x1 ^ x2 ^ roundKey[r + 3];
1243
+ tmp3 = byteSub(tmp3);
1244
+ x3 ^= tmp3 ^ (tmp3 << 2 | tmp3 >>> 30) ^ (tmp3 << 10 | tmp3 >>> 22) ^ (tmp3 << 18 | tmp3 >>> 14) ^ (tmp3 << 24 | tmp3 >>> 8);
1226
1245
  }
1246
+ output[0] = x3 >>> 24 & 255;
1247
+ output[1] = x3 >>> 16 & 255;
1248
+ output[2] = x3 >>> 8 & 255;
1249
+ output[3] = x3 & 255;
1250
+ output[4] = x2 >>> 24 & 255;
1251
+ output[5] = x2 >>> 16 & 255;
1252
+ output[6] = x2 >>> 8 & 255;
1253
+ output[7] = x2 & 255;
1254
+ output[8] = x1 >>> 24 & 255;
1255
+ output[9] = x1 >>> 16 & 255;
1256
+ output[10] = x1 >>> 8 & 255;
1257
+ output[11] = x1 & 255;
1258
+ output[12] = x0 >>> 24 & 255;
1259
+ output[13] = x0 >>> 16 & 255;
1260
+ output[14] = x0 >>> 8 & 255;
1261
+ output[15] = x0 & 255;
1227
1262
  }
1228
1263
  function sms4KeyExt(key, roundKey, cryptFlag) {
1229
- for (let i = 0; i < 4; i++) {
1230
- tmp[0] = key[0 + 4 * i] & 255;
1231
- tmp[1] = key[1 + 4 * i] & 255;
1232
- tmp[2] = key[2 + 4 * i] & 255;
1233
- tmp[3] = key[3 + 4 * i] & 255;
1234
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
1235
- }
1236
- x[0] ^= 2746333894;
1237
- x[1] ^= 1453994832;
1238
- x[2] ^= 1736282519;
1239
- x[3] ^= 2993693404;
1240
- for (let r = 0, mid; r < 32; r += 4) {
1241
- mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0];
1242
- roundKey[r + 0] = x[0] ^= l2(byteSub(mid));
1243
- mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1];
1244
- roundKey[r + 1] = x[1] ^= l2(byteSub(mid));
1245
- mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2];
1246
- roundKey[r + 2] = x[2] ^= l2(byteSub(mid));
1247
- mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3];
1248
- roundKey[r + 3] = x[3] ^= l2(byteSub(mid));
1264
+ let x0 = 0, x1 = 0, x2 = 0, x3 = 0, mid = 0;
1265
+ x0 = (key[0] & 255) << 24 | (key[1] & 255) << 16 | (key[2] & 255) << 8 | key[3] & 255;
1266
+ x1 = (key[4] & 255) << 24 | (key[5] & 255) << 16 | (key[6] & 255) << 8 | key[7] & 255;
1267
+ x2 = (key[8] & 255) << 24 | (key[9] & 255) << 16 | (key[10] & 255) << 8 | key[11] & 255;
1268
+ x3 = (key[12] & 255) << 24 | (key[13] & 255) << 16 | (key[14] & 255) << 8 | key[15] & 255;
1269
+ x0 ^= 2746333894;
1270
+ x1 ^= 1453994832;
1271
+ x2 ^= 1736282519;
1272
+ x3 ^= 2993693404;
1273
+ for (let r = 0; r < 32; r += 4) {
1274
+ mid = x1 ^ x2 ^ x3 ^ CK[r + 0];
1275
+ mid = byteSub(mid);
1276
+ x0 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1277
+ roundKey[r + 0] = x0;
1278
+ mid = x2 ^ x3 ^ x0 ^ CK[r + 1];
1279
+ mid = byteSub(mid);
1280
+ x1 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1281
+ roundKey[r + 1] = x1;
1282
+ mid = x3 ^ x0 ^ x1 ^ CK[r + 2];
1283
+ mid = byteSub(mid);
1284
+ x2 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1285
+ roundKey[r + 2] = x2;
1286
+ mid = x0 ^ x1 ^ x2 ^ CK[r + 3];
1287
+ mid = byteSub(mid);
1288
+ x3 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
1289
+ roundKey[r + 3] = x3;
1249
1290
  }
1250
1291
  if (cryptFlag === DECRYPT) {
1251
- for (let r = 0, mid; r < 16; r++) {
1252
- mid = roundKey[r];
1253
- roundKey[r] = roundKey[31 - r];
1254
- roundKey[31 - r] = mid;
1292
+ for (let r = 0; r < 16; r++) {
1293
+ [roundKey[r], roundKey[31 - r]] = [roundKey[31 - r], roundKey[r]];
1255
1294
  }
1256
1295
  }
1257
1296
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sm-crypto-v2",
3
- "version": "1.5.1",
3
+ "version": "1.7.0",
4
4
  "description": "sm-crypto-v2",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -33,6 +33,7 @@
33
33
  "@noble/curves": "^1.1.0"
34
34
  },
35
35
  "devDependencies": {
36
+ "@swc-node/register": "^1.6.6",
36
37
  "@swc/core": "^1.3.62",
37
38
  "@types/node": "^16",
38
39
  "@typescript-eslint/eslint-plugin": "^5.23.0",
@@ -40,6 +41,7 @@
40
41
  "@vitest/coverage-c8": "^0.31.0",
41
42
  "@vitest/coverage-istanbul": "^0.31.0",
42
43
  "@vitest/expect": "^0.31.4",
44
+ "@vitest/runner": "^0.33.0",
43
45
  "@vitest/ui": "^0.31.0",
44
46
  "conventional-changelog-cli": "^2.2.2",
45
47
  "eslint": "^8.15.0",
package/src/sm2/index.ts CHANGED
@@ -6,6 +6,7 @@ import * as utils from '@noble/curves/abstract/utils';
6
6
  import { field, sm2Curve } from './ec';
7
7
  import { ONE, ZERO } from './bn';
8
8
  import { bytesToHex } from '@/sm3/utils';
9
+ import { ProjPointType } from '@noble/curves/abstract/weierstrass';
9
10
 
10
11
  export * from './utils'
11
12
  export { initRNGPool } from './rng'
@@ -17,10 +18,11 @@ export const EmptyArray = new Uint8Array()
17
18
  /**
18
19
  * 加密
19
20
  */
20
- export function doEncrypt(msg: string | Uint8Array, publicKey: string, cipherMode = 1) {
21
+ export function doEncrypt(msg: string | Uint8Array, publicKey: string | ProjPointType<bigint>, cipherMode = 1) {
21
22
 
22
23
  const msgArr = typeof msg === 'string' ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg)
23
- const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey)
24
+ const publicKeyPoint = typeof publicKey === 'string' ? sm2Curve.ProjectivePoint.fromHex(publicKey) :
25
+ publicKey
24
26
 
25
27
  const keypair = generateKeyPairHex()
26
28
  const k = utils.hexToNumber(keypair.privateKey)
@@ -28,7 +30,7 @@ export function doEncrypt(msg: string | Uint8Array, publicKey: string, cipherMod
28
30
  // c1 = k * G
29
31
  let c1 = keypair.publicKey
30
32
  if (c1.length > 128) c1 = c1.substring(c1.length - 128)
31
- const p = publicKeyPoint!.multiply(k)
33
+ const p = publicKeyPoint.multiply(k)
32
34
 
33
35
  // (x2, y2) = k * publicKey
34
36
  const x2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.x), 64))
@@ -165,16 +167,17 @@ export function doSignature(msg: Uint8Array | string, privateKey: string, option
165
167
  /**
166
168
  * 验签
167
169
  */
168
- export function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string, options: { der?: boolean, hash?: boolean, userId?: string } = {}) {
170
+ export function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string | ProjPointType<bigint>, options: { der?: boolean, hash?: boolean, userId?: string } = {}) {
169
171
  let hashHex: string
170
172
  const {
171
173
  hash,
172
174
  der,
173
175
  userId,
174
176
  } = options
177
+ const publicKeyHex = typeof publicKey === 'string' ? publicKey : publicKey.toHex(false)
175
178
  if (hash) {
176
179
  // sm3杂凑
177
- hashHex = getHash(typeof msg === 'string' ? utf8ToHex(msg) : msg, publicKey, userId)
180
+ hashHex = getHash(typeof msg === 'string' ? utf8ToHex(msg) : msg, publicKeyHex, userId)
178
181
  } else {
179
182
  hashHex = typeof msg === 'string' ? utf8ToHex(msg) : arrayToHex(Array.from(msg))
180
183
  }
@@ -190,7 +193,7 @@ export function doVerifySignature(msg: string | Uint8Array, signHex: string, pub
190
193
  s = utils.hexToNumber(signHex.substring(64))
191
194
  }
192
195
 
193
- const PA = sm2Curve.ProjectivePoint.fromHex(publicKey)!
196
+ const PA = typeof publicKey === 'string' ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey
194
197
  const e = utils.hexToNumber(hashHex)
195
198
 
196
199
  // t = (r + s) mod n
@@ -250,6 +253,18 @@ export function getHash(hashHex: string | Uint8Array, publicKey: string, userId
250
253
  return bytesToHex(sm3(utils.concatBytes(z, typeof hashHex === 'string' ? hexToArray(hashHex) : hashHex)))
251
254
  }
252
255
 
256
+ /**
257
+ * 预计算公钥点,可用于提升加密性能
258
+ * @export
259
+ * @param {string} publicKey 公钥
260
+ * @param windowSize 计算窗口大小,默认为 8
261
+ * @returns {ProjPointType<bigint>} 预计算的点
262
+ */
263
+ export function precomputePublicKey(publicKey: string, windowSize?: number) {
264
+ const point = sm2Curve.ProjectivePoint.fromHex(publicKey)
265
+ return sm2Curve.utils.precompute(windowSize, point)
266
+ }
267
+
253
268
  /**
254
269
  * 计算公钥
255
270
  */
package/src/sm2/rng.ts CHANGED
@@ -1,10 +1,10 @@
1
- /**
2
- * 安全随机数发生器
3
- * 如果有原生同步接口,直接使用。否则维护一个随机数池,使用异步接口实现。
4
- * Web: webcrypto 原生同步接口
5
- * Node: Node v18 之前需要引入 crypto 模块,这里使用异步 import
6
- * 小程序:异步接口
7
- */
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
8
  declare module wx {
9
9
  function getRandomValues(options: {
10
10
  length: number;
@@ -23,7 +23,7 @@ export async function initRNGPool() {
23
23
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2) return // there is sufficient number
24
24
  // we always populate full pool size
25
25
  // since numbers may be consumed during micro tasks.
26
- if ('wx' in globalThis) {
26
+ if ('wx' in globalThis && 'getRandomValues' in globalThis.wx) {
27
27
  prngPool = await new Promise(r => {
28
28
  wx.getRandomValues({
29
29
  length: DEFAULT_PRNG_POOL_SIZE,
@@ -33,10 +33,16 @@ export async function initRNGPool() {
33
33
  });
34
34
  });
35
35
  } else {
36
- // check if node, use webcrypto if available
36
+ // check if node or browser, use webcrypto if available
37
37
  try {
38
- const crypto = await import(/* webpackIgnore: true */ 'crypto');
39
- _syncCrypto = crypto.webcrypto
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
+ }
40
46
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
41
47
  _syncCrypto.getRandomValues(array);
42
48
  prngPool = array;
package/src/sm2/utils.ts CHANGED
@@ -142,11 +142,12 @@ export function hexToArray(hexStr: string) {
142
142
  export function verifyPublicKey(publicKey: string) {
143
143
  const point = sm2Curve.ProjectivePoint.fromHex(publicKey)
144
144
  if (!point) return false
145
-
146
- const x = point.x
147
- const y = point.y
148
- // 验证 y^2 是否等于 x^3 + ax + 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)
145
+ try {
146
+ point.assertValidity()
147
+ return true
148
+ } catch (error) {
149
+ return false
150
+ }
150
151
  }
151
152
 
152
153
  /**
package/src/sm3/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { hmac } from '@/sm2/hmac'
2
2
  import { sm3 as sm2sm3 } from '../sm2/sm3'
3
- import { arrayToHex, hexToArray, leftPad } from '../sm2/utils'
3
+ import { hexToArray } from '../sm2/utils'
4
4
  import { bytesToHex } from './utils'
5
5
 
6
6
  /**
@@ -0,0 +1,286 @@
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
+ }
package/src/sm4/index.ts CHANGED
@@ -68,83 +68,122 @@ function l2(b: number) {
68
68
  const x = new Uint32Array(4)
69
69
  const tmp = new Uint32Array(4)
70
70
  function sms4Crypt(input: Uint8Array, output: Uint8Array, roundKey: Uint32Array) {
71
- // 字节数组转成字数组(此处 1 = 32 比特)
72
- for (let i = 0; i < 4; i++) {
73
- tmp[0] = input[4 * i] & 0xff
74
- tmp[1] = input[4 * i + 1] & 0xff
75
- tmp[2] = input[4 * i + 2] & 0xff
76
- tmp[3] = input[4 * i + 3] & 0xff
77
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]
71
+ let x0 = 0, x1 = 0, x2 = 0, x3 = 0, tmp0 = 0, tmp1 = 0, tmp2 = 0, tmp3 = 0;
72
+
73
+ // Unroll the first loop
74
+ tmp0 = input[0] & 0xff;
75
+ tmp1 = input[1] & 0xff;
76
+ tmp2 = input[2] & 0xff;
77
+ tmp3 = input[3] & 0xff;
78
+ x0 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
79
+
80
+ tmp0 = input[4] & 0xff;
81
+ tmp1 = input[5] & 0xff;
82
+ tmp2 = input[6] & 0xff;
83
+ tmp3 = input[7] & 0xff;
84
+ x1 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
85
+
86
+ tmp0 = input[8] & 0xff;
87
+ tmp1 = input[9] & 0xff;
88
+ tmp2 = input[10] & 0xff;
89
+ tmp3 = input[11] & 0xff;
90
+ x2 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
91
+
92
+ tmp0 = input[12] & 0xff;
93
+ tmp1 = input[13] & 0xff;
94
+ tmp2 = input[14] & 0xff;
95
+ tmp3 = input[15] & 0xff;
96
+ x3 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
97
+
98
+ for (let r = 0; r < 32; r += 4) {
99
+ // Inlined l1 and rotl functions and avoid the mid variable
100
+ tmp0 = x1 ^ x2 ^ x3 ^ roundKey[r];
101
+ tmp0 = byteSub(tmp0); // byteSub is another function we should inline if possible.
102
+ x0 ^= tmp0 ^ ((tmp0 << 2) | (tmp0 >>> 30)) ^ ((tmp0 << 10) | (tmp0 >>> 22)) ^ ((tmp0 << 18) | (tmp0 >>> 14)) ^ ((tmp0 << 24) | (tmp0 >>> 8));
103
+
104
+ tmp1 = x2 ^ x3 ^ x0 ^ roundKey[r + 1];
105
+ tmp1 = byteSub(tmp1);
106
+ x1 ^= tmp1 ^ ((tmp1 << 2) | (tmp1 >>> 30)) ^ ((tmp1 << 10) | (tmp1 >>> 22)) ^ ((tmp1 << 18) | (tmp1 >>> 14)) ^ ((tmp1 << 24) | (tmp1 >>> 8));
107
+
108
+ tmp2 = x3 ^ x0 ^ x1 ^ roundKey[r + 2];
109
+ tmp2 = byteSub(tmp2);
110
+ x2 ^= tmp2 ^ ((tmp2 << 2) | (tmp2 >>> 30)) ^ ((tmp2 << 10) | (tmp2 >>> 22)) ^ ((tmp2 << 18) | (tmp2 >>> 14)) ^ ((tmp2 << 24) | (tmp2 >>> 8));
111
+
112
+ tmp3 = x0 ^ x1 ^ x2 ^ roundKey[r + 3];
113
+ tmp3 = byteSub(tmp3);
114
+ x3 ^= tmp3 ^ ((tmp3 << 2) | (tmp3 >>> 30)) ^ ((tmp3 << 10) | (tmp3 >>> 22)) ^ ((tmp3 << 18) | (tmp3 >>> 14)) ^ ((tmp3 << 24) | (tmp3 >>> 8));
78
115
  }
79
116
 
80
- // x[i + 4] = x[i] ^ l1(byteSub(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ roundKey[i]))
81
- for (let r = 0, mid: number; r < 32; r += 4) {
82
- mid = x[1] ^ x[2] ^ x[3] ^ roundKey[r + 0]
83
- x[0] ^= l1(byteSub(mid)) // x[4]
84
-
85
- mid = x[2] ^ x[3] ^ x[0] ^ roundKey[r + 1]
86
- x[1] ^= l1(byteSub(mid)) // x[5]
87
-
88
- mid = x[3] ^ x[0] ^ x[1] ^ roundKey[r + 2]
89
- x[2] ^= l1(byteSub(mid)) // x[6]
90
-
91
- mid = x[0] ^ x[1] ^ x[2] ^ roundKey[r + 3]
92
- x[3] ^= l1(byteSub(mid)) // x[7]
93
- }
94
-
95
- // 反序变换
96
- for (let j = 0; j < 16; j += 4) {
97
- output[j] = x[3 - j / 4] >>> 24 & 0xff
98
- output[j + 1] = x[3 - j / 4] >>> 16 & 0xff
99
- output[j + 2] = x[3 - j / 4] >>> 8 & 0xff
100
- output[j + 3] = x[3 - j / 4] & 0xff
101
- }
117
+ // Unroll the last loop
118
+ output[0] = x3 >>> 24 & 0xff;
119
+ output[1] = x3 >>> 16 & 0xff;
120
+ output[2] = x3 >>> 8 & 0xff;
121
+ output[3] = x3 & 0xff;
122
+
123
+ output[4] = x2 >>> 24 & 0xff;
124
+ output[5] = x2 >>> 16 & 0xff;
125
+ output[6] = x2 >>> 8 & 0xff;
126
+ output[7] = x2 & 0xff;
127
+
128
+ output[8] = x1 >>> 24 & 0xff;
129
+ output[9] = x1 >>> 16 & 0xff;
130
+ output[10] = x1 >>> 8 & 0xff;
131
+ output[11] = x1 & 0xff;
132
+
133
+ output[12] = x0 >>> 24 & 0xff;
134
+ output[13] = x0 >>> 16 & 0xff;
135
+ output[14] = x0 >>> 8 & 0xff;
136
+ output[15] = x0 & 0xff;
102
137
  }
103
138
 
104
139
  /**
105
140
  * 密钥扩展算法
106
141
  */
107
142
  function sms4KeyExt(key: Uint8Array, roundKey: Uint32Array, cryptFlag: 0 | 1) {
143
+ let x0 = 0, x1 = 0, x2 = 0, x3 = 0, mid = 0;
108
144
 
109
- // 字节数组转成字数组(此处 1 = 32 比特)
110
- for (let i = 0; i < 4; i++) {
111
- tmp[0] = key[0 + 4 * i] & 0xff
112
- tmp[1] = key[1 + 4 * i] & 0xff
113
- tmp[2] = key[2 + 4 * i] & 0xff
114
- tmp[3] = key[3 + 4 * i] & 0xff
115
- x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3]
116
- }
145
+ // Unwrap the first loop and use local variables instead of the array x
146
+ x0 = (key[0] & 0xff) << 24 | (key[1] & 0xff) << 16 | (key[2] & 0xff) << 8 | (key[3] & 0xff);
147
+ x1 = (key[4] & 0xff) << 24 | (key[5] & 0xff) << 16 | (key[6] & 0xff) << 8 | (key[7] & 0xff);
148
+ x2 = (key[8] & 0xff) << 24 | (key[9] & 0xff) << 16 | (key[10] & 0xff) << 8 | (key[11] & 0xff);
149
+ x3 = (key[12] & 0xff) << 24 | (key[13] & 0xff) << 16 | (key[14] & 0xff) << 8 | (key[15] & 0xff);
117
150
 
118
151
  // 与系统参数做异或
119
- x[0] ^= 0xa3b1bac6
120
- x[1] ^= 0x56aa3350
121
- x[2] ^= 0x677d9197
122
- x[3] ^= 0xb27022dc
123
-
124
- // roundKey[i] = x[i + 4] = x[i] ^ l2(byteSub(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ CK[i]))
125
- for (let r = 0, mid: number; r < 32; r += 4) {
126
- mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0]
127
- roundKey[r + 0] = x[0] ^= l2(byteSub(mid)) // x[4]
128
-
129
- mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1]
130
- roundKey[r + 1] = x[1] ^= l2(byteSub(mid)) // x[5]
131
-
132
- mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2]
133
- roundKey[r + 2] = x[2] ^= l2(byteSub(mid)) // x[6]
134
-
135
- mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3]
136
- roundKey[r + 3] = x[3] ^= l2(byteSub(mid)) // x[7]
152
+ x0 ^= 0xa3b1bac6;
153
+ x1 ^= 0x56aa3350;
154
+ x2 ^= 0x677d9197;
155
+ x3 ^= 0xb27022dc;
156
+
157
+ for (let r = 0; r < 32; r += 4) {
158
+ mid = x1 ^ x2 ^ x3 ^ CK[r + 0];
159
+ mid = byteSub(mid); // Again, if possible, inline the byteSub function.
160
+ x0 ^= mid ^ ((mid << 13) | (mid >>> 19)) ^ ((mid << 23) | (mid >>> 9));
161
+ roundKey[r + 0] = x0;
162
+
163
+ mid = x2 ^ x3 ^ x0 ^ CK[r + 1];
164
+ mid = byteSub(mid);
165
+ x1 ^= mid ^ ((mid << 13) | (mid >>> 19)) ^ ((mid << 23) | (mid >>> 9));
166
+ roundKey[r + 1] = x1;
167
+
168
+ mid = x3 ^ x0 ^ x1 ^ CK[r + 2];
169
+ mid = byteSub(mid);
170
+ x2 ^= mid ^ ((mid << 13) | (mid >>> 19)) ^ ((mid << 23) | (mid >>> 9));
171
+ roundKey[r + 2] = x2;
172
+
173
+ mid = x0 ^ x1 ^ x2 ^ CK[r + 3];
174
+ mid = byteSub(mid);
175
+ x3 ^= mid ^ ((mid << 13) | (mid >>> 19)) ^ ((mid << 23) | (mid >>> 9));
176
+ roundKey[r + 3] = x3;
137
177
  }
138
178
 
139
- // 解密时使用反序的轮密钥
140
179
  if (cryptFlag === DECRYPT) {
141
- for (let r = 0, mid: number; r < 16; r++) {
142
- mid = roundKey[r]
143
- roundKey[r] = roundKey[31 - r]
144
- roundKey[31 - r] = mid
180
+ for (let r = 0; r < 16; r++) {
181
+ // Use destructuring to swap elements
182
+ [roundKey[r], roundKey[31 - r]] = [roundKey[31 - r], roundKey[r]];
145
183
  }
146
184
  }
147
185
  }
186
+
148
187
  export interface SM4Options {
149
188
  padding?: 'pkcs#7' | 'pkcs#5' | 'none' | null
150
189
  mode?: 'cbc' | 'ecb'