cyberchef 11.1.0 → 11.3.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.
Files changed (148) hide show
  1. package/AGENTS.md +75 -0
  2. package/CHANGELOG.md +173 -2
  3. package/Dockerfile +2 -2
  4. package/Gruntfile.js +1 -0
  5. package/README.md +7 -6
  6. package/SECURITY.md +3 -1
  7. package/package.json +22 -21
  8. package/src/core/Chef.mjs +2 -0
  9. package/src/core/Dish.mjs +1 -5
  10. package/src/core/Ingredient.mjs +92 -0
  11. package/src/core/Operation.mjs +19 -0
  12. package/src/core/Recipe.mjs +4 -0
  13. package/src/core/Utils.mjs +48 -0
  14. package/src/core/config/Categories.json +22 -6
  15. package/src/core/config/OperationConfig.json +4774 -1228
  16. package/src/core/config/modules/Ciphers.mjs +20 -0
  17. package/src/core/config/modules/Crypto.mjs +10 -0
  18. package/src/core/config/modules/Default.mjs +8 -0
  19. package/src/core/config/modules/File.mjs +16 -0
  20. package/src/core/config/modules/OpModules.mjs +2 -0
  21. package/src/core/config/scripts/generateHTMLEntities.mjs +139 -0
  22. package/src/core/config/scripts/htmlEntityOverrides.mjs +86 -0
  23. package/src/core/dishTypes/DishType.mjs +1 -1
  24. package/src/core/errors/ExcludedOperationError.mjs +1 -1
  25. package/src/core/lib/Arithmetic.mjs +21 -5
  26. package/src/core/lib/BigIntUtils.mjs +0 -1
  27. package/src/core/lib/COBS.mjs +86 -0
  28. package/src/core/lib/Charts.mjs +3 -3
  29. package/src/core/lib/Decimal.mjs +5 -5
  30. package/src/core/lib/HTMLEntities.mjs +2068 -0
  31. package/src/core/lib/Present.mjs +422 -0
  32. package/src/core/lib/Protocol.mjs +8 -6
  33. package/src/core/lib/TEA.mjs +494 -0
  34. package/src/core/lib/TLVParser.mjs +16 -7
  35. package/src/core/lib/Twofish.mjs +608 -0
  36. package/src/core/operations/AsconDecrypt.mjs +112 -0
  37. package/src/core/operations/AsconEncrypt.mjs +108 -0
  38. package/src/core/operations/AsconHash.mjs +49 -0
  39. package/src/core/operations/AsconMAC.mjs +68 -0
  40. package/src/core/operations/AutomatedValidationTestOp.mjs +84 -0
  41. package/src/core/operations/AvroToJSON.mjs +1 -1
  42. package/src/core/operations/BLAKE3.mjs +5 -1
  43. package/src/core/operations/BcryptCompare.mjs +11 -5
  44. package/src/core/operations/BitShiftLeft.mjs +4 -1
  45. package/src/core/operations/Bzip2Compress.mjs +1 -1
  46. package/src/core/operations/DechunkHTTPResponse.mjs +4 -1
  47. package/src/core/operations/ExtendedGCD.mjs +101 -0
  48. package/src/core/operations/FromBase.mjs +2 -1
  49. package/src/core/operations/FromCOBS.mjs +38 -0
  50. package/src/core/operations/FromDecimal.mjs +6 -1
  51. package/src/core/operations/FromHTMLEntity.mjs +2 -1458
  52. package/src/core/operations/GenerateDeBruijnSequence.mjs +8 -0
  53. package/src/core/operations/GenerateHOTP.mjs +21 -6
  54. package/src/core/operations/GenerateImage.mjs +22 -10
  55. package/src/core/operations/GeneratePrime.mjs +154 -0
  56. package/src/core/operations/GenerateTOTP.mjs +24 -7
  57. package/src/core/operations/Gzip.mjs +1 -3
  58. package/src/core/operations/Jsonata.mjs +12 -0
  59. package/src/core/operations/MIMEDecoding.mjs +1 -1
  60. package/src/core/operations/MOD.mjs +62 -0
  61. package/src/core/operations/ModularInverse.mjs +107 -0
  62. package/src/core/operations/PRESENTDecrypt.mjs +94 -0
  63. package/src/core/operations/PRESENTEncrypt.mjs +94 -0
  64. package/src/core/operations/ParityBit.mjs +1 -1
  65. package/src/core/operations/ParseIPv4Header.mjs +1 -1
  66. package/src/core/operations/ParseURI.mjs +18 -5
  67. package/src/core/operations/PseudoRandomNumberGenerator.mjs +2 -1
  68. package/src/core/operations/RandomPrime.mjs +154 -0
  69. package/src/core/operations/RenderPDF.mjs +100 -0
  70. package/src/core/operations/SHA2.mjs +1 -1
  71. package/src/core/operations/SM4Encrypt.mjs +1 -1
  72. package/src/core/operations/SetDifference.mjs +8 -1
  73. package/src/core/operations/SetIntersection.mjs +8 -1
  74. package/src/core/operations/ShowOnMap.mjs +14 -2
  75. package/src/core/operations/TEADecrypt.mjs +98 -0
  76. package/src/core/operations/TEAEncrypt.mjs +98 -0
  77. package/src/core/operations/ToBase.mjs +4 -4
  78. package/src/core/operations/ToBase32.mjs +20 -4
  79. package/src/core/operations/ToBinary.mjs +4 -1
  80. package/src/core/operations/ToCOBS.mjs +38 -0
  81. package/src/core/operations/ToHTMLEntity.mjs +7 -1430
  82. package/src/core/operations/ToHexdump.mjs +7 -1
  83. package/src/core/operations/TwofishDecrypt.mjs +94 -0
  84. package/src/core/operations/TwofishEncrypt.mjs +94 -0
  85. package/src/core/operations/URLEncode.mjs +22 -18
  86. package/src/core/operations/UnescapeUnicodeCharacters.mjs +2 -1
  87. package/src/core/operations/ViewBitPlane.mjs +9 -3
  88. package/src/core/operations/Wrap.mjs +5 -0
  89. package/src/core/operations/XORBruteForce.mjs +4 -1
  90. package/src/core/operations/XORChecksum.mjs +10 -3
  91. package/src/core/operations/XTEADecrypt.mjs +110 -0
  92. package/src/core/operations/XTEAEncrypt.mjs +110 -0
  93. package/src/core/operations/index.mjs +42 -0
  94. package/src/core/vendor/ascon.mjs +162 -0
  95. package/src/core/vendor/htmlEntities/entity.json +2233 -0
  96. package/src/core/vendor/htmlEntities/entity.txt +14 -0
  97. package/src/node/api.mjs +4 -1
  98. package/src/node/index.mjs +105 -0
  99. package/src/web/HTMLOperation.mjs +2 -1
  100. package/src/web/stylesheets/layout/_io.css +8 -0
  101. package/tests/browser/00_nightwatch.js +26 -0
  102. package/tests/browser/02_ops.js +20 -4
  103. package/tests/node/index.mjs +2 -0
  104. package/tests/node/tests/Dish.mjs +19 -0
  105. package/tests/node/tests/NodeDish.mjs +36 -0
  106. package/tests/node/tests/ToHTMLEntity.mjs +82 -0
  107. package/tests/node/tests/Utils.mjs +77 -0
  108. package/tests/node/tests/lib/ChartsProtocolPrototypePollution.mjs +90 -0
  109. package/tests/node/tests/nodeApi.mjs +33 -1
  110. package/tests/node/tests/operations.mjs +26 -1
  111. package/tests/operations/index.mjs +17 -0
  112. package/tests/operations/tests/Arithmetic.mjs +33 -0
  113. package/tests/operations/tests/Ascon.mjs +501 -0
  114. package/tests/operations/tests/AutomatedValidation.mjs +154 -0
  115. package/tests/operations/tests/BLAKE3.mjs +39 -1
  116. package/tests/operations/tests/Base32.mjs +22 -0
  117. package/tests/operations/tests/COBS.mjs +476 -0
  118. package/tests/operations/tests/CharEnc.mjs +2 -2
  119. package/tests/operations/tests/DechunkHTTPResponse.mjs +66 -0
  120. package/tests/operations/tests/ExtendedGCD.mjs +78 -0
  121. package/tests/operations/tests/FromBase.mjs +66 -0
  122. package/tests/operations/tests/FromDecimal.mjs +55 -0
  123. package/tests/operations/tests/GenerateLoremIpsum.mjs +2 -2
  124. package/tests/operations/tests/Gzip.mjs +60 -0
  125. package/tests/operations/tests/HTMLEntity.mjs +126 -0
  126. package/tests/operations/tests/Hash.mjs +44 -0
  127. package/tests/operations/tests/Hexdump.mjs +11 -0
  128. package/tests/operations/tests/Image.mjs +26 -0
  129. package/tests/operations/tests/Jsonata.mjs +23 -0
  130. package/tests/operations/tests/MIMEDecoding.mjs +33 -0
  131. package/tests/operations/tests/MOD.mjs +208 -0
  132. package/tests/operations/tests/Median.mjs +33 -0
  133. package/tests/operations/tests/ModularInverse.mjs +78 -0
  134. package/tests/operations/tests/OTP.mjs +167 -2
  135. package/tests/operations/tests/PRESENT.mjs +465 -0
  136. package/tests/operations/tests/ParseIPv4Header.mjs +11 -0
  137. package/tests/operations/tests/ParseTLV.mjs +41 -0
  138. package/tests/operations/tests/RenderPDF.mjs +55 -0
  139. package/tests/operations/tests/SM2.mjs +1 -1
  140. package/tests/operations/tests/SetDifference.mjs +22 -0
  141. package/tests/operations/tests/SetIntersection.mjs +23 -1
  142. package/tests/operations/tests/ShowOnMap.mjs +61 -0
  143. package/tests/operations/tests/TEA.mjs +566 -0
  144. package/tests/operations/tests/Twofish.mjs +486 -0
  145. package/tests/operations/tests/URLEncodeDecode.mjs +26 -0
  146. package/tests/operations/tests/UnescapeUnicodeCharacters.mjs +88 -0
  147. package/tests/operations/tests/Wrap.mjs +44 -0
  148. package/webpack.config.js +3 -3
@@ -8,6 +8,8 @@ import Operation from "../Operation.mjs";
8
8
  import Utils from "../Utils.mjs";
9
9
  import OperationError from "../errors/OperationError.mjs";
10
10
 
11
+ const MAX_WIDTH = 65536;
12
+
11
13
  /**
12
14
  * To Hexdump operation
13
15
  */
@@ -30,7 +32,8 @@ class ToHexdump extends Operation {
30
32
  "name": "Width",
31
33
  "type": "number",
32
34
  "value": 16,
33
- "min": 1
35
+ "min": 1,
36
+ "max": MAX_WIDTH
34
37
  },
35
38
  {
36
39
  "name": "Upper case hex",
@@ -63,6 +66,9 @@ class ToHexdump extends Operation {
63
66
  if (length < 1 || Math.round(length) !== length)
64
67
  throw new OperationError("Width must be a positive integer");
65
68
 
69
+ if (length > MAX_WIDTH)
70
+ throw new OperationError(`Width must be no more than ${MAX_WIDTH}`);
71
+
66
72
  const lines = [];
67
73
  for (let i = 0; i < data.length; i += length) {
68
74
  let lineNo = Utils.hex(i, 8);
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @author Medjedtxm
3
+ * @copyright Crown Copyright 2026
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 { decryptTwofish } from "../lib/Twofish.mjs";
12
+
13
+ /**
14
+ * Twofish Decrypt operation
15
+ */
16
+ class TwofishDecrypt extends Operation {
17
+
18
+ /**
19
+ * TwofishDecrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "Twofish Decrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "Twofish is a symmetric key block cipher designed by Bruce Schneier. It was one of the five AES finalists. Twofish operates on 128-bit blocks and supports key sizes of 128, 192, or 256 bits with 16 rounds of a Feistel network.<br><br>When using CBC or ECB mode, the PKCS#7 padding scheme is used.";
27
+ this.infoURL = "https://wikipedia.org/wiki/Twofish";
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": ["Hex", "Raw"]
52
+ },
53
+ {
54
+ "name": "Output",
55
+ "type": "option",
56
+ "value": ["Raw", "Hex"]
57
+ },
58
+ {
59
+ "name": "Padding",
60
+ "type": "option",
61
+ "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
62
+ }
63
+ ];
64
+ }
65
+
66
+ /**
67
+ * @param {string} input
68
+ * @param {Object[]} args
69
+ * @returns {string}
70
+ */
71
+ run(input, args) {
72
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
73
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
74
+ [,, mode, inputType, outputType, padding] = args;
75
+
76
+ if (key.length !== 16 && key.length !== 24 && key.length !== 32)
77
+ throw new OperationError(`Invalid key length: ${key.length} bytes
78
+
79
+ Twofish uses a key length of 16 bytes (128 bits), 24 bytes (192 bits), or 32 bytes (256 bits).`);
80
+
81
+ if (iv.length !== 16 && mode !== "ECB")
82
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
83
+
84
+ Twofish uses an IV length of 16 bytes (128 bits).
85
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
86
+
87
+ input = Utils.convertToByteArray(input, inputType);
88
+ const output = decryptTwofish(input, key, iv, mode, padding);
89
+ return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
90
+ }
91
+
92
+ }
93
+
94
+ export default TwofishDecrypt;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @author Medjedtxm
3
+ * @copyright Crown Copyright 2026
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 { encryptTwofish } from "../lib/Twofish.mjs";
12
+
13
+ /**
14
+ * Twofish Encrypt operation
15
+ */
16
+ class TwofishEncrypt extends Operation {
17
+
18
+ /**
19
+ * TwofishEncrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "Twofish Encrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "Twofish is a symmetric key block cipher designed by Bruce Schneier. It was one of the five AES finalists. Twofish operates on 128-bit blocks and supports key sizes of 128, 192, or 256 bits with 16 rounds of a Feistel network.<br><br>When using CBC or ECB mode, the PKCS#7 padding scheme is used.";
27
+ this.infoURL = "https://wikipedia.org/wiki/Twofish";
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
+ "name": "Padding",
60
+ "type": "option",
61
+ "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
62
+ }
63
+ ];
64
+ }
65
+
66
+ /**
67
+ * @param {string} input
68
+ * @param {Object[]} args
69
+ * @returns {string}
70
+ */
71
+ run(input, args) {
72
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
73
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
74
+ [,, mode, inputType, outputType, padding] = args;
75
+
76
+ if (key.length !== 16 && key.length !== 24 && key.length !== 32)
77
+ throw new OperationError(`Invalid key length: ${key.length} bytes
78
+
79
+ Twofish uses a key length of 16 bytes (128 bits), 24 bytes (192 bits), or 32 bytes (256 bits).`);
80
+
81
+ if (iv.length !== 16 && mode !== "ECB")
82
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
83
+
84
+ Twofish uses an IV length of 16 bytes (128 bits).
85
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
86
+
87
+ input = Utils.convertToByteArray(input, inputType);
88
+ const output = encryptTwofish(input, key, iv, mode, padding);
89
+ return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
90
+ }
91
+
92
+ }
93
+
94
+ export default TwofishEncrypt;
@@ -21,7 +21,7 @@ class URLEncode extends Operation {
21
21
  this.module = "URL";
22
22
  this.description = "Encodes problematic characters into percent-encoding, a format supported by URIs/URLs.<br><br>e.g. <code>=</code> becomes <code>%3d</code>";
23
23
  this.infoURL = "https://wikipedia.org/wiki/Percent-encoding";
24
- this.inputType = "string";
24
+ this.inputType = "byteArray";
25
25
  this.outputType = "string";
26
26
  this.args = [
27
27
  {
@@ -33,34 +33,38 @@ class URLEncode extends Operation {
33
33
  }
34
34
 
35
35
  /**
36
- * @param {string} input
36
+ * @param {byteArray} input
37
37
  * @param {Object[]} args
38
38
  * @returns {string}
39
39
  */
40
40
  run(input, args) {
41
41
  const encodeAll = args[0];
42
- return encodeAll ? this.encodeAllChars(input) : encodeURI(input);
42
+ return this.encodeBytes(input, encodeAll);
43
43
  }
44
44
 
45
45
  /**
46
- * Encode characters in URL outside of encodeURI() function spec
46
+ * Encode bytes in URL using percent encoding.
47
47
  *
48
- * @param {string} str
48
+ * @param {byteArray} bytes
49
+ * @param {boolean} encodeAll
49
50
  * @returns {string}
50
51
  */
51
- encodeAllChars (str) {
52
- // TODO Do this programmatically
53
- return encodeURIComponent(str)
54
- .replace(/!/g, "%21")
55
- .replace(/#/g, "%23")
56
- .replace(/'/g, "%27")
57
- .replace(/\(/g, "%28")
58
- .replace(/\)/g, "%29")
59
- .replace(/\*/g, "%2A")
60
- .replace(/-/g, "%2D")
61
- .replace(/\./g, "%2E")
62
- .replace(/_/g, "%5F")
63
- .replace(/~/g, "%7E");
52
+ encodeBytes(bytes, encodeAll) {
53
+ const safeChars = encodeAll ?
54
+ /^[A-Za-z0-9]$/ :
55
+ /^[A-Za-z0-9:/?#[\]@!$&'()*+,;=%]$/;
56
+
57
+ let output = "";
58
+
59
+ for (const byte of bytes) {
60
+ const char = String.fromCharCode(byte);
61
+
62
+ output += safeChars.test(char) ?
63
+ char :
64
+ "%" + byte.toString(16).toUpperCase().padStart(2, "0");
65
+ }
66
+
67
+ return output;
64
68
  }
65
69
 
66
70
  }
@@ -56,7 +56,8 @@ class UnescapeUnicodeCharacters extends Operation {
56
56
  */
57
57
  run(input, args) {
58
58
  const prefix = prefixToRegex[args[0]],
59
- regex = new RegExp(prefix+"([a-f\\d]{4})", "ig");
59
+ quantifier = args[0] === "U+" ? "{4,6}" : "{4}",
60
+ regex = new RegExp(prefix+"([a-f\\d]"+quantifier+")", "ig");
60
61
  let output = "",
61
62
  m,
62
63
  i = 0;
@@ -52,9 +52,15 @@ class ViewBitPlane extends Operation {
52
52
  if (!isImage(input))
53
53
  throw new OperationError("Please enter a valid image file.");
54
54
 
55
- const [colour, bit] = args,
56
- parsedImage = await Jimp.read(input),
57
- width = parsedImage.bitmap.width,
55
+ const [colour, bit] = args;
56
+ let parsedImage;
57
+ try {
58
+ parsedImage = await Jimp.read(input);
59
+ } catch (err) {
60
+ throw new OperationError(`Error loading image. (${err})`);
61
+ }
62
+
63
+ const width = parsedImage.bitmap.width,
58
64
  height = parsedImage.bitmap.height,
59
65
  colourIndex = COLOUR_OPTIONS.indexOf(colour),
60
66
  bitIndex = 7 - bit;
@@ -6,6 +6,8 @@
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
8
 
9
+ const MAX_LINE_WIDTH = 65536;
10
+
9
11
  /**
10
12
  * Wrap operation
11
13
  */
@@ -27,6 +29,9 @@ class Wrap extends Operation {
27
29
  "name": "Line Width",
28
30
  "type": "number",
29
31
  "value": 64,
32
+ "min": 1,
33
+ "max": MAX_LINE_WIDTH,
34
+ "integer": true,
30
35
  },
31
36
  ];
32
37
  }
@@ -31,7 +31,10 @@ class XORBruteForce extends Operation {
31
31
  {
32
32
  "name": "Key length",
33
33
  "type": "number",
34
- "value": 1
34
+ "value": 1,
35
+ "min": 1,
36
+ "max": 2,
37
+ "integer": true
35
38
  },
36
39
  {
37
40
  "name": "Sample length",
@@ -7,12 +7,12 @@
7
7
  import Operation from "../Operation.mjs";
8
8
  import Utils from "../Utils.mjs";
9
9
  import { toHex } from "../lib/Hex.mjs";
10
+ import OperationError from "../errors/OperationError.mjs";
10
11
 
11
12
  /**
12
13
  * XOR Checksum operation
13
14
  */
14
15
  class XORChecksum extends Operation {
15
-
16
16
  /**
17
17
  * XORChecksum constructor
18
18
  */
@@ -21,7 +21,8 @@ class XORChecksum extends Operation {
21
21
 
22
22
  this.name = "XOR Checksum";
23
23
  this.module = "Crypto";
24
- this.description = "XOR Checksum splits the input into blocks of a configurable size and performs the XOR operation on these blocks.";
24
+ this.description =
25
+ "XOR Checksum splits the input into blocks of a configurable size and performs the XOR operation on these blocks.";
25
26
  this.infoURL = "https://wikipedia.org/wiki/XOR";
26
27
  this.inputType = "ArrayBuffer";
27
28
  this.outputType = "string";
@@ -29,7 +30,7 @@ class XORChecksum extends Operation {
29
30
  {
30
31
  name: "Blocksize",
31
32
  type: "number",
32
- value: 4
33
+ value: 4,
33
34
  },
34
35
  ];
35
36
  }
@@ -41,6 +42,12 @@ class XORChecksum extends Operation {
41
42
  */
42
43
  run(input, args) {
43
44
  const blocksize = args[0];
45
+
46
+
47
+ if (!Number.isInteger(blocksize) || blocksize <= 0) {
48
+ throw new OperationError("Blocksize must be a positive integer.");
49
+ }
50
+
44
51
  input = new Uint8Array(input);
45
52
 
46
53
  const res = Array(blocksize);
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @author Medjedtxm
3
+ * @copyright Crown Copyright 2026
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 { decryptXTEA, TEA_BLOCK_SIZE } from "../lib/TEA.mjs";
12
+
13
+ /**
14
+ * XTEA Decrypt operation
15
+ */
16
+ class XTEADecrypt extends Operation {
17
+
18
+ /**
19
+ * XTEADecrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "XTEA Decrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "XTEA (eXtended Tiny Encryption Algorithm) is a block cipher designed by David Wheeler and Roger Needham in 1997 as a successor to TEA, correcting several weaknesses identified in the original algorithm. It operates on 64-bit blocks using a 128-bit key with an improved key schedule that uses sum-dependent key word selection to resist related-key attacks.<br><br>XTEA retains the simplicity and compact implementation of TEA whilst providing significantly improved security. It is frequently encountered in malware analysis and CTF challenges due to its straightforward implementation.<br><br><b>Key:</b> Must be exactly 16 bytes (128 bits).<br><br><b>IV:</b> The Initialisation Vector should be 8 bytes (64 bits). If not entered, it will default to null bytes.<br><br><b>Rounds:</b> The recommended number of rounds is 32 (default). The reference implementation by Wheeler &amp; Needham accepts a configurable round count.<br><br><b>Padding:</b> In CBC and ECB mode, the PKCS#5 padding scheme is used.";
27
+ this.infoURL = "https://wikipedia.org/wiki/XTEA";
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": ["Hex", "Raw"]
52
+ },
53
+ {
54
+ "name": "Output",
55
+ "type": "option",
56
+ "value": ["Raw", "Hex"]
57
+ },
58
+ {
59
+ "name": "Padding",
60
+ "type": "option",
61
+ "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
62
+ },
63
+ {
64
+ "name": "Rounds",
65
+ "type": "number",
66
+ "value": 32,
67
+ "min": 1,
68
+ "max": 255
69
+ }
70
+ ];
71
+ }
72
+
73
+ /**
74
+ * @param {string} input
75
+ * @param {Object[]} args
76
+ * @returns {string}
77
+ */
78
+ run(input, args) {
79
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
80
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
81
+ [,, mode, inputType, outputType, padding, rounds] = args;
82
+
83
+ if (key.length !== 16)
84
+ throw new OperationError(`Invalid key length: ${key.length} bytes
85
+
86
+ XTEA requires a key length of 16 bytes (128 bits).
87
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
88
+
89
+ if (iv.length !== TEA_BLOCK_SIZE && iv.length !== 0 && mode !== "ECB")
90
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
91
+
92
+ XTEA uses an IV length of ${TEA_BLOCK_SIZE} bytes (${TEA_BLOCK_SIZE * 8} bits).
93
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
94
+
95
+ if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255)
96
+ throw new OperationError(`Invalid number of rounds: ${rounds}
97
+
98
+ Rounds must be an integer between 1 and 255. Standard XTEA uses 32 rounds.`);
99
+
100
+ // Default IV to null bytes if empty (like AES)
101
+ const actualIv = iv.length === 0 ? new Array(TEA_BLOCK_SIZE).fill(0) : iv;
102
+
103
+ input = Utils.convertToByteArray(input, inputType);
104
+ const output = decryptXTEA(input, key, actualIv, mode, padding, rounds);
105
+ return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
106
+ }
107
+
108
+ }
109
+
110
+ export default XTEADecrypt;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @author Medjedtxm
3
+ * @copyright Crown Copyright 2026
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 { encryptXTEA, TEA_BLOCK_SIZE } from "../lib/TEA.mjs";
12
+
13
+ /**
14
+ * XTEA Encrypt operation
15
+ */
16
+ class XTEAEncrypt extends Operation {
17
+
18
+ /**
19
+ * XTEAEncrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "XTEA Encrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "XTEA (eXtended Tiny Encryption Algorithm) is a block cipher designed by David Wheeler and Roger Needham in 1997 as a successor to TEA, correcting several weaknesses identified in the original algorithm. It operates on 64-bit blocks using a 128-bit key with an improved key schedule that uses sum-dependent key word selection to resist related-key attacks.<br><br>XTEA retains the simplicity and compact implementation of TEA whilst providing significantly improved security. It is frequently encountered in malware analysis and CTF challenges due to its straightforward implementation.<br><br><b>Key:</b> Must be exactly 16 bytes (128 bits).<br><br><b>IV:</b> The Initialisation Vector should be 8 bytes (64 bits). If not entered, it will default to null bytes.<br><br><b>Rounds:</b> The recommended number of rounds is 32 (default). The reference implementation by Wheeler &amp; Needham accepts a configurable round count.<br><br><b>Padding:</b> In CBC and ECB mode, the PKCS#5 padding scheme is used.";
27
+ this.infoURL = "https://wikipedia.org/wiki/XTEA";
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
+ "name": "Padding",
60
+ "type": "option",
61
+ "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
62
+ },
63
+ {
64
+ "name": "Rounds",
65
+ "type": "number",
66
+ "value": 32,
67
+ "min": 1,
68
+ "max": 255
69
+ }
70
+ ];
71
+ }
72
+
73
+ /**
74
+ * @param {string} input
75
+ * @param {Object[]} args
76
+ * @returns {string}
77
+ */
78
+ run(input, args) {
79
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
80
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
81
+ [,, mode, inputType, outputType, padding, rounds] = args;
82
+
83
+ if (key.length !== 16)
84
+ throw new OperationError(`Invalid key length: ${key.length} bytes
85
+
86
+ XTEA requires a key length of 16 bytes (128 bits).
87
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
88
+
89
+ if (iv.length !== TEA_BLOCK_SIZE && iv.length !== 0 && mode !== "ECB")
90
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
91
+
92
+ XTEA uses an IV length of ${TEA_BLOCK_SIZE} bytes (${TEA_BLOCK_SIZE * 8} bits).
93
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
94
+
95
+ if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255)
96
+ throw new OperationError(`Invalid number of rounds: ${rounds}
97
+
98
+ Rounds must be an integer between 1 and 255. Standard XTEA uses 32 rounds.`);
99
+
100
+ // Default IV to null bytes if empty (like AES)
101
+ const actualIv = iv.length === 0 ? new Array(TEA_BLOCK_SIZE).fill(0) : iv;
102
+
103
+ input = Utils.convertToByteArray(input, inputType);
104
+ const output = encryptXTEA(input, key, actualIv, mode, padding, rounds);
105
+ return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
106
+ }
107
+
108
+ }
109
+
110
+ export default XTEAEncrypt;