cyberchef 9.35.0 → 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.
@@ -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,
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Emulation of the Bombe machine.
3
3
  *
4
+ * Tested against the Bombe Rebuild at Bletchley Park's TNMOC
5
+ * using a variety of inputs and settings to confirm correctness.
6
+ *
4
7
  * @author s2224834
5
8
  * @copyright Crown Copyright 2019
6
9
  * @license Apache-2.0
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Emulation of Colossus.
3
3
  *
4
+ * Tested against the Colossus Rebuild at Bletchley Park's TNMOC
5
+ * using a variety of inputs and settings to confirm correctness.
6
+ *
4
7
  * @author VirtualColossus [martin@virtualcolossus.co.uk]
5
8
  * @copyright Crown Copyright 2019
6
9
  * @license Apache-2.0
@@ -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();
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Emulation of the Enigma machine.
3
3
  *
4
+ * Tested against various genuine Enigma machines using a variety of inputs
5
+ * and settings to confirm correctness.
6
+ *
4
7
  * @author s2224834
5
8
  * @copyright Crown Copyright 2019
6
9
  * @license Apache-2.0
@@ -46,7 +46,7 @@ class GetAllCasings extends Operation {
46
46
  }
47
47
  result += temp.join("") + "\n";
48
48
  }
49
- return result;
49
+ return result.slice(0, -1);
50
50
  }
51
51
  }
52
52
 
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Emulation of the Lorenz SZ40/42a/42b cipher attachment.
3
3
  *
4
+ * Tested against the Colossus Rebuild at Bletchley Park's TNMOC
5
+ * using a variety of inputs and settings to confirm correctness.
6
+ *
4
7
  * @author VirtualColossus [martin@virtualcolossus.co.uk]
5
8
  * @copyright Crown Copyright 2019
6
9
  * @license Apache-2.0