cyberchef 9.39.6 → 9.42.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,12 @@ All major and minor version changes will be documented in this file. Details of
13
13
 
14
14
  ## Details
15
15
 
16
+ ### [9.41.0] - 2022-07-08
17
+ - Added 'Caesar Box Cipher' operation [@n1073645] | [#1066]
18
+
19
+ ### [9.40.0] - 2022-07-08
20
+ - Added 'P-list Viewer' operation [@n1073645] | [#906]
21
+
16
22
  ### [9.39.0] - 2022-06-09
17
23
  - Added 'ELF Info' operation [@n1073645] | [#1364]
18
24
 
@@ -294,6 +300,8 @@ All major and minor version changes will be documented in this file. Details of
294
300
 
295
301
 
296
302
 
303
+ [9.41.0]: https://github.com/gchq/CyberChef/releases/tag/v9.41.0
304
+ [9.40.0]: https://github.com/gchq/CyberChef/releases/tag/v9.40.0
297
305
  [9.39.0]: https://github.com/gchq/CyberChef/releases/tag/v9.39.0
298
306
  [9.38.0]: https://github.com/gchq/CyberChef/releases/tag/v9.38.0
299
307
  [9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0
@@ -491,6 +499,7 @@ All major and minor version changes will be documented in this file. Details of
491
499
  [#674]: https://github.com/gchq/CyberChef/pull/674
492
500
  [#683]: https://github.com/gchq/CyberChef/pull/683
493
501
  [#865]: https://github.com/gchq/CyberChef/pull/865
502
+ [#906]: https://github.com/gchq/CyberChef/pull/906
494
503
  [#912]: https://github.com/gchq/CyberChef/pull/912
495
504
  [#917]: https://github.com/gchq/CyberChef/pull/917
496
505
  [#934]: https://github.com/gchq/CyberChef/pull/934
@@ -506,6 +515,7 @@ All major and minor version changes will be documented in this file. Details of
506
515
  [#1045]: https://github.com/gchq/CyberChef/pull/1045
507
516
  [#1049]: https://github.com/gchq/CyberChef/pull/1049
508
517
  [#1065]: https://github.com/gchq/CyberChef/pull/1065
518
+ [#1066]: https://github.com/gchq/CyberChef/pull/1066
509
519
  [#1083]: https://github.com/gchq/CyberChef/pull/1083
510
520
  [#1189]: https://github.com/gchq/CyberChef/pull/1189
511
521
  [#1242]: https://github.com/gchq/CyberChef/pull/1242
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberchef",
3
- "version": "9.39.6",
3
+ "version": "9.42.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",
@@ -79,6 +79,8 @@
79
79
  "DES Decrypt",
80
80
  "Triple DES Encrypt",
81
81
  "Triple DES Decrypt",
82
+ "LS47 Encrypt",
83
+ "LS47 Decrypt",
82
84
  "RC2 Encrypt",
83
85
  "RC2 Decrypt",
84
86
  "RC4",
@@ -97,6 +99,7 @@
97
99
  "Bacon Cipher Decode",
98
100
  "Bifid Cipher Encode",
99
101
  "Bifid Cipher Decode",
102
+ "Caesar Box Cipher",
100
103
  "Affine Cipher Encode",
101
104
  "Affine Cipher Decode",
102
105
  "A1Z26 Cipher Encode",
@@ -457,6 +460,7 @@
457
460
  "Frequency distribution",
458
461
  "Index of Coincidence",
459
462
  "Chi Square",
463
+ "P-list Viewer",
460
464
  "Disassemble x86",
461
465
  "Pseudo-Random Number Generator",
462
466
  "Generate UUID",
@@ -1469,6 +1469,22 @@
1469
1469
  "manualBake": false,
1470
1470
  "args": []
1471
1471
  },
1472
+ "Caesar Box Cipher": {
1473
+ "module": "Ciphers",
1474
+ "description": "Caesar Box is a transposition cipher used in the Roman Empire, in which letters of the message are written in rows in a square (or a rectangle) and then, read by column.",
1475
+ "infoURL": "https://www.dcode.fr/caesar-box-cipher",
1476
+ "inputType": "string",
1477
+ "outputType": "string",
1478
+ "flowControl": false,
1479
+ "manualBake": false,
1480
+ "args": [
1481
+ {
1482
+ "name": "Box Height",
1483
+ "type": "number",
1484
+ "value": 1
1485
+ }
1486
+ ]
1487
+ },
1472
1488
  "Cartesian Product": {
1473
1489
  "module": "Default",
1474
1490
  "description": "Calculates the cartesian product of multiple sets of data, returning all possible combinations.",
@@ -7918,6 +7934,53 @@
7918
7934
  }
7919
7935
  ]
7920
7936
  },
7937
+ "LS47 Decrypt": {
7938
+ "module": "Crypto",
7939
+ "description": "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.<br>The LS47 alphabet consists of following characters: <code>_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()</code><br>An LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption.",
7940
+ "infoURL": "https://github.com/exaexa/ls47",
7941
+ "inputType": "string",
7942
+ "outputType": "string",
7943
+ "flowControl": false,
7944
+ "manualBake": false,
7945
+ "args": [
7946
+ {
7947
+ "name": "Password",
7948
+ "type": "string",
7949
+ "value": ""
7950
+ },
7951
+ {
7952
+ "name": "Padding",
7953
+ "type": "number",
7954
+ "value": 10
7955
+ }
7956
+ ]
7957
+ },
7958
+ "LS47 Encrypt": {
7959
+ "module": "Crypto",
7960
+ "description": "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.<br>The LS47 alphabet consists of following characters: <code>_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()</code><br>A LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption.",
7961
+ "infoURL": "https://github.com/exaexa/ls47",
7962
+ "inputType": "string",
7963
+ "outputType": "string",
7964
+ "flowControl": false,
7965
+ "manualBake": false,
7966
+ "args": [
7967
+ {
7968
+ "name": "Password",
7969
+ "type": "string",
7970
+ "value": ""
7971
+ },
7972
+ {
7973
+ "name": "Padding",
7974
+ "type": "number",
7975
+ "value": 10
7976
+ },
7977
+ {
7978
+ "name": "Signature",
7979
+ "type": "string",
7980
+ "value": ""
7981
+ }
7982
+ ]
7983
+ },
7921
7984
  "Label": {
7922
7985
  "module": "Default",
7923
7986
  "description": "Provides a location for conditional and fixed jumps to redirect execution to.",
@@ -8770,6 +8833,16 @@
8770
8833
  }
8771
8834
  ]
8772
8835
  },
8836
+ "P-list Viewer": {
8837
+ "module": "Default",
8838
+ "description": "In the macOS, iOS, NeXTSTEP, and GNUstep programming frameworks, property list files are files that store serialized objects. Property list files use the filename extension .plist, and thus are often referred to as p-list files.<br><br>This operation displays plist files in a human readable format.",
8839
+ "infoURL": "https://wikipedia.org/wiki/Property_list",
8840
+ "inputType": "string",
8841
+ "outputType": "string",
8842
+ "flowControl": false,
8843
+ "manualBake": false,
8844
+ "args": []
8845
+ },
8773
8846
  "Pad lines": {
8774
8847
  "module": "Default",
8775
8848
  "description": "Add the specified number of the specified character to the beginning or end of each line",
@@ -12947,7 +13020,7 @@
12947
13020
  },
12948
13021
  "Subsection": {
12949
13022
  "module": "Default",
12950
- "description": "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.<br><br>You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on.",
13023
+ "description": "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.<br><br>You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on.<br><br>Use the Merge operation to reset the effects of subsection.",
12951
13024
  "infoURL": "",
12952
13025
  "inputType": "string",
12953
13026
  "outputType": "string",
@@ -16,6 +16,7 @@ import BifidCipherDecode from "../../operations/BifidCipherDecode.mjs";
16
16
  import BifidCipherEncode from "../../operations/BifidCipherEncode.mjs";
17
17
  import BlowfishDecrypt from "../../operations/BlowfishDecrypt.mjs";
18
18
  import BlowfishEncrypt from "../../operations/BlowfishEncrypt.mjs";
19
+ import CaesarBoxCipher from "../../operations/CaesarBoxCipher.mjs";
19
20
  import DESDecrypt from "../../operations/DESDecrypt.mjs";
20
21
  import DESEncrypt from "../../operations/DESEncrypt.mjs";
21
22
  import DeriveEVPKey from "../../operations/DeriveEVPKey.mjs";
@@ -53,6 +54,7 @@ OpModules.Ciphers = {
53
54
  "Bifid Cipher Encode": BifidCipherEncode,
54
55
  "Blowfish Decrypt": BlowfishDecrypt,
55
56
  "Blowfish Encrypt": BlowfishEncrypt,
57
+ "Caesar Box Cipher": CaesarBoxCipher,
56
58
  "DES Decrypt": DESDecrypt,
57
59
  "DES Encrypt": DESEncrypt,
58
60
  "Derive EVP key": DeriveEVPKey,
@@ -34,6 +34,8 @@ import JWTDecode from "../../operations/JWTDecode.mjs";
34
34
  import JWTSign from "../../operations/JWTSign.mjs";
35
35
  import JWTVerify from "../../operations/JWTVerify.mjs";
36
36
  import Keccak from "../../operations/Keccak.mjs";
37
+ import LS47Decrypt from "../../operations/LS47Decrypt.mjs";
38
+ import LS47Encrypt from "../../operations/LS47Encrypt.mjs";
37
39
  import MD2 from "../../operations/MD2.mjs";
38
40
  import MD4 from "../../operations/MD4.mjs";
39
41
  import MD5 from "../../operations/MD5.mjs";
@@ -83,6 +85,8 @@ OpModules.Crypto = {
83
85
  "JWT Sign": JWTSign,
84
86
  "JWT Verify": JWTVerify,
85
87
  "Keccak": Keccak,
88
+ "LS47 Decrypt": LS47Decrypt,
89
+ "LS47 Encrypt": LS47Encrypt,
86
90
  "MD2": MD2,
87
91
  "MD4": MD4,
88
92
  "MD5": MD5,
@@ -92,6 +92,7 @@ import OR from "../../operations/OR.mjs";
92
92
  import OffsetChecker from "../../operations/OffsetChecker.mjs";
93
93
  import PEMToHex from "../../operations/PEMToHex.mjs";
94
94
  import PHPDeserialize from "../../operations/PHPDeserialize.mjs";
95
+ import PLISTViewer from "../../operations/PLISTViewer.mjs";
95
96
  import PadLines from "../../operations/PadLines.mjs";
96
97
  import ParseColourCode from "../../operations/ParseColourCode.mjs";
97
98
  import ParseDateTime from "../../operations/ParseDateTime.mjs";
@@ -261,6 +262,7 @@ OpModules.Default = {
261
262
  "Offset checker": OffsetChecker,
262
263
  "PEM to Hex": PEMToHex,
263
264
  "PHP Deserialize": PHPDeserialize,
265
+ "P-list Viewer": PLISTViewer,
264
266
  "Pad lines": PadLines,
265
267
  "Parse colour code": ParseColourCode,
266
268
  "Parse DateTime": ParseDateTime,
@@ -0,0 +1,244 @@
1
+ /**
2
+ * @author n1073645 [n1073645@gmail.com]
3
+ * @copyright Crown Copyright 2020
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import OperationError from "../errors/OperationError.mjs";
8
+
9
+ const letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
10
+ const tiles = [];
11
+
12
+ /**
13
+ * Initialises the tiles with values and positions.
14
+ */
15
+ export function initTiles() {
16
+ for (let i = 0; i < 49; i++)
17
+ tiles.push([letters.charAt(i), [Math.floor(i/7), i % 7]]);
18
+ }
19
+
20
+ /**
21
+ * Rotates the key "down".
22
+ *
23
+ * @param {string} key
24
+ * @param {number} col
25
+ * @param {number} n
26
+ * @returns {string}
27
+ */
28
+ function rotateDown(key, col, n) {
29
+ const lines = [];
30
+ for (let i = 0; i < 7; i++)
31
+ lines.push(key.slice(i*7, (i + 1) * 7));
32
+ const lefts = [];
33
+ let mids = [];
34
+ const rights = [];
35
+ lines.forEach((element) => {
36
+ lefts.push(element.slice(0, col));
37
+ mids.push(element.charAt(col));
38
+ rights.push(element.slice(col+1));
39
+ });
40
+ n = (7 - n % 7) % 7;
41
+ mids = mids.slice(n).concat(mids.slice(0, n));
42
+ let result = "";
43
+ for (let i = 0; i < 7; i++)
44
+ result += lefts[i] + mids[i] + rights[i];
45
+ return result;
46
+ }
47
+
48
+ /**
49
+ * Rotates the key "right".
50
+ *
51
+ * @param {string} key
52
+ * @param {number} row
53
+ * @param {number} n
54
+ * @returns {string}
55
+ */
56
+ function rotateRight(key, row, n) {
57
+ const mid = key.slice(row * 7, (row + 1) * 7);
58
+ n = (7 - n % 7) % 7;
59
+ return key.slice(0, 7 * row) + mid.slice(n) + mid.slice(0, n) + key.slice(7 * (row + 1));
60
+ }
61
+
62
+ /**
63
+ * Finds the position of a letter in the tiles.
64
+ *
65
+ * @param {string} letter
66
+ * @returns {string}
67
+ */
68
+ function findIx(letter) {
69
+ for (let i = 0; i < tiles.length; i++)
70
+ if (tiles[i][0] === letter)
71
+ return tiles[i][1];
72
+ throw new OperationError("Letter " + letter + " is not included in LS47");
73
+ }
74
+
75
+ /**
76
+ * Derives key from the input password.
77
+ *
78
+ * @param {string} password
79
+ * @returns {string}
80
+ */
81
+ export function deriveKey(password) {
82
+ let i = 0;
83
+ let k = letters;
84
+ for (const c of password) {
85
+ const [row, col] = findIx(c);
86
+ k = rotateDown(rotateRight(k, i, col), i, row);
87
+ i = (i + 1) % 7;
88
+ }
89
+ return k;
90
+ }
91
+
92
+ /**
93
+ * Checks the key is a valid key.
94
+ *
95
+ * @param {string} key
96
+ */
97
+ function checkKey(key) {
98
+ if (key.length !== letters.length)
99
+ throw new OperationError("Wrong key size");
100
+ const counts = new Array();
101
+ for (let i = 0; i < letters.length; i++)
102
+ counts[letters.charAt(i)] = 0;
103
+ for (const elem of letters) {
104
+ if (letters.indexOf(elem) === -1)
105
+ throw new OperationError("Letter " + elem + " not in LS47");
106
+ counts[elem]++;
107
+ if (counts[elem] > 1)
108
+ throw new OperationError("Letter duplicated in the key");
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Finds the position of a letter in they key.
114
+ *
115
+ * @param {letter} key
116
+ * @param {string} letter
117
+ * @returns {object}
118
+ */
119
+ function findPos (key, letter) {
120
+ const index = key.indexOf(letter);
121
+ if (index >= 0 && index < 49)
122
+ return [Math.floor(index/7), index%7];
123
+ throw new OperationError("Letter " + letter + " is not in the key");
124
+ }
125
+
126
+ /**
127
+ * Returns the character at the position on the tiles.
128
+ *
129
+ * @param {string} key
130
+ * @param {object} coord
131
+ * @returns {string}
132
+ */
133
+ function findAtPos(key, coord) {
134
+ return key.charAt(coord[1] + (coord[0] * 7));
135
+ }
136
+
137
+ /**
138
+ * Returns new position by adding two positions.
139
+ *
140
+ * @param {object} a
141
+ * @param {object} b
142
+ * @returns {object}
143
+ */
144
+ function addPos(a, b) {
145
+ return [(a[0] + b[0]) % 7, (a[1] + b[1]) % 7];
146
+ }
147
+
148
+ /**
149
+ * Returns new position by subtracting two positions.
150
+ * Note: We have to manually do the remainder division, since JS does not
151
+ * operate correctly on negative numbers (e.g. -3 % 4 = -3 when it should be 1).
152
+ *
153
+ * @param {object} a
154
+ * @param {object} b
155
+ * @returns {object}
156
+ */
157
+ function subPos(a, b) {
158
+ const asub = a[0] - b[0];
159
+ const bsub = a[1] - b[1];
160
+ return [asub - (Math.floor(asub/7) * 7), bsub - (Math.floor(bsub/7) * 7)];
161
+ }
162
+
163
+ /**
164
+ * Encrypts the plaintext string.
165
+ *
166
+ * @param {string} key
167
+ * @param {string} plaintext
168
+ * @returns {string}
169
+ */
170
+ function encrypt(key, plaintext) {
171
+ checkKey(key);
172
+ let mp = [0, 0];
173
+ let ciphertext = "";
174
+ for (const p of plaintext) {
175
+ const pp = findPos(key, p);
176
+ const mix = findIx(findAtPos(key, mp));
177
+ let cp = addPos(pp, mix);
178
+ const c = findAtPos(key, cp);
179
+ ciphertext += c;
180
+ key = rotateRight(key, pp[0], 1);
181
+ cp = findPos(key, c);
182
+ key = rotateDown(key, cp[1], 1);
183
+ mp = addPos(mp, findIx(c));
184
+ }
185
+ return ciphertext;
186
+ }
187
+
188
+ /**
189
+ * Decrypts the ciphertext string.
190
+ *
191
+ * @param {string} key
192
+ * @param {string} ciphertext
193
+ * @returns {string}
194
+ */
195
+ function decrypt(key, ciphertext) {
196
+ checkKey(key);
197
+ let mp = [0, 0];
198
+ let plaintext = "";
199
+ for (const c of ciphertext) {
200
+ let cp = findPos(key, c);
201
+ const mix = findIx(findAtPos(key, mp));
202
+ const pp = subPos(cp, mix);
203
+ const p = findAtPos(key, pp);
204
+ plaintext += p;
205
+ key = rotateRight(key, pp[0], 1);
206
+ cp = findPos(key, c);
207
+ key = rotateDown(key, cp[1], 1);
208
+ mp = addPos(mp, findIx(c));
209
+ }
210
+ return plaintext;
211
+ }
212
+
213
+ /**
214
+ * Adds padding to the input.
215
+ *
216
+ * @param {string} key
217
+ * @param {string} plaintext
218
+ * @param {string} signature
219
+ * @param {number} paddingSize
220
+ * @returns {string}
221
+ */
222
+ export function encryptPad(key, plaintext, signature, paddingSize) {
223
+ initTiles();
224
+ checkKey(key);
225
+ let padding = "";
226
+ for (let i = 0; i < paddingSize; i++) {
227
+ padding += letters.charAt(Math.floor(Math.random() * letters.length));
228
+ }
229
+ return encrypt(key, padding+plaintext+"---"+signature);
230
+ }
231
+
232
+ /**
233
+ * Removes padding from the ouput.
234
+ *
235
+ * @param {string} key
236
+ * @param {string} ciphertext
237
+ * @param {number} paddingSize
238
+ * @returns {string}
239
+ */
240
+ export function decryptPad(key, ciphertext, paddingSize) {
241
+ initTiles();
242
+ checkKey(key);
243
+ return decrypt(key, ciphertext).slice(paddingSize);
244
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @author n1073645 [n1073645@gmail.com]
3
+ * @copyright Crown Copyright 2020
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+
9
+ /**
10
+ * Caesar Box Cipher operation
11
+ */
12
+ class CaesarBoxCipher extends Operation {
13
+
14
+ /**
15
+ * CaesarBoxCipher constructor
16
+ */
17
+ constructor() {
18
+ super();
19
+
20
+ this.name = "Caesar Box Cipher";
21
+ this.module = "Ciphers";
22
+ this.description = "Caesar Box is a transposition cipher used in the Roman Empire, in which letters of the message are written in rows in a square (or a rectangle) and then, read by column.";
23
+ this.infoURL = "https://www.dcode.fr/caesar-box-cipher";
24
+ this.inputType = "string";
25
+ this.outputType = "string";
26
+ this.args = [
27
+ {
28
+ name: "Box Height",
29
+ type: "number",
30
+ value: 1
31
+ }
32
+ ];
33
+ }
34
+
35
+ /**
36
+ * @param {string} input
37
+ * @param {Object[]} args
38
+ * @returns {string}
39
+ */
40
+ run(input, args) {
41
+ const tableHeight = args[0];
42
+ const tableWidth = Math.ceil(input.length / tableHeight);
43
+ while (input.indexOf(" ") !== -1)
44
+ input = input.replace(" ", "");
45
+ for (let i = 0; i < (tableHeight * tableWidth) - input.length; i++) {
46
+ input += "\x00";
47
+ }
48
+ let result = "";
49
+ for (let i = 0; i < tableHeight; i++) {
50
+ for (let j = i; j < input.length; j += tableHeight) {
51
+ if (input.charAt(j) !== "\x00") {
52
+ result += input.charAt(j);
53
+ }
54
+ }
55
+ }
56
+ return result;
57
+ }
58
+
59
+ }
60
+
61
+ export default CaesarBoxCipher;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @author n1073645 [n1073645@gmail.com]
3
+ * @copyright Crown Copyright 2020
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import * as LS47 from "../lib/LS47.mjs";
9
+
10
+ /**
11
+ * LS47 Decrypt operation
12
+ */
13
+ class LS47Decrypt extends Operation {
14
+
15
+ /**
16
+ * LS47Decrypt constructor
17
+ */
18
+ constructor() {
19
+ super();
20
+
21
+ this.name = "LS47 Decrypt";
22
+ this.module = "Crypto";
23
+ this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.<br>The LS47 alphabet consists of following characters: <code>_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()</code><br>An LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption.";
24
+ this.infoURL = "https://github.com/exaexa/ls47";
25
+ this.inputType = "string";
26
+ this.outputType = "string";
27
+ this.args = [
28
+ {
29
+ name: "Password",
30
+ type: "string",
31
+ value: ""
32
+ },
33
+ {
34
+ name: "Padding",
35
+ type: "number",
36
+ value: 10
37
+ }
38
+ ];
39
+ }
40
+
41
+ /**
42
+ * @param {string} input
43
+ * @param {Object[]} args
44
+ * @returns {string}
45
+ */
46
+ run(input, args) {
47
+ this.paddingSize = parseInt(args[1], 10);
48
+
49
+ LS47.initTiles();
50
+
51
+ const key = LS47.deriveKey(args[0]);
52
+ return LS47.decryptPad(key, input, this.paddingSize);
53
+ }
54
+
55
+ }
56
+
57
+ export default LS47Decrypt;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @author n1073645 [n1073645@gmail.com]
3
+ * @copyright Crown Copyright 2020
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import * as LS47 from "../lib/LS47.mjs";
9
+
10
+ /**
11
+ * LS47 Encrypt operation
12
+ */
13
+ class LS47Encrypt extends Operation {
14
+
15
+ /**
16
+ * LS47Encrypt constructor
17
+ */
18
+ constructor() {
19
+ super();
20
+
21
+ this.name = "LS47 Encrypt";
22
+ this.module = "Crypto";
23
+ this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.<br>The LS47 alphabet consists of following characters: <code>_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()</code><br>A LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption.";
24
+ this.infoURL = "https://github.com/exaexa/ls47";
25
+ this.inputType = "string";
26
+ this.outputType = "string";
27
+ this.args = [
28
+ {
29
+ name: "Password",
30
+ type: "string",
31
+ value: ""
32
+ },
33
+ {
34
+ name: "Padding",
35
+ type: "number",
36
+ value: 10
37
+ },
38
+ {
39
+ name: "Signature",
40
+ type: "string",
41
+ value: ""
42
+ }
43
+ ];
44
+ }
45
+
46
+ /**
47
+ * @param {string} input
48
+ * @param {Object[]} args
49
+ * @returns {string}
50
+ */
51
+ run(input, args) {
52
+ this.paddingSize = parseInt(args[1], 10);
53
+
54
+ LS47.initTiles();
55
+
56
+ const key = LS47.deriveKey(args[0]);
57
+ return LS47.encryptPad(key, input, args[2], this.paddingSize);
58
+ }
59
+
60
+ }
61
+
62
+ export default LS47Encrypt;
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @author n1073645 [n1073645@gmail.com]
3
+ * @copyright Crown Copyright 2019
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+
9
+ /**
10
+ * P-list Viewer operation
11
+ */
12
+ class PlistViewer extends Operation {
13
+
14
+ /**
15
+ * PlistViewer constructor
16
+ */
17
+ constructor() {
18
+ super();
19
+
20
+ this.name = "P-list Viewer";
21
+ this.module = "Default";
22
+ this.description = "In the macOS, iOS, NeXTSTEP, and GNUstep programming frameworks, property list files are files that store serialized objects. Property list files use the filename extension .plist, and thus are often referred to as p-list files.<br><br>This operation displays plist files in a human readable format.";
23
+ this.infoURL = "https://wikipedia.org/wiki/Property_list";
24
+ this.inputType = "string";
25
+ this.outputType = "string";
26
+ this.args = [];
27
+ }
28
+
29
+ /**
30
+ * @param {string} input
31
+ * @param {Object[]} args
32
+ * @returns {string}
33
+ */
34
+ run(input, args) {
35
+
36
+ // Regexes are designed to transform the xml format into a more readable string format.
37
+ input = input.slice(input.indexOf("<plist"))
38
+ .replace(/<plist.+>/g, "plist => ")
39
+ .replace(/<dict>/g, "{")
40
+ .replace(/<\/dict>/g, "}")
41
+ .replace(/<array>/g, "[")
42
+ .replace(/<\/array>/g, "]")
43
+ .replace(/<key>.+<\/key>/g, m => `${m.slice(5, m.indexOf(/<\/key>/g)-5)}\t=> `)
44
+ .replace(/<real>.+<\/real>/g, m => `${m.slice(6, m.indexOf(/<\/real>/g)-6)}\n`)
45
+ .replace(/<string>.+<\/string>/g, m => `"${m.slice(8, m.indexOf(/<\/string>/g)-8)}"\n`)
46
+ .replace(/<integer>.+<\/integer>/g, m => `${m.slice(9, m.indexOf(/<\/integer>/g)-9)}\n`)
47
+ .replace(/<false\/>/g, m => "false")
48
+ .replace(/<true\/>/g, m => "true")
49
+ .replace(/<\/plist>/g, "/plist")
50
+ .replace(/<date>.+<\/date>/g, m => `${m.slice(6, m.indexOf(/<\/integer>/g)-6)}`)
51
+ .replace(/<data>(\s|.)+?<\/data>/g, m => `${m.slice(6, m.indexOf(/<\/data>/g)-6)}`)
52
+ .replace(/[ \t\r\f\v]/g, "");
53
+
54
+ /**
55
+ * Depending on the type of brace, it will increment the depth and amount of arrays accordingly.
56
+ *
57
+ * @param {string} elem
58
+ * @param {array} vals
59
+ * @param {number} offset
60
+ */
61
+ function braces(elem, vals, offset) {
62
+ const temp = vals.indexOf(elem);
63
+ if (temp !== -1) {
64
+ depthCount += offset;
65
+ if (temp === 1)
66
+ arrCount += offset;
67
+ }
68
+ }
69
+
70
+ let result = "";
71
+ let arrCount = 0;
72
+ let depthCount = 0;
73
+
74
+ /**
75
+ * Formats the input after the regex has replaced all of the relevant parts.
76
+ *
77
+ * @param {array} input
78
+ * @param {number} index
79
+ */
80
+ function printIt(input, index) {
81
+ if (!(input.length))
82
+ return;
83
+
84
+ let temp = "";
85
+ const origArr = arrCount;
86
+ let currElem = input[0];
87
+
88
+ // If the current position points at a larger dynamic structure.
89
+ if (currElem.indexOf("=>") !== -1) {
90
+
91
+ // If the LHS also points at a larger structure (nested plists in a dictionary).
92
+ if (input[1].indexOf("=>") !== -1)
93
+ temp = currElem.slice(0, -2) + " => " + input[1].slice(0, -2) + " =>\n";
94
+ else
95
+ temp = currElem.slice(0, -2) + " => " + input[1] + "\n";
96
+
97
+ input = input.slice(1);
98
+ } else {
99
+ // Controls the tab depth for how many closing braces there have been.
100
+
101
+ braces(currElem, ["}", "]"], -1);
102
+
103
+ // Has to be here since the formatting breaks otherwise.
104
+ temp = currElem + "\n";
105
+ }
106
+
107
+ currElem = input[0];
108
+
109
+ // Tab out to the correct distance.
110
+ result += ("\t".repeat(depthCount));
111
+
112
+ // If it is enclosed in an array show index.
113
+ if (arrCount > 0 && currElem !== "]")
114
+ result += index.toString() + " => ";
115
+
116
+ result += temp;
117
+
118
+ // Controls the tab depth for how many opening braces there have been.
119
+ braces(currElem, ["{", "["], 1);
120
+
121
+ // If there has been a new array then reset index.
122
+ if (arrCount > origArr)
123
+ return printIt(input.slice(1), 0);
124
+ return printIt(input.slice(1), ++index);
125
+ }
126
+
127
+ input = input.split("\n").filter(e => e !== "");
128
+ printIt(input, 0);
129
+ return result;
130
+ }
131
+ }
132
+
133
+ export default PlistViewer;
@@ -22,7 +22,7 @@ class Subsection extends Operation {
22
22
  this.name = "Subsection";
23
23
  this.flowControl = true;
24
24
  this.module = "Default";
25
- this.description = "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.<br><br>You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on.";
25
+ this.description = "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.<br><br>You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on.<br><br>Use the Merge operation to reset the effects of subsection.";
26
26
  this.infoURL = "";
27
27
  this.inputType = "string";
28
28
  this.outputType = "string";
@@ -48,6 +48,7 @@ import CSSMinify from "./CSSMinify.mjs";
48
48
  import CSSSelector from "./CSSSelector.mjs";
49
49
  import CSVToJSON from "./CSVToJSON.mjs";
50
50
  import CTPH from "./CTPH.mjs";
51
+ import CaesarBoxCipher from "./CaesarBoxCipher.mjs";
51
52
  import CartesianProduct from "./CartesianProduct.mjs";
52
53
  import ChangeIPFormat from "./ChangeIPFormat.mjs";
53
54
  import ChiSquare from "./ChiSquare.mjs";
@@ -191,6 +192,8 @@ import JavaScriptMinify from "./JavaScriptMinify.mjs";
191
192
  import JavaScriptParser from "./JavaScriptParser.mjs";
192
193
  import Jump from "./Jump.mjs";
193
194
  import Keccak from "./Keccak.mjs";
195
+ import LS47Decrypt from "./LS47Decrypt.mjs";
196
+ import LS47Encrypt from "./LS47Encrypt.mjs";
194
197
  import Label from "./Label.mjs";
195
198
  import Lorenz from "./Lorenz.mjs";
196
199
  import LuhnChecksum from "./LuhnChecksum.mjs";
@@ -220,6 +223,7 @@ import PGPEncrypt from "./PGPEncrypt.mjs";
220
223
  import PGPEncryptAndSign from "./PGPEncryptAndSign.mjs";
221
224
  import PGPVerify from "./PGPVerify.mjs";
222
225
  import PHPDeserialize from "./PHPDeserialize.mjs";
226
+ import PLISTViewer from "./PLISTViewer.mjs";
223
227
  import PadLines from "./PadLines.mjs";
224
228
  import ParseASN1HexString from "./ParseASN1HexString.mjs";
225
229
  import ParseColourCode from "./ParseColourCode.mjs";
@@ -422,6 +426,7 @@ export {
422
426
  CSSSelector,
423
427
  CSVToJSON,
424
428
  CTPH,
429
+ CaesarBoxCipher,
425
430
  CartesianProduct,
426
431
  ChangeIPFormat,
427
432
  ChiSquare,
@@ -565,6 +570,8 @@ export {
565
570
  JavaScriptParser,
566
571
  Jump,
567
572
  Keccak,
573
+ LS47Decrypt,
574
+ LS47Encrypt,
568
575
  Label,
569
576
  Lorenz,
570
577
  LuhnChecksum,
@@ -594,6 +601,7 @@ export {
594
601
  PGPEncryptAndSign,
595
602
  PGPVerify,
596
603
  PHPDeserialize,
604
+ PLISTViewer,
597
605
  PadLines,
598
606
  ParseASN1HexString,
599
607
  ParseColourCode,
@@ -58,6 +58,7 @@ import {
58
58
  CSSSelector as core_CSSSelector,
59
59
  CSVToJSON as core_CSVToJSON,
60
60
  CTPH as core_CTPH,
61
+ CaesarBoxCipher as core_CaesarBoxCipher,
61
62
  CartesianProduct as core_CartesianProduct,
62
63
  ChangeIPFormat as core_ChangeIPFormat,
63
64
  ChiSquare as core_ChiSquare,
@@ -194,6 +195,8 @@ import {
194
195
  JWTSign as core_JWTSign,
195
196
  JWTVerify as core_JWTVerify,
196
197
  Keccak as core_Keccak,
198
+ LS47Decrypt as core_LS47Decrypt,
199
+ LS47Encrypt as core_LS47Encrypt,
197
200
  Lorenz as core_Lorenz,
198
201
  LuhnChecksum as core_LuhnChecksum,
199
202
  MD2 as core_MD2,
@@ -221,6 +224,7 @@ import {
221
224
  PGPEncryptAndSign as core_PGPEncryptAndSign,
222
225
  PGPVerify as core_PGPVerify,
223
226
  PHPDeserialize as core_PHPDeserialize,
227
+ PLISTViewer as core_PLISTViewer,
224
228
  PadLines as core_PadLines,
225
229
  ParseASN1HexString as core_ParseASN1HexString,
226
230
  ParseColourCode as core_ParseColourCode,
@@ -432,6 +436,7 @@ function generateChef() {
432
436
  "CSSSelector": _wrap(core_CSSSelector),
433
437
  "CSVToJSON": _wrap(core_CSVToJSON),
434
438
  "CTPH": _wrap(core_CTPH),
439
+ "caesarBoxCipher": _wrap(core_CaesarBoxCipher),
435
440
  "cartesianProduct": _wrap(core_CartesianProduct),
436
441
  "changeIPFormat": _wrap(core_ChangeIPFormat),
437
442
  "chiSquare": _wrap(core_ChiSquare),
@@ -568,6 +573,8 @@ function generateChef() {
568
573
  "JWTSign": _wrap(core_JWTSign),
569
574
  "JWTVerify": _wrap(core_JWTVerify),
570
575
  "keccak": _wrap(core_Keccak),
576
+ "LS47Decrypt": _wrap(core_LS47Decrypt),
577
+ "LS47Encrypt": _wrap(core_LS47Encrypt),
571
578
  "lorenz": _wrap(core_Lorenz),
572
579
  "luhnChecksum": _wrap(core_LuhnChecksum),
573
580
  "MD2": _wrap(core_MD2),
@@ -595,6 +602,7 @@ function generateChef() {
595
602
  "PGPEncryptAndSign": _wrap(core_PGPEncryptAndSign),
596
603
  "PGPVerify": _wrap(core_PGPVerify),
597
604
  "PHPDeserialize": _wrap(core_PHPDeserialize),
605
+ "PLISTViewer": _wrap(core_PLISTViewer),
598
606
  "padLines": _wrap(core_PadLines),
599
607
  "parseASN1HexString": _wrap(core_ParseASN1HexString),
600
608
  "parseColourCode": _wrap(core_ParseColourCode),
@@ -814,6 +822,7 @@ const CSSMinify = chef.CSSMinify;
814
822
  const CSSSelector = chef.CSSSelector;
815
823
  const CSVToJSON = chef.CSVToJSON;
816
824
  const CTPH = chef.CTPH;
825
+ const caesarBoxCipher = chef.caesarBoxCipher;
817
826
  const cartesianProduct = chef.cartesianProduct;
818
827
  const changeIPFormat = chef.changeIPFormat;
819
828
  const chiSquare = chef.chiSquare;
@@ -957,6 +966,8 @@ const javaScriptMinify = chef.javaScriptMinify;
957
966
  const javaScriptParser = chef.javaScriptParser;
958
967
  const jump = chef.jump;
959
968
  const keccak = chef.keccak;
969
+ const LS47Decrypt = chef.LS47Decrypt;
970
+ const LS47Encrypt = chef.LS47Encrypt;
960
971
  const label = chef.label;
961
972
  const lorenz = chef.lorenz;
962
973
  const luhnChecksum = chef.luhnChecksum;
@@ -986,6 +997,7 @@ const PGPEncrypt = chef.PGPEncrypt;
986
997
  const PGPEncryptAndSign = chef.PGPEncryptAndSign;
987
998
  const PGPVerify = chef.PGPVerify;
988
999
  const PHPDeserialize = chef.PHPDeserialize;
1000
+ const PLISTViewer = chef.PLISTViewer;
989
1001
  const padLines = chef.padLines;
990
1002
  const parseASN1HexString = chef.parseASN1HexString;
991
1003
  const parseColourCode = chef.parseColourCode;
@@ -1190,6 +1202,7 @@ const operations = [
1190
1202
  CSSSelector,
1191
1203
  CSVToJSON,
1192
1204
  CTPH,
1205
+ caesarBoxCipher,
1193
1206
  cartesianProduct,
1194
1207
  changeIPFormat,
1195
1208
  chiSquare,
@@ -1333,6 +1346,8 @@ const operations = [
1333
1346
  javaScriptParser,
1334
1347
  jump,
1335
1348
  keccak,
1349
+ LS47Decrypt,
1350
+ LS47Encrypt,
1336
1351
  label,
1337
1352
  lorenz,
1338
1353
  luhnChecksum,
@@ -1362,6 +1377,7 @@ const operations = [
1362
1377
  PGPEncryptAndSign,
1363
1378
  PGPVerify,
1364
1379
  PHPDeserialize,
1380
+ PLISTViewer,
1365
1381
  padLines,
1366
1382
  parseASN1HexString,
1367
1383
  parseColourCode,
@@ -1570,6 +1586,7 @@ export {
1570
1586
  CSSSelector,
1571
1587
  CSVToJSON,
1572
1588
  CTPH,
1589
+ caesarBoxCipher,
1573
1590
  cartesianProduct,
1574
1591
  changeIPFormat,
1575
1592
  chiSquare,
@@ -1713,6 +1730,8 @@ export {
1713
1730
  javaScriptParser,
1714
1731
  jump,
1715
1732
  keccak,
1733
+ LS47Decrypt,
1734
+ LS47Encrypt,
1716
1735
  label,
1717
1736
  lorenz,
1718
1737
  luhnChecksum,
@@ -1742,6 +1761,7 @@ export {
1742
1761
  PGPEncryptAndSign,
1743
1762
  PGPVerify,
1744
1763
  PHPDeserialize,
1764
+ PLISTViewer,
1745
1765
  padLines,
1746
1766
  parseASN1HexString,
1747
1767
  parseColourCode,
@@ -116,6 +116,8 @@ import "./tests/GetAllCasings.mjs";
116
116
  import "./tests/SIGABA.mjs";
117
117
  import "./tests/ELFInfo.mjs";
118
118
  import "./tests/Subsection.mjs";
119
+ import "./tests/CaesarBoxCipher.mjs";
120
+ import "./tests/LS47.mjs";
119
121
 
120
122
 
121
123
  // Cannot test operations that use the File type yet
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Caesar Box Cipher tests.
3
+ *
4
+ * @author n1073645 [n1073645@gmail.com]
5
+ *
6
+ * @copyright Crown Copyright 2020
7
+ * @license Apache-2.0
8
+ */
9
+ import TestRegister from "../../lib/TestRegister.mjs";
10
+
11
+ TestRegister.addTests([
12
+ {
13
+ name: "Caesar Box Cipher: nothing",
14
+ input: "",
15
+ expectedOutput: "",
16
+ recipeConfig: [
17
+ {
18
+ op: "Caesar Box Cipher",
19
+ args: ["1"],
20
+ },
21
+ ],
22
+ },
23
+ {
24
+ name: "Caesar Box Cipher: Hello World!",
25
+ input: "Hello World!",
26
+ expectedOutput: "Hlodeor!lWl",
27
+ recipeConfig: [
28
+ {
29
+ op: "Caesar Box Cipher",
30
+ args: ["3"],
31
+ },
32
+ ],
33
+ },
34
+ {
35
+ name: "Caesar Box Cipher: Hello World!",
36
+ input: "Hlodeor!lWl",
37
+ expectedOutput: "HelloWorld!",
38
+ recipeConfig: [
39
+ {
40
+ op: "Caesar Box Cipher",
41
+ args: ["4"],
42
+ },
43
+ ],
44
+ }
45
+ ]);
@@ -0,0 +1,45 @@
1
+ /**
2
+ * LS47 tests.
3
+ *
4
+ * @author n1073645 [n1073645@gmail.com]
5
+ *
6
+ * @copyright Crown Copyright 2020
7
+ * @license Apache-2.0
8
+ */
9
+ import TestRegister from "../../lib/TestRegister.mjs";
10
+
11
+ TestRegister.addTests([
12
+ {
13
+ name: "LS47 Encrypt",
14
+ input: "thequickbrownfoxjumped",
15
+ expectedOutput: "(,t74ci78cp/8trx*yesu:alp1wqy",
16
+ recipeConfig: [
17
+ {
18
+ op: "LS47 Encrypt",
19
+ args: ["helloworld", 0, "test"],
20
+ },
21
+ ],
22
+ },
23
+ {
24
+ name: "LS47 Decrypt",
25
+ input: "(,t74ci78cp/8trx*yesu:alp1wqy",
26
+ expectedOutput: "thequickbrownfoxjumped---test",
27
+ recipeConfig: [
28
+ {
29
+ op: "LS47 Decrypt",
30
+ args: ["helloworld", 0],
31
+ },
32
+ ],
33
+ },
34
+ {
35
+ name: "LS47 Encrypt",
36
+ input: "thequickbrownfoxjumped",
37
+ expectedOutput: "Letter H is not included in LS47",
38
+ recipeConfig: [
39
+ {
40
+ op: "LS47 Encrypt",
41
+ args: ["Helloworld", 0, "test"],
42
+ },
43
+ ],
44
+ }
45
+ ]);