sm-crypto-v2 1.5.1 → 1.6.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 +7 -0
- package/dist/index.js +88 -58
- package/dist/index.mjs +88 -58
- package/package.json +1 -1
- package/src/sm2/rng.ts +17 -11
- package/src/sm4/_slow.ts +286 -0
- package/src/sm4/index.ts +99 -60
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
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.6.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.5.1...v1.6.0) (2023-07-11)
|
6
|
+
|
7
|
+
|
8
|
+
### Features
|
9
|
+
|
10
|
+
* **sm4:** optimize sm4 ([031159c](https://github.com/Cubelrti/sm-crypto-v2/commit/031159c7e2889f01b499b9286ce1d93a5e55b151))
|
11
|
+
|
5
12
|
### [1.5.1](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.5.0...v1.5.1) (2023-06-28)
|
6
13
|
|
7
14
|
|
package/dist/index.js
CHANGED
@@ -198,7 +198,7 @@ async function initRNGPool() {
|
|
198
198
|
}
|
199
199
|
if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
|
200
200
|
return;
|
201
|
-
if ("wx" in globalThis) {
|
201
|
+
if ("wx" in globalThis && "getRandomValues" in globalThis.wx) {
|
202
202
|
prngPool = await new Promise((r) => {
|
203
203
|
wx.getRandomValues({
|
204
204
|
length: DEFAULT_PRNG_POOL_SIZE,
|
@@ -209,11 +209,15 @@ async function initRNGPool() {
|
|
209
209
|
});
|
210
210
|
} else {
|
211
211
|
try {
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
212
|
+
if (globalThis.crypto) {
|
213
|
+
_syncCrypto = globalThis.crypto;
|
214
|
+
} else {
|
215
|
+
const crypto = await import(
|
216
|
+
/* webpackIgnore: true */
|
217
|
+
"crypto"
|
218
|
+
);
|
219
|
+
_syncCrypto = crypto.webcrypto;
|
220
|
+
}
|
217
221
|
const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
|
218
222
|
_syncCrypto.getRandomValues(array);
|
219
223
|
prngPool = array;
|
@@ -1220,66 +1224,92 @@ var CK = new Uint32Array([
|
|
1220
1224
|
function byteSub(a) {
|
1221
1225
|
return (Sbox[a >>> 24 & 255] & 255) << 24 | (Sbox[a >>> 16 & 255] & 255) << 16 | (Sbox[a >>> 8 & 255] & 255) << 8 | Sbox[a & 255] & 255;
|
1222
1226
|
}
|
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
1227
|
var x = new Uint32Array(4);
|
1230
1228
|
var tmp = new Uint32Array(4);
|
1231
1229
|
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
|
-
|
1230
|
+
let x0 = 0, x1 = 0, x2 = 0, x3 = 0, tmp0 = 0, tmp1 = 0, tmp2 = 0, tmp3 = 0;
|
1231
|
+
tmp0 = input[0] & 255;
|
1232
|
+
tmp1 = input[1] & 255;
|
1233
|
+
tmp2 = input[2] & 255;
|
1234
|
+
tmp3 = input[3] & 255;
|
1235
|
+
x0 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1236
|
+
tmp0 = input[4] & 255;
|
1237
|
+
tmp1 = input[5] & 255;
|
1238
|
+
tmp2 = input[6] & 255;
|
1239
|
+
tmp3 = input[7] & 255;
|
1240
|
+
x1 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1241
|
+
tmp0 = input[8] & 255;
|
1242
|
+
tmp1 = input[9] & 255;
|
1243
|
+
tmp2 = input[10] & 255;
|
1244
|
+
tmp3 = input[11] & 255;
|
1245
|
+
x2 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1246
|
+
tmp0 = input[12] & 255;
|
1247
|
+
tmp1 = input[13] & 255;
|
1248
|
+
tmp2 = input[14] & 255;
|
1249
|
+
tmp3 = input[15] & 255;
|
1250
|
+
x3 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1251
|
+
for (let r = 0; r < 32; r += 4) {
|
1252
|
+
tmp0 = x1 ^ x2 ^ x3 ^ roundKey[r];
|
1253
|
+
tmp0 = byteSub(tmp0);
|
1254
|
+
x0 ^= tmp0 ^ (tmp0 << 2 | tmp0 >>> 30) ^ (tmp0 << 10 | tmp0 >>> 22) ^ (tmp0 << 18 | tmp0 >>> 14) ^ (tmp0 << 24 | tmp0 >>> 8);
|
1255
|
+
tmp1 = x2 ^ x3 ^ x0 ^ roundKey[r + 1];
|
1256
|
+
tmp1 = byteSub(tmp1);
|
1257
|
+
x1 ^= tmp1 ^ (tmp1 << 2 | tmp1 >>> 30) ^ (tmp1 << 10 | tmp1 >>> 22) ^ (tmp1 << 18 | tmp1 >>> 14) ^ (tmp1 << 24 | tmp1 >>> 8);
|
1258
|
+
tmp2 = x3 ^ x0 ^ x1 ^ roundKey[r + 2];
|
1259
|
+
tmp2 = byteSub(tmp2);
|
1260
|
+
x2 ^= tmp2 ^ (tmp2 << 2 | tmp2 >>> 30) ^ (tmp2 << 10 | tmp2 >>> 22) ^ (tmp2 << 18 | tmp2 >>> 14) ^ (tmp2 << 24 | tmp2 >>> 8);
|
1261
|
+
tmp3 = x0 ^ x1 ^ x2 ^ roundKey[r + 3];
|
1262
|
+
tmp3 = byteSub(tmp3);
|
1263
|
+
x3 ^= tmp3 ^ (tmp3 << 2 | tmp3 >>> 30) ^ (tmp3 << 10 | tmp3 >>> 22) ^ (tmp3 << 18 | tmp3 >>> 14) ^ (tmp3 << 24 | tmp3 >>> 8);
|
1254
1264
|
}
|
1265
|
+
output[0] = x3 >>> 24 & 255;
|
1266
|
+
output[1] = x3 >>> 16 & 255;
|
1267
|
+
output[2] = x3 >>> 8 & 255;
|
1268
|
+
output[3] = x3 & 255;
|
1269
|
+
output[4] = x2 >>> 24 & 255;
|
1270
|
+
output[5] = x2 >>> 16 & 255;
|
1271
|
+
output[6] = x2 >>> 8 & 255;
|
1272
|
+
output[7] = x2 & 255;
|
1273
|
+
output[8] = x1 >>> 24 & 255;
|
1274
|
+
output[9] = x1 >>> 16 & 255;
|
1275
|
+
output[10] = x1 >>> 8 & 255;
|
1276
|
+
output[11] = x1 & 255;
|
1277
|
+
output[12] = x0 >>> 24 & 255;
|
1278
|
+
output[13] = x0 >>> 16 & 255;
|
1279
|
+
output[14] = x0 >>> 8 & 255;
|
1280
|
+
output[15] = x0 & 255;
|
1255
1281
|
}
|
1256
1282
|
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
|
-
|
1283
|
+
let x0 = 0, x1 = 0, x2 = 0, x3 = 0, mid = 0;
|
1284
|
+
x0 = (key[0] & 255) << 24 | (key[1] & 255) << 16 | (key[2] & 255) << 8 | key[3] & 255;
|
1285
|
+
x1 = (key[4] & 255) << 24 | (key[5] & 255) << 16 | (key[6] & 255) << 8 | key[7] & 255;
|
1286
|
+
x2 = (key[8] & 255) << 24 | (key[9] & 255) << 16 | (key[10] & 255) << 8 | key[11] & 255;
|
1287
|
+
x3 = (key[12] & 255) << 24 | (key[13] & 255) << 16 | (key[14] & 255) << 8 | key[15] & 255;
|
1288
|
+
x0 ^= 2746333894;
|
1289
|
+
x1 ^= 1453994832;
|
1290
|
+
x2 ^= 1736282519;
|
1291
|
+
x3 ^= 2993693404;
|
1292
|
+
for (let r = 0; r < 32; r += 4) {
|
1293
|
+
mid = x1 ^ x2 ^ x3 ^ CK[r + 0];
|
1294
|
+
mid = byteSub(mid);
|
1295
|
+
x0 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1296
|
+
roundKey[r + 0] = x0;
|
1297
|
+
mid = x2 ^ x3 ^ x0 ^ CK[r + 1];
|
1298
|
+
mid = byteSub(mid);
|
1299
|
+
x1 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1300
|
+
roundKey[r + 1] = x1;
|
1301
|
+
mid = x3 ^ x0 ^ x1 ^ CK[r + 2];
|
1302
|
+
mid = byteSub(mid);
|
1303
|
+
x2 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1304
|
+
roundKey[r + 2] = x2;
|
1305
|
+
mid = x0 ^ x1 ^ x2 ^ CK[r + 3];
|
1306
|
+
mid = byteSub(mid);
|
1307
|
+
x3 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1308
|
+
roundKey[r + 3] = x3;
|
1277
1309
|
}
|
1278
1310
|
if (cryptFlag === DECRYPT) {
|
1279
|
-
for (let r = 0
|
1280
|
-
|
1281
|
-
roundKey[r] = roundKey[31 - r];
|
1282
|
-
roundKey[31 - r] = mid;
|
1311
|
+
for (let r = 0; r < 16; r++) {
|
1312
|
+
[roundKey[r], roundKey[31 - r]] = [roundKey[31 - r], roundKey[r]];
|
1283
1313
|
}
|
1284
1314
|
}
|
1285
1315
|
}
|
package/dist/index.mjs
CHANGED
@@ -170,7 +170,7 @@ async function initRNGPool() {
|
|
170
170
|
}
|
171
171
|
if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
|
172
172
|
return;
|
173
|
-
if ("wx" in globalThis) {
|
173
|
+
if ("wx" in globalThis && "getRandomValues" in globalThis.wx) {
|
174
174
|
prngPool = await new Promise((r) => {
|
175
175
|
wx.getRandomValues({
|
176
176
|
length: DEFAULT_PRNG_POOL_SIZE,
|
@@ -181,11 +181,15 @@ async function initRNGPool() {
|
|
181
181
|
});
|
182
182
|
} else {
|
183
183
|
try {
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
184
|
+
if (globalThis.crypto) {
|
185
|
+
_syncCrypto = globalThis.crypto;
|
186
|
+
} else {
|
187
|
+
const crypto = await import(
|
188
|
+
/* webpackIgnore: true */
|
189
|
+
"crypto"
|
190
|
+
);
|
191
|
+
_syncCrypto = crypto.webcrypto;
|
192
|
+
}
|
189
193
|
const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
|
190
194
|
_syncCrypto.getRandomValues(array);
|
191
195
|
prngPool = array;
|
@@ -1192,66 +1196,92 @@ var CK = new Uint32Array([
|
|
1192
1196
|
function byteSub(a) {
|
1193
1197
|
return (Sbox[a >>> 24 & 255] & 255) << 24 | (Sbox[a >>> 16 & 255] & 255) << 16 | (Sbox[a >>> 8 & 255] & 255) << 8 | Sbox[a & 255] & 255;
|
1194
1198
|
}
|
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
1199
|
var x = new Uint32Array(4);
|
1202
1200
|
var tmp = new Uint32Array(4);
|
1203
1201
|
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
|
-
|
1202
|
+
let x0 = 0, x1 = 0, x2 = 0, x3 = 0, tmp0 = 0, tmp1 = 0, tmp2 = 0, tmp3 = 0;
|
1203
|
+
tmp0 = input[0] & 255;
|
1204
|
+
tmp1 = input[1] & 255;
|
1205
|
+
tmp2 = input[2] & 255;
|
1206
|
+
tmp3 = input[3] & 255;
|
1207
|
+
x0 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1208
|
+
tmp0 = input[4] & 255;
|
1209
|
+
tmp1 = input[5] & 255;
|
1210
|
+
tmp2 = input[6] & 255;
|
1211
|
+
tmp3 = input[7] & 255;
|
1212
|
+
x1 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1213
|
+
tmp0 = input[8] & 255;
|
1214
|
+
tmp1 = input[9] & 255;
|
1215
|
+
tmp2 = input[10] & 255;
|
1216
|
+
tmp3 = input[11] & 255;
|
1217
|
+
x2 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1218
|
+
tmp0 = input[12] & 255;
|
1219
|
+
tmp1 = input[13] & 255;
|
1220
|
+
tmp2 = input[14] & 255;
|
1221
|
+
tmp3 = input[15] & 255;
|
1222
|
+
x3 = tmp0 << 24 | tmp1 << 16 | tmp2 << 8 | tmp3;
|
1223
|
+
for (let r = 0; r < 32; r += 4) {
|
1224
|
+
tmp0 = x1 ^ x2 ^ x3 ^ roundKey[r];
|
1225
|
+
tmp0 = byteSub(tmp0);
|
1226
|
+
x0 ^= tmp0 ^ (tmp0 << 2 | tmp0 >>> 30) ^ (tmp0 << 10 | tmp0 >>> 22) ^ (tmp0 << 18 | tmp0 >>> 14) ^ (tmp0 << 24 | tmp0 >>> 8);
|
1227
|
+
tmp1 = x2 ^ x3 ^ x0 ^ roundKey[r + 1];
|
1228
|
+
tmp1 = byteSub(tmp1);
|
1229
|
+
x1 ^= tmp1 ^ (tmp1 << 2 | tmp1 >>> 30) ^ (tmp1 << 10 | tmp1 >>> 22) ^ (tmp1 << 18 | tmp1 >>> 14) ^ (tmp1 << 24 | tmp1 >>> 8);
|
1230
|
+
tmp2 = x3 ^ x0 ^ x1 ^ roundKey[r + 2];
|
1231
|
+
tmp2 = byteSub(tmp2);
|
1232
|
+
x2 ^= tmp2 ^ (tmp2 << 2 | tmp2 >>> 30) ^ (tmp2 << 10 | tmp2 >>> 22) ^ (tmp2 << 18 | tmp2 >>> 14) ^ (tmp2 << 24 | tmp2 >>> 8);
|
1233
|
+
tmp3 = x0 ^ x1 ^ x2 ^ roundKey[r + 3];
|
1234
|
+
tmp3 = byteSub(tmp3);
|
1235
|
+
x3 ^= tmp3 ^ (tmp3 << 2 | tmp3 >>> 30) ^ (tmp3 << 10 | tmp3 >>> 22) ^ (tmp3 << 18 | tmp3 >>> 14) ^ (tmp3 << 24 | tmp3 >>> 8);
|
1226
1236
|
}
|
1237
|
+
output[0] = x3 >>> 24 & 255;
|
1238
|
+
output[1] = x3 >>> 16 & 255;
|
1239
|
+
output[2] = x3 >>> 8 & 255;
|
1240
|
+
output[3] = x3 & 255;
|
1241
|
+
output[4] = x2 >>> 24 & 255;
|
1242
|
+
output[5] = x2 >>> 16 & 255;
|
1243
|
+
output[6] = x2 >>> 8 & 255;
|
1244
|
+
output[7] = x2 & 255;
|
1245
|
+
output[8] = x1 >>> 24 & 255;
|
1246
|
+
output[9] = x1 >>> 16 & 255;
|
1247
|
+
output[10] = x1 >>> 8 & 255;
|
1248
|
+
output[11] = x1 & 255;
|
1249
|
+
output[12] = x0 >>> 24 & 255;
|
1250
|
+
output[13] = x0 >>> 16 & 255;
|
1251
|
+
output[14] = x0 >>> 8 & 255;
|
1252
|
+
output[15] = x0 & 255;
|
1227
1253
|
}
|
1228
1254
|
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
|
-
|
1255
|
+
let x0 = 0, x1 = 0, x2 = 0, x3 = 0, mid = 0;
|
1256
|
+
x0 = (key[0] & 255) << 24 | (key[1] & 255) << 16 | (key[2] & 255) << 8 | key[3] & 255;
|
1257
|
+
x1 = (key[4] & 255) << 24 | (key[5] & 255) << 16 | (key[6] & 255) << 8 | key[7] & 255;
|
1258
|
+
x2 = (key[8] & 255) << 24 | (key[9] & 255) << 16 | (key[10] & 255) << 8 | key[11] & 255;
|
1259
|
+
x3 = (key[12] & 255) << 24 | (key[13] & 255) << 16 | (key[14] & 255) << 8 | key[15] & 255;
|
1260
|
+
x0 ^= 2746333894;
|
1261
|
+
x1 ^= 1453994832;
|
1262
|
+
x2 ^= 1736282519;
|
1263
|
+
x3 ^= 2993693404;
|
1264
|
+
for (let r = 0; r < 32; r += 4) {
|
1265
|
+
mid = x1 ^ x2 ^ x3 ^ CK[r + 0];
|
1266
|
+
mid = byteSub(mid);
|
1267
|
+
x0 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1268
|
+
roundKey[r + 0] = x0;
|
1269
|
+
mid = x2 ^ x3 ^ x0 ^ CK[r + 1];
|
1270
|
+
mid = byteSub(mid);
|
1271
|
+
x1 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1272
|
+
roundKey[r + 1] = x1;
|
1273
|
+
mid = x3 ^ x0 ^ x1 ^ CK[r + 2];
|
1274
|
+
mid = byteSub(mid);
|
1275
|
+
x2 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1276
|
+
roundKey[r + 2] = x2;
|
1277
|
+
mid = x0 ^ x1 ^ x2 ^ CK[r + 3];
|
1278
|
+
mid = byteSub(mid);
|
1279
|
+
x3 ^= mid ^ (mid << 13 | mid >>> 19) ^ (mid << 23 | mid >>> 9);
|
1280
|
+
roundKey[r + 3] = x3;
|
1249
1281
|
}
|
1250
1282
|
if (cryptFlag === DECRYPT) {
|
1251
|
-
for (let r = 0
|
1252
|
-
|
1253
|
-
roundKey[r] = roundKey[31 - r];
|
1254
|
-
roundKey[31 - r] = mid;
|
1283
|
+
for (let r = 0; r < 16; r++) {
|
1284
|
+
[roundKey[r], roundKey[31 - r]] = [roundKey[31 - r], roundKey[r]];
|
1255
1285
|
}
|
1256
1286
|
}
|
1257
1287
|
}
|
package/package.json
CHANGED
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/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'
|