cyberchef 9.36.1 → 9.37.2

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
@@ -13,6 +13,10 @@ All major and minor version changes will be documented in this file. Details of
13
13
 
14
14
  ## Details
15
15
 
16
+ ### [9.37.0] - 2022-03-29
17
+ - 'SM4 Encrypt' and 'SM4 Decrypt' operations added [@swesven] | [#1189]
18
+ - NoPadding options added for CBC and ECB modes in AES, DES and Triple DES Decrypt operations [@swesven] | [#1189]
19
+
16
20
  ### [9.36.0] - 2022-03-29
17
21
  - 'SIGABA' operation added [@hettysymes] | [#934]
18
22
 
@@ -284,6 +288,7 @@ All major and minor version changes will be documented in this file. Details of
284
288
 
285
289
 
286
290
 
291
+ [9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0
287
292
  [9.36.0]: https://github.com/gchq/CyberChef/releases/tag/v9.36.0
288
293
  [9.35.0]: https://github.com/gchq/CyberChef/releases/tag/v9.35.0
289
294
  [9.34.0]: https://github.com/gchq/CyberChef/releases/tag/v9.34.0
@@ -404,6 +409,7 @@ All major and minor version changes will be documented in this file. Details of
404
409
  [@john19696]: https://github.com/john19696
405
410
  [@t-8ch]: https://github.com/t-8ch
406
411
  [@hettysymes]: https://github.com/hettysymes
412
+ [@swesven]: https://github.com/swesven
407
413
 
408
414
  [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
409
415
  [9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
@@ -492,6 +498,7 @@ All major and minor version changes will be documented in this file. Details of
492
498
  [#1049]: https://github.com/gchq/CyberChef/pull/1049
493
499
  [#1065]: https://github.com/gchq/CyberChef/pull/1065
494
500
  [#1083]: https://github.com/gchq/CyberChef/pull/1083
501
+ [#1189]: https://github.com/gchq/CyberChef/pull/1189
495
502
  [#1242]: https://github.com/gchq/CyberChef/pull/1242
496
503
  [#1244]: https://github.com/gchq/CyberChef/pull/1244
497
504
  [#1313]: https://github.com/gchq/CyberChef/pull/1313
package/nightwatch.json CHANGED
@@ -10,11 +10,12 @@
10
10
  "start_process": true,
11
11
  "server_path": "./node_modules/.bin/chromedriver",
12
12
  "port": 9515,
13
- "log_path": false
13
+ "log_path": "tests/browser/output"
14
14
  },
15
15
  "desiredCapabilities": {
16
16
  "browserName": "chrome"
17
- }
17
+ },
18
+ "enable_fail_fast": true
18
19
  },
19
20
 
20
21
  "dev": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberchef",
3
- "version": "9.36.1",
3
+ "version": "9.37.2",
4
4
  "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
5
5
  "author": "n1474335 <n1474335@gmail.com>",
6
6
  "homepage": "https://gchq.github.io/CyberChef",
@@ -723,8 +723,8 @@ class Utils {
723
723
  }
724
724
 
725
725
  if (removeScriptAndStyle) {
726
- htmlStr = recursiveRemove(/<script[^>]*>.*?<\/script>/gi, htmlStr);
727
- htmlStr = recursiveRemove(/<style[^>]*>.*?<\/style>/gi, htmlStr);
726
+ htmlStr = recursiveRemove(/<script[^>]*>.*?<\/script[^>]*>/gi, htmlStr);
727
+ htmlStr = recursiveRemove(/<style[^>]*>.*?<\/style[^>]*>/gi, htmlStr);
728
728
  }
729
729
  return htmlStr.replace(/<[^>]+>/g, "");
730
730
  }
@@ -83,6 +83,8 @@
83
83
  "RC2 Decrypt",
84
84
  "RC4",
85
85
  "RC4 Drop",
86
+ "SM4 Encrypt",
87
+ "SM4 Decrypt",
86
88
  "ROT13",
87
89
  "ROT47",
88
90
  "XOR",
@@ -115,7 +115,7 @@
115
115
  },
116
116
  "AES Decrypt": {
117
117
  "module": "Ciphers",
118
- "description": "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul><br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.",
118
+ "description": "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul><br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.",
119
119
  "infoURL": "https://wikipedia.org/wiki/Advanced_Encryption_Standard",
120
120
  "inputType": "string",
121
121
  "outputType": "string",
@@ -189,6 +189,20 @@
189
189
  5,
190
190
  6
191
191
  ]
192
+ },
193
+ {
194
+ "name": "CBC/NoPadding",
195
+ "off": [
196
+ 5,
197
+ 6
198
+ ]
199
+ },
200
+ {
201
+ "name": "ECB/NoPadding",
202
+ "off": [
203
+ 5,
204
+ 6
205
+ ]
192
206
  }
193
207
  ]
194
208
  },
@@ -3378,7 +3392,7 @@
3378
3392
  },
3379
3393
  "DES Decrypt": {
3380
3394
  "module": "Ciphers",
3381
- "description": "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.",
3395
+ "description": "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.",
3382
3396
  "infoURL": "https://wikipedia.org/wiki/Data_Encryption_Standard",
3383
3397
  "inputType": "string",
3384
3398
  "outputType": "string",
@@ -3415,7 +3429,9 @@
3415
3429
  "CFB",
3416
3430
  "OFB",
3417
3431
  "CTR",
3418
- "ECB"
3432
+ "ECB",
3433
+ "CBC/NoPadding",
3434
+ "ECB/NoPadding"
3419
3435
  ]
3420
3436
  },
3421
3437
  {
@@ -9859,9 +9875,9 @@
9859
9875
  ]
9860
9876
  },
9861
9877
  {
9862
- "name": "Number of bytes to drop",
9878
+ "name": "Number of dwords to drop",
9863
9879
  "type": "number",
9864
- "value": 768
9880
+ "value": 192
9865
9881
  }
9866
9882
  ]
9867
9883
  },
@@ -11874,6 +11890,128 @@
11874
11890
  }
11875
11891
  ]
11876
11892
  },
11893
+ "SM4 Decrypt": {
11894
+ "module": "Ciphers",
11895
+ "description": "SM4 is a 128-bit block cipher, currently established as a national standard (GB/T 32907-2016) of China.",
11896
+ "infoURL": "https://wikipedia.org/wiki/SM4_(cipher)",
11897
+ "inputType": "string",
11898
+ "outputType": "string",
11899
+ "flowControl": false,
11900
+ "manualBake": false,
11901
+ "args": [
11902
+ {
11903
+ "name": "Key",
11904
+ "type": "toggleString",
11905
+ "value": "",
11906
+ "toggleValues": [
11907
+ "Hex",
11908
+ "UTF8",
11909
+ "Latin1",
11910
+ "Base64"
11911
+ ]
11912
+ },
11913
+ {
11914
+ "name": "IV",
11915
+ "type": "toggleString",
11916
+ "value": "",
11917
+ "toggleValues": [
11918
+ "Hex",
11919
+ "UTF8",
11920
+ "Latin1",
11921
+ "Base64"
11922
+ ]
11923
+ },
11924
+ {
11925
+ "name": "Mode",
11926
+ "type": "option",
11927
+ "value": [
11928
+ "CBC",
11929
+ "CFB",
11930
+ "OFB",
11931
+ "CTR",
11932
+ "ECB",
11933
+ "CBC/NoPadding",
11934
+ "ECB/NoPadding"
11935
+ ]
11936
+ },
11937
+ {
11938
+ "name": "Input",
11939
+ "type": "option",
11940
+ "value": [
11941
+ "Raw",
11942
+ "Hex"
11943
+ ]
11944
+ },
11945
+ {
11946
+ "name": "Output",
11947
+ "type": "option",
11948
+ "value": [
11949
+ "Hex",
11950
+ "Raw"
11951
+ ]
11952
+ }
11953
+ ]
11954
+ },
11955
+ "SM4 Encrypt": {
11956
+ "module": "Ciphers",
11957
+ "description": "SM4 is a 128-bit block cipher, currently established as a national standard (GB/T 32907-2016) of China. Multiple block cipher modes are supported. When using CBC or ECB mode, the PKCS#7 padding scheme is used.",
11958
+ "infoURL": "https://wikipedia.org/wiki/SM4_(cipher)",
11959
+ "inputType": "string",
11960
+ "outputType": "string",
11961
+ "flowControl": false,
11962
+ "manualBake": false,
11963
+ "args": [
11964
+ {
11965
+ "name": "Key",
11966
+ "type": "toggleString",
11967
+ "value": "",
11968
+ "toggleValues": [
11969
+ "Hex",
11970
+ "UTF8",
11971
+ "Latin1",
11972
+ "Base64"
11973
+ ]
11974
+ },
11975
+ {
11976
+ "name": "IV",
11977
+ "type": "toggleString",
11978
+ "value": "",
11979
+ "toggleValues": [
11980
+ "Hex",
11981
+ "UTF8",
11982
+ "Latin1",
11983
+ "Base64"
11984
+ ]
11985
+ },
11986
+ {
11987
+ "name": "Mode",
11988
+ "type": "option",
11989
+ "value": [
11990
+ "CBC",
11991
+ "CFB",
11992
+ "OFB",
11993
+ "CTR",
11994
+ "ECB"
11995
+ ]
11996
+ },
11997
+ {
11998
+ "name": "Input",
11999
+ "type": "option",
12000
+ "value": [
12001
+ "Raw",
12002
+ "Hex"
12003
+ ]
12004
+ },
12005
+ {
12006
+ "name": "Output",
12007
+ "type": "option",
12008
+ "value": [
12009
+ "Hex",
12010
+ "Raw"
12011
+ ]
12012
+ }
12013
+ ]
12014
+ },
11877
12015
  "SQL Beautify": {
11878
12016
  "module": "Code",
11879
12017
  "description": "Indents and prettifies Structured Query Language (SQL) code.",
@@ -15066,7 +15204,7 @@
15066
15204
  },
15067
15205
  "Triple DES Decrypt": {
15068
15206
  "module": "Ciphers",
15069
- "description": "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.",
15207
+ "description": "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.",
15070
15208
  "infoURL": "https://wikipedia.org/wiki/Triple_DES",
15071
15209
  "inputType": "string",
15072
15210
  "outputType": "string",
@@ -15103,7 +15241,9 @@
15103
15241
  "CFB",
15104
15242
  "OFB",
15105
15243
  "CTR",
15106
- "ECB"
15244
+ "ECB",
15245
+ "CBC/NoPadding",
15246
+ "ECB/NoPadding"
15107
15247
  ]
15108
15248
  },
15109
15249
  {
@@ -32,6 +32,8 @@ import RSASign from "../../operations/RSASign.mjs";
32
32
  import RSAVerify from "../../operations/RSAVerify.mjs";
33
33
  import RailFenceCipherDecode from "../../operations/RailFenceCipherDecode.mjs";
34
34
  import RailFenceCipherEncode from "../../operations/RailFenceCipherEncode.mjs";
35
+ import SM4Decrypt from "../../operations/SM4Decrypt.mjs";
36
+ import SM4Encrypt from "../../operations/SM4Encrypt.mjs";
35
37
  import TripleDESDecrypt from "../../operations/TripleDESDecrypt.mjs";
36
38
  import TripleDESEncrypt from "../../operations/TripleDESEncrypt.mjs";
37
39
  import VigenèreDecode from "../../operations/VigenèreDecode.mjs";
@@ -67,6 +69,8 @@ OpModules.Ciphers = {
67
69
  "RSA Verify": RSAVerify,
68
70
  "Rail Fence Cipher Decode": RailFenceCipherDecode,
69
71
  "Rail Fence Cipher Encode": RailFenceCipherEncode,
72
+ "SM4 Decrypt": SM4Decrypt,
73
+ "SM4 Encrypt": SM4Encrypt,
70
74
  "Triple DES Decrypt": TripleDESDecrypt,
71
75
  "Triple DES Encrypt": TripleDESEncrypt,
72
76
  "Vigenère Decode": VigenèreDecode,
@@ -0,0 +1,331 @@
1
+ /**
2
+ * Complete implementation of SM4 cipher encryption/decryption with
3
+ * ECB, CBC, CFB, OFB, CTR block modes.
4
+ * These modes are specified in IETF draft-ribose-cfrg-sm4-09, see:
5
+ * https://tools.ietf.org/id/draft-ribose-cfrg-sm4-09.html
6
+ * for details.
7
+ *
8
+ * Follows spec from Cryptography Standardization Technical Comittee:
9
+ * http://www.gmbz.org.cn/upload/2018-04-04/1522788048733065051.pdf
10
+ *
11
+ * @author swesven
12
+ * @copyright 2021
13
+ * @license Apache-2.0
14
+ */
15
+
16
+ import OperationError from "../errors/OperationError.mjs";
17
+
18
+ /** Number of rounds */
19
+ const NROUNDS = 32;
20
+
21
+ /** block size in bytes */
22
+ const BLOCKSIZE = 16;
23
+
24
+ /** The S box, 256 8-bit values */
25
+ const Sbox = [
26
+ 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
27
+ 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
28
+ 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
29
+ 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
30
+ 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
31
+ 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
32
+ 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
33
+ 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
34
+ 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
35
+ 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
36
+ 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
37
+ 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
38
+ 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
39
+ 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
40
+ 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
41
+ 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
42
+ ];
43
+
44
+ /** "Fixed parameter CK" used in key expansion */
45
+ const CK = [
46
+ 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
47
+ 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
48
+ 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
49
+ 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
50
+ 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
51
+ 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
52
+ 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
53
+ 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
54
+ ];
55
+
56
+ /** "System parameter FK" */
57
+ const FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc];
58
+
59
+ /**
60
+ * Rotating 32-bit shift left
61
+ *
62
+ * (Note that although JS integers are stored in doubles and thus have 53 bits,
63
+ * the JS bitwise operations are 32-bit)
64
+ */
65
+ function ROL(i, n) {
66
+ return (i << n) | (i >>> (32 - n));
67
+ }
68
+
69
+ /**
70
+ * Linear transformation L
71
+ *
72
+ * @param {integer} b - a 32 bit integer
73
+ */
74
+ function transformL(b) {
75
+ /* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
76
+ b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
77
+ (Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
78
+ /* circular rotate and xor */
79
+ return b ^ ROL(b, 2) ^ ROL(b, 10) ^ ROL(b, 18) ^ ROL(b, 24);
80
+ }
81
+
82
+ /**
83
+ * Linear transformation L'
84
+ *
85
+ * @param {integer} b - a 32 bit integer
86
+ */
87
+ function transformLprime(b) {
88
+ /* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
89
+ b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
90
+ (Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
91
+ return b ^ ROL(b, 13) ^ ROL(b, 23); /* circular rotate and XOR */
92
+ }
93
+
94
+ /**
95
+ * Initialize the round key
96
+ */
97
+ function initSM4RoundKey(rawkey) {
98
+ const K = rawkey.map((a, i) => a ^ FK[i]); /* K = rawkey ^ FK */
99
+ const roundKey = [];
100
+ for (let i = 0; i < 32; i++)
101
+ roundKey[i] = K[i + 4] = K[i] ^ transformLprime(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]);
102
+ return roundKey;
103
+ }
104
+
105
+ /**
106
+ * Encrypts/decrypts a single block X (4 32-bit values) with a prepared round key.
107
+ *
108
+ * @param {intArray} X - A cleartext block.
109
+ * @param {intArray} roundKey - The round key from initSMRoundKey for encrypting (reversed for decrypting).
110
+ * @returns {byteArray} - The cipher text.
111
+ */
112
+ function encryptBlockSM4(X, roundKey) {
113
+ for (let i = 0; i < NROUNDS; i++)
114
+ X[i + 4] = X[i] ^ transformL(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ roundKey[i]);
115
+ return [X[35], X[34], X[33], X[32]];
116
+ }
117
+
118
+ /**
119
+ * Takes 16 bytes from an offset in an array and returns an array of 4 32-bit Big-Endian values.
120
+ * (DataView won't work portably here as we need Big-Endian)
121
+ *
122
+ * @param {byteArray} bArray - the array of bytes
123
+ * @param {integer} offset - starting offset in the array; 15 bytes must follow it.
124
+ */
125
+ function bytesToInts(bArray, offs=0) {
126
+ let offset = offs;
127
+ const A = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
128
+ offset += 4;
129
+ const B = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
130
+ offset += 4;
131
+ const C = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
132
+ offset += 4;
133
+ const D = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
134
+ return [A, B, C, D];
135
+ }
136
+
137
+ /**
138
+ * Inverse of bytesToInts above; takes an array of 32-bit integers and turns it into an array of bytes.
139
+ * Again, Big-Endian order.
140
+ */
141
+ function intsToBytes(ints) {
142
+ const bArr = [];
143
+ for (let i = 0; i < ints.length; i++) {
144
+ bArr.push((ints[i] >> 24) & 0xFF);
145
+ bArr.push((ints[i] >> 16) & 0xFF);
146
+ bArr.push((ints[i] >> 8) & 0xFF);
147
+ bArr.push(ints[i] & 0xFF);
148
+ }
149
+ return bArr;
150
+ }
151
+
152
+ /**
153
+ * Encrypt using SM4 using a given block cipher mode.
154
+ *
155
+ * @param {byteArray} message - The clear text message; any length under 32 Gb or so.
156
+ * @param {byteArray} key - The cipher key, 16 bytes.
157
+ * @param {byteArray} iv - The IV or nonce, 16 bytes (not used with ECB mode)
158
+ * @param {string} mode - The block cipher mode "CBC", "ECB", "CFB", "OFB", "CTR".
159
+ * @param {boolean} noPadding - Don't add PKCS#7 padding if set.
160
+ * @returns {byteArray} - The cipher text.
161
+ */
162
+ export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
163
+ const messageLength = message.length;
164
+ if (messageLength === 0)
165
+ return [];
166
+ const roundKey = initSM4RoundKey(bytesToInts(key, 0));
167
+
168
+ /* Pad with PKCS#7 if requested for ECB/CBC else add zeroes (which are sliced off at the end) */
169
+ let padByte = 0;
170
+ let nPadding = 16 - (message.length & 0xF);
171
+ if (mode === "ECB" || mode === "CBC") {
172
+ if (noPadding) {
173
+ if (nPadding !== 16)
174
+ throw new OperationError(`No padding requested in ${mode} mode but input is not a 16-byte multiple.`);
175
+ nPadding = 0;
176
+ } else
177
+ padByte = nPadding;
178
+ }
179
+ for (let i = 0; i < nPadding; i++)
180
+ message.push(padByte);
181
+
182
+ const cipherText = [];
183
+ switch (mode) {
184
+ case "ECB":
185
+ for (let i = 0; i < message.length; i += BLOCKSIZE)
186
+ Array.prototype.push.apply(cipherText, intsToBytes(encryptBlockSM4(bytesToInts(message, i), roundKey)));
187
+ break;
188
+ case "CBC":
189
+ iv = bytesToInts(iv, 0);
190
+ for (let i = 0; i < message.length; i += BLOCKSIZE) {
191
+ const block = bytesToInts(message, i);
192
+ block[0] ^= iv[0]; block[1] ^= iv[1];
193
+ block[2] ^= iv[2]; block[3] ^= iv[3];
194
+ iv = encryptBlockSM4(block, roundKey);
195
+ Array.prototype.push.apply(cipherText, intsToBytes(iv));
196
+ }
197
+ break;
198
+ case "CFB":
199
+ iv = bytesToInts(iv, 0);
200
+ for (let i = 0; i < message.length; i += BLOCKSIZE) {
201
+ iv = encryptBlockSM4(iv, roundKey);
202
+ const block = bytesToInts(message, i);
203
+ block[0] ^= iv[0]; block[1] ^= iv[1];
204
+ block[2] ^= iv[2]; block[3] ^= iv[3];
205
+ Array.prototype.push.apply(cipherText, intsToBytes(block));
206
+ iv = block;
207
+ }
208
+ break;
209
+ case "OFB":
210
+ iv = bytesToInts(iv, 0);
211
+ for (let i = 0; i < message.length; i += BLOCKSIZE) {
212
+ iv = encryptBlockSM4(iv, roundKey);
213
+ const block = bytesToInts(message, i);
214
+ block[0] ^= iv[0]; block[1] ^= iv[1];
215
+ block[2] ^= iv[2]; block[3] ^= iv[3];
216
+ Array.prototype.push.apply(cipherText, intsToBytes(block));
217
+ }
218
+ break;
219
+ case "CTR":
220
+ iv = bytesToInts(iv, 0);
221
+ for (let i = 0; i < message.length; i += BLOCKSIZE) {
222
+ let iv2 = [...iv]; /* containing the IV + counter */
223
+ iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
224
+ iv2 = encryptBlockSM4(iv2, roundKey);
225
+ const block = bytesToInts(message, i);
226
+ block[0] ^= iv2[0]; block[1] ^= iv2[1];
227
+ block[2] ^= iv2[2]; block[3] ^= iv2[3];
228
+ Array.prototype.push.apply(cipherText, intsToBytes(block));
229
+ }
230
+ break;
231
+ default:
232
+ throw new OperationError("Invalid block cipher mode: "+mode);
233
+ }
234
+ if (mode !== "ECB" && mode !== "CBC")
235
+ return cipherText.slice(0, messageLength);
236
+ return cipherText;
237
+ }
238
+
239
+ /**
240
+ * Decrypt using SM4 using a given block cipher mode.
241
+ *
242
+ * @param {byteArray} cipherText - The ciphertext
243
+ * @param {byteArray} key - The cipher key, 16 bytes.
244
+ * @param {byteArray} iv - The IV or nonce, 16 bytes (not used with ECB mode)
245
+ * @param {string} mode - The block cipher mode "CBC", "ECB", "CFB", "OFB", "CTR"
246
+ * @param {boolean] ignorePadding - If true, ignore padding issues in ECB/CBC mode.
247
+ * @returns {byteArray} - The cipher text.
248
+ */
249
+ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false) {
250
+ const originalLength = cipherText.length;
251
+ if (originalLength === 0)
252
+ return [];
253
+ let roundKey = initSM4RoundKey(bytesToInts(key, 0));
254
+
255
+ if (mode === "ECB" || mode === "CBC") {
256
+ /* Init decryption key */
257
+ roundKey = roundKey.reverse();
258
+ if ((originalLength & 0xF) !== 0 && !ignorePadding)
259
+ throw new OperationError(`With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${cipherText.length & 0xF} bytes extra)`);
260
+ } else { /* Pad dummy bytes for other modes, chop them off at the end */
261
+ while ((cipherText.length & 0xF) !== 0)
262
+ cipherText.push(0);
263
+ }
264
+
265
+ const clearText = [];
266
+ switch (mode) {
267
+ case "ECB":
268
+ for (let i = 0; i < cipherText.length; i += BLOCKSIZE)
269
+ Array.prototype.push.apply(clearText, intsToBytes(encryptBlockSM4(bytesToInts(cipherText, i), roundKey)));
270
+ break;
271
+ case "CBC":
272
+ iv = bytesToInts(iv, 0);
273
+ for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
274
+ const block = encryptBlockSM4(bytesToInts(cipherText, i), roundKey);
275
+ block[0] ^= iv[0]; block[1] ^= iv[1];
276
+ block[2] ^= iv[2]; block[3] ^= iv[3];
277
+ Array.prototype.push.apply(clearText, intsToBytes(block));
278
+ iv = bytesToInts(cipherText, i);
279
+ }
280
+ break;
281
+ case "CFB":
282
+ iv = bytesToInts(iv, 0);
283
+ for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
284
+ iv = encryptBlockSM4(iv, roundKey);
285
+ const block = bytesToInts(cipherText, i);
286
+ block[0] ^= iv[0]; block[1] ^= iv[1];
287
+ block[2] ^= iv[2]; block[3] ^= iv[3];
288
+ Array.prototype.push.apply(clearText, intsToBytes(block));
289
+ iv = bytesToInts(cipherText, i);
290
+ }
291
+ break;
292
+ case "OFB":
293
+ iv = bytesToInts(iv, 0);
294
+ for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
295
+ iv = encryptBlockSM4(iv, roundKey);
296
+ const block = bytesToInts(cipherText, i);
297
+ block[0] ^= iv[0]; block[1] ^= iv[1];
298
+ block[2] ^= iv[2]; block[3] ^= iv[3];
299
+ Array.prototype.push.apply(clearText, intsToBytes(block));
300
+ }
301
+ break;
302
+ case "CTR":
303
+ iv = bytesToInts(iv, 0);
304
+ for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
305
+ let iv2 = [...iv]; /* containing the IV + counter */
306
+ iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
307
+ iv2 = encryptBlockSM4(iv2, roundKey);
308
+ const block = bytesToInts(cipherText, i);
309
+ block[0] ^= iv2[0]; block[1] ^= iv2[1];
310
+ block[2] ^= iv2[2]; block[3] ^= iv2[3];
311
+ Array.prototype.push.apply(clearText, intsToBytes(block));
312
+ }
313
+ break;
314
+ default:
315
+ throw new OperationError(`Invalid block cipher mode: ${mode}`);
316
+ }
317
+ /* Check PKCS#7 padding */
318
+ if (mode === "ECB" || mode === "CBC") {
319
+ if (ignorePadding)
320
+ return clearText;
321
+ const padByte = clearText[clearText.length - 1];
322
+ if (padByte > 16)
323
+ throw new OperationError("Invalid PKCS#7 padding.");
324
+ for (let i = 0; i < padByte; i++)
325
+ if (clearText[clearText.length -i - 1] !== padByte)
326
+ throw new OperationError("Invalid PKCS#7 padding.");
327
+ return clearText.slice(0, clearText.length - padByte);
328
+ }
329
+ return clearText.slice(0, originalLength);
330
+ }
331
+