cyberchef 10.22.0 → 10.23.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 (121) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/CONTRIBUTING.md +37 -0
  3. package/Dockerfile +2 -0
  4. package/Gruntfile.js +0 -12
  5. package/README.md +1 -1
  6. package/babel.config.js +0 -6
  7. package/package.json +63 -62
  8. package/src/core/Chef.mjs +8 -1
  9. package/src/core/Ingredient.mjs +5 -2
  10. package/src/core/Operation.mjs +6 -1
  11. package/src/core/Recipe.mjs +10 -5
  12. package/src/core/config/Categories.json +18 -3
  13. package/src/core/config/OperationConfig.json +22310 -0
  14. package/src/core/config/modules/Bletchley.mjs +28 -0
  15. package/src/core/config/modules/Charts.mjs +24 -0
  16. package/src/core/config/modules/Ciphers.mjs +128 -0
  17. package/src/core/config/modules/Code.mjs +60 -0
  18. package/src/core/config/modules/Compression.mjs +52 -0
  19. package/src/core/config/modules/Crypto.mjs +134 -0
  20. package/src/core/config/modules/Default.mjs +424 -0
  21. package/src/core/config/modules/Diff.mjs +16 -0
  22. package/src/core/config/modules/Encodings.mjs +42 -0
  23. package/src/core/config/modules/Handlebars.mjs +16 -0
  24. package/src/core/config/modules/Hashing.mjs +30 -0
  25. package/src/core/config/modules/Image.mjs +70 -0
  26. package/src/core/config/modules/Jq.mjs +16 -0
  27. package/src/core/config/modules/OCR.mjs +16 -0
  28. package/src/core/config/modules/OpModules.mjs +63 -0
  29. package/src/core/config/modules/PGP.mjs +26 -0
  30. package/src/core/config/modules/Protobuf.mjs +18 -0
  31. package/src/core/config/modules/PublicKey.mjs +36 -0
  32. package/src/core/config/modules/Regex.mjs +40 -0
  33. package/src/core/config/modules/Serialise.mjs +26 -0
  34. package/src/core/config/modules/Shellcode.mjs +18 -0
  35. package/src/core/config/modules/URL.mjs +20 -0
  36. package/src/core/config/modules/UserAgent.mjs +16 -0
  37. package/src/core/config/modules/Yara.mjs +16 -0
  38. package/src/core/lib/AudioBytes.mjs +103 -0
  39. package/src/core/lib/AudioMetaSchema.mjs +82 -0
  40. package/src/core/lib/AudioParsers.mjs +630 -0
  41. package/src/core/lib/BigIntUtils.mjs +73 -0
  42. package/src/core/lib/Modhex.mjs +2 -0
  43. package/src/core/lib/QRCode.mjs +30 -10
  44. package/src/core/lib/RC6.mjs +625 -0
  45. package/src/core/operations/A1Z26CipherDecode.mjs +1 -1
  46. package/src/core/operations/AddTextToImage.mjs +116 -64
  47. package/src/core/operations/BlurImage.mjs +10 -12
  48. package/src/core/operations/ContainImage.mjs +50 -40
  49. package/src/core/operations/ConvertImageFormat.mjs +33 -39
  50. package/src/core/operations/CoverImage.mjs +39 -37
  51. package/src/core/operations/CropImage.mjs +35 -21
  52. package/src/core/operations/DisassembleARM.mjs +193 -0
  53. package/src/core/operations/DitherImage.mjs +8 -8
  54. package/src/core/operations/EscapeUnicodeCharacters.mjs +0 -17
  55. package/src/core/operations/ExtractAudioMetadata.mjs +175 -0
  56. package/src/core/operations/ExtractLSB.mjs +17 -11
  57. package/src/core/operations/ExtractRGBA.mjs +12 -10
  58. package/src/core/operations/FlaskSessionDecode.mjs +80 -0
  59. package/src/core/operations/FlaskSessionSign.mjs +89 -0
  60. package/src/core/operations/FlaskSessionVerify.mjs +136 -0
  61. package/src/core/operations/FlipImage.mjs +14 -10
  62. package/src/core/operations/GenerateImage.mjs +39 -32
  63. package/src/core/operations/ImageBrightnessContrast.mjs +10 -10
  64. package/src/core/operations/ImageFilter.mjs +14 -13
  65. package/src/core/operations/ImageHueSaturationLightness.mjs +22 -20
  66. package/src/core/operations/ImageOpacity.mjs +6 -8
  67. package/src/core/operations/InvertImage.mjs +4 -6
  68. package/src/core/operations/Jq.mjs +12 -4
  69. package/src/core/operations/NormaliseImage.mjs +5 -7
  70. package/src/core/operations/OffsetChecker.mjs +1 -1
  71. package/src/core/operations/ParseEthernetFrame.mjs +112 -0
  72. package/src/core/operations/ParseIPv4Header.mjs +23 -6
  73. package/src/core/operations/ParseQRCode.mjs +13 -13
  74. package/src/core/operations/PseudoRandomIntegerGenerator.mjs +164 -0
  75. package/src/core/operations/RC6Decrypt.mjs +119 -0
  76. package/src/core/operations/RC6Encrypt.mjs +119 -0
  77. package/src/core/operations/RandomizeColourPalette.mjs +11 -11
  78. package/src/core/operations/ResizeImage.mjs +30 -23
  79. package/src/core/operations/RotateImage.mjs +8 -9
  80. package/src/core/operations/SQLBeautify.mjs +21 -3
  81. package/src/core/operations/SharpenImage.mjs +94 -62
  82. package/src/core/operations/SplitColourChannels.mjs +47 -21
  83. package/src/core/operations/TextIntegerConverter.mjs +123 -0
  84. package/src/core/operations/UnescapeUnicodeCharacters.mjs +17 -0
  85. package/src/core/operations/ViewBitPlane.mjs +16 -20
  86. package/src/core/operations/index.mjs +960 -0
  87. package/src/node/index.mjs +2423 -0
  88. package/src/web/HTMLIngredient.mjs +24 -43
  89. package/src/web/Manager.mjs +1 -0
  90. package/src/web/html/index.html +6 -6
  91. package/src/web/static/fonts/bmfonts/Roboto72White.fnt +491 -485
  92. package/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +494 -488
  93. package/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +110 -103
  94. package/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +498 -492
  95. package/src/web/stylesheets/layout/_banner.css +30 -0
  96. package/src/web/stylesheets/layout/_modals.css +5 -0
  97. package/src/web/stylesheets/utils/_overrides.css +7 -0
  98. package/src/web/waiters/ControlsWaiter.mjs +82 -0
  99. package/src/web/waiters/InputWaiter.mjs +12 -6
  100. package/src/web/waiters/RecipeWaiter.mjs +2 -2
  101. package/tests/browser/02_ops.js +23 -3
  102. package/tests/node/index.mjs +1 -0
  103. package/tests/node/tests/lib/BigIntUtils.mjs +150 -0
  104. package/tests/node/tests/operations.mjs +9 -7
  105. package/tests/operations/index.mjs +8 -0
  106. package/tests/operations/tests/A1Z26CipherDecode.mjs +33 -0
  107. package/tests/operations/tests/DisassembleARM.mjs +377 -0
  108. package/tests/operations/tests/ExtractAudioMetadata.mjs +287 -0
  109. package/tests/operations/tests/FlaskSession.mjs +246 -0
  110. package/tests/operations/tests/GenerateQRCode.mjs +67 -0
  111. package/tests/operations/tests/JWTSign.mjs +83 -8
  112. package/tests/operations/tests/Jq.mjs +32 -0
  113. package/tests/operations/tests/Modhex.mjs +20 -0
  114. package/tests/operations/tests/ParseEthernetFrame.mjs +45 -0
  115. package/tests/operations/tests/RC6.mjs +487 -0
  116. package/tests/operations/tests/SQLBeautify.mjs +54 -0
  117. package/tests/operations/tests/TextIntegerConverter.mjs +199 -0
  118. package/tests/samples/Audio.mjs +73 -0
  119. package/tests/samples/Images.mjs +0 -12
  120. package/webpack.config.js +10 -7
  121. package/src/core/lib/ImageManipulation.mjs +0 -251
@@ -26,6 +26,36 @@
26
26
  color: var(--banner-url-colour);
27
27
  }
28
28
 
29
+ #options:focus {
30
+ background-color: #eef3ec;
31
+ border: solid black 2px;
32
+ border-radius: 4px;
33
+ }
34
+
35
+ #support:focus {
36
+ background-color: #eef3ec;
37
+ border: solid black 2px;
38
+ border-radius: 4px;
39
+ }
40
+
41
+ #notice:focus {
42
+ background-color: #eef3ec;
43
+ border: solid black 2px;
44
+ border-radius: 4px;
45
+ }
46
+
47
+ #banner .col a:focus {
48
+ background-color: #eef3ec;
49
+ border: solid black 2px;
50
+ border-radius: 4px;
51
+ }
52
+
53
+ #notice-wrapper #notice:focus {
54
+ background-color: #eef3ec;
55
+ border: solid black 2px;
56
+ border-radius: 4px;
57
+ }
58
+
29
59
  #notice-wrapper {
30
60
  text-align: center;
31
61
  overflow: hidden;
@@ -78,6 +78,11 @@
78
78
  border-left: 2px solid var(--primary-border-colour);
79
79
  }
80
80
 
81
+ p a:focus {
82
+ color: #0a6ebd;
83
+ text-decoration: underline;
84
+ }
85
+
81
86
  .checkbox label input[type=checkbox]+.checkbox-decorator .check,
82
87
  .checkbox label input[type=checkbox]+.checkbox-decorator .check::before {
83
88
  border-color: var(--input-border-colour);
@@ -249,6 +249,13 @@ optgroup {
249
249
  }
250
250
 
251
251
 
252
+ /* Bootstrap form inside CodeMirror editor */
253
+
254
+ .cm-panel > .bmd-form-group {
255
+ padding-top: 0;
256
+ }
257
+
258
+
252
259
  /* CodeMirror */
253
260
 
254
261
  .ͼ2 .cm-specialChar,
@@ -57,6 +57,18 @@ class ControlsWaiter {
57
57
  }
58
58
  }
59
59
 
60
+ /**
61
+ * Checks or unchecks the Auto Bake checkbox with "Enter"
62
+ * @param {Event} ev
63
+ */
64
+ autoBakeKeyboardHandler(ev) {
65
+ const checkBox = document.getElementById("auto-bake");
66
+ ev.preventDefault();
67
+ if (ev.key === "Enter" || ev.key === " ") {
68
+ checkBox.checked = !checkBox.checked;
69
+ }
70
+ }
71
+
60
72
 
61
73
  /**
62
74
  * Handler to trigger baking.
@@ -387,6 +399,18 @@ class ControlsWaiter {
387
399
  */
388
400
  supportButtonClick(e) {
389
401
  e.preventDefault();
402
+ const faqs = document.getElementById("faqs");
403
+ const faqsAElement = faqs.getElementsByTagName("a");
404
+ for (let i = 0; i < faqsAElement.length; i++) {
405
+ faqsAElement[i].setAttribute("tabindex", "0");
406
+ faqsAElement[i].addEventListener("keydown", this.navigateFAQList, false);
407
+ }
408
+
409
+ const tabs = document.querySelectorAll('[role="tab"]');
410
+
411
+ for (let i = 0; i < tabs.length; i++) {
412
+ tabs[i].addEventListener("keydown", this.changeTabs, false);
413
+ }
390
414
 
391
415
  const reportBugInfo = document.getElementById("report-bug-info");
392
416
  const saveLink = this.generateStateUrl(true, true, null, null, "https://gchq.github.io/CyberChef/");
@@ -403,6 +427,64 @@ ${navigator.userAgent}
403
427
  }
404
428
 
405
429
 
430
+ /**
431
+ * @param {Event} ev
432
+ */
433
+ changeTabs(ev) {
434
+ const tab = ev.target;
435
+ ev.preventDefault();
436
+ ev.stopPropagation();
437
+
438
+ if (ev.key === "ArrowRight") {
439
+ const nextTab = tab.parentElement;
440
+ if (nextTab.nextElementSibling === null) {
441
+ tab.parentElement.parentElement.firstElementChild.firstElementChild.focus();
442
+ } else {
443
+ nextTab.nextElementSibling.firstElementChild.focus();
444
+ }
445
+
446
+ } else if (ev.key === "ArrowLeft") {
447
+ const prevTab = tab.parentElement;
448
+
449
+ if (prevTab.previousElementSibling === null) {
450
+ tab.parentElement.parentElement.lastElementChild.firstElementChild.focus();
451
+ } else {
452
+ prevTab.previousElementSibling.firstElementChild.focus();
453
+ }
454
+ } else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-1")) {
455
+ document.getElementById("faqs").querySelector("[class='btn btn-primary']").focus();
456
+ } else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-2")) {
457
+ document.getElementById("report-bug").querySelector("[class='btn btn-primary']").focus();
458
+ } else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-3")) {
459
+ document.getElementById("about").querySelector("[href]").focus();
460
+ } else if (ev.key === "Tab" && !ev.shiftKey && ev.target === document.getElementById("tab-4")) {
461
+ const button = document.getElementById("support-modal").getElementsByClassName("modal-footer");
462
+ const close = button[0].firstElementChild;
463
+ close.focus();
464
+ } else if (ev.key === "Enter" || ev.key === "Space" || ev.key === " ") {
465
+ tab.click();
466
+ }
467
+ }
468
+
469
+ /**
470
+ * @param {Event} ev
471
+ */
472
+ navigateFAQList(ev) {
473
+
474
+ const el = ev.target.nextElementSibling;
475
+ if (ev.key === "Enter" || ev.key === "Space" || ev.key === " ") {
476
+ ev.preventDefault();
477
+ const question = el.classList;
478
+ if (question !== undefined && question.value) {
479
+ if (!question.value.includes("show")) {
480
+ question.add("show");
481
+ } else if (question.contains("show")) {
482
+ question.remove("show");
483
+ }
484
+ }
485
+ }
486
+ }
487
+
406
488
  /**
407
489
  * Shows the stale indicator to show that the input or recipe has changed
408
490
  * since the last bake.
@@ -153,16 +153,22 @@ class InputWaiter {
153
153
  paste(event, view) {
154
154
  const clipboardData = event.clipboardData;
155
155
  const items = clipboardData.items;
156
- const files = [];
156
+ let files = [];
157
157
  for (let i = 0; i < items.length; i++) {
158
158
  const item = items[i];
159
- if (item.kind === "file") {
160
- const file = item.getAsFile();
161
- files.push(file);
162
-
163
- event.preventDefault(); // Prevent the default paste behavior
159
+ if (item.kind === "string") {
160
+ // If there are any string items they should be preferred over
161
+ // files.
162
+ files = [];
163
+ break;
164
+ } else if (item.kind === "file") {
165
+ files.push(item.getAsFile());
164
166
  }
165
167
  }
168
+ if (files.length > 0) {
169
+ // Prevent the default paste behavior, afterPaste will load the files instead
170
+ event.preventDefault();
171
+ }
166
172
  setTimeout(() => {
167
173
  self.afterPaste(files);
168
174
  });
@@ -417,6 +417,8 @@ class RecipeWaiter {
417
417
  el.classList.add("flow-control-op");
418
418
  }
419
419
 
420
+ $(el).find("[data-toggle='tooltip']").tooltip();
421
+
420
422
  // Disable auto-bake if this is a manual op
421
423
  if (op.manualBake && this.app.autoBake_) {
422
424
  this.manager.controls.setAutoBake(false);
@@ -442,8 +444,6 @@ class RecipeWaiter {
442
444
  this.buildRecipeOperation(item);
443
445
  document.getElementById("rec-list").appendChild(item);
444
446
 
445
- $(item).find("[data-toggle='tooltip']").tooltip();
446
-
447
447
  item.dispatchEvent(this.manager.operationadd);
448
448
  return item;
449
449
  }
@@ -34,7 +34,14 @@ module.exports = {
34
34
  testOp(browser, "AES Encrypt", "test input", "e42eb8fbfb7a98fff061cd2c1a794d92", [{"option": "Hex", "string": "00112233445566778899aabbccddeeff"}, {"option": "Hex", "string": "00000000000000000000000000000000"}, "CBC", "Raw", "Hex"]);
35
35
  testOp(browser, "AND", "test input", "4$04 $044", [{ "option": "Hex", "string": "34" }]);
36
36
  testOp(browser, "Add line numbers", "test input", "1 test input");
37
- testOp(browser, ["From Hex", "Add Text To Image", "To Base64"], Images.PNG_HEX, Images.PNG_CHEF_B64, [[], ["Chef", "Center", "Middle", 0, 0, 16], []]);
37
+ testOp(browser, ["From Hex", "Add Text To Image", "SHA2"], Images.PNG_HEX, "50cdf8ea483c55564a091650c2bccb4586f919b721e5fe9d6a61660505b4346d6ebdb2ef0cf075a7728cd84cb26ea3e477b5bd86a94a49a27d79423994afb60a", [[], ["Chef", "Center", "Middle", 0, 0, 16, "Roboto"], []]);
38
+ testOp(browser, ["From Hex", "Add Text To Image", "SHA2"], Images.PNG_HEX, "78b3055463d9167dd039e47f451acaf06c593d209f8e405b4e18011cdcf190dc0af5952be887d93c0ebd38738e978120c1294c71104e6b00d3f9de8d6320ec1c", [[], ["Chef", "Center", "Middle", 0, 0, 16, "Roboto Black"], []]);
39
+ testOp(browser, ["From Hex", "Add Text To Image", "SHA2"], Images.PNG_HEX, "4ab4d4b6cb22ad700f6cd144c2c8ecad2a094f21a1d1d5d48eb6c8f97417192f89b4512f6a78276d49668ebef5e89c3a4d14860cb79399a0dafce98c92209e07", [[], ["Chef", "Center", "Middle", 0, 0, 16, "Roboto Mono"], []]);
40
+ testOp(browser, ["From Hex", "Add Text To Image", "SHA2"], Images.PNG_HEX, "11490db4907516b4d9e256da1ac0b02b561fa7547971e6316a8a0b90c9c66585a11f3145672c6d972b1a221d3bfad9c8a97de7ff77fd9442ebc40f39c1ef9ef7", [[], ["Chef", "Center", "Middle", 0, 0, 16, "Roboto Slab"], []]);
41
+ testOp(browser, ["From Hex", "Dither Image", "SHA2"], Images.PNG_HEX, "cbf587a78915cfb14546ba83080b13e5054800802488dd0cb786b8951e7dc0b48f055260917bd0ccfc075e422b9d6aff112948562653995d74e70f0b66367ac3", [[], [], []]);
42
+ testOp(browser, ["From Hex", "Generate Image", "SHA2"], Images.PNG_HEX, "2c451762a6c9192fd31dc80765eab3f447be70ea51f6fdb6911ade4d89d4a98bd0a1ff00b08d76aac472faeceb54b66092e3f3be7bbf899bf3e55ca9c96a56aa", [[], [], []]);
43
+ testOp(browser, ["From Hex", "Image Hue/Saturation/Lightness", "SHA2"], Images.PNG_HEX, "522dfc0bbef00e05c5d6861a002039fa2952e4bbb7fe8d21d0d538ef6f9d65da82065929b4150dc5b8b49460ee6c9bef7f660b86f8d4e7442a07c61c0a152a4b", [[], [50, 50, 50], []]);
44
+ testOp(browser, ["From Hex", "Resize Image", "SHA2"], Images.PNG_HEX, "654bfbf0a0537c901459c4bc22c5fb0bacbf01af775a0733e3a1c46cda5b699bcc4ed85322d813c7bb9b245d62d64425c0766fe03d3d20bc63634e2a4df17626", [[], [64, 64], []]);
38
45
  testOp(browser, "Adler-32 Checksum", "test input", "16160411");
39
46
  testOp(browser, "Affine Cipher Decode", "test input", "rcqr glnsr", [1, 2]);
40
47
  testOp(browser, "Affine Cipher Encode", "test input", "gndg zoujg", [3, 1]);
@@ -43,6 +50,14 @@ module.exports = {
43
50
  testOp(browser, "Analyse hash", "0123456789abcdef", /CRC-64/);
44
51
  testOp(browser, "Atbash Cipher", "test input", "gvhg rmkfg");
45
52
  // testOp(browser, "Avro to JSON", "test input", "test_output");
53
+ testOp(browser,
54
+ [
55
+ "From Hex", "Avro to JSON"
56
+ ],
57
+ "4f626a0104166176726f2e736368656d6196017b2274797065223a227265636f7264222c226e616d65223a22736d616c6c222c226669656c6473223a5b7b226e616d65223a226e616d65222c2274797065223a22737472696e67227d5d7d146176726f2e636f646563086e756c6c004e0247632e3702e5b75cdab9a62f1541020e0c6d796e616d654e0247632e3702e5b75cdab9a62f1541",
58
+ '{"name":"myname"}\n',
59
+ [[], [false]]
60
+ );
46
61
  testOp(browser, "BLAKE2b", "test input", "33ebdc8f38177f3f3f334eeb117a84e11f061bbca4db6b8923e5cec85103f59f415551a5d5a933fdb6305dc7bf84671c2540b463dbfa08ee1895cfaa5bd780b5", ["512", "Hex", { "option": "UTF8", "string": "pass" }]);
47
62
  testOp(browser, "BLAKE2s", "test input", "defe73d61dfa6e5807e4f9643e159a09ccda6be3c26dcd65f8a9bb38bfc973a7", ["256", "Hex", { "option": "UTF8", "string": "pass" }]);
48
63
  testOp(browser, "BSON deserialise", "\u0011\u0000\u0000\u0000\u0002a\u0000\u0005\u0000\u0000\u0000test\u0000\u0000", '{\u000A "a": "test"\u000A}');
@@ -58,7 +73,10 @@ module.exports = {
58
73
  testOp(browser, "Bit shift right", "test input", ":29:\u0010478::");
59
74
  testOp(browser, "Blowfish Decrypt", "10884e15427dd84ec35204e9c8e921ae", "test_output", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Hex", "Raw"]);
60
75
  testOp(browser, "Blowfish Encrypt", "test input", "f0fadbd1d90d774f714248cf26b96410", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Raw", "Hex"]);
61
- testOp(browser, ["From Hex", "Blur Image", "To Base64"], Images.PNG_HEX, Images.PNG_BLUR_B64);
76
+ testOp(browser, ["From Hex", "Blur Image", "SHA2"], Images.PNG_HEX, "24f2e89f3e00cc35f551bbc48ea82e76474946ce0282183494d1ca3d3b0012c27b6102c4368ae056dc7fecb6df7886d86ff3d29b7e5965493f30c371eee9a24e");
77
+ testOp(browser, ["From Hex", "Blur Image", "SHA2"], Images.PNG_HEX, "2c49d89fc10c94352c9a19f82de353c37928831d6f976a6b36eb918825a0ba027980801838228a4a0da63f1886e4fa59b6666f992ad2d2b7d4622253dc034052", [[], [5, "Gaussian"], []]);
78
+ testOp(browser, ["From Hex", "Sharpen Image", "SHA2"], Images.PNG_HEX, "acc7027642c2eeb67d7356a80ed8a1bdce9adabf656ea1294e47723f506626a7aa41f1660fa844a1e1e83b17180017ab0d5bccd7f6a341692832020dc887eaa5");
79
+ testOp(browser, ["From Hex", "Contain Image", "SHA2"], Images.PNG_HEX, "cb871ad0722d487d56a2b18247b1aa30ecc244eb717e08e23a55cae78759553312dc1717196d7cb9daa04743e57c56fc3901ba92be5a68fb03c377f718e8efe7");
62
80
  testOpHtml(browser, "Bombe", "XTSYN WAEUG EZALY NRQIM AMLZX MFUOD AWXLY LZCUZ QOQBQ JLCPK NDDRW F", "table tr:last-child td:first-child", "ECG", ["3-rotor", "LEYJVCNIXWPBQMDRTAKZGFUHOS", "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", "HELLO CYBER CHEFU SER", 0, true]);
63
81
  testOp(browser, ["Bzip2 Compress", "To Hex"], "test input", "42 5a 68 39 31 41 59 26 53 59 cf 96 82 1d 00 00 03 91 80 40 00 02 21 4e 00 20 00 21 90 c2 10 c0 88 33 92 8e df 17 72 45 38 50 90 cf 96 82 1d");
64
82
  testOp(browser, ["From Hex", "Bzip2 Decompress"], "425a68393141592653597b0884b7000003038000008200ce00200021a647a4218013709517c5dc914e14241ec2212dc0", "test_output", [[], [true]]);
@@ -196,6 +214,7 @@ module.exports = {
196
214
  testOpHtml(browser, "Index of Coincidence", "test input", "", /Index of Coincidence: 0.08333333333333333/);
197
215
  testOpImage(browser, "Invert Image", "files/Hitchhikers_Guide.jpeg");
198
216
  // testOp(browser, "JPath expression", "test input", "test_output");
217
+ testOp(browser, "Jq", '{"a":{"b":1}}', '{"b":1}', [".a"]);
199
218
  testOpHtml(browser, "JSON Beautify", "{a:1}", ".json-dict .json-literal", "1");
200
219
  // testOp(browser, "JSON Minify", "test input", "test_output");
201
220
  // testOp(browser, "JSON to CSV", "test input", "test_output");
@@ -249,7 +268,7 @@ module.exports = {
249
268
  testOpHtml(browser, "Parse colour code", "#000", ".colorpicker-preview", "rgb(0, 0, 0)");
250
269
  testOpHtml(browser, "Parse DateTime", "01/12/2000 13:00:00", "", /Date: Friday 1st December 2000/);
251
270
  // testOp(browser, "Parse IP range", "test input", "test_output");
252
- testOpHtml(browser, "Parse IPv4 header", "45 c0 00 c4 02 89 00 00 ff 11 1e 8c c0 a8 0c 01 c0 a8 0c 02", "tr:last-child td:last-child", "192.168.12.2");
271
+ testOpHtml(browser, "Parse IPv4 header", "45 c0 00 c4 02 89 00 00 ff 11 1e 8c c0 a8 0c 01 c0 a8 0c 02", "tr:nth-last-child(2) td:last-child", "192.168.12.2");
253
272
  // testOp(browser, "Parse IPv6 address", "test input", "test_output");
254
273
  // testOp(browser, "Parse ObjectID timestamp", "test input", "test_output");
255
274
  // testOp(browser, "Parse QR Code", "test input", "test_output");
@@ -335,6 +354,7 @@ module.exports = {
335
354
  // testOp(browser, "Tail", "test input", "test_output");
336
355
  // testOp(browser, "Take bytes", "test input", "test_output");
337
356
  testOp(browser, "Tar", "test input", /^file\.txt\x00{92}/);
357
+ testOp(browser, "Template", "{\"one\": 1, \"two\": 2}", "1 2", ["{{ one }} {{ two }}"]);
338
358
  testOpHtml(browser, "Text Encoding Brute Force", "test input", "tr:nth-of-type(4) td:last-child", /t\u2400e\u2400s\u2400t\u2400/);
339
359
  // testOp(browser, "To BCD", "test input", "test_output");
340
360
  // testOp(browser, "To Base", "test input", "test_output");
@@ -23,6 +23,7 @@ import "./tests/Dish.mjs";
23
23
  import "./tests/NodeDish.mjs";
24
24
  import "./tests/Utils.mjs";
25
25
  import "./tests/Categories.mjs";
26
+ import "./tests/lib/BigIntUtils.mjs";
26
27
 
27
28
  const testStatus = {
28
29
  allTestsPassing: true,
@@ -0,0 +1,150 @@
1
+ import TestRegister from "../../../lib/TestRegister.mjs";
2
+ import { parseBigInt, egcd, modPow } from "../../../../src/core/lib/BigIntUtils.mjs";
3
+ import it from "../../assertionHandler.mjs";
4
+ import assert from "assert";
5
+
6
+ TestRegister.addApiTests([
7
+ // ===== parseBigInt tests =====
8
+ it("BigIntUtils: parseBigInt - decimal number", () => {
9
+ const value = parseBigInt("1", "test value");
10
+ assert.deepStrictEqual(value, BigInt("1"));
11
+ }),
12
+
13
+ it("BigIntUtils: parseBigInt - large decimal", () => {
14
+ const value = parseBigInt("123456789012345678901234567890", "test value");
15
+ assert.deepStrictEqual(value, BigInt("123456789012345678901234567890"));
16
+ }),
17
+
18
+ it("BigIntUtils: parseBigInt - hexadecimal lowercase", () => {
19
+ const value = parseBigInt("0xff", "test value");
20
+ assert.deepStrictEqual(value, BigInt("255"));
21
+ }),
22
+
23
+ it("BigIntUtils: parseBigInt - hexadecimal uppercase", () => {
24
+ const value = parseBigInt("0xFF", "test value");
25
+ assert.deepStrictEqual(value, BigInt("255"));
26
+ }),
27
+
28
+ it("BigIntUtils: parseBigInt - large hexadecimal", () => {
29
+ const value = parseBigInt("0x123456789ABCDEF", "test value");
30
+ assert.deepStrictEqual(value, BigInt("0x123456789ABCDEF"));
31
+ }),
32
+
33
+ it("BigIntUtils: parseBigInt - whitespace trimming", () => {
34
+ const value = parseBigInt(" 42 ", "test value");
35
+ assert.deepStrictEqual(value, BigInt("42"));
36
+ }),
37
+
38
+ it("BigIntUtils: parseBigInt - invalid input (text)", () => {
39
+ assert.throws(() => parseBigInt("test", "test value"), {
40
+ name: "Error",
41
+ message: "test value must be decimal or hex (0x...)"
42
+ });
43
+ }),
44
+
45
+ it("BigIntUtils: parseBigInt - invalid input (hex without prefix)", () => {
46
+ assert.throws(() => parseBigInt("FF", "test value"), {
47
+ name: "Error",
48
+ message: "test value must be decimal or hex (0x...)"
49
+ });
50
+ }),
51
+
52
+ it("BigIntUtils: parseBigInt - invalid input (mixed)", () => {
53
+ assert.throws(() => parseBigInt("12abc", "test value"), {
54
+ name: "Error",
55
+ message: "test value must be decimal or hex (0x...)"
56
+ });
57
+ }),
58
+
59
+ // ===== egcd tests =====
60
+ it("BigIntUtils: egcd - basic coprime", () => {
61
+ const a = BigInt("36");
62
+ const b = BigInt("48");
63
+ const gcd = BigInt("12");
64
+ const bezout1 = BigInt("-1");
65
+ const bezout2 = BigInt("1");
66
+ assert.deepStrictEqual(egcd(a, b), [gcd, bezout1, bezout2]);
67
+ }),
68
+
69
+ it("BigIntUtils: egcd - coprime numbers", () => {
70
+ const [g, x, y] = egcd(BigInt("3"), BigInt("11"));
71
+ assert.strictEqual(g, BigInt("1"));
72
+ // Verify Bézout identity: a*x + b*y = gcd
73
+ assert.strictEqual(BigInt("3") * x + BigInt("11") * y, g);
74
+ }),
75
+
76
+ it("BigIntUtils: egcd - non-coprime numbers", () => {
77
+ const [g, x, y] = egcd(BigInt("240"), BigInt("46"));
78
+ assert.strictEqual(g, BigInt("2"));
79
+ // Verify Bézout identity
80
+ assert.strictEqual(BigInt("240") * x + BigInt("46") * y, g);
81
+ }),
82
+
83
+ it("BigIntUtils: egcd - with zero", () => {
84
+ const [g, x, y] = egcd(BigInt("17"), BigInt("0"));
85
+ assert.strictEqual(g, BigInt("17"));
86
+ assert.strictEqual(x, BigInt("1"));
87
+ assert.strictEqual(y, BigInt("0"));
88
+ }),
89
+
90
+ it("BigIntUtils: egcd - identical numbers", () => {
91
+ const [g, x, y] = egcd(BigInt("42"), BigInt("42"));
92
+ assert.strictEqual(g, BigInt("42"));
93
+ // Verify Bézout identity
94
+ assert.strictEqual(BigInt("42") * x + BigInt("42") * y, g);
95
+ }),
96
+
97
+ it("BigIntUtils: egcd - large numbers", () => {
98
+ const a = BigInt("123456789012345678901234567890");
99
+ const b = BigInt("987654321098765432109876543210");
100
+ const [g, x, y] = egcd(a, b);
101
+ // Verify Bézout identity
102
+ assert.strictEqual(a * x + b * y, g);
103
+ }),
104
+
105
+ // ===== modPow tests =====
106
+ it("BigIntUtils: modPow - basic", () => {
107
+ // 2^10 mod 1000 = 1024 mod 1000 = 24
108
+ const result = modPow(BigInt("2"), BigInt("10"), BigInt("1000"));
109
+ assert.strictEqual(result, BigInt("24"));
110
+ }),
111
+
112
+ it("BigIntUtils: modPow - RSA-like example", () => {
113
+ // Common RSA public exponent
114
+ const base = BigInt("123456789");
115
+ const exp = BigInt("65537");
116
+ const mod = BigInt("999999999999");
117
+ const result = modPow(base, exp, mod);
118
+ // Result should be less than modulus
119
+ assert(result < mod);
120
+ assert(result >= BigInt("0"));
121
+ }),
122
+
123
+ it("BigIntUtils: modPow - exponent zero", () => {
124
+ // Any number^0 = 1
125
+ const result = modPow(BigInt("999"), BigInt("0"), BigInt("100"));
126
+ assert.strictEqual(result, BigInt("1"));
127
+ }),
128
+
129
+ it("BigIntUtils: modPow - base zero", () => {
130
+ // 0^n = 0
131
+ const result = modPow(BigInt("0"), BigInt("5"), BigInt("100"));
132
+ assert.strictEqual(result, BigInt("0"));
133
+ }),
134
+
135
+ it("BigIntUtils: modPow - large exponent", () => {
136
+ // Test with very large exponent (efficient algorithm should handle this)
137
+ const result = modPow(BigInt("3"), BigInt("1000000"), BigInt("1000000007"));
138
+ assert(result >= BigInt("0"));
139
+ assert(result < BigInt("1000000007"));
140
+ }),
141
+
142
+ it("BigIntUtils: modPow - modular inverse verification", () => {
143
+ // If a*x . 1 (mod m), then modPow(a, 1, m) * x . 1 (mod m)
144
+ const a = BigInt("3");
145
+ const m = BigInt("11");
146
+ const x = BigInt("4"); // inverse of 3 mod 11
147
+ const result = modPow(a, BigInt("1"), m) * x % m;
148
+ assert.strictEqual(result, BigInt("1"));
149
+ }),
150
+ ]);
@@ -867,13 +867,15 @@ pCGTErs=
867
867
  }),
868
868
 
869
869
  it("SQL Beautify", () => {
870
- const result = chef.SQLBeautify(`SELECT MONTH, ID, RAIN_I, TEMP_F
871
- FROM STATS;`);
872
- const expected = `SELECT MONTH,
873
- ID,
874
- RAIN_I,
875
- TEMP_F
876
- FROM STATS;`;
870
+ const result = chef.SQLBeautify(`SELECT MONTH, ID, RAIN_I, TEMP_F FROM STATS;`);
871
+ const expected =
872
+ `SELECT
873
+ MONTH,
874
+ ID,
875
+ RAIN_I,
876
+ TEMP_F
877
+ FROM
878
+ STATS;`;
877
879
  assert.strictEqual(result.toString(), expected);
878
880
  }),
879
881
 
@@ -14,6 +14,7 @@
14
14
  import { setLongTestFailure, logTestReport } from "../lib/utils.mjs";
15
15
 
16
16
  import TestRegister from "../lib/TestRegister.mjs";
17
+ import "./tests/A1Z26CipherDecode.mjs";
17
18
  import "./tests/AESKeyWrap.mjs";
18
19
  import "./tests/AlternatingCaps.mjs";
19
20
  import "./tests/AvroToJSON.mjs";
@@ -61,10 +62,12 @@ import "./tests/Crypt.mjs";
61
62
  import "./tests/CSV.mjs";
62
63
  import "./tests/DateTime.mjs";
63
64
  import "./tests/DefangIP.mjs";
65
+ import "./tests/DisassembleARM.mjs";
64
66
  import "./tests/DropNthBytes.mjs";
65
67
  import "./tests/ECDSA.mjs";
66
68
  import "./tests/ELFInfo.mjs";
67
69
  import "./tests/Enigma.mjs";
70
+ import "./tests/ExtractAudioMetadata.mjs";
68
71
  import "./tests/ExtractEmailAddresses.mjs";
69
72
  import "./tests/ExtractHashes.mjs";
70
73
  import "./tests/ExtractIPAddresses.mjs";
@@ -76,6 +79,7 @@ import "./tests/FromDecimal.mjs";
76
79
  import "./tests/GenerateAllChecksums.mjs";
77
80
  import "./tests/GenerateAllHashes.mjs";
78
81
  import "./tests/GenerateDeBruijnSequence.mjs";
82
+ import "./tests/GenerateQRCode.mjs";
79
83
  import "./tests/GetAllCasings.mjs";
80
84
  import "./tests/GOST.mjs";
81
85
  import "./tests/Gunzip.mjs";
@@ -118,6 +122,7 @@ import "./tests/NetBIOS.mjs";
118
122
  import "./tests/NormaliseUnicode.mjs";
119
123
  import "./tests/NTLM.mjs";
120
124
  import "./tests/OTP.mjs";
125
+ import "./tests/ParseEthernetFrame.mjs";
121
126
  import "./tests/ParseIPRange.mjs";
122
127
  import "./tests/ParseObjectIDTimestamp.mjs";
123
128
  import "./tests/ParseQRCode.mjs";
@@ -151,7 +156,9 @@ import "./tests/Shuffle.mjs";
151
156
  import "./tests/SIGABA.mjs";
152
157
  import "./tests/SM2.mjs";
153
158
  import "./tests/SM4.mjs";
159
+ import "./tests/RC6.mjs";
154
160
  // import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet
161
+ import "./tests/SQLBeautify.mjs";
155
162
  import "./tests/StrUtils.mjs";
156
163
  import "./tests/StripIPv4Header.mjs";
157
164
  import "./tests/StripTCPHeader.mjs";
@@ -162,6 +169,7 @@ import "./tests/SymmetricDifference.mjs";
162
169
  import "./tests/TakeNthBytes.mjs";
163
170
  import "./tests/Template.mjs";
164
171
  import "./tests/TextEncodingBruteForce.mjs";
172
+ import "./tests/TextIntegerConverter.mjs";
165
173
  import "./tests/ToFromInsensitiveRegex.mjs";
166
174
  import "./tests/TranslateDateTimeFormat.mjs";
167
175
  import "./tests/Typex.mjs";
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A1Z26 Cipher Decode tests
3
+ *
4
+ * @author brick-pixel
5
+ * @copyright Crown Copyright 2026
6
+ * @license Apache-2.0
7
+ */
8
+ import TestRegister from "../../lib/TestRegister.mjs";
9
+
10
+ TestRegister.addTests([
11
+ {
12
+ "name": "A1Z26 Cipher Decode: basic decode",
13
+ "input": "8 5 12 12 15",
14
+ "expectedOutput": "hello",
15
+ "recipeConfig": [
16
+ {
17
+ "op": "A1Z26 Cipher Decode",
18
+ "args": ["Space"]
19
+ }
20
+ ]
21
+ },
22
+ {
23
+ "name": "A1Z26 Cipher Decode: empty input returns empty string",
24
+ "input": "",
25
+ "expectedOutput": "",
26
+ "recipeConfig": [
27
+ {
28
+ "op": "A1Z26 Cipher Decode",
29
+ "args": ["Space"]
30
+ }
31
+ ]
32
+ }
33
+ ]);