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

Compare commits

..

179 Commits

Author SHA1 Message Date
n1474335
4563c86acd 9.24.5 2021-02-09 14:24:08 +00:00
n1474335
0a59f8068e Merge branch 'aussieklutz-master' 2021-02-09 14:23:18 +00:00
n1474335
24548e3a48 Tidied up JWT tests 2021-02-09 14:23:02 +00:00
n1474335
f4784d49e7 Merge branch 'master' of https://github.com/aussieklutz/CyberChef into aussieklutz-master 2021-02-09 14:16:36 +00:00
n1474335
14d5069c6e Merge branch 'mt3571-1073-jwt-verify' 2021-02-09 14:15:12 +00:00
n1474335
9fdd55c5c6 Tidied up JWT ops 2021-02-09 14:14:59 +00:00
n1474335
5bc523aeff Merge branch '1073-jwt-verify' of https://github.com/mt3571/CyberChef into mt3571-1073-jwt-verify 2021-02-09 14:02:21 +00:00
n1474335
3ae2e2e2c8 Fixed highlighting of op names where only the description has hit 2021-02-09 11:50:20 +00:00
n1474335
83e49da7f6 Fixed description hiighlighting issue 2021-02-09 11:37:25 +00:00
n1474335
fe6df8778f Fixed year in CHANGELOG records. Closes #1168 2021-02-09 11:26:00 +00:00
aussieklutz
d5a0adea0c Update JWTVerify.mjs 2021-02-06 18:35:46 +10:00
aussieklutz
1bcb8e433d Update JWTVerify.mjs 2021-02-06 18:10:54 +10:00
aussieklutz
fa05cf1d78 Update JWTVerify.mjs
Enabled ESRSA verification.
2021-02-06 17:58:49 +10:00
aussieklutz
63dff0d34d Update JWTVerify.mjs
Enabled validation of ECSHA256 JWT tokens in the tests
2021-02-06 17:55:44 +10:00
aussieklutz
e228b197f9 Update JWTVerify.mjs 2021-02-06 17:45:42 +10:00
aussieklutz
4bbeb6caa3 Update JWTVerify.mjs
Add expectation for working RSASHA256 test, and comment out unused privatekey.
2021-02-06 17:42:42 +10:00
aussieklutz
139d25dff9 Update JWTVerify.mjs
Update RSASHA256 test with the public key derived from the pre-existing private key, and expect a working testcase.
2021-02-06 17:40:04 +10:00
aussieklutz
6984258404 Update JWTVerify.mjs
Enable verification of RSASHA256 and 512 tokens
2021-02-06 17:27:54 +10:00
n1474335
ba66fd6546 Fixed recursive matching arguments 2021-02-05 19:04:27 +00:00
n1474335
47bbefd81f Fixed recursive scoring results in fuzzy match lib 2021-02-05 18:24:15 +00:00
n1474335
50f796049c Fixed search test 2021-02-05 18:07:20 +00:00
n1474335
618da545b1 9.24.4 2021-02-05 17:55:10 +00:00
n1474335
21236f1938 Added fuzzy search for operations 2021-02-05 17:54:57 +00:00
n1474335
4169a15066 9.24.3 2021-02-03 19:07:46 +00:00
n1474335
6b10f61e11 Moved postinstall script to a Grunt task to fix relative calls. npm scripts now use local grunt install. 2021-02-03 19:07:39 +00:00
n1474335
83f119f7e4 9.24.2 2021-02-03 17:54:57 +00:00
n1474335
041c899a35 Comments are now treated as disabled so that they do not interfere with the Dish type. Closes #1126 and #1132. Thanks to @mt3571 for the suggestion. 2021-02-03 17:54:49 +00:00
n1474335
5412fc01b3 Merge branch 'Prinzhorn-base_64_order' 2021-02-02 17:36:23 +00:00
n1474335
76926d9252 Merge branch 'base_64_order' of https://github.com/Prinzhorn/CyberChef into Prinzhorn-base_64_order 2021-02-02 17:36:10 +00:00
n1474335
3270961574 Merge branch 'n1073645-microsoftDecoderMagic' 2021-02-02 17:29:41 +00:00
n1474335
9a1ef71aec Merge branch 'microsoftDecoderMagic' of https://github.com/n1073645/CyberChef into n1073645-microsoftDecoderMagic 2021-02-02 17:29:25 +00:00
n1474335
ba878925ad Merge branch 'Prinzhorn-boolean_args' 2021-02-02 17:23:23 +00:00
n1474335
8d6b71bfaa Merge branch 'boolean_args' of https://github.com/Prinzhorn/CyberChef into Prinzhorn-boolean_args 2021-02-02 17:23:05 +00:00
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
mt3571
887ea0cf06 Changed an incorrect name 2020-12-01 13:49:34 +00:00
mt3571
3e0525ee9e Added in a new file to store the list of JWT algorithms that can be used, as this error was occurring due to a mismatch between what you could sign and what you could verify 2020-12-01 13:38:01 +00: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
Alexander Prinzhorn
cb8fe42c66 Put Base64 after Base62 2020-04-16 10:20:38 +02:00
Alexander Prinzhorn
7f4b2574b0 Use proper booleans instead of relying on truthy/falsy values 2020-04-16 09:59:43 +02: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
n1073645
1f0fddd0e9 Added magic signature to Microsoft Script Decoder 2020-04-07 10:33:15 +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
Jarrod Connolly
462f619f43 Update JavaScript Minify operation to support ES6. 2019-10-31 23:18:54 -07: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
131 changed files with 7928 additions and 6159 deletions

View File

@@ -63,7 +63,8 @@
}],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", {
"avoidEscape": true
"avoidEscape": true,
"allowTemplateLiterals": true
}],
"camelcase": ["error", {
"properties": "always"

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

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

@@ -0,0 +1,56 @@
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
body: "See the [CHANGELOG](https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md) and [commit messages](https://github.com/gchq/CyberChef/commits/master) for details."
- 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,55 +0,0 @@
language: node_js
node_js:
- lts/dubnium
cache: npm
os: linux
addons:
chrome: stable
install: npm install
before_script:
- npm install -g grunt
- export NODE_OPTIONS=--max_old_space_size=2048
script:
- grunt lint
- npm 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
edge: true
token: $GITHUB_TOKEN
local_dir: build/prod/
target_branch: gh-pages
on:
repo: gchq/CyberChef
branch: master
- provider: releases
edge: true
token:
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
edge: true
email: "n1474335@gmail.com"
api_token:
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,30 @@
# 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] - 2021-02-02
- 'SM3' hashing function added along with more configuration options for other hashing operations [@n1073645] [@n1474335] | [#1022]
### [9.23.0] - 2021-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]
@@ -224,6 +247,10 @@ 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
@@ -323,6 +350,7 @@ All major and minor version changes will be documented in this file. Details of
[@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
@@ -384,6 +412,7 @@ 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
@@ -395,3 +424,6 @@ All major and minor version changes will be documented in this file. Details of
[#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

@@ -78,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");
@@ -197,18 +196,6 @@ 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: webpackProdConf(),
@@ -302,7 +289,7 @@ module.exports = function (grunt) {
},
files: [
{
src: "build/prod/index.html",
src: ["build/prod/index.html"],
dest: "build/prod/index.html"
}
]
@@ -324,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`
}
]
@@ -424,6 +411,16 @@ module.exports = function (grunt) {
]),
stdout: false,
},
fixCryptoApiImports: {
command: [
`[[ "$OSTYPE" == "darwin"* ]]`,
"&&",
`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'`,
"||",
`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'`
].join(" "),
stdout: false
}
},
});
};

10308
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.20.3",
"version": "9.24.5",
"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,135 +36,143 @@
"node >= 10"
],
"devDependencies": {
"@babel/core": "^7.8.7",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/preset-env": "^7.8.7",
"autoprefixer": "^9.7.4",
"@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.0.6",
"babel-plugin-dynamic-import-node": "^2.3.0",
"chromedriver": "^80.0.1",
"cli-progress": "^3.6.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": "^5.1.1",
"css-loader": "^3.4.2",
"eslint": "^6.8.0",
"exports-loader": "^0.7.0",
"file-loader": "^6.0.0",
"grunt": "^1.1.0",
"grunt-accessibility": "~6.0.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.1.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.9.0",
"nightwatch": "^1.3.4",
"node-sass": "^4.13.1",
"postcss-css-variables": "^0.14.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"prompt": "^1.0.0",
"sass-loader": "^8.0.2",
"sitemap": "^6.1.0",
"style-loader": "^1.1.3",
"svg-url-loader": "^5.0.0",
"url-loader": "^4.0.0",
"webpack": "^4.42.0",
"webpack-bundle-analyzer": "^3.6.1",
"webpack-dev-server": "^3.10.3",
"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.8.7",
"@babel/runtime": "^7.8.7",
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.12.5",
"arrive": "^2.4.1",
"avsc": "^5.4.19",
"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.4.1",
"bootstrap": "4.6.0",
"bootstrap-colorpicker": "^3.2.0",
"bootstrap-material-design": "^4.1.2",
"bson": "^4.0.3",
"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.6.4",
"core-js": "^3.8.3",
"crypto-api": "^0.8.5",
"crypto-browserify": "^3.12.0",
"crypto-js": "^4.0.0",
"ctph.js": "0.0.5",
"d3": "^5.15.0",
"d3": "^6.5.0",
"d3-hexbin": "^0.2.2",
"diff": "^4.0.2",
"es6-promisify": "^6.1.0",
"escodegen": "^1.14.1",
"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.18.1",
"jimp": "^0.9.5",
"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.13",
"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.7",
"libyara-wasm": "^1.1.0",
"lodash": "^4.17.20",
"loglevel": "^1.7.1",
"loglevel-message-prefix": "^3.0.0",
"markdown-it": "^10.0.0",
"moment": "^2.24.0",
"moment-timezone": "^0.5.28",
"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.4.0",
"notepack.io": "^2.3.0",
"nwmatcher": "^1.4.4",
"otp": "^0.1.3",
"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.10.2",
"split.js": "^1.5.11",
"sortablejs": "^1.13.0",
"split.js": "^1.6.2",
"ssdeep.js": "0.0.2",
"tesseract.js": "^2.0.2",
"ua-parser-js": "^0.7.21",
"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.3.0",
"xpath": "0.0.27",
"xregexp": "^4.3.0",
"xmldom": "^0.4.0",
"xpath": "0.0.32",
"xregexp": "^4.4.1",
"zlibjs": "^0.3.1"
},
"scripts": {
"start": "grunt dev",
"build": "grunt prod",
"start": "npx grunt dev",
"build": "npx grunt prod",
"repl": "node src/node/repl.js",
"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",
"test": "npx 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": "npx grunt testnodeconsumer",
"testui": "npx grunt testui",
"testuidev": "npx nightwatch --env=dev",
"lint": "grunt lint",
"lint": "npx grunt lint",
"postinstall": "npx grunt exec:fixCryptoApiImports",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
}
}

View File

@@ -46,7 +46,7 @@ class Recipe {
module: OperationConfig[c.op].module,
ingValues: c.args,
breakpoint: c.breakpoint,
disabled: c.disabled,
disabled: c.disabled || c.op === "Comment",
});
});
}

View File

@@ -18,15 +18,15 @@
"From Binary",
"To Octal",
"From Octal",
"To Base64",
"From Base64",
"Show Base64 offsets",
"To Base32",
"From Base32",
"To Base58",
"From Base58",
"To Base62",
"From Base62",
"To Base64",
"From Base64",
"Show Base64 offsets",
"To Base85",
"From Base85",
"To Base",
@@ -134,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"
]
},
@@ -200,6 +205,7 @@
"ops": [
"Encode text",
"Decode text",
"Unicode Text Format",
"Remove Diacritics",
"Unescape Unicode Characters",
"Convert to NATO alphabet"
@@ -313,6 +319,7 @@
"SHA1",
"SHA2",
"SHA3",
"SM3",
"Keccak",
"Shake",
"RIPEMD",

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

@@ -0,0 +1,219 @@
/**
* LICENSE
*
* This software is dual-licensed to the public domain and under the following
* license: you are granted a perpetual, irrevocable license to copy, modify,
* publish, and distribute this file as you see fit.
*
* VERSION
* 0.1.0 (2016-03-28) Initial release
*
* AUTHOR
* Forrest Smith
*
* CONTRIBUTORS
* J<>rgen Tjern<72> - async helper
* Anurag Awasthi - updated to 0.2.0
*/
const SEQUENTIAL_BONUS = 15; // bonus for adjacent matches
const SEPARATOR_BONUS = 30; // bonus if match occurs after a separator
const CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower
const FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched
const LEADING_LETTER_PENALTY = -5; // penalty applied for every letter in str before the first match
const MAX_LEADING_LETTER_PENALTY = -15; // maximum penalty for leading letters
const UNMATCHED_LETTER_PENALTY = -1;
/**
* Does a fuzzy search to find pattern inside a string.
* @param {*} pattern string pattern to search for
* @param {*} str string string which is being searched
* @returns [boolean, number] a boolean which tells if pattern was
* found or not and a search score
*/
export function fuzzyMatch(pattern, str) {
const recursionCount = 0;
const recursionLimit = 10;
const matches = [];
const maxMatches = 256;
return fuzzyMatchRecursive(
pattern,
str,
0 /* patternCurIndex */,
0 /* strCurrIndex */,
null /* srcMatces */,
matches,
maxMatches,
0 /* nextMatch */,
recursionCount,
recursionLimit
);
}
/**
* Recursive helper function
*/
function fuzzyMatchRecursive(
pattern,
str,
patternCurIndex,
strCurrIndex,
srcMatches,
matches,
maxMatches,
nextMatch,
recursionCount,
recursionLimit
) {
let outScore = 0;
// Return if recursion limit is reached.
if (++recursionCount >= recursionLimit) {
return [false, outScore, []];
}
// Return if we reached ends of strings.
if (patternCurIndex === pattern.length || strCurrIndex === str.length) {
return [false, outScore, []];
}
// Recursion params
let recursiveMatch = false;
let bestRecursiveMatches = [];
let bestRecursiveScore = 0;
// Loop through pattern and str looking for a match.
let firstMatch = true;
while (patternCurIndex < pattern.length && strCurrIndex < str.length) {
// Match found.
if (
pattern[patternCurIndex].toLowerCase() === str[strCurrIndex].toLowerCase()
) {
if (nextMatch >= maxMatches) {
return [false, outScore, []];
}
if (firstMatch && srcMatches) {
matches = [...srcMatches];
firstMatch = false;
}
const [matched, recursiveScore, recursiveMatches] = fuzzyMatchRecursive(
pattern,
str,
patternCurIndex,
strCurrIndex + 1,
matches,
recursiveMatches,
maxMatches,
nextMatch,
recursionCount,
recursionLimit
);
if (matched) {
// Pick best recursive score.
if (!recursiveMatch || recursiveScore > bestRecursiveScore) {
bestRecursiveMatches = [...recursiveMatches];
bestRecursiveScore = recursiveScore;
}
recursiveMatch = true;
}
matches[nextMatch++] = strCurrIndex;
++patternCurIndex;
}
++strCurrIndex;
}
const matched = patternCurIndex === pattern.length;
if (matched) {
outScore = 100;
// Apply leading letter penalty
let penalty = LEADING_LETTER_PENALTY * matches[0];
penalty =
penalty < MAX_LEADING_LETTER_PENALTY ?
MAX_LEADING_LETTER_PENALTY :
penalty;
outScore += penalty;
// Apply unmatched penalty
const unmatched = str.length - nextMatch;
outScore += UNMATCHED_LETTER_PENALTY * unmatched;
// Apply ordering bonuses
for (let i = 0; i < nextMatch; i++) {
const currIdx = matches[i];
if (i > 0) {
const prevIdx = matches[i - 1];
if (currIdx === prevIdx + 1) {
outScore += SEQUENTIAL_BONUS;
}
}
// Check for bonuses based on neighbor character value.
if (currIdx > 0) {
// Camel case
const neighbor = str[currIdx - 1];
const curr = str[currIdx];
if (
neighbor !== neighbor.toUpperCase() &&
curr !== curr.toLowerCase()
) {
outScore += CAMEL_BONUS;
}
const isNeighbourSeparator = neighbor === "_" || neighbor === " ";
if (isNeighbourSeparator) {
outScore += SEPARATOR_BONUS;
}
} else {
// First letter
outScore += FIRST_LETTER_BONUS;
}
}
// Return best result
if (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {
// Recursive score is better than "this"
matches = bestRecursiveMatches;
outScore = bestRecursiveScore;
return [true, outScore, matches];
} else if (matched) {
// "this" score is better than recursive
return [true, outScore, matches];
} else {
return [false, outScore, matches];
}
}
return [false, outScore, matches];
}
/**
* Turns a list of match indexes into a list of match ranges
*
* @author n1474335 [n1474335@gmail.com]
* @param [number] matches
* @returns [[number]]
*/
export function calcMatchRanges(matches) {
const ranges = [];
let start = matches[0],
curr = start;
matches.forEach(m => {
if (m === curr || m === curr + 1) curr = m;
else {
ranges.push([start, curr - start + 1]);
start = m;
curr = m;
}
});
ranges.push([start, curr - start + 1]);
return ranges;
}

24
src/core/lib/JWT.mjs Normal file
View File

@@ -0,0 +1,24 @@
/**
* JWT resources
*
* @author mt3571 [mt3571@protonmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
/**
* List of the JWT algorithms that can be used
*/
export const JWT_ALGORITHMS = [
"HS256",
"HS384",
"HS512",
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
"None"
];

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

@@ -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

@@ -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

@@ -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

@@ -125,7 +125,8 @@ class Colossus extends Operation {
},
{
name: "R1-Negate",
type: "boolean"
type: "boolean",
value: false
},
{
name: "R1-Counter",
@@ -164,7 +165,8 @@ class Colossus extends Operation {
},
{
name: "R2-Negate",
type: "boolean"
type: "boolean",
value: false
},
{
name: "R2-Counter",
@@ -203,7 +205,8 @@ class Colossus extends Operation {
},
{
name: "R3-Negate",
type: "boolean"
type: "boolean",
value: false
},
{
name: "R3-Counter",
@@ -212,7 +215,8 @@ class Colossus extends Operation {
},
{
name: "Negate All",
type: "boolean"
type: "boolean",
value: false
},
{
name: "K Rack: Addition",
@@ -220,23 +224,28 @@ class Colossus extends Operation {
},
{
name: "Add-Q1",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q2",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q3",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q4",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q5",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Equals",
@@ -246,11 +255,13 @@ class Colossus extends Operation {
},
{
name: "Add-Counter1",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add Negate All",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Total Motor",

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

@@ -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

@@ -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

@@ -27,7 +27,7 @@ class ExtractDomains extends Operation {
{
"name": "Display total",
"type": "boolean",
"value": "Extract.DISPLAY_TOTAL"
"value": true
}
];
}

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";
@@ -38,7 +38,7 @@ class ExtractFiles extends Operation {
{
name: "Ignore failed extractions",
type: "boolean",
value: "true"
value: true
}
]);
}

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

@@ -30,7 +30,7 @@ class FrequencyDistribution extends Operation {
{
"name": "Show 0%s",
"type": "boolean",
"value": "Entropy.FREQ_ZEROS"
"value": true
}
];
}

View File

@@ -31,6 +31,11 @@ class FromBinary extends Operation {
"name": "Delimiter",
"type": "option",
"value": BIN_DELIM_OPTIONS
},
{
"name": "Byte Length",
"type": "number",
"value": 8
}
];
this.checks = [
@@ -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

@@ -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

@@ -7,10 +7,11 @@
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import {isImage} from "../lib/FileType";
import {toBase64} from "../lib/Base64";
import jimp from "jimp";
import {isWorkerEnvironment} from "../Utils";
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

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

@@ -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

@@ -3,10 +3,11 @@
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import jwt from "jsonwebtoken";
import OperationError from "../errors/OperationError.mjs";
import {JWT_ALGORITHMS} from "../lib/JWT.mjs";
/**
* JWT Sign operation
@@ -34,18 +35,7 @@ class JWTSign extends Operation {
{
name: "Signing algorithm",
type: "option",
value: [
"HS256",
"HS384",
"HS512",
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
"None"
]
value: JWT_ALGORITHMS
}
];
}

View File

@@ -3,10 +3,11 @@
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import jwt from "jsonwebtoken";
import OperationError from "../errors/OperationError.mjs";
import {JWT_ALGORITHMS} from "../lib/JWT.mjs";
/**
* JWT Verify operation
@@ -27,7 +28,7 @@ class JWTVerify extends Operation {
this.outputType = "JSON";
this.args = [
{
name: "Private/Secret Key",
name: "Public/Secret Key",
type: "text",
value: "secret"
},
@@ -41,14 +42,11 @@ class JWTVerify extends Operation {
*/
run(input, args) {
const [key] = args;
const algos = JWT_ALGORITHMS;
algos[algos.indexOf("None")] = "none";
try {
const verified = jwt.verify(input, key, { algorithms: [
"HS256",
"HS384",
"HS512",
"none"
]});
const verified = jwt.verify(input, key, { algorithms: algos });
if (Object.prototype.hasOwnProperty.call(verified, "name") && verified.name === "JsonWebTokenError") {
throw new OperationError(verified.message);

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

@@ -60,7 +60,8 @@ class Lorenz extends Operation {
},
{
name: "KT-Schalter",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Mode",

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]});
}
}

View File

@@ -24,6 +24,13 @@ class MicrosoftScriptDecoder extends Operation {
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.checks = [
{
pattern: "#@~\\^.{6}==(.+).{6}==\\^#~@",
flags: "i",
args: []
}
];
}
/**

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;
/**
* Normalise Image operation

View File

@@ -51,7 +51,7 @@ class NormaliseUnicode extends Operation {
case "NFKD":
return unorm.nfkd(input);
case "NFKC":
return unorm.nfc(input);
return unorm.nfkc(input);
default:
throw new OperationError("Unknown Normalisation Form");
}

View File

@@ -1,6 +1,7 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @author mshwed [m@ttshwed.com]
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
@@ -12,7 +13,7 @@ import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import Tesseract from "tesseract.js";
const { TesseractWorker } = Tesseract;
const { createWorker } = Tesseract;
import process from "process";
@@ -60,23 +61,30 @@ class OpticalCharacterRecognition extends Operation {
const assetDir = isWorkerEnvironment() ? `${self.docURL}/assets/` : `${process.cwd()}/src/core/vendor/`;
try {
self.sendStatusMessage("Spinning up Tesseract worker...");
const image = `data:${type};base64,${toBase64(input)}`;
const worker = new TesseractWorker({
const worker = createWorker({
workerPath: `${assetDir}tesseract/worker.min.js`,
langPath: `${assetDir}tesseract/lang-data`,
corePath: `${assetDir}tesseract/tesseract-core.wasm.js`,
});
const result = await worker.recognize(image)
.progress(progress => {
logger: progress => {
if (isWorkerEnvironment()) {
self.sendStatusMessage(`Status: ${progress.status} - ${(parseFloat(progress.progress)*100).toFixed(2)}%`);
self.sendStatusMessage(`Status: ${progress.status}${progress.status === "recognizing text" ? ` - ${(parseFloat(progress.progress)*100).toFixed(2)}%`: "" }`);
}
});
}
});
await worker.load();
self.sendStatusMessage("Loading English language...");
await worker.loadLanguage("eng");
self.sendStatusMessage("Intialising Tesseract API...");
await worker.initialize("eng");
self.sendStatusMessage("Finding text...");
const result = await worker.recognize(image);
if (showConfidence) {
return `Confidence: ${result.confidence}%\n\n${result.text}`;
return `Confidence: ${result.data.confidence}%\n\n${result.data.text}`;
} else {
return result.text;
return result.data.text;
}
} catch (err) {
throw new OperationError(`Error performing OCR on image. (${err})`);

View File

@@ -72,7 +72,7 @@ class ParseDateTime extends Operation {
"\nLeap year: " + date.isLeapYear() +
"\nDays in this month: " + date.daysInMonth() +
"\n\nDay of year: " + date.dayOfYear() +
"\nWeek number: " + date.weekYear() +
"\nWeek number: " + date.week() +
"\nQuarter: " + date.quarter();
return output;

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 BigNumber from "bignumber.js";
import { isWorkerEnvironment } from "../Utils.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";
/**
* RC2 Decrypt operation

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";
/**

View File

@@ -35,6 +35,11 @@ class ROT13 extends Operation {
type: "boolean",
value: true
},
{
name: "Rotate numbers",
type: "boolean",
value: false
},
{
name: "Amount",
type: "number",
@@ -51,8 +56,9 @@ class ROT13 extends Operation {
run(input, args) {
const output = input,
rot13Lowercase = args[0],
rot13Upperacse = args[1];
let amount = args[2],
rot13Upperacse = args[1],
rotNumbers = args[2];
let amount = args[3],
chr;
if (amount) {
@@ -68,6 +74,9 @@ class ROT13 extends Operation {
} else if (rot13Lowercase && chr >= 97 && chr <= 122) { // Lower case
chr = (chr - 97 + amount) % 26;
output[i] = chr + 97;
} else if (rotNumbers && chr >= 48 && chr <= 57) { // Numbers
chr = (chr - 48 + amount) % 10;
output[i] = chr + 48;
}
}
}

View File

@@ -0,0 +1,86 @@
/**
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import forge from "node-forge";
import { MD_ALGORITHMS } from "../lib/RSA.mjs";
/**
* RSA Decrypt operation
*/
class RSADecrypt extends Operation {
/**
* RSADecrypt constructor
*/
constructor() {
super();
this.name = "RSA Decrypt";
this.module = "Ciphers";
this.description = "Decrypt an RSA encrypted message with a PEM encoded private key.";
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "RSA Private Key (PEM)",
type: "text",
value: "-----BEGIN RSA PRIVATE KEY-----"
},
{
name: "Key Password",
type: "text",
value: ""
},
{
name: "Encryption Scheme",
type: "argSelector",
value: [
{
name: "RSA-OAEP",
on: [3]
},
{
name: "RSAES-PKCS1-V1_5",
off: [3]
},
{
name: "RAW",
off: [3]
}]
},
{
name: "Message Digest Algorithm",
type: "option",
value: Object.keys(MD_ALGORITHMS)
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [pemKey, password, scheme, md] = args;
if (pemKey.replace("-----BEGIN RSA PRIVATE KEY-----", "").length === 0) {
throw new OperationError("Please enter a private key.");
}
try {
const privKey = forge.pki.decryptRsaPrivateKey(pemKey, password);
const dMsg = privKey.decrypt(input, scheme, {md: MD_ALGORITHMS[md].create()});
return forge.util.decodeUtf8(dMsg);
} catch (err) {
throw new OperationError(err);
}
}
}
export default RSADecrypt;

View File

@@ -0,0 +1,89 @@
/**
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import forge from "node-forge";
import { MD_ALGORITHMS } from "../lib/RSA.mjs";
/**
* RSA Encrypt operation
*/
class RSAEncrypt extends Operation {
/**
* RSAEncrypt constructor
*/
constructor() {
super();
this.name = "RSA Encrypt";
this.module = "Ciphers";
this.description = "Encrypt a message with a PEM encoded RSA public key.";
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "RSA Public Key (PEM)",
type: "text",
value: "-----BEGIN RSA PUBLIC KEY-----"
},
{
name: "Encryption Scheme",
type: "argSelector",
value: [
{
name: "RSA-OAEP",
on: [2]
},
{
name: "RSAES-PKCS1-V1_5",
off: [2]
},
{
name: "RAW",
off: [2]
}]
},
{
name: "Message Digest Algorithm",
type: "option",
value: Object.keys(MD_ALGORITHMS)
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [pemKey, scheme, md] = args;
if (pemKey.replace("-----BEGIN RSA PUBLIC KEY-----", "").length === 0) {
throw new OperationError("Please enter a public key.");
}
try {
// Load public key
const pubKey = forge.pki.publicKeyFromPem(pemKey);
// https://github.com/digitalbazaar/forge/issues/465#issuecomment-271097600
const plaintextBytes = forge.util.encodeUtf8(input);
// Encrypt message
const eMsg = pubKey.encrypt(plaintextBytes, scheme, {md: MD_ALGORITHMS[md].create()});
return eMsg;
} catch (err) {
if (err.message === "RSAES-OAEP input message length is too long.") {
throw new OperationError(`RSAES-OAEP input message length (${err.length}) is longer than the maximum allowed length (${err.maxLength}).`);
}
throw new OperationError(err);
}
}
}
export default RSAEncrypt;

View File

@@ -0,0 +1,74 @@
/**
* @author Matt C [me@mitt.dev]
* @author gchq77703 []
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import forge from "node-forge";
import { MD_ALGORITHMS } from "../lib/RSA.mjs";
/**
* RSA Sign operation
*/
class RSASign extends Operation {
/**
* RSASign constructor
*/
constructor() {
super();
this.name = "RSA Sign";
this.module = "Ciphers";
this.description = "Sign a plaintext message with a PEM encoded RSA key.";
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "RSA Private Key (PEM)",
type: "text",
value: "-----BEGIN RSA PRIVATE KEY-----"
},
{
name: "Key Password",
type: "text",
value: ""
},
{
name: "Message Digest Algorithm",
type: "option",
value: Object.keys(MD_ALGORITHMS)
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [key, password, mdAlgo] = args;
if (key.replace("-----BEGIN RSA PRIVATE KEY-----", "").length === 0) {
throw new OperationError("Please enter a private key.");
}
try {
const privateKey = forge.pki.decryptRsaPrivateKey(key, password);
// Generate message hash
const md = MD_ALGORITHMS[mdAlgo].create();
md.update(input, "utf8");
// Sign message hash
const sig = privateKey.sign(md);
return sig;
} catch (err) {
throw new OperationError(err);
}
}
}
export default RSASign;

View File

@@ -0,0 +1,77 @@
/**
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import forge from "node-forge";
import { MD_ALGORITHMS } from "../lib/RSA.mjs";
/**
* RSA Verify operation
*/
class RSAVerify extends Operation {
/**
* RSAVerify constructor
*/
constructor() {
super();
this.name = "RSA Verify";
this.module = "Ciphers";
this.description = "Verify a message against a signature and a public PEM encoded RSA key.";
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "RSA Public Key (PEM)",
type: "text",
value: "-----BEGIN RSA PUBLIC KEY-----"
},
{
name: "Message",
type: "text",
value: ""
},
{
name: "Message Digest Algorithm",
type: "option",
value: Object.keys(MD_ALGORITHMS)
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [pemKey, message, mdAlgo] = args;
if (pemKey.replace("-----BEGIN RSA PUBLIC KEY-----", "").length === 0) {
throw new OperationError("Please enter a public key.");
}
try {
// Load public key
const pubKey = forge.pki.publicKeyFromPem(pemKey);
// Generate message digest
const md = MD_ALGORITHMS[mdAlgo].create();
md.update(message, "utf8");
// Compare signed message digest and generated message digest
const result = pubKey.verify(md.digest().bytes(), input);
return result ? "Verified OK" : "Verification Failure";
} catch (err) {
if (err.message === "Encrypted message length is invalid.") {
throw new OperationError(`Signature length (${err.length}) does not match expected length based on key (${err.expected}).`);
}
throw new OperationError(err);
}
}
}
export default RSAVerify;

View File

@@ -46,7 +46,7 @@ class RailFenceCipherDecode extends Operation {
run(input, args) {
const [key, offset] = args;
let cipher = input;
const cipher = input;
if (key < 2) {
throw new OperationError("Key has to be bigger than 2");
@@ -59,13 +59,6 @@ class RailFenceCipherDecode extends Operation {
}
const cycle = (key - 1) * 2;
const rest = cipher.length % key;
if (rest !== 0) {
cipher = cipher + (" ".repeat(key - rest));
}
const plaintext = new Array(cipher.length);
let j = 0;

View File

@@ -10,7 +10,8 @@ import Utils from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs";
import { runHash } from "../lib/Hash.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import jimp from "jimp";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
/**
* Randomize Colour Palette operation

View File

@@ -19,7 +19,7 @@ class RemoveDiacritics extends Operation {
this.name = "Remove Diacritics";
this.module = "Default";
this.description = "Replaces accented characters with their latin character equivalent.";
this.description = "Replaces accented characters with their latin character equivalent. Accented characters are made up of Unicode combining characters, so unicode text formatting such as strikethroughs and underlines will also be removed.";
this.infoURL = "https://wikipedia.org/wiki/Diacritic";
this.inputType = "string";
this.outputType = "string";

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;
/**
* Resize 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;
/**
* Rotate Image operation

View File

@@ -20,11 +20,18 @@ class SHA0 extends Operation {
this.name = "SHA0";
this.module = "Crypto";
this.description = "SHA-0 is a retronym applied to the original version of the 160-bit hash function published in 1993 under the name 'SHA'. It was withdrawn shortly after publication due to an undisclosed 'significant flaw' and replaced by the slightly revised version SHA-1.";
this.description = "SHA-0 is a retronym applied to the original version of the 160-bit hash function published in 1993 under the name 'SHA'. It was withdrawn shortly after publication due to an undisclosed 'significant flaw' and replaced by the slightly revised version SHA-1. The message digest algorithm consists, by default, of 80 rounds.";
this.infoURL = "https://wikipedia.org/wiki/SHA-1#SHA-0";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [];
this.args = [
{
name: "Rounds",
type: "number",
value: 80,
min: 16
}
];
}
/**
@@ -33,7 +40,7 @@ class SHA0 extends Operation {
* @returns {string}
*/
run(input, args) {
return runHash("sha0", input);
return runHash("sha0", input, {rounds: args[0]});
}
}

View File

@@ -20,11 +20,18 @@ class SHA1 extends Operation {
this.name = "SHA1";
this.module = "Crypto";
this.description = "The SHA (Secure Hash Algorithm) hash functions were designed by the NSA. SHA-1 is the most established of the existing SHA hash functions and it is used in a variety of security applications and protocols.<br><br>However, SHA-1's collision resistance has been weakening as new attacks are discovered or improved.";
this.description = "The SHA (Secure Hash Algorithm) hash functions were designed by the NSA. SHA-1 is the most established of the existing SHA hash functions and it is used in a variety of security applications and protocols.<br><br>However, SHA-1's collision resistance has been weakening as new attacks are discovered or improved. The message digest algorithm consists, by default, of 80 rounds.";
this.infoURL = "https://wikipedia.org/wiki/SHA-1";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [];
this.args = [
{
name: "Rounds",
type: "number",
value: 80,
min: 16
}
];
}
/**
@@ -33,7 +40,7 @@ class SHA1 extends Operation {
* @returns {string}
*/
run(input, args) {
return runHash("sha1", input);
return runHash("sha1", input, {rounds: args[0]});
}
}

View File

@@ -20,15 +20,58 @@ class SHA2 extends Operation {
this.name = "SHA2";
this.module = "Crypto";
this.description = "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384 bytes.</li><li>SHA-224 is largely identical to SHA-256 but is truncated to 224 bytes.</li><li>SHA-512/224 and SHA-512/256 are truncated versions of SHA-512, but the initial values are generated using the method described in Federal Information Processing Standards (FIPS) PUB 180-4.</li></ul>";
this.description = "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384 bytes.</li><li>SHA-224 is largely identical to SHA-256 but is truncated to 224 bytes.</li><li>SHA-512/224 and SHA-512/256 are truncated versions of SHA-512, but the initial values are generated using the method described in Federal Information Processing Standards (FIPS) PUB 180-4.</li></ul> The message digest algorithm for SHA256 variants consists, by default, of 64 rounds, and for SHA512 variants, it is, by default, 160.";
this.infoURL = "https://wikipedia.org/wiki/SHA-2";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
"name": "Size",
"type": "option",
"value": ["512", "256", "384", "224", "512/256", "512/224"]
name: "Size",
type: "argSelector",
value: [
{
name: "512",
on: [2],
off: [1]
},
{
name: "384",
on: [2],
off: [1]
},
{
name: "256",
on: [1],
off: [2]
},
{
name: "224",
on: [1],
off: [2]
},
{
name: "512/256",
on: [2],
off: [1]
},
{
name: "512/224",
on: [2],
off: [1]
}
]
},
{
name: "Rounds", // For SHA256 variants
type: "number",
value: 64,
min: 16
},
{
name: "Rounds", // For SHA512 variants
type: "number",
value: 160,
min: 32
}
];
}
@@ -40,7 +83,8 @@ class SHA2 extends Operation {
*/
run(input, args) {
const size = args[0];
return runHash("sha" + size, input);
const rounds = (size === "256" || size === "224") ? args[1] : args[2];
return runHash("sha" + size, input, {rounds: rounds});
}
}

View File

@@ -0,0 +1,57 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import Sm3 from "crypto-api/src/hasher/sm3.mjs";
import {toHex} from "crypto-api/src/encoder/hex.mjs";
/**
* SM3 operation
*/
class SM3 extends Operation {
/**
* SM3 constructor
*/
constructor() {
super();
this.name = "SM3";
this.module = "Crypto";
this.description = "SM3 is a cryptographic hash function used in the Chinese National Standard. SM3 is mainly used in digital signatures, message authentication codes, and pseudorandom number generators. The message digest algorithm consists, by default, of 64 rounds and length of 256.";
this.infoURL = "https://wikipedia.org/wiki/SM3_(hash_function)";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
name: "Length",
type: "number",
value: 256
},
{
name: "Rounds",
type: "number",
value: 64,
min: 16
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const msg = Utils.arrayBufferToStr(input, false);
const hasher = new Sm3({length: args[0], rounds: args[1]});
hasher.update(msg);
return toHex(hasher.finalize());
}
}
export default SM3;

View File

@@ -21,7 +21,7 @@ class SSDEEP extends Operation {
this.name = "SSDEEP";
this.module = "Crypto";
this.description = "SSDEEP is a program for computing context triggered piecewise hashes (CTPH). Also called fuzzy hashes, CTPH 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>SSDEEP hashes are now widely used for simple identification purposes (e.g. the 'Basic Properties' section in VirusTotal). Although 'better' fuzzy hashes are available, SSDEEP is still one of the primary choices because of its speed and being a de facto standard.<br><br>This operation is fundamentally the same as the CTPH operation, however their outputs differ in format.";
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Ssdeep";
this.inputType = "string";
this.outputType = "string";
this.args = [];

View File

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

View File

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

View File

@@ -26,14 +26,17 @@ class Snefru extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Rounds",
"type": "option",
"value": ["8", "4", "2"]
name: "Size",
type: "number",
value: 128,
min: 32,
max: 480,
step: 32
},
{
"name": "Size",
"type": "option",
"value": ["256", "128"]
name: "Rounds",
type: "option",
value: ["8", "4", "2"]
}
];
}
@@ -45,8 +48,8 @@ class Snefru extends Operation {
*/
run(input, args) {
return runHash("snefru", input, {
rounds: args[0],
length: args[1]
length: args[0],
rounds: args[1]
});
}

View File

@@ -8,8 +8,8 @@ import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.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;
/**
* Split Colour Channels operation

View File

@@ -31,6 +31,11 @@ class ToBinary extends Operation {
"name": "Delimiter",
"type": "option",
"value": BIN_DELIM_OPTIONS
},
{
"name": "Byte Length",
"type": "number",
"value": 8
}
];
}
@@ -42,7 +47,8 @@ class ToBinary extends Operation {
*/
run(input, args) {
input = new Uint8Array(input);
return toBinary(input, args[0]);
const padding = args[1] ? args[1] : 8;
return toBinary(input, args[0], padding);
}
/**

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";
/**
* Triple 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";
/**
* Triple DES Encrypt operation

View File

@@ -34,7 +34,7 @@ class UNIXTimestampToWindowsFiletime extends Operation {
{
"name": "Output format",
"type": "option",
"value": ["Decimal", "Hex"]
"value": ["Decimal", "Hex (big endian)", "Hex (little endian)"]
}
];
}
@@ -65,11 +65,24 @@ class UNIXTimestampToWindowsFiletime extends Operation {
input = input.plus(new BigNumber("116444736000000000"));
if (format === "Hex") {
return input.toString(16);
let result;
if (format.startsWith("Hex")) {
result = input.toString(16);
} else {
return input.toFixed();
result = input.toFixed();
}
if (format === "Hex (little endian)") {
// Swap endianness
let flipped = "";
for (let i = result.length - 2; i >= 0; i -= 2) {
flipped += result.charAt(i);
flipped += result.charAt(i + 1);
}
result = flipped;
}
return result;
}
}

View File

@@ -0,0 +1,67 @@
/**
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
/**
* Unicode Text Format operation
*/
class UnicodeTextFormat extends Operation {
/**
* UnicodeTextFormat constructor
*/
constructor() {
super();
this.name = "Unicode Text Format";
this.module = "Default";
this.description = "Adds Unicode combining characters to change formatting of plaintext.";
this.infoURL = "https://wikipedia.org/wiki/Combining_character";
this.inputType = "byteArray";
this.outputType = "byteArray";
this.args = [
{
name: "Underline",
type: "boolean",
value: "false"
},
{
name: "Strikethrough",
type: "boolean",
value: "false"
}
];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
const [underline, strikethrough] = args;
let output = input.map(char => [char]);
if (strikethrough) {
output = output.map(charFormat => {
charFormat.push(...Utils.strToUtf8ByteArray("\u0336"));
return charFormat;
});
}
if (underline) {
output = output.map(charFormat => {
charFormat.push(...Utils.strToUtf8ByteArray("\u0332"));
return charFormat;
});
}
// return output.flat(); - Not supported in Node 10, polyfilled
return [].concat(...output);
}
}
export default UnicodeTextFormat;

View File

@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.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;
/**
* View Bit Plane operation

View File

@@ -26,9 +26,16 @@ class Whirlpool extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Variant",
"type": "option",
"value": ["Whirlpool", "Whirlpool-T", "Whirlpool-0"]
name: "Variant",
type: "option",
value: ["Whirlpool", "Whirlpool-T", "Whirlpool-0"]
},
{
name: "Rounds",
type: "number",
value: 10,
min: 1,
max: 10
}
];
}
@@ -40,7 +47,7 @@ class Whirlpool extends Operation {
*/
run(input, args) {
const variant = args[0].toLowerCase();
return runHash(variant, input);
return runHash(variant, input, {rounds: args[1]});
}
}

View File

@@ -34,7 +34,7 @@ class WindowsFiletimeToUNIXTimestamp extends Operation {
{
"name": "Input format",
"type": "option",
"value": ["Decimal", "Hex"]
"value": ["Decimal", "Hex (big endian)", "Hex (little endian)"]
}
];
}
@@ -49,7 +49,17 @@ class WindowsFiletimeToUNIXTimestamp extends Operation {
if (!input) return "";
if (format === "Hex") {
if (format === "Hex (little endian)") {
// Swap endianness
let result = "";
for (let i = input.length - 2; i >= 0; i -= 2) {
result += input.charAt(i);
result += input.charAt(i + 1);
}
input = result;
}
if (format.startsWith("Hex")) {
input = new BigNumber(input, 16);
} else {
input = new BigNumber(input);

View File

@@ -50,7 +50,19 @@ class XPathExpression extends Operation {
let doc;
try {
doc = new xmldom.DOMParser().parseFromString(input, "application/xml");
doc = new xmldom.DOMParser({
errorHandler: {
warning(w) {
throw w;
},
error(e) {
throw e;
},
fatalError(e) {
throw e;
}
}
}).parseFromString(input, "application/xml");
} catch (err) {
throw new OperationError("Invalid input XML.");
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -24,20 +24,30 @@ class NodeRecipe {
/**
* Validate an ingredient $ coerce to operation if necessary.
* Validate an ingredient & coerce to operation if necessary.
* @param {String | Function | Object} ing
* @returns {Function || Object} The operation, or an object with the
* operation and its arguments
* @throws {TypeError} If it cannot find the operation in chef's list of operations.
*/
_validateIngredient(ing) {
// CASE operation name given. Find operation and validate
if (typeof ing === "string") {
const op = operations.find((op) => {
return sanitise(op.opName) === sanitise(ing);
});
if (op) {
return op;
// Need to validate against case 2
return this._validateIngredient(op);
} else {
throw new TypeError(`Couldn't find an operation with name '${ing}'.`);
}
// CASE operation given. Check its a chef operation and check its not flowcontrol
} else if (typeof ing === "function") {
if (ing.flowControl) {
throw new TypeError(`flowControl operations like ${ing.opName} are not currently allowed in recipes for chef.bake in the Node API`);
}
if (operations.includes(ing)) {
return ing;
} else {
@@ -57,7 +67,7 @@ class NodeRecipe {
/**
* Parse config for recipe.
* Parse an opList from a recipeConfig and assign it to the recipe's opList.
* @param {String | Function | String[] | Function[] | [String | Function]} recipeConfig
*/
_parseConfig(recipeConfig) {

View File

@@ -177,6 +177,7 @@ export function _wrap(OpClass) {
// Check to see if class's run function is async.
const opInstance = new OpClass();
const isAsync = opInstance.run.constructor.name === "AsyncFunction";
const isFlowControl = opInstance.flowControl;
let wrapped;
@@ -191,7 +192,28 @@ export function _wrap(OpClass) {
*/
wrapped = async (input, args=null) => {
const {transformedInput, transformedArgs} = prepareOp(opInstance, input, args);
// SPECIAL CASE for Magic. Other flowControl operations will
// not work because the opList is not passed in.
if (isFlowControl) {
opInstance.ingValues = transformedArgs;
const state = {
progress: 0,
dish: ensureIsDish(transformedInput),
opList: [opInstance],
};
const updatedState = await opInstance.run(state);
return new NodeDish({
value: updatedState.dish.value,
type: opInstance.outputType,
});
}
const result = await opInstance.run(transformedInput, transformedArgs);
return new NodeDish({
value: result,
type: opInstance.outputType,
@@ -218,6 +240,8 @@ export function _wrap(OpClass) {
// used in chef.help
wrapped.opName = OpClass.name;
wrapped.args = createArgInfo(opInstance);
// Used in NodeRecipe to check for flowControl ops
wrapped.flowControl = isFlowControl;
return wrapped;
}
@@ -292,25 +316,18 @@ export function help(input) {
/**
* bake [Wrapped] - Perform an array of operations on some input.
* @returns {Function}
* bake
*
* @param {*} input - some input for a recipe.
* @param {String | Function | String[] | Function[] | [String | Function]} recipeConfig -
* An operation, operation name, or an array of either.
* @returns {NodeDish} of the result
* @throws {TypeError} if invalid recipe given.
*/
export function bake() {
/**
* bake
*
* @param {*} input - some input for a recipe.
* @param {String | Function | String[] | Function[] | [String | Function]} recipeConfig -
* An operation, operation name, or an array of either.
* @returns {SyncDish} of the result
* @throws {TypeError} if invalid recipe given.
*/
return function(input, recipeConfig) {
const recipe = new NodeRecipe(recipeConfig);
const dish = ensureIsDish(input);
return recipe.execute(dish);
};
export function bake(input, recipeConfig) {
const recipe = new NodeRecipe(recipeConfig);
const dish = ensureIsDish(input);
return recipe.execute(dish);
}

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