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 +14 -0
- package/README.md +15 -0
- package/dist/index.d.ts +14 -2
- package/dist/index.js +103 -64
- package/dist/index.mjs +103 -64
- package/package.json +3 -1
- package/src/sm2/index.ts +21 -6
- package/src/sm2/rng.ts +17 -11
- package/src/sm2/utils.ts +6 -5
- package/src/sm3/index.ts +1 -1
- package/src/sm4/_slow.ts +286 -0
- package/src/sm4/index.ts +99 -60
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
|
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
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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
|
-
|
640
|
-
|
641
|
-
|
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,
|
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
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
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
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
roundKey[r + 0] =
|
1271
|
-
mid =
|
1272
|
-
|
1273
|
-
|
1274
|
-
roundKey[r +
|
1275
|
-
mid =
|
1276
|
-
|
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
|
1280
|
-
|
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
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
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
|
-
|
612
|
-
|
613
|
-
|
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,
|
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
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
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
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
roundKey[r + 0] =
|
1243
|
-
mid =
|
1244
|
-
|
1245
|
-
|
1246
|
-
roundKey[r +
|
1247
|
-
mid =
|
1248
|
-
|
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
|
1252
|
-
|
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.
|
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
|
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
|
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
|
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,
|
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
|
-
|
5
|
-
|
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
|
-
|
39
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
package/src/sm4/_slow.ts
ADDED
@@ -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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
//
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
//
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
mid =
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
roundKey[r +
|
134
|
-
|
135
|
-
mid =
|
136
|
-
|
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
|
142
|
-
|
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'
|