2
0
mirror of https://github.com/gchq/CyberChef synced 2025-12-05 23:53:27 +00:00

Compare commits

...

206 Commits

Author SHA1 Message Date
n1474335
0fc1c37e65 9.10.0 2019-11-06 12:17:41 +00:00
n1474335
6b4efb420e Updated CHANGELOG 2019-11-06 12:16:35 +00:00
n1474335
9ed2b26933 Tidied up Lorenz operation and created new Bletchley module for WW2-era ciphers 2019-11-06 12:14:22 +00:00
n1474335
70665534b8 Merge branch 'master' of https://github.com/VirtualColossus/CyberChef 2019-11-06 12:00:37 +00:00
n1474335
7244d4d343 9.9.0 2019-11-01 14:57:46 +00:00
n1474335
980c1e8681 Updated CHANGELOG 2019-11-01 14:57:41 +00:00
n1474335
e1378860d6 Added support for 109 more character encodings 2019-11-01 14:56:18 +00:00
VirtualColossus
b9571db9f1 Merge branch 'master' into master 2019-10-31 15:33:54 +00:00
n1474335
734962ac22 9.8.0 2019-10-31 14:21:03 +00:00
n1474335
35103bf155 Updated CHANGELOG 2019-10-31 14:20:55 +00:00
n1474335
4c4d7b5d26 Merge branch 'jarrodconnolly-avro-to-json' 2019-10-31 14:17:55 +00:00
n1474335
daad633195 Tidied up Avro to JSON operation 2019-10-31 14:17:07 +00:00
VirtualColossus
d5cfe9f262 removed duplicate test 2019-10-31 13:54:52 +00:00
n1474335
a2c46b3f66 Merge branch 'avro-to-json' of https://github.com/jarrodconnolly/CyberChef into jarrodconnolly-avro-to-json 2019-10-31 13:54:00 +00:00
n1474335
6a1d11b9b5 Argument hints are not tooltips instead of bmd-help elements 2019-10-31 13:39:06 +00:00
n1474335
0630c094e0 9.7.20 2019-10-31 13:00:22 +00:00
n1474335
ace71f20b3 Merge branch 'gsilvapt-master' 2019-10-31 13:00:15 +00:00
VirtualColossus
c0e02451a1 Fixed bug using KT option, added tests 2019-10-31 07:28:33 +00:00
Jarrod Connolly
2d12a16771 Add Avro to JSON data format conversion 2019-10-30 22:09:42 -07:00
Gustavo Silva
9108b3923b diff.mjs: Fixes tests and adds default flag
* Sets default flag to `false` for `showSubtraction` flag.
    * Removes extra span for else case that was causing some tests to
    fail. Moreover, the previous behavior was defined as that.
    * Adds custom test for the showSubtraction option, both using the
    `showAdded` and `showRemoved` flags.
2019-10-29 23:39:14 +00:00
Gustavo Silva
726e117656 diff.mjs: Allows showing subtraction
Adds "Show Subtraction" button to allow seeing only the difference
    between two texts.
    When selected and combined, user can see only the characters or
    words that were added. If not combined, with either removed or added
    but selected, then nothing is displayed.
2019-10-29 23:12:24 +00:00
VirtualColossus
ab524fff15 Mixed tabs & spaces 2019-10-29 21:52:18 +00:00
VirtualColossus
55eae9910f Tidied run function, added some tests 2019-10-29 21:39:29 +00:00
VirtualColossus
d3138a7fdf Merge remote-tracking branch 'upstream/master' 2019-10-28 22:23:28 +00:00
n1474335
05e65a74ce Improved Magic scoring slightly 2019-10-28 17:26:13 +00:00
n1474335
6d138f345f 9.7.19 2019-10-27 15:27:36 +00:00
n1474335
3c165dd7e8 Merge branch 'mattnotmitt-chores/yara-update' 2019-10-27 15:27:12 +00:00
n1474335
04561d29b5 Dependency update 2019-10-27 15:26:48 +00:00
n1474335
e5e6c1a2dd Merge branch 'chores/yara-update' of https://github.com/mattnotmitt/CyberChef into mattnotmitt-chores/yara-update 2019-10-27 15:23:47 +00:00
n1474335
882efea314 Updated README 2019-10-27 15:21:41 +00:00
n1474335
89d979d92e Merge branch 'rianadon-theme-by-url' 2019-10-27 15:17:33 +00:00
n1474335
383aab5f85 Improved theme selection. Added changeTheme method. 2019-10-27 15:17:06 +00:00
n1474335
6659174f88 Merge branch 'theme-by-url' of https://github.com/rianadon/CyberChef into rianadon-theme-by-url 2019-10-27 14:43:59 +00:00
n1474335
3ca29b8744 Merge branch 'brian-digital-labs-autofocus-search' 2019-10-27 14:39:05 +00:00
n1474335
726bf3345e Added tabindex to ingredients 2019-10-27 14:38:55 +00:00
n1474335
b2d61482d5 Merge branch 'autofocus-search' of https://github.com/brian-digital-labs/CyberChef into brian-digital-labs-autofocus-search 2019-10-27 14:17:06 +00:00
n1474335
88d8e9a7f9 9.7.18 2019-10-27 14:13:37 +00:00
n1474335
0b0ddd3140 Merge branch 'mattnotmitt-chores/nightwatch-update' 2019-10-27 14:12:22 +00:00
Matt
3d4f74945c Update nightwatch and chromedriver
Rebase onto master
2019-10-26 16:59:41 +01:00
Matt
4387038351 Update libyara-wasm 2019-10-26 16:14:25 +01:00
Brian Hoang
49f444dfe9 auto focus on search bar and made searchbar and text area tab-able 2019-10-26 15:30:27 +01:00
Ryan Adolf
061533bb57 Document theme option in README 2019-10-24 16:37:10 -07:00
Ryan Adolf
6e2fb67d76 Theme configuration through url 2019-10-24 16:32:14 -07:00
n1474335
60f5093c6c Update .travis.yml 2019-10-21 13:56:52 +01:00
n1474335
665f91ec37 Update README.md 2019-10-21 13:49:42 +01:00
n1474335
0805a011b9 9.7.17 2019-10-18 13:57:26 +01:00
n1474335
3e3322e1f0 Fork no longer appends its merge delimiter to the end of the output. Closes #692 2019-10-18 13:57:21 +01:00
Matt
252b1b65c4 Add YARA rules node test 2019-10-18 12:58:17 +01:00
Matt
e8b4536ec2 Updated yara to v3.11.0 and openssl to v1.1.1d
finally managed to fudge the compiler
2019-10-18 12:57:13 +01:00
n1474335
61d40b5a0b 9.7.16 2019-10-18 11:11:17 +01:00
n1474335
d175aa958c DES no longer requires an IV in ECB mode 2019-10-18 11:09:12 +01:00
n1474335
ac3c220789 9.7.15 2019-10-16 17:36:25 +01:00
n1474335
add65e121a Merge branch 'Storms-Engineering-master' 2019-10-16 17:36:02 +01:00
n1474335
de2e757691 Merge branch 'master' of https://github.com/Storms-Engineering/CyberChef into Storms-Engineering-master 2019-10-16 17:34:58 +01:00
n1474335
eb34ab4f6a 9.7.14 2019-10-16 17:23:59 +01:00
n1474335
08e4232166 Merge branch 'wh0-backslash' 2019-10-16 17:23:47 +01:00
n1474335
adf9772928 Added tests for Utils.parseEscapedChars 2019-10-16 17:22:48 +01:00
n1474335
562171ec86 Merge branch 'backslash' of https://github.com/wh0/CyberChef into wh0-backslash 2019-10-16 16:47:01 +01:00
n1474335
e9e162319f Merge branch 'BjoernAkAManf-master' 2019-10-16 16:32:20 +01:00
n1474335
17c9ffe107 Tidied up chainCommands function in Gruntfile 2019-10-16 16:32:06 +01:00
n1474335
1831c84a29 Merge branch 'master' of https://github.com/BjoernAkAManf/CyberChef into BjoernAkAManf-master 2019-10-16 16:23:09 +01:00
n1474335
7e27449204 Fixed search box appaerance in Firefox 2019-10-16 16:12:22 +01:00
n1474335
282476d530 Merge branch 'Xenonym-chore/remove-duplicate-issue-template' 2019-10-16 16:04:49 +01:00
n1474335
fce0728d5d Updated bug report template 2019-10-16 16:04:36 +01:00
n1474335
0e9ac90607 Merge branch 'chore/remove-duplicate-issue-template' of https://github.com/Xenonym/CyberChef into Xenonym-chore/remove-duplicate-issue-template 2019-10-16 15:59:59 +01:00
n1474335
5383f56b26 9.7.13 2019-10-16 15:51:06 +01:00
n1474335
a02484c6cd Merge branch 'Storms-Engineering-IV-length-Error' 2019-10-16 15:50:51 +01:00
n1474335
be365f66ef Added length check to Triple DES IVs 2019-10-16 15:50:37 +01:00
n1474335
011dc09d5e Merge branch 'IV-length-Error' of https://github.com/Storms-Engineering/CyberChef into Storms-Engineering-IV-length-Error 2019-10-16 15:43:47 +01:00
n1474335
fc4d6d2d2e 9.7.12 2019-10-16 15:39:56 +01:00
n1474335
9d73127cae Fixed some typos 2019-10-16 15:38:20 +01:00
n1474335
223743e3b5 Removed Clippy 2019-10-16 15:37:18 +01:00
n1474335
44ed372f21 9.7.11 2019-10-16 15:10:16 +01:00
n1474335
4d1f970105 Added test to ensure all operations are in a category. Added various operations to categories. 2019-10-16 15:10:03 +01:00
n1474335
b28a891a40 9.7.10 2019-10-15 16:26:01 +01:00
n1474335
834ff95702 Base64 operations now throw a meaningful error if the alphabet is the wrong length 2019-10-15 16:25:52 +01:00
Storms-Engineering
3e93580aa4 DES Encrypt/Decrypt - checks length of IV string
Checks the length of IV string when encrypting.  DES encrypt/decrypt test swas updated to use utf8 instead of HEX.
2019-10-12 09:42:13 -08:00
Storms-Engineering
7a3ca027bb PHP Deserialize NULL values converted to correctly
PHP Deserialize now correctly returns N as a null instead of an empty object
2019-10-12 05:56:10 -08:00
Tan Zhen Yong
3c021919dd Rename feature request issue template
- to remain consistent with other issue templates using a `-` instead of `_`
2019-10-12 16:17:40 +08:00
Tan Zhen Yong
2106e8ddb0 Remove duplicate bug report issue template
The bug report issue template is duplicated (`bug-report.md` and
`bug_report.md`, note the `-`/`_` difference).

Thus, GitHub was unable to use the bug report issue template, and it
does not show up when a new issue is being created.

Let's remove the duplicate template `bug_report.md`.
2019-10-12 16:13:40 +08:00
n1474335
3472484601 Merge branch 'd98762625-fix-node-tests' 2019-10-09 16:19:39 +01:00
n1474335
826a8c8a74 Merge branch 'fix-node-tests' of https://github.com/d98762625/CyberChef into d98762625-fix-node-tests 2019-10-09 16:18:54 +01:00
n1474335
c66703f0ca 9.7.9 2019-10-09 16:14:47 +01:00
n1474335
874e7d8d54 Merge branch 'expose-operationerror' 2019-10-09 16:14:38 +01:00
n1474335
4e2b85b8c8 Merge branch 'master' into expose-operationerror 2019-10-09 16:14:03 +01:00
n1474335
5314a456cb 9.7.8 2019-10-09 16:12:46 +01:00
n1474335
ba2a5b195c Improved PE extractor to also carve the overlay if possible 2019-10-09 16:12:41 +01:00
d98762625
f8115671ee fix linting tests 2019-10-07 18:05:28 +01:00
d98762625
494279edd8 update gitignore 2019-10-07 18:01:35 +01:00
d98762625
bd6673afed Merge branch 'master' of github.com:gchq/CyberChef into expose-operationerror 2019-10-07 17:59:00 +01:00
d98762625
210daf7324 make async node tests actually fail when they fail. Update tests that were failing 2019-10-07 17:41:51 +01:00
wh0
d60d595254 Utils: don't consume three backslashes at a time 2019-10-06 17:07:58 -07:00
n1474335
06708949a1 9.7.7 2019-10-04 17:52:15 +01:00
n1474335
da901e20d9 Added several more file signatures. The background magic button now highlights when a file type has been detected. 2019-10-04 17:52:09 +01:00
Björn Heinrichs
c28999ec6f Fixed building on Windows
On Windows OperationConfig was not generated.
See #360 #645 for more Information.
2019-10-03 02:23:18 +02:00
n1474335
6810f38808 9.7.6 2019-10-01 17:11:36 +01:00
n1474335
087cc6b8fd Fixed webm signature 2019-10-01 17:11:31 +01:00
n1474335
10c8101476 9.7.5 2019-10-01 16:54:26 +01:00
n1474335
22028b074a Added support for many more file types to file signature operations 2019-10-01 16:54:19 +01:00
n1474335
3d086beed2 9.7.4 2019-10-01 12:15:07 +01:00
n1474335
777d814e70 Updated package-lock.json 2019-10-01 12:14:57 +01:00
n1474335
15c26a95c5 Merge branch 'master' into edit-node-recipe 2019-10-01 12:12:49 +01:00
n1474335
f87d3bd1cb 9.7.3 2019-10-01 12:10:43 +01:00
n1474335
b9ea1e8c71 Merge branch 'forge-update' of https://github.com/cbeuw/CyberChef into cbeuw-forge-update 2019-10-01 10:56:30 +01:00
n1474335
db232f4ff2 9.7.2 2019-09-27 11:29:01 +01:00
n1474335
70f705afbc Fixed typo in 'Convert Data Units' preventing Kilobits from working. Closes #649 2019-09-27 11:28:57 +01:00
Andy Wang
880df212d5 Correct wrong DES and 3DES tests 2019-09-26 22:00:13 +01:00
Andy Wang
b06acd99ec Adapt AES "no IV" tests 2019-09-26 21:52:34 +01:00
Andy Wang
a59de80d18 Update node API tests 2019-09-26 21:41:35 +01:00
Andy Wang
1e8dee9935 update node-forge version 2019-09-26 21:32:08 +01:00
n1474335
928f1c3e4b Remove excess slashes from Tesseract paths 2019-09-25 15:39:04 +01:00
d98762625
014e70a7b1 add node index to source 2019-09-20 18:44:13 +01:00
d98762625
5148b16246 Export cyberchef error types to be used in consuming applications 2019-09-20 18:40:21 +01:00
n1474335
b4ae4c5a00 9.7.1 2019-09-13 17:40:26 +01:00
n1474335
70346bce35 OCR operation now relies on local files 2019-09-13 17:40:20 +01:00
n1474335
3539e065fa 9.7.0 2019-09-13 14:36:00 +01:00
n1474335
8ffc58b340 Updated CHANGELOG 2019-09-13 14:35:54 +01:00
n1474335
503e733c81 Merge branch 'MShwed-feature/ocr' 2019-09-13 14:34:22 +01:00
n1474335
7eabaf0de6 Cleaned up and improved OCR operation 2019-09-13 14:34:08 +01:00
n1474335
a8ad10757c Merge branch 'feature/ocr' of https://github.com/MShwed/CyberChef into MShwed-feature/ocr 2019-09-13 12:41:38 +01:00
d98762625
111546ad1a update function comments 2019-09-06 12:26:24 +01:00
d98762625
a8fbd5164e Update NodeRecipe so args is optional in bake config 2019-09-06 12:21:53 +01:00
mshwed
8dde732514 Fixed linting issues 2019-09-05 09:20:59 -04:00
mshwed
f1659af5e4 Added basic OCR text extraction 2019-09-04 14:37:02 -04:00
n1474335
e68fb51f44 Merge branch 'master' of github.com:gchq/CyberChef 2019-09-04 17:17:17 +01:00
n1474335
95453131c8 9.6.0 2019-09-04 17:16:54 +01:00
n1474335
c60d5c8e85 Updated CHANGELOG 2019-09-04 17:16:47 +01:00
n1474335
b31f32a7e7 Tidied up Bacon Cipher operations 2019-09-04 17:13:05 +01:00
n1474335
f0b3bd0ede Merge branch 'bacon' of https://github.com/kassi/CyberChef 2019-09-04 16:30:05 +01:00
n1474335
de5243ec67 Update issue templates 2019-09-04 14:51:57 +01:00
n1474335
c6de3eb2ae 9.5.0 2019-09-04 14:00:29 +01:00
n1474335
d7b6f29c81 Updated CHANGELOG 2019-09-04 14:00:25 +01:00
n1474335
5bebd71a44 Merge branch 'Ge0rg3-steganography' 2019-09-04 13:55:17 +01:00
n1474335
eb769c7fb4 Tidied up Steganography operations. FileType and toBase64 functions now accept ArrayBuffers. 2019-09-04 13:54:59 +01:00
n1474335
5bc5c0df90 Merge branch 'steganography' of https://github.com/Ge0rg3/CyberChef into Ge0rg3-steganography 2019-09-04 11:31:58 +01:00
n1474335
cfc3684a16 Merge branch 'wesinator-patch-1' 2019-09-04 11:17:13 +01:00
n1474335
0590020130 Merge branch 'patch-1' of https://github.com/wesinator/CyberChef into wesinator-patch-1 2019-09-04 11:16:57 +01:00
n1474335
2a91af152d Fixed sitemap generation 2019-09-04 11:14:45 +01:00
Ԝеѕ
d8120d4e13 Add Quoted-printable example 2019-09-03 11:21:58 -04:00
n1474335
0ac211ce77 9.4.1 2019-08-30 18:49:11 +01:00
n1474335
32c0d6f253 Updated dependencies 2019-08-30 18:49:05 +01:00
n1474335
de762847e9 9.4.0 2019-08-30 15:48:47 +01:00
n1474335
6248e32148 Updated CHANGELOG 2019-08-30 15:47:50 +01:00
n1474335
52f88ee32d Merge branch 'j433866-render-markdown' 2019-08-30 15:46:37 +01:00
n1474335
f8d1cf2f60 Tidied up 'Render Markdown' operation 2019-08-30 15:46:24 +01:00
n1474335
e129425d8d Merge branch 'render-markdown' of https://github.com/j433866/CyberChef into j433866-render-markdown 2019-08-30 15:33:47 +01:00
n1474335
ae20d82e1d Fix Nightwatch test 2019-08-30 15:30:30 +01:00
n1474335
463b2ce040 9.3.0 2019-08-30 11:58:37 +01:00
n1474335
412b47abba Updated CHANGELOG 2019-08-30 11:58:32 +01:00
n1474335
ed216eee73 Merge branch 'j433866-show-on-map' 2019-08-30 11:57:00 +01:00
n1474335
9dd5234962 Tidied up 'Show on map' operation 2019-08-30 11:56:48 +01:00
n1474335
018532016b Merge branch 'show-on-map' of https://github.com/j433866/CyberChef into j433866-show-on-map 2019-08-30 11:44:12 +01:00
n1474335
7dfecc38f6 Added more UI tests to ensure all modules load, categories can be viewed, and operations can be dragged 2019-08-30 11:43:30 +01:00
Ge0rg3
aa5afadcce Tests for Randomize Colour Palette Op 2019-08-29 16:24:21 +01:00
Ge0rg3
d23a584b9e Randomize Colour Palette Operation 2019-08-29 16:17:07 +01:00
n1474335
572f035877 Background magic is now debounced to prevent it firing too often. 2019-08-29 14:08:56 +01:00
j433866
b94eb6adb0 Add syntax highlighting
Explicitly disable HTML rendering.
Updated description.
2019-08-29 14:08:07 +01:00
j433866
45fccb94e1 Merge remote-tracking branch 'upstream/master' into render-markdown 2019-08-29 13:23:37 +01:00
j433866
2628f17fae Change maps source to use Wikimedia maps.
Add link to Wikimedia maps ToS.
If there's no data, show the map anyway.
2019-08-29 11:43:45 +01:00
j433866
69fb6e77fc Merge remote-tracking branch 'upstream/master' into show-on-map 2019-08-29 10:42:40 +01:00
j433866
6992858e67 9.2.3 2019-08-29 10:23:41 +01:00
j433866
59917cca45 Add overflow CSS rule to fix scrolling. Fixes #626 2019-08-29 10:18:52 +01:00
n1474335
2f0b959aa4 Fixed copy:ghPages docs error 2019-08-28 18:48:31 +01:00
n1474335
4f2749e0dc 9.2.2 2019-08-28 17:14:20 +01:00
n1474335
c9deaae744 Updated supported browser versions. 2019-08-28 17:14:12 +01:00
Ge0rg3
950a12360e Tests + Bug Fixes
* Test cases for LSB extraction, RGBA extraction and bit plane browsing
* Bug fix for alpha planes in bit plane browser
2019-08-28 17:07:43 +01:00
n1474335
686ca284fe Removed JSDoc generation as it is never really used. JSDoc comments are still required but the doc files will no longer be generated. This simplifies the build process and config scripts. 2019-08-28 16:37:31 +01:00
n1474335
b21643f485 Merge branch 'master' of github.com:gchq/CyberChef 2019-08-28 16:14:49 +01:00
n1474335
4c28627459 Added pulse to Background Magic button to draw attention. 2019-08-28 16:14:13 +01:00
n1474335
6a6fe0f56d Update CONTRIBUTING.md 2019-08-28 15:47:33 +01:00
Ge0rg3
48831225ac Extract RGBA Values Operation 2019-08-28 09:58:00 +01:00
Ge0rg3
4e8a79d8f1 Bit Plane Browser and LSB Extraction
Bit Plane Browser and LSB Extraction

Bit Plane Browser and LSB Extraction
2019-08-28 01:06:59 +01:00
n1474335
570a4c7fca Update CHANGELOG.md 2019-08-27 18:30:33 +01:00
n1474335
094d352e5f Added eslint space-before-blocks rule 2019-08-27 18:13:33 +01:00
n1474335
44b90be7d6 Added 'fully qualified' to the description for the 'Extract Domains' operation to reduce ambiguity. #618 2019-08-27 17:59:45 +01:00
n1474335
e7980a8886 9.2.1 2019-08-27 13:02:24 +01:00
n1474335
1c9c0a48be Merge branch 'csmith-ip-format-octal' 2019-08-27 13:02:18 +01:00
n1474335
c541eebe3e Merge branch 'ip-format-octal' of https://github.com/csmith/CyberChef into csmith-ip-format-octal 2019-08-27 13:00:54 +01:00
n1474335
c51e6efe74 Merge branch 'chrishepner-scanembedded-typo' 2019-08-27 12:57:20 +01:00
Chris Smith
6c9ce15b26 Add octal support to Change IP Format.
Also add test cases covering interchanging between all four
formats.
2019-08-24 01:14:44 +01:00
Chris Hepner
8e1bd36b4c Fix typo in ScanForEmbeddedFiles
Change "suffiently" to "sufficiently"
2019-08-23 14:52:16 -07:00
j433866
82b5e97a2b Merge branch 'master' into render-markdown 2019-08-22 12:31:52 +01:00
j433866
7f168d49a6 Add render markdown operation 2019-07-12 09:33:13 +01:00
Martin Gillow
8ece8ebec2 Updated description 2019-04-01 13:40:53 +01:00
martin gillow
4d39c3bbd2 Fixed code spacing and formatting 2019-03-30 13:42:29 +00:00
martin gillow
23ddb87c9f Fixed code spacing and formatting 2019-03-30 13:02:14 +00:00
martin gillow
db662a7662 Removed debug. Final testing 2019-03-30 10:13:25 +00:00
martin gillow
39f3383709 Renamed option 2019-03-27 20:57:04 +00:00
martin gillow
4f8fc8d65e Fixed p5 limitation 2019-03-27 20:44:57 +00:00
Martin Gillow
0397ba857f Fixed motor wheel movement 2019-03-27 13:02:18 +00:00
martin gillow
444fb4555b Custom wheel settings 2019-03-25 21:10:47 +00:00
martin gillow
294f890a92 Merge branch 'master' of https://github.com/VirtualColossus/CyberChef 2019-03-25 19:47:50 +00:00
martin gillow
578502187d Added custom lug option 2019-03-25 19:37:20 +00:00
Martin Gillow
786082a9d0 Adding Lorenz SZ40/42 operation 2019-03-25 13:43:34 +00:00
Martin Gillow
b6eb851a13 Added Lorenz SZ40/42 operation 2019-03-25 13:34:25 +00:00
Martin Gillow
93c41f044c Added Lorenz SZ40/42 operation 2019-03-25 13:31:13 +00:00
VirtualColossus
a7f61397f7 Added Lorenz SZ40/42 Operation 2019-03-25 13:26:26 +00:00
VirtualColossus
0f5f20247a Added Lorenz SZ40/42 operation 2019-03-25 13:25:13 +00:00
Karsten Silkenbäumer
ad571e6019 Change author URL 2019-03-03 17:20:54 +01:00
Karsten Silkenbäumer
14d924f6c7 Add test for the error fixed before 2019-03-02 22:27:53 +01:00
Karsten Silkenbäumer
282f02f4d5 Fix error when decoding a text with 2+ whitespaces in AMNZ mode 2019-03-02 22:17:44 +01:00
Karsten Silkenbäumer
d36cede0c7 Use better names for the alphabet selection 2019-03-02 17:55:03 +01:00
Karsten Silkenbäumer
a262d70b88 Add Bacon cipher encoding 2019-03-02 17:33:17 +01:00
Karsten Silkenbäumer
77b098c5fe Add Bacon cipher decoding 2019-03-02 15:00:42 +01:00
j433866
b491b9d77d Move conversion of co-ordinates to run() instead of present() 2019-01-18 11:31:53 +00:00
j433866
237f792fb4 Add new Show on map operation 2019-01-18 11:19:06 +00:00
162 changed files with 5844 additions and 5305 deletions

View File

@@ -1,2 +1 @@
src/core/vendor/**
src/web/static/clippy_assets/**
src/core/vendor/**

View File

@@ -43,6 +43,7 @@
// stylistic conventions
"brace-style": ["error", "1tbs"],
"space-before-blocks": ["error", "always"],
"block-spacing": "error",
"array-bracket-spacing": "error",
"comma-spacing": "error",

View File

@@ -6,7 +6,7 @@ There are lots of opportunities to contribute to CyberChef. If you want ideas, t
Before your contributions can be accepted, you must:
- Sign the [GCHQ Contributor Licence Agreement](https://github.com/gchq/Gaffer/wiki/GCHQ-OSS-Contributor-License-Agreement-V1.0)
- Sign the [GCHQ Contributor Licence Agreement](https://cla-assistant.io/gchq/CyberChef)
- Push your changes to your fork.
- Submit a pull request.
@@ -25,9 +25,9 @@ Before your contributions can be accepted, you must:
## Design Principles
1. If at all possible, all operations and features should be client-side and not rely on connections to an external server. This increases the utility of CyberChef on closed networks and in virtual machines that are not connected to the Internet. Calls to external APIs may be accepted if there is no other option, but not for critical components.
2. Latency should be kept to a minimum to enhance the user experience. This means that all operation code should sit on the client, rather than being loaded dynamically from a server.
3. Use Vanilla JS if at all possible to reduce the number of libraries required and relied upon. Frameworks like jQuery, although included, should not be used unless absolutely necessary.
4. Minimise the use of large libraries, especially for niche operations that won't be used very often - these will be downloaded by everyone using the app, whether they use that operation or not (due to principal 2).
2. Latency should be kept to a minimum to enhance the user experience. This means that operation code should sit on the client and be executed there. However, as a trade-off between latency and bandwidth, operation code with large dependencies can be loaded in discrete modules in order to reduce the size of the initial download. The downloading of additional modules must remain entirely transparent so that the user is not inconvenienced.
3. Large libraries should be kept in separate modules so that they are not downloaded by everyone who uses the app, just those who specifically require the relevant operations.
4. Use Vanilla JS if at all possible to reduce the number of libraries required and relied upon. Frameworks like jQuery, although included, should not be used unless absolutely necessary.
With these principles in mind, any changes or additions to CyberChef should keep it:

View File

@@ -7,19 +7,18 @@ assignees: ''
---
<!-- Prefix the title above with 'Bug report:' -->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior or a link to the recipe / input used to cause the bug:
Steps to reproduce the behaviour or a link to the recipe / input used to cause the bug:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots**
@@ -27,9 +26,8 @@ If applicable, add screenshots to help explain your problem.
**Desktop (if relevant, please complete the following information):**
- OS: [e.g. Windows]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- Browser: [e.g. chrome 72, firefox 60]
- CyberChef version: [e.g. 9.7.14]
**Additional context**
Add any other context about the problem here.

View File

@@ -6,9 +6,9 @@ labels: feature
assignees: ''
---
<!-- Prefix the title above with 'Feature request:' -->
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A clear and concise description of what the problem is. E.g. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.

View File

@@ -7,8 +7,6 @@ assignees: ''
---
<!-- Prefix the title above with 'Operation request:' -->
## Summary
### Example Input

4
.gitignore vendored
View File

@@ -2,12 +2,8 @@ node_modules
npm-debug.log
travis.log
build
docs/*
!docs/*.conf.json
!docs/*.ico
.vscode
.*.swp
.DS_Store
src/core/config/modules/*
src/core/config/OperationConfig.json
src/core/operations/index.mjs

View File

@@ -3,6 +3,5 @@ npm-debug.log
travis.log
build/*
!build/node
docs
.vscode
.github

View File

@@ -1,6 +1,6 @@
language: node_js
node_js:
- lts/*
- lts/dubnium
cache: npm
addons:
chrome: stable
@@ -11,10 +11,9 @@ before_script:
script:
- grunt lint
- grunt test
- grunt docs
- grunt testnodeconsumer
- grunt prod --msg="$COMPILE_MSG"
- xvfb-run --server-args="-screen 0 1200x800x24" grunt testui
- grunt testnodeconsumer
before_deploy:
- grunt exec:sitemap
- grunt copy:ghPages

View File

@@ -2,6 +2,30 @@
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
### [9.10.0] - 2019-11-06
- 'Lorenz' operation added [@VirtualColossus] | [#528]
### [9.9.0] - 2019-11-01
- Added support for 109 more character encodings [@n1474335]
### [9.8.0] - 2019-10-31
- 'Avro to JSON' operation added [@jarrodconnolly] | [#865]
### [9.7.0] - 2019-09-13
- 'Optical Character Recognition' operation added [@MShwed] [@n1474335] | [#632]
### [9.6.0] - 2019-09-04
- 'Bacon Cipher Encode' and 'Bacon Cipher Decode' operations added [@kassi] | [#500]
### [9.5.0] - 2019-09-04
- Various Steganography operations added: 'Extract LSB', 'Extract RGBA', 'Randomize Colour Palette', and 'View Bit Plane' [@Ge0rg3] | [#625]
### [9.4.0] - 2019-08-30
- 'Render Markdown' operation added [@j433866] | [#627]
### [9.3.0] - 2019-08-30
- 'Show on map' operation added [@j433866] | [#477]
### [9.2.0] - 2019-08-23
- 'Parse UDP' operation added [@h345983745] | [#614]
@@ -15,6 +39,9 @@ All major and minor version changes will be documented in this file. Details of
- A [read-eval-print loop (REPL)](https://github.com/gchq/CyberChef/wiki/Node-API#repl) is also included to enable prototyping and experimentation with the API [@d98762625] | [#291]
- Light and dark Solarized themes added [@j433866] | [#566]
<details>
<summary>Click to expand v8 minor versions</summary>
### [8.38.0] - 2019-07-03
- 'Streebog' and 'GOST hash' operations added [@MShwed] [@n1474335] | [#530]
@@ -136,6 +163,8 @@ All major and minor version changes will be documented in this file. Details of
### [8.1.0] - 2018-08-19
- 'Dechunk HTTP response' operation added [@sevzero] | [#311]
</details>
## [8.0.0] - 2018-08-05
- Codebase rewritten using [ES modules](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/) and [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) [@n1474335] [@d98762625] [@artemisbot] [@picapi] | [#284]
- Operation architecture restructured to make adding new operations a lot simpler [@n1474335] | [#284]
@@ -165,6 +194,14 @@ All major and minor version changes will be documented in this file. Details of
[9.10.0]: https://github.com/gchq/CyberChef/releases/tag/v9.10.0
[9.9.0]: https://github.com/gchq/CyberChef/releases/tag/v9.9.0
[9.8.0]: https://github.com/gchq/CyberChef/releases/tag/v9.8.0
[9.7.0]: https://github.com/gchq/CyberChef/releases/tag/v9.7.0
[9.6.0]: https://github.com/gchq/CyberChef/releases/tag/v9.6.0
[9.5.0]: https://github.com/gchq/CyberChef/releases/tag/v9.5.0
[9.4.0]: https://github.com/gchq/CyberChef/releases/tag/v9.4.0
[9.3.0]: https://github.com/gchq/CyberChef/releases/tag/v9.3.0
[9.2.0]: https://github.com/gchq/CyberChef/releases/tag/v9.2.0
[9.1.0]: https://github.com/gchq/CyberChef/releases/tag/v9.1.0
[9.0.0]: https://github.com/gchq/CyberChef/releases/tag/v9.0.0
@@ -236,6 +273,9 @@ All major and minor version changes will be documented in this file. Details of
[@masq]: https://github.com/masq
[@Ge0rg3]: https://github.com/Ge0rg3
[@MShwed]: https://github.com/MShwed
[@kassi]: https://github.com/kassi
[@jarrodconnolly]: https://github.com/jarrodconnolly
[@VirtualColossus]: https://github.com/VirtualColossus
[#95]: https://github.com/gchq/CyberChef/pull/299
[#173]: https://github.com/gchq/CyberChef/pull/173
@@ -274,12 +314,15 @@ All major and minor version changes will be documented in this file. Details of
[#467]: https://github.com/gchq/CyberChef/pull/467
[#468]: https://github.com/gchq/CyberChef/pull/468
[#476]: https://github.com/gchq/CyberChef/pull/476
[#477]: https://github.com/gchq/CyberChef/pull/477
[#489]: https://github.com/gchq/CyberChef/pull/489
[#496]: https://github.com/gchq/CyberChef/pull/496
[#500]: https://github.com/gchq/CyberChef/pull/500
[#506]: https://github.com/gchq/CyberChef/pull/506
[#515]: https://github.com/gchq/CyberChef/pull/515
[#516]: https://github.com/gchq/CyberChef/pull/516
[#525]: https://github.com/gchq/CyberChef/pull/525
[#528]: https://github.com/gchq/CyberChef/pull/528
[#530]: https://github.com/gchq/CyberChef/pull/530
[#531]: https://github.com/gchq/CyberChef/pull/531
[#533]: https://github.com/gchq/CyberChef/pull/533
@@ -291,3 +334,7 @@ All major and minor version changes will be documented in this file. Details of
[#591]: https://github.com/gchq/CyberChef/pull/591
[#595]: https://github.com/gchq/CyberChef/pull/595
[#614]: https://github.com/gchq/CyberChef/pull/614
[#625]: https://github.com/gchq/CyberChef/pull/625
[#627]: https://github.com/gchq/CyberChef/pull/627
[#632]: https://github.com/gchq/CyberChef/pull/632
[#865]: https://github.com/gchq/CyberChef/pull/865

View File

@@ -14,7 +14,6 @@ const path = require("path");
* @license Apache-2.0
*/
module.exports = function (grunt) {
grunt.file.defaultEncoding = "utf8";
grunt.file.preserveBOM = false;
@@ -52,17 +51,10 @@ module.exports = function (grunt) {
"A task which checks whether consuming CJS and ESM apps work with the CyberChef build",
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:testESMDeepImportNodeConsumer", "exec:teardownNodeConsumers"]);
grunt.registerTask("docs",
"Compiles documentation in the /docs directory.",
["clean:docs", "jsdoc", "chmod:docs"]);
grunt.registerTask("default",
"Lints the code base",
["eslint", "exec:repoSize"]);
grunt.registerTask("doc", "docs");
grunt.registerTask("tests", "test");
grunt.registerTask("lint", "eslint");
@@ -70,7 +62,6 @@ module.exports = function (grunt) {
// Load tasks provided by each plugin
grunt.loadNpmTasks("grunt-eslint");
grunt.loadNpmTasks("grunt-webpack");
grunt.loadNpmTasks("grunt-jsdoc");
grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.loadNpmTasks("grunt-contrib-watch");
@@ -110,6 +101,26 @@ module.exports = function (grunt) {
return entryModules;
}
/**
* Detects the correct delimiter to use to chain shell commands together
* based on the current OS.
*
* @param {string[]} cmds
* @returns {string}
*/
function chainCommands(cmds) {
const win = process.platform === "win32";
if (!win) {
return cmds.join(";");
}
return cmds
// && means that subsequent commands will not be executed if the
// previous one fails. & would coninue on a fail
.join("&&")
// Windows does not support \n properly
.replace("\n", "\\n");
}
grunt.initConfig({
clean: {
dev: ["build/dev/*"],
@@ -117,7 +128,6 @@ module.exports = function (grunt) {
node: ["build/node/*"],
config: ["src/core/config/OperationConfig.json", "src/core/config/modules/*", "src/code/operations/index.mjs"],
nodeConfig: ["src/node/index.mjs", "src/node/config/OperationConfig.json"],
docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico", "!docs/*.png"],
standalone: ["build/prod/CyberChef*.html"]
},
eslint: {
@@ -130,22 +140,6 @@ module.exports = function (grunt) {
node: ["src/node/**/*.{js,mjs}"],
tests: ["tests/**/*.{js,mjs}"],
},
jsdoc: {
options: {
destination: "docs",
template: "node_modules/ink-docstrap/template",
recurse: true,
readme: "./README.md",
configure: "docs/jsdoc.conf.json"
},
all: {
src: [
"src/**/*.js",
"src/**/*.mjs",
"!src/core/vendor/**/*"
],
}
},
accessibility: {
options: {
accessibilityLevel: "WCAG2A",
@@ -165,8 +159,7 @@ module.exports = function (grunt) {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js",
sitemap: "./src/web/static/sitemap.js"
main: "./src/web/index.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod",
@@ -257,7 +250,6 @@ module.exports = function (grunt) {
"build/prod/**/*",
"!build/prod/index.html",
"!build/prod/BundleAnalyzerReport.html",
"!build/prod/sitemap.js"
],
dest: `build/prod/CyberChef_v${pkg.version}.zip`
}
@@ -295,12 +287,7 @@ module.exports = function (grunt) {
{
src: "build/prod/index.html",
dest: "build/prod/index.html"
},
{
expand: true,
src: "docs/**",
dest: "build/prod/"
},
}
]
},
standalone: {
@@ -332,12 +319,6 @@ module.exports = function (grunt) {
mode: "755",
},
src: ["build/**/*", "build/"]
},
docs: {
options: {
mode: "755",
},
src: ["docs/**/*", "docs/"]
}
},
watch: {
@@ -354,33 +335,33 @@ module.exports = function (grunt) {
},
exec: {
repoSize: {
command: [
command: chainCommands([
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
"du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
].join(";"),
]),
stderr: false
},
cleanGit: {
command: "git gc --prune=now --aggressive"
},
sitemap: {
command: "node build/prod/sitemap.js > build/prod/sitemap.xml"
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml"
},
generateConfig: {
command: [
command: chainCommands([
"echo '\n--- Regenerating config files. ---'",
"echo [] > src/core/config/OperationConfig.json",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
"echo '--- Config scripts finished. ---\n'"
].join(";")
])
},
generateNodeIndex: {
command: [
command: chainCommands([
"echo '\n--- Regenerating node index ---'",
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
"echo '--- Node index generated. ---\n'"
].join(";"),
]),
},
opTests: {
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
@@ -392,40 +373,40 @@ module.exports = function (grunt) {
command: "node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs"
},
setupNodeConsumers: {
command: [
"echo '\n--- Testing node conumers ---'",
command: chainCommands([
"echo '\n--- Testing node consumers ---'",
"npm link",
`mkdir ${nodeConsumerTestPath}`,
`cp tests/node/consumers/* ${nodeConsumerTestPath}`,
`cd ${nodeConsumerTestPath}`,
"npm link cyberchef"
].join(";"),
]),
},
teardownNodeConsumers: {
command: [
command: chainCommands([
`rm -rf ${nodeConsumerTestPath}`,
"echo '\n--- Node consumer tests complete ---'"
].join(";"),
]),
},
testCJSNodeConsumer: {
command: [
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings cjs-consumer.js",
].join(";"),
]),
stdout: false,
},
testESMNodeConsumer: {
command: [
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-consumer.mjs",
].join(";"),
]),
stdout: false,
},
testESMDeepImportNodeConsumer: {
command: [
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
].join(";"),
]),
stdout: false,
},
},

View File

@@ -69,16 +69,24 @@ You can use as many operations as you like in simple or complex ways. Some examp
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field. Files up to around 2GB are supported (depending on your browser), however some operations may take a very long time to run over this much data.
- CyberChef is entirely client-side
- It should be noted that none of your recipe configuration or input (either text or files) is ever sent to the CyberChef web server - all processing is carried out within your browser, on your own computer.
- Due to this feature, CyberChef can be compiled into a single HTML file. You can download this file and drop it into a virtual machine, share it with other people, or use it independently on your local machine.
- Due to this feature, CyberChef can be downloaded and run locally. You can use the link in the top left corner of the app to download a full copy of CyberChef and drop it into a virtual machine, share it with other people, or host it in a closed network.
## Deep linking
By manipulation of CyberChef's URL hash, you can change the initial settings with which the page opens.
The format is `https://gchq.github.io/CyberChef/#recipe=Operation()&input=...`
Supported arguments are `recipe`, `input` (encoded in Base64), and `theme`.
## Browser support
CyberChef is built to support
- Google Chrome 40+
- Mozilla Firefox 35+
- Microsoft Edge 14+
- Google Chrome 50+
- Mozilla Firefox 38+
## Node.js support

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,32 +0,0 @@
{
"tags": {
"allowUnknownTags": true
},
"plugins": [
"plugins/markdown",
"node_modules/jsdoc-babel"
],
"templates": {
"systemName": "CyberChef",
"footer": "",
"copyright": "&copy; Crown Copyright 2017",
"navType": "inline",
"theme": "cerulean",
"linenums": true,
"collapseSymbols": false,
"inverseNav": true,
"outputSourceFiles": true,
"outputSourcePath": true,
"dateFormat": "ddd MMM Do YYYY",
"sort": false,
"logoFile": "cyberchef-32x32.png",
"cleverLinks": false,
"monospaceLinks": false,
"protocol": "html://",
"methodHeadingReturns": false
},
"markdown": {
"parser": "gfm",
"hardwrap": true
}
}

2995
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.2.0",
"version": "9.10.0",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -31,25 +31,25 @@
"module": "src/node/index.mjs",
"bugs": "https://github.com/gchq/CyberChef/issues",
"browserslist": [
"Chrome >= 40",
"Firefox >= 35",
"Edge >= 14",
"node >= 6.5"
"Chrome >= 50",
"Firefox >= 38",
"node >= 10"
],
"devDependencies": {
"@babel/core": "^7.5.0",
"@babel/plugin-transform-runtime": "^7.5.0",
"@babel/preset-env": "^7.5.0",
"autoprefixer": "^9.6.0",
"babel-eslint": "^10.0.2",
"@babel/core": "^7.5.5",
"@babel/plugin-transform-runtime": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"autoprefixer": "^9.6.1",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"babel-plugin-dynamic-import-node": "^2.2.0",
"chromedriver": "^75.0.1",
"babel-plugin-dynamic-import-node": "^2.3.0",
"chromedriver": "^77.0.0",
"colors": "^1.3.3",
"css-loader": "^3.0.0",
"eslint": "^6.0.1",
"copy-webpack-plugin": "^5.0.4",
"css-loader": "^3.2.0",
"eslint": "^6.2.2",
"exports-loader": "^0.7.0",
"file-loader": "^4.0.0",
"file-loader": "^4.2.0",
"grunt": "^1.0.4",
"grunt-accessibility": "~6.0.0",
"grunt-chmod": "~1.1.1",
@@ -60,35 +60,33 @@
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^22.0.0",
"grunt-exec": "~3.0.0",
"grunt-jsdoc": "^2.4.0",
"grunt-webpack": "^3.1.3",
"grunt-zip": "^0.18.2",
"html-webpack-plugin": "^3.2.0",
"imports-loader": "^0.8.0",
"ink-docstrap": "^1.3.2",
"jsdoc-babel": "^0.5.0",
"mini-css-extract-plugin": "^0.7.0",
"nightwatch": "^1.1.13",
"mini-css-extract-plugin": "^0.8.0",
"nightwatch": "^1.2.1",
"node-sass": "^4.12.0",
"postcss-css-variables": "^0.13.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"prompt": "^1.0.0",
"sass-loader": "^7.1.0",
"sitemap": "^3.2.0",
"style-loader": "^0.23.1",
"svg-url-loader": "^3.0.0",
"url-loader": "^2.0.1",
"webpack": "^4.35.2",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-dev-server": "^3.7.2",
"sass-loader": "^8.0.0",
"sitemap": "^4.1.1",
"style-loader": "^1.0.0",
"svg-url-loader": "^3.0.1",
"url-loader": "^2.1.0",
"webpack": "^4.39.3",
"webpack-bundle-analyzer": "^3.4.1",
"webpack-dev-server": "^3.8.0",
"webpack-node-externals": "^1.7.2",
"worker-loader": "^2.0.0"
},
"dependencies": {
"@babel/polyfill": "^7.4.4",
"@babel/runtime": "^7.5.0",
"@babel/runtime": "^7.5.5",
"arrive": "^2.4.1",
"avsc": "^5.4.16",
"babel-plugin-transform-builtin-extend": "1.1.2",
"bcryptjs": "^2.4.3",
"bignumber.js": "^9.0.0",
@@ -98,23 +96,23 @@
"bootstrap-material-design": "^4.1.2",
"bson": "^4.0.2",
"chi-squared": "^1.1.0",
"clippyjs": "0.0.3",
"core-js": "^3.1.4",
"crypto-api": "^0.8.3",
"codepage": "^1.14.0",
"core-js": "^3.2.1",
"crypto-api": "^0.8.5",
"crypto-js": "^3.1.9-1",
"ctph.js": "0.0.5",
"d3": "^5.9.7",
"d3": "^5.11.0",
"d3-hexbin": "^0.2.2",
"diff": "^4.0.1",
"es6-promisify": "^6.0.1",
"escodegen": "^1.11.1",
"es6-promisify": "^6.0.2",
"escodegen": "^1.12.0",
"esm": "^3.2.25",
"esmangle": "^1.0.1",
"esprima": "^4.0.1",
"exif-parser": "^0.1.12",
"file-saver": "^2.0.2",
"geodesy": "^1.1.3",
"highlight.js": "^9.15.8",
"highlight.js": "^9.15.10",
"jimp": "^0.6.4",
"jquery": "3.4.1",
"js-crc": "^0.2.0",
@@ -124,16 +122,17 @@
"jsonwebtoken": "^8.5.1",
"jsqr": "^1.2.0",
"jsrsasign": "8.0.12",
"kbpgp": "2.1.2",
"kbpgp": "2.1.3",
"libbzip2-wasm": "0.0.4",
"libyara-wasm": "0.0.12",
"libyara-wasm": "^1.0.1",
"lodash": "^4.17.15",
"loglevel": "^1.6.3",
"loglevel-message-prefix": "^3.0.0",
"markdown-it": "^9.1.0",
"moment": "^2.24.0",
"moment-timezone": "^0.5.25",
"moment-timezone": "^0.5.26",
"ngeohash": "^0.6.3",
"node-forge": "^0.8.5",
"node-forge": "^0.9.1",
"node-md6": "^0.1.0",
"nodom": "^2.2.0",
"notepack.io": "^2.2.0",
@@ -146,6 +145,7 @@
"sortablejs": "^1.9.0",
"split.js": "^1.5.11",
"ssdeep.js": "0.0.2",
"tesseract.js": "^2.0.0-alpha.15",
"ua-parser-js": "^0.7.20",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3",
@@ -161,7 +161,7 @@
"test": "grunt test",
"test-node-consumer": "grunt testnodeconsumer",
"testui": "grunt testui",
"docs": "grunt docs",
"testuidev": "npx nightwatch --env=dev",
"lint": "grunt lint",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
}

View File

@@ -129,7 +129,7 @@ class Dish {
*
* @param {number} type - The data type of value, see Dish enums.
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
* @returns {* | Promise} - (Broswer) A promise | (Node) value of dish in given type
* @returns {* | Promise} - (Browser) A promise | (Node) value of dish in given type
*/
get(type, notUTF8=false) {
if (typeof type === "string") {
@@ -177,7 +177,7 @@ class Dish {
this.type = type;
if (!this.valid()) {
const sample = Utils.truncate(JSON.stringify(this.value), 13);
const sample = Utils.truncate(JSON.stringify(this.value), 25);
throw new DishError(`Data is not a valid ${Dish.enumLookup(type)}: ${sample}`);
}
}
@@ -191,7 +191,7 @@ class Dish {
*
* @param {number} type - The data type of value, see Dish enums.
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
* @returns {Dish | Promise} - (Broswer) A promise | (Node) value of dish in given type
* @returns {Dish | Promise} - (Browser) A promise | (Node) value of dish in given type
*/
presentAs(type, notUTF8=false) {
const clone = this.clone();

View File

@@ -201,9 +201,8 @@ class Utils {
* Utils.parseEscapedChars("\\n");
*/
static parseEscapedChars(str) {
return str.replace(/(\\)?\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a, b) {
if (a === "\\") return "\\"+b;
switch (b[0]) {
return str.replace(/\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a) {
switch (a[0]) {
case "\\":
return "\\";
case "0":
@@ -214,7 +213,7 @@ class Utils {
case "5":
case "6":
case "7":
return String.fromCharCode(parseInt(b, 8));
return String.fromCharCode(parseInt(a, 8));
case "b":
return "\b";
case "t":
@@ -232,12 +231,12 @@ class Utils {
case "'":
return "'";
case "x":
return String.fromCharCode(parseInt(b.substr(1), 16));
return String.fromCharCode(parseInt(a.substr(1), 16));
case "u":
if (b[1] === "{")
return String.fromCodePoint(parseInt(b.slice(2, -1), 16));
if (a[1] === "{")
return String.fromCodePoint(parseInt(a.slice(2, -1), 16));
else
return String.fromCharCode(parseInt(b.substr(1), 16));
return String.fromCharCode(parseInt(a.substr(1), 16));
}
});
}
@@ -1303,6 +1302,30 @@ export function sendStatusMessage(msg) {
console.debug(msg);
}
const debounceTimeouts = {};
/**
* Debouncer to stop functions from being executed multiple times in a
* short space of time
* https://davidwalsh.name/javascript-debounce-function
*
* @param {function} func - The function to be executed after the debounce time
* @param {number} wait - The time (ms) to wait before executing the function
* @param {string} id - Unique ID to reference the timeout for the function
* @param {object} scope - The object to bind to the debounced function
* @param {array} args - Array of arguments to be passed to func
* @returns {function}
*/
export function debounce(func, wait, id, scope, args) {
return function() {
const later = function() {
func.apply(scope, args);
};
clearTimeout(debounceTimeouts[id]);
debounceTimeouts[id] = setTimeout(later, wait);
};
}
/*
* Polyfills

View File

@@ -59,7 +59,8 @@
"From Braille",
"Parse TLV",
"CSV to JSON",
"JSON to CSV"
"JSON to CSV",
"Avro to JSON"
]
},
{
@@ -85,6 +86,8 @@
"Vigenère Decode",
"To Morse Code",
"From Morse Code",
"Bacon Cipher Encode",
"Bacon Cipher Decode",
"Bifid Cipher Encode",
"Bifid Cipher Decode",
"Affine Cipher Encode",
@@ -106,7 +109,8 @@
"Enigma",
"Bombe",
"Multiple Bombe",
"Typex"
"Typex",
"Lorenz"
]
},
{
@@ -121,6 +125,7 @@
"Generate PGP Key Pair",
"PGP Encrypt",
"PGP Decrypt",
"PGP Verify",
"PGP Encrypt and Sign",
"PGP Decrypt and Verify",
"Parse SSH Host Key"
@@ -228,6 +233,7 @@
"Convert speed",
"Convert data units",
"Convert co-ordinate format",
"Show on map",
"Parse UNIX file permissions",
"Swap endianness",
"Parse colour code",
@@ -281,6 +287,7 @@
"Zip",
"Unzip",
"Bzip2 Decompress",
"Bzip2 Compress",
"Tar",
"Untar"
]
@@ -357,7 +364,8 @@
"BSON serialise",
"BSON deserialise",
"To MessagePack",
"From MessagePack"
"From MessagePack",
"Render Markdown"
]
},
{
@@ -366,8 +374,13 @@
"Detect File Type",
"Scan for Embedded Files",
"Extract Files",
"YARA Rules",
"Remove EXIF",
"Extract EXIF"
"Extract EXIF",
"Extract RGBA",
"View Bit Plane",
"Randomize Colour Palette",
"Extract LSB"
]
},
{
@@ -375,6 +388,7 @@
"ops": [
"Render Image",
"Play Media",
"Optical Character Recognition",
"Remove EXIF",
"Extract EXIF",
"Split Colour Channels",
@@ -392,6 +406,7 @@
"Cover Image",
"Image Hue/Saturation/Lightness",
"Sharpen Image",
"Normalise Image",
"Convert Image Format",
"Add Text To Image",
"Hex Density chart",

View File

@@ -0,0 +1,9 @@
import OperationError from "./OperationError.mjs";
import DishError from "./DishError.mjs";
import ExcludedOperationError from "./ExcludedOperationError";
export {
OperationError,
DishError,
ExcludedOperationError,
};

View File

@@ -109,7 +109,7 @@ export function mean(data) {
*/
export function median(data) {
if ((data.length % 2) === 0 && data.length > 0) {
data.sort(function(a, b){
data.sort(function(a, b) {
return a.minus(b);
});
const first = data[Math.floor(data.length / 2)];

View File

@@ -22,7 +22,7 @@ export const ENCODING_SCHEME = [
/**
* Lookup table for the binary value of each digit representation.
*
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programmatically,
* but unfortunately it's much easier (if less elegant) to use lookup tables
* when supporting multiple encoding schemes.
*

66
src/core/lib/Bacon.mjs Normal file
View File

@@ -0,0 +1,66 @@
/**
* Bacon Cipher resources.
*
* @author Karsten Silkenbäumer [github.com/kassi]
* @copyright Karsten Silkenbäumer 2019
* @license Apache-2.0
*/
/**
* Bacon definitions.
*/
export const BACON_ALPHABETS = {
"Standard (I=J and U=V)": {
alphabet: "ABCDEFGHIKLMNOPQRSTUWXYZ",
codes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23]
},
"Complete": {
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}
};
export const BACON_TRANSLATION_01 = "0/1";
export const BACON_TRANSLATION_AB = "A/B";
export const BACON_TRANSLATION_CASE = "Case";
export const BACON_TRANSLATION_AMNZ = "A-M/N-Z first letter";
export const BACON_TRANSLATIONS = [
BACON_TRANSLATION_01,
BACON_TRANSLATION_AB,
BACON_TRANSLATION_CASE,
BACON_TRANSLATION_AMNZ,
];
export const BACON_TRANSLATIONS_FOR_ENCODING = [
BACON_TRANSLATION_01,
BACON_TRANSLATION_AB
];
export const BACON_CLEARER_MAP = {
[BACON_TRANSLATION_01]: /[^01]/g,
[BACON_TRANSLATION_AB]: /[^ABab]/g,
[BACON_TRANSLATION_CASE]: /[^A-Za-z]/g,
};
export const BACON_NORMALIZE_MAP = {
[BACON_TRANSLATION_AB]: {
"A": "0",
"B": "1",
"a": "0",
"b": "1"
},
};
/**
* Swaps zeros to ones and ones to zeros.
*
* @param {string} data
* @returns {string}
*
* @example
* // returns "11001 01010"
* swapZeroAndOne("00110 10101");
*/
export function swapZeroAndOne(string) {
return string.replace(/[01]/g, function (c) {
return {
"0": "1",
"1": "0"
}[c];
});
}

View File

@@ -7,12 +7,12 @@
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Base64's the input byte array using the given alphabet, returning a string.
*
* @param {byteArray|Uint8Array|string} data
* @param {byteArray|Uint8Array|ArrayBuffer|string} data
* @param {string} [alphabet="A-Za-z0-9+/="]
* @returns {string}
*
@@ -25,11 +25,17 @@ import Utils from "../Utils.mjs";
*/
export function toBase64(data, alphabet="A-Za-z0-9+/=") {
if (!data) return "";
if (data instanceof ArrayBuffer) {
data = new Uint8Array(data);
}
if (typeof data == "string") {
data = Utils.strToByteArray(data);
}
alphabet = Utils.expandAlphRange(alphabet).join("");
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
}
let output = "",
chr1, chr2, chr3,
@@ -83,6 +89,9 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
alphabet = alphabet || "A-Za-z0-9+/=";
alphabet = Utils.expandAlphRange(alphabet).join("");
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
}
const output = [];
let chr1, chr2, chr3,

View File

@@ -12,16 +12,65 @@
export const IO_FORMAT = {
"UTF-8 (65001)": 65001,
"UTF-7 (65000)": 65000,
"UTF16LE (1200)": 1200,
"UTF16BE (1201)": 1201,
"UTF16 (1201)": 1201,
"UTF-16LE (1200)": 1200,
"UTF-16BE (1201)": 1201,
"UTF-32LE (12000)": 12000,
"UTF-32BE (12001)": 12001,
"IBM EBCDIC International (500)": 500,
"IBM EBCDIC US-Canada (37)": 37,
"IBM EBCDIC Multilingual/ROECE (Latin 2) (870)": 870,
"IBM EBCDIC Greek Modern (875)": 875,
"IBM EBCDIC French (1010)": 1010,
"IBM EBCDIC Turkish (Latin 5) (1026)": 1026,
"IBM EBCDIC Latin 1/Open System (1047)": 1047,
"IBM EBCDIC Lao (1132/1133/1341)": 1132,
"IBM EBCDIC US-Canada (037 + Euro symbol) (1140)": 1140,
"IBM EBCDIC Germany (20273 + Euro symbol) (1141)": 1141,
"IBM EBCDIC Denmark-Norway (20277 + Euro symbol) (1142)": 1142,
"IBM EBCDIC Finland-Sweden (20278 + Euro symbol) (1143)": 1143,
"IBM EBCDIC Italy (20280 + Euro symbol) (1144)": 1144,
"IBM EBCDIC Latin America-Spain (20284 + Euro symbol) (1145)": 1145,
"IBM EBCDIC United Kingdom (20285 + Euro symbol) (1146)": 1146,
"IBM EBCDIC France (20297 + Euro symbol) (1147)": 1147,
"IBM EBCDIC International (500 + Euro symbol) (1148)": 1148,
"IBM EBCDIC Icelandic (20871 + Euro symbol) (1149)": 1149,
"IBM EBCDIC Germany (20273)": 20273,
"IBM EBCDIC Denmark-Norway (20277)": 20277,
"IBM EBCDIC Finland-Sweden (20278)": 20278,
"IBM EBCDIC Italy (20280)": 20280,
"IBM EBCDIC Latin America-Spain (20284)": 20284,
"IBM EBCDIC United Kingdom (20285)": 20285,
"IBM EBCDIC Japanese Katakana Extended (20290)": 20290,
"IBM EBCDIC France (20297)": 20297,
"IBM EBCDIC Arabic (20420)": 20420,
"IBM EBCDIC Greek (20423)": 20423,
"IBM EBCDIC Hebrew (20424)": 20424,
"IBM EBCDIC Korean Extended (20833)": 20833,
"IBM EBCDIC Thai (20838)": 20838,
"IBM EBCDIC Icelandic (20871)": 20871,
"IBM EBCDIC Cyrillic Russian (20880)": 20880,
"IBM EBCDIC Turkish (20905)": 20905,
"IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) (20924)": 20924,
"IBM EBCDIC Cyrillic Serbian-Bulgarian (21025)": 21025,
"OEM United States (437)": 437,
"OEM Greek (formerly 437G); Greek (DOS) (737)": 737,
"OEM Baltic; Baltic (DOS) (775)": 775,
"OEM Russian; Cyrillic + Euro symbol (808)": 808,
"OEM Multilingual Latin 1; Western European (DOS) (850)": 850,
"OEM Latin 2; Central European (DOS) (852)": 852,
"OEM Cyrillic (primarily Russian) (855)": 855,
"OEM Turkish; Turkish (DOS) (857)": 857,
"OEM Multilingual Latin 1 + Euro symbol (858)": 858,
"OEM Portuguese; Portuguese (DOS) (860)": 860,
"OEM Icelandic; Icelandic (DOS) (861)": 861,
"OEM Hebrew; Hebrew (DOS) (862)": 862,
"OEM French Canadian; French Canadian (DOS) (863)": 863,
"OEM Arabic; Arabic (864) (864)": 864,
"OEM Nordic; Nordic (DOS) (865)": 865,
"OEM Russian; Cyrillic (DOS) (866)": 866,
"OEM Modern Greek; Greek, Modern (DOS) (869)": 869,
"OEM Cyrillic (primarily Russian) + Euro Symbol (872)": 872,
"Windows-874 Thai (874)": 874,
"Japanese Shift-JIS (932)": 932,
"Simplified Chinese GBK (936)": 936,
"Korean (949)": 949,
"Traditional Chinese Big5 (950)": 950,
"Windows-1250 Central European (1250)": 1250,
"Windows-1251 Cyrillic (1251)": 1251,
"Windows-1252 Latin (1252)": 1252,
@@ -31,10 +80,6 @@ export const IO_FORMAT = {
"Windows-1256 Arabic (1256)": 1256,
"Windows-1257 Baltic (1257)": 1257,
"Windows-1258 Vietnam (1258)": 1258,
"US-ASCII (20127)": 20127,
"Simplified Chinese GB2312 (20936)": 20936,
"KOI8-R Russian Cyrillic (20866)": 20866,
"KOI8-U Ukrainian Cyrillic (21866)": 21866,
"ISO-8859-1 Latin 1 Western European (28591)": 28591,
"ISO-8859-2 Latin 2 Central European (28592)": 28592,
"ISO-8859-3 Latin 3 South European (28593)": 28593,
@@ -43,6 +88,7 @@ export const IO_FORMAT = {
"ISO-8859-6 Latin/Arabic (28596)": 28596,
"ISO-8859-7 Latin/Greek (28597)": 28597,
"ISO-8859-8 Latin/Hebrew (28598)": 28598,
"ISO 8859-8 Hebrew (ISO-Logical) (38598)": 38598,
"ISO-8859-9 Latin 5 Turkish (28599)": 28599,
"ISO-8859-10 Latin 6 Nordic (28600)": 28600,
"ISO-8859-11 Latin/Thai (28601)": 28601,
@@ -50,9 +96,71 @@ export const IO_FORMAT = {
"ISO-8859-14 Latin 8 Celtic (28604)": 28604,
"ISO-8859-15 Latin 9 (28605)": 28605,
"ISO-8859-16 Latin 10 (28606)": 28606,
"ISO-2022 JIS Japanese (50222)": 50222,
"ISO 2022 JIS Japanese with no halfwidth Katakana (50220)": 50220,
"ISO 2022 JIS Japanese with halfwidth Katakana (50221)": 50221,
"ISO 2022 Japanese JIS X 0201-1989 (1 byte Kana-SO/SI) (50222)": 50222,
"ISO 2022 Korean (50225)": 50225,
"ISO 2022 Simplified Chinese (50227)": 50227,
"ISO 6937 Non-Spacing Accent (20269)": 20269,
"EUC Japanese (51932)": 51932,
"EUC Simplified Chinese (51936)": 51936,
"EUC Korean (51949)": 51949,
"ISCII Devanagari (57002)": 57002,
"ISCII Bengali (57003)": 57003,
"ISCII Tamil (57004)": 57004,
"ISCII Telugu (57005)": 57005,
"ISCII Assamese (57006)": 57006,
"ISCII Oriya (57007)": 57007,
"ISCII Kannada (57008)": 57008,
"ISCII Malayalam (57009)": 57009,
"ISCII Gujarati (57010)": 57010,
"ISCII Punjabi (57011)": 57011,
"Japanese Shift-JIS (932)": 932,
"Simplified Chinese GBK (936)": 936,
"Korean (949)": 949,
"Traditional Chinese Big5 (950)": 950,
"US-ASCII (7-bit) (20127)": 20127,
"Simplified Chinese GB2312 (20936)": 20936,
"KOI8-R Russian Cyrillic (20866)": 20866,
"KOI8-U Ukrainian Cyrillic (21866)": 21866,
"Mazovia (Polish) MS-DOS (620)": 620,
"Arabic (ASMO 708) (708)": 708,
"Arabic (Transparent ASMO); Arabic (DOS) (720)": 720,
"Kamenický (Czech) MS-DOS (895)": 895,
"Korean (Johab) (1361)": 1361,
"MAC Roman (10000)": 10000,
"Japanese (Mac) (10001)": 10001,
"MAC Traditional Chinese (Big5) (10002)": 10002,
"Korean (Mac) (10003)": 10003,
"Arabic (Mac) (10004)": 10004,
"Hebrew (Mac) (10005)": 10005,
"Greek (Mac) (10006)": 10006,
"Cyrillic (Mac) (10007)": 10007,
"MAC Simplified Chinese (GB 2312) (10008)": 10008,
"Romanian (Mac) (10010)": 10010,
"Ukrainian (Mac) (10017)": 10017,
"Thai (Mac) (10021)": 10021,
"MAC Latin 2 (Central European) (10029)": 10029,
"Icelandic (Mac) (10079)": 10079,
"Turkish (Mac) (10081)": 10081,
"Croatian (Mac) (10082)": 10082,
"CNS Taiwan (Chinese Traditional) (20000)": 20000,
"TCA Taiwan (20001)": 20001,
"ETEN Taiwan (Chinese Traditional) (20002)": 20002,
"IBM5550 Taiwan (20003)": 20003,
"TeleText Taiwan (20004)": 20004,
"Wang Taiwan (20005)": 20005,
"Western European IA5 (IRV International Alphabet 5) (20105)": 20105,
"IA5 German (7-bit) (20106)": 20106,
"IA5 Swedish (7-bit) (20107)": 20107,
"IA5 Norwegian (7-bit) (20108)": 20108,
"T.61 (20261)": 20261,
"Japanese (JIS 0208-1990 and 0212-1990) (20932)": 20932,
"Korean Wansung (20949)": 20949,
"Extended/Ext Alpha Lowercase (21027)": 21027,
"Europa 3 (29001)": 29001,
"Atari ST/TT (47451)": 47451,
"HZ-GB2312 Simplified Chinese (52936)": 52936,
"Simplified Chinese GB18030 (54936)": 54936,
};

View File

@@ -6,9 +6,22 @@
* @license Apache-2.0
*/
import geohash from "ngeohash";
import geodesy from "geodesy";
import OperationError from "../errors/OperationError.mjs";
import geohash from "ngeohash";
/*
Currently unable to update to geodesy v2 as we cannot load .js modules into a .mjs file.
When we do update, imports will look like this:
import LatLonEllipsoidal from "geodesy/latlon-ellipsoidal.js";
import Mgrs from "geodesy/mgrs.js";
import OsGridRef from "geodesy/osgridref.js";
import Utm from "geodesy/utm.js";
*/
import geodesy from "geodesy";
const LatLonEllipsoidal = geodesy.LatLonEllipsoidal,
Mgrs = geodesy.Mgrs,
OsGridRef = geodesy.OsGridRef,
Utm = geodesy.Utm;
/**
* Co-ordinate formats
@@ -116,22 +129,22 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
switch (inFormat) {
case "Geohash":
hash = geohash.decode(input.replace(/[^A-Za-z0-9]/g, ""));
latlon = new geodesy.LatLonEllipsoidal(hash.latitude, hash.longitude);
latlon = new LatLonEllipsoidal(hash.latitude, hash.longitude);
break;
case "Military Grid Reference System":
utm = geodesy.Mgrs.parse(input.replace(/[^A-Za-z0-9]/g, "")).toUtm();
utm = Mgrs.parse(input.replace(/[^A-Za-z0-9]/g, "")).toUtm();
latlon = utm.toLatLonE();
break;
case "Ordnance Survey National Grid":
osng = geodesy.OsGridRef.parse(input.replace(/[^A-Za-z0-9]/g, ""));
latlon = geodesy.OsGridRef.osGridToLatLon(osng);
osng = OsGridRef.parse(input.replace(/[^A-Za-z0-9]/g, ""));
latlon = OsGridRef.osGridToLatLon(osng);
break;
case "Universal Transverse Mercator":
// Geodesy needs a space between the first 2 digits and the next letter
if (/^[\d]{2}[A-Za-z]/.test(input)) {
input = input.slice(0, 2) + " " + input.slice(2);
}
utm = geodesy.Utm.parse(input);
utm = Utm.parse(input);
latlon = utm.toLatLonE();
break;
case "Degrees Minutes Seconds":
@@ -143,7 +156,7 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
if (splitLat.length >= 3 && splitLong.length >= 3) {
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2], 10);
lon = convDMSToDD(splitLong[0], splitLong[1], splitLong[2], 10);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
latlon = new LatLonEllipsoidal(lat.degrees, lon.degrees);
} else {
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
}
@@ -152,7 +165,7 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
splitLat = splitInput(split[0]);
if (splitLat.length >= 3) {
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2]);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
latlon = new LatLonEllipsoidal(lat.degrees, lat.degrees);
} else {
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
}
@@ -168,7 +181,7 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
// Convert to decimal degrees, and then convert to a geodesy object
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
lon = convDDMToDD(splitLong[0], splitLong[1], 10);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
latlon = new LatLonEllipsoidal(lat.degrees, lon.degrees);
} else {
// Not a pair, so only try to convert one set of co-ordinates
splitLat = splitInput(input);
@@ -176,7 +189,7 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
}
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
latlon = new LatLonEllipsoidal(lat.degrees, lat.degrees);
}
break;
case "Decimal Degrees":
@@ -186,14 +199,14 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
if (splitLat.length !== 1 || splitLong.length !== 1) {
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
}
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLong[0]);
latlon = new LatLonEllipsoidal(splitLat[0], splitLong[0]);
} else {
// Not a pair, so only try to convert one set of co-ordinates
splitLat = splitInput(split[0]);
if (splitLat.length !== 1) {
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
}
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLat[0]);
latlon = new LatLonEllipsoidal(splitLat[0], splitLat[0]);
}
break;
default:
@@ -260,7 +273,7 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
convLat = mgrs.toString(precision);
break;
case "Ordnance Survey National Grid":
osng = geodesy.OsGridRef.latLonToOsGrid(latlon);
osng = OsGridRef.latLonToOsGrid(latlon);
if (osng.toString() === "") {
throw new OperationError("Could not convert co-ordinates to OS National Grid. Are the co-ordinates in range?");
}
@@ -327,13 +340,13 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
* @param {string} input - The input data to be split
* @returns {number[]} An array of the different items in the string, stored as floats
*/
function splitInput (input){
function splitInput (input) {
const split = [];
input.split(/\s+/).forEach(item => {
// Remove any character that isn't a digit, decimal point or negative sign
item = item.replace(/[^0-9.-]/g, "");
if (item.length > 0){
if (item.length > 0) {
// Turn the item into a float
split.push(parseFloat(item));
}
@@ -350,7 +363,7 @@ function splitInput (input){
* @param {number} precision - The precision the result should be rounded to
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
*/
function convDMSToDD (degrees, minutes, seconds, precision){
function convDMSToDD (degrees, minutes, seconds, precision) {
const absDegrees = Math.abs(degrees);
let conv = absDegrees + (minutes / 60) + (seconds / 3600);
let outString = round(conv, precision) + "°";
@@ -566,7 +579,7 @@ export function findFormat (input, delim) {
// Test DMS/DDM/DD formats
if (testData !== undefined) {
const split = splitInput(testData);
switch (split.length){
switch (split.length) {
case 3:
return "Degrees Minutes Seconds";
case 2:

View File

@@ -32,7 +32,7 @@ export const WORD_DELIM_OPTIONS = ["Line feed", "CRLF", "Forward slash", "Backsl
export const INPUT_DELIM_OPTIONS = ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"];
/**
* Armithmetic sequence delimiters
* Arithmetic sequence delimiters
*/
export const ARITHMETIC_DELIM_OPTIONS = ["Line feed", "Space", "Comma", "Semi-colon", "Colon", "CRLF"];
@@ -72,3 +72,12 @@ export const JOIN_DELIM_OPTIONS = [
{name: "Nothing (join chars)", value: ""}
];
/**
* RGBA list delimiters.
*/
export const RGBA_DELIM_OPTIONS = [
{name: "Comma", value: ","},
{name: "Space", value: " "},
{name: "CRLF", value: "\\r\\n"},
{name: "Line Feed", value: "\n"}
];

File diff suppressed because it is too large Load Diff

View File

@@ -75,7 +75,7 @@ function bytesMatch(sig, buf, offset=0) {
* Given a buffer, detects magic byte sequences at specific positions and returns the
* extension and mime type.
*
* @param {Uint8Array} buf
* @param {Uint8Array|ArrayBuffer} buf
* @param {string[]} [categories=All] - Which categories of file to look for
* @returns {Object[]} types
* @returns {string} type.name - Name of file type
@@ -84,6 +84,10 @@ function bytesMatch(sig, buf, offset=0) {
* @returns {string} [type.desc] - Description
*/
export function detectFileType(buf, categories=Object.keys(FILE_SIGNATURES)) {
if (buf instanceof ArrayBuffer) {
buf = new Uint8Array(buf);
}
if (!(buf && buf.length > 1)) {
return [];
}
@@ -174,7 +178,7 @@ export function scanForFileTypes(buf, categories=Object.keys(FILE_SIGNATURES)) {
* @param {Uint8Array} buf - The buffer to search
* @param {Object} sig - A single signature object (Not an array of signatures)
* @param {number} offset - Where to start search from
* @returs {number} The position of the match or -1 if one cannot be found.
* @returns {number} The position of the match or -1 if one cannot be found.
*/
function locatePotentialSig(buf, sig, offset) {
// Find values for first key and value in sig
@@ -203,7 +207,7 @@ function locatePotentialSig(buf, sig, offset) {
* Detects whether the given buffer is a file of the type specified.
*
* @param {string|RegExp} type
* @param {Uint8Array} buf
* @param {Uint8Array|ArrayBuffer} buf
* @returns {string|false} The mime type or false if the type does not match
*/
export function isType(type, buf) {
@@ -230,7 +234,7 @@ export function isType(type, buf) {
/**
* Detects whether the given buffer contains an image file.
*
* @param {Uint8Array} buf
* @param {Uint8Array|ArrayBuffer} buf
* @returns {string|false} The mime type or false if the type does not match
*/
export function isImage(buf) {

View File

@@ -241,7 +241,7 @@ export function ipv6ListedRange(match, includeNetworkInfo) {
ipv6List = ipv6List.filter(function(str) {
return str.trim();
});
for (let i =0; i < ipv6List.length; i++){
for (let i =0; i < ipv6List.length; i++) {
ipv6List[i] = ipv6List[i].trim();
}
const ipv6CidrList = ipv6List.filter(function(a) {
@@ -502,8 +502,8 @@ export function ipv6Compare(a, b) {
const a_ = strToIpv6(a),
b_ = strToIpv6(b);
for (let i = 0; i < a_.length; i++){
if (a_[i] !== b_[i]){
for (let i = 0; i < a_.length; i++) {
if (a_[i] !== b_[i]) {
return a_[i] - b_[i];
}
}

View File

@@ -85,7 +85,7 @@ function getWords(length=3) {
const words = [];
let word;
let previousWord;
while (words.length < length){
while (words.length < length) {
do {
word = wordList[Math.floor(Math.random() * wordList.length)];
} while (previousWord === word);

View File

@@ -97,6 +97,7 @@ class Magic {
if (!fileType.length) return null;
return {
name: fileType[0].name,
ext: fileType[0].extension,
mime: fileType[0].mime,
desc: fileType[0].description
@@ -354,17 +355,17 @@ class Magic {
let aScore = a.languageScores[0].score,
bScore = b.languageScores[0].score;
// If a recipe results in a file being detected, it receives a relatively good score
if (a.fileType) aScore = 500;
if (b.fileType) bScore = 500;
// If the result is valid UTF8, its score gets boosted (lower being better)
if (a.isUTF8) aScore -= 100;
if (b.isUTF8) bScore -= 100;
// If a recipe results in a file being detected, it receives a relatively good score
if (a.fileType && aScore > 500) aScore = 500;
if (b.fileType && bScore > 500) bScore = 500;
// If the option is marked useful, give it a good score
if (a.useful) aScore = 100;
if (b.useful) bScore = 100;
if (a.useful && aScore > 100) aScore = 100;
if (b.useful && bScore > 100) bScore = 100;
// Shorter recipes are better, so we add the length of the recipe to the score
aScore += a.recipe.length;
@@ -497,7 +498,7 @@ class Magic {
* Taken from http://wikistats.wmflabs.org/display.php?t=wp
*
* @param {string} code - ISO 639 code
* @returns {string} The full name of the languge
* @returns {string} The full name of the language
*/
static codeToLanguage(code) {
return {

View File

@@ -37,7 +37,7 @@ export async function parseQrCode(input, normalise) {
image = await jimp.read(image);
}
} catch (err) {
throw new OperationError(`Error normalising iamge. (${err})`);
throw new OperationError(`Error normalising image. (${err})`);
}
const qrData = jsQR(image.bitmap.data, image.getWidth(), image.getHeight());

View File

@@ -121,7 +121,7 @@ class AddTextToImage extends Operation {
let xPos = args[3],
yPos = args[4];
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -0,0 +1,76 @@
/**
* @author jarrodconnolly [jarrod@nestedquotes.ca]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import avro from "avsc";
/**
* Avro to JSON operation
*/
class AvroToJSON extends Operation {
/**
* AvroToJSON constructor
*/
constructor() {
super();
this.name = "Avro to JSON";
this.module = "Serialise";
this.description = "Converts Avro encoded data into JSON.";
this.infoURL = "https://wikipedia.org/wiki/Apache_Avro";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
name: "Force Valid JSON",
type: "boolean",
value: true
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
if (input.byteLength <= 0) {
throw new OperationError("Please provide an input.");
}
const forceJSON = args[0];
return new Promise((resolve, reject) => {
const result = [];
const inpArray = new Uint8Array(input);
const decoder = new avro.streams.BlockDecoder();
decoder
.on("data", function (obj) {
result.push(obj);
})
.on("error", function () {
reject(new OperationError("Error parsing Avro file."));
})
.on("end", function () {
if (forceJSON) {
resolve(result.length === 1 ? JSON.stringify(result[0], null, 4) : JSON.stringify(result, null, 4));
} else {
const data = result.reduce((result, current) => result + JSON.stringify(current) + "\n", "");
resolve(data);
}
});
decoder.write(inpArray);
decoder.end();
});
}
}
export default AvroToJSON;

View File

@@ -50,7 +50,7 @@ class BLAKE2b extends Operation {
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string} The input having been hashed with BLAKE2b in the encoding format speicifed.
* @returns {string} The input having been hashed with BLAKE2b in the encoding format specified.
*/
run(input, args) {
const [outSize, outFormat] = args;

View File

@@ -51,7 +51,7 @@ class BLAKE2s extends Operation {
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string} The input having been hashed with BLAKE2s in the encoding format speicifed.
* @returns {string} The input having been hashed with BLAKE2s in the encoding format specified.
*/
run(input, args) {
const [outSize, outFormat] = args;

View File

@@ -20,7 +20,7 @@ class BSONDeserialise extends Operation {
super();
this.name = "BSON deserialise";
this.module = "BSON";
this.module = "Serialise";
this.description = "BSON is a computer data interchange format used mainly as a data storage and network transfer format in the MongoDB database. It is a binary form for representing simple data structures, associative arrays (called objects or documents in MongoDB), and various data types of specific interest to MongoDB. The name 'BSON' is based on the term JSON and stands for 'Binary JSON'.<br><br>Input data should be in a raw bytes format.";
this.infoURL = "https://wikipedia.org/wiki/BSON";
this.inputType = "ArrayBuffer";

View File

@@ -20,7 +20,7 @@ class BSONSerialise extends Operation {
super();
this.name = "BSON serialise";
this.module = "BSON";
this.module = "Serialise";
this.description = "BSON is a computer data interchange format used mainly as a data storage and network transfer format in the MongoDB database. It is a binary form for representing simple data structures, associative arrays (called objects or documents in MongoDB), and various data types of specific interest to MongoDB. The name 'BSON' is based on the term JSON and stands for 'Binary JSON'.<br><br>Input data should be valid JSON.";
this.infoURL = "https://wikipedia.org/wiki/BSON";
this.inputType = "string";

View File

@@ -0,0 +1,107 @@
/**
* @author Karsten Silkenbäumer [github.com/kassi]
* @copyright Karsten Silkenbäumer 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import {
BACON_ALPHABETS,
BACON_TRANSLATION_CASE, BACON_TRANSLATION_AMNZ, BACON_TRANSLATIONS, BACON_CLEARER_MAP, BACON_NORMALIZE_MAP,
swapZeroAndOne
} from "../lib/Bacon";
/**
* Bacon Cipher Decode operation
*/
class BaconCipherDecode extends Operation {
/**
* BaconCipherDecode constructor
*/
constructor() {
super();
this.name = "Bacon Cipher Decode";
this.module = "Default";
this.description = "Bacon's cipher or the Baconian cipher is a method of steganography devised by Francis Bacon in 1605. A message is concealed in the presentation of text, rather than its content.";
this.infoURL = "https://wikipedia.org/wiki/Bacon%27s_cipher";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Alphabet",
"type": "option",
"value": Object.keys(BACON_ALPHABETS)
},
{
"name": "Translation",
"type": "option",
"value": BACON_TRANSLATIONS
},
{
"name": "Invert Translation",
"type": "boolean",
"value": false
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [alphabet, translation, invert] = args;
const alphabetObject = BACON_ALPHABETS[alphabet];
// remove invalid characters
input = input.replace(BACON_CLEARER_MAP[translation], "");
// normalize to unique alphabet
if (BACON_NORMALIZE_MAP[translation] !== undefined) {
input = input.replace(/./g, function (c) {
return BACON_NORMALIZE_MAP[translation][c];
});
} else if (translation === BACON_TRANSLATION_CASE) {
const codeA = "A".charCodeAt(0);
const codeZ = "Z".charCodeAt(0);
input = input.replace(/./g, function (c) {
const code = c.charCodeAt(0);
if (code >= codeA && code <= codeZ) {
return "1";
} else {
return "0";
}
});
} else if (translation === BACON_TRANSLATION_AMNZ) {
const words = input.split(/\s+/);
const letters = words.map(function (e) {
if (e) {
const code = e[0].toUpperCase().charCodeAt(0);
return code >= "N".charCodeAt(0) ? "1" : "0";
} else {
return "";
}
});
input = letters.join("");
}
if (invert) {
input = swapZeroAndOne(input);
}
// group into 5
const inputArray = input.match(/(.{5})/g) || [];
let output = "";
for (let i = 0; i < inputArray.length; i++) {
const code = inputArray[i];
const number = parseInt(code, 2);
output += number < alphabetObject.alphabet.length ? alphabetObject.alphabet[number] : "?";
}
return output;
}
}
export default BaconCipherDecode;

View File

@@ -0,0 +1,101 @@
/**
* @author Karsten Silkenbäumer [github.com/kassi]
* @copyright Karsten Silkenbäumer 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import {
BACON_ALPHABETS,
BACON_TRANSLATIONS_FOR_ENCODING, BACON_TRANSLATION_AB,
swapZeroAndOne
} from "../lib/Bacon";
/**
* Bacon Cipher Encode operation
*/
class BaconCipherEncode extends Operation {
/**
* BaconCipherEncode constructor
*/
constructor() {
super();
this.name = "Bacon Cipher Encode";
this.module = "Default";
this.description = "Bacon's cipher or the Baconian cipher is a method of steganography devised by Francis Bacon in 1605. A message is concealed in the presentation of text, rather than its content.";
this.infoURL = "https://wikipedia.org/wiki/Bacon%27s_cipher";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Alphabet",
"type": "option",
"value": Object.keys(BACON_ALPHABETS)
},
{
"name": "Translation",
"type": "option",
"value": BACON_TRANSLATIONS_FOR_ENCODING
},
{
"name": "Keep extra characters",
"type": "boolean",
"value": false
},
{
"name": "Invert Translation",
"type": "boolean",
"value": false
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [alphabet, translation, keep, invert] = args;
const alphabetObject = BACON_ALPHABETS[alphabet];
const charCodeA = "A".charCodeAt(0);
const charCodeZ = "Z".charCodeAt(0);
let output = input.replace(/./g, function (c) {
const charCode = c.toUpperCase().charCodeAt(0);
if (charCode >= charCodeA && charCode <= charCodeZ) {
let code = charCode - charCodeA;
if (alphabetObject.codes !== undefined) {
code = alphabetObject.codes[code];
}
const bacon = ("00000" + code.toString(2)).substr(-5, 5);
return bacon;
} else {
return c;
}
});
if (invert) {
output = swapZeroAndOne(output);
}
if (!keep) {
output = output.replace(/[^01]/g, "");
const outputArray = output.match(/(.{5})/g) || [];
output = outputArray.join(" ");
}
if (translation === BACON_TRANSLATION_AB) {
output = output.replace(/[01]/g, function (c) {
return {
"0": "A",
"1": "B"
}[c];
});
}
return output;
}
}
export default BaconCipherEncode;

View File

@@ -53,7 +53,7 @@ class BlurImage extends Operation {
async run(input, args) {
const [blurAmount, blurType] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}
@@ -64,7 +64,7 @@ class BlurImage extends Operation {
throw new OperationError(`Error loading image. (${err})`);
}
try {
switch (blurType){
switch (blurType) {
case "Fast":
if (isWorkerEnvironment())
self.sendStatusMessage("Fast blurring image...");

View File

@@ -23,7 +23,7 @@ class Bombe extends Operation {
super();
this.name = "Bombe";
this.module = "Default";
this.module = "Bletchley";
this.description = "Emulation of the Bombe machine used at Bletchley Park to attack Enigma, based on work by Polish and British cryptanalysts.<br><br>To run this you need to have a 'crib', which is some known plaintext for a chunk of the target ciphertext, and know the rotors used. (See the 'Bombe (multiple runs)' operation if you don't know the rotors.) The machine will suggest possible configurations of the Enigma. Each suggestion has the rotor start positions (left to right) and known plugboard pairs.<br><br>Choosing a crib: First, note that Enigma cannot encrypt a letter to itself, which allows you to rule out some positions for possible cribs. Secondly, the Bombe does not simulate the Enigma's middle rotor stepping. The longer your crib, the more likely a step happened within it, which will prevent the attack working. However, other than that, longer cribs are generally better. The attack produces a 'menu' which maps ciphertext letters to plaintext, and the goal is to produce 'loops': for example, with ciphertext ABC and crib CAB, we have the mappings A&lt;-&gt;C, B&lt;-&gt;A, and C&lt;-&gt;B, which produces a loop A-B-C-A. The more loops, the better the crib. The operation will output this: if your menu has too few loops or is too short, a large number of incorrect outputs will usually be produced. Try a different crib. If the menu seems good but the right answer isn't produced, your crib may be wrong, or you may have overlapped the middle rotor stepping - try a different crib.<br><br>Output is not sufficient to fully decrypt the data. You will have to recover the rest of the plugboard settings by inspection. And the ring position is not taken into account: this affects when the middle rotor steps. If your output is correct for a bit, and then goes wrong, adjust the ring and start position on the right-hand rotor together until the output improves. If necessary, repeat for the middle rotor.<br><br>By default this operation runs the checking machine, a manual process to verify the quality of Bombe stops, on each stop, discarding stops which fail. If you want to see how many times the hardware actually stops for a given input, disable the checking machine.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
this.infoURL = "https://wikipedia.org/wiki/Bombe";
this.inputType = "string";

View File

@@ -47,7 +47,7 @@ class Bzip2Decompress extends Operation {
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
async run(input, args) {
const [small] = args;
if (input.byteLength <= 0) {
throw new OperationError("Please provide an input.");

View File

@@ -29,12 +29,12 @@ class ChangeIPFormat extends Operation {
{
"name": "Input format",
"type": "option",
"value": ["Dotted Decimal", "Decimal", "Hex"]
"value": ["Dotted Decimal", "Decimal", "Octal", "Hex"]
},
{
"name": "Output format",
"type": "option",
"value": ["Dotted Decimal", "Decimal", "Hex"]
"value": ["Dotted Decimal", "Decimal", "Octal", "Hex"]
}
];
}
@@ -54,7 +54,6 @@ class ChangeIPFormat extends Operation {
if (lines[i] === "") continue;
let baIp = [];
let octets;
let decimal;
if (inFormat === outFormat) {
output += lines[i] + "\n";
@@ -70,11 +69,10 @@ class ChangeIPFormat extends Operation {
}
break;
case "Decimal":
decimal = lines[i].toString();
baIp.push(decimal >> 24 & 255);
baIp.push(decimal >> 16 & 255);
baIp.push(decimal >> 8 & 255);
baIp.push(decimal & 255);
baIp = this.fromNumber(lines[i].toString(), 10);
break;
case "Octal":
baIp = this.fromNumber(lines[i].toString(), 8);
break;
case "Hex":
baIp = fromHex(lines[i]);
@@ -100,6 +98,10 @@ class ChangeIPFormat extends Operation {
decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
output += decIp.toString() + "\n";
break;
case "Octal":
decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
output += "0" + decIp.toString(8) + "\n";
break;
case "Hex":
hexIp = "";
for (j = 0; j < baIp.length; j++) {
@@ -115,6 +117,22 @@ class ChangeIPFormat extends Operation {
return output.slice(0, output.length-1);
}
/**
* Constructs an array of IP address octets from a numerical value.
* @param {string} value The value of the IP address
* @param {number} radix The numeral system to be used
* @returns {number[]}
*/
fromNumber(value, radix) {
const decimal = parseInt(value, radix);
const baIp = [];
baIp.push(decimal >> 24 & 255);
baIp.push(decimal >> 16 & 255);
baIp.push(decimal >> 8 & 255);
baIp.push(decimal & 255);
return baIp;
}
}
export default ChangeIPFormat;

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import cptable from "../vendor/js-codepage/cptable.js";
import cptable from "codepage";
/**
* Citrix CTX1 Decode operation

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation.mjs";
import cptable from "../vendor/js-codepage/cptable.js";
import cptable from "codepage";
/**
* Citrix CTX1 Encode operation

View File

@@ -107,7 +107,7 @@ class ContainImage extends Operation {
"Bottom": jimp.VERTICAL_ALIGN_BOTTOM
};
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -54,7 +54,7 @@ class ConvertDataUnits extends Operation {
const DATA_UNITS = [
"Bits (b)", "Nibbles", "Octets", "Bytes (B)",
"[Binary bits (2^n)]", "Kibibits (Kib)", "Mebibits (Mib)", "Gibibits (Gib)", "Tebibits (Tib)", "Pebibits (Pib)", "Exbibits (Eib)", "Zebibits (Zib)", "Yobibits (Yib)", "[/Binary bits (2^n)]",
"[Decimal bits (10^n)]", "Decabits", "Hectobits", "Kilobits (kb)", "Megabits (Mb)", "Gigabits (Gb)", "Terabits (Tb)", "Petabits (Pb)", "Exabits (Eb)", "Zettabits (Zb)", "Yottabits (Yb)", "[/Decimal bits (10^n)]",
"[Decimal bits (10^n)]", "Decabits", "Hectobits", "Kilobits (Kb)", "Megabits (Mb)", "Gigabits (Gb)", "Terabits (Tb)", "Petabits (Pb)", "Exabits (Eb)", "Zettabits (Zb)", "Yottabits (Yb)", "[/Decimal bits (10^n)]",
"[Binary bytes (8 x 2^n)]", "Kibibytes (KiB)", "Mebibytes (MiB)", "Gibibytes (GiB)", "Tebibytes (TiB)", "Pebibytes (PiB)", "Exbibytes (EiB)", "Zebibytes (ZiB)", "Yobibytes (YiB)", "[/Binary bytes (8 x 2^n)]",
"[Decimal bytes (8 x 10^n)]", "Kilobytes (KB)", "Megabytes (MB)", "Gigabytes (GB)", "Terabytes (TB)", "Petabytes (PB)", "Exabytes (EB)", "Zettabytes (ZB)", "Yottabytes (YB)", "[/Decimal bytes (8 x 10^n)]"
];

View File

@@ -93,7 +93,7 @@ class ConvertImageFormat extends Operation {
const mime = formatMap[format];
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file format.");
}
let image;

View File

@@ -102,7 +102,7 @@ class CoverImage extends Operation {
"Bottom": jimp.VERTICAL_ALIGN_BOTTOM
};
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -93,7 +93,7 @@ class CropImage extends Operation {
*/
async run(input, args) {
const [xPos, yPos, width, height, autocrop, autoTolerance, autoFrames, autoSymmetric, autoBorder] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -73,6 +73,12 @@ class DESDecrypt extends Operation {
DES uses a key length of 8 bytes (64 bits).
Triple DES uses a key length of 24 bytes (192 bits).`);
}
if (iv.length !== 8 && mode !== "ECB") {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);

View File

@@ -73,6 +73,12 @@ class DESEncrypt extends Operation {
DES uses a key length of 8 bytes (64 bits).
Triple DES uses a key length of 24 bytes (192 bits).`);
}
if (iv.length !== 8 && mode !== "ECB") {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);

View File

@@ -111,7 +111,7 @@ class DNSOverHTTPS extends Operation {
* @returns {JSON}
*/
function extractData(data) {
if (typeof(data) == "undefined"){
if (typeof(data) == "undefined") {
return [];
} else {
const dataValues = [];

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation.mjs";
import cptable from "../vendor/js-codepage/cptable.js";
import cptable from "codepage";
import {IO_FORMAT} from "../lib/ChrEnc.mjs";
/**

View File

@@ -8,6 +8,13 @@ import Operation from "../Operation.mjs";
import {detectFileType} from "../lib/FileType.mjs";
import {FILE_SIGNATURES} from "../lib/FileSignatures.mjs";
// Concat all supported extensions into a single flat list
const exts = [].concat.apply([], Object.keys(FILE_SIGNATURES).map(cat =>
[].concat.apply([], FILE_SIGNATURES[cat].map(sig =>
sig.extension.split(",")
))
)).unique().sort().join(", ");
/**
* Detect File Type operation
*/
@@ -22,11 +29,7 @@ class DetectFileType extends Operation {
this.name = "Detect File Type";
this.module = "Default";
this.description = "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.<br><br>Currently supports the following file types: " +
Object.keys(FILE_SIGNATURES).map(cat =>
FILE_SIGNATURES[cat].map(sig =>
sig.extension.split(",")[0]
).join(", ")
).join(", ") + ".";
exts + ".";
this.infoURL = "https://wikipedia.org/wiki/List_of_file_signatures";
this.inputType = "ArrayBuffer";
this.outputType = "string";

View File

@@ -47,6 +47,11 @@ class Diff extends Operation {
"type": "boolean",
"value": true
},
{
"name": "Show subtraction",
"type": "boolean",
"value": false
},
{
"name": "Ignore whitespace",
"type": "boolean",
@@ -67,6 +72,7 @@ class Diff extends Operation {
diffBy,
showAdded,
showRemoved,
showSubtraction,
ignoreWhitespace
] = args,
samples = input.split(sampleDelim);
@@ -116,7 +122,7 @@ class Diff extends Operation {
if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
} else if (diff[i].removed) {
if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
} else {
} else if (!showSubtraction) {
output += Utils.escapeHtml(diff[i].value);
}
}

View File

@@ -38,7 +38,7 @@ class DitherImage extends Operation {
* @returns {byteArray}
*/
async run(input, args) {
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation.mjs";
import cptable from "../vendor/js-codepage/cptable.js";
import cptable from "codepage";
import {IO_FORMAT} from "../lib/ChrEnc.mjs";
/**

View File

@@ -21,7 +21,7 @@ class Enigma extends Operation {
super();
this.name = "Enigma";
this.module = "Default";
this.module = "Bletchley";
this.description = "Encipher/decipher with the WW2 Enigma machine.<br><br>Enigma was used by the German military, among others, around the WW2 era as a portable cipher machine to protect sensitive military, diplomatic and commercial communications.<br><br>The standard set of German military rotors and reflectors are provided. To configure the plugboard, enter a string of connected pairs of letters, e.g. <code>AB CD EF</code> connects A to B, C to D, and E to F. This is also used to create your own reflectors. To create your own rotor, enter the letters that the rotor maps A to Z to, in order, optionally followed by <code>&lt;</code> then a list of stepping points.<br>This is deliberately fairly permissive with rotor placements etc compared to a real Enigma (on which, for example, a four-rotor Enigma uses only the thin reflectors and the beta or gamma rotor in the 4th slot).<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
this.infoURL = "https://wikipedia.org/wiki/Enigma_machine";
this.inputType = "string";

View File

@@ -20,7 +20,7 @@ class ExtractDomains extends Operation {
this.name = "Extract domains";
this.module = "Regex";
this.description = "Extracts domain names.<br>Note that this will not include paths. Use <strong>Extract URLs</strong> to find entire URLs.";
this.description = "Extracts fully qualified domain names.<br>Note that this will not include paths. Use <strong>Extract URLs</strong> to find entire URLs.";
this.inputType = "string";
this.outputType = "string";
this.args = [

View File

@@ -0,0 +1,114 @@
/**
* @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { fromBinary } from "../lib/Binary.mjs";
import { isImage } from "../lib/FileType.mjs";
import jimp from "jimp";
/**
* Extract LSB operation
*/
class ExtractLSB extends Operation {
/**
* ExtractLSB constructor
*/
constructor() {
super();
this.name = "Extract LSB";
this.module = "Image";
this.description = "Extracts the Least Significant Bit data from each pixel in an image. This is a common way to hide data in Steganography.";
this.infoURL = "https://wikipedia.org/wiki/Bit_numbering#Least_significant_bit_in_digital_steganography";
this.inputType = "ArrayBuffer";
this.outputType = "byteArray";
this.args = [
{
name: "Colour Pattern #1",
type: "option",
value: COLOUR_OPTIONS,
},
{
name: "Colour Pattern #2",
type: "option",
value: ["", ...COLOUR_OPTIONS],
},
{
name: "Colour Pattern #3",
type: "option",
value: ["", ...COLOUR_OPTIONS],
},
{
name: "Colour Pattern #4",
type: "option",
value: ["", ...COLOUR_OPTIONS],
},
{
name: "Pixel Order",
type: "option",
value: ["Row", "Column"],
},
{
name: "Bit",
type: "number",
value: 0
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {byteArray}
*/
async run(input, args) {
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
const bit = 7 - args.pop(),
pixelOrder = args.pop(),
colours = args.filter(option => option !== "").map(option => COLOUR_OPTIONS.indexOf(option)),
parsedImage = await jimp.read(input),
width = parsedImage.bitmap.width,
height = parsedImage.bitmap.height,
rgba = parsedImage.bitmap.data;
if (bit < 0 || bit > 7) {
throw new OperationError("Error: Bit argument must be between 0 and 7");
}
let i, combinedBinary = "";
if (pixelOrder === "Row") {
for (i = 0; i < rgba.length; i += 4) {
for (const colour of colours) {
combinedBinary += Utils.bin(rgba[i + colour])[bit];
}
}
} else {
let rowWidth;
const pixelWidth = width * 4;
for (let col = 0; col < width; col++) {
for (let row = 0; row < height; row++) {
rowWidth = row * pixelWidth;
for (const colour of colours) {
i = rowWidth + (col + colour * 4);
combinedBinary += Utils.bin(rgba[i])[bit];
}
}
}
}
return fromBinary(combinedBinary);
}
}
const COLOUR_OPTIONS = ["R", "G", "B", "A"];
export default ExtractLSB;

View File

@@ -0,0 +1,65 @@
/**
* @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import jimp from "jimp";
import {RGBA_DELIM_OPTIONS} from "../lib/Delim.mjs";
/**
* Extract RGBA operation
*/
class ExtractRGBA extends Operation {
/**
* ExtractRGBA constructor
*/
constructor() {
super();
this.name = "Extract RGBA";
this.module = "Image";
this.description = "Extracts each pixel's RGBA value in an image. These are sometimes used in Steganography to hide text or data.";
this.infoURL = "https://wikipedia.org/wiki/RGBA_color_space";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
name: "Delimiter",
type: "editableOption",
value: RGBA_DELIM_OPTIONS
},
{
name: "Include Alpha",
type: "boolean",
value: true
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
const delimiter = args[0],
includeAlpha = args[1],
parsedImage = await jimp.read(input);
let bitmap = parsedImage.bitmap.data;
bitmap = includeAlpha ? bitmap : bitmap.filter((val, idx) => idx % 4 !== 3);
return bitmap.join(delimiter);
}
}
export default ExtractRGBA;

View File

@@ -45,7 +45,7 @@ class FlipImage extends Operation {
*/
async run(input, args) {
const [flipAxis] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid input file type.");
}
@@ -58,7 +58,7 @@ class FlipImage extends Operation {
try {
if (isWorkerEnvironment())
self.sendStatusMessage("Flipping image...");
switch (flipAxis){
switch (flipAxis) {
case "Horizontal":
image.flip(true, false);
break;

View File

@@ -76,8 +76,8 @@ class Fork extends Operation {
}
const recipe = new Recipe();
let output = "",
progress = 0;
const outputs = [];
let progress = 0;
state.forkOffset += state.progress + 1;
@@ -104,10 +104,10 @@ class Fork extends Operation {
}
progress = err.progress + 1;
}
output += await dish.get(outputType) + mergeDelim;
outputs.push(await dish.get(outputType));
}
state.dish.set(output, outputType);
state.dish.set(outputs.join(mergeDelim), outputType);
state.progress += progress;
return state;
}

View File

@@ -23,7 +23,7 @@ class FromQuotedPrintable extends Operation {
this.name = "From Quoted Printable";
this.module = "Default";
this.description = "Converts QP-encoded text back to standard text.";
this.description = "Converts QP-encoded text back to standard text.<br><br>e.g. The quoted-printable encoded string <code>hello=20world</code> becomes <code>hello world</code>";
this.infoURL = "https://wikipedia.org/wiki/Quoted-printable";
this.inputType = "string";
this.outputType = "byteArray";

View File

@@ -47,7 +47,7 @@ class GenerateLoremIpsum extends Operation {
*/
run(input, args) {
const [length, lengthType] = args;
if (length < 1){
if (length < 1) {
throw new OperationError("Length must be greater than 0");
}
switch (lengthType) {

View File

@@ -58,7 +58,7 @@ class GeneratePGPKeyPair extends Operation {
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
async run(input, args) {
const [keyType, keySize] = args[0].split("-"),
password = args[1],
name = args[2],

View File

@@ -57,7 +57,7 @@ class HammingDistance extends Operation {
samples = input.split(delim);
if (samples.length !== 2) {
throw new OperationError("Error: You can only calculae the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.");
throw new OperationError("Error: You can only calculate the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.");
}
if (samples[0].length !== samples[1].length) {

View File

@@ -54,7 +54,7 @@ class ImageBrightnessContrast extends Operation {
*/
async run(input, args) {
const [brightness, contrast] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -48,7 +48,7 @@ class ImageFilter extends Operation {
*/
async run(input, args) {
const [filterType] = args;
if (!isImage(new Uint8Array(input))){
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -62,7 +62,7 @@ class ImageHueSaturationLightness extends Operation {
async run(input, args) {
const [hue, saturation, lightness] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -47,7 +47,7 @@ class ImageOpacity extends Operation {
*/
async run(input, args) {
const [opacity] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -38,7 +38,7 @@ class InvertImage extends Operation {
* @returns {byteArray}
*/
async run(input, args) {
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid input file format.");
}

View File

@@ -0,0 +1,759 @@
/**
* Emulation of the Lorenz SZ40/42a/42b cipher attachment.
*
* @author VirtualColossus [martin@virtualcolossus.co.uk]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
/**
* Lorenz operation
*/
class Lorenz extends Operation {
/**
* Lorenz constructor
*/
constructor() {
super();
this.name = "Lorenz";
this.module = "Bletchley";
this.description = "The Lorenz SZ40/42 cipher attachment was a WW2 German rotor cipher machine with twelve rotors which attached in-line between remote teleprinters.<br><br>It used the Vernam cipher with two groups of five rotors (named the psi(ψ) wheels and chi(χ) wheels at Bletchley Park) to create two pseudorandom streams of five bits, encoded in ITA2, which were XOR added to the plaintext. Two other rotors, dubbed the mu(μ) or motor wheels, could hold up the stepping of the psi wheels meaning they stepped intermittently.<br><br>Each rotor has a different number of cams/lugs around their circumference which could be set active or inactive changing the key stream.<br><br>Three models of the Lorenz are emulated, SZ40, SZ42a and SZ42b and three example wheel patterns (the lug settings) are included (KH, ZMUG & BREAM) with the option to set a custom set using the letter 'x' for active or '.' for an inactive lug.<br><br>The input can either be plaintext or ITA2 when sending and ITA2 when receiving.<br><br>To learn more, Virtual Lorenz, an online, browser based simulation of the Lorenz SZ40/42 is available at <a href='https://lorenz.virtualcolossus.co.uk' target='_blank'>https://lorenz.virtualcolossus.co.uk</a>.";
this.infoURL = "https://wikipedia.org/wiki/Lorenz_cipher";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Model",
type: "option",
value: ["SZ40", "SZ42a", "SZ42b"]
},
{
name: "Wheel Pattern",
type: "argSelector",
value: [
{
name: "KH Pattern",
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
},
{
name: "ZMUG Pattern",
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
},
{
name: "BREAM Pattern",
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
},
{
name: "No Pattern",
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
},
{
name: "Custom",
on: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
}
]
},
{
name: "KT-Schalter",
type: "boolean"
},
{
name: "Mode",
type: "argSelector",
value: [
{
name: "Send",
on: [4],
off: [5]
},
{
name: "Receive",
off: [4],
on: [5]
}
]
},
{
name: "Input Type",
type: "option",
value: ["Plaintext", "ITA2"]
},
{
name: "Output Type",
type: "option",
value: ["Plaintext", "ITA2"]
},
{
name: "ITA2 Format",
type: "option",
value: ["5/8/9", "+/-/."]
},
{
name: "Ψ1 start (1-43)",
type: "number",
value: 1
},
{
name: "Ψ2 start (1-47)",
type: "number",
value: 1
},
{
name: "Ψ3 start (1-51)",
type: "number",
value: 1
},
{
name: "Ψ4 start (1-53)",
type: "number",
value: 1
},
{
name: "Ψ5 start (1-59)",
type: "number",
value: 1
},
{
name: "Μ37 start (1-37)",
type: "number",
value: 1
},
{
name: "Μ61 start (1-61)",
type: "number",
value: 1
},
{
name: "Χ1 start (1-41)",
type: "number",
value: 1
},
{
name: "Χ2 start (1-31)",
type: "number",
value: 1
},
{
name: "Χ3 start (1-29)",
type: "number",
value: 1
},
{
name: "Χ4 start (1-26)",
type: "number",
value: 1
},
{
name: "Χ5 start (1-23)",
type: "number",
value: 1
},
{
name: "Ψ1 lugs (43)",
type: "string",
value: ".x...xx.x.x..xxx.x.x.xxxx.x.x.x.x.x..x.xx.x"
},
{
name: "Ψ2 lugs (47)",
type: "string",
value: ".xx.x.xxx..x.x.x..x.xx.x.xxx.x....x.xx.x.x.x..x"
},
{
name: "Ψ3 lugs (51)",
type: "string",
value: ".x.x.x..xxx....x.x.xx.x.x.x..xxx.x.x..x.x.xx..x.x.x"
},
{
name: "Ψ4 lugs (53)",
type: "string",
value: ".xx...xxxxx.x.x.xx...x.xx.x.x..x.x.xx.x..x.x.x.x.x.x."
},
{
name: "Ψ5 lugs (59)",
type: "string",
value: "xx...xx.x..x.xx.x...x.x.x.x.x.x.x.x.xx..xxxx.x.x...xx.x..x."
},
{
name: "Μ37 lugs (37)",
type: "string",
value: "x.x.x.x.x.x...x.x.x...x.x.x...x.x...."
},
{
name: "Μ61 lugs (61)",
type: "string",
value: ".xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx..."
},
{
name: "Χ1 lugs (41)",
type: "string",
value: ".x...xxx.x.xxxx.x...x.x..xxx....xx.xxxx.."
},
{
name: "Χ2 lugs (31)",
type: "string",
value: "x..xxx...x.xxxx..xx..x..xx.xx.."
},
{
name: "Χ3 lugs (29)",
type: "string",
value: "..xx..x.xxx...xx...xx..xx.xx."
},
{
name: "Χ4 lugs (26)",
type: "string",
value: "xx..x..xxxx..xx.xxx....x.."
},
{
name: "Χ5 lugs (23)",
type: "string",
value: "xx..xx....xxxx.x..x.x.."
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const model = args[0],
pattern = args[1],
kt = args[2],
mode = args[3],
intype = args[4],
outtype = args[5],
format = args[6],
lugs1 = args[19],
lugs2 = args[20],
lugs3 = args[21],
lugs4 = args[22],
lugs5 = args[23],
lugm37 = args[24],
lugm61 = args[25],
lugx1 = args[26],
lugx2 = args[27],
lugx3 = args[28],
lugx4 = args[29],
lugx5 = args[30];
let s1 = args[7],
s2 = args[8],
s3 = args[9],
s4 = args[10],
s5 = args[11],
m37 = args[12],
m61 = args[13],
x1 = args[14],
x2 = args[15],
x3 = args[16],
x4 = args[17],
x5 = args[18];
this.reverseTable();
if (s1<1 || s1>43) throw new OperationError("Ψ1 start must be between 1 and 43");
if (s2<1 || s2>47) throw new OperationError("Ψ2 start must be between 1 and 47");
if (s3<1 || s3>51) throw new OperationError("Ψ3 start must be between 1 and 51");
if (s4<1 || s4>53) throw new OperationError("Ψ4 start must be between 1 and 53");
if (s5<1 || s5>59) throw new OperationError("Ψ5 start must be between 1 and 59");
if (m37<1 || m37>37) throw new OperationError("Μ37 start must be between 1 and 37");
if (m61<1 || m61>61) throw new OperationError("Μ61 start must be between 1 and 61");
if (x1<1 || x1>41) throw new OperationError("Χ1 start must be between 1 and 41");
if (x2<1 || x2>31) throw new OperationError("Χ2 start must be between 1 and 31");
if (x3<1 || x3>29) throw new OperationError("Χ3 start must be between 1 and 29");
if (x4<1 || x4>26) throw new OperationError("Χ4 start must be between 1 and 26");
if (x5<1 || x5>23) throw new OperationError("Χ5 start must be between 1 and 23");
// Initialise chosen wheel pattern
let chosenSetting = "";
if (pattern === "Custom") {
const re = new RegExp("^[.xX]*$");
if (lugs1.length !== 43 || !re.test(lugs1)) throw new OperationError("Ψ1 custom lugs must be 43 long and can only include . or x ");
if (lugs2.length !== 47 || !re.test(lugs2)) throw new OperationError("Ψ2 custom lugs must be 47 long and can only include . or x");
if (lugs3.length !== 51 || !re.test(lugs3)) throw new OperationError("Ψ3 custom lugs must be 51 long and can only include . or x");
if (lugs4.length !== 53 || !re.test(lugs4)) throw new OperationError("Ψ4 custom lugs must be 53 long and can only include . or x");
if (lugs5.length !== 59 || !re.test(lugs5)) throw new OperationError("Ψ5 custom lugs must be 59 long and can only include . or x");
if (lugm37.length !== 37 || !re.test(lugm37)) throw new OperationError("M37 custom lugs must be 37 long and can only include . or x");
if (lugm61.length !== 61 || !re.test(lugm61)) throw new OperationError("M61 custom lugs must be 61 long and can only include . or x");
if (lugx1.length !== 41 || !re.test(lugx1)) throw new OperationError("Χ1 custom lugs must be 41 long and can only include . or x");
if (lugx2.length !== 31 || !re.test(lugx2)) throw new OperationError("Χ2 custom lugs must be 31 long and can only include . or x");
if (lugx3.length !== 29 || !re.test(lugx3)) throw new OperationError("Χ3 custom lugs must be 29 long and can only include . or x");
if (lugx4.length !== 26 || !re.test(lugx4)) throw new OperationError("Χ4 custom lugs must be 26 long and can only include . or x");
if (lugx5.length !== 23 || !re.test(lugx5)) throw new OperationError("Χ5 custom lugs must be 23 long and can only include . or x");
chosenSetting = INIT_PATTERNS["No Pattern"];
chosenSetting.S[1] = this.readLugs(lugs1);
chosenSetting.S[2] = this.readLugs(lugs2);
chosenSetting.S[3] = this.readLugs(lugs3);
chosenSetting.S[4] = this.readLugs(lugs4);
chosenSetting.S[5] = this.readLugs(lugs5);
chosenSetting.M[1] = this.readLugs(lugm37);
chosenSetting.M[2] = this.readLugs(lugm61);
chosenSetting.X[1] = this.readLugs(lugx1);
chosenSetting.X[2] = this.readLugs(lugx2);
chosenSetting.X[3] = this.readLugs(lugx3);
chosenSetting.X[4] = this.readLugs(lugx4);
chosenSetting.X[5] = this.readLugs(lugx5);
} else {
chosenSetting = INIT_PATTERNS[pattern];
}
const chiSettings = chosenSetting.X; // Pin settings for Chi links (X)
const psiSettings = chosenSetting.S; // Pin settings for Psi links (S)
const muSettings = chosenSetting.M; // Pin settings for Motor links (M)
// Convert input text to ITA2 (including figure/letter shifts)
const ita2Input = this.convertToITA2(input, intype, mode);
let thisPsi = [];
let thisChi = [];
let m61lug = muSettings[1][m61-1];
let m37lug = muSettings[2][m37-1];
const p5 = [0, 0, 0];
const self = this;
const letters = Array.prototype.map.call(ita2Input, function(character) {
const letter = character.toUpperCase();
// Store lugs used in limitations, need these later
let x2bptr = x2+1;
if (x2bptr===32) x2bptr=1;
let s1bptr = s1+1;
if (s1bptr===44) s1bptr=1;
thisChi = [
chiSettings[1][x1-1],
chiSettings[2][x2-1],
chiSettings[3][x3-1],
chiSettings[4][x4-1],
chiSettings[5][x5-1]
];
thisPsi = [
psiSettings[1][s1-1],
psiSettings[2][s2-1],
psiSettings[3][s3-1],
psiSettings[4][s4-1],
psiSettings[5][s5-1]
];
if (typeof ITA2_TABLE[letter] == "undefined") {
return "";
}
// The encipher calculation
// We calculate Bitwise XOR for each of the 5 bits across our input ( K XOR Psi XOR Chi )
const xorSum = [];
for (let i=0;i<=4;i++) {
xorSum[i] = ITA2_TABLE[letter][i] ^ thisPsi[i] ^ thisChi[i];
}
const resultStr = xorSum.join("");
// Wheel movement
// Chi wheels always move one back after each letter
if (--x1 < 1) x1 = 41;
if (--x2 < 1) x2 = 31;
if (--x3 < 1) x3 = 29;
if (--x4 < 1) x4 = 26;
if (--x5 < 1) x5 = 23;
// Motor wheel (61 pin) also moves one each letter
if (--m61 < 1) m61 = 61;
// If M61 is set, we also move M37
if (m61lug === 1) {
if (--m37 < 1) m37 = 37;
}
// Psi wheels only move sometimes, dependent on M37 current setting and limitations
const basicmotor = m37lug;
let totalmotor = basicmotor;
let lim = 0;
p5[2] = p5[1];
p5[1] = p5[0];
if (mode==="Send") {
p5[0] = parseInt(ITA2_TABLE[letter][4], 10);
} else {
p5[0] = parseInt(xorSum[4], 10);
}
// Limitations here
if (model==="SZ42a") {
// Chi 2 one back lim - The active character of Chi 2 (2nd Chi wheel) in the previous position
lim = parseInt(chiSettings[2][x2bptr-1], 10);
if (kt) {
//p5 back 2
if (lim===p5[2]) {
lim = 0;
} else {
lim=1;
}
}
// If basic motor = 0 and limitation = 1, Total motor = 0 [no move], otherwise, total motor = 1 [move]
if (basicmotor===0 && lim===1) {
totalmotor = 0;
} else {
totalmotor = 1;
}
} else if (model==="SZ42b") {
// Chi 2 one back + Psi 1 one back.
const x2b1lug = parseInt(chiSettings[2][x2bptr-1], 10);
const s1b1lug = parseInt(psiSettings[1][s1bptr-1], 10);
lim = 1;
if (x2b1lug===s1b1lug) lim=0;
if (kt) {
//p5 back 2
if (lim===p5[2]) {
lim=0;
} else {
lim=1;
}
}
// If basic motor = 0 and limitation = 1, Total motor = 0 [no move], otherwise, total motor = 1 [move]
if (basicmotor===0 && lim===1) {
totalmotor = 0;
} else {
totalmotor = 1;
}
} else if (model==="SZ40") {
// SZ40 - just move based on the M37 motor wheel
totalmotor = basicmotor;
} else {
throw new OperationError("Lorenz model type not recognised");
}
// Move the Psi wheels when current totalmotor active
if (totalmotor === 1) {
if (--s1 < 1) s1 = 43;
if (--s2 < 1) s2 = 47;
if (--s3 < 1) s3 = 51;
if (--s4 < 1) s4 = 53;
if (--s5 < 1) s5 = 59;
}
m61lug = muSettings[1][m61-1];
m37lug = muSettings[2][m37-1];
let rtnstr = self.REVERSE_ITA2_TABLE[resultStr];
if (format==="5/8/9") {
if (rtnstr==="+") rtnstr="5"; // + or 5 used to represent figure shift
if (rtnstr==="-") rtnstr="8"; // - or 8 used to represent letter shift
if (rtnstr===".") rtnstr="9"; // . or 9 used to represent space
}
return rtnstr;
});
const ita2output = letters.join("");
return this.convertFromITA2(ita2output, outtype, mode);
}
/**
* Reverses the ITA2 Code lookup table
*/
reverseTable() {
this.REVERSE_ITA2_TABLE = {};
this.REVERSE_FIGSHIFT_TABLE = {};
for (const letter in ITA2_TABLE) {
const code = ITA2_TABLE[letter];
this.REVERSE_ITA2_TABLE[code] = letter;
}
for (const letter in figShiftArr) {
const ltr = figShiftArr[letter];
this.REVERSE_FIGSHIFT_TABLE[ltr] = letter;
}
}
/**
* Read lugs settings - convert to 0|1
*/
readLugs(lugstr) {
const arr = Array.prototype.map.call(lugstr, function(lug) {
if (lug===".") {
return 0;
} else {
return 1;
}
});
return arr;
}
/**
* Convert input plaintext to ITA2
*/
convertToITA2(input, intype, mode) {
let result = "";
let figShifted = false;
for (const character of input) {
const letter = character.toUpperCase();
// Convert input text to ITA2 (including figure/letter shifts)
if (intype === "ITA2" || mode === "Receive") {
if (validITA2.indexOf(letter) === -1) {
let errltr = letter;
if (errltr==="\n") errltr = "Carriage Return";
if (errltr===" ") errltr = "Space";
throw new OperationError("Invalid ITA2 character : "+errltr);
}
result += letter;
} else {
if (validChars.indexOf(letter) === -1) throw new OperationError("Invalid Plaintext character : "+letter);
if (!figShifted && figShiftedChars.indexOf(letter) !== -1) {
// in letters mode and next char needs to be figure shifted
figShifted = true;
result += "55" + figShiftArr[letter];
} else if (figShifted) {
// in figures mode and next char needs to be letter shifted
if (letter==="\n") {
result += "34";
} else if (letter==="\r") {
result += "4";
} else if (figShiftedChars.indexOf(letter) === -1) {
figShifted = false;
result += "88" + letter;
} else {
result += figShiftArr[letter];
}
} else {
if (letter==="\n") {
result += "34";
} else if (letter==="\r") {
result += "4";
} else {
result += letter;
}
}
}
}
return result;
}
/**
* Convert final result ITA2 to plaintext
*/
convertFromITA2(input, outtype, mode) {
let result = "";
let figShifted = false;
for (const letter of input) {
if (mode === "Receive") {
// Convert output ITA2 to plaintext (including figure/letter shifts)
if (outtype === "Plaintext") {
if (letter === "5" || letter === "+") {
figShifted = true;
} else if (letter === "8" || letter === "-") {
figShifted = false;
} else if (letter === "9") {
result += " ";
} else if (letter === "3") {
result += "\n";
} else if (letter === "4") {
result += "";
} else if (letter === "/") {
result += "/";
} else {
if (figShifted) {
result += this.REVERSE_FIGSHIFT_TABLE[letter];
} else {
result += letter;
}
}
} else {
result += letter;
}
} else {
result += letter;
}
}
return result;
}
}
const ITA2_TABLE = {
"A": "11000",
"B": "10011",
"C": "01110",
"D": "10010",
"E": "10000",
"F": "10110",
"G": "01011",
"H": "00101",
"I": "01100",
"J": "11010",
"K": "11110",
"L": "01001",
"M": "00111",
"N": "00110",
"O": "00011",
"P": "01101",
"Q": "11101",
"R": "01010",
"S": "10100",
"T": "00001",
"U": "11100",
"V": "01111",
"W": "11001",
"X": "10111",
"Y": "10101",
"Z": "10001",
"3": "00010",
"4": "01000",
"9": "00100",
"/": "00000",
" ": "00100",
".": "00100",
"8": "11111",
"5": "11011",
"-": "11111",
"+": "11011"
};
const validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-'()/:=?,. \n\r";
const validITA2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ34589+-./";
const figShiftedChars = "1234567890+-'()/:=?,.";
const figShiftArr = {
"1": "Q",
"2": "W",
"3": "E",
"4": "R",
"5": "T",
"6": "Y",
"7": "U",
"8": "I",
"9": "O",
"0": "P",
" ": "9",
"-": "A",
"?": "B",
":": "C",
"#": "D",
"%": "F",
"@": "G",
"£": "H",
"": "J",
"(": "K",
")": "L",
".": "M",
",": "N",
"'": "S",
"=": "V",
"/": "X",
"+": "Z",
"\n": "3",
"\r": "4"
};
const INIT_PATTERNS = {
"No Pattern": {
"X": {
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
},
"S": {
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
},
"M": {
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
},
"KH Pattern": {
"X": {
1: [0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
2: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0],
3: [0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0],
4: [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0],
5: [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0]
},
"S": {
1: [0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1],
2: [0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
3: [0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
4: [0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
5: [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0]
},
"M": {
1: [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
2: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
}
},
"ZMUG Pattern": {
"X": {
1: [0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
2: [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0],
3: [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0],
4: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1],
5: [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1]
},
"S": {
1: [1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0],
2: [0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1],
3: [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1],
4: [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1],
5: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0]
},
"M": {
1: [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
2: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
}
},
"BREAM Pattern": {
"X": {
1: [0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
2: [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
3: [1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0],
4: [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0],
5: [0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0]
},
"S": {
1: [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
2: [1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
3: [1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
4: [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1],
5: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
},
"M": {
1: [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1],
2: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1]
}
}
};
export default Lorenz;

View File

@@ -34,7 +34,7 @@ class MicrosoftScriptDecoder extends Operation {
run(input, args) {
const matcher = /#@~\^.{6}==(.+).{6}==\^#~@/;
const encodedData = matcher.exec(input);
if (encodedData){
if (encodedData) {
return MicrosoftScriptDecoder._decode(encodedData[1]);
} else {
return "";

View File

@@ -54,7 +54,7 @@ class MultipleBombe extends Operation {
super();
this.name = "Multiple Bombe";
this.module = "Default";
this.module = "Bletchley";
this.description = "Emulation of the Bombe machine used to attack Enigma. This version carries out multiple Bombe runs to handle unknown rotor configurations.<br><br>You should test your menu on the single Bombe operation before running it here. See the description of the Bombe operation for instructions on choosing a crib.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
this.infoURL = "https://wikipedia.org/wiki/Bombe";
this.inputType = "string";

View File

@@ -37,7 +37,7 @@ class NormaliseImage extends Operation {
* @returns {byteArray}
*/
async run(input, args) {
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -0,0 +1,87 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @author mshwed [m@ttshwed.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import Tesseract from "tesseract.js";
const { TesseractWorker } = Tesseract;
import process from "process";
/**
* Optical Character Recognition operation
*/
class OpticalCharacterRecognition extends Operation {
/**
* OpticalCharacterRecognition constructor
*/
constructor() {
super();
this.name = "Optical Character Recognition";
this.module = "OCR";
this.description = "Optical character recognition or optical character reader (OCR) is the mechanical or electronic conversion of images of typed, handwritten or printed text into machine-encoded text.<br><br>Supported image formats: png, jpg, bmp, pbm.";
this.infoURL = "https://wikipedia.org/wiki/Optical_character_recognition";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
name: "Show confidence",
type: "boolean",
value: true
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [showConfidence] = args;
if (!isWorkerEnvironment()) throw OperationError("This operation only works in a browser");
const type = isImage(input);
if (!type) {
throw new OperationError("Invalid File Type");
}
const assetDir = isWorkerEnvironment() ? `${self.docURL}/assets/` : `${process.cwd()}/src/core/vendor/`;
try {
const image = `data:${type};base64,${toBase64(input)}`;
const worker = new TesseractWorker({
workerPath: `${assetDir}tesseract/worker.min.js`,
langPath: `${assetDir}tesseract/lang-data`,
corePath: `${assetDir}tesseract/tesseract-core.wasm.js`,
});
const result = await worker.recognize(image)
.progress(progress => {
if (isWorkerEnvironment()) {
self.sendStatusMessage(`Status: ${progress.status} - ${(parseFloat(progress.progress)*100).toFixed(2)}%`);
}
});
if (showConfidence) {
return `Confidence: ${result.confidence}%\n\n${result.text}`;
} else {
return result.text;
}
} catch (err) {
throw new OperationError(`Error performing OCR on image. (${err})`);
}
}
}
export default OpticalCharacterRecognition;

View File

@@ -128,8 +128,7 @@ class PHPDeserialize extends Operation {
switch (kind) {
case "n":
expect(";");
return "";
return "null";
case "i":
case "d":
case "b": {

View File

@@ -134,7 +134,7 @@ CMYK: ${cmyk}
static _hslToRgb(h, s, l) {
let r, g, b;
if (s === 0){
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = function hue2rgb(p, q, t) {

View File

@@ -51,7 +51,7 @@ class ParseQRCode extends Operation {
async run(input, args) {
const [normalise] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}
return await parseQrCode(input, normalise);

View File

@@ -0,0 +1,83 @@
/**
* @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs";
import { runHash } from "../lib/Hash.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import jimp from "jimp";
/**
* Randomize Colour Palette operation
*/
class RandomizeColourPalette extends Operation {
/**
* RandomizeColourPalette constructor
*/
constructor() {
super();
this.name = "Randomize Colour Palette";
this.module = "Image";
this.description = "Randomizes each colour in an image's colour palette. This can often reveal text or symbols that were previously a very similar colour to their surroundings, a technique sometimes used in Steganography.";
this.infoURL = "https://wikipedia.org/wiki/Indexed_color";
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
this.presentType = "html";
this.args = [
{
name: "Seed",
type: "string",
value: ""
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
async run(input, args) {
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
const seed = args[0] || (Math.random().toString().substr(2)),
parsedImage = await jimp.read(input),
width = parsedImage.bitmap.width,
height = parsedImage.bitmap.height;
let rgbString, rgbHash, rgbHex;
parsedImage.scan(0, 0, width, height, function(x, y, idx) {
rgbString = this.bitmap.data.slice(idx, idx+3).join(".");
rgbHash = runHash("md5", Utils.strToArrayBuffer(seed + rgbString));
rgbHex = rgbHash.substr(0, 6) + "ff";
parsedImage.setPixelColor(parseInt(rgbHex, 16), x, y);
});
const imageBuffer = await parsedImage.getBufferAsync(jimp.AUTO);
return new Uint8Array(imageBuffer).buffer;
}
/**
* Displays the extracted data as an image for web apps.
* @param {ArrayBuffer} data
* @returns {html}
*/
present(data) {
if (!data.byteLength) return "";
const type = isImage(data);
return `<img src="data:${type};base64,${toBase64(data)}">`;
}
}
export default RandomizeColourPalette;

View File

@@ -77,7 +77,7 @@ class RawInflate extends Operation {
}),
result = new Uint8Array(inflate.decompress());
// Raw Inflate somethimes messes up and returns nonsense like this:
// Raw Inflate sometimes messes up and returns nonsense like this:
// ]....]....]....]....]....]....]....]....]....]....]....]....]....]...
// e.g. Input data of [8b, 1d, dc, 44]
// Look for the first two square brackets:

View File

@@ -64,7 +64,7 @@ class RemoveWhitespace extends Operation {
run(input, args) {
const [
removeSpaces,
removeCariageReturns,
removeCarriageReturns,
removeLineFeeds,
removeTabs,
removeFormFeeds,
@@ -73,7 +73,7 @@ class RemoveWhitespace extends Operation {
let data = input;
if (removeSpaces) data = data.replace(/ /g, "");
if (removeCariageReturns) data = data.replace(/\r/g, "");
if (removeCarriageReturns) data = data.replace(/\r/g, "");
if (removeLineFeeds) data = data.replace(/\n/g, "");
if (removeTabs) data = data.replace(/\t/g, "");
if (removeFormFeeds) data = data.replace(/\f/g, "");

View File

@@ -0,0 +1,69 @@
/**
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import MarkdownIt from "markdown-it";
import hljs from "highlight.js";
/**
* Render Markdown operation
*/
class RenderMarkdown extends Operation {
/**
* RenderMarkdown constructor
*/
constructor() {
super();
this.name = "Render Markdown";
this.module = "Code";
this.description = "Renders input Markdown as HTML. HTML rendering is disabled to avoid XSS.";
this.infoURL = "https://wikipedia.org/wiki/Markdown";
this.inputType = "string";
this.outputType = "html";
this.args = [
{
name: "Autoconvert URLs to links",
type: "boolean",
value: false
},
{
name: "Enable syntax highlighting",
type: "boolean",
value: true
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run(input, args) {
const [convertLinks, enableHighlighting] = args,
md = new MarkdownIt({
linkify: convertLinks,
html: false, // Explicitly disable HTML rendering
highlight: function(str, lang) {
if (lang && hljs.getLanguage(lang) && enableHighlighting) {
try {
return hljs.highlight(lang, str).value;
} catch (__) {}
}
return "";
}
}),
rendered = md.render(input);
return `<div style="font-family: var(--primary-font-family)">${rendered}</div>`;
}
}
export default RenderMarkdown;

View File

@@ -87,7 +87,7 @@ class ResizeImage extends Operation {
"Bezier": jimp.RESIZE_BEZIER
};
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -46,7 +46,7 @@ class RotateImage extends Operation {
async run(input, args) {
const [degrees] = args;
if (!isImage(new Uint8Array(input))) {
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -41,7 +41,7 @@ class ScanForEmbeddedFiles extends Operation {
* @returns {string}
*/
run(input, args) {
let output = "Scanning data for 'magic bytes' which may indicate embedded files. The following results may be false positives and should not be treat as reliable. Any suffiently long file is likely to contain these magic bytes coincidentally.\n",
let output = "Scanning data for 'magic bytes' which may indicate embedded files. The following results may be false positives and should not be treat as reliable. Any sufficiently long file is likely to contain these magic bytes coincidentally.\n",
numFound = 0;
const categories = [],
data = new Uint8Array(input);

View File

@@ -62,7 +62,7 @@ class SharpenImage extends Operation {
async run(input, args) {
const [radius, amount, threshold] = args;
if (!isImage(new Uint8Array(input))){
if (!isImage(input)) {
throw new OperationError("Invalid file type.");
}

View File

@@ -0,0 +1,113 @@
/**
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Show on map operation
*/
class ShowOnMap extends Operation {
/**
* ShowOnMap constructor
*/
constructor() {
super();
this.name = "Show on map";
this.module = "Hashing";
this.description = "Displays co-ordinates on a slippy map.<br><br>Co-ordinates will be converted to decimal degrees before being shown on the map.<br><br>Supported formats:<ul><li>Degrees Minutes Seconds (DMS)</li><li>Degrees Decimal Minutes (DDM)</li><li>Decimal Degrees (DD)</li><li>Geohash</li><li>Military Grid Reference System (MGRS)</li><li>Ordnance Survey National Grid (OSNG)</li><li>Universal Transverse Mercator (UTM)</li></ul><br>This operation will not work offline.";
this.infoURL = "https://foundation.wikimedia.org/wiki/Maps_Terms_of_Use";
this.inputType = "string";
this.outputType = "string";
this.presentType = "html";
this.args = [
{
name: "Zoom Level",
type: "number",
value: 13
},
{
name: "Input Format",
type: "option",
value: ["Auto"].concat(FORMATS)
},
{
name: "Input Delimiter",
type: "option",
value: [
"Auto",
"Direction Preceding",
"Direction Following",
"\\n",
"Comma",
"Semi-colon",
"Colon"
]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
if (input.replace(/\s+/g, "") !== "") {
const inFormat = args[1],
inDelim = args[2];
let latLong;
try {
latLong = convertCoordinates(input, inFormat, inDelim, "Decimal Degrees", "Comma", "None", 5);
} catch (error) {
throw new OperationError(error);
}
latLong = latLong.replace(/[,]$/, "");
latLong = latLong.replace(/°/g, "");
return latLong;
}
return input;
}
/**
* @param {string} data
* @param {Object[]} args
* @returns {string}
*/
async present(data, args) {
if (data.replace(/\s+/g, "") === "") {
data = "0, 0";
}
const zoomLevel = args[0];
const tileUrl = "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",
tileAttribution = "<a href=\"https://wikimediafoundation.org/wiki/Maps_Terms_of_Use\">Wikimedia maps</a> | &copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors",
leafletUrl = "https://unpkg.com/leaflet@1.5.0/dist/leaflet.js",
leafletCssUrl = "https://unpkg.com/leaflet@1.5.0/dist/leaflet.css";
return `<link rel="stylesheet" href="${leafletCssUrl}" crossorigin=""/>
<style>#output-html { white-space: normal; padding: 0; }</style>
<div id="presentedMap" style="width: 100%; height: 100%;"></div>
<script type="text/javascript">
var mapscript = document.createElement('script');
document.body.appendChild(mapscript);
mapscript.onload = function() {
var presentMap = L.map('presentedMap').setView([${data}], ${zoomLevel});
L.tileLayer('${tileUrl}', {
attribution: '${tileAttribution}'
}).addTo(presentMap);
L.marker([${data}]).addTo(presentMap)
.bindPopup('${data}')
.openPopup();
};
mapscript.src = "${leafletUrl}";
</script>`;
}
}
export default ShowOnMap;

View File

@@ -79,7 +79,7 @@ class SwapEndianness extends Operation {
const word = data.slice(i, i + wordLength);
// Pad word if too short
if (padIncompleteWords && word.length < wordLength){
if (padIncompleteWords && word.length < wordLength) {
for (j = word.length; j < wordLength; j++) {
word.push(0);
}

View File

@@ -7,7 +7,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import cptable from "../vendor/js-codepage/cptable.js";
import cptable from "codepage";
import {IO_FORMAT} from "../lib/ChrEnc.mjs";
/**

View File

@@ -40,7 +40,7 @@ class ToBase64 extends Operation {
*/
run(input, args) {
const alphabet = args[0];
return toBase64(new Uint8Array(input), alphabet);
return toBase64(input, alphabet);
}
/**

View File

@@ -108,7 +108,7 @@ class ToQuotedPrintable extends Operation {
* @private
* @param {number} nr
* @param {byteArray[]} ranges
* @returns {bolean}
* @returns {boolean}
*/
_checkRanges(nr, ranges) {
for (let i = ranges.length - 1; i >= 0; i--) {

View File

@@ -75,6 +75,12 @@ class TripleDESDecrypt extends Operation {
Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).`);
}
if (iv.length !== 8 && mode !== "ECB") {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
Triple DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);

View File

@@ -75,6 +75,12 @@ class TripleDESEncrypt extends Operation {
Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).`);
}
if (iv.length !== 8 && mode !== "ECB") {
throw new OperationError(`Invalid IV length: ${iv.length} bytes
Triple DES uses an IV length of 8 bytes (64 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
}
input = Utils.convertToByteString(input, inputType);

View File

@@ -22,8 +22,8 @@ class Typex extends Operation {
super();
this.name = "Typex";
this.module = "Default";
this.description = "Encipher/decipher with the WW2 Typex machine.<br><br>Typex was originally built by the British Royal Air Force prior to WW2, and is based on the Enigma machine with some improvements made, including using five rotors with more stepping points and interchangeable wiring cores. It was used across the British and Commonewealth militaries. A number of later variants were produced; here we simulate a WW2 era Mark 22 Typex with plugboards for the reflector and input. Typex rotors were changed regularly and none are public: a random example set are provided.<br><br>To configure the reflector plugboard, enter a string of connected pairs of letters in the reflector box, e.g. <code>AB CD EF</code> connects A to B, C to D, and E to F (you'll need to connect every letter). There is also an input plugboard: unlike Enigma's plugboard, it's not restricted to pairs, so it's entered like a rotor (without stepping). To create your own rotor, enter the letters that the rotor maps A to Z to, in order, optionally followed by <code>&lt;</code> then a list of stepping points.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
this.module = "Bletchley";
this.description = "Encipher/decipher with the WW2 Typex machine.<br><br>Typex was originally built by the British Royal Air Force prior to WW2, and is based on the Enigma machine with some improvements made, including using five rotors with more stepping points and interchangeable wiring cores. It was used across the British and Commonwealth militaries. A number of later variants were produced; here we simulate a WW2 era Mark 22 Typex with plugboards for the reflector and input. Typex rotors were changed regularly and none are public: a random example set are provided.<br><br>To configure the reflector plugboard, enter a string of connected pairs of letters in the reflector box, e.g. <code>AB CD EF</code> connects A to B, C to D, and E to F (you'll need to connect every letter). There is also an input plugboard: unlike Enigma's plugboard, it's not restricted to pairs, so it's entered like a rotor (without stepping). To create your own rotor, enter the letters that the rotor maps A to Z to, in order, optionally followed by <code>&lt;</code> then a list of stepping points.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
this.infoURL = "https://wikipedia.org/wiki/Typex";
this.inputType = "string";
this.outputType = "string";

View File

@@ -51,12 +51,12 @@ class UNIXTimestampToWindowsFiletime extends Operation {
input = new BigNumber(input);
if (units === "Seconds (s)"){
if (units === "Seconds (s)") {
input = input.multipliedBy(new BigNumber("10000000"));
} else if (units === "Milliseconds (ms)") {
input = input.multipliedBy(new BigNumber("10000"));
} else if (units === "Microseconds (μs)") {
input = input.multiplyiedBy(new BigNumber("10"));
input = input.multipliedBy(new BigNumber("10"));
} else if (units === "Nanoseconds (ns)") {
input = input.dividedBy(new BigNumber("100"));
} else {
@@ -65,7 +65,7 @@ class UNIXTimestampToWindowsFiletime extends Operation {
input = input.plus(new BigNumber("116444736000000000"));
if (format === "Hex"){
if (format === "Hex") {
return input.toString(16);
} else {
return input.toFixed();

Some files were not shown because too many files have changed in this diff Show More