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

Compare commits

...

408 Commits

Author SHA1 Message Date
n1474335
b6845aa03c 9.24.1 2021-02-02 17:18:49 +00:00
n1474335
4a673bd92a AES Decrypt now supports Additional Authenticated Data in GCM mode. Added tests for ADD at each AES size. 2021-02-02 17:18:35 +00:00
n1474335
fdffabfdd4 Merge branch 'n1073645-AESGCMAAD' 2021-02-02 16:11:03 +00:00
n1474335
ba8591293b Merge branch 'AESGCMAAD' of https://github.com/n1073645/CyberChef into n1073645-AESGCMAAD 2021-02-02 16:10:47 +00:00
n1474335
9b3aae10cf 9.24.0 2021-02-02 16:07:57 +00:00
n1474335
5c85c4df63 Updated CHANGELOG 2021-02-02 16:07:52 +00:00
n1474335
8ece2603fb Merge branch 'n1073645-SM3' 2021-02-02 16:06:49 +00:00
n1474335
1b54584820 Tweaks to various hashing functions to improve config options 2021-02-02 16:06:37 +00:00
n1474335
3ce3866000 Merge branch 'SM3' of https://github.com/n1073645/CyberChef into n1073645-SM3 2021-02-02 11:58:36 +00:00
n1474335
becc258b6c Updated CHANGELOG 2021-02-02 11:12:52 +00:00
n1474335
16c9e7119d Updated CHANGELOG 2021-02-02 11:02:23 +00:00
n1474335
f5888fea9c 9.23.1 2021-02-01 19:29:47 +00:00
n1474335
b5162c7549 Merge branch 'maqifrnswa-master' 2021-02-01 19:27:42 +00:00
n1474335
1baea1da3d Merge branch 'master' of https://github.com/maqifrnswa/CyberChef into maqifrnswa-master 2021-02-01 19:27:24 +00:00
n1474335
40899a6fe4 9.23.0 2021-02-01 19:16:03 +00:00
n1474335
66c533431d Merge branch 'mattnotmitt-rsa' 2021-02-01 19:15:46 +00:00
n1474335
74ae77f17a Tidied up and added tests for RSA operations 2021-02-01 19:15:32 +00:00
n1474335
99eb1cced5 Merge branch 'rsa' of https://github.com/mattnotmitt/CyberChef into mattnotmitt-rsa 2021-02-01 17:30:02 +00:00
n1474335
c880ecf3c4 Merge branch 'stephengroat-nvmrc' 2021-02-01 17:01:44 +00:00
n1474335
c54c34d88e Merge branch 'nvmrc' of https://github.com/stephengroat/CyberChef into stephengroat-nvmrc 2021-02-01 17:01:31 +00:00
n1474335
60b3c597a7 9.22.4 2021-02-01 16:57:48 +00:00
n1474335
372ab32539 Updated dependencies 2021-02-01 16:57:42 +00:00
n1474335
e14745a973 9.22.3 2021-02-01 16:43:19 +00:00
n1474335
afffe584cf Added flat lib for JSON to CSV op 2021-02-01 16:41:54 +00:00
n1474335
cf532f1e30 Merge branch 'n1073645-JSONTOCSV' 2021-02-01 16:35:09 +00:00
n1474335
46425ba552 Merge branch 'JSONTOCSV' of https://github.com/n1073645/CyberChef into n1073645-JSONTOCSV 2021-02-01 16:34:57 +00:00
n1474335
9f65fac4e6 Added actions for linting and testing Pull Requests 2021-02-01 16:34:12 +00:00
n1474335
af98feff51 Improved PGP keygen test 2021-02-01 16:24:47 +00:00
n1474335
339c741a2c 9.22.2 2021-02-01 16:14:38 +00:00
n1474335
d1bde23f00 Merge branch 'n1073645-datetime' 2021-02-01 16:13:57 +00:00
n1474335
be544faf0f Merge branch 'datetime' of https://github.com/n1073645/CyberChef into n1073645-datetime 2021-02-01 16:13:43 +00:00
n1474335
eff77fd3bb 9.22.1 2021-02-01 16:11:46 +00:00
n1474335
3df57ba3dd Added big and little endian options for Windows timestamp conversion ops 2021-02-01 16:11:39 +00:00
n1474335
4bae662357 Merge branch 'n1073645-FiletimeEndianness' 2021-02-01 15:56:03 +00:00
n1474335
357c90546e Merge branch 'FiletimeEndianness' of https://github.com/n1073645/CyberChef into n1073645-FiletimeEndianness 2021-02-01 15:55:42 +00:00
n1474335
54769a90ac 9.22.0 2021-02-01 15:52:34 +00:00
n1474335
0550aedd54 Merge branch 'mattnotmitt-features/unicode-format' 2021-02-01 15:51:29 +00:00
n1474335
5947ed21fc Tidied up localisation in Wikipedia URL 2021-02-01 15:51:14 +00:00
n1474335
0a0949246f Merge branch 'features/unicode-format' of https://github.com/mattnotmitt/CyberChef into mattnotmitt-features/unicode-format 2021-02-01 15:45:21 +00:00
n1474335
09c6e181fb 9.21.6 2021-02-01 14:42:32 +00:00
n1474335
02cf394bcd ROT13 tweaks 2021-02-01 14:42:00 +00:00
n1474335
46afbf9888 Merge branch 'n1073645-numberRot' 2021-02-01 14:37:44 +00:00
n1474335
7cf19d22a8 Merge branch 'numberRot' of https://github.com/n1073645/CyberChef into n1073645-numberRot 2021-02-01 14:37:30 +00:00
n1474335
46d708360f Merge branch 'xavier630-patch-1' 2021-02-01 14:32:05 +00:00
n1474335
7ec91e2366 Merge branch 'patch-1' of https://github.com/xavier630/CyberChef into xavier630-patch-1 2021-02-01 14:31:42 +00:00
n1474335
a74ee47bf0 Updated actions config 2021-02-01 14:18:17 +00:00
n1474335
7b68b92498 Updated actions config 2021-02-01 14:14:40 +00:00
n1474335
274f3acd45 Added GH Releases and NPM actions 2021-02-01 14:10:21 +00:00
n1474335
53dff8b30f 9.21.5 2021-02-01 11:10:16 +00:00
n1474335
9892ee273e Bugfix: ECC mode now works correctly in 'Generate PGP Key Pair' 2021-02-01 11:10:04 +00:00
n1474335
7dccecb336 Moved GH Pages prep to its own step 2021-01-22 17:15:58 +00:00
n1474335
aa09da0403 GitHub Actions now pushes to GitHub Pages 2021-01-22 17:13:17 +00:00
n1474335
98d7f1481c Improved UI tests 2021-01-22 16:52:37 +00:00
n1474335
7d8bdbcf7e Improved UI tests 2021-01-22 16:39:04 +00:00
n1474335
db009d3689 Improved UI tests 2021-01-22 16:25:19 +00:00
n1474335
d7bc529a95 Improved UI tests 2021-01-22 16:16:11 +00:00
n1474335
3f035294a6 Improved UI tests 2021-01-22 16:06:44 +00:00
n1474335
36282e362f Improved UI tests 2021-01-22 15:53:56 +00:00
n1474335
223353cf4d Increased UI test operation timeout 2021-01-22 15:43:18 +00:00
n1474335
ded32da632 Back to a single job 2021-01-22 15:33:15 +00:00
n1474335
d6fc21cc34 Fixed yaml 2021-01-22 15:28:46 +00:00
n1474335
b86e960456 Actions broken out into separate jobs 2021-01-22 15:27:42 +00:00
n1474335
7747bfe0f2 Fixed prod build and Actions now creates a sitemap 2021-01-22 15:17:17 +00:00
n1474335
fabea8cc61 Fix whitespace 2021-01-22 15:00:15 +00:00
n1474335
de4cd2eebc Add production build to GitHub Actions script 2021-01-22 14:59:26 +00:00
n1474335
e16ce1d9c2 Specify node version 2021-01-22 14:53:53 +00:00
n1474335
345ad741b3 Fixed sed command in postinstall script to be platform dependent 2021-01-22 14:47:33 +00:00
n1474335
e53108c493 Merge branch 'gh-actions' 2021-01-22 14:33:48 +00:00
n1474335
6129378854 Reduced Actions script to just linting and testing 2021-01-22 14:33:35 +00:00
n1474335
11a1416dcc Merge branch 'gh-actions' of https://github.com/mattnotmitt/CyberChef into mattnotmitt-gh-actions 2021-01-22 14:17:29 +00:00
n1474335
9025538544 9.21.4 2021-01-22 13:48:30 +00:00
n1474335
46929e1844 Merge branch 'mattnotmax-haversine' 2021-01-22 13:48:19 +00:00
n1474335
bf023cad48 Merge branch 'haversine' of https://github.com/mattnotmax/CyberChef into mattnotmax-haversine 2021-01-22 13:48:04 +00:00
n1474335
f649236bad 9.21.3 2021-01-22 13:45:24 +00:00
n1474335
54b1454c0a Merge branch 'n1073645-binaryLength' 2021-01-22 13:45:09 +00:00
n1474335
a41b1c2f5e Merge branch 'binaryLength' of https://github.com/n1073645/CyberChef into n1073645-binaryLength 2021-01-22 13:44:49 +00:00
n1474335
0327d7cb7a 9.21.2 2021-01-22 13:40:36 +00:00
n1474335
621d7c3683 Merge branch 'manicgiraffe-update_forensicswiki_url' 2021-01-22 13:40:24 +00:00
n1474335
ae7c3fca31 Merge branch 'update_forensicswiki_url' of https://github.com/manicgiraffe/CyberChef into manicgiraffe-update_forensicswiki_url 2021-01-22 13:39:55 +00:00
n1474335
1b3295ff59 9.21.1 2021-01-22 12:59:05 +00:00
n1474335
e40e7a0e4e Added UI tests for operations. Unfinished. 2021-01-22 12:57:21 +00:00
n1474335
cf5fd7cbf2 Updated dependencies 2021-01-22 11:04:45 +00:00
n1474335
ec37a676a8 Updated dependencies 2020-12-14 17:51:12 +00:00
n1474335
f33193e122 Updated dependencies 2020-12-14 15:32:12 +00:00
n1474335
7c40204e4f Updated dependencies 2020-12-11 17:58:23 +00:00
n1474335
2b2ffb3346 Updated dependencies 2020-12-11 16:24:39 +00:00
mattnotmax
39b7e4ff9e Correct Haversine test output 2020-12-09 21:12:26 +11:00
mattnotmax
a1109c43f6 Fix for haversine distance bug 2020-12-08 21:17:43 +11:00
Arthur Taggart
e6eafc2843 Updated the links to forensic wiki website 2020-11-29 14:19:42 +00:00
Xavier Downs
3e8dea73d2 Update ScanForEmbeddedFiles.mjs 2020-11-24 12:18:02 +00:00
n1073645
bbf19ee944 argument added for numbers in ROT 2020-08-24 11:24:25 +01:00
n1073645
f6c8c9e76c swap endianness argument added to Windows Filetime To Unix Timestamp 2020-08-24 10:39:18 +01:00
n1073645
9dba1232b7 byte length argument added to ToBinary 2020-08-24 09:41:05 +01:00
Matt
bf14c8983f trigger travis 2020-08-19 11:04:09 +01:00
Matt
3ab95384df Add unicode tests 2020-08-19 10:55:29 +01:00
n1073645
953a581a94 byte length arg added 2020-08-17 14:12:29 +01:00
n1073645
3bfddd708c rectify week number 2020-08-17 10:40:00 +01:00
Matt
13a54ec318 Add unicode text format operation 2020-08-13 12:36:02 +01:00
n1073645
2781640a2a JSON to CSV improvements 2020-07-29 15:27:55 +01:00
n1073645
7989f119d3 Linting Modifications 2020-07-16 09:56:30 +01:00
Scott Howard
2e0aa7ae87 Don't pad rail fence decode fixes #1069 2020-07-15 22:05:15 -04:00
Matt
0b5ee7c79f Update actions 2020-07-04 15:35:49 +01:00
Matt
23cbe1c426 Merge branch 'master' into gh-actions 2020-07-04 15:29:24 +01:00
Stephen G
de727bcddc use nvmrc file
avoids storing node version in travis to allow nvm tool for local dev
2020-06-13 14:51:37 -07:00
d98762625
c9d9730726 Updated CHANGELOG 2020-06-12 13:50:30 +01:00
d98762625
a380aed878 9.21.0 2020-06-12 12:49:39 +01:00
d98762625
4dafa50799 improve some comments, remove unused properties from magic state shim in node API 2020-06-12 12:35:33 +01:00
Matt
d4ae241758 Merge branch 'master' into rsa 2020-06-08 15:55:37 +01:00
d98762625
53e69835ff Formally disallow flowcontrol operations from being used in bake recipes 2020-06-05 14:44:34 +01:00
d98762625
939208903a Allow magic in node api 2020-06-05 12:26:17 +01:00
d98762625
616b38c6fb 9.20.7 2020-05-28 09:50:22 +01:00
d98762625
a302df8f91 update bootstrap 2020-05-28 09:34:57 +01:00
dependabot[bot]
093512a55a Bump jquery from 3.4.1 to 3.5.0
Bumps [jquery](https://github.com/jquery/jquery) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.4.1...3.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-05-27 15:11:47 +00:00
d98762625
007224c92e 9.20.6 2020-05-27 15:59:42 +01:00
Matthieu
738ee33959 Fix bug in Normalise Unicode operation: replace nfc by nfkc 2020-05-27 15:47:40 +01:00
d98762625
d720a6b250 9.20.5 2020-05-27 15:34:45 +01:00
Matt
5ce3cc17bb Fixed tesseract issue 2020-05-27 15:00:34 +01:00
d98762625
5c35205315 9.20.4 2020-05-27 13:35:20 +01:00
d98762625
10751934e4 add uname dependency and bump chromedriver 2020-05-27 12:28:59 +01:00
d98762625
d658f91106 Merge branch 'master' of github.com:gchq/CyberChef into javascript-minify 2020-05-27 11:54:07 +01:00
n1073645
fae96af17d Info for sm3 added 2020-04-24 14:13:55 +01:00
n1073645
57c1a03c4f Option structures added for hashing algorithms 2020-04-24 14:04:13 +01:00
Matt
fad163e0eb Added tests (that can't be run) 2020-04-07 21:16:29 +01:00
Matt
7ad3992bd1 Add RSA Decrypt Operation 2020-04-07 13:31:33 +01:00
Matt
e7b5c0e37c Add RSA Encrypt Operation 2020-04-07 13:31:17 +01:00
n1073645
cc35127459 AAD for AES Added 2020-04-07 13:03:24 +01:00
Matt
1c0ecd29c2 Fix RSA operations 2020-04-07 11:45:54 +01:00
Matt
18c6b9bc09 Add RSA Verify operation 2020-04-06 15:24:22 +01:00
Matt
2233b9a094 Comment and add error handling to generate and sign 2020-04-06 15:24:06 +01:00
Matt
e0f000b913 Fixed RSA generation and added digest option to verify 2020-04-06 13:35:14 +01:00
Matt
73864e0809 Merge branch 'master' into features/rsa 2020-04-05 12:08:24 +01:00
n1474335
4c3324aea1 9.20.3 2020-03-30 11:17:46 +01:00
n1474335
ac2fcee90f Merge branch 'Danh4-issue-998' 2020-03-30 11:17:38 +01:00
71819
94e00115fe Issue 998: DishJSON should only replace undefined with new ArrayBuffer not null or false 2020-03-28 20:27:59 +00:00
d98762625
29255d2338 Merge pull request #983 from n1073645/gruntSpelling
Grunt npm tests comment changed to npm test
2020-03-27 14:23:54 +00:00
n1474335
39278cfce7 9.20.2 2020-03-27 12:10:01 +00:00
n1474335
46cc48cfb9 Renamed Parse ObjectID Timestamp operation files 2020-03-27 12:09:57 +00:00
n1474335
eb4009949d 9.20.1 2020-03-27 12:05:41 +00:00
n1474335
57c48a4bd2 Merge branch 'n1073645-TargaExtractor' 2020-03-27 12:05:34 +00:00
n1474335
45011de494 Tidied up TARGE extractor 2020-03-27 12:05:23 +00:00
n1474335
5e51ed0a5f Merge branch 'TargaExtractor' of https://github.com/n1073645/CyberChef into n1073645-TargaExtractor 2020-03-27 12:01:46 +00:00
n1474335
875802ef2a 9.20.0 2020-03-27 12:00:39 +00:00
n1474335
bbc255ef83 Updated CHANGELOG 2020-03-27 12:00:33 +00:00
n1474335
fc155ec3fc Merge branch 'dmfj-parse-objectid-timestamp' 2020-03-27 11:56:58 +00:00
n1474335
3a0c8a199a Tidied up 'Parse ObjectID Timestamp' operation 2020-03-27 11:56:42 +00:00
n1474335
9c729c4490 Merge branch 'parse-objectid-timestamp' of https://github.com/dmfj/CyberChef into dmfj-parse-objectid-timestamp 2020-03-27 11:48:55 +00:00
n1474335
19bdbd66e5 Merge branch 'cbeuw-stacking-fix' 2020-03-27 10:19:14 +00:00
n1474335
ea090f79ee Merge branch 'stacking-fix' of https://github.com/cbeuw/CyberChef into cbeuw-stacking-fix 2020-03-27 10:17:54 +00:00
Andy Wang
1be6c54be2 Fix dropup menu being covered 2020-03-26 22:45:03 +00:00
n1474335
a4eeb226b1 9.19.1 2020-03-26 12:02:09 +00:00
n1474335
d136717636 Merge branch 'n1073645-MP3Extractor' 2020-03-26 12:02:02 +00:00
n1474335
ad0a2e6f58 Merge branch 'MP3Extractor' of https://github.com/n1073645/CyberChef into n1073645-MP3Extractor 2020-03-26 12:01:30 +00:00
n1474335
0212bfb46e 9.19.0 2020-03-24 11:37:30 +00:00
n1474335
5e0d661542 Updated CHANGELOG 2020-03-24 11:37:26 +00:00
n1474335
4c5f529ef4 Merge branch 'n1073645-newMagic' 2020-03-24 11:07:20 +00:00
n1474335
b765534b8b Tidied up the Magic operation 2020-03-24 11:06:37 +00:00
n1073645
7c672c5ee9 MP3 Extractor added 2020-03-23 10:11:24 +00:00
n1073645
090bf3f8ec MP3 Extractor added 2020-03-23 10:10:47 +00:00
Dominic Fitch-Jones
9f4ef9cdad Add ObjectId timestamp parser operation 2020-03-21 17:42:17 -04:00
n1474335
26fa66ef64 Merge branch 'newMagic' of https://github.com/n1073645/CyberChef into n1073645-newMagic 2020-03-20 14:51:40 +00:00
n1073645
b69e4567c0 MP3extractor 2020-03-19 16:10:22 +00:00
n1474335
26b19350f2 9.18.2 2020-03-18 16:47:53 +00:00
n1474335
2018b7e247 Fixed sitemap 2020-03-18 16:47:48 +00:00
n1474335
cbff4161a1 9.18.1 2020-03-18 16:12:38 +00:00
n1474335
130bdfb7f2 Updated dependencies 2020-03-18 16:12:30 +00:00
n1474335
d0c43f5aa9 Added a challenge 2020-03-18 15:45:40 +00:00
n1474335
f864a5f31e Suppressed highlighting errors 2020-03-18 13:40:16 +00:00
n1073645
ff585584f6 MP3 Extractor 2020-03-18 12:51:47 +00:00
n1073645
8a029e5147 Grunt npm tests changed to npm test 2020-03-17 08:40:15 +00:00
n1073645
4251089687 Targa Image Extractor 2020-03-17 08:24:35 +00:00
n1073645
dbcd670ca8 Targa file extractor 2020-03-16 16:56:01 +00:00
n1474335
cecae671d8 9.18.0 2020-03-13 17:13:19 +00:00
n1474335
b4e23ac454 Updated CHANGELOG 2020-03-13 17:13:12 +00:00
n1474335
e7209ca085 Merge branch 'MarvinJWendt-operation/convert-to-nato-alphabet' 2020-03-13 17:10:50 +00:00
n1474335
022ef71d2c Tidied up 'Convert to NATO alphabet' operation 2020-03-13 17:10:29 +00:00
n1474335
0fad891a3a Merge branch 'operation/convert-to-nato-alphabet' of https://github.com/MarvinJWendt/CyberChef into MarvinJWendt-operation/convert-to-nato-alphabet 2020-03-13 16:45:37 +00:00
n1474335
47f608b502 9.17.0 2020-03-13 16:38:03 +00:00
n1474335
4ab745f730 Updated CHANGELOG 2020-03-13 16:37:41 +00:00
n1474335
1f89ac11d2 Merge branch 'pointhi-generate_image' 2020-03-13 16:35:33 +00:00
n1474335
1a5dae76c2 Tidied up 'Generate Image' operation 2020-03-13 16:35:19 +00:00
n1474335
032c7f529a Merge branch 'generate_image' of https://github.com/pointhi/CyberChef into pointhi-generate_image 2020-03-13 16:20:45 +00:00
n1474335
707818abcc Merge branch 'n1073645-importFix' 2020-03-13 16:18:31 +00:00
n1474335
58e8b4c618 Merge branch 'importFix' of https://github.com/n1073645/CyberChef into n1073645-importFix 2020-03-13 16:18:10 +00:00
n1474335
9c0c2867dd Increased test timeout to 120s from 60 2020-03-13 15:06:40 +00:00
n1474335
4308c717c3 Tests now display a progress bar and report long running tests 2020-03-13 14:59:48 +00:00
n1073645
342b67581b Very small correction for import in Colossus 2020-03-13 10:14:08 +00:00
n1474335
75da5b650c Replaced 'new Date().getTime()' calls with 'Date.now()' for clarity and performance 2020-03-12 15:23:22 +00:00
n1073645
5b6a53be3e Docstrings added for Magic functions 2020-03-12 14:55:19 +00:00
n1073645
5b5105c864 Caching added for Magic regexes 2020-03-12 14:45:40 +00:00
n1474335
9d09146f68 9.16.4 2020-03-12 14:42:10 +00:00
n1474335
1b19d20d0c Merge branch 'n1073645-Luhn' 2020-03-12 14:42:03 +00:00
n1474335
0eacab5ddc Tidied up Luhn checksum op 2020-03-12 14:41:46 +00:00
n1474335
0d7874bac1 Merge branch 'Luhn' of https://github.com/n1073645/CyberChef into n1073645-Luhn 2020-03-12 14:35:40 +00:00
n1474335
5cddfafbd0 9.16.3 2020-03-12 14:31:49 +00:00
n1474335
5ce133c47e Merge branch 'VirtualColossus-master' 2020-03-12 14:31:38 +00:00
n1073645
570a84b67a More Magic tests 2020-03-11 16:27:37 +00:00
VirtualColossus
a68bfd7223 Fix gchq#973 custom setting correction 2020-03-11 13:01:49 +00:00
n1073645
fd7176a445 Extra Magic Tests 2020-03-11 12:51:46 +00:00
n1073645
0a06472639 Test added for From Hex 2020-03-10 11:23:14 +00:00
n1073645
3f3a7cd4f6 From Hex Regexes 2020-03-10 11:12:43 +00:00
n1073645
99415359d0 Extra Magic Tests 2020-03-10 09:39:13 +00:00
n1073645
54cb2d268b Luhn checksum tests 2020-03-09 09:37:34 +00:00
n1073645
0e40daecb6 Generates both the checksum and checkdigit. 2020-03-09 09:13:02 +00:00
n1474335
21a822b082 9.16.2 2020-03-06 16:00:06 +00:00
n1474335
a770d09687 Merge branch 'n1073645-debExtractor' 2020-03-06 15:59:59 +00:00
n1474335
27b81c4e11 Tidied up JAR and DEB extractors 2020-03-06 15:59:42 +00:00
n1474335
8826c80e07 Merge branch 'debExtractor' of https://github.com/n1073645/CyberChef into n1073645-debExtractor 2020-03-06 15:57:16 +00:00
n1073645
02e3ce7fc1 Linting 2020-03-06 14:50:25 +00:00
n1073645
673e6aede5 Moved alternative JAR signature 2020-03-06 14:26:05 +00:00
n1474335
5809dea0fc 9.16.1 2020-03-06 13:36:17 +00:00
n1474335
165ca9ebc1 Merge branch 'n1073645-moreExtractors' 2020-03-06 13:36:07 +00:00
n1474335
154b9386f7 Merge commit 'refs/pull/932/head' of github.com:gchq/CyberChef into n1073645-moreExtractors 2020-03-06 13:34:35 +00:00
n1073645
62dd7c3dbc Removed debugging try/catch 2020-03-06 13:29:11 +00:00
n1474335
82d098fc1a Merge branch 'moreExtractors' of https://github.com/n1073645/CyberChef into n1073645-moreExtractors 2020-03-06 13:21:13 +00:00
n1474335
c69ac7f0f2 9.16.0 2020-03-06 13:10:57 +00:00
n1474335
5578f4577d Updated CHANGELOG 2020-03-06 13:08:15 +00:00
n1474335
28bd8a32e3 Merge branch 'VirtualColossus-master' 2020-03-06 13:05:30 +00:00
n1474335
24fd35e6af Tidied up Colossus operation 2020-03-06 13:05:08 +00:00
n1474335
c4493d15b6 Merge branch 'master' of https://github.com/VirtualColossus/CyberChef into VirtualColossus-master 2020-03-06 10:43:52 +00:00
n1474335
f9ef9739b0 9.15.1 2020-03-05 17:11:44 +00:00
n1474335
d50b9103c2 Merge branch 'n1073645-extractWavFix' 2020-03-05 17:11:38 +00:00
n1474335
196a611c9b Merge branch 'extractWavFix' of https://github.com/n1073645/CyberChef into n1073645-extractWavFix 2020-03-05 17:09:54 +00:00
n1474335
7c057ad254 Added logo files to repository 2020-03-05 17:02:02 +00:00
n1474335
cced384e0a 9.15.0 2020-03-05 16:43:15 +00:00
n1474335
cce7abecd5 Updated CHANGELOG 2020-03-05 16:43:10 +00:00
n1474335
8013b3b5e9 Merge branch 'n1073645-NewCiphers' 2020-03-05 16:40:07 +00:00
n1474335
64b979e25e CipherSaber2 ops now accept a variety of key types 2020-03-05 16:39:52 +00:00
n1474335
5e7b004925 Merge branch 'NewCiphers' of https://github.com/n1073645/CyberChef into n1073645-NewCiphers 2020-03-05 15:25:10 +00:00
n1474335
1e791d7f1b 9.14.0 2020-03-05 15:22:23 +00:00
n1474335
a255d1912c Updated CHANGELOG 2020-03-05 15:22:16 +00:00
n1474335
3d1266f815 Merge branch 'n1073645-Luhn' 2020-03-05 15:19:37 +00:00
n1474335
ede78c540f Tidied up 'Luhn Checksum' operation 2020-03-05 15:19:23 +00:00
n1474335
c0f003b450 Merge branch 'Luhn' of https://github.com/n1073645/CyberChef into n1073645-Luhn 2020-03-05 15:16:50 +00:00
n1073645
14190fc533 DEB extractor 2020-03-05 15:01:07 +00:00
n1474335
9f34009244 9.13.2 2020-03-05 14:46:41 +00:00
n1474335
bc2fefd1b2 Merge branch 'n1073645-emailRegexFix' 2020-03-05 14:46:30 +00:00
n1073645
940b56ba5f Luhn Checksum Operation Added 2020-02-26 10:55:15 +00:00
n1073645
8f2a1f5b2c Improved email regex 2020-02-25 14:48:22 +00:00
n1073645
20d0ae5304 Linting corrections 2020-02-25 11:35:39 +00:00
n1073645
2ba37af109 extra signatures 2020-02-25 11:33:35 +00:00
n1073645
728f8e65d6 Magic rebuild 2020-02-25 11:27:03 +00:00
n1474335
d78730edc0 9.13.1 2020-02-19 12:06:11 +00:00
n1474335
b0d2593968 Merge branch 'n1073645-MoreSignatures' 2020-02-19 12:05:30 +00:00
n1474335
38a033f1a9 Updated npm install 2020-02-19 12:05:06 +00:00
n1474335
846ad1796a Merge branch 'MoreSignatures' of https://github.com/n1073645/CyberChef into n1073645-MoreSignatures 2020-02-19 12:04:30 +00:00
n1073645
355a6d6b76 Modifications made to CipherSaber2 2020-02-14 14:21:32 +00:00
n1073645
6090842372 Modifications made to ciphersaber 2020-02-14 09:15:50 +00:00
n1073645
0a3bd6456c Modifications made to signatures 2020-02-14 08:27:48 +00:00
n1474335
ab6576d739 Travis config now uses dpl v2 2020-02-13 16:31:44 +00:00
n1474335
d5615b90bb Updated .travis.yml 2020-02-13 16:14:02 +00:00
n1474335
cf1349ccb2 9.13.0 2020-02-13 15:09:19 +00:00
n1474335
36190f1967 Merge branch 'Flavsditz-master' 2020-02-13 15:09:08 +00:00
n1474335
3ecbe22d99 Updated CHANGELOG 2020-02-13 15:08:54 +00:00
n1474335
b045dc37f5 Tidied up infoURL in Rail Fence Cipher ops 2020-02-13 15:06:09 +00:00
n1474335
015d0f065f Merge branch 'master' of https://github.com/Flavsditz/CyberChef into Flavsditz-master 2020-02-13 15:04:00 +00:00
n1474335
d7cc6c7363 9.12.1 2020-02-13 14:18:12 +00:00
n1474335
a5bc1c6f9e Merge branch 'cbeuw-toHex' 2020-02-13 14:17:58 +00:00
n1474335
c2212f9ab3 Tidied up To Hex mods 2020-02-13 14:17:43 +00:00
n1474335
3fb5bf14a6 Merge branch 'toHex' of https://github.com/cbeuw/CyberChef into cbeuw-toHex 2020-02-13 12:58:39 +00:00
n1474335
f32b7d5de5 Merge branch 'retnikt-allow-custom-ports' 2020-02-13 12:54:21 +00:00
n1474335
7a58567659 Updated chromedriver version 2020-02-13 12:54:05 +00:00
n1474335
4be0a436f2 Merge branch 'allow-custom-ports' of https://github.com/retnikt/CyberChef into retnikt-allow-custom-ports 2020-02-13 12:34:02 +00:00
n1474335
1e71fc91a1 Merge branch 'hjung4-spell' 2020-02-13 12:29:49 +00:00
Flavio Diez
0ab96dd4ca Throw OperationError instead of returning a String 2020-01-29 14:16:04 +01:00
Flavio Diez
1509b2b96c Implemented the Rail Fence Cipher with both encoding and decoding 2020-01-29 12:46:38 +01:00
comet
4430ea55c4 update 2020-01-27 17:02:13 -06:00
retnikt
4b6cebc068 allow custom ports for Grunt tasks 2020-01-27 18:55:50 +00:00
n1073645
a06303c2fd CipherSaber2 added 2020-01-27 14:33:05 +00:00
n1073645
115b064081 Extra Signatures added 2020-01-23 12:56:51 +00:00
Andy Wang
1197859865 Preserve null data when type is number in prepare 2020-01-18 14:56:17 +00:00
Andy Wang
293a95e938 Remove tickbox and make 0x comma an option 2020-01-18 13:55:32 +00:00
Andy Wang
9a3464a5ec Fix ingredient type conversion for null number 2020-01-18 13:19:28 +00:00
Andy Wang
55dddd3ef9 Add tests 2020-01-18 00:21:15 +00:00
Andy Wang
23956480b7 Variable name 2020-01-17 18:47:46 +00:00
Andy Wang
6dbaf6a36c reverse highlight 2020-01-17 12:48:21 +00:00
Andy Wang
1d8c7dcb97 Allow output highlighting 2020-01-15 23:29:18 +00:00
Andy Wang
41c8a5aff0 fromHex can now extract 0x format 2020-01-15 22:20:47 +00:00
Andy Wang
597fba2fd0 Add line size formatting and comma separation 2020-01-15 00:14:43 +00:00
n1073645
0f0674daf6 More extractors added. 2020-01-09 09:57:12 +00:00
n1073645
d9b7fe2bb9 ExtractWAV fixed 2020-01-06 12:32:14 +00:00
n1073645
ace8121d0e Update dependencies. 2020-01-06 08:53:51 +00:00
n1474335
f7be8d720b 9.12.0 2019-12-20 16:08:03 +00:00
n1474335
0a5038e533 Updated CHANGELOG 2019-12-20 16:07:52 +00:00
n1474335
5feba30956 Merge branch 'matthieuxyz-normalise-unicode' 2019-12-20 16:05:43 +00:00
n1474335
23a228bbd9 Tidied up Normalise Unicode operation 2019-12-20 16:05:24 +00:00
n1474335
598813ff88 Merge branch 'normalise-unicode' of https://github.com/matthieuxyz/CyberChef into matthieuxyz-normalise-unicode 2019-12-20 15:56:59 +00:00
n1474335
118f0130d8 9.11.20 2019-12-20 15:55:26 +00:00
n1474335
e77d3a4b7d Merge branch 'n1073645-dev' 2019-12-20 15:55:01 +00:00
n1474335
bf0bd620f1 Tidied up Case Insensitive Regex ops 2019-12-20 15:54:39 +00:00
n1474335
62edd76d7e Merge branch 'dev' of https://github.com/n1073645/CyberChef into n1073645-dev 2019-12-20 15:49:40 +00:00
n1474335
cef6585cab 9.11.19 2019-12-20 15:47:29 +00:00
n1474335
481241b88d Merge branch 'bartblaze-master' 2019-12-20 15:46:23 +00:00
n1474335
93c0c7cc10 Merge branch 'master' of https://github.com/bartblaze/CyberChef into bartblaze-master 2019-12-20 15:45:31 +00:00
n1474335
01d9536bbd Merge branch 'n1073645-dish-fix' 2019-12-20 15:42:15 +00:00
n1474335
24a7c75926 Merge branch 'dish-fix' of https://github.com/n1073645/CyberChef into n1073645-dish-fix 2019-12-20 15:41:59 +00:00
n1474335
c2eea7a9f7 9.11.18 2019-12-20 15:39:32 +00:00
n1474335
e2812cadb5 Merge branch 'n1073645-dish-fix' 2019-12-20 15:39:23 +00:00
n1073645
cde958af16 Linting 2019-12-20 15:27:46 +00:00
n1073645
bf70589b3c Tidy up 2019-12-20 15:23:30 +00:00
n1073645
78d1114869 Merge remote-tracking branch 'upstream/master' into dish-fix 2019-12-20 15:22:31 +00:00
n1474335
ab83caa77b 9.11.17 2019-12-20 15:21:13 +00:00
n1474335
42dd03bb84 Merge branch 'n1073645-gzip-bugfix' 2019-12-20 15:21:05 +00:00
n1474335
cb09949fb9 Merge branch 'gzip-bugfix' of https://github.com/n1073645/CyberChef into n1073645-gzip-bugfix 2019-12-20 15:17:36 +00:00
n1474335
0c6eac3b21 9.11.16 2019-12-20 15:04:49 +00:00
n1474335
5e771c521c Merge branch 'n1073645-ICOextractor' 2019-12-20 15:04:39 +00:00
n1474335
b8afbf7458 Tidied up ICO extractor 2019-12-20 15:04:27 +00:00
n1474335
be59efbd6b Merge branch 'ICOextractor' of https://github.com/n1073645/CyberChef into n1073645-ICOextractor 2019-12-20 15:03:05 +00:00
n1474335
99ccd06f23 9.11.15 2019-12-20 15:02:01 +00:00
n1474335
f4d75f88a9 Merge branch 'n1073645-OLE2' 2019-12-20 15:00:28 +00:00
n1474335
9112bd4936 Tidied up OLE2 extractor 2019-12-20 15:00:10 +00:00
n1474335
3e513efd59 Merge branch 'OLE2' of https://github.com/n1073645/CyberChef into n1073645-OLE2 2019-12-20 14:47:50 +00:00
n1073645
4100a22c7f Linting on tests 2019-12-17 12:30:32 +00:00
n1073645
71078d9332 Added tests for gunzip. 2019-12-17 12:28:09 +00:00
n1073645
72ba579e1e Remove unnecessary comments. 2019-12-17 12:17:13 +00:00
n1073645
5fd2512a9b Gzip tests added 2019-12-17 12:15:11 +00:00
n1073645
3a1a6a94d2 Sets the gzip comment bitfield 2019-12-16 17:05:06 +00:00
n1474335
928178716a Operation elements now have decreasing z-index properties, meaning dropdowns do not get hidden. Fixes #925 2019-12-16 14:46:06 +00:00
n1073645
08419a20c0 Fixed the magic bug where it wouldnt recommended operations that resulted in lists of files 2019-12-13 16:27:31 +00:00
n1073645
60506ee2d1 Fixed the magic bug where it wouldnt recommended operations that resulted in lists of files 2019-12-13 16:23:54 +00:00
n1073645
6e411c9dd9 Merge remote-tracking branch 'upstream/master' into dish-fix 2019-12-13 16:11:48 +00:00
n1073645
86db43e6dd Fixed the magic bug where it wouldnt recommended operations that resulted in lists of files 2019-12-13 16:09:02 +00:00
n1474335
252ac0bdaa 9.11.14 2019-12-13 14:57:09 +00:00
n1474335
4d8b1721bc Always display HTML outputs even if they are above the size threshold. Could lead to crashing, but this risk is accepted. 2019-12-13 14:57:03 +00:00
n1474335
fd390bc61b Improved CR preservation logic - now based on entropy 2019-12-13 14:45:13 +00:00
n1474335
813a151524 Added 'Show all' button to output file overlay 2019-12-13 12:59:59 +00:00
Bart
c06502cd76 Improve RTF detection
Certain RTF files may attempt to thwart detection by having a malformed RTF header, such as **{\rt000**. Removing 0x66 will result in detecting these malformed yet valid RTFs as well.

Additional reading:
https://www.decalage.info/rtf_tricks#Trick_1:_Incomplete_RTF_Header
2019-12-11 22:58:33 +01:00
n1474335
974ce1fd12 9.11.13 2019-12-10 16:21:59 +00:00
n1474335
d2dc50fe8e Fixed file overlay icon 2019-12-10 16:21:53 +00:00
n1474335
ec50105e34 9.11.12 2019-12-09 13:51:52 +00:00
n1474335
86ebed132d Updated dependencies 2019-12-09 13:51:48 +00:00
n1073645
47ccafcbb2 Linting and tidy up 2019-12-05 09:47:32 +00:00
VirtualColossus
9f901188af Added Colossus test 2019-12-04 23:02:20 +00:00
VirtualColossus
ccdd2af8be Added tests, removed debug 2019-12-04 22:43:22 +00:00
VirtualColossus
a387db6109 Merge branch 'master' of https://github.com/VirtualColossus/CyberChef 2019-12-04 14:29:41 +00:00
VirtualColossus
b88a35cd14 Added P5 limitation 2019-12-04 14:28:53 +00:00
VirtualColossus
bcafaebf77 Merge remote-tracking branch 'upstream/master' 2019-12-04 14:28:05 +00:00
n1474335
798f013219 9.11.11 2019-12-02 15:17:22 +00:00
n1474335
61e6423d95 Added word separator code to Morse Code ops. 2019-12-02 15:17:17 +00:00
VirtualColossus
c32fec6b53 Various fixes for conditional calcs 2019-11-30 10:25:24 +00:00
VirtualColossus
4c0d944992 Merge remote-tracking branch 'upstream/master' 2019-11-29 20:36:06 +00:00
VirtualColossus
57ee3f305d Fixed issue in counter 2019-11-28 13:56:02 +00:00
VirtualColossus
61ab9a904f Added argument validation 2019-11-28 13:22:51 +00:00
VirtualColossus
820bd2f867 Added Total Motor, fixed bug in printout 2019-11-27 13:38:28 +00:00
n1474335
44c2b71e6c 9.11.10 2019-11-27 12:56:30 +00:00
n1474335
b806be3f49 Merge branch 'n1073645-master' 2019-11-27 12:56:21 +00:00
n1474335
2750284eea Improved comment in Tar extractor 2019-11-27 12:56:10 +00:00
n1474335
5366f1a2eb Merge branch 'master' of https://github.com/n1073645/CyberChef into n1073645-master 2019-11-27 12:52:25 +00:00
VirtualColossus
32625dc0b0 Added label type ingredient 2019-11-27 12:49:35 +00:00
VirtualColossus
dfc8f517f2 Added Colossus operation 2019-11-27 12:48:09 +00:00
n1474335
b459c15d74 9.11.9 2019-11-27 12:47:16 +00:00
n1474335
8a02b35d7d Merge branch 'Mirclus-master' 2019-11-27 12:47:10 +00:00
n1474335
d4441823aa Merge branch 'master' of https://github.com/Mirclus/CyberChef into Mirclus-master 2019-11-27 12:46:25 +00:00
n1474335
13e9a4f0da 9.11.8 2019-11-27 12:36:18 +00:00
n1474335
33471a33d6 Merge branch 'fjh1997-master' 2019-11-27 12:36:13 +00:00
Matthieu
a6fa0628f2 Add operation to normalise unicode 2019-11-25 22:59:14 +01:00
Mirclus
8e5aa2c393 DNS over HTTP: Fix "validate" argument
The argument sets the "cd" parameter on the request.
For both included providers, this flag disables validation ([1], [2]),
so doing the exact opposite of the described action.

This changes the label to the correct name and also flips the default
value to keep the old behavior.

[1] Google
<https://developers.google.com/speed/public-dns/docs/doh/json#supported_parameters>
[2] Cloudflare
<https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/>
2019-11-25 20:08:30 +01:00
n1073645
1118ff598d From Base85 and From Braille signatures added for magic 2019-11-25 13:43:31 +00:00
n1073645
09e93b4639 Added ICO extractor 2019-11-25 11:26:31 +00:00
fjh1997
d16bbe1e7e Fixed typo in IPV6 alphabet
According to python3 base64.b85decode module https://github.com/python/cpython/blob/3.8/Lib/base64.py
2019-11-24 22:03:37 +08:00
n1073645
4814922e67 Linting for regex operation 2019-11-22 10:58:24 +00:00
n1073645
81d1007bb7 Added tests for regex operation and a slight bug fix 2019-11-22 10:45:02 +00:00
n1474335
610d46a1a4 9.11.7 2019-11-21 14:21:20 +00:00
n1474335
f7acef4642 Fixed module detection issue. Closes #881 2019-11-21 14:13:36 +00:00
n1474335
fd5b6c5243 9.11.6 2019-11-21 13:05:39 +00:00
n1474335
a8917e4713 Updated dependencies 2019-11-21 12:15:07 +00:00
n1073645
04036e001e Comments and linting for regex operation. 2019-11-21 12:13:34 +00:00
n1073645
725b0d42f8 Comments to OLE2 extractor 2019-11-21 11:34:11 +00:00
n1073645
071c1bdea6 Comments for OLE2 extractor. 2019-11-21 11:29:45 +00:00
n1073645
7386c145ef Comments for OLE2 extractor. 2019-11-21 11:23:28 +00:00
n1073645
25ca8d85a6 Added extractor for OLE2 and modified the PLIST one. 2019-11-21 11:14:56 +00:00
n1073645
c60ed2c403 Linting on regex operation 2019-11-21 09:56:52 +00:00
n1073645
7d41d4d030 Replaced the .replaces in regex operation 2019-11-21 09:11:12 +00:00
n1073645
6d77fe6eb3 Combined two rules into one case insensitive rule 2019-11-20 09:28:34 +00:00
n1073645
40d3c8b071 ToCaseInsensitiveRegex improvements 2019-11-18 13:31:19 +00:00
n1073645
02ec4a3bfd ToCaseInsensitiveRegex improvements 2019-11-18 13:21:05 +00:00
n1073645
7a4ebbf47e Tidied up ExtractTAR 2019-11-18 08:42:46 +00:00
n1073645
2e7ce477d7 Tidied up ExtractTAR 2019-11-18 08:40:57 +00:00
n1073645
c1a22ef639 Made TAR extractor and MACHO signature more robust 2019-11-15 16:01:33 +00:00
n1073645
0a7b78b7ee Made TAR extractor and MACHO signature more robust 2019-11-15 15:46:13 +00:00
n1073645
e1cb62848c Made TAR extractor and MACHO signature more robust 2019-11-15 15:35:37 +00:00
n1073645
acf5c733c2 Tidied up local and global variables for Mach-o 2019-11-15 09:26:49 +00:00
n1073645
7c25e29515 Rectified magic bytes for MACHO extractor 2019-11-15 09:21:46 +00:00
n1073645
7c72871c02 Added Tar and Mach-O extractors 2019-11-14 17:17:25 +00:00
n1474335
ddb77c6ab3 Merge branch 'n1073645-master' 2019-11-14 16:09:38 +00:00
n1073645
8502fd246d Linting changes 2019-11-14 14:52:40 +00:00
n1073645
30c6917914 Merge remote-tracking branch 'upstream/master' 2019-11-14 09:03:06 +00:00
n1073645
33464b3388 Linting changes 2019-11-14 08:55:27 +00:00
n1474335
2205637ad6 9.11.5 2019-11-13 18:06:39 +00:00
n1474335
149198ef1c Merge branch 'janisozaur-node12filenames' 2019-11-13 18:06:20 +00:00
n1474335
2c40353180 Merge branch 'node12filenames' of https://github.com/janisozaur/CyberChef into janisozaur-node12filenames 2019-11-13 18:05:55 +00:00
Michał Janiszewski
69c6c3e790 Add missing filenames for Node 12 imports 2019-11-12 23:43:16 +01:00
Jarrod Connolly
462f619f43 Update JavaScript Minify operation to support ES6. 2019-10-31 23:18:54 -07:00
Thomas Pointhuber
ef61735f64 Fix typo 2019-10-12 17:52:16 +02:00
Thomas Pointhuber
a2780ca056 Add bitwse mode to Generate Image operation 2019-10-12 17:35:46 +02:00
Thomas Pointhuber
d025c8bd9a Add new operation to generate image from raw data 2019-10-12 17:13:14 +02:00
Marvin Wendt
acf38e47ba Add ConvertToNATOAlphabet tests 2019-10-11 15:32:14 +02:00
Marvin Wendt
4122d4207d Add ConvertToNATOAlphabet 2019-10-11 15:32:06 +02:00
Marvin Wendt
d550ae7d93 Add operation to categories 2019-10-11 15:31:46 +02:00
Marvin Wendt
815a542cc1 package-lock automaitcally updated on install 2019-10-11 15:31:25 +02:00
Matt
123a0ccd70 Changed pages workflow 2019-09-30 14:41:14 +01:00
Matt
4c737475d4 Forgot to run prod build 2019-09-30 14:08:23 +01:00
Matt
4e0d97f2c1 Added sudo 2019-09-30 14:02:22 +01:00
Matt
85906cafbb Adjustment 2019-09-30 13:56:26 +01:00
Matt
a8dc691033 Try using github actions
Gonna monch this commit once i know it works
2019-09-30 13:51:38 +01:00
Matt
4d7988b78e Fixed RSA key generation 2019-09-30 13:12:10 +01:00
Matt
841e760b04 Merge remote-tracking branch 'upstream/master' into features/rsa 2019-09-30 11:03:41 +01:00
Matt C
31e758ca45 Attempt to make RSA key generation functional 2018-08-31 11:25:05 +01:00
GCHQ 77703
f81ca3ba60 Implement RSA generation and signing of messages 2018-08-30 22:38:01 +01:00
225 changed files with 17448 additions and 7607 deletions

View File

@@ -47,6 +47,7 @@
"block-spacing": "error",
"array-bracket-spacing": "error",
"comma-spacing": "error",
"spaced-comment": ["error", "always", { "exceptions": ["/"] } ],
"comma-style": "error",
"computed-property-spacing": "error",
"no-trailing-spaces": "warn",

54
.github/workflows/master.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: Master
on:
push:
branches:
- master
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set node version
uses: actions/setup-node@v1
with:
node-version: '10.x'
- name: Install
run: |
npm install
export NODE_OPTIONS=--max_old_space_size=2048
- name: Lint
run: npx grunt lint
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
- name: Production Build
if: success()
run: npx grunt prod
- name: Generate sitemap
run: npx grunt exec:sitemap
- name: UI Tests
if: success()
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
- name: Prepare for GitHub Pages
if: success()
run: npx grunt copy:ghPages
- name: Deploy to GitHub Pages
if: success() && github.ref == 'refs/heads/master'
uses: crazy-max/ghaction-github-pages@v2
with:
target_branch: gh-pages
build_dir: ./build/prod
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

37
.github/workflows/pull_requests.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: PRs
on:
pull_request:
types: [synchronize, opened, reopened]
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set node version
uses: actions/setup-node@v1
with:
node-version: '10.x'
- name: Install
run: |
npm install
export NODE_OPTIONS=--max_old_space_size=2048
- name: Lint
run: npx grunt lint
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
- name: Production Build
if: success()
run: npx grunt prod
- name: UI Tests
if: success()
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui

55
.github/workflows/releases.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set node version
uses: actions/setup-node@v1
with:
node-version: '10.x'
- name: Install
run: |
npm install
export NODE_OPTIONS=--max_old_space_size=2048
- name: Lint
run: npx grunt lint
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
- name: Production Build
if: success()
run: npx grunt prod
- name: UI Tests
if: success()
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
- name: Upload Release Assets
if: success()
id: upload-release-assets
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/prod/*.zip
tag: ${{ github.ref }}
overwrite: true
file_glob: true
- name: Publish to NPM
if: success()
uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
lts/dubnium

View File

@@ -1,54 +0,0 @@
language: node_js
node_js:
- lts/dubnium
cache: npm
addons:
chrome: stable
install: npm install
before_script:
- npm install -g grunt
- export NODE_OPTIONS=--max_old_space_size=2048
script:
- grunt lint
- grunt test
- grunt testnodeconsumer
- grunt prod --msg="$COMPILE_MSG"
- xvfb-run --server-args="-screen 0 1200x800x24" grunt testui
before_deploy:
- grunt exec:sitemap
- grunt copy:ghPages
deploy:
- provider: pages
skip_cleanup: true
github_token: $GITHUB_TOKEN
local_dir: build/prod/
target_branch: gh-pages
on:
repo: gchq/CyberChef
branch: master
- provider: releases
skip_cleanup: true
api_key:
secure: "HV1WSKv4l/0Y2bKKs1iBJocBcmLj08PCRUeEM/jTwA4jqJ8EiLHWiXtER/D5sEg2iibRVKd2OQjfrmS6bo4AiwdeVgAKmv0FtS2Jw+391N8Nd5AkEANHa5Om/IpHLTL2YRAjpJTsDpY72bMUTJIwjQA3TFJkgrpOw6KYfohOcgbxLpZ4XuNJRU3VL4Hsxdv5V9aOVmfFOmMOVPQlakXy7NgtW5POp1f2WJwgcZxylkR1CjwaqMyXmSoVl46pyH3tr5+dptsQoKSGdi6sIHGA60oDotFPcm+0ifa47wZw+vapuuDi4tdNxhrHGaDMG8xiE0WFDHwQUDlk2/+W7j9SEX0H3Em7us371JXRp56EDwEcDa34VpVkC6i8HGcHK55hnxVbMZXGf3qhOFD8wY7qMbjMRvIpucrMHBi86OfkDfv0vDj2LyvIl5APj/AX50BrE0tfH1MZbH26Jkx4NdlkcxQ14GumarmUqfmVvbX/fsoA6oUuAAE9ZgRRi3KHO4wci6KUcRfdm+XOeUkaBFsL86G3EEYIvrtBTuaypdz+Cx7nd1iPZyWMx5Y1gXnVzha4nBdV4+7l9JIsFggD8QVpw2uHXQiS1KXFjOeqA3DBD8tjMB7q26Fl2fD3jkOo4BTbQ2NrRIZUu/iL+fOmMPsyMt2qulB0yaSBCfkbEq8xrUA="
file_glob: true
file:
- build/prod/*.zip
- src/node/cjs.js
on:
repo: gchq/CyberChef
tags: true
- provider: npm
skip_cleanup: true
email: "n1474335@gmail.com"
api_key:
secure: "UnDQL3Kh+GK2toL0TK3FObO0ujVssU3Eg4BBuYdjwLB81GhiGE5/DTh7THdZPOpbLo6wQeOwfZDuMeKC1OU+0Uf4NsdYFu1aq6xMO20qBQ4qUfgsyiK4Qgywj9gk0p1+OFZdGAZ/j1CNRAaF71XQIY6iV84c+SO4WoizXYrNT0Jh4sr2DA4/97G2xmJtPi0qOzYrJ09R56ZUozmqeik5G0pMRIuJRbpjS/7bZXV+N7WV0ombZc9RkUaetbabEVOLQ+Xx5YAIVq+VuEeMe9VBSnxY/FfCLmy1wJsjGzpLCyBI9nbrG4nw8Wgc2m8NfK9rcpIvBTGner9r2j60NVDkZ8kLZPrqXhq6AZMwa+oz6K5UQCqRo2RRQzSGwXxg67HY5Tcq+oNmjd+DqpPg4LZ3eGlluyP5XfG+hpSr9Ya4d8q8SrUWLxkoLHI6ZKMtoKFbTCSSQPiluW5hsZxjz3yDkkjsJw64M/EM8UyJrgaXqDklQu+7rBGKLfsK6os7RDiqjBWpQ7gwpo8HvY0O8yqEAabPz+QGkanpjcCOZCXFbSkzWxYy37RMAPu88iINVZVlZE4l+WJenCpZY95ueyy0mG9cyMSzVRPyX6A+/n4H6VMFPFjpGDLTD588ACEjY1lmHfS/eXwXJcgqPPD2gW0XdRdUheU/ssqlfCfGWQMTDXs="
on:
tags: true
branch: master
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/83c143a6822e218d5b34
on_success: change
on_failure: always
on_start: never

View File

@@ -1,7 +1,57 @@
# Changelog
## Versioning
CyberChef uses the [semver](https://semver.org/) system to manage versioning: MAJOR.MINOR.PATCH.
- MAJOR version changes represent a significant change to the fundamental architecture of CyberChef and may (but don't always) make breaking changes that are not backwards compatible.
- MINOR version changes usually mean the addition of new operations or reasonably significant new features.
- PATCH versions are used for bug fixes and any other small tweaks that modify or improve existing capabilities.
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).
## Details
### [9.24.0] - 2020-02-02
- 'SM3' hashing function added along with more configuration options for other hashing operations [@n1073645] [@n1474335] | [#1022]
### [9.23.0] - 2020-02-01
- Various RSA operations added to encrypt, decrypt, sign, verify and generate keys [@mattnotmitt] [@GCHQ77703] | [#652]
### [9.22.0] - 2021-02-01
- 'Unicode Text Format' operation added [@mattnotmitt] | [#1083]
### [9.21.0] - 2020-06-12
- Node API now exports `magic` operation [@d98762625] | [#1049]
### [9.20.0] - 2020-03-27
- 'Parse ObjectID Timestamp' operation added [@dmfj] | [#987]
### [9.19.0] - 2020-03-24
- Improvements to the 'Magic' operation, allowing it to recognise more data formats and provide more accurate results [@n1073645] [@n1474335] | [#966] [b765534b](https://github.com/gchq/CyberChef/commit/b765534b8b2a0454a5132a0a52d1d8844bcbdaaa)
### [9.18.0] - 2020-03-13
- 'Convert to NATO alphabet' operation added [@MarvinJWendt] | [#674]
### [9.17.0] - 2020-03-13
- 'Generate Image' operation added [@pointhi] | [#683]
### [9.16.0] - 2020-03-06
- 'Colossus' operation added [@VirtualColossus] | [#917]
### [9.15.0] - 2020-03-05
- 'CipherSaber2 Encrypt' and 'CipherSaber2 Decrypt' operations added [@n1073645] | [#952]
### [9.14.0] - 2020-03-05
- 'Luhn Checksum' operation added [@n1073645] | [#965]
### [9.13.0] - 2020-02-13
- 'Rail Fence Cipher Encode' and 'Rail Fence Cipher Decode' operations added [@Flavsditz] | [#948]
### [9.12.0] - 2019-12-20
- 'Normalise Unicode' operation added [@matthieuxyz] | [#912]
### [9.11.0] - 2019-11-06
- Implemented CFB, OFB, and CTR modes for Blowfish operations [@cbeuw] | [#653]
@@ -197,6 +247,19 @@ All major and minor version changes will be documented in this file. Details of
[9.24.0]: https://github.com/gchq/CyberChef/releases/tag/v9.24.0
[9.23.0]: https://github.com/gchq/CyberChef/releases/tag/v9.23.0
[9.22.0]: https://github.com/gchq/CyberChef/releases/tag/v9.22.0
[9.21.0]: https://github.com/gchq/CyberChef/releases/tag/v9.21.0
[9.20.0]: https://github.com/gchq/CyberChef/releases/tag/v9.20.0
[9.19.0]: https://github.com/gchq/CyberChef/releases/tag/v9.19.0
[9.18.0]: https://github.com/gchq/CyberChef/releases/tag/v9.18.0
[9.17.0]: https://github.com/gchq/CyberChef/releases/tag/v9.17.0
[9.16.0]: https://github.com/gchq/CyberChef/releases/tag/v9.16.0
[9.15.0]: https://github.com/gchq/CyberChef/releases/tag/v9.15.0
[9.14.0]: https://github.com/gchq/CyberChef/releases/tag/v9.14.0
[9.13.0]: https://github.com/gchq/CyberChef/releases/tag/v9.13.0
[9.12.0]: https://github.com/gchq/CyberChef/releases/tag/v9.12.0
[9.11.0]: https://github.com/gchq/CyberChef/releases/tag/v9.11.0
[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
@@ -257,6 +320,7 @@ All major and minor version changes will be documented in this file. Details of
[@n1474335]: https://github.com/n1474335
[@d98762625]: https://github.com/d98762625
[@j433866]: https://github.com/j433866
[@n1073645]: https://github.com/n1073645
[@GCHQ77703]: https://github.com/GCHQ77703
[@h345983745]: https://github.com/h345983745
[@s2224834]: https://github.com/s2224834
@@ -281,6 +345,12 @@ All major and minor version changes will be documented in this file. Details of
[@jarrodconnolly]: https://github.com/jarrodconnolly
[@VirtualColossus]: https://github.com/VirtualColossus
[@cbeuw]: https://github.com/cbeuw
[@matthieuxyz]: https://github.com/matthieuxyz
[@Flavsditz]: https://github.com/Flavsditz
[@pointhi]: https://github.com/pointhi
[@MarvinJWendt]: https://github.com/MarvinJWendt
[@dmfj]: https://github.com/dmfj
[@mattnotmitt]: https://github.com/mattnotmitt
[#95]: https://github.com/gchq/CyberChef/pull/299
[#173]: https://github.com/gchq/CyberChef/pull/173
@@ -342,5 +412,18 @@ All major and minor version changes will be documented in this file. Details of
[#625]: https://github.com/gchq/CyberChef/pull/625
[#627]: https://github.com/gchq/CyberChef/pull/627
[#632]: https://github.com/gchq/CyberChef/pull/632
[#652]: https://github.com/gchq/CyberChef/pull/652
[#653]: https://github.com/gchq/CyberChef/pull/653
[#674]: https://github.com/gchq/CyberChef/pull/674
[#683]: https://github.com/gchq/CyberChef/pull/683
[#865]: https://github.com/gchq/CyberChef/pull/865
[#912]: https://github.com/gchq/CyberChef/pull/912
[#917]: https://github.com/gchq/CyberChef/pull/917
[#948]: https://github.com/gchq/CyberChef/pull/948
[#952]: https://github.com/gchq/CyberChef/pull/952
[#965]: https://github.com/gchq/CyberChef/pull/965
[#966]: https://github.com/gchq/CyberChef/pull/966
[#987]: https://github.com/gchq/CyberChef/pull/987
[#1022]: https://github.com/gchq/CyberChef/pull/1022
[#1049]: https://github.com/gchq/CyberChef/pull/1049
[#1083]: https://github.com/gchq/CyberChef/pull/1083

View File

@@ -26,7 +26,7 @@ module.exports = function (grunt) {
grunt.registerTask("prod",
"Creates a production-ready build. Use the --msg flag to add a compile message.",
[
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "webpack:web",
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "findModules", "webpack:web",
"copy:standalone", "zip:standalone", "clean:standalone", "chmod"
]);
@@ -36,11 +36,10 @@ module.exports = function (grunt) {
"clean:node", "clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
]);
grunt.registerTask("test",
"A task which runs all the operation tests in the tests directory.",
grunt.registerTask("configTests",
"A task which configures config files in preparation for tests to be run. Use `npm test` to run tests.",
[
"clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex",
"exec:nodeTests", "exec:opTests"
"clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
]);
grunt.registerTask("testui",
@@ -55,9 +54,21 @@ module.exports = function (grunt) {
"Lints the code base",
["eslint", "exec:repoSize"]);
grunt.registerTask("tests", "test");
grunt.registerTask("lint", "eslint");
grunt.registerTask("findModules",
"Finds all generated modules and updates the entry point list for Webpack",
function(arg1, arg2) {
const moduleEntryPoints = listEntryModules();
grunt.log.writeln(`Found ${Object.keys(moduleEntryPoints).length} modules.`);
grunt.config.set("webpack.web.entry",
Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints));
});
// Load tasks provided by each plugin
grunt.loadNpmTasks("grunt-eslint");
@@ -67,7 +78,6 @@ module.exports = function (grunt) {
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-chmod");
grunt.loadNpmTasks("grunt-exec");
grunt.loadNpmTasks("grunt-accessibility");
grunt.loadNpmTasks("grunt-concurrent");
grunt.loadNpmTasks("grunt-contrib-connect");
grunt.loadNpmTasks("grunt-zip");
@@ -83,7 +93,53 @@ module.exports = function (grunt) {
PKG_VERSION: JSON.stringify(pkg.version),
},
moduleEntryPoints = listEntryModules(),
nodeConsumerTestPath = "~/tmp-cyberchef";
nodeConsumerTestPath = "~/tmp-cyberchef",
/**
* Configuration for Webpack production build. Defined as a function so that it
* can be recalculated when new modules are generated.
*/
webpackProdConf = () => {
return {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod",
filename: chunkData => {
return chunkData.chunk.name === "main" ? "assets/[name].js": "[name].js";
},
globalObject: "this"
},
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
minify: {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true
}
}),
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: "BundleAnalyzerReport.html",
openAnalyzer: false
}),
]
};
};
/**
@@ -140,67 +196,15 @@ module.exports = function (grunt) {
node: ["src/node/**/*.{js,mjs}"],
tests: ["tests/**/*.{js,mjs}"],
},
accessibility: {
options: {
accessibilityLevel: "WCAG2A",
verbose: false,
ignore: [
"WCAG2A.Principle1.Guideline1_3.1_3_1.H42.2"
]
},
test: {
src: ["build/**/*.html"]
}
},
webpack: {
options: webpackConfig,
web: () => {
return {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod",
filename: chunkData => {
return chunkData.chunk.name === "main" ? "assets/[name].js": "[name].js";
},
globalObject: "this"
},
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
minify: {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true
}
}),
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: "BundleAnalyzerReport.html",
openAnalyzer: false
}),
]
};
},
web: webpackProdConf(),
},
"webpack-dev-server": {
options: {
webpack: webpackConfig,
host: "0.0.0.0",
port: grunt.option("port") || 8080,
disableHostCheck: true,
overlay: true,
inline: false,
@@ -257,7 +261,7 @@ module.exports = function (grunt) {
connect: {
prod: {
options: {
port: 8000,
port: grunt.option("port") || 8000,
base: "build/prod/"
}
}
@@ -285,7 +289,7 @@ module.exports = function (grunt) {
},
files: [
{
src: "build/prod/index.html",
src: ["build/prod/index.html"],
dest: "build/prod/index.html"
}
]
@@ -307,7 +311,7 @@ module.exports = function (grunt) {
},
files: [
{
src: "build/prod/index.html",
src: ["build/prod/index.html"],
dest: `build/prod/CyberChef_v${pkg.version}.html`
}
]
@@ -345,7 +349,8 @@ module.exports = function (grunt) {
command: "git gc --prune=now --aggressive"
},
sitemap: {
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml"
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml",
sync: true
},
generateConfig: {
command: chainCommands([
@@ -354,7 +359,8 @@ module.exports = function (grunt) {
"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'"
])
]),
sync: true
},
generateNodeIndex: {
command: chainCommands([
@@ -362,16 +368,11 @@ module.exports = function (grunt) {
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
"echo '--- Node index generated. ---\n'"
]),
},
opTests: {
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
sync: true
},
browserTests: {
command: "./node_modules/.bin/nightwatch --env prod"
},
nodeTests: {
command: "node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs"
},
setupNodeConsumers: {
command: chainCommands([
"echo '\n--- Testing node consumers ---'",
@@ -381,6 +382,7 @@ module.exports = function (grunt) {
`cd ${nodeConsumerTestPath}`,
"npm link cyberchef"
]),
sync: true
},
teardownNodeConsumers: {
command: chainCommands([

12963
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.11.4",
"version": "9.24.1",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -36,133 +36,143 @@
"node >= 10"
],
"devDependencies": {
"@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.3.0",
"chromedriver": "^77.0.0",
"colors": "^1.3.3",
"copy-webpack-plugin": "^5.0.4",
"css-loader": "^3.2.0",
"eslint": "^6.2.2",
"exports-loader": "^0.7.0",
"file-loader": "^4.2.0",
"grunt": "^1.0.4",
"grunt-accessibility": "~6.0.0",
"@babel/core": "^7.12.10",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"autoprefixer": "^10.2.4",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"babel-plugin-dynamic-import-node": "^2.3.3",
"chromedriver": "^88.0.0",
"cli-progress": "^3.9.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.1",
"eslint": "^7.19.0",
"exports-loader": "^2.0.0",
"file-loader": "^6.2.0",
"grunt": "^1.3.0",
"grunt-chmod": "~1.1.1",
"grunt-concurrent": "^3.0.0",
"grunt-contrib-clean": "~2.0.0",
"grunt-contrib-connect": "^2.0.0",
"grunt-contrib-connect": "^3.0.0",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^22.0.0",
"grunt-eslint": "^23.0.0",
"grunt-exec": "~3.0.0",
"grunt-webpack": "^3.1.3",
"grunt-webpack": "^4.0.2",
"grunt-zip": "^0.18.2",
"html-webpack-plugin": "^3.2.0",
"imports-loader": "^0.8.0",
"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": "^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"
"html-webpack-plugin": "^4.5.1",
"imports-loader": "^2.0.0",
"mini-css-extract-plugin": "^1.3.5",
"nightwatch": "^1.5.1",
"node-sass": "^5.0.0",
"postcss": "^8.2.4",
"postcss-css-variables": "^0.17.0",
"postcss-import": "^14.0.0",
"postcss-loader": "^4.2.0",
"prompt": "^1.1.0",
"sass-loader": "^10.1.1",
"sitemap": "^6.3.5",
"style-loader": "^2.0.0",
"svg-url-loader": "^7.1.1",
"url-loader": "^4.1.1",
"webpack": "^5.19.0",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-dev-server": "^3.11.2",
"webpack-node-externals": "^2.5.2",
"worker-loader": "^3.0.7"
},
"dependencies": {
"@babel/polyfill": "^7.4.4",
"@babel/runtime": "^7.5.5",
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.12.5",
"arrive": "^2.4.1",
"avsc": "^5.4.16",
"avsc": "^5.5.3",
"babel-plugin-transform-builtin-extend": "1.1.2",
"bcryptjs": "^2.4.3",
"bignumber.js": "^9.0.0",
"bignumber.js": "^9.0.1",
"blakejs": "^1.1.0",
"bootstrap": "4.3.1",
"bootstrap-colorpicker": "^3.1.2",
"bootstrap-material-design": "^4.1.2",
"bson": "^4.0.2",
"bootstrap": "4.6.0",
"bootstrap-colorpicker": "^3.2.0",
"bootstrap-material-design": "^4.1.3",
"browserify-zlib": "^0.2.0",
"bson": "^4.2.2",
"buffer": "^6.0.3",
"chi-squared": "^1.1.0",
"codepage": "^1.14.0",
"core-js": "^3.2.1",
"core-js": "^3.8.3",
"crypto-api": "^0.8.5",
"crypto-js": "^3.1.9-1",
"crypto-browserify": "^3.12.0",
"crypto-js": "^4.0.0",
"ctph.js": "0.0.5",
"d3": "^5.11.0",
"d3": "^6.5.0",
"d3-hexbin": "^0.2.2",
"diff": "^4.0.1",
"es6-promisify": "^6.0.2",
"escodegen": "^1.12.0",
"diff": "^5.0.0",
"es6-promisify": "^6.1.1",
"escodegen": "^2.0.0",
"esm": "^3.2.25",
"esmangle": "^1.0.1",
"esprima": "^4.0.1",
"exif-parser": "^0.1.12",
"file-saver": "^2.0.2",
"file-saver": "^2.0.5",
"flat": "^5.0.2",
"geodesy": "^1.1.3",
"highlight.js": "^9.15.10",
"jimp": "^0.6.4",
"jquery": "3.4.1",
"highlight.js": "^10.5.0",
"jimp": "^0.16.1",
"jquery": "3.5.1",
"js-crc": "^0.2.0",
"js-sha3": "^0.8.0",
"jsesc": "^2.5.2",
"jsonpath": "^1.0.2",
"jsesc": "^3.0.2",
"jsonpath": "^1.1.0",
"jsonwebtoken": "^8.5.1",
"jsqr": "^1.2.0",
"jsrsasign": "8.0.12",
"kbpgp": "2.1.3",
"jsqr": "^1.3.1",
"jsrsasign": "10.1.5",
"kbpgp": "2.1.15",
"libbzip2-wasm": "0.0.4",
"libyara-wasm": "^1.0.1",
"lodash": "^4.17.15",
"loglevel": "^1.6.3",
"libyara-wasm": "^1.1.0",
"lodash": "^4.17.20",
"loglevel": "^1.7.1",
"loglevel-message-prefix": "^3.0.0",
"markdown-it": "^9.1.0",
"moment": "^2.24.0",
"moment-timezone": "^0.5.26",
"markdown-it": "^12.0.4",
"moment": "^2.29.1",
"moment-timezone": "^0.5.32",
"ngeohash": "^0.6.3",
"node-forge": "^0.9.1",
"node-forge": "^0.10.0",
"node-md6": "^0.1.0",
"nodom": "^2.2.0",
"notepack.io": "^2.2.0",
"nodom": "^2.4.0",
"notepack.io": "^2.3.0",
"nwmatcher": "^1.4.4",
"otp": "^0.1.3",
"popper.js": "^1.15.0",
"path": "^0.12.7",
"popper.js": "^1.16.1",
"process": "^0.11.10",
"qr-image": "^3.2.0",
"scryptsy": "^2.1.0",
"snackbarjs": "^1.1.0",
"sortablejs": "^1.9.0",
"split.js": "^1.5.11",
"sortablejs": "^1.13.0",
"split.js": "^1.6.2",
"ssdeep.js": "0.0.2",
"tesseract.js": "^2.0.0-alpha.15",
"ua-parser-js": "^0.7.20",
"stream-browserify": "^3.0.0",
"terser": "^5.5.1",
"tesseract.js": "^2.1.1",
"ua-parser-js": "^0.7.23",
"unorm": "^1.6.0",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3",
"xmldom": "^0.1.27",
"xpath": "0.0.27",
"xregexp": "^4.2.4",
"xmldom": "^0.4.0",
"xpath": "0.0.32",
"xregexp": "^4.4.1",
"zlibjs": "^0.3.1"
},
"scripts": {
"start": "grunt dev",
"build": "grunt prod",
"repl": "node src/node/repl.js",
"test": "grunt test",
"test": "grunt configTests && node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs",
"test-node-consumer": "grunt testnodeconsumer",
"testui": "grunt testui",
"testuidev": "npx nightwatch --env=dev",
"lint": "grunt lint",
"postinstall": "bash postinstall.sh",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
}
}

8
postinstall.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Add file extensions to Crypto-Api imports
if [[ "$OSTYPE" == "darwin"* ]]; then
find ./node_modules/crypto-api/src/ \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i '' -e '/\.mjs/!s/\(from "\.[^"]*\)";/\1.mjs";/g'
else
find ./node_modules/crypto-api/src/ \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i -e '/\.mjs/!s/\(from "\.[^"]*\)";/\1.mjs";/g'
fi

View File

@@ -39,7 +39,7 @@ class Chef {
*/
async bake(input, recipeConfig, options) {
log.debug("Chef baking");
const startTime = new Date().getTime(),
const startTime = Date.now(),
recipe = new Recipe(recipeConfig),
containsFc = recipe.containsFlowControl(),
notUTF8 = options && "treatAsUtf8" in options && !options.treatAsUtf8;
@@ -73,10 +73,10 @@ class Chef {
// The threshold is specified in KiB.
const threshold = (options.ioDisplayThreshold || 1024) * 1024;
const returnType =
this.dish.size > threshold ?
Dish.ARRAY_BUFFER :
this.dish.type === Dish.HTML ?
Dish.HTML :
this.dish.type === Dish.HTML ?
Dish.HTML :
this.dish.size > threshold ?
Dish.ARRAY_BUFFER :
Dish.STRING;
return {
@@ -84,7 +84,7 @@ class Chef {
result: await this.dish.get(returnType, notUTF8),
type: Dish.enumLookup(this.dish.type),
progress: progress,
duration: new Date().getTime() - startTime,
duration: Date.now() - startTime,
error: error
};
}
@@ -110,7 +110,7 @@ class Chef {
silentBake(recipeConfig) {
log.debug("Running silent bake");
const startTime = new Date().getTime(),
const startTime = Date.now(),
recipe = new Recipe(recipeConfig),
dish = new Dish();
@@ -119,7 +119,7 @@ class Chef {
} catch (err) {
// Suppress all errors
}
return new Date().getTime() - startTime;
return Date.now() - startTime;
}
@@ -146,7 +146,12 @@ class Chef {
const func = direction === "forward" ? highlights[i].f : highlights[i].b;
if (typeof func == "function") {
pos = func(pos, highlights[i].args);
try {
pos = func(pos, highlights[i].args);
} catch (err) {
// Throw away highlighting errors
pos = [];
}
}
}

View File

@@ -113,6 +113,7 @@ class Ingredient {
return data;
}
case "number":
if (data === null) return data;
number = parseFloat(data);
if (isNaN(number)) {
const sample = Utils.truncate(data.toString(), 10);

View File

@@ -591,6 +591,44 @@ class Utils {
return utf8 ? Utils.byteArrayToUtf8(arr) : Utils.byteArrayToChars(arr);
}
/**
* Calculates the Shannon entropy for a given set of data.
*
* @param {Uint8Array|ArrayBuffer} input
* @returns {number}
*/
static calculateShannonEntropy(data) {
if (data instanceof ArrayBuffer) {
data = new Uint8Array(data);
}
const prob = [],
occurrences = new Array(256).fill(0);
// Count occurrences of each byte in the input
let i;
for (i = 0; i < data.length; i++) {
occurrences[data[i]]++;
}
// Store probability list
for (i = 0; i < occurrences.length; i++) {
if (occurrences[i] > 0) {
prob.push(occurrences[i] / data.length);
}
}
// Calculate Shannon entropy
let entropy = 0,
p;
for (i = 0; i < prob.length; i++) {
p = prob[i];
entropy += p * Math.log(p) / Math.log(2);
}
return -entropy;
}
/**
* Parses CSV data and returns it as a two dimensional array or strings.
@@ -758,15 +796,15 @@ class Utils {
"%7E": "~",
"%21": "!",
"%24": "$",
//"%26": "&",
// "%26": "&",
"%27": "'",
"%28": "(",
"%29": ")",
"%2A": "*",
//"%2B": "+",
// "%2B": "+",
"%2C": ",",
"%3B": ";",
//"%3D": "=",
// "%3D": "=",
"%3A": ":",
"%40": "@",
"%2F": "/",
@@ -1144,6 +1182,7 @@ class Utils {
"CRLF": /\r\n/g,
"Forward slash": /\//g,
"Backslash": /\\/g,
"0x with comma": /,?0x/g,
"0x": /0x/g,
"\\x": /\\x/g,
"None": /\s+/g // Included here to remove whitespace when there shouldn't be any
@@ -1297,7 +1336,7 @@ export function sendStatusMessage(msg) {
self.sendStatusMessage(msg);
else if (isWebEnvironment())
app.alert(msg, 10000);
else if (isNodeEnvironment())
else if (isNodeEnvironment() && !global.TESTING)
// eslint-disable-next-line no-console
console.debug(msg);
}
@@ -1335,14 +1374,14 @@ export function debounce(func, wait, id, scope, args) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
if (!String.prototype.padStart) {
String.prototype.padStart = function padStart(targetLength, padString) {
targetLength = targetLength>>0; //floor if number or convert non-number to 0;
targetLength = targetLength>>0; // floor if number or convert non-number to 0;
padString = String((typeof padString !== "undefined" ? padString : " "));
if (this.length > targetLength) {
return String(this);
} else {
targetLength = targetLength-this.length;
if (targetLength > padString.length) {
padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
padString += padString.repeat(targetLength/padString.length); // append to original to ensure we are longer than needed
}
return padString.slice(0, targetLength) + String(this);
}
@@ -1354,14 +1393,14 @@ if (!String.prototype.padStart) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
if (!String.prototype.padEnd) {
String.prototype.padEnd = function padEnd(targetLength, padString) {
targetLength = targetLength>>0; //floor if number or convert non-number to 0;
targetLength = targetLength>>0; // floor if number or convert non-number to 0;
padString = String((typeof padString !== "undefined" ? padString : " "));
if (this.length > targetLength) {
return String(this);
} else {
targetLength = targetLength-this.length;
if (targetLength > padString.length) {
padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
padString += padString.repeat(targetLength/padString.length); // append to original to ensure we are longer than needed
}
return String(this) + padString.slice(0, targetLength);
}

View File

@@ -39,6 +39,7 @@
"URL Decode",
"Escape Unicode Characters",
"Unescape Unicode Characters",
"Normalise Unicode",
"To Quoted Printable",
"From Quoted Printable",
"To Punycode",
@@ -94,7 +95,11 @@
"Affine Cipher Decode",
"A1Z26 Cipher Encode",
"A1Z26 Cipher Decode",
"Rail Fence Cipher Encode",
"Rail Fence Cipher Decode",
"Atbash Cipher",
"CipherSaber2 Encrypt",
"CipherSaber2 Decrypt",
"Substitute",
"Derive PBKDF2 key",
"Derive EVP key",
@@ -110,7 +115,8 @@
"Bombe",
"Multiple Bombe",
"Typex",
"Lorenz"
"Lorenz",
"Colossus"
]
},
{
@@ -128,6 +134,11 @@
"PGP Verify",
"PGP Encrypt and Sign",
"PGP Decrypt and Verify",
"Generate RSA Key Pair",
"RSA Sign",
"RSA Verify",
"RSA Encrypt",
"RSA Decrypt",
"Parse SSH Host Key"
]
},
@@ -194,8 +205,10 @@
"ops": [
"Encode text",
"Decode text",
"Unicode Text Format",
"Remove Diacritics",
"Unescape Unicode Characters"
"Unescape Unicode Characters",
"Convert to NATO alphabet"
]
},
{
@@ -235,6 +248,7 @@
"Convert co-ordinate format",
"Show on map",
"Parse UNIX file permissions",
"Parse ObjectID timestamp",
"Swap endianness",
"Parse colour code",
"Escape string",
@@ -305,6 +319,7 @@
"SHA1",
"SHA2",
"SHA3",
"SM3",
"Keccak",
"Shake",
"RIPEMD",
@@ -329,6 +344,7 @@
"Fletcher-32 Checksum",
"Fletcher-64 Checksum",
"Adler-32 Checksum",
"Luhn Checksum",
"CRC-8 Checksum",
"CRC-16 Checksum",
"CRC-32 Checksum",
@@ -388,6 +404,7 @@
"ops": [
"Render Image",
"Play Media",
"Generate Image",
"Optical Character Recognition",
"Remove EXIF",
"Extract EXIF",

View File

@@ -9,7 +9,7 @@
* @license Apache-2.0
*/
/*eslint no-console: ["off"] */
/* eslint no-console: ["off"] */
import path from "path";
import fs from "fs";
@@ -42,13 +42,10 @@ for (const opObj in Ops) {
outputType: op.presentType,
flowControl: op.flowControl,
manualBake: op.manualBake,
args: op.args
args: op.args,
checks: op.checks
};
if ("patterns" in op) {
operationConfig[op.name].patterns = op.patterns;
}
if (!(op.module in modules))
modules[op.module] = {};
modules[op.module][op.name] = opObj;

View File

@@ -7,7 +7,7 @@
* @license Apache-2.0
*/
/*eslint no-console: ["off"] */
/* eslint no-console: ["off"] */
import path from "path";
import fs from "fs";

View File

@@ -6,7 +6,7 @@
* @license Apache-2.0
*/
/*eslint no-console: ["off"] */
/* eslint no-console: ["off"] */
import prompt from "prompt";
import colors from "colors";
@@ -208,7 +208,7 @@ ${result.highlight ? `
export default ${moduleName};
`;
//console.log(template);
// console.log(template);
const filename = path.join(dir, `./${moduleName}.mjs`);
if (fs.existsSync(filename)) {

View File

@@ -17,7 +17,7 @@ class DishJSON extends DishType {
*/
static toArrayBuffer() {
DishJSON.checkForValue(this.value);
this.value = this.value ? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4)) : new ArrayBuffer;
this.value = this.value !== undefined ? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4)) : new ArrayBuffer;
}
/**

View File

@@ -5,7 +5,7 @@
*/
import DishType from "./DishType.mjs";
import { isNodeEnvironment } from "../Utils.mjs";
import Utils, { isNodeEnvironment } from "../Utils.mjs";
/**
@@ -16,13 +16,14 @@ class DishListFile extends DishType {
/**
* convert the given value to a ArrayBuffer
*/
static toArrayBuffer() {
static async toArrayBuffer() {
DishListFile.checkForValue(this.value);
if (isNodeEnvironment()) {
this.value = this.value.map(file => Uint8Array.from(file.data));
} else {
this.value = await DishListFile.concatenateTypedArraysWithTypedElements(...this.value);
}
this.value = DishListFile.concatenateTypedArrays(...this.value).buffer;
}
/**
@@ -33,6 +34,27 @@ class DishListFile extends DishType {
this.value = [new File(this.value, "unknown")];
}
/**
* Concatenates a list of typed elements together.
*
* @param {Uint8Array[]} arrays
* @returns {Uint8Array}
*/
static async concatenateTypedArraysWithTypedElements(...arrays) {
let totalLength = 0;
for (const arr of arrays) {
totalLength += arr.size;
}
const myArray = new Uint8Array(totalLength);
let offset = 0;
for (const arr of arrays) {
const data = await Utils.readFile(arr);
myArray.set(data, offset);
offset += data.length;
}
return myArray;
}
/**
* Concatenates a list of Uint8Arrays together

View File

@@ -20,7 +20,7 @@ export const ALPHABET_OPTIONS = [
},
{
name: "IPv6",
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|~}",
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~",
}
];

View File

@@ -38,7 +38,7 @@
const crypto = {};
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
/* dojo-release-1.8.1/dojo/_base/lang.js.uncompressed.js */

View File

@@ -164,3 +164,15 @@ export const IO_FORMAT = {
"Simplified Chinese GB18030 (54936)": 54936,
};
/**
* Unicode Normalisation Forms
*
* @author Matthieu [m@tthieu.xyz]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
/**
* Character encoding format mappings.
*/
export const UNICODE_NORMALISATION_FORMS = ["NFD", "NFC", "NFKD", "NFKC"];

View File

@@ -0,0 +1,34 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
export function encode(tempIVP, key, rounds, input) {
const ivp = new Uint8Array(key.concat(tempIVP));
const state = new Array(256).fill(0);
let j = 0, i = 0;
const result = [];
// Mixing states based off of IV.
for (let i = 0; i < 256; i++)
state[i] = i;
const ivpLength = ivp.length;
for (let r = 0; r < rounds; r ++) {
for (let k = 0; k < 256; k++) {
j = (j + state[k] + ivp[k % ivpLength]) % 256;
[state[k], state[j]] = [state[j], state[k]];
}
}
j = 0;
i = 0;
// XOR cipher with key.
for (let x = 0; x < input.length; x++) {
i = (++i) % 256;
j = (j + state[i]) % 256;
[state[i], state[j]] = [state[j], state[i]];
const n = (state[i] + state[j]) % 256;
result.push(state[n] ^ input[x]);
}
return result;
}

417
src/core/lib/Colossus.mjs Normal file
View File

@@ -0,0 +1,417 @@
/**
* Colossus - an emulation of the world's first electronic computer
*
* @author VirtualColossus [martin@virtualcolossus.co.uk]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import {INIT_PATTERNS, ITA2_TABLE, ROTOR_SIZES} from "../lib/Lorenz.mjs";
/**
* Colossus simulator class.
*/
export class ColossusComputer {
/**
* Construct a Colossus.
*
* @param {string} ciphertext
* @param {string} pattern - named pattern of Chi, Mu and Psi wheels
* @param {Object} qbusin - which data inputs are being sent to q bus - each can be null, plain or delta
* @param {Object[]} qbusswitches - Q bus calculation switches, multiple rows
* @param {Object} control - control switches which specify stepping modes
* @param {Object} starts - rotor start positions
*/
constructor(ciphertext, pattern, qbusin, qbusswitches, control, starts, settotal, limit) {
this.ITAlookup = ITA2_TABLE;
this.ReverseITAlookup = {};
for (const letter in this.ITAlookup) {
const code = this.ITAlookup[letter];
this.ReverseITAlookup[code] = letter;
}
this.initThyratrons(pattern);
this.ciphertext = ciphertext;
this.qbusin = qbusin;
this.qbusswitches = qbusswitches;
this.control = control;
this.starts = starts;
this.settotal = settotal;
this.limitations = limit;
this.allCounters = [0, 0, 0, 0, 0];
this.Zbits = [0, 0, 0, 0, 0]; // Z input is the cipher tape
this.ZbitsOneBack = [0, 0, 0, 0, 0]; // for delta
this.Qbits = [0, 0, 0, 0, 0]; // input generated for placing onto the Q-bus (the logic processor)
this.Xbits = [0, 0, 0, 0, 0]; // X is the Chi wheel bits
this.Xptr = [0, 0, 0, 0, 0]; // pointers to the current X bits (Chi wheels)
this.XbitsOneBack = [0, 0, 0, 0, 0]; // the X bits one back (for delta)
this.Sbits = [0, 0, 0, 0, 0]; // S is the Psi wheel bits
this.Sptr = [0, 0, 0, 0, 0]; // pointers to the current S bits (Psi wheels)
this.SbitsOneBack = [0, 0, 0, 0, 0]; // the S bits one back (for delta)
this.Mptr = [0, 0];
this.rotorPtrs = {};
this.totalmotor = 0;
this.P5Zbit = [0, 0];
}
/**
* Begin a run
*
* @returns {object}
*/
run() {
const result = {
printout: ""
};
// loop until our start positions are back to the beginning
this.rotorPtrs = {X1: this.starts.X1, X2: this.starts.X2, X3: this.starts.X3, X4: this.starts.X4, X5: this.starts.X5, M61: this.starts.M61, M37: this.starts.M37, S1: this.starts.S1, S2: this.starts.S2, S3: this.starts.S3, S4: this.starts.S4, S5: this.starts.S5};
// this.rotorPtrs = this.starts;
let runcount = 1;
const fast = this.control.fast;
const slow = this.control.slow;
// Print Headers
result.printout += fast + " " + slow + "\n";
do {
this.allCounters = [0, 0, 0, 0, 0];
this.ZbitsOneBack = [0, 0, 0, 0, 0];
this.XbitsOneBack = [0, 0, 0, 0, 0];
// Run full tape loop and process counters
this.runTape();
// Only print result if larger than set total
let fastRef = "00";
let slowRef = "00";
if (fast !== "") fastRef = this.rotorPtrs[fast].toString().padStart(2, "0");
if (slow !== "") slowRef = this.rotorPtrs[slow].toString().padStart(2, "0");
let printline = "";
for (let c=0;c<5;c++) {
if (this.allCounters[c] > this.settotal) {
printline += String.fromCharCode(c+97) + this.allCounters[c]+" ";
}
}
if (printline !== "") {
result.printout += fastRef + " " + slowRef + " : ";
result.printout += printline;
result.printout += "\n";
}
// Step fast rotor if required
if (fast !== "") {
this.rotorPtrs[fast]++;
if (this.rotorPtrs[fast] > ROTOR_SIZES[fast]) this.rotorPtrs[fast] = 1;
}
// Step slow rotor if fast rotor has returned to initial start position
if (slow !== "" && this.rotorPtrs[fast] === this.starts[fast]) {
this.rotorPtrs[slow]++;
if (this.rotorPtrs[slow] > ROTOR_SIZES[slow]) this.rotorPtrs[slow] = 1;
}
runcount++;
} while (JSON.stringify(this.rotorPtrs) !== JSON.stringify(this.starts));
result.counters = this.allCounters;
result.runcount = runcount;
return result;
}
/**
* Run tape loop
*/
runTape() {
let charZin = "";
this.Xptr = [this.rotorPtrs.X1, this.rotorPtrs.X2, this.rotorPtrs.X3, this.rotorPtrs.X4, this.rotorPtrs.X5];
this.Mptr = [this.rotorPtrs.M37, this.rotorPtrs.M61];
this.Sptr = [this.rotorPtrs.S1, this.rotorPtrs.S2, this.rotorPtrs.S3, this.rotorPtrs.S4, this.rotorPtrs.S5];
// Run full loop of all character on the input tape (Z)
for (let i=0; i<this.ciphertext.length; i++) {
charZin = this.ciphertext.charAt(i);
// Firstly, we check what inputs are specified on the Q-bus input switches
this.getQbusInputs(charZin);
/*
* Pattern conditions on individual impulses. Matching patterns of bits on the Q bus.
* This is the top section on Colussus K rack - the Q bus programming switches
*/
const tmpcnt = this.runQbusProcessingConditional();
/*
* Addition of impulses.
* This is the bottom section of Colossus K rack.
*/
this.runQbusProcessingAddition(tmpcnt);
// Store Z bit impulse 5 two back required for P5 limitation
this.P5Zbit[1] = this.P5Zbit[0];
this.P5Zbit[0] = this.ITAlookup[charZin].split("")[4];
// Step rotors
this.stepThyratrons();
}
}
/**
* Step thyratron rings to simulate movement of Lorenz rotors
* Chi rotors all step one per character
* Motor M61 rotor steps one per character, M37 steps dependant on M61 setting
* Psi rotors only step dependant on M37 setting + limitation
*/
stepThyratrons() {
let X2bPtr = this.Xptr[1]-1;
if (X2bPtr===0) X2bPtr = ROTOR_SIZES.X2;
let S1bPtr = this.Sptr[0]-1;
if (S1bPtr===0) S1bPtr = ROTOR_SIZES.S1;
// Get Chi rotor 5 two back to calculate plaintext (Z+Chi+Psi=Plain)
let X5bPtr=this.Xptr[4]-1;
if (X5bPtr===0) X5bPtr=ROTOR_SIZES.X5;
X5bPtr=X5bPtr-1;
if (X5bPtr===0) X5bPtr=ROTOR_SIZES.X5;
// Get Psi rotor 5 two back to calculate plaintext (Z+Chi+Psi=Plain)
let S5bPtr=this.Sptr[4]-1;
if (S5bPtr===0) S5bPtr=ROTOR_SIZES.S5;
S5bPtr=S5bPtr-1;
if (S5bPtr===0) S5bPtr=ROTOR_SIZES.S5;
const x2sw = this.limitations.X2;
const s1sw = this.limitations.S1;
const p5sw = this.limitations.P5;
// Limitation calculations
let lim=1;
if (x2sw) lim = this.rings.X[2][X2bPtr-1];
if (s1sw) lim = lim ^ this.rings.S[1][S1bPtr-1];
// P5
if (p5sw) {
let p5lim = this.P5Zbit[1];
p5lim = p5lim ^ this.rings.X[5][X5bPtr-1];
p5lim = p5lim ^ this.rings.S[5][S5bPtr-1];
lim = lim ^ p5lim;
}
const basicmotor = this.rings.M[2][this.Mptr[0]-1];
this.totalmotor = basicmotor;
if (x2sw || s1sw) {
if (basicmotor===0 && lim===1) {
this.totalmotor = 0;
} else {
this.totalmotor = 1;
}
}
// Step Chi rotors
for (let r=0; r<5; r++) {
this.Xptr[r]++;
if (this.Xptr[r] > ROTOR_SIZES["X"+(r+1)]) this.Xptr[r] = 1;
}
if (this.totalmotor) {
// Step Psi rotors
for (let r=0; r<5; r++) {
this.Sptr[r]++;
if (this.Sptr[r] > ROTOR_SIZES["S"+(r+1)]) this.Sptr[r] = 1;
}
}
// Move M37 rotor if M61 set
if (this.rings.M[1][this.Mptr[1]-1]===1) this.Mptr[0]++;
if (this.Mptr[0] > ROTOR_SIZES.M37) this.Mptr[0]=1;
// Always move M61 rotor
this.Mptr[1]++;
if (this.Mptr[1] > ROTOR_SIZES.M61) this.Mptr[1]=1;
}
/**
* Get Q bus inputs
*/
getQbusInputs(charZin) {
// Zbits - the bits from the current character from the cipher tape.
this.Zbits = this.ITAlookup[charZin].split("");
if (this.qbusin.Z === "Z") {
// direct Z
this.Qbits = this.Zbits;
} else if (this.qbusin.Z === "ΔZ") {
// delta Z, the Bitwise XOR of this character Zbits + last character Zbits
for (let b=0;b<5;b++) {
this.Qbits[b] = this.Zbits[b] ^ this.ZbitsOneBack[b];
}
}
this.ZbitsOneBack = this.Zbits.slice(); // copy value of object, not reference
// Xbits - the current Chi wheel bits
for (let b=0;b<5;b++) {
this.Xbits[b] = this.rings.X[b+1][this.Xptr[b]-1];
}
if (this.qbusin.Chi !== "") {
if (this.qbusin.Chi === "Χ") {
// direct X added to Qbits
for (let b=0;b<5;b++) {
this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
}
} else if (this.qbusin.Chi === "ΔΧ") {
// delta X
for (let b=0;b<5;b++) {
this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
this.Qbits[b] = this.Qbits[b] ^ this.XbitsOneBack[b];
}
}
}
this.XbitsOneBack = this.Xbits.slice();
// Sbits - the current Psi wheel bits
for (let b=0;b<5;b++) {
this.Sbits[b] = this.rings.S[b+1][this.Sptr[b]-1];
}
if (this.qbusin.Psi !== "") {
if (this.qbusin.Psi === "Ψ") {
// direct S added to Qbits
for (let b=0;b<5;b++) {
this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
}
} else if (this.qbusin.Psi === "ΔΨ") {
// delta S
for (let b=0;b<5;b++) {
this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
this.Qbits[b] = this.Qbits[b] ^ this.SbitsOneBack[b];
}
}
}
this.SbitsOneBack = this.Sbits.slice();
}
/**
* Conditional impulse Q bus section
*/
runQbusProcessingConditional() {
const cnt = [-1, -1, -1, -1, -1];
const numrows = this.qbusswitches.condition.length;
for (let r=0;r<numrows;r++) {
const row = this.qbusswitches.condition[r];
if (row.Counter !== "") {
let result = true;
const cPnt = row.Counter-1;
const Qswitch = this.readBusSwitches(row.Qswitches);
// Match switches to bit pattern
for (let s=0;s<5;s++) {
if (Qswitch[s] >= 0 && Qswitch[s] !== parseInt(this.Qbits[s], 10)) result = false;
}
// Check for NOT switch
if (row.Negate) result = !result;
// AND each row to get final result
if (cnt[cPnt] === -1) {
cnt[cPnt] = result;
} else if (!result) {
cnt[cPnt] = false;
}
}
}
// Negate the whole column, this allows A OR B by doing NOT(NOT A AND NOT B)
for (let c=0;c<5;c++) {
if (this.qbusswitches.condNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
}
return cnt;
}
/**
* Addition of impulses Q bus section
*/
runQbusProcessingAddition(cnt) {
const row = this.qbusswitches.addition[0];
const Qswitch = row.Qswitches.slice();
// To save making the arguments of this operation any larger, limiting addition counter to first one only
// Colossus could actually add into any of the five counters.
if (row.C1) {
let addition = 0;
for (let s=0;s<5;s++) {
// XOR addition
if (Qswitch[s]) {
addition = addition ^ this.Qbits[s];
}
}
const equals = (row.Equals===""?-1:(row.Equals==="."?0:1));
if (addition === equals) {
// AND with conditional rows to get final result
if (cnt[0] === -1) cnt[0] = true;
} else {
cnt[0] = false;
}
}
// Final check, check for addition section negate
// then, if any column set, from top to bottom of rack, add to counter.
for (let c=0;c<5;c++) {
if (this.qbusswitches.addNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor === 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor === 1)) {
if (cnt[c] === true) this.allCounters[c]++;
}
}
}
/**
* Initialise thyratron rings
* These hold the pattern of 1s & 0s for each rotor on banks of thyraton GT1C valves which act as a one-bit store.
*/
initThyratrons(pattern) {
this.rings = {
X: {
1: INIT_PATTERNS[pattern].X[1].slice().reverse(),
2: INIT_PATTERNS[pattern].X[2].slice().reverse(),
3: INIT_PATTERNS[pattern].X[3].slice().reverse(),
4: INIT_PATTERNS[pattern].X[4].slice().reverse(),
5: INIT_PATTERNS[pattern].X[5].slice().reverse()
},
M: {
1: INIT_PATTERNS[pattern].M[1].slice().reverse(),
2: INIT_PATTERNS[pattern].M[2].slice().reverse(),
},
S: {
1: INIT_PATTERNS[pattern].S[1].slice().reverse(),
2: INIT_PATTERNS[pattern].S[2].slice().reverse(),
3: INIT_PATTERNS[pattern].S[3].slice().reverse(),
4: INIT_PATTERNS[pattern].S[4].slice().reverse(),
5: INIT_PATTERNS[pattern].S[5].slice().reverse()
}
};
}
/**
* Read argument bus switches X & . and convert to 1 & 0
*/
readBusSwitches(row) {
const output = [-1, -1, -1, -1, -1];
for (let c=0;c<5;c++) {
if (row[c]===".") output[c] = 0;
if (row[c]==="x") output[c] = 1;
}
return output;
}
}

View File

@@ -280,7 +280,7 @@ export const FILE_SIGNATURES = {
9: 0x0,
10: [0x0, 0x1]
},
extractor: null
extractor: extractICO
},
{
name: "Radiance High Dynamic Range image",
@@ -468,6 +468,34 @@ export const FILE_SIGNATURES = {
],
extractor: null
},
{
name: "Targa Image",
extension: "tga",
mime: "image/x-targa",
description: "",
signature: [
{ // This signature is not at the beginning of the file. The extractor works backwards.
0: 0x54,
1: 0x52,
2: 0x55,
3: 0x45,
4: 0x56,
5: 0x49,
6: 0x53,
7: 0x49,
8: 0x4f,
9: 0x4e,
10: 0x2d,
11: 0x58,
12: 0x46,
13: 0x49,
14: 0x4c,
15: 0x45,
16: 0x2e
}
],
extractor: extractTARGA
}
],
"Video": [
{ // Place before webm
@@ -780,7 +808,7 @@ export const FILE_SIGNATURES = {
1: 0xfb
}
],
extractor: null
extractor: extractMP3
},
{
name: "MPEG-4 Part 14 audio",
@@ -1008,8 +1036,7 @@ export const FILE_SIGNATURES = {
0: 0x7b,
1: 0x5c,
2: 0x72,
3: 0x74,
4: 0x66
3: 0x74
},
extractor: extractRTF
},
@@ -1282,17 +1309,30 @@ export const FILE_SIGNATURES = {
extension: "dylib",
mime: "application/octet-stream",
description: "",
signature: {
0: 0xca,
1: 0xfe,
2: 0xba,
3: 0xbe,
4: 0x00,
5: 0x00,
6: 0x00,
7: [0x01, 0x02, 0x03]
},
extractor: null
signature: [
{
0: 0xca,
1: 0xfe,
2: 0xba,
3: 0xbe,
4: 0x00,
5: 0x00,
6: 0x00,
7: [0x01, 0x02, 0x03]
},
{
0: 0xce,
1: 0xfa,
2: 0xed,
3: 0xfe,
4: 0x07,
5: 0x00,
6: 0x00,
7: 0x00,
8: [0x01, 0x02, 0x03]
}
],
extractor: extractMACHO
},
{
name: "MacOS Mach-O 64-bit object",
@@ -1305,7 +1345,7 @@ export const FILE_SIGNATURES = {
2: 0xed,
3: 0xfe
},
extractor: null
extractor: extractMACHO
},
{
name: "Adobe Flash",
@@ -1404,7 +1444,7 @@ export const FILE_SIGNATURES = {
260: 0x61,
261: 0x72
},
extractor: null
extractor: extractTAR
},
{
name: "Roshal Archive",
@@ -1712,6 +1752,25 @@ export const FILE_SIGNATURES = {
},
extractor: null
},
{
name: "Jar Archive",
extension: "jar",
mime: "application/java-archive",
description: "",
signature: {
0: 0x50,
1: 0x4B,
2: 0x03,
3: 0x04,
4: 0x14,
5: 0x00,
6: 0x08,
7: 0x00,
8: 0x08,
9: 0x00
},
extractor: extractZIP
},
{
name: "lzop compressed",
extension: "lzop,lzo",
@@ -1727,8 +1786,40 @@ export const FILE_SIGNATURES = {
6: 0x0a,
7: 0x1a
},
extractor: null
extractor: extractLZOP
},
{
name: "Linux deb package",
extension: "deb",
mime: "application/vnd.debian.binary-package",
description: "",
signature: {
0: 0x21,
1: 0x3C,
2: 0x61,
3: 0x72,
4: 0x63,
5: 0x68,
6: 0x3e
},
extractor: extractDEB
},
{
name: "Apple Disk Image",
extension: "dmg",
mime: "application/x-apple-diskimage",
description: "",
signature: {
0: 0x78,
1: 0x01,
2: 0x73,
3: 0x0d,
4: 0x62,
5: 0x62,
6: 0x60
},
extractor: null
}
],
"Miscellaneous": [
{
@@ -2026,7 +2117,7 @@ export const FILE_SIGNATURES = {
6: [0x4d, 0x36],
7: [0x50, 0x34]
},
extractor: null
extractor: extractDMP
},
{
name: "Windows Prefetch",
@@ -2043,7 +2134,7 @@ export const FILE_SIGNATURES = {
6: 0x43,
7: 0x41
},
extractor: null
extractor: extractPF
},
{
name: "Windows Prefetch (Win 10)",
@@ -2057,7 +2148,7 @@ export const FILE_SIGNATURES = {
3: 0x04,
7: 0x0
},
extractor: null
extractor: extractPFWin10
},
{
name: "PList (XML)",
@@ -2330,7 +2421,7 @@ export const FILE_SIGNATURES = {
18: 0x00,
19: 0x46
},
extractor: null
extractor: extractLNK
},
{
name: "Bash",
@@ -2458,6 +2549,44 @@ export const FILE_SIGNATURES = {
4: 0x70,
},
extractor: null
},
{
name: "Smile",
extension: "sml",
mime: " application/x-jackson-smile",
description: "",
signature: {
0: 0x3a,
1: 0x29,
2: 0xa
},
extractor: null
},
{
name: "Lua Bytecode",
extension: "luac",
mime: "application/x-lua",
description: "",
signature: {
0: 0x1b,
1: 0x4c,
2: 0x75,
3: 0x61
},
extractor: null
},
{
name: "WebAssembly binary",
extension: "wasm",
mime: "application/octet-stream",
description: "",
signature: {
0: 0x00,
1: 0x61,
2: 0x73,
3: 0x6d
},
extractor: null
}
]
};
@@ -2720,6 +2849,154 @@ export function extractZIP(bytes, offset) {
}
/**
* MACHO extractor
*
* @param {Uint8Array} bytes
* @param {number} offset
* @returns {Uint8Array}
*/
export function extractMACHO(bytes, offset) {
// Magic bytes.
const MHCIGAM64 = "207250237254";
const MHMAGIC64 = "254237250207";
const MHCIGAM = "206250237254";
/**
* Checks to see if the file is 64-bit.
*
* @param {string} magic
* @returns {bool}
*/
function isMagic64(magic) {
return magic === MHCIGAM64 || magic === MHMAGIC64;
}
/**
* Checks the endianness of the file.
*
* @param {string} magic
* @returns {bool}
*/
function shouldSwapBytes(magic) {
return magic === MHCIGAM || magic === MHCIGAM64;
}
/**
* Jumps through segment information and calculates the sum of the segement sizes.
*
* @param {Stream} stream
* @param {number} offset
* @param {string} isSwap
* @param {number} ncmds
* @returns {number}
*/
function dumpSegmentCommands(stream, offset, isSwap, ncmds) {
let total = 0;
const LCSEGEMENT64 = 0x19;
const LCSEGEMENT = 0x1;
for (let i = 0; i < ncmds; i++) {
// Move to start of segment.
stream.moveTo(offset);
const cmd = stream.readInt(4, isSwap);
if (cmd === LCSEGEMENT64) {
// Move to size of segment field.
stream.moveTo(offset + 48);
// Extract size of segement.
total += stream.readInt(8, isSwap);
stream.moveTo(offset + 4);
// Move to offset of next segment.
offset += stream.readInt(4, isSwap);
} else if (cmd === LCSEGEMENT) {
stream.moveTo(offset + 36);
// Extract size of segement.
total += stream.readInt(4, isSwap);
stream.moveTo(offset + 4);
offset += stream.readInt(4, isSwap);
}
}
return total;
}
/**
* Reads the number of command segments.
*
* @param {Stream} stream
* @param {bool} is64
* @param {string} isSwap
* @returns {number}
*/
function dumpMachHeader(stream, is64, isSwap) {
let loadCommandsOffset = 28;
if (is64)
loadCommandsOffset += 4;
// Move to number of commands field.
stream.moveTo(16);
const ncmds = stream.readInt(4, isSwap);
return dumpSegmentCommands(stream, loadCommandsOffset, isSwap, ncmds);
}
const stream = new Stream(bytes.slice(offset));
const magic = stream.getBytes(4).join("");
// Move to the end of the final segment.
stream.moveTo(dumpMachHeader(stream, isMagic64(magic), shouldSwapBytes(magic) ? "le" : "be"));
return stream.carve();
}
/**
* TAR extractor.
*
* @param {Uint8Array} bytes
* @param {number} offset
* @returns {Uint8Array}
*/
export function extractTAR(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
while (stream.hasMore()) {
// Move to ustar identifier.
stream.moveForwardsBy(0x101);
if (stream.getBytes(5).join("") !== [0x75, 0x73, 0x74, 0x61, 0x72].join("")) {
// Reverse back to the end of the last section.
stream.moveBackwardsBy(0x106);
break;
}
// Move back to file size field.
stream.moveBackwardsBy(0x8a);
let fsize = 0;
// Read file size field.
stream.getBytes(11).forEach((element, index) => {
fsize += (element - 48).toString();
});
// Round number up from octet to nearest 512.
fsize = (Math.ceil(parseInt(fsize, 8) / 512) * 512);
// Move forwards to the end of that file.
stream.moveForwardsBy(fsize + 0x179);
}
stream.consumeWhile(0x00);
return stream.carve();
}
/**
* PNG extractor.
*
@@ -2772,6 +3049,116 @@ export function extractBMP(bytes, offset) {
}
/**
* ICO extractor.
*
* @param {Uint8Array} bytes
* @param {number} offset
*/
export function extractICO(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to number of files there are.
stream.moveTo(4);
// Read the number of files stored in the ICO
const numberFiles = stream.readInt(2, "le");
// Move forward to the last file header.
stream.moveForwardsBy(8 + ((numberFiles-1) * 16));
const fileSize = stream.readInt(4, "le");
const fileOffset = stream.readInt(4, "le");
// Move to the end of the last file.
stream.moveTo(fileOffset + fileSize);
return stream.carve();
}
/**
* TARGA extractor.
*
* @param {Uint8Array} bytes
* @param {number} offset
*/
export function extractTARGA(bytes, offset) {
// Need all the bytes since we do not know how far up the image goes.
const stream = new Stream(bytes);
stream.moveTo(offset - 8);
// Read in the offsets of the possible areas.
const extensionOffset = stream.readInt(4, "le");
const developerOffset = stream.readInt(4, "le");
stream.moveBackwardsBy(8);
/**
* Moves backwards in the stream until it meet bytes that are the same as the amount of bytes moved.
*
* @param {number} sizeOfSize
* @param {number} maxSize
*/
function moveBackwardsUntilSize(maxSize, sizeOfSize) {
for (let i = 0; i < maxSize; i++) {
stream.moveBackwardsBy(1);
// Read in sizeOfSize amount of bytes in.
const size = stream.readInt(sizeOfSize, "le") - 1;
stream.moveBackwardsBy(sizeOfSize);
// If the size matches.
if (size === i)
break;
}
}
/**
* Moves backwards in the stream until we meet bytes(when calculated) that are the same as the amount of bytes moved.
*/
function moveBackwardsUntilImageSize() {
stream.moveBackwardsBy(5);
// The documentation said that 0x100000 was the largest the file could be.
for (let i = 0; i < 0x100000; i++) {
// (Height * Width * pixel depth in bits)/8
const total = (stream.readInt(2, "le") * stream.readInt(2, "le") * stream.readInt(1))/8;
if (total === i-1)
break;
stream.moveBackwardsBy(6);
}
}
if (extensionOffset || developerOffset) {
if (extensionOffset) {
// Size is stored in two bytes hence the maximum is 0xffff.
moveBackwardsUntilSize(0xffff, 2);
// Move to where we think the start of the file is.
stream.moveBackwardsBy(extensionOffset);
} else if (developerOffset) {
// Size is stored in 4 bytes hence the maxiumum is 0xffffffff.
moveBackwardsUntilSize(0xffffffff, 4);
// Size is stored in byte position 6 so have to move back.
stream.moveBackwardsBy(6);
// Move to where we think the start of the file is.
stream.moveBackwardsBy(developerOffset);
}
} else {
// Move backwards until size === number of bytes passed.
moveBackwardsUntilImageSize();
// Move backwards over the reaminder of the header + the 5 we borrowed in moveBackwardsUntilImageSize().
stream.moveBackwardsBy(0xc+5);
}
return stream.carve(stream.position, offset+0x12);
}
/**
* WAV extractor.
*
@@ -2786,12 +3173,85 @@ export function extractWAV(bytes, offset) {
stream.moveTo(4);
// Move to file size.
stream.moveTo(stream.readInt(4, "le") - 4);
stream.moveTo(stream.readInt(4, "le") + 8);
return stream.carve();
}
/**
* MP3 extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
* @returns {Uint8Array}
*/
export function extractMP3(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Constants for flag byte.
const bitRateIndexes = ["free", 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, "bad"];
const samplingRateFrequencyIndex = [44100, 48000, 32000, "reserved"];
// ID3 tag, move over it.
if ((stream.getBytes(3).toString() === [0x49, 0x44, 0x33].toString())) {
stream.moveTo(6);
const tagSize = (stream.readInt(1) << 21) | (stream.readInt(1) << 14) | (stream.readInt(1) << 7) | stream.readInt(1);
stream.moveForwardsBy(tagSize);
} else {
stream.moveTo(0);
}
// Loop over all the frame headers in the file.
while (stream.hasMore()) {
// If it has an old TAG frame at the end of it, fixed size, 128 bytes.
if (stream.getBytes(3) === [0x54, 0x41, 0x47].toString()) {
stream.moveForwardsBy(125);
break;
}
// If not start of frame.
if (stream.getBytes(2).toString() !== [0xff, 0xfb].toString()) {
stream.moveBackwardsBy(2);
break;
}
// Read flag byte.
const flags = stream.readInt(1);
// Extract frame bit rate from flag byte.
const bitRate = bitRateIndexes[flags >> 4];
// Extract frame sample rate from flag byte.
const sampleRate = samplingRateFrequencyIndex[(flags & 0x0f) >> 2];
// Padding if the frame size is not a multiple of the bitrate.
const padding = (flags & 0x02) >> 1;
// Things that are either not standard or undocumented.
if (bitRate === "free" || bitRate === "bad" || sampleRate === "reserved") {
stream.moveBackwardsBy(1);
break;
}
// Formula: FrameLength = (144 * BitRate / SampleRate ) + Padding
const frameSize = Math.floor(((144 * bitRate) / sampleRate) + padding);
// If the next move goes past the end of the bytestream then extract the entire bytestream.
// We assume complete frames in the above formula because there is no field that suggests otherwise.
if ((stream.position + frameSize) > stream.length) {
stream.moveTo(stream.length);
break;
} else {
stream.moveForwardsBy(frameSize - 3);
}
}
return stream.carve();
}
/**
* FLV extractor.
*
@@ -2914,15 +3374,127 @@ export function extractSQLITE(bytes, offset) {
export function extractPListXML(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Find closing tag (</plist>)
stream.continueUntil([0x3c, 0x2f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e]);
stream.moveForwardsBy(8);
let braceCount = 0;
// Continue to the first (<plist).
stream.continueUntil([0x3c, 0x70, 0x6c, 0x69, 0x73, 0x74]);
stream.moveForwardsBy(6);
braceCount++;
// While we have an unequal amount of braces.
while (braceCount > 0 && stream.hasMore()) {
if (stream.readInt(1) === 0x3c) {
// If we hit an <plist.
if (stream.getBytes(5).join("") === [0x70, 0x6c, 0x69, 0x73, 0x74].join("")) {
braceCount++;
} else {
stream.moveBackwardsBy(5);
}
// If we hit an </plist>.
if (stream.getBytes(7).join("") === [0x2f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e].join("")) {
braceCount--;
} else {
stream.moveBackwardsBy(7);
}
}
}
stream.consumeIf(0x0a);
return stream.carve();
}
/**
* OLE2 extractor.
*
* @param {Uint8Array} bytes
* @param {number} offset
* @returns {Uint8Array}
*/
export function extractOLE2(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
const entries = [
[[0x52, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x20, 0x00, 0x45, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x72, 0x00, 0x79], 19, "Root Entry"],
[[0x57, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6b], 15, "Workbook"],
[[0x43, 0x00, 0x75, 0x00, 0x72, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x55, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72], 23, "Current User"],
[[0x50, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x65, 0x00, 0x72, 0x00, 0x50, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74], 37, "PowerPoint Document"],
[[0x57, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x64, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74], 23, "WordDocument"],
[[0x44, 0x00, 0x61, 0x00, 0x74, 0x00, 0x61], 7, "Data"],
[[0x50, 0x00, 0x69, 0x00, 0x63, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73], 15, "Pictures"],
[[0x31, 0x00, 0x54, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65], 11, "1Table"],
[[0x05, 0x00, 0x53, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x72, 0x00, 0x79, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e], 37, "SummaryInformation"],
[[0x05, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x53, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x72, 0x00, 0x79, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e], 53, "DocumentSummaryInformation"],
[[0x43, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x4f, 0x00, 0x62, 0x00, 0x6a], 13, "Comp Obj"],
[[0x01, 0x00], 2, "Entry"]
];
let endianness = "le";
// Move to endianess field.
stream.moveForwardsBy(28);
if (stream.readInt(2, endianness) === 0xfffe)
endianness = "be";
// Calculate the size of the normal sectors.
const sizeOfSector = 2 ** stream.readInt(2, endianness);
// Move to root directory offset field.
stream.moveTo(48);
// Read root directory offset.
const rootStuff = stream.readInt(4, endianness);
// Calculate root directory offset.
let total = 512 + (rootStuff * sizeOfSector);
stream.moveTo(total);
// While valid directory entries.
let found = true;
while (found) {
found = false;
// Attempt to determine what directory entry it is.
for (const element of entries) {
// If the byte pattern matches.
if (stream.getBytes(element[1]).join("") === element[0].join("")) {
stream.moveBackwardsBy(element[1]);
found = true;
// Move forwards by the size of the comp obj.
if (element[2] === "Comp Obj") {
// The size of the Comp Obj entry - 128. Since we add 128 later.
total += 128 * 6;
stream.moveTo(total);
} else if (element[2] === "Entry") {
// If there is an entry move backwards by 126 to then move forwards by 128. Hence a total displacement of 2.
stream.moveBackwardsBy(126);
}
break;
}
stream.moveBackwardsBy(element[1]);
}
// If we have found a valid entry, move forwards by 128.
if (found) {
// Every entry is at least 128 in size, some are bigger which is dealt with by the above if statement.
total += 128;
stream.moveForwardsBy(128);
}
}
// Round up to a multiple of 512.
total = Math.ceil(total / 512) * 512;
stream.moveTo(total);
return stream.carve();
}
/**
* GZIP extractor.
*
@@ -3080,6 +3652,37 @@ export function extractXZ(bytes, offset) {
}
/**
* DEB extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
*/
export function extractDEB(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move past !<arch>
stream.moveForwardsBy(8);
while (stream.hasMore()) {
// Move to size field.
stream.moveForwardsBy(48);
let fsize= "";
// Convert size to a usable number.
for (const elem of stream.getBytes(10)) {
fsize += String.fromCharCode(elem);
}
fsize = parseInt(fsize.trim(), 10);
// Move past `\n
stream.moveForwardsBy(2);
stream.moveForwardsBy(fsize);
}
return stream.carve();
}
/**
* ELF extractor.
*
@@ -3381,3 +3984,158 @@ export function extractEVT(bytes, offset) {
stream.moveForwardsBy(eofSize-4);
return stream.carve();
}
/**
* DMP extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
* @returns {Uint8Array}
*/
export function extractDMP(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to fileSize field.
stream.moveTo(0x70);
// Multiply number of pages by page size. Plus 1 since the header is a page.
stream.moveTo((stream.readInt(4, "le") + 1) * 0x1000);
return stream.carve();
}
/**
* PF extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
* @returns {Uint8Array}
*/
export function extractPF(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to file size.
stream.moveTo(12);
stream.moveTo(stream.readInt(4, "be"));
return stream.carve();
}
/**
* PF (Win 10) extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
* @returns {Uint8Array}
*/
export function extractPFWin10(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Read in file size.
stream.moveTo(stream.readInt(4, "be"));
return stream.carve();
}
/**
* LNK extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
* @returns {Uint8Array}
*/
export function extractLNK(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to file size field.
stream.moveTo(0x34);
stream.moveTo(stream.readInt(4, "le"));
return stream.carve();
}
/**
* LZOP extractor.
*
* @param {Uint8Array} bytes
* @param {Number} offset
* @returns {Uint8Array}
*/
export function extractLZOP(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Flag bits.
const F_ADLER32_D = 0x00000001;
const F_ADLER32_C = 0x00000002;
const F_CRC32_D = 0x00000100;
const F_CRC32_C = 0x00000200;
const F_H_FILTER = 0x00000800;
const F_H_EXTRA_FIELD = 0x00000040;
let numCheckSumC = 0, numCheckSumD = 0;
// Move over magic bytes.
stream.moveForwardsBy(9);
const version = stream.readInt(2, "be");
// Move to flag register offset.
stream.moveForwardsBy(6);
const flags = stream.readInt(4, "be");
if (version & F_H_FILTER)
stream.moveForwardsBy(4);
if (flags & F_ADLER32_C)
numCheckSumC++;
if (flags & F_CRC32_C)
numCheckSumC++;
if (flags & F_ADLER32_D)
numCheckSumD++;
if (flags & F_CRC32_D)
numCheckSumD++;
// Move over the mode, mtime_low
stream.moveForwardsBy(8);
if (version >= 0x0940)
stream.moveForwardsBy(4);
const fnameSize = stream.readInt(1, "be");
// Move forwards by size of file name and the following 4 byte checksum.
stream.moveForwardsBy(fnameSize);
if (flags & F_H_EXTRA_FIELD) {
const extraSize = stream.readInt(4, "be");
stream.moveForwardsBy(extraSize);
}
// Move past checksum.
stream.moveForwardsBy(4);
while (stream.hasMore()) {
const uncompSize = stream.readInt(4, "be");
// If data has no length, break.
if (uncompSize === 0)
break;
const compSize = stream.readInt(4, "be");
const numCheckSumSkip = (uncompSize === compSize) ? numCheckSumD : numCheckSumD + numCheckSumC;
// skip forwards by compressed data size and the size of the checksum(s).
stream.moveForwardsBy(compSize + (numCheckSumSkip * 4));
}
return stream.carve();
}

View File

@@ -23,25 +23,39 @@ import Utils from "../Utils.mjs";
*
* // returns "0a:14:1e"
* toHex([10,20,30], ":");
*
* // returns "0x0a,0x14,0x1e"
* toHex([10,20,30], "0x", 2, ",")
*/
export function toHex(data, delim=" ", padding=2) {
export function toHex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
if (!data) return "";
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
let output = "";
const prepend = (delim === "0x" || delim === "\\x");
for (let i = 0; i < data.length; i++) {
output += data[i].toString(16).padStart(padding, "0") + delim;
const hex = data[i].toString(16).padStart(padding, "0");
output += prepend ? delim + hex : hex + delim;
if (extraDelim) {
output += extraDelim;
}
// Add LF after each lineSize amount of bytes but not at the end
if ((i !== data.length - 1) && ((i + 1) % lineSize === 0)) {
output += "\n";
}
}
// Add \x or 0x to beginning
if (delim === "0x") output = "0x" + output;
if (delim === "\\x") output = "\\x" + output;
if (delim.length)
return output.slice(0, -delim.length);
else
// Remove the extraDelim at the end (if there is one)
// and remove the delim at the end, but if it's prepended there's nothing to remove
const rTruncLen = extraDelim.length + (prepend ? 0 : delim.length);
if (rTruncLen) {
// If rTruncLen === 0 then output.slice(0,0) will be returned, which is nothing
return output.slice(0, -rTruncLen);
} else {
return output;
}
}
@@ -87,7 +101,7 @@ export function toHexFast(data) {
*/
export function fromHex(data, delim="Auto", byteLen=2) {
if (delim !== "None") {
const delimRegex = delim === "Auto" ? /[^a-f\d]/gi : Utils.regexRep(delim);
const delimRegex = delim === "Auto" ? /[^a-f\d]|(0x)/gi : Utils.regexRep(delim);
data = data.replace(delimRegex, "");
}
@@ -102,7 +116,7 @@ export function fromHex(data, delim="Auto", byteLen=2) {
/**
* To Hexadecimal delimiters.
*/
export const TO_HEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"];
export const TO_HEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "0x with comma", "\\x", "None"];
/**

View File

@@ -26,7 +26,7 @@ export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allo
let output = "";
if (cidrRange < 0 || cidrRange > 31) {
return "IPv4 CIDR must be less than 32";
throw new OperationError("IPv4 CIDR must be less than 32");
}
const mask = ~(0xFFFFFFFF >>> cidrRange),
@@ -64,7 +64,7 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
cidrRange = parseInt(cidr[cidr.length-1], 10);
if (cidrRange < 0 || cidrRange > 127) {
return "IPv6 CIDR must be less than 128";
throw new OperationError("IPv6 CIDR must be less than 128");
}
const ip1 = new Array(8),
@@ -211,7 +211,7 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
if (cidrRange < 0 || cidrRange > 31) {
return "IPv4 CIDR must be less than 32";
throw new OperationError("IPv4 CIDR must be less than 32");
}
const mask = ~(0xFFFFFFFF >>> cidrRange),
cidrIp1 = network & mask,
@@ -254,7 +254,7 @@ export function ipv6ListedRange(match, includeNetworkInfo) {
const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
if (cidrRange < 0 || cidrRange > 127) {
return "IPv6 CIDR must be less than 128";
throw new OperationError("IPv6 CIDR must be less than 128");
}
const cidrIp1 = new Array(8),

156
src/core/lib/Lorenz.mjs Normal file
View File

@@ -0,0 +1,156 @@
/**
* Resources required by the Lorenz SZ40/42 and Colossus
*
* @author VirtualColossus [martin@virtualcolossus.co.uk]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
export const SWITCHES = [
{name: "Up (.)", value: "."},
{name: "Centre", value: ""},
{name: "Down (x)", value: "x"}
];
export const VALID_ITA2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ34589+-./";
export 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"
};
export const ROTOR_SIZES = {
S1: 43,
S2: 47,
S3: 51,
S4: 53,
S5: 59,
M37: 37,
M61: 61,
X1: 41,
X2: 31,
X3: 29,
X4: 26,
X5: 23
};
/**
* Initial rotor patterns
*/
export 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]
}
}
};

View File

@@ -2,7 +2,7 @@ import OperationConfig from "../config/OperationConfig.json";
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
import Recipe from "../Recipe.mjs";
import Dish from "../Dish.mjs";
import {detectFileType} from "./FileType.mjs";
import {detectFileType, isType} from "./FileType.mjs";
import chiSquared from "chi-squared";
/**
@@ -19,31 +19,38 @@ class Magic {
* Magic constructor.
*
* @param {ArrayBuffer} buf
* @param {Object[]} [opPatterns]
* @param {Object[]} [opCriteria]
* @param {Object} [prevOp]
*/
constructor(buf, opPatterns) {
constructor(buf, opCriteria=Magic._generateOpCriteria(), prevOp=null) {
this.inputBuffer = new Uint8Array(buf);
this.inputStr = Utils.arrayBufferToStr(buf);
this.opPatterns = opPatterns || Magic._generateOpPatterns();
this.opCriteria = opCriteria;
this.prevOp = prevOp;
}
/**
* Finds operations that claim to be able to decode the input based on regular
* expression matches.
* Finds operations that claim to be able to decode the input based on various criteria.
*
* @returns {Object[]}
*/
findMatchingOps() {
const matches = [];
findMatchingInputOps() {
const matches = [],
inputEntropy = this.calcEntropy();
for (let i = 0; i < this.opPatterns.length; i++) {
const pattern = this.opPatterns[i],
regex = new RegExp(pattern.match, pattern.flags);
this.opCriteria.forEach(check => {
// If the input doesn't lie in the required entropy range, move on
if (check.entropyRange &&
(inputEntropy < check.entropyRange[0] ||
inputEntropy > check.entropyRange[1]))
return;
// If the input doesn't match the pattern, move on
if (check.pattern &&
!check.pattern.test(this.inputStr))
return;
if (regex.test(this.inputStr)) {
matches.push(pattern);
}
}
matches.push(check);
});
return matches;
}
@@ -185,8 +192,10 @@ class Magic {
*
* @returns {number}
*/
calcEntropy() {
const prob = this._freqDist();
calcEntropy(data=this.inputBuffer, standalone=false) {
if (!standalone && this.inputEntropy) return this.inputEntropy;
const prob = this._freqDist(data, standalone);
let entropy = 0,
p;
@@ -195,6 +204,8 @@ class Magic {
if (p === 0) continue;
entropy += p * Math.log(p) / Math.log(2);
}
if (!standalone) this.inputEntropy = -entropy;
return -entropy;
}
@@ -264,25 +275,59 @@ class Magic {
return results;
}
/**
* Checks whether the data passes output criteria for an operation check
*
* @param {ArrayBuffer} data
* @param {Object} criteria
* @returns {boolean}
*/
outputCheckPasses(data, criteria) {
if (criteria.pattern) {
const dataStr = Utils.arrayBufferToStr(data),
regex = new RegExp(criteria.pattern, criteria.flags);
if (!regex.test(dataStr))
return false;
}
if (criteria.entropyRange) {
const dataEntropy = this.calcEntropy(data, true);
if (dataEntropy < criteria.entropyRange[0] || dataEntropy > criteria.entropyRange[1])
return false;
}
if (criteria.mime &&
!isType(criteria.mime, data))
return false;
return true;
}
/**
* Speculatively executes matching operations, recording metadata of each result.
*
* @param {number} [depth=0] - How many levels to try to execute
* @param {boolean} [extLang=false] - Extensive language support (false = only check the most
* common Internet languages)
* common Internet languages)
* @param {boolean} [intensive=false] - Run brute-forcing on each branch (significantly affects
* performance)
* performance)
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
* @param {boolean} [useful=false] - Whether the current recipe should be scored highly
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation output
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation
* output
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
*/
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null) {
async speculativeExecution(
depth=0,
extLang=false,
intensive=false,
recipeConfig=[],
useful=false,
crib=null) {
// If we have reached the recursion depth, return
if (depth < 0) return [];
// Find any operations that can be run on this data
const matchingOps = this.findMatchingOps();
const matchingOps = this.findMatchingInputOps();
let results = [];
// Record the properties of the current data
@@ -308,17 +353,21 @@ class Magic {
},
output = await this._runRecipe([opConfig]);
// If the recipe is repeating and returning the same data, do not continue
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
return;
}
// If the recipe returned an empty buffer, do not continue
if (_buffersEqual(output, new ArrayBuffer())) {
return;
}
const magic = new Magic(output, this.opPatterns),
// If the recipe is repeating and returning the same data, do not continue
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
return;
}
// If the output criteria for this op doesn't match the output, do not continue
if (op.output && !this.outputCheckPasses(output, op.output))
return;
const magic = new Magic(output, this.opCriteria, OperationConfig[op.op]),
speculativeResults = await magic.speculativeExecution(
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
@@ -330,7 +379,7 @@ class Magic {
const bfEncodings = await this.bruteForce();
await Promise.all(bfEncodings.map(async enc => {
const magic = new Magic(enc.data, this.opPatterns),
const magic = new Magic(enc.data, this.opCriteria, undefined),
bfResults = await magic.speculativeExecution(
depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
@@ -345,7 +394,8 @@ class Magic {
r.languageScores[0].probability > 0 || // Some kind of language was found
r.fileType || // A file was found
r.isUTF8 || // UTF-8 was found
r.matchingOps.length // A matching op was found
r.matchingOps.length || // A matching op was found
r.matchesCrib // The crib matches
)
);
@@ -376,9 +426,10 @@ class Magic {
bScore += b.entropy;
// A result with no recipe but matching ops suggests there are better options
if ((!a.recipe.length && a.matchingOps.length) &&
b.recipe.length)
if ((!a.recipe.length && a.matchingOps.length) && b.recipe.length)
return 1;
if ((!b.recipe.length && b.matchingOps.length) && a.recipe.length)
return -1;
return aScore - bScore;
});
@@ -403,7 +454,7 @@ class Magic {
await recipe.execute(dish);
// Return an empty buffer if the recipe did not run to completion
if (recipe.lastRunOp === recipe.opList[recipe.opList.length - 1]) {
return dish.get(Dish.ARRAY_BUFFER);
return await dish.get(Dish.ARRAY_BUFFER);
} else {
return new ArrayBuffer();
}
@@ -417,14 +468,16 @@ class Magic {
* Calculates the number of times each byte appears in the input as a percentage
*
* @private
* @param {ArrayBuffer} [data]
* @param {boolean} [standalone]
* @returns {number[]}
*/
_freqDist() {
if (this.freqDist) return this.freqDist;
_freqDist(data=this.inputBuffer, standalone=false) {
if (!standalone && this.freqDist) return this.freqDist;
const len = this.inputBuffer.length;
const len = data.length,
counts = new Array(256).fill(0);
let i = len;
const counts = new Array(256).fill(0);
if (!len) {
this.freqDist = counts;
@@ -432,13 +485,15 @@ class Magic {
}
while (i--) {
counts[this.inputBuffer[i]]++;
counts[data[i]]++;
}
this.freqDist = counts.map(c => {
const result = counts.map(c => {
return c / len * 100;
});
return this.freqDist;
if (!standalone) this.freqDist = result;
return result;
}
/**
@@ -447,24 +502,29 @@ class Magic {
* @private
* @returns {Object[]}
*/
static _generateOpPatterns() {
const opPatterns = [];
static _generateOpCriteria() {
const opCriteria = [];
for (const op in OperationConfig) {
if (!("patterns" in OperationConfig[op])) continue;
if (!("checks" in OperationConfig[op]))
continue;
OperationConfig[op].patterns.forEach(pattern => {
opPatterns.push({
OperationConfig[op].checks.forEach(check => {
// Add to the opCriteria list.
// Compile the regex here and cache the compiled version so we
// don't have to keep calculating it.
opCriteria.push({
op: op,
match: pattern.match,
flags: pattern.flags,
args: pattern.args,
useful: pattern.useful || false
pattern: check.pattern ? new RegExp(check.pattern, check.flags) : null,
args: check.args,
useful: check.useful,
entropyRange: check.entropyRange,
output: check.output
});
});
}
return opPatterns;
return opCriteria;
}
/**

View File

@@ -9,8 +9,9 @@
import OperationError from "../errors/OperationError.mjs";
import jsQR from "jsqr";
import qr from "qr-image";
import jimp from "jimp";
import Utils from "../Utils.mjs";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Parses a QR code image from an image

17
src/core/lib/RSA.mjs Normal file
View File

@@ -0,0 +1,17 @@
/**
* RSA resources.
*
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import forge from "node-forge";
export const MD_ALGORITHMS = {
"SHA-1": forge.md.sha1,
"MD5": forge.md.md5,
"SHA-256": forge.md.sha256,
"SHA-384": forge.md.sha384,
"SHA-512": forge.md.sha512,
};

View File

@@ -303,11 +303,13 @@ export default class Stream {
/**
* Returns a slice of the stream up to the current position.
*
* @param {number} [start=0]
* @param {number} [finish=this.position]
* @returns {Uint8Array}
*/
carve() {
if (this.bitPos > 0) this.position++;
return this.bytes.slice(0, this.position);
carve(start=0, finish=this.position) {
if (this.bitPos > 0) finish++;
return this.bytes.slice(start, finish);
}
}

View File

@@ -33,6 +33,38 @@ class A1Z26CipherDecode extends Operation {
value: DELIM_OPTIONS
}
];
this.checks = [
{
pattern: "^\\s*([12]?[0-9] )+[12]?[0-9]\\s*$",
flags: "",
args: ["Space"]
},
{
pattern: "^\\s*([12]?[0-9],)+[12]?[0-9]\\s*$",
flags: "",
args: ["Comma"]
},
{
pattern: "^\\s*([12]?[0-9];)+[12]?[0-9]\\s*$",
flags: "",
args: ["Semi-colon"]
},
{
pattern: "^\\s*([12]?[0-9]:)+[12]?[0-9]\\s*$",
flags: "",
args: ["Colon"]
},
{
pattern: "^\\s*([12]?[0-9]\\n)+[12]?[0-9]\\s*$",
flags: "",
args: ["Line feed"]
},
{
pattern: "^\\s*([12]?[0-9]\\r\\n)+[12]?[0-9]\\s*$",
flags: "",
args: ["CRLF"]
}
];
}
/**

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
import OperationError from "../errors/OperationError.mjs";
/**
@@ -41,8 +41,33 @@ class AESDecrypt extends Operation {
},
{
"name": "Mode",
"type": "option",
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
"type": "argSelector",
"value": [
{
name: "CBC",
off: [5, 6]
},
{
name: "CFB",
off: [5, 6]
},
{
name: "OFB",
off: [5, 6]
},
{
name: "CTR",
off: [5, 6]
},
{
name: "GCM",
on: [5, 6]
},
{
name: "ECB",
off: [5, 6]
}
]
},
{
"name": "Input",
@@ -59,6 +84,11 @@ class AESDecrypt extends Operation {
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "Additional Authenticated Data",
"type": "binaryString",
"value": ""
}
];
}
@@ -76,7 +106,8 @@ class AESDecrypt extends Operation {
mode = args[2],
inputType = args[3],
outputType = args[4],
gcmTag = Utils.convertToByteString(args[5].string, args[5].option);
gcmTag = Utils.convertToByteString(args[5].string, args[5].option),
aad = args[6];
if ([16, 24, 32].indexOf(key.length) < 0) {
throw new OperationError(`Invalid key length: ${key.length} bytes
@@ -92,7 +123,8 @@ The following algorithms will be used based on the size of the key:
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
decipher.start({
iv: iv.length === 0 ? "" : iv,
tag: gcmTag
tag: mode === "GCM" ? gcmTag : undefined,
additionalData: mode === "GCM" ? aad : undefined
});
decipher.update(forge.util.createBuffer(input));
const result = decipher.finish();

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
import OperationError from "../errors/OperationError.mjs";
/**
@@ -41,8 +41,33 @@ class AESEncrypt extends Operation {
},
{
"name": "Mode",
"type": "option",
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
"type": "argSelector",
"value": [
{
name: "CBC",
off: [5]
},
{
name: "CFB",
off: [5]
},
{
name: "OFB",
off: [5]
},
{
name: "CTR",
off: [5]
},
{
name: "GCM",
on: [5]
},
{
name: "ECB",
off: [5]
}
]
},
{
"name": "Input",
@@ -53,6 +78,11 @@ class AESEncrypt extends Operation {
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
},
{
"name": "Additional Authenticated Data",
"type": "binaryString",
"value": ""
}
];
}
@@ -69,7 +99,8 @@ class AESEncrypt extends Operation {
iv = Utils.convertToByteString(args[1].string, args[1].option),
mode = args[2],
inputType = args[3],
outputType = args[4];
outputType = args[4],
aad = args[5];
if ([16, 24, 32].indexOf(key.length) < 0) {
throw new OperationError(`Invalid key length: ${key.length} bytes
@@ -83,7 +114,10 @@ The following algorithms will be used based on the size of the key:
input = Utils.convertToByteString(input, inputType);
const cipher = forge.cipher.createCipher("AES-" + mode, key);
cipher.start({iv: iv});
cipher.start({
iv: iv,
additionalData: mode === "GCM" ? aad : undefined
});
cipher.update(forge.util.createBuffer(input));
cipher.finish();

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Add Text To Image operation

View File

@@ -44,6 +44,48 @@ class BaconCipherDecode extends Operation {
"value": false
}
];
this.checks = [
{
pattern: "^\\s*([01]{5}\\s?)+$",
flags: "",
args: ["Standard (I=J and U=V)", "0/1", false]
},
{
pattern: "^\\s*([01]{5}\\s?)+$",
flags: "",
args: ["Standard (I=J and U=V)", "0/1", true]
},
{
pattern: "^\\s*([AB]{5}\\s?)+$",
flags: "",
args: ["Standard (I=J and U=V)", "A/B", false]
},
{
pattern: "^\\s*([AB]{5}\\s?)+$",
flags: "",
args: ["Standard (I=J and U=V)", "A/B", true]
},
{
pattern: "^\\s*([01]{5}\\s?)+$",
flags: "",
args: ["Complete", "0/1", false]
},
{
pattern: "^\\s*([01]{5}\\s?)+$",
flags: "",
args: ["Complete", "0/1", true]
},
{
pattern: "^\\s*([AB]{5}\\s?)+$",
flags: "",
args: ["Complete", "A/B", false]
},
{
pattern: "^\\s*([AB]{5}\\s?)+$",
flags: "",
args: ["Complete", "A/B", true]
}
];
}
/**

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
import OperationError from "../errors/OperationError.mjs";
import { Blowfish } from "../lib/Blowfish.mjs";

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
import OperationError from "../errors/OperationError.mjs";
import { Blowfish } from "../lib/Blowfish.mjs";

View File

@@ -9,8 +9,9 @@ import OperationError from "../errors/OperationError.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import jimp from "jimp";
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Blur Image operation

View File

@@ -33,9 +33,9 @@ class Bzip2Decompress extends Operation {
value: false
}
];
this.patterns = [
this.checks = [
{
"match": "^\\x42\\x5a\\x68",
"pattern": "^\\x42\\x5a\\x68",
"flags": "",
"args": []
}

View File

@@ -21,7 +21,7 @@ class CTPH extends Operation {
this.name = "CTPH";
this.module = "Crypto";
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing";
this.inputType = "string";
this.outputType = "string";
this.args = [];

View File

@@ -0,0 +1,61 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import { encode } from "../lib/CipherSaber2.mjs";
import Utils from "../Utils.mjs";
/**
* CipherSaber2 Decrypt operation
*/
class CipherSaber2Decrypt extends Operation {
/**
* CipherSaber2Decrypt constructor
*/
constructor() {
super();
this.name = "CipherSaber2 Decrypt";
this.module = "Crypto";
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Rounds",
type: "number",
value: 20
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
run(input, args) {
input = new Uint8Array(input);
const result = [],
key = Utils.convertToByteArray(args[0].string, args[0].option),
rounds = args[1];
const tempIVP = input.slice(0, 10);
input = input.slice(10);
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
}
}
export default CipherSaber2Decrypt;

View File

@@ -0,0 +1,65 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import crypto from "crypto";
import { encode } from "../lib/CipherSaber2.mjs";
import Utils from "../Utils.mjs";
/**
* CipherSaber2 Encrypt operation
*/
class CipherSaber2Encrypt extends Operation {
/**
* CipherSaber2Encrypt constructor
*/
constructor() {
super();
this.name = "CipherSaber2 Encrypt";
this.module = "Crypto";
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Rounds",
type: "number",
value: 20
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
run(input, args) {
input = new Uint8Array(input);
const result = [],
key = Utils.convertToByteArray(args[0].string, args[0].option),
rounds = args[1];
// Assign into initialisation vector based on cipher mode.
const tempIVP = crypto.randomBytes(10);
for (let m = 0; m < 10; m++)
result.push(tempIVP[m]);
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
}
}
export default CipherSaber2Encrypt;

View File

@@ -0,0 +1,572 @@
/**
* Emulation of Colossus.
*
* @author VirtualColossus [martin@virtualcolossus.co.uk]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { ColossusComputer } from "../lib/Colossus.mjs";
import { SWITCHES, VALID_ITA2 } from "../lib/Lorenz.mjs";
/**
* Colossus operation
*/
class Colossus extends Operation {
/**
* Colossus constructor
*/
constructor() {
super();
this.name = "Colossus";
this.module = "Bletchley";
this.description = "Colossus is the name of the world's first electronic computer. Ten Colossi were designed by Tommy Flowers and built at the Post Office Research Labs at Dollis Hill in 1943 during World War 2. They assisted with the breaking of the German Lorenz cipher attachment, a machine created to encipher communications between Hitler and his generals on the front lines.<br><br>To learn more, Virtual Colossus, an online, browser based simulation of a Colossus computer is available at <a href='https://virtualcolossus.co.uk' target='_blank'>virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Colossus' target='_blank'>here</a>.";
this.infoURL = "https://wikipedia.org/wiki/Colossus_computer";
this.inputType = "string";
this.outputType = "JSON";
this.presentType = "html";
this.args = [
{
name: "Input",
type: "label"
},
{
name: "Pattern",
type: "option",
value: ["KH Pattern", "ZMUG Pattern", "BREAM Pattern"]
},
{
name: "QBusZ",
type: "option",
value: ["", "Z", "ΔZ"]
},
{
name: "QBusΧ",
type: "option",
value: ["", "Χ", "ΔΧ"]
},
{
name: "QBusΨ",
type: "option",
value: ["", "Ψ", "ΔΨ"]
},
{
name: "Limitation",
type: "option",
value: ["None", "Χ2", "Χ2 + P5", "X2 + Ψ1", "X2 + Ψ1 + P5"]
},
{
name: "K Rack Option",
type: "argSelector",
value: [
{
name: "Select Program",
on: [7],
off: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
},
{
name: "Top Section - Conditional",
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
off: [7, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
},
{
name: "Bottom Section - Addition",
on: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
off: [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
},
{
name: "Advanced",
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
off: [7]
}
]
},
{
name: "Program to run",
type: "option",
value: ["", "Letter Count", "1+2=. (1+2 Break In, Find X1,X2)", "4=5=/1=2 (Given X1,X2 find X4,X5)", "/,5,U (Count chars to find X3)"]
},
{
name: "K Rack: Conditional",
type: "label"
},
{
name: "R1-Q1",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R1-Q2",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R1-Q3",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R1-Q4",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R1-Q5",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R1-Negate",
type: "boolean"
},
{
name: "R1-Counter",
type: "option",
value: ["", "1", "2", "3", "4", "5"]
},
{
name: "R2-Q1",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R2-Q2",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R2-Q3",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R2-Q4",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R2-Q5",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R2-Negate",
type: "boolean"
},
{
name: "R2-Counter",
type: "option",
value: ["", "1", "2", "3", "4", "5"]
},
{
name: "R3-Q1",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R3-Q2",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R3-Q3",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R3-Q4",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R3-Q5",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "R3-Negate",
type: "boolean"
},
{
name: "R3-Counter",
type: "option",
value: ["", "1", "2", "3", "4", "5"]
},
{
name: "Negate All",
type: "boolean"
},
{
name: "K Rack: Addition",
type: "label"
},
{
name: "Add-Q1",
type: "boolean"
},
{
name: "Add-Q2",
type: "boolean"
},
{
name: "Add-Q3",
type: "boolean"
},
{
name: "Add-Q4",
type: "boolean"
},
{
name: "Add-Q5",
type: "boolean"
},
{
name: "Add-Equals",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "Add-Counter1",
type: "boolean"
},
{
name: "Add Negate All",
type: "boolean"
},
{
name: "Total Motor",
type: "editableOptionShort",
value: SWITCHES,
defaultIndex: 1
},
{
name: "Master Control Panel",
type: "label"
},
{
name: "Set Total",
type: "number",
value: 0
},
{
name: "Fast Step",
type: "option",
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
},
{
name: "Slow Step",
type: "option",
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
},
{
name: "Start Χ1",
type: "number",
value: 1
},
{
name: "Start Χ2",
type: "number",
value: 1
},
{
name: "Start Χ3",
type: "number",
value: 1
},
{
name: "Start Χ4",
type: "number",
value: 1
},
{
name: "Start Χ5",
type: "number",
value: 1
},
{
name: "Start M61",
type: "number",
value: 1
},
{
name: "Start M37",
type: "number",
value: 1
},
{
name: "Start Ψ1",
type: "number",
value: 1
},
{
name: "Start Ψ2",
type: "number",
value: 1
},
{
name: "Start Ψ3",
type: "number",
value: 1
},
{
name: "Start Ψ4",
type: "number",
value: 1
},
{
name: "Start Ψ5",
type: "number",
value: 1
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {Object}
*/
run(input, args) {
input = input.toUpperCase();
for (const character of input) {
if (VALID_ITA2.indexOf(character) === -1) {
let errltr = character;
if (errltr === "\n") errltr = "Carriage Return";
if (errltr === " ") errltr = "Space";
throw new OperationError("Invalid ITA2 character : " + errltr);
}
}
const pattern = args[1];
const qbusin = {
"Z": args[2],
"Chi": args[3],
"Psi": args[4],
};
const limitation = args[5];
const lm = [false, false, false];
if (limitation.includes("Χ2")) lm[0] = true;
if (limitation.includes("Ψ1")) lm[1] = true;
if (limitation.includes("P5")) lm[2] = true;
const limit = {
X2: lm[0], S1: lm[1], P5: lm[2]
};
const KRackOpt = args[6];
const setProgram = args[7];
if (KRackOpt === "Select Program" && setProgram !== "") {
args = this.selectProgram(setProgram, args);
}
const re = new RegExp("^$|^[.x]$");
for (let qr=0;qr<3;qr++) {
for (let a=0;a<5;a++) {
if (!re.test(args[((qr*7)+(a+9))]))
throw new OperationError("Switch R"+(qr+1)+"-Q"+(a+1)+" can only be set to blank, . or x");
}
}
if (!re.test(args[37])) throw new OperationError("Switch Add-Equals can only be set to blank, . or x");
if (!re.test(args[40])) throw new OperationError("Switch Total Motor can only be set to blank, . or x");
// Q1,Q2,Q3,Q4,Q5,negate,counter1
const qbusswitches = {
condition: [
{Qswitches: [args[9], args[10], args[11], args[12], args[13]], Negate: args[14], Counter: args[15]},
{Qswitches: [args[16], args[17], args[18], args[19], args[20]], Negate: args[21], Counter: args[22]},
{Qswitches: [args[23], args[24], args[25], args[26], args[27]], Negate: args[28], Counter: args[29]}
],
condNegateAll: args[30],
addition: [
{Qswitches: [args[32], args[33], args[34], args[35], args[36]], Equals: args[37], C1: args[38]}
],
addNegateAll: args[39],
totalMotor: args[40]
};
const settotal = parseInt(args[42], 10);
if (settotal < 0 || settotal > 9999)
throw new OperationError("Set Total must be between 0000 and 9999");
// null|fast|slow for each of S1-5,M1-2,X1-5
const control = {
fast: args[43],
slow: args[44]
};
// Start positions
if (args[52]<1 || args[52]>43) throw new OperationError("Ψ1 start must be between 1 and 43");
if (args[53]<1 || args[53]>47) throw new OperationError("Ψ2 start must be between 1 and 47");
if (args[54]<1 || args[54]>51) throw new OperationError("Ψ3 start must be between 1 and 51");
if (args[55]<1 || args[55]>53) throw new OperationError("Ψ4 start must be between 1 and 53");
if (args[56]<1 || args[57]>59) throw new OperationError("Ψ5 start must be between 1 and 59");
if (args[51]<1 || args[51]>37) throw new OperationError("Μ37 start must be between 1 and 37");
if (args[50]<1 || args[50]>61) throw new OperationError("Μ61 start must be between 1 and 61");
if (args[45]<1 || args[45]>41) throw new OperationError("Χ1 start must be between 1 and 41");
if (args[46]<1 || args[46]>31) throw new OperationError("Χ2 start must be between 1 and 31");
if (args[47]<1 || args[47]>29) throw new OperationError("Χ3 start must be between 1 and 29");
if (args[48]<1 || args[48]>26) throw new OperationError("Χ4 start must be between 1 and 26");
if (args[49]<1 || args[49]>23) throw new OperationError("Χ5 start must be between 1 and 23");
const starts = {
X1: args[45], X2: args[46], X3: args[47], X4: args[48], X5: args[49],
M61: args[50], M37: args[51],
S1: args[52], S2: args[53], S3: args[54], S4: args[55], S5: args[56]
};
const colossus = new ColossusComputer(input, pattern, qbusin, qbusswitches, control, starts, settotal, limit);
const result = colossus.run();
return result;
}
/**
* Select Program
*
* @param {string} progname
* @param {Object[]} args
* @returns {Object[]}
*/
selectProgram(progname, args) {
// Basic Letter Count
if (progname === "Letter Count") {
// Set Conditional R1 : count every character into counter 1
args[9] = "";
args[10] = "";
args[11] = "";
args[12] = "";
args[13] = "";
args[14] = false;
args[15] = "1";
// clear Conditional R2 & R3
args[22] = "";
args[29] = "";
// Clear Negate result
args[30] = false;
// Clear Addition row counter
args[38] = false;
}
// Bill Tutte's 1+2 Break In
if (progname === "1+2=. (1+2 Break In, Find X1,X2)") {
// Clear any other counters
args[15] = ""; // Conditional R1
args[22] = ""; // Conditional R2
args[29] = ""; // Conditional R3
// Set Add Q1+Q2=. into Counter 1
args[32] = true;
args[33] = true;
args[34] = false;
args[35] = false;
args[36] = false;
args[37] = ".";
args[38] = true;
}
// 4=3=/1=2 : Find X4 & X5 where X1 & X2 are known
if (progname === "4=5=/1=2 (Given X1,X2 find X4,X5)") {
// Set Conditional R1 : Match NOT ..?.. into counter 1
args[9] = ".";
args[10] = ".";
args[11] = "";
args[12] = ".";
args[13] = ".";
args[14] = true;
args[15] = "1";
// Set Conditional R2 : AND Match NOT xx?xx into counter 1
args[16] = "x";
args[17] = "x";
args[18] = "";
args[19] = "x";
args[20] = "x";
args[21] = true;
args[22] = "1";
// clear Conditional R3
args[29] = "";
// Negate result, giving NOT(NOT Q1 AND NOT Q2) which is equivalent to Q1 OR Q2
args[30] = true;
// Clear Addition row counter
args[38] = false;
}
// /,5,U : Count number of matches of /, 5 & U to find X3
if (progname === "/,5,U (Count chars to find X3)") {
// Set Conditional R1 : Match / char, ITA2 = ..... into counter 1
args[9] = ".";
args[10] = ".";
args[11] = ".";
args[12] = ".";
args[13] = ".";
args[14] = false;
args[15] = "1";
// Set Conditional R2 : Match 5 char, ITA2 = xx.xx into counter 2
args[16] = "x";
args[17] = "x";
args[18] = ".";
args[19] = "x";
args[20] = "x";
args[21] = false;
args[22] = "2";
// Set Conditional R3 : Match U char, ITA2 = xxx.. into counter 3
args[23] = "x";
args[24] = "x";
args[25] = "x";
args[26] = ".";
args[27] = ".";
args[28] = false;
args[29] = "3";
// Clear Negate result
args[30] = false;
// Clear Addition row counter
args[38] = false;
}
return args;
}
/**
* Displays Colossus results in an HTML table
*
* @param {Object} output
* @param {Object[]} output.counters
* @returns {html}
*/
present(output) {
let html = "Colossus Printer\n\n";
html += output.printout + "\n\n";
html += "Colossus Counters\n\n";
html += "<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>C1</th> <th>C2</th> <th>C3</th> <th>C4</th> <th>C5</th></tr>\n";
html += "<tr>";
for (const ct of output.counters) {
html += `<td>${ct}</td>\n`;
}
html += "</tr>";
html += "</table>";
return html;
}
}
export default Colossus;

View File

@@ -24,7 +24,7 @@ class CompareCTPHHashes extends Operation {
this.name = "Compare CTPH hashes";
this.module = "Crypto";
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing";
this.inputType = "string";
this.outputType = "Number";
this.args = [

View File

@@ -24,7 +24,7 @@ class CompareSSDEEPHashes extends Operation {
this.name = "Compare SSDEEP hashes";
this.module = "Crypto";
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Ssdeep";
this.inputType = "string";
this.outputType = "Number";
this.args = [

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Contain Image operation

View File

@@ -8,7 +8,8 @@ import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Convert Image Format operation
@@ -88,7 +89,7 @@ class ConvertImageFormat extends Operation {
"Sub": jimp.PNG_FILTER_SUB,
"Up": jimp.PNG_FILTER_UP,
"Average": jimp.PNG_FILTER_AVERAGE,
"Paeth": jimp.PNG_FILTER_PATH // Incorrect spelling in Jimp library
"Paeth": jimp.PNG_FILTER_PATH
};
const mime = formatMap[format];

View File

@@ -0,0 +1,82 @@
/**
* @author MarvinJWendt [git@marvinjwendt.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Convert to NATO alphabet operation
*/
class ConvertToNATOAlphabet extends Operation {
/**
* ConvertToNATOAlphabet constructor
*/
constructor() {
super();
this.name = "Convert to NATO alphabet";
this.module = "Default";
this.description = "Converts characters to their representation in the NATO phonetic alphabet.";
this.infoURL = "https://wikipedia.org/wiki/NATO_phonetic_alphabet";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
return input.replace(/[a-z0-9,/.]/ig, letter => {
return lookup[letter.toUpperCase()];
});
}
}
const lookup = {
"A": "Alfa ",
"B": "Bravo ",
"C": "Charlie ",
"D": "Delta ",
"E": "Echo ",
"F": "Foxtrot ",
"G": "Golf ",
"H": "Hotel ",
"I": "India ",
"J": "Juliett ",
"K": "Kilo ",
"L": "Lima ",
"M": "Mike ",
"N": "November ",
"O": "Oscar ",
"P": "Papa ",
"Q": "Quebec ",
"R": "Romeo ",
"S": "Sierra ",
"T": "Tango ",
"U": "Uniform ",
"V": "Victor ",
"W": "Whiskey ",
"X": "X-ray ",
"Y": "Yankee ",
"Z": "Zulu ",
"0": "Zero ",
"1": "One ",
"2": "Two ",
"3": "Three ",
"4": "Four ",
"5": "Five ",
"6": "Six ",
"7": "Seven ",
"8": "Eight ",
"9": "Nine ",
",": "Comma ",
"/": "Fraction bar ",
".": "Full stop ",
};
export default ConvertToNATOAlphabet;

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Cover Image operation

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Crop Image operation

View File

@@ -7,7 +7,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
/**
* DES Decrypt operation

View File

@@ -7,7 +7,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
/**
* DES Encrypt operation

View File

@@ -63,9 +63,9 @@ class DNSOverHTTPS extends Operation {
value: false
},
{
name: "Validate DNSSEC",
name: "Disable DNSSEC validation",
type: "boolean",
value: true
value: false
}
];
}

View File

@@ -24,6 +24,13 @@ class DechunkHTTPResponse extends Operation {
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.checks = [
{
pattern: "^[0-9A-F]+\r\n",
flags: "i",
args: []
}
];
}
/**

View File

@@ -30,6 +30,13 @@ class DecodeNetBIOSName extends Operation {
"value": 65
}
];
this.checks = [
{
pattern: "^\\s*\\S{32}$",
flags: "",
args: [65]
}
];
}
/**

View File

@@ -25,7 +25,17 @@ class DefangIPAddresses extends Operation {
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.checks = [
{
pattern: "^\\s*(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-f]{4}:){7}[0-9a-f]{4})\\s*$",
flags: "i",
args: [],
output: {
pattern: "^\\s*(([0-9]{1,3}\\[\\.\\]){3}[0-9]{1,3}|([0-9a-f]{4}\\[\\:\\]){7}[0-9a-f]{4})\\s*$",
flags: "i"
}
}
];
}
/**

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import forge from "node-forge/dist/forge.min.js";
import forge from "node-forge";
/**
* Derive PBKDF2 key operation

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Image Dither operation

View File

@@ -44,22 +44,22 @@ class EscapeUnicodeCharacters extends Operation {
"value": true
}
];
this.patterns = [
this.checks = [
{
match: "\\\\u(?:[\\da-f]{4,6})",
pattern: "\\\\u(?:[\\da-f]{4,6})",
flags: "i",
args: ["\\u"]
},
{
match: "%u(?:[\\da-f]{4,6})",
pattern: "%u(?:[\\da-f]{4,6})",
flags: "i",
args: ["%u"]
},
{
match: "U\\+(?:[\\da-f]{4,6})",
pattern: "U\\+(?:[\\da-f]{4,6})",
flags: "i",
args: ["U+"]
},
}
];
}

View File

@@ -24,7 +24,7 @@ class ExtractFiles extends Operation {
this.name = "Extract Files";
this.module = "Default";
this.description = "Performs file carving to attempt to extract files from the input.<br><br>This operation is currently capable of carving out the following formats:<ul><li>JPG</li><li>EXE</li><li>ZIP</li><li>PDF</li><li>PNG</li><li>BMP</li><li>FLV</li><li>RTF</li><li>DOCX, PPTX, XLSX</li><li>EPUB</li><li>GZIP</li><li>ZLIB</li><li>ELF, BIN, AXF, O, PRX, SO</li></ul>";
this.infoURL = "https://forensicswiki.org/wiki/File_Carving";
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=File_Carving";
this.inputType = "ArrayBuffer";
this.outputType = "List<File>";
this.presentType = "html";

View File

@@ -9,7 +9,8 @@ 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";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Extract LSB operation

View File

@@ -7,7 +7,8 @@
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
import {RGBA_DELIM_OPTIONS} from "../lib/Delim.mjs";

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Flip Image operation

View File

@@ -49,9 +49,9 @@ class FromBCD extends Operation {
"value": FORMAT
}
];
this.patterns = [
this.checks = [
{
match: "^(?:\\d{4} ){3,}\\d{4}$",
pattern: "^(?:\\d{4} ){3,}\\d{4}$",
flags: "",
args: ["8 4 2 1", true, false, "Nibbles"]
},

View File

@@ -36,12 +36,12 @@ class FromBase32 extends Operation {
value: true
}
];
this.patterns = [
this.checks = [
{
match: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
pattern: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
flags: "",
args: ["A-Z2-7=", false]
},
}
];
}

View File

@@ -38,14 +38,14 @@ class FromBase58 extends Operation {
"value": true
}
];
this.patterns = [
this.checks = [
{
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
pattern: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
flags: "",
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", false]
},
{
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
pattern: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
flags: "",
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", false]
},

View File

@@ -36,69 +36,69 @@ class FromBase64 extends Operation {
value: true
}
];
this.patterns = [
this.checks = [
{
match: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
pattern: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
flags: "i",
args: ["A-Za-z0-9+/=", true]
},
{
match: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
pattern: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
flags: "i",
args: ["A-Za-z0-9-_", true]
},
{
match: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
pattern: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
flags: "i",
args: ["A-Za-z0-9+\\-=", true]
},
{
match: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
pattern: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
flags: "i",
args: ["./0-9A-Za-z=", true]
},
{
match: "^\\s*[A-Z\\d_.]{20,}\\s*$",
pattern: "^\\s*[A-Z\\d_.]{20,}\\s*$",
flags: "i",
args: ["A-Za-z0-9_.", true]
},
{
match: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
pattern: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
flags: "i",
args: ["A-Za-z0-9._-", true]
},
{
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
flags: "i",
args: ["0-9a-zA-Z+/=", true]
},
{
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
flags: "i",
args: ["0-9A-Za-z+/=", true]
},
{
match: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
pattern: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
flags: "",
args: [" -_", false]
},
{
match: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
pattern: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
flags: "i",
args: ["+\\-0-9A-Za-z", true]
},
{
match: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
pattern: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
flags: "",
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
},
{
match: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
pattern: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
flags: "i",
args: ["N-ZA-Mn-za-m0-9+/=", true]
},
{
match: "^\\s*[A-Z\\d./]{20,}\\s*$",
pattern: "^\\s*[A-Z\\d./]{20,}\\s*$",
flags: "i",
args: ["./0-9A-Za-z", true]
},

View File

@@ -31,41 +31,46 @@ class FromBinary extends Operation {
"name": "Delimiter",
"type": "option",
"value": BIN_DELIM_OPTIONS
},
{
"name": "Byte Length",
"type": "number",
"value": 8
}
];
this.patterns = [
this.checks = [
{
match: "^(?:[01]{8})+$",
pattern: "^(?:[01]{8})+$",
flags: "",
args: ["None"]
},
{
match: "^(?:[01]{8})(?: [01]{8})*$",
pattern: "^(?:[01]{8})(?: [01]{8})*$",
flags: "",
args: ["Space"]
},
{
match: "^(?:[01]{8})(?:,[01]{8})*$",
pattern: "^(?:[01]{8})(?:,[01]{8})*$",
flags: "",
args: ["Comma"]
},
{
match: "^(?:[01]{8})(?:;[01]{8})*$",
pattern: "^(?:[01]{8})(?:;[01]{8})*$",
flags: "",
args: ["Semi-colon"]
},
{
match: "^(?:[01]{8})(?::[01]{8})*$",
pattern: "^(?:[01]{8})(?::[01]{8})*$",
flags: "",
args: ["Colon"]
},
{
match: "^(?:[01]{8})(?:\\n[01]{8})*$",
pattern: "^(?:[01]{8})(?:\\n[01]{8})*$",
flags: "",
args: ["Line feed"]
},
{
match: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
pattern: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
flags: "",
args: ["CRLF"]
},
@@ -78,7 +83,8 @@ class FromBinary extends Operation {
* @returns {byteArray}
*/
run(input, args) {
return fromBinary(input, args[0]);
const byteLen = args[1] ? args[1] : 8;
return fromBinary(input, args[0], byteLen);
}
/**

View File

@@ -36,37 +36,37 @@ class FromDecimal extends Operation {
"value": false
}
];
this.patterns = [
this.checks = [
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Space", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Comma", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Semi-colon", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Colon", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Line feed", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["CRLF", false]
},
}
];
}

View File

@@ -25,12 +25,12 @@ class FromHTMLEntity extends Operation {
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.patterns = [
this.checks = [
{
match: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
pattern: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
flags: "i",
args: []
},
}
];
}

View File

@@ -32,49 +32,54 @@ class FromHex extends Operation {
value: FROM_HEX_DELIM_OPTIONS
}
];
this.patterns = [
this.checks = [
{
match: "^(?:[\\dA-F]{2})+$",
pattern: "^(?:[\\dA-F]{2})+$",
flags: "i",
args: ["None"]
},
{
match: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
pattern: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
flags: "i",
args: ["Space"]
},
{
match: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
pattern: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
flags: "i",
args: ["Comma"]
},
{
match: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
pattern: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
flags: "i",
args: ["Semi-colon"]
},
{
match: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
pattern: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
flags: "i",
args: ["Colon"]
},
{
match: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
pattern: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
flags: "i",
args: ["Line feed"]
},
{
match: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
pattern: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
flags: "i",
args: ["CRLF"]
},
{
match: "^[\\dA-F]{2}(?:0x[\\dA-F]{2})*$",
pattern: "^(?:0x[\\dA-F]{2})+$",
flags: "i",
args: ["0x"]
},
{
match: "^[\\dA-F]{2}(?:\\\\x[\\dA-F]{2})*$",
pattern: "^0x[\\dA-F]{2}(?:,0x[\\dA-F]{2})*$",
flags: "i",
args: ["0x with comma"]
},
{
pattern: "^(?:\\\\x[\\dA-F]{2})+$",
flags: "i",
args: ["\\x"]
}

View File

@@ -26,6 +26,13 @@ class FromHexContent extends Operation {
this.inputType = "string";
this.outputType = "byteArray";
this.args = [];
this.checks = [
{
pattern: "\\|([\\da-f]{2} ?)+\\|",
flags: "i",
args: []
}
];
}
/**

View File

@@ -27,9 +27,9 @@ class FromHexdump extends Operation {
this.inputType = "string";
this.outputType = "byteArray";
this.args = [];
this.patterns = [
this.checks = [
{
match: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
pattern: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
flags: "i",
args: []
},

View File

@@ -37,12 +37,12 @@ class FromMorseCode extends Operation {
"value": WORD_DELIM_OPTIONS
}
];
this.patterns = [
this.checks = [
{
match: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
pattern: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
flags: "i",
args: ["Space", "Line feed"]
},
}
];
}
@@ -59,7 +59,7 @@ class FromMorseCode extends Operation {
const letterDelim = Utils.charRep(args[0]);
const wordDelim = Utils.charRep(args[1]);
input = input.replace(/-|||_||—|dash/ig, "<dash>"); //hyphen-minus|hyphen|minus-sign|undersore|en-dash|em-dash
input = input.replace(/-|||_||—|dash/ig, "<dash>"); // hyphen-minus|hyphen|minus-sign|undersore|en-dash|em-dash
input = input.replace(/\.|·|dot/ig, "<dot>");
let words = input.split(wordDelim);
@@ -147,7 +147,8 @@ const MORSE_TABLE = {
"=": "<dash><dot><dot><dot><dash>",
"&": "<dot><dash><dot><dot><dot>",
"_": "<dot><dot><dash><dash><dot><dash>",
"$": "<dot><dot><dot><dash><dot><dot><dash>"
"$": "<dot><dot><dot><dash><dot><dot><dash>",
" ": "<dot><dot><dot><dot><dot><dot><dot>"
};
export default FromMorseCode;

View File

@@ -32,37 +32,37 @@ class FromOctal extends Operation {
"value": DELIM_OPTIONS
}
];
this.patterns = [
this.checks = [
{
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
flags: "",
args: ["Space"]
},
{
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
flags: "",
args: ["Comma"]
},
{
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
flags: "",
args: ["Semi-colon"]
},
{
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
flags: "",
args: ["Colon"]
},
{
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
flags: "",
args: ["Line feed"]
},
{
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
flags: "",
args: ["CRLF"]
},
}
];
}

View File

@@ -28,9 +28,9 @@ class FromQuotedPrintable extends Operation {
this.inputType = "string";
this.outputType = "byteArray";
this.args = [];
this.patterns = [
this.checks = [
{
match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
pattern: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
flags: "i",
args: []
},

View File

@@ -33,27 +33,27 @@ class FromUNIXTimestamp extends Operation {
"value": UNITS
}
];
this.patterns = [
this.checks = [
{
match: "^1?\\d{9}$",
pattern: "^1?\\d{9}$",
flags: "",
args: ["Seconds (s)"]
},
{
match: "^1?\\d{12}$",
pattern: "^1?\\d{12}$",
flags: "",
args: ["Milliseconds (ms)"]
},
{
match: "^1?\\d{15}$",
pattern: "^1?\\d{15}$",
flags: "",
args: ["Microseconds (μs)"]
},
{
match: "^1?\\d{18}$",
pattern: "^1?\\d{18}$",
flags: "",
args: ["Nanoseconds (ns)"]
},
}
];
}

View File

@@ -21,7 +21,7 @@ class GenerateHOTP extends Operation {
this.name = "Generate HOTP";
this.module = "Default";
this.description = "The HMAC-based One-Time Password algorithm (HOTP) is an algorithm that computes a one-time password from a shared secret key and an incrementing counter. It has been adopted as Internet Engineering Task Force standard RFC 4226, is the cornerstone of Initiative For Open Authentication (OATH), and is used in a number of two-factor authentication systems.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated.";
this.description = "The HMAC-based One-Time Password algorithm (HOTP) is an algorithm that computes a one-time password from a shared secret key and an incrementing counter. It has been adopted as Internet Engineering Task Force standard RFC 4226, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated.";
this.infoURL = "https://wikipedia.org/wiki/HMAC-based_One-time_Password_algorithm";
this.inputType = "ArrayBuffer";
this.outputType = "string";
@@ -59,7 +59,7 @@ class GenerateHOTP extends Operation {
name: args[0],
keySize: args[1],
codeLength: args[2],
secret: (new ToBase32).run(input, []),
secret: (new ToBase32).run(input, []).split("=")[0],
});
const counter = args[3];
return `URI: ${otpObj.hotpURL}\n\nPassword: ${otpObj.hotp(counter)}`;

View File

@@ -0,0 +1,185 @@
/**
* @author pointhi [thomas.pointhuber@gmx.at]
* @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 {toBase64} from "../lib/Base64.mjs";
import {isWorkerEnvironment} from "../Utils.mjs";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Generate Image operation
*/
class GenerateImage extends Operation {
/**
* GenerateImage constructor
*/
constructor() {
super();
this.name = "Generate Image";
this.module = "Image";
this.description = "Generates an image using the input as pixel values.";
this.infoURL = "";
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
this.presentType = "html";
this.args = [
{
"name": "Mode",
"type": "option",
"value": ["Greyscale", "RG", "RGB", "RGBA", "Bits"]
},
{
"name": "Pixel Scale Factor",
"type": "number",
"value": 8,
},
{
"name": "Pixels per row",
"type": "number",
"value": 64,
}
];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
async run(input, args) {
const [mode, scale, width] = args;
input = new Uint8Array(input);
if (scale <= 0) {
throw new OperationError("Pixel Scale Factor needs to be > 0");
}
if (width <= 0) {
throw new OperationError("Pixels per Row needs to be > 0");
}
const bytePerPixelMap = {
"Greyscale": 1,
"RG": 2,
"RGB": 3,
"RGBA": 4,
"Bits": 1/8,
};
const bytesPerPixel = bytePerPixelMap[mode];
if (bytesPerPixel > 0 && input.length % bytesPerPixel !== 0) {
throw new OperationError(`Number of bytes is not a divisor of ${bytesPerPixel}`);
}
const height = Math.ceil(input.length / bytesPerPixel / width);
const image = await new jimp(width, height, (err, image) => {});
if (isWorkerEnvironment())
self.sendStatusMessage("Generating image from data...");
if (mode === "Bits") {
let index = 0;
for (let j = 0; j < input.length; j++) {
const curByte = Utils.bin(input[j]);
for (let k = 0; k < 8; k++, index++) {
const x = index % width;
const y = Math.floor(index / width);
const value = curByte[k] === "0" ? 0xFF : 0x00;
const pixel = jimp.rgbaToInt(value, value, value, 0xFF);
image.setPixelColor(pixel, x, y);
}
}
} else {
let i = 0;
while (i < input.length) {
const index = i / bytesPerPixel;
const x = index % width;
const y = Math.floor(index / width);
let red = 0x00;
let green = 0x00;
let blue = 0x00;
let alpha = 0xFF;
switch (mode) {
case "Greyscale":
red = green = blue = input[i++];
break;
case "RG":
red = input[i++];
green = input[i++];
break;
case "RGB":
red = input[i++];
green = input[i++];
blue = input[i++];
break;
case "RGBA":
red = input[i++];
green = input[i++];
blue = input[i++];
alpha = input[i++];
break;
default:
throw new OperationError(`Unsupported Mode: (${mode})`);
}
try {
const pixel = jimp.rgbaToInt(red, green, blue, alpha);
image.setPixelColor(pixel, x, y);
} catch (err) {
throw new OperationError(`Error while generating image from pixel values. (${err})`);
}
}
}
if (scale !== 1) {
if (isWorkerEnvironment())
self.sendStatusMessage("Scaling image...");
image.scaleToFit(width*scale, height*scale, jimp.RESIZE_NEAREST_NEIGHBOR);
}
try {
const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
return imageBuffer.buffer;
} catch (err) {
throw new OperationError(`Error generating image. (${err})`);
}
}
/**
* Displays the generated image using HTML for web apps
* @param {ArrayBuffer} data
* @returns {html}
*/
present(data) {
if (!data.byteLength) return "";
const dataArray = new Uint8Array(data);
const type = isImage(dataArray);
if (!type) {
throw new OperationError("Invalid file type.");
}
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
}
}
export default GenerateImage;

View File

@@ -25,7 +25,7 @@ class GeneratePGPKeyPair extends Operation {
this.name = "Generate PGP Key Pair";
this.module = "PGP";
this.description = "Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.";
this.description = "Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.<br><br>WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";
this.infoURL = "https://wikipedia.org/wiki/Pretty_Good_Privacy";
this.inputType = "string";
this.outputType = "string";
@@ -33,7 +33,7 @@ class GeneratePGPKeyPair extends Operation {
{
"name": "Key type",
"type": "option",
"value": ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384"]
"value": ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384", "ECC-521"]
},
{
"name": "Password (optional)",
@@ -59,12 +59,15 @@ class GeneratePGPKeyPair extends Operation {
* @returns {string}
*/
async run(input, args) {
const [keyType, keySize] = args[0].split("-"),
password = args[1],
let [keyType, keySize] = args[0].split("-");
const password = args[1],
name = args[2],
email = args[3];
let userIdentifier = "";
keyType = keyType.toLowerCase();
keySize = parseInt(keySize, 10);
if (name) userIdentifier += name;
if (email) userIdentifier += ` <${email}>`;

View File

@@ -0,0 +1,87 @@
/**
* @author Matt C [me@mitt.dev]
* @author gchq77703 []
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import forge from "node-forge";
/**
* Generate RSA Key Pair operation
*/
class GenerateRSAKeyPair extends Operation {
/**
* GenerateRSAKeyPair constructor
*/
constructor() {
super();
this.name = "Generate RSA Key Pair";
this.module = "Ciphers";
this.description = "Generate an RSA key pair with a given number of bits.<br><br>WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "RSA Key Length",
type: "option",
value: [
"1024",
"2048",
"4096"
]
},
{
name: "Output Format",
type: "option",
value: [
"PEM",
"JSON",
"DER"
]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [keyLength, outputFormat] = args;
return new Promise((resolve, reject) => {
forge.pki.rsa.generateKeyPair({
bits: Number(keyLength),
workers: -1,
workerScript: "assets/forge/prime.worker.min.js"
}, (err, keypair) => {
if (err) return reject(err);
let result;
switch (outputFormat) {
case "PEM":
result = forge.pki.publicKeyToPem(keypair.publicKey) + "\n" + forge.pki.privateKeyToPem(keypair.privateKey);
break;
case "JSON":
result = JSON.stringify(keypair);
break;
case "DER":
result = forge.asn1.toDer(forge.pki.privateKeyToAsn1(keypair.privateKey)).getBytes();
break;
}
resolve(result);
});
});
}
}
export default GenerateRSAKeyPair;

View File

@@ -21,7 +21,7 @@ class GenerateTOTP extends Operation {
this.name = "Generate TOTP";
this.module = "Default";
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OATH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
this.infoURL = "https://wikipedia.org/wiki/Time-based_One-time_Password_algorithm";
this.inputType = "ArrayBuffer";
this.outputType = "string";
@@ -64,7 +64,7 @@ class GenerateTOTP extends Operation {
name: args[0],
keySize: args[1],
codeLength: args[2],
secret: (new ToBase32).run(input, []),
secret: (new ToBase32).run(input, []).split("=")[0],
epoch: args[3],
timeSlice: args[4]
});

View File

@@ -117,7 +117,7 @@ class GroupIPAddresses extends Operation {
// Sort IPv6 network dictionaries and print
for (networkStr in ipv6Networks) {
//ipv6Networks[networkStr] = ipv6Networks[networkStr].sort(); TODO
// ipv6Networks[networkStr] = ipv6Networks[networkStr].sort(); TODO
output += networkStr + "/" + cidr + "\n";

View File

@@ -5,9 +5,9 @@
*/
import Operation from "../Operation.mjs";
import zlibAndGzip from "zlibjs/bin/zlib_and_gzip.min.js";
import gunzip from "zlibjs/bin/gunzip.min.js";
const Zlib = zlibAndGzip.Zlib;
const Zlib = gunzip.Zlib;
/**
* Gunzip operation
@@ -27,12 +27,12 @@ class Gunzip extends Operation {
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
this.args = [];
this.patterns = [
this.checks = [
{
match: "^\\x1f\\x8b\\x08",
pattern: "^\\x1f\\x8b\\x08",
flags: "",
args: []
},
}
];
}
@@ -42,8 +42,8 @@ class Gunzip extends Operation {
* @returns {File}
*/
run(input, args) {
const gunzip = new Zlib.Gunzip(new Uint8Array(input));
return new Uint8Array(gunzip.decompress()).buffer;
const gzipObj = new Zlib.Gunzip(new Uint8Array(input));
return new Uint8Array(gzipObj.decompress()).buffer;
}
}

View File

@@ -6,9 +6,9 @@
import Operation from "../Operation.mjs";
import {COMPRESSION_TYPE, ZLIB_COMPRESSION_TYPE_LOOKUP} from "../lib/Zlib.mjs";
import zlibAndGzip from "zlibjs/bin/zlib_and_gzip.min.js";
import gzip from "zlibjs/bin/gzip.min.js";
const Zlib = zlibAndGzip.Zlib;
const Zlib = gzip.Zlib;
/**
* Gzip operation
@@ -73,12 +73,15 @@ class Gzip extends Operation {
options.filename = filename;
}
if (comment.length) {
options.flags.fcommenct = true;
options.flags.comment = true;
options.comment = comment;
}
const gzip = new Zlib.Gzip(new Uint8Array(input), options);
return new Uint8Array(gzip.compress()).buffer;
const gzipObj = new Zlib.Gzip(new Uint8Array(input), options);
const compressed = new Uint8Array(gzipObj.compress());
if (options.flags.comment && !(compressed[3] & 0x10)) {
compressed[3] |= 0x10;
}
return compressed.buffer;
}
}

View File

@@ -20,11 +20,19 @@ class HAS160 extends Operation {
this.name = "HAS-160";
this.module = "Crypto";
this.description = "HAS-160 is a cryptographic hash function designed for use with the Korean KCDSA digital signature algorithm. It is derived from SHA-1, with assorted changes intended to increase its security. It produces a 160-bit output.<br><br>HAS-160 is used in the same way as SHA-1. First it divides input in blocks of 512 bits each and pads the final block. A digest function updates the intermediate hash value by processing the input blocks in turn.<br><br>The message digest algorithm consists of 80 rounds.";
this.description = "HAS-160 is a cryptographic hash function designed for use with the Korean KCDSA digital signature algorithm. It is derived from SHA-1, with assorted changes intended to increase its security. It produces a 160-bit output.<br><br>HAS-160 is used in the same way as SHA-1. First it divides input in blocks of 512 bits each and pads the final block. A digest function updates the intermediate hash value by processing the input blocks in turn.<br><br>The message digest algorithm consists, by default, of 80 rounds.";
this.infoURL = "https://wikipedia.org/wiki/HAS-160";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [];
this.args = [
{
name: "Rounds",
type: "number",
value: 80,
min: 1,
max: 80
}
];
}
/**
@@ -33,7 +41,7 @@ class HAS160 extends Operation {
* @returns {string}
*/
run(input, args) {
return runHash("has160", input);
return runHash("has160", input, {rounds: args[0]});
}
}

View File

@@ -41,8 +41,8 @@ class HaversineDistance extends Operation {
const lat1 = parseFloat(values[1]);
const lng1 = parseFloat(values[3]);
const lat2 = parseFloat(values[6]);
const lng2 = parseFloat(values[8]);
const lat2 = parseFloat(values[5]);
const lng2 = parseFloat(values[7]);
const TO_RAD = Math.PI / 180;
const dLat = (lat2-lat1) * TO_RAD;

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Image Brightness / Contrast operation

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Image Filter operation

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Image Hue/Saturation/Lightness operation

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Image Opacity operation

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Invert Image operation

View File

@@ -6,6 +6,8 @@
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import * as flat from "flat";
const flatten = flat.default ? flat.default.flatten : flat.flatten;
/**
* JSON to CSV operation
@@ -38,6 +40,40 @@ class JSONToCSV extends Operation {
];
}
/**
* Converts JSON to a CSV equivalent.
*
* @returns {string}
*/
toCSV() {
const self = this;
// If the JSON is an array of arrays, this is easy
if (this.flattened[0] instanceof Array) {
return this.flattened
.map(row => row
.map(self.escapeCellContents.bind(self))
.join(this.cellDelim)
)
.join(this.rowDelim) +
this.rowDelim;
}
// If it's an array of dictionaries...
const header = Object.keys(this.flattened[0]);
return header
.map(self.escapeCellContents.bind(self))
.join(this.cellDelim) +
this.rowDelim +
this.flattened
.map(row => header
.map(h => row[h])
.map(self.escapeCellContents.bind(self))
.join(this.cellDelim)
)
.join(this.rowDelim) +
this.rowDelim;
}
/**
* @param {JSON} input
* @param {Object[]} args
@@ -49,40 +85,23 @@ class JSONToCSV extends Operation {
// Record values so they don't have to be passed to other functions explicitly
this.cellDelim = cellDelim;
this.rowDelim = rowDelim;
const self = this;
if (!(input instanceof Array)) {
input = [input];
this.flattened = input;
if (!(this.flattened instanceof Array)) {
this.flattened = [input];
}
try {
// If the JSON is an array of arrays, this is easy
if (input[0] instanceof Array) {
return input
.map(row => row
.map(self.escapeCellContents.bind(self))
.join(cellDelim)
)
.join(rowDelim) +
rowDelim;
}
// If it's an array of dictionaries...
const header = Object.keys(input[0]);
return header
.map(self.escapeCellContents.bind(self))
.join(cellDelim) +
rowDelim +
input
.map(row => header
.map(h => row[h])
.map(self.escapeCellContents.bind(self))
.join(cellDelim)
)
.join(rowDelim) +
rowDelim;
return this.toCSV();
} catch (err) {
throw new OperationError("Unable to parse JSON to CSV: " + err.toString());
try {
this.flattened = flatten(input);
if (!(this.flattened instanceof Array)) {
this.flattened = [this.flattened];
}
return this.toCSV();
} catch (err) {
throw new OperationError("Unable to parse JSON to CSV: " + err.toString());
}
}
}

View File

@@ -4,10 +4,9 @@
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
import Operation from "../Operation.mjs";
import * as esprima from "esprima";
import escodegen from "escodegen";
import esmangle from "esmangle";
import * as terser from "terser";
/**
* JavaScript Minify operation
@@ -33,23 +32,12 @@ class JavaScriptMinify extends Operation {
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
let result = "";
const AST = esprima.parseScript(input),
optimisedAST = esmangle.optimize(AST, null),
mangledAST = esmangle.mangle(optimisedAST);
result = escodegen.generate(mangledAST, {
format: {
renumber: true,
hexadecimal: true,
escapeless: true,
compact: true,
semicolons: false,
parentheses: false
}
});
return result;
async run(input, args) {
const result = await terser.minify(input);
if (result.error) {
throw new OperationError(`Error minifying JavaScript. (${result.error})`);
}
return result.code;
}
}

View File

@@ -6,8 +6,8 @@
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Lorenz operation
@@ -22,7 +22,7 @@ class Lorenz extends Operation {
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>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Lorenz-SZ' target='_blank'>here</a>.";
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'>lorenz.virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Lorenz-SZ' target='_blank'>here</a>.";
this.infoURL = "https://wikipedia.org/wiki/Lorenz_cipher";
this.inputType = "string";
this.outputType = "string";
@@ -293,8 +293,8 @@ class Lorenz extends Operation {
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.M[1] = this.readLugs(lugm61);
chosenSetting.M[2] = this.readLugs(lugm37);
chosenSetting.X[1] = this.readLugs(lugx1);
chosenSetting.X[2] = this.readLugs(lugx2);
chosenSetting.X[3] = this.readLugs(lugx3);
@@ -391,7 +391,7 @@ class Lorenz extends Operation {
// 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
// p5 back 2
if (lim===p5[2]) {
lim = 0;
} else {
@@ -413,7 +413,7 @@ class Lorenz extends Operation {
lim = 1;
if (x2b1lug===s1b1lug) lim=0;
if (kt) {
//p5 back 2
// p5 back 2
if (lim===p5[2]) {
lim=0;
} else {

View File

@@ -0,0 +1,77 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Luhn Checksum operation
*/
class LuhnChecksum extends Operation {
/**
* LuhnChecksum constructor
*/
constructor() {
super();
this.name = "Luhn Checksum";
this.module = "Default";
this.description = "The Luhn algorithm, also known as the modulus 10 or mod 10 algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers and Canadian Social Insurance Numbers.";
this.infoURL = "https://wikipedia.org/wiki/Luhn_algorithm";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* Generates the Luhn Checksum from the input.
*
* @param {string} inputStr
* @returns {number}
*/
checksum(inputStr) {
let even = false;
return inputStr.split("").reverse().reduce((acc, elem) => {
// Convert element to integer.
let temp = parseInt(elem, 10);
// If element is not an integer.
if (isNaN(temp))
throw new OperationError("Character: " + elem + " is not a digit.");
// If element is in an even position
if (even) {
// Double the element and add the quotient and remainder together.
temp = 2 * elem;
temp = Math.floor(temp/10) + (temp % 10);
}
even = !even;
return acc + temp;
}, 0) % 10;
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
if (!input) return "";
const checkSum = this.checksum(input);
let checkDigit = this.checksum(input + "0");
checkDigit = checkDigit === 0 ? 0 : (10-checkDigit);
return `Checksum: ${checkSum}
Checkdigit: ${checkDigit}
Luhn Validated String: ${input + "" + checkDigit}`;
}
}
export default LuhnChecksum;

View File

@@ -20,11 +20,18 @@ class MD2 extends Operation {
this.name = "MD2";
this.module = "Crypto";
this.description = "The MD2 (Message-Digest 2) algorithm is a cryptographic hash function developed by Ronald Rivest in 1989. The algorithm is optimized for 8-bit computers.<br><br>Although MD2 is no longer considered secure, even as of 2014, it remains in use in public key infrastructures as part of certificates generated with MD2 and RSA.";
this.description = "The MD2 (Message-Digest 2) algorithm is a cryptographic hash function developed by Ronald Rivest in 1989. The algorithm is optimized for 8-bit computers.<br><br>Although MD2 is no longer considered secure, even as of 2014, it remains in use in public key infrastructures as part of certificates generated with MD2 and RSA. The message digest algorithm consists, by default, of 18 rounds.";
this.infoURL = "https://wikipedia.org/wiki/MD2_(cryptography)";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [];
this.args = [
{
name: "Rounds",
type: "number",
value: 18,
min: 0
}
];
}
/**
@@ -33,7 +40,7 @@ class MD2 extends Operation {
* @returns {string}
*/
run(input, args) {
return runHash("md2", input);
return runHash("md2", input, {rounds: args[0]});
}
}

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