cyberchef 11.0.0 → 11.1.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 +144 -0
- package/Dockerfile +2 -2
- package/Gruntfile.js +10 -5
- package/README.md +3 -1
- package/SECURITY.md +8 -18
- package/package.json +35 -34
- package/src/core/config/Categories.json +6 -0
- package/src/core/config/OperationConfig.json +140 -16
- package/src/core/config/modules/Default.mjs +8 -0
- package/src/core/config/modules/PGP.mjs +2 -0
- package/src/core/config/scripts/generateOpsIndex.mjs +63 -0
- package/src/core/config/scripts/newOperation.mjs +31 -4
- package/src/core/operations/AESDecrypt.mjs +61 -16
- package/src/core/operations/AESEncrypt.mjs +26 -11
- package/src/core/operations/BLAKE3.mjs +13 -7
- package/src/core/operations/BSONDeserialise.mjs +2 -2
- package/src/core/operations/BSONSerialise.mjs +3 -2
- package/src/core/operations/Bcrypt.mjs +1 -1
- package/src/core/operations/BcryptCompare.mjs +1 -1
- package/src/core/operations/DecodeText.mjs +4 -0
- package/src/core/operations/EncodeText.mjs +4 -0
- package/src/core/operations/EscapeSmartCharacters.mjs +129 -0
- package/src/core/operations/GenerateLoremIpsum.mjs +34 -3
- package/src/core/operations/GeneratePGPKeyPair.mjs +8 -7
- package/src/core/operations/PGPSign.mjs +83 -0
- package/src/core/operations/ParseEthernetFrame.mjs +1 -1
- package/src/core/operations/ParseIPv4Header.mjs +1 -1
- package/src/core/operations/ParseObjectIDTimestamp.mjs +2 -2
- package/src/core/operations/ParseUserAgent.mjs +1 -1
- package/src/core/operations/ROR13.mjs +83 -0
- package/src/core/operations/RemoveANSIEscapeCodes.mjs +41 -0
- package/src/core/operations/SeriesChart.mjs +16 -0
- package/src/core/operations/Wrap.mjs +47 -0
- package/src/core/operations/index.mjs +10 -0
- package/src/node/index.mjs +25 -0
- package/src/web/App.mjs +19 -1
- package/src/web/HTMLIngredient.mjs +1 -0
- package/src/web/html/index.html +3 -3
- package/src/web/static/sitemap.mjs +3 -3
- package/src/web/waiters/RecipeWaiter.mjs +9 -1
- package/tests/browser/02_ops.js +7 -7
- package/tests/browser/03_recipe_load.js +48 -0
- package/tests/browser/browserUtils.js +6 -3
- package/tests/node/index.mjs +1 -0
- package/tests/node/tests/PGP.mjs +69 -0
- package/tests/node/tests/operations.mjs +41 -2
- package/tests/operations/index.mjs +71 -66
- package/tests/operations/tests/BLAKE3.mjs +18 -0
- package/tests/operations/tests/CharEnc.mjs +26 -0
- package/tests/operations/tests/Charts.mjs +11 -0
- package/tests/operations/tests/Crypt.mjs +288 -62
- package/tests/operations/tests/EscapeSmartCharacters.mjs +132 -0
- package/tests/operations/tests/FlaskSession.mjs +11 -8
- package/tests/operations/tests/GenerateLoremIpsum.mjs +80 -0
- package/tests/operations/tests/IPv6Transition.mjs +4 -4
- package/tests/operations/tests/PGP.mjs +178 -154
- package/tests/operations/tests/ParseEthernetFrame.mjs +11 -0
- package/tests/operations/tests/ParseIPv4Header.mjs +23 -0
- package/tests/operations/tests/ParseX509CRL.mjs +16 -16
- package/tests/operations/tests/ROR13.mjs +45 -0
- package/tests/operations/tests/Register.mjs +3 -1
- package/tests/operations/tests/RemoveANSIEscapeCodes.mjs +62 -0
- package/tests/operations/tests/Wrap.mjs +44 -0
|
@@ -144,6 +144,11 @@
|
|
|
144
144
|
"Base64"
|
|
145
145
|
]
|
|
146
146
|
},
|
|
147
|
+
{
|
|
148
|
+
"name": "IV Length",
|
|
149
|
+
"type": "number",
|
|
150
|
+
"value": 16
|
|
151
|
+
},
|
|
147
152
|
{
|
|
148
153
|
"name": "Mode",
|
|
149
154
|
"type": "argSelector",
|
|
@@ -151,57 +156,57 @@
|
|
|
151
156
|
{
|
|
152
157
|
"name": "CBC",
|
|
153
158
|
"off": [
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
6,
|
|
160
|
+
7
|
|
156
161
|
]
|
|
157
162
|
},
|
|
158
163
|
{
|
|
159
164
|
"name": "CFB",
|
|
160
165
|
"off": [
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
6,
|
|
167
|
+
7
|
|
163
168
|
]
|
|
164
169
|
},
|
|
165
170
|
{
|
|
166
171
|
"name": "OFB",
|
|
167
172
|
"off": [
|
|
168
|
-
|
|
169
|
-
|
|
173
|
+
6,
|
|
174
|
+
7
|
|
170
175
|
]
|
|
171
176
|
},
|
|
172
177
|
{
|
|
173
178
|
"name": "CTR",
|
|
174
179
|
"off": [
|
|
175
|
-
|
|
176
|
-
|
|
180
|
+
6,
|
|
181
|
+
7
|
|
177
182
|
]
|
|
178
183
|
},
|
|
179
184
|
{
|
|
180
185
|
"name": "GCM",
|
|
181
186
|
"on": [
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
6,
|
|
188
|
+
7
|
|
184
189
|
]
|
|
185
190
|
},
|
|
186
191
|
{
|
|
187
192
|
"name": "ECB",
|
|
188
193
|
"off": [
|
|
189
|
-
|
|
190
|
-
|
|
194
|
+
6,
|
|
195
|
+
7
|
|
191
196
|
]
|
|
192
197
|
},
|
|
193
198
|
{
|
|
194
199
|
"name": "CBC/NoPadding",
|
|
195
200
|
"off": [
|
|
196
|
-
|
|
197
|
-
|
|
201
|
+
6,
|
|
202
|
+
7
|
|
198
203
|
]
|
|
199
204
|
},
|
|
200
205
|
{
|
|
201
206
|
"name": "ECB/NoPadding",
|
|
202
207
|
"off": [
|
|
203
|
-
|
|
204
|
-
|
|
208
|
+
6,
|
|
209
|
+
7
|
|
205
210
|
]
|
|
206
211
|
}
|
|
207
212
|
]
|
|
@@ -243,6 +248,39 @@
|
|
|
243
248
|
"Latin1",
|
|
244
249
|
"Base64"
|
|
245
250
|
]
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"name": "IV from input",
|
|
254
|
+
"type": "argSelector",
|
|
255
|
+
"value": [
|
|
256
|
+
{
|
|
257
|
+
"name": "Off",
|
|
258
|
+
"on": [
|
|
259
|
+
1
|
|
260
|
+
],
|
|
261
|
+
"off": [
|
|
262
|
+
2
|
|
263
|
+
]
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"name": "From start",
|
|
267
|
+
"on": [
|
|
268
|
+
2
|
|
269
|
+
],
|
|
270
|
+
"off": [
|
|
271
|
+
1
|
|
272
|
+
]
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"name": "From end",
|
|
276
|
+
"on": [
|
|
277
|
+
2
|
|
278
|
+
],
|
|
279
|
+
"off": [
|
|
280
|
+
1
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
]
|
|
246
284
|
}
|
|
247
285
|
]
|
|
248
286
|
},
|
|
@@ -357,6 +395,15 @@
|
|
|
357
395
|
"Latin1",
|
|
358
396
|
"Base64"
|
|
359
397
|
]
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
"name": "Include IV in output",
|
|
401
|
+
"type": "option",
|
|
402
|
+
"value": [
|
|
403
|
+
"Off",
|
|
404
|
+
"Prepend",
|
|
405
|
+
"Append"
|
|
406
|
+
]
|
|
360
407
|
}
|
|
361
408
|
]
|
|
362
409
|
},
|
|
@@ -7552,6 +7599,26 @@
|
|
|
7552
7599
|
}
|
|
7553
7600
|
]
|
|
7554
7601
|
},
|
|
7602
|
+
"Escape Smart Characters": {
|
|
7603
|
+
"module": "Default",
|
|
7604
|
+
"description": "Converts smart (typographic) Unicode characters — e.g. smart quotes, em/en dashes, ellipses, ©, ®, ™, arrows — into their plain ASCII equivalents.<br><br>Characters with no ASCII mapping (e.g. <code>☣</code>) are handled according to the 'Unmappable characters' option.<br><br>e.g. <code>“Hello” — world…</code> becomes <code>\"Hello\" -- world...</code>",
|
|
7605
|
+
"infoURL": "",
|
|
7606
|
+
"inputType": "string",
|
|
7607
|
+
"outputType": "string",
|
|
7608
|
+
"flowControl": false,
|
|
7609
|
+
"manualBake": false,
|
|
7610
|
+
"args": [
|
|
7611
|
+
{
|
|
7612
|
+
"name": "Unmappable characters",
|
|
7613
|
+
"type": "option",
|
|
7614
|
+
"value": [
|
|
7615
|
+
"Include",
|
|
7616
|
+
"Remove",
|
|
7617
|
+
"Replace with '.'"
|
|
7618
|
+
]
|
|
7619
|
+
}
|
|
7620
|
+
]
|
|
7621
|
+
},
|
|
7555
7622
|
"Escape string": {
|
|
7556
7623
|
"module": "Default",
|
|
7557
7624
|
"description": "Escapes special characters in a string so that they do not cause conflicts. For example, <code>Don't stop me now</code> becomes <code>Don\\'t stop me now</code>.<br><br>Supports the following escape sequences:<ul><li><code>\\n</code> (Line feed/newline)</li><li><code>\\r</code> (Carriage return)</li><li><code>\\t</code> (Horizontal tab)</li><li><code>\\b</code> (Backspace)</li><li><code>\\f</code> (Form feed)</li><li><code>\\xnn</code> (Hex, where n is 0-f)</li><li><code>\\\\</code> (Backslash)</li><li><code>\\'</code> (Single quote)</li><li><code>\\"</code> (Double quote)</li><li><code>\\unnnn</code> (Unicode character)</li><li><code>\\u{nnnnnn}</code> (Unicode code point)</li></ul>",
|
|
@@ -13143,6 +13210,27 @@
|
|
|
13143
13210
|
}
|
|
13144
13211
|
]
|
|
13145
13212
|
},
|
|
13213
|
+
"PGP Sign": {
|
|
13214
|
+
"module": "PGP",
|
|
13215
|
+
"description": "Input: the message you want to sign\n<br><br>\nArguments: the ASCII-armoured PGP private key of the sender.\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.",
|
|
13216
|
+
"infoURL": "https://wikipedia.org/wiki/Pretty_Good_Privacy",
|
|
13217
|
+
"inputType": "string",
|
|
13218
|
+
"outputType": "string",
|
|
13219
|
+
"flowControl": false,
|
|
13220
|
+
"manualBake": false,
|
|
13221
|
+
"args": [
|
|
13222
|
+
{
|
|
13223
|
+
"name": "Private key of signer",
|
|
13224
|
+
"type": "text",
|
|
13225
|
+
"value": ""
|
|
13226
|
+
},
|
|
13227
|
+
{
|
|
13228
|
+
"name": "Private key passphrase (optional)",
|
|
13229
|
+
"type": "string",
|
|
13230
|
+
"value": ""
|
|
13231
|
+
}
|
|
13232
|
+
]
|
|
13233
|
+
},
|
|
13146
13234
|
"PGP Verify": {
|
|
13147
13235
|
"module": "PGP",
|
|
13148
13236
|
"description": "Input: the ASCII-armoured encrypted PGP message you want to verify.\n<br><br>\nArgument: the ASCII-armoured PGP public key of the signer\n<br><br>\nThis operation uses PGP to decrypt a clearsigned message.\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.",
|
|
@@ -14918,6 +15006,16 @@
|
|
|
14918
15006
|
}
|
|
14919
15007
|
]
|
|
14920
15008
|
},
|
|
15009
|
+
"ROR13": {
|
|
15010
|
+
"module": "Default",
|
|
15011
|
+
"description": "Computes a ROR13 hash used in API hashing techniques.",
|
|
15012
|
+
"infoURL": "",
|
|
15013
|
+
"inputType": "byteArray",
|
|
15014
|
+
"outputType": "string",
|
|
15015
|
+
"flowControl": false,
|
|
15016
|
+
"manualBake": false,
|
|
15017
|
+
"args": []
|
|
15018
|
+
},
|
|
14921
15019
|
"ROT13": {
|
|
14922
15020
|
"module": "Default",
|
|
14923
15021
|
"description": "A simple caesar substitution cipher which rotates alphabet characters by the specified amount (default 13).",
|
|
@@ -15574,6 +15672,16 @@
|
|
|
15574
15672
|
}
|
|
15575
15673
|
]
|
|
15576
15674
|
},
|
|
15675
|
+
"Remove ANSI Escape Codes": {
|
|
15676
|
+
"module": "Default",
|
|
15677
|
+
"description": "Removes ANSI Escape Codes.",
|
|
15678
|
+
"infoURL": "https://wikipedia.org/wiki/ANSI_escape_code",
|
|
15679
|
+
"inputType": "string",
|
|
15680
|
+
"outputType": "string",
|
|
15681
|
+
"flowControl": false,
|
|
15682
|
+
"manualBake": false,
|
|
15683
|
+
"args": []
|
|
15684
|
+
},
|
|
15577
15685
|
"Remove Diacritics": {
|
|
15578
15686
|
"module": "Default",
|
|
15579
15687
|
"description": "Replaces accented characters with their latin character equivalent. Accented characters are made up of Unicode combining characters, so unicode text formatting such as strikethroughs and underlines will also be removed.",
|
|
@@ -21895,6 +22003,22 @@
|
|
|
21895
22003
|
}
|
|
21896
22004
|
]
|
|
21897
22005
|
},
|
|
22006
|
+
"Wrap": {
|
|
22007
|
+
"module": "Default",
|
|
22008
|
+
"description": "Wraps the input text at a specified number of characters per line.",
|
|
22009
|
+
"infoURL": null,
|
|
22010
|
+
"inputType": "string",
|
|
22011
|
+
"outputType": "string",
|
|
22012
|
+
"flowControl": false,
|
|
22013
|
+
"manualBake": false,
|
|
22014
|
+
"args": [
|
|
22015
|
+
{
|
|
22016
|
+
"name": "Line Width",
|
|
22017
|
+
"type": "number",
|
|
22018
|
+
"value": 64
|
|
22019
|
+
}
|
|
22020
|
+
]
|
|
22021
|
+
},
|
|
21898
22022
|
"XKCD Random Number": {
|
|
21899
22023
|
"module": "Default",
|
|
21900
22024
|
"description": "RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.",
|
|
@@ -41,6 +41,7 @@ import DropBytes from "../../operations/DropBytes.mjs";
|
|
|
41
41
|
import DropNthBytes from "../../operations/DropNthBytes.mjs";
|
|
42
42
|
import ELFInfo from "../../operations/ELFInfo.mjs";
|
|
43
43
|
import EncodeNetBIOSName from "../../operations/EncodeNetBIOSName.mjs";
|
|
44
|
+
import EscapeSmartCharacters from "../../operations/EscapeSmartCharacters.mjs";
|
|
44
45
|
import EscapeString from "../../operations/EscapeString.mjs";
|
|
45
46
|
import EscapeUnicodeCharacters from "../../operations/EscapeUnicodeCharacters.mjs";
|
|
46
47
|
import ExpandAlphabetRange from "../../operations/ExpandAlphabetRange.mjs";
|
|
@@ -131,11 +132,13 @@ import ParseUNIXFilePermissions from "../../operations/ParseUNIXFilePermissions.
|
|
|
131
132
|
import PlayMedia from "../../operations/PlayMedia.mjs";
|
|
132
133
|
import PowerSet from "../../operations/PowerSet.mjs";
|
|
133
134
|
import RAKE from "../../operations/RAKE.mjs";
|
|
135
|
+
import ROR13 from "../../operations/ROR13.mjs";
|
|
134
136
|
import ROT13 from "../../operations/ROT13.mjs";
|
|
135
137
|
import ROT13BruteForce from "../../operations/ROT13BruteForce.mjs";
|
|
136
138
|
import ROT47 from "../../operations/ROT47.mjs";
|
|
137
139
|
import ROT47BruteForce from "../../operations/ROT47BruteForce.mjs";
|
|
138
140
|
import ROT8000 from "../../operations/ROT8000.mjs";
|
|
141
|
+
import RemoveANSIEscapeCodes from "../../operations/RemoveANSIEscapeCodes.mjs";
|
|
139
142
|
import RemoveDiacritics from "../../operations/RemoveDiacritics.mjs";
|
|
140
143
|
import RemoveLineNumbers from "../../operations/RemoveLineNumbers.mjs";
|
|
141
144
|
import RemoveNullBytes from "../../operations/RemoveNullBytes.mjs";
|
|
@@ -207,6 +210,7 @@ import Unique from "../../operations/Unique.mjs";
|
|
|
207
210
|
import VarIntDecode from "../../operations/VarIntDecode.mjs";
|
|
208
211
|
import VarIntEncode from "../../operations/VarIntEncode.mjs";
|
|
209
212
|
import WindowsFiletimeToUNIXTimestamp from "../../operations/WindowsFiletimeToUNIXTimestamp.mjs";
|
|
213
|
+
import Wrap from "../../operations/Wrap.mjs";
|
|
210
214
|
import XKCDRandomNumber from "../../operations/XKCDRandomNumber.mjs";
|
|
211
215
|
import XOR from "../../operations/XOR.mjs";
|
|
212
216
|
import XORBruteForce from "../../operations/XORBruteForce.mjs";
|
|
@@ -251,6 +255,7 @@ OpModules.Default = {
|
|
|
251
255
|
"Drop nth bytes": DropNthBytes,
|
|
252
256
|
"ELF Info": ELFInfo,
|
|
253
257
|
"Encode NetBIOS Name": EncodeNetBIOSName,
|
|
258
|
+
"Escape Smart Characters": EscapeSmartCharacters,
|
|
254
259
|
"Escape string": EscapeString,
|
|
255
260
|
"Escape Unicode Characters": EscapeUnicodeCharacters,
|
|
256
261
|
"Expand alphabet range": ExpandAlphabetRange,
|
|
@@ -341,11 +346,13 @@ OpModules.Default = {
|
|
|
341
346
|
"Play Media": PlayMedia,
|
|
342
347
|
"Power Set": PowerSet,
|
|
343
348
|
"RAKE": RAKE,
|
|
349
|
+
"ROR13": ROR13,
|
|
344
350
|
"ROT13": ROT13,
|
|
345
351
|
"ROT13 Brute Force": ROT13BruteForce,
|
|
346
352
|
"ROT47": ROT47,
|
|
347
353
|
"ROT47 Brute Force": ROT47BruteForce,
|
|
348
354
|
"ROT8000": ROT8000,
|
|
355
|
+
"Remove ANSI Escape Codes": RemoveANSIEscapeCodes,
|
|
349
356
|
"Remove Diacritics": RemoveDiacritics,
|
|
350
357
|
"Remove line numbers": RemoveLineNumbers,
|
|
351
358
|
"Remove null bytes": RemoveNullBytes,
|
|
@@ -417,6 +424,7 @@ OpModules.Default = {
|
|
|
417
424
|
"VarInt Decode": VarIntDecode,
|
|
418
425
|
"VarInt Encode": VarIntEncode,
|
|
419
426
|
"Windows Filetime to UNIX Timestamp": WindowsFiletimeToUNIXTimestamp,
|
|
427
|
+
"Wrap": Wrap,
|
|
420
428
|
"XKCD Random Number": XKCDRandomNumber,
|
|
421
429
|
"XOR": XOR,
|
|
422
430
|
"XOR Brute Force": XORBruteForce,
|
|
@@ -10,6 +10,7 @@ import PGPDecrypt from "../../operations/PGPDecrypt.mjs";
|
|
|
10
10
|
import PGPDecryptAndVerify from "../../operations/PGPDecryptAndVerify.mjs";
|
|
11
11
|
import PGPEncrypt from "../../operations/PGPEncrypt.mjs";
|
|
12
12
|
import PGPEncryptAndSign from "../../operations/PGPEncryptAndSign.mjs";
|
|
13
|
+
import PGPSign from "../../operations/PGPSign.mjs";
|
|
13
14
|
import PGPVerify from "../../operations/PGPVerify.mjs";
|
|
14
15
|
|
|
15
16
|
const OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
|
@@ -20,6 +21,7 @@ OpModules.PGP = {
|
|
|
20
21
|
"PGP Decrypt and Verify": PGPDecryptAndVerify,
|
|
21
22
|
"PGP Encrypt": PGPEncrypt,
|
|
22
23
|
"PGP Encrypt and Sign": PGPEncryptAndSign,
|
|
24
|
+
"PGP Sign": PGPSign,
|
|
23
25
|
"PGP Verify": PGPVerify,
|
|
24
26
|
};
|
|
25
27
|
|
|
@@ -58,3 +58,66 @@ fs.writeFileSync(
|
|
|
58
58
|
code
|
|
59
59
|
);
|
|
60
60
|
console.log("Written operation index.");
|
|
61
|
+
|
|
62
|
+
// find all test files
|
|
63
|
+
const testsDir = path.join(process.cwd() + "/tests/operations/tests/");
|
|
64
|
+
const testObjs = [];
|
|
65
|
+
fs.readdirSync(testsDir).forEach(file => {
|
|
66
|
+
if (!file.endsWith(".mjs")) return;
|
|
67
|
+
testObjs.push(file.split(".mjs")[0]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Construct test index file
|
|
71
|
+
code = `/**
|
|
72
|
+
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
|
|
73
|
+
*
|
|
74
|
+
* @author john [john19696@protonmail.com]
|
|
75
|
+
* @author tlwr [toby@toby.codes]
|
|
76
|
+
* @author n1474335 [n1474335@gmail.com]
|
|
77
|
+
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
|
|
78
|
+
* @license Apache-2.0
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
import {
|
|
82
|
+
setLongTestFailure,
|
|
83
|
+
logTestReport,
|
|
84
|
+
} from "../lib/utils.mjs";
|
|
85
|
+
|
|
86
|
+
import "../lib/wasmFetchPolyfill.mjs";
|
|
87
|
+
|
|
88
|
+
import TestRegister from "../lib/TestRegister.mjs";
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
testObjs.forEach(obj => {
|
|
92
|
+
if (obj !== "SplitColourChannels")
|
|
93
|
+
code += `import "./tests/${obj}.mjs";\n`;
|
|
94
|
+
else
|
|
95
|
+
code += `// Cannot test operations that use the File type yet
|
|
96
|
+
// import "./tests/SplitColourChannels.mjs";\n`;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
code += `
|
|
100
|
+
|
|
101
|
+
const testStatus = {
|
|
102
|
+
allTestsPassing: true,
|
|
103
|
+
counts: {
|
|
104
|
+
total: 0,
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
setLongTestFailure();
|
|
109
|
+
|
|
110
|
+
const logOpsTestReport = logTestReport.bind(null, testStatus);
|
|
111
|
+
|
|
112
|
+
(async function() {
|
|
113
|
+
const results = await TestRegister.runTests();
|
|
114
|
+
logOpsTestReport(results);
|
|
115
|
+
})();
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
// Write tests file
|
|
119
|
+
fs.writeFileSync(
|
|
120
|
+
path.join(testsDir, "../index.mjs"),
|
|
121
|
+
code
|
|
122
|
+
);
|
|
123
|
+
console.log("Written operation tests index.");
|
|
@@ -23,7 +23,7 @@ if (!fs.existsSync(dir)) {
|
|
|
23
23
|
console.log("Example> node --experimental-modules src/core/config/scripts/newOperation.mjs");
|
|
24
24
|
process.exit(1);
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
const testDir = path.join(process.cwd() + "/tests/operations/tests/");
|
|
27
27
|
const ioTypes = ["string", "byteArray", "number", "html", "ArrayBuffer", "BigNumber", "JSON", "File", "List<File>"];
|
|
28
28
|
|
|
29
29
|
const schema = {
|
|
@@ -123,6 +123,30 @@ prompt.get(schema, (err, result) => {
|
|
|
123
123
|
return txt.charAt(0).toUpperCase() + txt.substr(1);
|
|
124
124
|
}).replace(/[\s-()./]/g, "");
|
|
125
125
|
|
|
126
|
+
const testTemplate = `/**
|
|
127
|
+
* ${moduleName} tests
|
|
128
|
+
*
|
|
129
|
+
* @author ${result.authorName} [${result.authorEmail}]
|
|
130
|
+
* @copyright Crown Copyright ${(new Date()).getFullYear()}
|
|
131
|
+
* @license Apache-2.0
|
|
132
|
+
*/
|
|
133
|
+
|
|
134
|
+
import TestRegister from "../../lib/TestRegister.mjs";
|
|
135
|
+
|
|
136
|
+
TestRegister.addTests([
|
|
137
|
+
{
|
|
138
|
+
name: "${result.opName}: test",
|
|
139
|
+
input: "Example input",
|
|
140
|
+
expectedOutput: "Expected output",
|
|
141
|
+
recipeConfig: [
|
|
142
|
+
{
|
|
143
|
+
op: "${result.opName}",
|
|
144
|
+
args: [],
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
149
|
+
`;
|
|
126
150
|
|
|
127
151
|
const template = `/**
|
|
128
152
|
* @author ${result.authorName} [${result.authorEmail}]
|
|
@@ -218,13 +242,16 @@ export default ${moduleName};
|
|
|
218
242
|
}
|
|
219
243
|
fs.writeFileSync(filename, template);
|
|
220
244
|
|
|
245
|
+
const testFilename = path.join(testDir, `./${moduleName}.mjs`);
|
|
246
|
+
fs.writeFileSync(testFilename, testTemplate);
|
|
247
|
+
|
|
221
248
|
console.log(`\nOperation template written to ${colors.green(filename)}`);
|
|
249
|
+
console.log(`\nOperation test template written to ${colors.green(testFilename)}`);
|
|
222
250
|
console.log(`\nNext steps:
|
|
223
251
|
1. Add your operation to ${colors.green("src/core/config/Categories.json")}
|
|
224
|
-
2. Write your operation code.
|
|
225
|
-
3. Write
|
|
252
|
+
2. Write your operation code in ${colors.green(filename)}
|
|
253
|
+
3. Write your operation test code in ${colors.green(testFilename)}
|
|
226
254
|
4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
|
|
227
255
|
5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);
|
|
228
256
|
|
|
229
257
|
});
|
|
230
|
-
|
|
@@ -39,41 +39,46 @@ class AESDecrypt extends Operation {
|
|
|
39
39
|
"value": "",
|
|
40
40
|
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
"name": "IV Length",
|
|
44
|
+
"type": "number",
|
|
45
|
+
"value": 16
|
|
46
|
+
},
|
|
42
47
|
{
|
|
43
48
|
"name": "Mode",
|
|
44
49
|
"type": "argSelector",
|
|
45
50
|
"value": [
|
|
46
51
|
{
|
|
47
52
|
name: "CBC",
|
|
48
|
-
off: [
|
|
53
|
+
off: [6, 7]
|
|
49
54
|
},
|
|
50
55
|
{
|
|
51
56
|
name: "CFB",
|
|
52
|
-
off: [
|
|
57
|
+
off: [6, 7]
|
|
53
58
|
},
|
|
54
59
|
{
|
|
55
60
|
name: "OFB",
|
|
56
|
-
off: [
|
|
61
|
+
off: [6, 7]
|
|
57
62
|
},
|
|
58
63
|
{
|
|
59
64
|
name: "CTR",
|
|
60
|
-
off: [
|
|
65
|
+
off: [6, 7]
|
|
61
66
|
},
|
|
62
67
|
{
|
|
63
68
|
name: "GCM",
|
|
64
|
-
on: [
|
|
69
|
+
on: [6, 7]
|
|
65
70
|
},
|
|
66
71
|
{
|
|
67
72
|
name: "ECB",
|
|
68
|
-
off: [
|
|
73
|
+
off: [6, 7]
|
|
69
74
|
},
|
|
70
75
|
{
|
|
71
76
|
name: "CBC/NoPadding",
|
|
72
|
-
off: [
|
|
77
|
+
off: [6, 7]
|
|
73
78
|
},
|
|
74
79
|
{
|
|
75
80
|
name: "ECB/NoPadding",
|
|
76
|
-
off: [
|
|
81
|
+
off: [6, 7]
|
|
77
82
|
}
|
|
78
83
|
]
|
|
79
84
|
},
|
|
@@ -98,6 +103,26 @@ class AESDecrypt extends Operation {
|
|
|
98
103
|
"type": "toggleString",
|
|
99
104
|
"value": "",
|
|
100
105
|
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"name": "IV from input",
|
|
109
|
+
"type": "argSelector",
|
|
110
|
+
"value": [
|
|
111
|
+
{
|
|
112
|
+
name: "Off",
|
|
113
|
+
on: [1],
|
|
114
|
+
off: [2]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "From start",
|
|
118
|
+
on: [2],
|
|
119
|
+
off: [1]
|
|
120
|
+
}, {
|
|
121
|
+
name: "From end",
|
|
122
|
+
on: [2],
|
|
123
|
+
off: [1]
|
|
124
|
+
}
|
|
125
|
+
]
|
|
101
126
|
}
|
|
102
127
|
];
|
|
103
128
|
}
|
|
@@ -110,14 +135,18 @@ class AESDecrypt extends Operation {
|
|
|
110
135
|
* @throws {OperationError} if cannot decrypt input or invalid key length
|
|
111
136
|
*/
|
|
112
137
|
run(input, args) {
|
|
138
|
+
let iv;
|
|
139
|
+
|
|
113
140
|
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
|
114
|
-
|
|
115
|
-
mode = args[
|
|
116
|
-
noPadding = args[
|
|
117
|
-
inputType = args[
|
|
118
|
-
outputType = args[
|
|
119
|
-
gcmTag = Utils.convertToByteString(args[
|
|
120
|
-
aad = Utils.convertToByteString(args[
|
|
141
|
+
ivLength = args[2],
|
|
142
|
+
mode = args[3].split("/")[0],
|
|
143
|
+
noPadding = args[3].endsWith("NoPadding"),
|
|
144
|
+
inputType = args[4],
|
|
145
|
+
outputType = args[5],
|
|
146
|
+
gcmTag = Utils.convertToByteString(args[6].string, args[6].option),
|
|
147
|
+
aad = Utils.convertToByteString(args[7].string, args[7].option),
|
|
148
|
+
ivFromInput = args[8];
|
|
149
|
+
|
|
121
150
|
|
|
122
151
|
if ([16, 24, 32].indexOf(key.length) < 0) {
|
|
123
152
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
|
@@ -130,11 +159,27 @@ The following algorithms will be used based on the size of the key:
|
|
|
130
159
|
|
|
131
160
|
input = Utils.convertToByteString(input, inputType);
|
|
132
161
|
|
|
162
|
+
if (ivFromInput !== "Off") {
|
|
163
|
+
if (input.length <= ivLength) {
|
|
164
|
+
throw new OperationError(`Input is too short to contain an IV of ${ivLength} bytes.`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (ivFromInput === "From start") {
|
|
168
|
+
iv = input.substr(0, ivLength);
|
|
169
|
+
input = input.substr(ivLength);
|
|
170
|
+
} else {
|
|
171
|
+
iv = input.substr(input.length - ivLength);
|
|
172
|
+
input = input.substr(0, input.length - ivLength);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
iv = Utils.convertToByteString(args[1].string, args[1].option);
|
|
176
|
+
}
|
|
177
|
+
|
|
133
178
|
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
|
|
134
179
|
|
|
135
180
|
/* Allow for a "no padding" mode */
|
|
136
181
|
if (noPadding) {
|
|
137
|
-
decipher.mode.unpad = function(output, options) {
|
|
182
|
+
decipher.mode.unpad = function (output, options) {
|
|
138
183
|
return true;
|
|
139
184
|
};
|
|
140
185
|
}
|
|
@@ -8,6 +8,7 @@ import Operation from "../Operation.mjs";
|
|
|
8
8
|
import Utils from "../Utils.mjs";
|
|
9
9
|
import forge from "node-forge";
|
|
10
10
|
import OperationError from "../errors/OperationError.mjs";
|
|
11
|
+
import { toHexFast } from "../lib/Hex.mjs";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* AES Encrypt operation
|
|
@@ -92,6 +93,11 @@ class AESEncrypt extends Operation {
|
|
|
92
93
|
"type": "toggleString",
|
|
93
94
|
"value": "",
|
|
94
95
|
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "Include IV in output",
|
|
99
|
+
"type": "option",
|
|
100
|
+
"value": ["Off", "Prepend", "Append"]
|
|
95
101
|
}
|
|
96
102
|
];
|
|
97
103
|
}
|
|
@@ -107,10 +113,11 @@ class AESEncrypt extends Operation {
|
|
|
107
113
|
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
|
108
114
|
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
|
109
115
|
mode = args[2].split("/")[0],
|
|
110
|
-
noPadding =
|
|
116
|
+
noPadding = args[2].endsWith("NoPadding"),
|
|
111
117
|
inputType = args[3],
|
|
112
118
|
outputType = args[4],
|
|
113
|
-
aad = Utils.convertToByteString(args[5].string, args[5].option)
|
|
119
|
+
aad = Utils.convertToByteString(args[5].string, args[5].option),
|
|
120
|
+
includeIV = args[6];
|
|
114
121
|
|
|
115
122
|
if ([16, 24, 32].indexOf(key.length) < 0) {
|
|
116
123
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
|
@@ -133,26 +140,34 @@ The following algorithms will be used based on the size of the key:
|
|
|
133
140
|
additionalData: mode === "GCM" ? aad : undefined
|
|
134
141
|
});
|
|
135
142
|
if (noPadding) {
|
|
136
|
-
cipher.mode.pad = function(output, options) {
|
|
143
|
+
cipher.mode.pad = function (output, options) {
|
|
137
144
|
return true;
|
|
138
145
|
};
|
|
139
146
|
}
|
|
140
147
|
cipher.update(forge.util.createBuffer(input));
|
|
141
148
|
cipher.finish();
|
|
142
149
|
|
|
150
|
+
let output = cipher.output.getBytes();
|
|
151
|
+
|
|
152
|
+
if (includeIV === "Prepend") {
|
|
153
|
+
output = iv + output;
|
|
154
|
+
} else if (includeIV === "Append") {
|
|
155
|
+
output = output + iv;
|
|
156
|
+
}
|
|
157
|
+
|
|
143
158
|
if (outputType === "Hex") {
|
|
159
|
+
output = toHexFast(Utils.strToByteArray(output));
|
|
160
|
+
|
|
144
161
|
if (mode === "GCM") {
|
|
145
|
-
return
|
|
162
|
+
return output + "\n\n" +
|
|
146
163
|
"Tag: " + cipher.mode.tag.toHex();
|
|
147
164
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return cipher.output.getBytes() + "\n\n" +
|
|
152
|
-
"Tag: " + cipher.mode.tag.getBytes();
|
|
153
|
-
}
|
|
154
|
-
return cipher.output.getBytes();
|
|
165
|
+
} else if (mode === "GCM") {
|
|
166
|
+
return output + "\n\n" +
|
|
167
|
+
"Tag: " + cipher.mode.tag.getBytes();
|
|
155
168
|
}
|
|
169
|
+
|
|
170
|
+
return output;
|
|
156
171
|
}
|
|
157
172
|
|
|
158
173
|
}
|