cyberchef 9.36.1 → 9.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberchef",
3
- "version": "9.36.1",
3
+ "version": "9.37.0",
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",
@@ -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
  {
@@ -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
+
@@ -22,7 +22,7 @@ class AESDecrypt extends Operation {
22
22
 
23
23
  this.name = "AES Decrypt";
24
24
  this.module = "Ciphers";
25
- this.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.";
25
+ this.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.";
26
26
  this.infoURL = "https://wikipedia.org/wiki/Advanced_Encryption_Standard";
27
27
  this.inputType = "string";
28
28
  this.outputType = "string";
@@ -66,6 +66,14 @@ class AESDecrypt extends Operation {
66
66
  {
67
67
  name: "ECB",
68
68
  off: [5, 6]
69
+ },
70
+ {
71
+ name: "CBC/NoPadding",
72
+ off: [5, 6]
73
+ },
74
+ {
75
+ name: "ECB/NoPadding",
76
+ off: [5, 6]
69
77
  }
70
78
  ]
71
79
  },
@@ -104,7 +112,8 @@ class AESDecrypt extends Operation {
104
112
  run(input, args) {
105
113
  const key = Utils.convertToByteString(args[0].string, args[0].option),
106
114
  iv = Utils.convertToByteString(args[1].string, args[1].option),
107
- mode = args[2],
115
+ mode = args[2].substring(0, 3),
116
+ noPadding = args[2].endsWith("NoPadding"),
108
117
  inputType = args[3],
109
118
  outputType = args[4],
110
119
  gcmTag = Utils.convertToByteString(args[5].string, args[5].option),
@@ -122,6 +131,14 @@ The following algorithms will be used based on the size of the key:
122
131
  input = Utils.convertToByteString(input, inputType);
123
132
 
124
133
  const decipher = forge.cipher.createDecipher("AES-" + mode, key);
134
+
135
+ /* Allow for a "no padding" mode */
136
+ if (noPadding) {
137
+ decipher.mode.unpad = function(output, options) {
138
+ return true;
139
+ };
140
+ }
141
+
125
142
  decipher.start({
126
143
  iv: iv.length === 0 ? "" : iv,
127
144
  tag: mode === "GCM" ? gcmTag : undefined,
@@ -22,7 +22,7 @@ class DESDecrypt extends Operation {
22
22
 
23
23
  this.name = "DES Decrypt";
24
24
  this.module = "Ciphers";
25
- this.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.";
25
+ this.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.";
26
26
  this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
27
27
  this.inputType = "string";
28
28
  this.outputType = "string";
@@ -42,7 +42,7 @@ class DESDecrypt extends Operation {
42
42
  {
43
43
  "name": "Mode",
44
44
  "type": "option",
45
- "value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
45
+ "value": ["CBC", "CFB", "OFB", "CTR", "ECB", "CBC/NoPadding", "ECB/NoPadding"]
46
46
  },
47
47
  {
48
48
  "name": "Input",
@@ -65,7 +65,9 @@ class DESDecrypt extends Operation {
65
65
  run(input, args) {
66
66
  const key = Utils.convertToByteString(args[0].string, args[0].option),
67
67
  iv = Utils.convertToByteArray(args[1].string, args[1].option),
68
- [,, mode, inputType, outputType] = args;
68
+ mode = args[2].substring(0, 3),
69
+ noPadding = args[2].endsWith("NoPadding"),
70
+ [,,, inputType, outputType] = args;
69
71
 
70
72
  if (key.length !== 8) {
71
73
  throw new OperationError(`Invalid key length: ${key.length} bytes
@@ -83,6 +85,14 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
83
85
  input = Utils.convertToByteString(input, inputType);
84
86
 
85
87
  const decipher = forge.cipher.createDecipher("DES-" + mode, key);
88
+
89
+ /* Allow for a "no padding" mode */
90
+ if (noPadding) {
91
+ decipher.mode.unpad = function(output, options) {
92
+ return true;
93
+ };
94
+ }
95
+
86
96
  decipher.start({iv: iv});
87
97
  decipher.update(forge.util.createBuffer(input));
88
98
  const result = decipher.finish();
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @author swesven
3
+ * @copyright 2021
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import Utils from "../Utils.mjs";
9
+ import OperationError from "../errors/OperationError.mjs";
10
+ import { toHex } from "../lib/Hex.mjs";
11
+ import { decryptSM4 } from "../lib/SM4.mjs";
12
+
13
+ /**
14
+ * SM4 Decrypt operation
15
+ */
16
+ class SM4Decrypt extends Operation {
17
+
18
+ /**
19
+ * SM4Encrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "SM4 Decrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "SM4 is a 128-bit block cipher, currently established as a national standard (GB/T 32907-2016) of China.";
27
+ this.infoURL = "https://wikipedia.org/wiki/SM4_(cipher)";
28
+ this.inputType = "string";
29
+ this.outputType = "string";
30
+ this.args = [
31
+ {
32
+ "name": "Key",
33
+ "type": "toggleString",
34
+ "value": "",
35
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
36
+ },
37
+ {
38
+ "name": "IV",
39
+ "type": "toggleString",
40
+ "value": "",
41
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
42
+ },
43
+ {
44
+ "name": "Mode",
45
+ "type": "option",
46
+ "value": ["CBC", "CFB", "OFB", "CTR", "ECB", "CBC/NoPadding", "ECB/NoPadding"]
47
+ },
48
+ {
49
+ "name": "Input",
50
+ "type": "option",
51
+ "value": ["Raw", "Hex"]
52
+ },
53
+ {
54
+ "name": "Output",
55
+ "type": "option",
56
+ "value": ["Hex", "Raw"]
57
+ }
58
+ ];
59
+ }
60
+
61
+ /**
62
+ * @param {string} input
63
+ * @param {Object[]} args
64
+ * @returns {string}
65
+ */
66
+ run(input, args) {
67
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
68
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
69
+ [,, mode, inputType, outputType] = args;
70
+
71
+ if (key.length !== 16)
72
+ throw new OperationError(`Invalid key length: ${key.length} bytes
73
+
74
+ SM4 uses a key length of 16 bytes (128 bits).`);
75
+ if (iv.length !== 16 && !mode.startsWith("ECB"))
76
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
77
+
78
+ SM4 uses an IV length of 16 bytes (128 bits).
79
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
80
+
81
+ input = Utils.convertToByteArray(input, inputType);
82
+ const output = decryptSM4(input, key, iv, mode.substring(0, 3), mode.endsWith("NoPadding"));
83
+ return outputType === "Hex" ? toHex(output) : Utils.byteArrayToUtf8(output);
84
+ }
85
+
86
+ }
87
+
88
+ export default SM4Decrypt;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @author swesven
3
+ * @copyright 2021
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import Utils from "../Utils.mjs";
9
+ import OperationError from "../errors/OperationError.mjs";
10
+ import { toHex } from "../lib/Hex.mjs";
11
+ import { encryptSM4 } from "../lib/SM4.mjs";
12
+
13
+ /**
14
+ * SM4 Encrypt operation
15
+ */
16
+ class SM4Encrypt extends Operation {
17
+
18
+ /**
19
+ * SM4Encrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "SM4 Encrypt";
25
+ this.module = "Ciphers";
26
+ this.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.";
27
+ this.infoURL = "https://wikipedia.org/wiki/SM4_(cipher)";
28
+ this.inputType = "string";
29
+ this.outputType = "string";
30
+ this.args = [
31
+ {
32
+ "name": "Key",
33
+ "type": "toggleString",
34
+ "value": "",
35
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
36
+ },
37
+ {
38
+ "name": "IV",
39
+ "type": "toggleString",
40
+ "value": "",
41
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
42
+ },
43
+ {
44
+ "name": "Mode",
45
+ "type": "option",
46
+ "value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
47
+ },
48
+ {
49
+ "name": "Input",
50
+ "type": "option",
51
+ "value": ["Raw", "Hex"]
52
+ },
53
+ {
54
+ "name": "Output",
55
+ "type": "option",
56
+ "value": ["Hex", "Raw"]
57
+ }
58
+ ];
59
+ }
60
+
61
+ /**
62
+ * @param {string} input
63
+ * @param {Object[]} args
64
+ * @returns {string}
65
+ */
66
+ run(input, args) {
67
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
68
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
69
+ [,, mode, inputType, outputType] = args;
70
+
71
+ if (key.length !== 16)
72
+ throw new OperationError(`Invalid key length: ${key.length} bytes
73
+
74
+ SM4 uses a key length of 16 bytes (128 bits).`);
75
+ if (iv.length !== 16 && !mode.startsWith("ECB"))
76
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
77
+
78
+ SM4 uses an IV length of 16 bytes (128 bits).
79
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
80
+
81
+ input = Utils.convertToByteArray(input, inputType);
82
+ const output = encryptSM4(input, key, iv, mode.substring(0, 3), mode.endsWith("NoPadding"));
83
+ return outputType === "Hex" ? toHex(output) : Utils.byteArrayToUtf8(output);
84
+ }
85
+
86
+ }
87
+
88
+ export default SM4Encrypt;
@@ -22,7 +22,7 @@ class TripleDESDecrypt extends Operation {
22
22
 
23
23
  this.name = "Triple DES Decrypt";
24
24
  this.module = "Ciphers";
25
- this.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.";
25
+ this.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.";
26
26
  this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
27
27
  this.inputType = "string";
28
28
  this.outputType = "string";
@@ -42,7 +42,7 @@ class TripleDESDecrypt extends Operation {
42
42
  {
43
43
  "name": "Mode",
44
44
  "type": "option",
45
- "value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
45
+ "value": ["CBC", "CFB", "OFB", "CTR", "ECB", "CBC/NoPadding", "ECB/NoPadding"]
46
46
  },
47
47
  {
48
48
  "name": "Input",
@@ -65,7 +65,8 @@ class TripleDESDecrypt extends Operation {
65
65
  run(input, args) {
66
66
  const key = Utils.convertToByteString(args[0].string, args[0].option),
67
67
  iv = Utils.convertToByteArray(args[1].string, args[1].option),
68
- mode = args[2],
68
+ mode = args[2].substring(0, 3),
69
+ noPadding = args[2].endsWith("NoPadding"),
69
70
  inputType = args[3],
70
71
  outputType = args[4];
71
72
 
@@ -85,6 +86,14 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
85
86
  input = Utils.convertToByteString(input, inputType);
86
87
 
87
88
  const decipher = forge.cipher.createDecipher("3DES-" + mode, key);
89
+
90
+ /* Allow for a "no padding" mode */
91
+ if (noPadding) {
92
+ decipher.mode.unpad = function(output, options) {
93
+ return true;
94
+ };
95
+ }
96
+
88
97
  decipher.start({iv: iv});
89
98
  decipher.update(forge.util.createBuffer(input));
90
99
  const result = decipher.finish();
@@ -277,6 +277,8 @@ import SHA2 from "./SHA2.mjs";
277
277
  import SHA3 from "./SHA3.mjs";
278
278
  import SIGABA from "./SIGABA.mjs";
279
279
  import SM3 from "./SM3.mjs";
280
+ import SM4Decrypt from "./SM4Decrypt.mjs";
281
+ import SM4Encrypt from "./SM4Encrypt.mjs";
280
282
  import SQLBeautify from "./SQLBeautify.mjs";
281
283
  import SQLMinify from "./SQLMinify.mjs";
282
284
  import SSDEEP from "./SSDEEP.mjs";
@@ -647,6 +649,8 @@ export {
647
649
  SHA3,
648
650
  SIGABA,
649
651
  SM3,
652
+ SM4Decrypt,
653
+ SM4Encrypt,
650
654
  SQLBeautify,
651
655
  SQLMinify,
652
656
  SSDEEP,
@@ -278,6 +278,8 @@ import {
278
278
  SHA3 as core_SHA3,
279
279
  SIGABA as core_SIGABA,
280
280
  SM3 as core_SM3,
281
+ SM4Decrypt as core_SM4Decrypt,
282
+ SM4Encrypt as core_SM4Encrypt,
281
283
  SQLBeautify as core_SQLBeautify,
282
284
  SQLMinify as core_SQLMinify,
283
285
  SSDEEP as core_SSDEEP,
@@ -648,6 +650,8 @@ function generateChef() {
648
650
  "SHA3": _wrap(core_SHA3),
649
651
  "SIGABA": _wrap(core_SIGABA),
650
652
  "SM3": _wrap(core_SM3),
653
+ "SM4Decrypt": _wrap(core_SM4Decrypt),
654
+ "SM4Encrypt": _wrap(core_SM4Encrypt),
651
655
  "SQLBeautify": _wrap(core_SQLBeautify),
652
656
  "SQLMinify": _wrap(core_SQLMinify),
653
657
  "SSDEEP": _wrap(core_SSDEEP),
@@ -1035,6 +1039,8 @@ const SHA2 = chef.SHA2;
1035
1039
  const SHA3 = chef.SHA3;
1036
1040
  const SIGABA = chef.SIGABA;
1037
1041
  const SM3 = chef.SM3;
1042
+ const SM4Decrypt = chef.SM4Decrypt;
1043
+ const SM4Encrypt = chef.SM4Encrypt;
1038
1044
  const SQLBeautify = chef.SQLBeautify;
1039
1045
  const SQLMinify = chef.SQLMinify;
1040
1046
  const SSDEEP = chef.SSDEEP;
@@ -1407,6 +1413,8 @@ const operations = [
1407
1413
  SHA3,
1408
1414
  SIGABA,
1409
1415
  SM3,
1416
+ SM4Decrypt,
1417
+ SM4Encrypt,
1410
1418
  SQLBeautify,
1411
1419
  SQLMinify,
1412
1420
  SSDEEP,
@@ -1783,6 +1791,8 @@ export {
1783
1791
  SHA3,
1784
1792
  SIGABA,
1785
1793
  SM3,
1794
+ SM4Decrypt,
1795
+ SM4Encrypt,
1786
1796
  SQLBeautify,
1787
1797
  SQLMinify,
1788
1798
  SSDEEP,
@@ -119,7 +119,7 @@ TestRegister.addApiTests([
119
119
  assert.strictEqual(result[0].module, "Ciphers");
120
120
  assert.strictEqual(result[0].inputType, "string");
121
121
  assert.strictEqual(result[0].outputType, "string");
122
- assert.strictEqual(result[0].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.");
122
+ assert.strictEqual(result[0].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.");
123
123
  assert.strictEqual(result[0].args.length, 5);
124
124
  }),
125
125
 
@@ -75,6 +75,7 @@ import "./tests/SeqUtils.mjs";
75
75
  import "./tests/SetDifference.mjs";
76
76
  import "./tests/SetIntersection.mjs";
77
77
  import "./tests/SetUnion.mjs";
78
+ import "./tests/SM4.mjs";
78
79
  import "./tests/StrUtils.mjs";
79
80
  import "./tests/SymmetricDifference.mjs";
80
81
  import "./tests/TextEncodingBruteForce.mjs";
@@ -0,0 +1,279 @@
1
+ /**
2
+ * SM4 crypto tests.
3
+ *
4
+ * Test data used from IETF draft-ribose-cfrg-sm4-09, see:
5
+ * https://tools.ietf.org/id/draft-ribose-cfrg-sm4-09.html
6
+ *
7
+ * @author swesven
8
+ * @copyright 2021
9
+ * @license Apache-2.0
10
+ */
11
+ import TestRegister from "../../lib/TestRegister.mjs";
12
+
13
+ /* Cleartexts */
14
+ const TWO_BLOCK_PLAIN = "aa aa aa aa bb bb bb bb cc cc cc cc dd dd dd dd ee ee ee ee ff ff ff ff aa aa aa aa bb bb bb bb";
15
+ const FOUR_BLOCK_PLAIN = "aa aa aa aa aa aa aa aa bb bb bb bb bb bb bb bb cc cc cc cc cc cc cc cc dd dd dd dd dd dd dd dd ee ee ee ee ee ee ee ee ff ff ff ff ff ff ff ff aa aa aa aa aa aa aa aa bb bb bb bb bb bb bb bb";
16
+ /* Keys */
17
+ const KEY_1 = "01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10";
18
+ const KEY_2 = "fe dc ba 98 76 54 32 10 01 23 45 67 89 ab cd ef";
19
+ /* IV */
20
+ const IV = "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f";
21
+ /* Ciphertexts */
22
+ const ECB_1 = "5e c8 14 3d e5 09 cf f7 b5 17 9f 8f 47 4b 86 19 2f 1d 30 5a 7f b1 7d f9 85 f8 1c 84 82 19 23 04";
23
+ const ECB_2 = "c5 87 68 97 e4 a5 9b bb a7 2a 10 c8 38 72 24 5b 12 dd 90 bc 2d 20 06 92 b5 29 a4 15 5a c9 e6 00";
24
+ /* With PKCS#7 padding */
25
+ const ECB_1P ="5e c8 14 3d e5 09 cf f7 b5 17 9f 8f 47 4b 86 19 2f 1d 30 5a 7f b1 7d f9 85 f8 1c 84 82 19 23 04 00 2a 8a 4e fa 86 3c ca d0 24 ac 03 00 bb 40 d2";
26
+ const ECB_2P= "c5 87 68 97 e4 a5 9b bb a7 2a 10 c8 38 72 24 5b 12 dd 90 bc 2d 20 06 92 b5 29 a4 15 5a c9 e6 00 a2 51 49 20 93 f8 f6 42 89 b7 8d 6e 8a 28 b1 c6";
27
+ const CBC_1 = "78 eb b1 1c c4 0b 0a 48 31 2a ae b2 04 02 44 cb 4c b7 01 69 51 90 92 26 97 9b 0d 15 dc 6a 8f 6d";
28
+ const CBC_2 = "0d 3a 6d dc 2d 21 c6 98 85 72 15 58 7b 7b b5 9a 91 f2 c1 47 91 1a 41 44 66 5e 1f a1 d4 0b ae 38";
29
+ const OFB_1 = "ac 32 36 cb 86 1d d3 16 e6 41 3b 4e 3c 75 24 b7 1d 01 ac a2 48 7c a5 82 cb f5 46 3e 66 98 53 9b";
30
+ const OFB_2 = "5d cc cd 25 a8 4b a1 65 60 d7 f2 65 88 70 68 49 33 fa 16 bd 5c d9 c8 56 ca ca a1 e1 01 89 7a 97";
31
+ const CFB_1 = "ac 32 36 cb 86 1d d3 16 e6 41 3b 4e 3c 75 24 b7 69 d4 c5 4e d4 33 b9 a0 34 60 09 be b3 7b 2b 3f";
32
+ const CFB_2 = "5d cc cd 25 a8 4b a1 65 60 d7 f2 65 88 70 68 49 0d 9b 86 ff 20 c3 bf e1 15 ff a0 2c a6 19 2c c5";
33
+ const CTR_1 = "ac 32 36 cb 97 0c c2 07 91 36 4c 39 5a 13 42 d1 a3 cb c1 87 8c 6f 30 cd 07 4c ce 38 5c dd 70 c7 f2 34 bc 0e 24 c1 19 80 fd 12 86 31 0c e3 7b 92 6e 02 fc d0 fa a0 ba f3 8b 29 33 85 1d 82 45 14";
34
+ const CTR_2 = "5d cc cd 25 b9 5a b0 74 17 a0 85 12 ee 16 0e 2f 8f 66 15 21 cb ba b4 4c c8 71 38 44 5b c2 9e 5c 0a e0 29 72 05 d6 27 04 17 3b 21 23 9b 88 7f 6c 8c b5 b8 00 91 7a 24 88 28 4b de 9e 16 ea 29 06";
35
+
36
+ TestRegister.addTests([
37
+ {
38
+ name: "SM4 Encrypt: ECB 1, No padding",
39
+ input: TWO_BLOCK_PLAIN,
40
+ expectedOutput: ECB_1,
41
+ recipeConfig: [
42
+ {
43
+ "op": "SM4 Encrypt",
44
+ "args": [{string: KEY_1, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ name: "SM4 Encrypt: ECB 2, No padding",
50
+ input: TWO_BLOCK_PLAIN,
51
+ expectedOutput: ECB_2,
52
+ recipeConfig: [
53
+ {
54
+ "op": "SM4 Encrypt",
55
+ "args": [{string: KEY_2, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ name: "SM4 Encrypt: ECB 1, With padding",
61
+ input: TWO_BLOCK_PLAIN,
62
+ expectedOutput: ECB_1P,
63
+ recipeConfig: [
64
+ {
65
+ "op": "SM4 Encrypt",
66
+ "args": [{string: KEY_1, option: "Hex"}, {string: "", option: "Hex"}, "ECB", "Hex", "Hex"]
67
+ }
68
+ ]
69
+ },
70
+ {
71
+ name: "SM4 Encrypt: ECB 2, With padding",
72
+ input: TWO_BLOCK_PLAIN,
73
+ expectedOutput: ECB_2P,
74
+ recipeConfig: [
75
+ {
76
+ "op": "SM4 Encrypt",
77
+ "args": [{string: KEY_2, option: "Hex"}, {string: "", option: "Hex"}, "ECB", "Hex", "Hex"]
78
+ }
79
+ ]
80
+ },
81
+ {
82
+ name: "SM4 Encrypt: CBC 1",
83
+ input: TWO_BLOCK_PLAIN,
84
+ expectedOutput: CBC_1,
85
+ recipeConfig: [
86
+ {
87
+ "op": "SM4 Encrypt",
88
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
89
+ }
90
+ ]
91
+ },
92
+ {
93
+ name: "SM4 Encrypt: CBC 2",
94
+ input: TWO_BLOCK_PLAIN,
95
+ expectedOutput: CBC_2,
96
+ recipeConfig: [
97
+ {
98
+ "op": "SM4 Encrypt",
99
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
100
+ }
101
+ ]
102
+ },
103
+ {
104
+ name: "SM4 Encrypt: OFB1",
105
+ input: TWO_BLOCK_PLAIN,
106
+ expectedOutput: OFB_1,
107
+ recipeConfig: [
108
+ {
109
+ "op": "SM4 Encrypt",
110
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ name: "SM4 Encrypt: OFB2",
116
+ input: TWO_BLOCK_PLAIN,
117
+ expectedOutput: OFB_2,
118
+ recipeConfig: [
119
+ {
120
+ "op": "SM4 Encrypt",
121
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
122
+ }
123
+ ]
124
+ },
125
+ {
126
+ name: "SM4 Encrypt: CFB1",
127
+ input: TWO_BLOCK_PLAIN,
128
+ expectedOutput: CFB_1,
129
+ recipeConfig: [
130
+ {
131
+ "op": "SM4 Encrypt",
132
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
133
+ }
134
+ ]
135
+ },
136
+ {
137
+ name: "SM4 Encrypt: CFB2",
138
+ input: TWO_BLOCK_PLAIN,
139
+ expectedOutput: CFB_2,
140
+ recipeConfig: [
141
+ {
142
+ "op": "SM4 Encrypt",
143
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
144
+ }
145
+ ]
146
+ },
147
+ {
148
+ name: "SM4 Encrypt: CTR1",
149
+ input: FOUR_BLOCK_PLAIN,
150
+ expectedOutput: CTR_1,
151
+ recipeConfig: [
152
+ {
153
+ "op": "SM4 Encrypt",
154
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
155
+ }
156
+ ]
157
+ },
158
+ {
159
+ name: "SM4 Encrypt: CTR1",
160
+ input: FOUR_BLOCK_PLAIN,
161
+ expectedOutput: CTR_2,
162
+ recipeConfig: [
163
+ {
164
+ "op": "SM4 Encrypt",
165
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
166
+ }
167
+ ]
168
+ },
169
+ {
170
+ name: "SM4 Decrypt: ECB 1",
171
+ input: ECB_1,
172
+ expectedOutput: TWO_BLOCK_PLAIN,
173
+ recipeConfig: [
174
+ {
175
+ "op": "SM4 Decrypt",
176
+ "args": [{string: KEY_1, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
177
+ }
178
+ ]
179
+ },
180
+ {
181
+ name: "SM4 Decrypt: ECB 2",
182
+ input: ECB_2,
183
+ expectedOutput: TWO_BLOCK_PLAIN,
184
+ recipeConfig: [
185
+ {
186
+ "op": "SM4 Decrypt",
187
+ "args": [{string: KEY_2, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
188
+ }
189
+ ]
190
+ },
191
+ {
192
+ name: "SM4 Decrypt: CBC 1",
193
+ input: CBC_1,
194
+ expectedOutput: TWO_BLOCK_PLAIN,
195
+ recipeConfig: [
196
+ {
197
+ "op": "SM4 Decrypt",
198
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
199
+ }
200
+ ]
201
+ },
202
+ {
203
+ name: "SM4 Decrypt: CBC 2",
204
+ input: CBC_2,
205
+ expectedOutput: TWO_BLOCK_PLAIN,
206
+ recipeConfig: [
207
+ {
208
+ "op": "SM4 Decrypt",
209
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
210
+ }
211
+ ]
212
+ },
213
+ {
214
+ name: "SM4 Decrypt: OFB1",
215
+ input: TWO_BLOCK_PLAIN,
216
+ expectedOutput: OFB_1,
217
+ recipeConfig: [
218
+ {
219
+ "op": "SM4 Decrypt",
220
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
221
+ }
222
+ ]
223
+ },
224
+ {
225
+ name: "SM4 Decrypt: OFB2",
226
+ input: OFB_2,
227
+ expectedOutput: TWO_BLOCK_PLAIN,
228
+ recipeConfig: [
229
+ {
230
+ "op": "SM4 Decrypt",
231
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
232
+ }
233
+ ]
234
+ },
235
+ {
236
+ name: "SM4 Decrypt: CFB1",
237
+ input: CFB_1,
238
+ expectedOutput: TWO_BLOCK_PLAIN,
239
+ recipeConfig: [
240
+ {
241
+ "op": "SM4 Decrypt",
242
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
243
+ }
244
+ ]
245
+ },
246
+ {
247
+ name: "SM4 Decrypt: CFB2",
248
+ input: CFB_2,
249
+ expectedOutput: TWO_BLOCK_PLAIN,
250
+ recipeConfig: [
251
+ {
252
+ "op": "SM4 Decrypt",
253
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
254
+ }
255
+ ]
256
+ },
257
+ {
258
+ name: "SM4 Decrypt: CTR1",
259
+ input: CTR_1,
260
+ expectedOutput: FOUR_BLOCK_PLAIN,
261
+ recipeConfig: [
262
+ {
263
+ "op": "SM4 Decrypt",
264
+ "args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
265
+ }
266
+ ]
267
+ },
268
+ {
269
+ name: "SM4 Decrypt: CTR1",
270
+ input: CTR_2,
271
+ expectedOutput: FOUR_BLOCK_PLAIN,
272
+ recipeConfig: [
273
+ {
274
+ "op": "SM4 Decrypt",
275
+ "args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
276
+ }
277
+ ]
278
+ },
279
+ ]);