cyberchef 11.2.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 (134) hide show
  1. package/AGENTS.md +75 -0
  2. package/CHANGELOG.md +147 -1
  3. package/Dockerfile +2 -2
  4. package/Gruntfile.js +1 -0
  5. package/package.json +22 -21
  6. package/src/core/Dish.mjs +1 -5
  7. package/src/core/Ingredient.mjs +92 -0
  8. package/src/core/Operation.mjs +19 -0
  9. package/src/core/Recipe.mjs +4 -0
  10. package/src/core/Utils.mjs +48 -0
  11. package/src/core/config/Categories.json +22 -6
  12. package/src/core/config/OperationConfig.json +4771 -1226
  13. package/src/core/config/modules/Ciphers.mjs +20 -0
  14. package/src/core/config/modules/Crypto.mjs +10 -0
  15. package/src/core/config/modules/Default.mjs +8 -0
  16. package/src/core/config/modules/File.mjs +16 -0
  17. package/src/core/config/modules/OpModules.mjs +2 -0
  18. package/src/core/config/scripts/generateHTMLEntities.mjs +139 -0
  19. package/src/core/config/scripts/htmlEntityOverrides.mjs +86 -0
  20. package/src/core/lib/Arithmetic.mjs +21 -5
  21. package/src/core/lib/BigIntUtils.mjs +0 -1
  22. package/src/core/lib/COBS.mjs +86 -0
  23. package/src/core/lib/Decimal.mjs +5 -5
  24. package/src/core/lib/HTMLEntities.mjs +2068 -0
  25. package/src/core/lib/Present.mjs +422 -0
  26. package/src/core/lib/TEA.mjs +494 -0
  27. package/src/core/lib/TLVParser.mjs +16 -7
  28. package/src/core/lib/Twofish.mjs +608 -0
  29. package/src/core/operations/AsconDecrypt.mjs +112 -0
  30. package/src/core/operations/AsconEncrypt.mjs +108 -0
  31. package/src/core/operations/AsconHash.mjs +49 -0
  32. package/src/core/operations/AsconMAC.mjs +68 -0
  33. package/src/core/operations/AutomatedValidationTestOp.mjs +84 -0
  34. package/src/core/operations/AvroToJSON.mjs +1 -1
  35. package/src/core/operations/BLAKE3.mjs +5 -1
  36. package/src/core/operations/BcryptCompare.mjs +11 -5
  37. package/src/core/operations/BitShiftLeft.mjs +4 -1
  38. package/src/core/operations/Bzip2Compress.mjs +1 -1
  39. package/src/core/operations/DechunkHTTPResponse.mjs +4 -1
  40. package/src/core/operations/ExtendedGCD.mjs +101 -0
  41. package/src/core/operations/FromBase.mjs +2 -1
  42. package/src/core/operations/FromCOBS.mjs +38 -0
  43. package/src/core/operations/FromDecimal.mjs +6 -1
  44. package/src/core/operations/FromHTMLEntity.mjs +2 -1458
  45. package/src/core/operations/GenerateHOTP.mjs +21 -6
  46. package/src/core/operations/GenerateImage.mjs +22 -10
  47. package/src/core/operations/GeneratePrime.mjs +154 -0
  48. package/src/core/operations/GenerateTOTP.mjs +24 -7
  49. package/src/core/operations/Gzip.mjs +1 -3
  50. package/src/core/operations/Jsonata.mjs +12 -0
  51. package/src/core/operations/MIMEDecoding.mjs +1 -1
  52. package/src/core/operations/MOD.mjs +62 -0
  53. package/src/core/operations/ModularInverse.mjs +107 -0
  54. package/src/core/operations/PRESENTDecrypt.mjs +94 -0
  55. package/src/core/operations/PRESENTEncrypt.mjs +94 -0
  56. package/src/core/operations/ParseURI.mjs +18 -5
  57. package/src/core/operations/PseudoRandomNumberGenerator.mjs +2 -1
  58. package/src/core/operations/RandomPrime.mjs +154 -0
  59. package/src/core/operations/RenderPDF.mjs +100 -0
  60. package/src/core/operations/SM4Encrypt.mjs +1 -1
  61. package/src/core/operations/SetDifference.mjs +8 -1
  62. package/src/core/operations/SetIntersection.mjs +8 -1
  63. package/src/core/operations/ShowOnMap.mjs +14 -2
  64. package/src/core/operations/TEADecrypt.mjs +98 -0
  65. package/src/core/operations/TEAEncrypt.mjs +98 -0
  66. package/src/core/operations/ToBase.mjs +4 -4
  67. package/src/core/operations/ToBase32.mjs +20 -4
  68. package/src/core/operations/ToBinary.mjs +4 -1
  69. package/src/core/operations/ToCOBS.mjs +38 -0
  70. package/src/core/operations/ToHTMLEntity.mjs +7 -1430
  71. package/src/core/operations/TwofishDecrypt.mjs +94 -0
  72. package/src/core/operations/TwofishEncrypt.mjs +94 -0
  73. package/src/core/operations/URLEncode.mjs +22 -18
  74. package/src/core/operations/UnescapeUnicodeCharacters.mjs +2 -1
  75. package/src/core/operations/ViewBitPlane.mjs +9 -3
  76. package/src/core/operations/Wrap.mjs +5 -0
  77. package/src/core/operations/XORBruteForce.mjs +4 -1
  78. package/src/core/operations/XORChecksum.mjs +2 -2
  79. package/src/core/operations/XTEADecrypt.mjs +110 -0
  80. package/src/core/operations/XTEAEncrypt.mjs +110 -0
  81. package/src/core/operations/index.mjs +42 -0
  82. package/src/core/vendor/ascon.mjs +162 -0
  83. package/src/core/vendor/htmlEntities/entity.json +2233 -0
  84. package/src/core/vendor/htmlEntities/entity.txt +14 -0
  85. package/src/node/api.mjs +4 -1
  86. package/src/node/index.mjs +105 -0
  87. package/src/web/HTMLOperation.mjs +2 -1
  88. package/src/web/stylesheets/layout/_io.css +8 -0
  89. package/tests/browser/00_nightwatch.js +26 -0
  90. package/tests/browser/02_ops.js +20 -4
  91. package/tests/node/index.mjs +1 -0
  92. package/tests/node/tests/Dish.mjs +19 -0
  93. package/tests/node/tests/NodeDish.mjs +36 -0
  94. package/tests/node/tests/ToHTMLEntity.mjs +82 -0
  95. package/tests/node/tests/Utils.mjs +77 -0
  96. package/tests/node/tests/nodeApi.mjs +33 -1
  97. package/tests/node/tests/operations.mjs +26 -1
  98. package/tests/operations/index.mjs +17 -0
  99. package/tests/operations/tests/Arithmetic.mjs +33 -0
  100. package/tests/operations/tests/Ascon.mjs +501 -0
  101. package/tests/operations/tests/AutomatedValidation.mjs +154 -0
  102. package/tests/operations/tests/BLAKE3.mjs +39 -1
  103. package/tests/operations/tests/Base32.mjs +22 -0
  104. package/tests/operations/tests/COBS.mjs +476 -0
  105. package/tests/operations/tests/CharEnc.mjs +2 -2
  106. package/tests/operations/tests/DechunkHTTPResponse.mjs +66 -0
  107. package/tests/operations/tests/ExtendedGCD.mjs +78 -0
  108. package/tests/operations/tests/FromBase.mjs +66 -0
  109. package/tests/operations/tests/FromDecimal.mjs +55 -0
  110. package/tests/operations/tests/GenerateLoremIpsum.mjs +2 -2
  111. package/tests/operations/tests/Gzip.mjs +60 -0
  112. package/tests/operations/tests/HTMLEntity.mjs +126 -0
  113. package/tests/operations/tests/Hash.mjs +44 -0
  114. package/tests/operations/tests/Hexdump.mjs +1 -1
  115. package/tests/operations/tests/Image.mjs +26 -0
  116. package/tests/operations/tests/Jsonata.mjs +23 -0
  117. package/tests/operations/tests/MIMEDecoding.mjs +33 -0
  118. package/tests/operations/tests/MOD.mjs +208 -0
  119. package/tests/operations/tests/Median.mjs +33 -0
  120. package/tests/operations/tests/ModularInverse.mjs +78 -0
  121. package/tests/operations/tests/OTP.mjs +167 -2
  122. package/tests/operations/tests/PRESENT.mjs +465 -0
  123. package/tests/operations/tests/ParseTLV.mjs +41 -0
  124. package/tests/operations/tests/RenderPDF.mjs +55 -0
  125. package/tests/operations/tests/SM2.mjs +1 -1
  126. package/tests/operations/tests/SetDifference.mjs +22 -0
  127. package/tests/operations/tests/SetIntersection.mjs +23 -1
  128. package/tests/operations/tests/ShowOnMap.mjs +61 -0
  129. package/tests/operations/tests/TEA.mjs +566 -0
  130. package/tests/operations/tests/Twofish.mjs +486 -0
  131. package/tests/operations/tests/URLEncodeDecode.mjs +26 -0
  132. package/tests/operations/tests/UnescapeUnicodeCharacters.mjs +88 -0
  133. package/tests/operations/tests/Wrap.mjs +44 -0
  134. package/webpack.config.js +3 -3
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
+ import OperationError from "../errors/OperationError.mjs";
8
9
  import * as OTPAuth from "otpauth";
9
10
 
10
11
  /**
@@ -19,7 +20,7 @@ class GenerateHOTP extends Operation {
19
20
 
20
21
  this.name = "Generate HOTP";
21
22
  this.module = "Default";
22
- this.description = "The HMAC-based One-Time Password algorithm (HOTP) is an algorithm that computes a one-time password from a shared secret key and an incrementing counter. It has been adopted as Internet Engineering Task Force standard RFC 4226, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated.";
23
+ this.description = "The HMAC-based One-Time Password algorithm (HOTP) is an algorithm that computes a one-time password from a shared secret key and an incrementing counter. It has been adopted as Internet Engineering Task Force standard RFC 4226, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. The secret must be a valid base32 string (characters A–Z and 2–7).";
23
24
  this.infoURL = "https://wikipedia.org/wiki/HMAC-based_One-time_Password_algorithm";
24
25
  this.inputType = "ArrayBuffer";
25
26
  this.outputType = "string";
@@ -27,17 +28,23 @@ class GenerateHOTP extends Operation {
27
28
  {
28
29
  "name": "Name",
29
30
  "type": "string",
30
- "value": ""
31
+ "value": "Account",
32
+ "allowEmpty": false
31
33
  },
32
34
  {
33
35
  "name": "Code length",
34
36
  "type": "number",
35
- "value": 6
37
+ "value": 6,
38
+ "min": 6,
39
+ "max": 8,
40
+ "integer": true
36
41
  },
37
42
  {
38
43
  "name": "Counter",
39
44
  "type": "number",
40
- "value": 0
45
+ "value": 0,
46
+ "min": 0,
47
+ "integer": true
41
48
  }
42
49
  ];
43
50
  }
@@ -47,7 +54,15 @@ class GenerateHOTP extends Operation {
47
54
  */
48
55
  run(input, args) {
49
56
  const secretStr = new TextDecoder("utf-8").decode(input).trim();
50
- const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
57
+
58
+ let secret;
59
+ try {
60
+ secret = secretStr ?
61
+ OTPAuth.Secret.fromBase32(secretStr.toUpperCase().replace(/\s+/g, "")) :
62
+ new OTPAuth.Secret();
63
+ } catch {
64
+ throw new OperationError("Invalid secret. The input must be a valid base32 string (characters A–Z and 2–7).");
65
+ }
51
66
 
52
67
  const hotp = new OTPAuth.HOTP({
53
68
  issuer: "",
@@ -55,7 +70,7 @@ class GenerateHOTP extends Operation {
55
70
  algorithm: "SHA1",
56
71
  digits: args[1],
57
72
  counter: args[2],
58
- secret: OTPAuth.Secret.fromBase32(secret)
73
+ secret
59
74
  });
60
75
 
61
76
  const uri = hotp.toString();
@@ -12,6 +12,14 @@ import { toBase64 } from "../lib/Base64.mjs";
12
12
  import { isWorkerEnvironment } from "../Utils.mjs";
13
13
  import { Jimp, JimpMime, ResizeStrategy, rgbaToInt } from "jimp";
14
14
 
15
+ // arbitrary limits to prevent resource exhaustion
16
+ // scale factor of 64 is big enough to likely result in scaling in the display
17
+ // window anyway
18
+ // pixels per row is harder to come up with a figure that won't inconvenience
19
+ // someone. 2048 feels like a reasonable compromise
20
+ const MAX_PIXEL_SCALE_FACTOR = 64;
21
+ const MAX_PIXELS_PER_ROW = 2048;
22
+
15
23
  /**
16
24
  * Generate Image operation
17
25
  */
@@ -40,11 +48,17 @@ class GenerateImage extends Operation {
40
48
  name: "Pixel Scale Factor",
41
49
  type: "number",
42
50
  value: 8,
51
+ integer: true,
52
+ min: 1,
53
+ max: MAX_PIXEL_SCALE_FACTOR,
43
54
  },
44
55
  {
45
56
  name: "Pixels per row",
46
57
  type: "number",
47
58
  value: 64,
59
+ integer: true,
60
+ min: 1,
61
+ max: MAX_PIXELS_PER_ROW,
48
62
  },
49
63
  ];
50
64
  }
@@ -58,14 +72,6 @@ class GenerateImage extends Operation {
58
72
  const [mode, scale, width] = args;
59
73
  input = new Uint8Array(input);
60
74
 
61
- if (scale <= 0) {
62
- throw new OperationError("Pixel Scale Factor needs to be > 0");
63
- }
64
-
65
- if (width <= 0) {
66
- throw new OperationError("Pixels per Row needs to be > 0");
67
- }
68
-
69
75
  const bytePerPixelMap = {
70
76
  Greyscale: 1,
71
77
  RG: 2,
@@ -74,6 +80,10 @@ class GenerateImage extends Operation {
74
80
  Bits: 1 / 8,
75
81
  };
76
82
 
83
+ if (!Object.hasOwn(bytePerPixelMap, mode)) {
84
+ throw new OperationError(`Unsupported Mode: (${mode})`);
85
+ }
86
+
77
87
  const bytesPerPixel = bytePerPixelMap[mode];
78
88
 
79
89
  if (bytesPerPixel > 0 && input.length % bytesPerPixel !== 0) {
@@ -163,8 +173,10 @@ class GenerateImage extends Operation {
163
173
  }
164
174
 
165
175
  try {
166
- const imageBuffer = await image.getBuffer(JimpMime.png);
167
- return imageBuffer.buffer;
176
+ // see https://nodejs.org/docs/latest-v24.x/api/buffer.html#bufbyteoffset
177
+ // for why we can't just return result.buffer
178
+ const result = await image.getBuffer(JimpMime.png);
179
+ return result.buffer.slice(result.byteOffset, result.byteOffset + result.byteLength);
168
180
  } catch (err) {
169
181
  throw new OperationError(`Error generating image. (${err})`);
170
182
  }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * @author p-leriche [philip.leriche@cantab.net]
3
+ * @copyright Crown Copyright 2025
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import OperationError from "../errors/OperationError.mjs";
9
+ import { modPow } from "../lib/BigIntUtils.mjs";
10
+
11
+ /* ---------- helper functions ---------- */
12
+
13
+ /**
14
+ * Generate random BigInt with specified bit length
15
+ */
16
+ function randBigInt(bits) {
17
+ const bytes = Math.ceil(bits / 8);
18
+ const a = new Uint8Array(bytes);
19
+ crypto.getRandomValues(a);
20
+
21
+ // Set high bit to ensure correct bit length
22
+ a[0] |= 1 << (7 - ((8 * bytes - bits)));
23
+ // Set low bit to ensure odd (primes > 2 are odd)
24
+ a[bytes - 1] |= 1;
25
+
26
+ let h = "";
27
+ for (const b of a) h += b.toString(16).padStart(2, "0");
28
+ return BigInt("0x" + h);
29
+ }
30
+
31
+ /**
32
+ * Miller-Rabin primality test
33
+ */
34
+ function isProbablePrime(n, rounds) {
35
+ if (n < 2n) return false;
36
+ if (n === 2n || n === 3n) return true;
37
+ if (n % 2n === 0n) return false;
38
+
39
+ // Write n-1 as 2^r * d
40
+ let d = n - 1n;
41
+ let r = 0n;
42
+ while (d % 2n === 0n) {
43
+ d /= 2n;
44
+ r++;
45
+ }
46
+
47
+ // Witness loop
48
+ for (let i = 0; i < rounds; i++) {
49
+ const a = randBigInt(n.toString(2).length - 1) % (n - 3n) + 2n;
50
+ let x = modPow(a, d, n);
51
+
52
+ if (x === 1n || x === n - 1n) continue;
53
+
54
+ let composite = true;
55
+ for (let j = 0n; j < r - 1n; j++) {
56
+ x = modPow(x, 2n, n);
57
+ if (x === n - 1n) {
58
+ composite = false;
59
+ break;
60
+ }
61
+ }
62
+
63
+ if (composite) return false;
64
+ }
65
+
66
+ return true;
67
+ }
68
+
69
+ /* ---------- operation class ---------- */
70
+
71
+ /**
72
+ * Generate Prime Number operation
73
+ */
74
+ class GeneratePrime extends Operation {
75
+ /**
76
+ * GeneratePrime constructor
77
+ */
78
+ constructor() {
79
+ super();
80
+
81
+ this.name = "Pseudo-Random Prime Generator";
82
+ this.module = "Crypto";
83
+ this.description =
84
+ "Generates a random probable prime number of specified bit length using the Miller-Rabin primality test.<br><br>" +
85
+ "<b>Primality guarantee:</b><br>" +
86
+ "For numbers . 3,317, the result is guaranteed prime (deterministic test).<br>" +
87
+ "For larger numbers, uses probabilistic testing:<br>" +
88
+ "- <b>Standard (7 rounds):</b> Probability of composite approx 1 in 16,000)<br><br>" +
89
+ "- <b>Crypto grade (40 rounds):</b> Probability of composite(approx 1 in 10^24)<br>" +
90
+ "Crypto grade is recommended for cryptographic applications (RSA, Diffie-Hellman, etc.).<br><br>" ;
91
+ this.infoURL = "https://wikipedia.org/wiki/Miller-Rabin_primality_test";
92
+ this.inputType = "string";
93
+ this.outputType = "string";
94
+ this.args = [
95
+ {
96
+ name: "Bit length",
97
+ type: "number",
98
+ value: 512,
99
+ min: 2
100
+ },
101
+ {
102
+ name: "Crypto grade",
103
+ type: "boolean",
104
+ value: false
105
+ },
106
+ {
107
+ name: "Output format",
108
+ type: "option",
109
+ value: ["Decimal", "Hexadecimal"]
110
+ }
111
+ ];
112
+ }
113
+
114
+ /**
115
+ * @param {string} input
116
+ * @param {Object[]} args
117
+ * @returns {string}
118
+ */
119
+ run(input, args) {
120
+ const [bits, cryptoGrade, outputFormat] = args;
121
+
122
+ if (bits < 2) {
123
+ throw new OperationError("Bit length must be at least 2");
124
+ }
125
+
126
+ if (bits > 4096) {
127
+ throw new OperationError("Bit length limited to 4096 bits for performance reasons");
128
+ }
129
+
130
+ const rounds = cryptoGrade ? 40 : 7;
131
+ let attempts = 0;
132
+ const maxAttempts = 10000;
133
+
134
+ let n = randBigInt(bits);
135
+
136
+ while (!isProbablePrime(n, rounds)) {
137
+ n = randBigInt(bits);
138
+ attempts++;
139
+
140
+ if (attempts > maxAttempts) {
141
+ throw new OperationError(`Failed to generate prime after ${maxAttempts} attempts. Try a different bit length.`);
142
+ }
143
+ }
144
+
145
+ // Return only the prime for pipeability
146
+ if (outputFormat === "Hexadecimal") {
147
+ return "0x" + n.toString(16);
148
+ } else {
149
+ return n.toString();
150
+ }
151
+ }
152
+ }
153
+
154
+ export default GeneratePrime;
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
+ import OperationError from "../errors/OperationError.mjs";
8
9
  import * as OTPAuth from "otpauth";
9
10
 
10
11
  /**
@@ -18,7 +19,7 @@ class GenerateTOTP extends Operation {
18
19
  super();
19
20
  this.name = "Generate TOTP";
20
21
  this.module = "Default";
21
- this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
22
+ this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. The secret must be a valid base32 string (characters A–Z and 2–7). T0 and T1 are in seconds.";
22
23
  this.infoURL = "https://wikipedia.org/wiki/Time-based_One-time_Password_algorithm";
23
24
  this.inputType = "ArrayBuffer";
24
25
  this.outputType = "string";
@@ -26,22 +27,30 @@ class GenerateTOTP extends Operation {
26
27
  {
27
28
  "name": "Name",
28
29
  "type": "string",
29
- "value": ""
30
+ "value": "Account",
31
+ "allowEmpty": false
30
32
  },
31
33
  {
32
34
  "name": "Code length",
33
35
  "type": "number",
34
- "value": 6
36
+ "value": 6,
37
+ "min": 6,
38
+ "max": 8,
39
+ "integer": true
35
40
  },
36
41
  {
37
42
  "name": "Epoch offset (T0)",
38
43
  "type": "number",
39
- "value": 0
44
+ "value": 0,
45
+ "min": 0,
46
+ "integer": true
40
47
  },
41
48
  {
42
49
  "name": "Interval (T1)",
43
50
  "type": "number",
44
- "value": 30
51
+ "value": 30,
52
+ "min": 1,
53
+ "integer": true
45
54
  }
46
55
  ];
47
56
  }
@@ -51,7 +60,15 @@ class GenerateTOTP extends Operation {
51
60
  */
52
61
  run(input, args) {
53
62
  const secretStr = new TextDecoder("utf-8").decode(input).trim();
54
- const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
63
+
64
+ let secret;
65
+ try {
66
+ secret = secretStr ?
67
+ OTPAuth.Secret.fromBase32(secretStr.toUpperCase().replace(/\s+/g, "")) :
68
+ new OTPAuth.Secret();
69
+ } catch {
70
+ throw new OperationError("Invalid secret. The input must be a valid base32 string (characters A–Z and 2–7).");
71
+ }
55
72
 
56
73
  const totp = new OTPAuth.TOTP({
57
74
  issuer: "",
@@ -60,7 +77,7 @@ class GenerateTOTP extends Operation {
60
77
  digits: args[1],
61
78
  period: args[3],
62
79
  epoch: args[2] * 1000, // Convert seconds to milliseconds
63
- secret: OTPAuth.Secret.fromBase32(secret)
80
+ secret
64
81
  });
65
82
 
66
83
  const uri = totp.toString();
@@ -74,13 +74,11 @@ class Gzip extends Operation {
74
74
  }
75
75
  if (comment.length) {
76
76
  options.flags.comment = true;
77
+ options.flags.fcomment = true;
77
78
  options.comment = comment;
78
79
  }
79
80
  const gzipObj = new Zlib.Gzip(new Uint8Array(input), options);
80
81
  const compressed = new Uint8Array(gzipObj.compress());
81
- if (options.flags.comment && !(compressed[3] & 0x10)) {
82
- compressed[3] |= 0x10;
83
- }
84
82
  return compressed.buffer;
85
83
  }
86
84
 
@@ -51,6 +51,18 @@ class JsonataQuery extends Operation {
51
51
 
52
52
  try {
53
53
  const expression = jsonata(query);
54
+ // Override built-in base64 functions which fail in Web Worker
55
+ // context where `window` is undefined. The jsonata library falls
56
+ // back to `global.Buffer` which also does not exist in workers.
57
+ // `atob`/`btoa` are available in both browser and worker scopes.
58
+ expression.registerFunction("base64decode", (str) => {
59
+ if (typeof str === "undefined") return undefined;
60
+ return atob(str);
61
+ }, "<s-:s>");
62
+ expression.registerFunction("base64encode", (str) => {
63
+ if (typeof str === "undefined") return undefined;
64
+ return btoa(str);
65
+ }, "<s-:s>");
54
66
  result = await expression.evaluate(jsonObj);
55
67
  } catch (err) {
56
68
  throw new OperationError(
@@ -87,7 +87,7 @@ class MIMEDecoding extends Operation {
87
87
  end = cur + j + "?=".length;
88
88
 
89
89
  if (encoding.toLowerCase() === "b") {
90
- text = fromBase64(text);
90
+ text = fromBase64(text, undefined, "byteArray");
91
91
  } else if (encoding.toLowerCase() === "q") {
92
92
  text = this.parseQEncodedWord(text);
93
93
  } else {
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ */
4
+
5
+ import BigNumber from "bignumber.js";
6
+ import Operation from "../Operation.mjs";
7
+ import { createNumArray } from "../lib/Arithmetic.mjs";
8
+ import { ARITHMETIC_DELIM_OPTIONS } from "../lib/Delim.mjs";
9
+
10
+
11
+ /**
12
+ * MOD operation
13
+ */
14
+ class MOD extends Operation {
15
+
16
+ /**
17
+ * MOD constructor
18
+ */
19
+ constructor() {
20
+ super();
21
+
22
+ this.name = "MOD";
23
+ this.module = "Default";
24
+ this.description = "Computes the modulo of each number in a list with a given modulus value. Numbers are extracted from the input based on the delimiter, and non-numeric values are ignored.<br><br>e.g. <code>15 4 7</code> with modulus <code>3</code> becomes <code>0 1 1</code>";
25
+ this.inputType = "string";
26
+ this.outputType = "string";
27
+ this.args = [
28
+ {
29
+ "name": "Modulus",
30
+ "type": "number",
31
+ "value": 2
32
+ },
33
+ {
34
+ "name": "Delimiter",
35
+ "type": "option",
36
+ "value": ARITHMETIC_DELIM_OPTIONS,
37
+ }
38
+ ];
39
+ }
40
+
41
+ /**
42
+ * @param {string} input
43
+ * @param {Object[]} args
44
+ * @returns {string}
45
+ */
46
+ run(input, args) {
47
+ const modulus = new BigNumber(args[0]);
48
+ const delimiter = args[1];
49
+
50
+ if (modulus.isZero()) {
51
+ throw new Error("Modulus cannot be zero");
52
+ }
53
+
54
+ const numbers = createNumArray(input, delimiter);
55
+ const results = numbers.map(num => num.mod(modulus));
56
+
57
+ return results.join(" ");
58
+ }
59
+
60
+ }
61
+
62
+ export default MOD;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @author p-leriche [philip.leriche@cantab.net]
3
+ * @copyright Crown Copyright 2025
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import OperationError from "../errors/OperationError.mjs";
9
+ import { parseBigInt, egcd } from "../lib/BigIntUtils.mjs";
10
+
11
+
12
+ /* ---------- operation class ---------- */
13
+
14
+ /**
15
+ * Modular Inverse operation
16
+ */
17
+ class ModularInverse extends Operation {
18
+
19
+ /**
20
+ * ModularInverse constructor
21
+ */
22
+ constructor() {
23
+ super();
24
+
25
+ this.name = "Modular Inverse";
26
+ this.module = "Crypto";
27
+ this.description =
28
+ "Computes the modular multiplicative inverse of <i>a</i> modulo <i>m</i>.<br><br>" +
29
+ "Finds <i>x</i> such that a*x = 1 (mod m).<br><br>" +
30
+ "<b>Input handling:</b> If either <i>a</i> or <i>m</i> is left blank, " +
31
+ "its value is taken from the Input field.";
32
+ this.infoURL = "https://wikipedia.org/wiki/Modular_multiplicative_inverse";
33
+ this.inputType = "string";
34
+ this.outputType = "string";
35
+ this.args = [
36
+ {
37
+ name: "Value (a)",
38
+ type: "string",
39
+ value: ""
40
+ },
41
+ {
42
+ name: "Modulus (m)",
43
+ type: "string",
44
+ value: ""
45
+ }
46
+ ];
47
+ }
48
+
49
+ /**
50
+ * @param {string} input
51
+ * @param {Object[]} args
52
+ * @returns {string}
53
+ */
54
+ run(input, args) {
55
+ const [aStr, mStr] = args;
56
+
57
+ // Trim everything so "" and " " count as empty
58
+ const aParam = aStr?.trim();
59
+ const mParam = mStr?.trim();
60
+ const inputVal = input?.trim();
61
+
62
+ let a, m;
63
+
64
+ if (aParam && mParam) {
65
+ // Case 1: value and modulus both given as parameters
66
+ a = aParam;
67
+ m = mParam;
68
+ } else if (!aParam && mParam) {
69
+ // Case 2: value missing - take from input
70
+ a = inputVal;
71
+ m = mParam;
72
+ if (!a) throw new OperationError("Value (a) must be defined");
73
+ } else if (aParam && !mParam) {
74
+ // Case 3: modulus missing - take from input
75
+ a = aParam;
76
+ m = inputVal;
77
+ if (!m) throw new OperationError("Modulus (m) must be defined");
78
+ } else if (!aParam && !mParam) {
79
+ // Case 4: value and modulus both missing
80
+ throw new OperationError("Value (a) and Modulus (m) must be defined");
81
+ }
82
+
83
+ const aBI = parseBigInt(a, "Value (a)");
84
+ const mBI = parseBigInt(m, "Modulus (m)");
85
+
86
+ if (mBI <= 0n) {
87
+ throw new OperationError("Modulus must be greater than zero");
88
+ }
89
+
90
+ const aNorm = ((aBI % mBI) + mBI) % mBI;
91
+ const [g, x] = egcd(aNorm, mBI);
92
+
93
+ if (g !== 1n && g !== -1n) {
94
+ throw new OperationError("Inverse does not exist because gcd(a, m) ≠ 1");
95
+ }
96
+
97
+ let inv = x;
98
+ if (g === -1n) inv = -inv;
99
+
100
+ inv = ((inv % mBI) + mBI) % mBI;
101
+
102
+
103
+ return inv.toString();
104
+ }
105
+ }
106
+
107
+ export default ModularInverse;
@@ -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 { decryptPRESENT } from "../lib/Present.mjs";
12
+
13
+ /**
14
+ * PRESENT Decrypt operation
15
+ */
16
+ class PRESENTDecrypt extends Operation {
17
+
18
+ /**
19
+ * PRESENTDecrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "PRESENT Decrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "PRESENT is an ultra-lightweight block cipher designed for constrained environments such as RFID tags and sensor networks. It operates on 64-bit blocks and supports 80-bit or 128-bit keys with 31 rounds. Standardised in ISO/IEC 29192-2:2019.<br><br>When using CBC mode, the PKCS#7 padding scheme is used.";
27
+ this.infoURL = "https://wikipedia.org/wiki/PRESENT_(cipher)";
28
+ this.inputType = "string";
29
+ this.outputType = "string";
30
+ this.args = [
31
+ {
32
+ "name": "Key",
33
+ "type": "toggleString",
34
+ "value": "",
35
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
36
+ },
37
+ {
38
+ "name": "IV",
39
+ "type": "toggleString",
40
+ "value": "",
41
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
42
+ },
43
+ {
44
+ "name": "Mode",
45
+ "type": "option",
46
+ "value": ["CBC", "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 !== 10 && key.length !== 16)
77
+ throw new OperationError(`Invalid key length: ${key.length} bytes
78
+
79
+ PRESENT uses a key length of 10 bytes (80 bits) or 16 bytes (128 bits).`);
80
+
81
+ if (iv.length !== 8 && mode !== "ECB")
82
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
83
+
84
+ PRESENT uses an IV length of 8 bytes (64 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 = decryptPRESENT(input, key, iv, mode, padding);
89
+ return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
90
+ }
91
+
92
+ }
93
+
94
+ export default PRESENTDecrypt;