cyberchef 10.22.1 → 10.24.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 (118) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/CONTRIBUTING.md +40 -0
  3. package/Dockerfile +2 -0
  4. package/Gruntfile.js +2 -28
  5. package/README.md +1 -1
  6. package/babel.config.js +0 -6
  7. package/package.json +64 -63
  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 +20 -4
  13. package/src/core/config/OperationConfig.json +550 -26
  14. package/src/core/config/modules/Ciphers.mjs +6 -0
  15. package/src/core/config/modules/Crypto.mjs +6 -0
  16. package/src/core/config/modules/Default.mjs +8 -0
  17. package/src/core/config/modules/Shellcode.mjs +2 -0
  18. package/src/core/config/scripts/fixCryptoApiImports.mjs +54 -0
  19. package/src/core/config/scripts/fixSnackBarMarkup.mjs +28 -0
  20. package/src/core/lib/AudioBytes.mjs +103 -0
  21. package/src/core/lib/AudioMetaSchema.mjs +82 -0
  22. package/src/core/lib/AudioParsers.mjs +630 -0
  23. package/src/core/lib/BigIntUtils.mjs +73 -0
  24. package/src/core/lib/Extract.mjs +5 -0
  25. package/src/core/lib/Modhex.mjs +2 -0
  26. package/src/core/lib/ParityBit.mjs +50 -0
  27. package/src/core/lib/QRCode.mjs +30 -10
  28. package/src/core/lib/RC6.mjs +625 -0
  29. package/src/core/operations/A1Z26CipherDecode.mjs +1 -1
  30. package/src/core/operations/AddTextToImage.mjs +116 -64
  31. package/src/core/operations/AnalyseUUID.mjs +109 -6
  32. package/src/core/operations/BlurImage.mjs +10 -12
  33. package/src/core/operations/ContainImage.mjs +50 -40
  34. package/src/core/operations/ConvertImageFormat.mjs +33 -39
  35. package/src/core/operations/CoverImage.mjs +39 -37
  36. package/src/core/operations/CropImage.mjs +35 -21
  37. package/src/core/operations/DisassembleARM.mjs +193 -0
  38. package/src/core/operations/DitherImage.mjs +8 -8
  39. package/src/core/operations/EscapeUnicodeCharacters.mjs +0 -17
  40. package/src/core/operations/ExtractAudioMetadata.mjs +175 -0
  41. package/src/core/operations/ExtractEmailAddresses.mjs +2 -3
  42. package/src/core/operations/ExtractLSB.mjs +17 -11
  43. package/src/core/operations/ExtractRGBA.mjs +12 -10
  44. package/src/core/operations/FlaskSessionDecode.mjs +80 -0
  45. package/src/core/operations/FlaskSessionSign.mjs +89 -0
  46. package/src/core/operations/FlaskSessionVerify.mjs +136 -0
  47. package/src/core/operations/FlipImage.mjs +14 -10
  48. package/src/core/operations/GenerateImage.mjs +39 -32
  49. package/src/core/operations/ImageBrightnessContrast.mjs +10 -10
  50. package/src/core/operations/ImageFilter.mjs +14 -13
  51. package/src/core/operations/ImageHueSaturationLightness.mjs +22 -20
  52. package/src/core/operations/ImageOpacity.mjs +6 -8
  53. package/src/core/operations/InvertImage.mjs +4 -6
  54. package/src/core/operations/Jq.mjs +12 -4
  55. package/src/core/operations/NormaliseImage.mjs +5 -7
  56. package/src/core/operations/OffsetChecker.mjs +1 -1
  57. package/src/core/operations/ParityBit.mjs +128 -0
  58. package/src/core/operations/ParseEthernetFrame.mjs +112 -0
  59. package/src/core/operations/ParseIPv4Header.mjs +23 -6
  60. package/src/core/operations/ParseQRCode.mjs +13 -13
  61. package/src/core/operations/PseudoRandomIntegerGenerator.mjs +164 -0
  62. package/src/core/operations/RC6Decrypt.mjs +119 -0
  63. package/src/core/operations/RC6Encrypt.mjs +119 -0
  64. package/src/core/operations/RandomizeColourPalette.mjs +11 -11
  65. package/src/core/operations/RegularExpression.mjs +2 -1
  66. package/src/core/operations/RenderMarkdown.mjs +35 -4
  67. package/src/core/operations/ResizeImage.mjs +30 -23
  68. package/src/core/operations/RotateImage.mjs +8 -9
  69. package/src/core/operations/SQLBeautify.mjs +21 -3
  70. package/src/core/operations/SharpenImage.mjs +94 -62
  71. package/src/core/operations/SplitColourChannels.mjs +47 -21
  72. package/src/core/operations/TextIntegerConverter.mjs +123 -0
  73. package/src/core/operations/UnescapeUnicodeCharacters.mjs +17 -0
  74. package/src/core/operations/ViewBitPlane.mjs +16 -20
  75. package/src/core/operations/index.mjs +22 -0
  76. package/src/node/index.mjs +55 -0
  77. package/src/web/HTMLIngredient.mjs +24 -43
  78. package/src/web/HTMLOperation.mjs +8 -2
  79. package/src/web/Manager.mjs +1 -0
  80. package/src/web/html/index.html +6 -6
  81. package/src/web/static/fonts/bmfonts/Roboto72White.fnt +491 -485
  82. package/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +494 -488
  83. package/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +110 -103
  84. package/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +498 -492
  85. package/src/web/stylesheets/layout/_banner.css +30 -0
  86. package/src/web/stylesheets/layout/_modals.css +5 -0
  87. package/src/web/stylesheets/utils/_overrides.css +7 -0
  88. package/src/web/waiters/ControlsWaiter.mjs +82 -0
  89. package/src/web/waiters/InputWaiter.mjs +12 -6
  90. package/src/web/waiters/OperationsWaiter.mjs +30 -13
  91. package/src/web/waiters/RecipeWaiter.mjs +2 -2
  92. package/tests/browser/02_ops.js +23 -3
  93. package/tests/node/index.mjs +1 -0
  94. package/tests/node/tests/lib/BigIntUtils.mjs +150 -0
  95. package/tests/node/tests/operations.mjs +11 -10
  96. package/tests/operations/index.mjs +13 -0
  97. package/tests/operations/tests/A1Z26CipherDecode.mjs +33 -0
  98. package/tests/operations/tests/AnalyseUUID.mjs +66 -0
  99. package/tests/operations/tests/DisassembleARM.mjs +377 -0
  100. package/tests/operations/tests/ExtractAudioMetadata.mjs +287 -0
  101. package/tests/operations/tests/ExtractEmailAddresses.mjs +38 -12
  102. package/tests/operations/tests/Fernet.mjs +18 -3
  103. package/tests/operations/tests/FlaskSession.mjs +246 -0
  104. package/tests/operations/tests/GenerateQRCode.mjs +67 -0
  105. package/tests/operations/tests/JWTSign.mjs +83 -8
  106. package/tests/operations/tests/Jq.mjs +32 -0
  107. package/tests/operations/tests/Modhex.mjs +20 -0
  108. package/tests/operations/tests/ParityBit.mjs +147 -0
  109. package/tests/operations/tests/ParseEthernetFrame.mjs +45 -0
  110. package/tests/operations/tests/RC6.mjs +487 -0
  111. package/tests/operations/tests/RegularExpression.mjs +75 -0
  112. package/tests/operations/tests/RenderMarkdown.mjs +110 -0
  113. package/tests/operations/tests/SQLBeautify.mjs +54 -0
  114. package/tests/operations/tests/TextIntegerConverter.mjs +199 -0
  115. package/tests/samples/Audio.mjs +73 -0
  116. package/tests/samples/Images.mjs +0 -12
  117. package/webpack.config.js +10 -7
  118. 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
  });
@@ -28,17 +28,16 @@ class OperationsWaiter {
28
28
  this.removeIntent = false;
29
29
  }
30
30
 
31
-
32
31
  /**
33
32
  * Handler for search events.
34
33
  * Finds operations which match the given search term and displays them under the search box.
35
34
  *
36
- * @param {event} e
35
+ * @param {KeyboardEvent | ClipboardEvent | Event} e
37
36
  */
38
37
  searchOperations(e) {
39
38
  let ops, selected;
40
39
 
41
- if (e.type === "search" || e.keyCode === 13) { // Search or Return
40
+ if ((e.type === "search" && e.target.value !== "") || e.keyCode === 13) { // Search (non-empty) or Return
42
41
  e.preventDefault();
43
42
  ops = document.querySelectorAll("#search-results li");
44
43
  if (ops.length) {
@@ -49,27 +48,43 @@ class OperationsWaiter {
49
48
  }
50
49
  }
51
50
 
51
+ /**
52
+ * Sets up the operation element with the correct attributes when selected
53
+ * @param {HTMLElement} element
54
+ */
55
+ const _selectOperation = (element) => {
56
+ element.classList.add("selected-op");
57
+ element.scrollIntoView({block: "nearest"});
58
+ $(element).popover("show");
59
+ e.target.setAttribute("aria-activedescendant", element.id);
60
+ };
61
+
62
+ /**
63
+ * Sets up the operation element with the correct attributes when deselected
64
+ * @param {HTMLElement} element
65
+ */
66
+ const _deselectOperation = (element) => {
67
+ element.classList.remove("selected-op");
68
+ $(element).popover("hide");
69
+ };
70
+
52
71
  if (e.keyCode === 40) { // Down
53
72
  e.preventDefault();
54
73
  ops = document.querySelectorAll("#search-results li");
55
74
  if (ops.length) {
56
75
  selected = this.getSelectedOp(ops);
57
- if (selected > -1) {
58
- ops[selected].classList.remove("selected-op");
59
- }
76
+ if (selected > -1) _deselectOperation(ops[selected]);
60
77
  if (selected === ops.length-1) selected = -1;
61
- ops[selected+1].classList.add("selected-op");
78
+ _selectOperation(ops[selected+1]);
62
79
  }
63
80
  } else if (e.keyCode === 38) { // Up
64
81
  e.preventDefault();
65
82
  ops = document.querySelectorAll("#search-results li");
66
83
  if (ops.length) {
67
84
  selected = this.getSelectedOp(ops);
68
- if (selected > -1) {
69
- ops[selected].classList.remove("selected-op");
70
- }
85
+ if (selected > -1) _deselectOperation(ops[selected]);
71
86
  if (selected === 0) selected = ops.length;
72
- ops[selected-1].classList.add("selected-op");
87
+ _selectOperation(ops[selected-1]);
73
88
  }
74
89
  } else {
75
90
  const searchResultsEl = document.getElementById("search-results");
@@ -83,11 +98,13 @@ class OperationsWaiter {
83
98
  searchResultsEl.removeChild(searchResultsEl.firstChild);
84
99
  }
85
100
 
101
+ document.querySelector("#search").removeAttribute("aria-activedescendant");
102
+
86
103
  $("#categories .show").collapse("hide");
87
104
  if (str) {
88
105
  const matchedOps = this.filterOperations(str, true);
89
106
  const matchedOpsHtml = matchedOps
90
- .map(v => v.toStubHtml())
107
+ .map((operation, idx) => operation.toStubHtml(false, `search-result-${idx}`))
91
108
  .join("");
92
109
 
93
110
  searchResultsEl.innerHTML = matchedOpsHtml;
@@ -103,7 +120,7 @@ class OperationsWaiter {
103
120
  * @param {string} searchStr
104
121
  * @param {boolean} highlight - Whether or not to highlight the matching string in the operation
105
122
  * name and description
106
- * @returns {string[]}
123
+ * @returns {HTMLOperation[]}
107
124
  */
108
125
  filterOperations(inStr, highlight) {
109
126
  const matchedOps = [];
@@ -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
+ ]);
@@ -589,8 +589,7 @@ Password: 282760`;
589
589
  ...[1, 3, 4, 5, 6, 7].map(version => it(`Analyze UUID v${version}`, () => {
590
590
  const uuid = chef.generateUUID("", { "version": `v${version}` }).toString();
591
591
  const result = chef.analyseUUID(uuid).toString();
592
- const expected = `UUID version: ${version}`;
593
- assert.strictEqual(result, expected);
592
+ assert.ok(result.startsWith(`Version:\n${version}\n`), `Expected output to start with "Version:\\n${version}\\n", got: ${result}`);
594
593
  })),
595
594
 
596
595
  it("Generate UUID using defaults", () => {
@@ -598,7 +597,7 @@ Password: 282760`;
598
597
  assert.ok(uuid);
599
598
 
600
599
  const analysis = chef.analyseUUID(uuid).toString();
601
- assert.strictEqual(analysis, "UUID version: 4");
600
+ assert.ok(analysis.startsWith("Version:\n4\n"), `Expected output to start with "Version:\\n4\\n", got: ${analysis}`);
602
601
  }),
603
602
 
604
603
  it("Gzip, Gunzip", () => {
@@ -867,13 +866,15 @@ pCGTErs=
867
866
  }),
868
867
 
869
868
  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;`;
869
+ const result = chef.SQLBeautify(`SELECT MONTH, ID, RAIN_I, TEMP_F FROM STATS;`);
870
+ const expected =
871
+ `SELECT
872
+ MONTH,
873
+ ID,
874
+ RAIN_I,
875
+ TEMP_F
876
+ FROM
877
+ STATS;`;
877
878
  assert.strictEqual(result.toString(), expected);
878
879
  }),
879
880
 
@@ -14,7 +14,9 @@
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";
19
+ import "./tests/AnalyseUUID.mjs";
18
20
  import "./tests/AlternatingCaps.mjs";
19
21
  import "./tests/AvroToJSON.mjs";
20
22
  import "./tests/BaconCipher.mjs";
@@ -61,13 +63,16 @@ import "./tests/Crypt.mjs";
61
63
  import "./tests/CSV.mjs";
62
64
  import "./tests/DateTime.mjs";
63
65
  import "./tests/DefangIP.mjs";
66
+ import "./tests/DisassembleARM.mjs";
64
67
  import "./tests/DropNthBytes.mjs";
65
68
  import "./tests/ECDSA.mjs";
66
69
  import "./tests/ELFInfo.mjs";
67
70
  import "./tests/Enigma.mjs";
71
+ import "./tests/ExtractAudioMetadata.mjs";
68
72
  import "./tests/ExtractEmailAddresses.mjs";
69
73
  import "./tests/ExtractHashes.mjs";
70
74
  import "./tests/ExtractIPAddresses.mjs";
75
+ import "./tests/Fernet.mjs";
71
76
  import "./tests/Float.mjs";
72
77
  import "./tests/FileTree.mjs";
73
78
  import "./tests/FletcherChecksum.mjs";
@@ -76,6 +81,7 @@ import "./tests/FromDecimal.mjs";
76
81
  import "./tests/GenerateAllChecksums.mjs";
77
82
  import "./tests/GenerateAllHashes.mjs";
78
83
  import "./tests/GenerateDeBruijnSequence.mjs";
84
+ import "./tests/GenerateQRCode.mjs";
79
85
  import "./tests/GetAllCasings.mjs";
80
86
  import "./tests/GOST.mjs";
81
87
  import "./tests/Gunzip.mjs";
@@ -118,6 +124,7 @@ import "./tests/NetBIOS.mjs";
118
124
  import "./tests/NormaliseUnicode.mjs";
119
125
  import "./tests/NTLM.mjs";
120
126
  import "./tests/OTP.mjs";
127
+ import "./tests/ParseEthernetFrame.mjs";
121
128
  import "./tests/ParseIPRange.mjs";
122
129
  import "./tests/ParseObjectIDTimestamp.mjs";
123
130
  import "./tests/ParseQRCode.mjs";
@@ -129,6 +136,7 @@ import "./tests/ParseUDP.mjs";
129
136
  import "./tests/PEMtoHex.mjs";
130
137
  import "./tests/PGP.mjs";
131
138
  import "./tests/PHP.mjs";
139
+ import "./tests/ParityBit.mjs";
132
140
  import "./tests/PHPSerialize.mjs";
133
141
  import "./tests/PowerSet.mjs";
134
142
  import "./tests/Protobuf.mjs";
@@ -138,6 +146,8 @@ import "./tests/Rabbit.mjs";
138
146
  import "./tests/RAKE.mjs";
139
147
  import "./tests/Regex.mjs";
140
148
  import "./tests/Register.mjs";
149
+ import "./tests/RegularExpression.mjs";
150
+ import "./tests/RenderMarkdown.mjs";
141
151
  import "./tests/RisonEncodeDecode.mjs";
142
152
  import "./tests/Rotate.mjs";
143
153
  import "./tests/RSA.mjs";
@@ -151,7 +161,9 @@ import "./tests/Shuffle.mjs";
151
161
  import "./tests/SIGABA.mjs";
152
162
  import "./tests/SM2.mjs";
153
163
  import "./tests/SM4.mjs";
164
+ import "./tests/RC6.mjs";
154
165
  // import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet
166
+ import "./tests/SQLBeautify.mjs";
155
167
  import "./tests/StrUtils.mjs";
156
168
  import "./tests/StripIPv4Header.mjs";
157
169
  import "./tests/StripTCPHeader.mjs";
@@ -162,6 +174,7 @@ import "./tests/SymmetricDifference.mjs";
162
174
  import "./tests/TakeNthBytes.mjs";
163
175
  import "./tests/Template.mjs";
164
176
  import "./tests/TextEncodingBruteForce.mjs";
177
+ import "./tests/TextIntegerConverter.mjs";
165
178
  import "./tests/ToFromInsensitiveRegex.mjs";
166
179
  import "./tests/TranslateDateTimeFormat.mjs";
167
180
  import "./tests/Typex.mjs";