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

Compare commits

...

186 Commits

Author SHA1 Message Date
n1474335
445a85798b 8.22.1 2019-01-18 14:50:00 +00:00
n1474335
55775f48e9 Merge branch 'picapi-b64-description-fix' 2019-01-18 14:49:53 +00:00
Callum Fraser
4d8127a7d9 Modified description of ToBase64 operation
Addresses #472
2019-01-14 22:25:49 +00:00
n1474335
9787ab04cd 8.22.0 2019-01-10 15:44:02 +00:00
n1474335
79d3c90026 Merge branch 'j433866-subsection' 2019-01-10 15:43:05 +00:00
n1474335
c2068b343b Tidied up and added global matching to Subsection operation 2019-01-10 15:42:48 +00:00
n1474335
6424839731 Merge branch 'subsection' of https://github.com/j433866/CyberChef into j433866-subsection 2019-01-10 15:11:34 +00:00
n1474335
863a525625 8.21.0 2019-01-10 15:02:26 +00:00
n1474335
f82a727e24 Merge branch 'masq-insense' 2019-01-10 15:01:22 +00:00
n1474335
995fcab071 Tidied up Case Insensitive Regex ops 2019-01-10 15:01:01 +00:00
n1474335
c5270d75a1 Merge branch 'insense' of https://github.com/masq/CyberChef into masq-insense 2019-01-10 14:53:21 +00:00
n1474335
324c409ff1 8.20.0 2019-01-09 16:38:53 +00:00
n1474335
1db8e6dddc Merge branch 'klaxon1-feature/lorem-ipsum-generator' 2019-01-09 16:38:46 +00:00
n1474335
c49a770c59 Tidied up Lorem Ipsum op 2019-01-09 16:36:34 +00:00
n1474335
0e601d5b5f Merge branch 'feature/lorem-ipsum-generator' of https://github.com/klaxon1/CyberChef into klaxon1-feature/lorem-ipsum-generator 2019-01-09 14:50:48 +00:00
n1474335
fe1332f18e 8.19.7 2019-01-08 18:29:14 +00:00
n1474335
cb9ab7a2c9 Fixed 'Maximise output' button functionality 2019-01-08 18:29:07 +00:00
n1474335
3a6b2875d5 8.19.6 2019-01-08 17:51:47 +00:00
n1474335
766de7e6fa Fixed bug in 'Regular expression' operation when highlighting lookaheads 2019-01-08 17:51:43 +00:00
j433866
8ac5b48493 Update operation description 2019-01-08 11:51:33 +00:00
j433866
1a827ef44f Add Subsection to Flow Control category 2019-01-08 11:17:06 +00:00
j433866
0f0e346a02 Add new Subsection operation 2019-01-08 11:12:02 +00:00
n1474335
c82971f8db 8.19.5 2019-01-01 20:49:24 +00:00
n1474335
cb2c376c63 Increasing Node memory limit from 1G to 2G 2019-01-01 20:27:38 +00:00
n1474335
bc00fa0694 8.19.4 2019-01-01 20:15:29 +00:00
n1474335
c86007da71 Removed increase-memory-limit plugin in favour of NODE_OPTIONS environment variable. 2019-01-01 20:15:16 +00:00
n1474335
1bf513ca74 8.19.3 2019-01-01 19:56:20 +00:00
n1474335
29411c903f Added increase-memory-limit plugin to TravisCI build process to reduce 'JavaScript heap out of memory' errors. 2019-01-01 19:56:12 +00:00
n1474335
017dde364c 8.19.2 2019-01-01 19:22:10 +00:00
n1474335
c123d7370a Merge branch 'edwardwall-patch-2' 2019-01-01 19:21:11 +00:00
n1474335
76f1e5e8f3 Merge branch 'patch-2' of https://github.com/edwardwall/CyberChef into edwardwall-patch-2 2019-01-01 19:20:07 +00:00
n1474335
4e466c7886 8.19.1 2019-01-01 19:19:16 +00:00
n1474335
d469fb9c58 Updated dependencies 2019-01-01 19:19:07 +00:00
Edward Wall
050ab03448 Simplify to improve readability 2018-12-30 17:06:48 +00:00
Edward Wall
40acf751a8 Update to understand Generalized / UTC Time
Future proofing for when certificates with dates after 2049 begin being issued.
These certificates' dates will be in Generalized Time not UTC Time as per RFC 5280
2018-12-30 16:46:18 +00:00
Spencer Walden
126ad585c0 Registers tests for 'To/From Case Insensitive Regex' operations 2018-12-30 03:26:44 -08:00
Spencer Walden
1d04b649e0 Adds 'To/From Case Insensitive Regex' operations under 'Utils' 2018-12-30 03:26:44 -08:00
Spencer Walden
b750006cf0 Adds tests for 'To/From Case Insensitive Regex' operations 2018-12-30 03:26:44 -08:00
Spencer Walden
3c16b839b6 Adds 'From Case Insensitive Regex' operation 2018-12-30 03:26:44 -08:00
Spencer Walden
32aea6b86c Adds 'To Case Insensitive Regex' operation 2018-12-30 03:26:44 -08:00
Edward Wall
688c2d0df5 Update ParseX509Certificate.mjs 2018-12-30 03:15:07 +00:00
n1474335
0cea56dc62 8.19.0 2018-12-30 01:07:54 +00:00
n1474335
bb44268c30 Merge branch 'feature-browser-testsuite' 2018-12-30 01:07:42 +00:00
n1474335
19b3dcf1c2 Updated CHANGELOG 2018-12-30 01:07:26 +00:00
n1474335
71e0a4e0ce Increased UI test timeouts 2018-12-30 00:47:10 +00:00
n1474335
7f2e879e24 Added explicit bake after input added in test suite. 2018-12-30 00:37:44 +00:00
n1474335
840e44deac Tidied up UI tests 2018-12-30 00:26:28 +00:00
n1474335
f7707faece Added Chrome to TravisCI config 2018-12-30 00:02:41 +00:00
n1474335
b631e3fef6 Added nightwatch tests to TravisCI build process for prod and inline versions. 2018-12-29 23:46:13 +00:00
n1474335
b0fb9db4b8 Added nightwatch.js test suite for confirming that the app loads correctly and can run operations from each module. Currently only support the latest version of Chrome. 2018-12-29 02:58:05 +00:00
n1474335
c7e9115994 Restructured tests directory 2018-12-28 21:49:40 +00:00
Klaxon
f2d115ee4d add lorem ipsum generator 2018-12-29 00:44:59 +10:00
n1474335
a1b161493c 8.18.1 2018-12-26 16:50:36 +00:00
n1474335
5acee80463 'editableOption's are now full width. 'editableOptionShort' type added to replace the old style. 2018-12-26 16:50:32 +00:00
n1474335
e6932401ad 8.18.0 2018-12-26 16:35:34 +00:00
n1474335
7a4eff0f5c Merge branch 'artemisbot-features/colour-channel' 2018-12-26 16:33:26 +00:00
n1474335
8b533e9893 Tidied up 'Split Colour Channels' operation and added 'Multimedia' category 2018-12-26 16:33:10 +00:00
n1474335
02b92c7977 Merge branch 'features/colour-channel' of https://github.com/artemisbot/CyberChef into artemisbot-features/colour-channel 2018-12-26 16:10:44 +00:00
n1474335
e386863bdb 8.17.2 2018-12-26 00:39:38 +00:00
n1474335
16be7cb28a Fixed grunt-webpack circular reference issue 2018-12-26 00:39:30 +00:00
n1474335
f6d97c19d9 8.17.1 2018-12-26 00:01:21 +00:00
n1474335
8fef01d961 Fixed bundle analyzer filepath 2018-12-26 00:01:12 +00:00
n1474335
43dcd544f2 Added webpack-bundle-analyzer to production build. Refactored some modules to improve performance. Removed moment-timezone from Utils to drastically reduce module size. 2018-12-25 23:58:00 +00:00
n1474335
b29bb6fdd7 Added 'DishError' and refined test results. 2018-12-25 22:38:53 +00:00
n1474335
d2325306db 8.17.0 2018-12-25 21:55:51 +00:00
n1474335
dfe31980b7 Merge branch 'j433866-qrcodes' 2018-12-25 21:55:35 +00:00
n1474335
9734b78aeb Tidied up QR code operations 2018-12-25 21:54:38 +00:00
n1474335
4ee0800990 Merge branch 'qrcodes' of https://github.com/j433866/CyberChef into j433866-qrcodes 2018-12-25 19:07:59 +00:00
n1474335
387008bd9c 8.16.1 2018-12-25 19:02:13 +00:00
n1474335
bf24547202 The 'option' and 'editableOption' arguments can now specify a 'defaultIndex' to populate, instead of using the first in the provided list. 2018-12-25 19:02:05 +00:00
Matt C
454ef0076b Disabled tests 2018-12-21 17:19:33 +00:00
Matt C
18693d2471 Add tests, however non-functional due to lack of File in Node
Also add jimp to package.json
2018-12-21 17:17:11 +00:00
Matt C
5a9583c970 Add to categories 2018-12-21 17:15:30 +00:00
Matt C
0046f7e3d7 Added colour channel splitting support 2018-12-21 17:08:09 +00:00
j433866
c2f6b8df66 Add tests for Parse QR Code module 2018-12-21 11:26:03 +00:00
j433866
d0e428b728 Improve image normalising 2018-12-21 11:24:31 +00:00
j433866
ae5128a33a Always generate a PNG if the format isn't SVG 2018-12-21 11:23:51 +00:00
j433866
ed25017e2d Add process.browser to webpack config, so we don't include stuff we don't need 2018-12-20 14:46:24 +00:00
j433866
e5b2b84073 Add new ParseQRCode operation 2018-12-20 14:45:23 +00:00
j433866
1953d9a4c8 Add Jimp and jsqr modules 2018-12-20 14:42:32 +00:00
j433866
b3113c109b Change module to Image, change default format value to PNG 2018-12-20 14:42:12 +00:00
n1474335
8c3569ea63 8.16.0 2018-12-19 17:59:55 +00:00
n1474335
ae28d476de Merge branch 'anthony-arnold-play-media' 2018-12-19 17:58:51 +00:00
n1474335
01c4cfdc8d Tidied up 'Play Media' operation 2018-12-19 17:58:38 +00:00
n1474335
8c6c3a1c01 Merge branch 'play-media' of https://github.com/anthony-arnold/CyberChef into anthony-arnold-play-media 2018-12-19 17:39:07 +00:00
n1474335
f367c1f78b 8.15.1 2018-12-19 17:25:05 +00:00
n1474335
13d87d397d Merge branch 'j433866-master' 2018-12-19 17:24:52 +00:00
n1474335
ed2c886359 Magic crib now only applies after all branches have been explored. 2018-12-19 17:24:38 +00:00
n1474335
6337e84708 Merge branch 'master' of https://github.com/j433866/CyberChef into j433866-master 2018-12-19 16:38:34 +00:00
j433866
ae20a951be Add customisation arguments.
Add presentation of QR code in HTML.
2018-12-19 14:43:31 +00:00
Anthony Arnold
866dd546c8 Add the Play Media operation and place it under a new "Multimedia" category. Move the Render Image to this new category as well. 2018-12-20 00:05:10 +10:00
j433866
2070e1a96b Add new Generate QR Code module 2018-12-19 13:27:45 +00:00
j433866
952f49e2e1 Add qr-image to package 2018-12-19 13:27:18 +00:00
j433866
f600571c6d Fix to make the filter work when intensive mode was turned on. 2018-12-19 09:42:09 +00:00
j433866
5d4c7244e1 Add note about crib to operation description 2018-12-18 16:52:09 +00:00
j433866
b6bdcaa71f Rename output filter argument to Crib 2018-12-18 14:19:52 +00:00
j433866
c8eab5d218 Commenting 2018-12-18 14:06:39 +00:00
n1474335
8ab56a29ac 8.15.0 2018-12-18 13:50:30 +00:00
n1474335
973b5f3f5c Merge branch 'Cynser-text-brute-force' 2018-12-18 13:50:23 +00:00
n1474335
076a1f97c2 Tidied up 'Text Encoding Brute Force' operations and updated CHANGELOG 2018-12-18 13:50:10 +00:00
n1474335
d96ef37d81 Merge branch 'text-brute-force' of https://github.com/Cynser/CyberChef into Cynser-text-brute-force 2018-12-18 12:28:27 +00:00
n1474335
56f8302402 8.14.0 2018-12-18 12:20:03 +00:00
n1474335
97e6a7cbd8 Merge branch 'tcode2k16-master' 2018-12-18 12:19:56 +00:00
n1474335
d89d79116c Cleaned up Base62 ops and updated CHANGELOG 2018-12-18 12:19:42 +00:00
j433866
367d79e820 Fix filtering to work on all the data and not just the result snippet 2018-12-18 11:55:49 +00:00
j433866
283d7f2159 Add Output Filter option to Magic operation 2018-12-18 10:40:18 +00:00
Cynser
dacb3ef6c3 Added decode option 2018-12-17 19:39:12 +00:00
tcode2k16
22454ae842 Add "To Base62" and "From Base62" operations 2018-12-17 12:37:00 +08:00
n1474335
79b9b63982 8.13.0 2018-12-15 00:26:41 +00:00
n1474335
2f68bf30a4 Merge branch 'jarmovanlenthe-master' 2018-12-15 00:26:31 +00:00
n1474335
50f078cc45 Updated CHANGELOG 2018-12-15 00:26:15 +00:00
n1474335
47a410d6ab Merge branch 'master' of https://github.com/jarmovanlenthe/CyberChef into jarmovanlenthe-master 2018-12-15 00:19:16 +00:00
n1474335
31cbf8cccc 8.12.4 2018-12-15 00:16:23 +00:00
n1474335
88bd321e3e Merge branch 'imhotepisinvisible-master' 2018-12-15 00:16:13 +00:00
Jarmo van Lenthe
b4a586c0b9 Some lets to consts and removing of trailing spaces from grunt lint 2018-12-14 22:35:43 +01:00
Oliver Grubin
63593f1b6c Fix HMAC operation when hex key has bytes >= 0x80 (#437)
Add test vectors from RFC4231
2018-12-14 21:32:44 +00:00
Jarmo van Lenthe
dcff8971e8 Added simple A1Z26 'cipher' 2018-12-14 22:29:51 +01:00
Cynser
3f7059a235 Remove unnecessary escape character 2018-12-12 17:49:11 +00:00
Cynser
71c743ff5a Add Text Encoding Brute Force operation 2018-12-12 17:34:45 +00:00
n1474335
15fbe5a459 8.12.3 2018-11-23 16:07:30 +00:00
n1474335
cd47394709 Merge branch 'PhillipNordwall-JSON_Object_Sort' 2018-11-23 16:07:21 +00:00
n1474335
6f4ee8b7b6 Tidied JSON Beautify op. Changed default indent to 4 spaces instead of a tab. 2018-11-23 16:05:51 +00:00
n1474335
8c5d05b611 Merge branch 'JSON_Object_Sort' of https://github.com/PhillipNordwall/CyberChef into PhillipNordwall-JSON_Object_Sort 2018-11-23 15:56:59 +00:00
n1474335
3bdcf4d851 8.12.2 2018-11-23 14:58:38 +00:00
n1474335
1d1c69ca51 Updated magic pattern matches for QP and B64 encodings to handle whitespace better 2018-11-23 14:58:30 +00:00
Phillip Nordwall
c4c679021d Adding Sort Object Keys, and tests for it. 2018-11-22 11:10:10 -08:00
Phillip Nordwall
c16d13e2c9 Adding test cases for JSON Minify 2018-11-22 11:07:48 -08:00
Phillip Nordwall
97613eb3c7 Adding test cases for JSON Beautify 2018-11-22 10:31:22 -08:00
n1474335
a946d04a72 8.12.1 2018-11-21 17:48:03 +00:00
n1474335
cc35ec82eb Fixed babel transpilation of jsesc and crypto-api 2018-11-21 17:47:56 +00:00
n1474335
d6604e0008 Updated CHANGELOG 2018-11-21 12:48:27 +00:00
n1474335
b9e63efc37 Fixed version links in CHANGELOG 2018-11-21 12:40:55 +00:00
n1474335
b458707921 8.12.0 2018-11-21 12:29:25 +00:00
n1474335
6ec52c6cd2 Merge branch 'bwhitn-citrix' 2018-11-21 12:28:36 +00:00
n1474335
79d7a5dd87 Tidied up Citrix CTX1 operations and updated CHANGELOG 2018-11-21 12:28:19 +00:00
n1474335
1653d0212a Merge branch 'citrix' of https://github.com/bwhitn/CyberChef into bwhitn-citrix 2018-11-21 10:23:39 +00:00
Brian Whitney
c378bcb00b Fixed lint issues 2018-11-20 11:24:50 -05:00
Brian Whitney
215e7a5f5d Citrix CTX1 encoding/decoding 2018-11-20 11:09:52 -05:00
bwhitn
6b686681d5 Encoding ctx1 2018-11-19 23:48:33 -05:00
n1474335
20ea050728 Updated description for 'Substitute' to include note about escaping backslashes. 2018-11-19 14:54:37 +00:00
n1474335
4b6132a2d7 8.11.2 2018-11-19 14:34:56 +00:00
n1474335
4cf80e3ebb Added RFC numbers to relevant Base64 alphabets. Closes #410 2018-11-19 14:34:52 +00:00
n1474335
045747f543 8.11.1 2018-11-14 12:27:55 +00:00
n1474335
b10c5e3256 Fixed faulty package-lock.json 2018-11-14 12:27:47 +00:00
n1474335
69df2e4183 Updated comments 2018-11-13 18:05:52 +00:00
n1474335
12ebd35c4d 8.11.0 2018-11-13 17:56:46 +00:00
n1474335
30c5f76cf0 Updated changelog 2018-11-13 17:56:40 +00:00
n1474335
3a979b6cda 'JSON to CSV' operation now escapes characters correctly. Added tests for CSV/JSON operations. 2018-11-13 17:54:43 +00:00
n1474335
863bdffa84 Added 'CSV to JSON' and 'JSON to CSV' operations. Closes #277 2018-11-09 17:40:19 +00:00
n1474335
42b956e402 Fixed JSDoc comment 2018-11-09 15:28:47 +00:00
n1474335
4acf7b4e4f 8.10.2 2018-11-09 15:25:22 +00:00
n1474335
42e881326f Added 'Binary' key option to all bitwise operations. Closes #398 2018-11-09 15:25:16 +00:00
n1474335
3c4893d7c7 8.10.1 2018-11-07 15:20:51 +00:00
n1474335
027aca4ab2 Merge branch 'qistoph-NumSortHex' 2018-11-07 15:20:43 +00:00
n1474335
2d471f551f Lint 2018-11-07 15:20:09 +00:00
n1474335
5c598b69b0 Merge branch 'NumSortHex' of https://github.com/qistoph/CyberChef into qistoph-NumSortHex 2018-11-07 15:15:39 +00:00
n1474335
037300de79 8.10.0 2018-11-07 15:10:57 +00:00
n1474335
6990dcae89 Updated changelog 2018-11-07 15:10:25 +00:00
n1474335
6e81d6dfcd Merge branch 'klaxon1-feature/remove-letter-accents' 2018-11-07 15:08:09 +00:00
n1474335
cea30465d8 Changed 'Remove Letter Accents' to 'Remove Diacritics' 2018-11-07 15:07:54 +00:00
n1474335
b301d16cb2 Merge branch 'feature/remove-letter-accents' of https://github.com/klaxon1/CyberChef into klaxon1-feature/remove-letter-accents 2018-11-07 14:57:05 +00:00
n1474335
19c002fcdd 8.9.2 2018-11-07 14:40:13 +00:00
n1474335
ab3a73fe58 Merge branch 'qistoph-FromNegs' 2018-11-07 14:39:51 +00:00
n1474335
91fc2c28dc Added signed feature to 'To Decimal' 2018-11-07 14:39:33 +00:00
n1474335
ca47ba3c7c Merge branch 'FromNegs' of https://github.com/qistoph/CyberChef into qistoph-FromNegs 2018-11-07 14:23:39 +00:00
n1474335
e1b456c01c 8.9.1 2018-11-07 14:21:26 +00:00
n1474335
5eb7e00eac Merge branch 'qistoph-HmacToggleStr' 2018-11-07 14:21:18 +00:00
n1474335
8bcf68c8a1 Merge branch 'HmacToggleStr' of https://github.com/qistoph/CyberChef into qistoph-HmacToggleStr 2018-11-07 14:18:24 +00:00
n1474335
520eaedd9a 8.9.0 2018-11-07 13:23:26 +00:00
n1474335
4c5e664ce0 Merge branch 'arnydo-add_url_defang' 2018-11-07 13:23:17 +00:00
n1474335
53c500eb1b Added various options to the 'Defang URL' operation. 2018-11-07 13:23:05 +00:00
n1474335
253346a201 Merge branch 'add_url_defang' of https://github.com/arnydo/CyberChef into arnydo-add_url_defang 2018-11-07 12:29:58 +00:00
Chris van Marle
3f0af9cdea Add tests for From Decimal 2018-10-22 17:51:26 +08:00
arnydo
69033a7343 Add Defang URL 2018-10-16 15:03:29 -04:00
arnydo
5a22106731 Create DefangURL.mjs 2018-10-16 15:02:39 -04:00
Chris van Marle
ba24e12454 Update hexadecimal sort after review
- Use Array.map instead of for-loop
- Add test case
2018-10-12 15:39:06 +02:00
Chris van Marle
b76aa16143 Fix Hash test 2018-10-12 13:54:40 +02:00
Chris van Marle
be2b466376 Use toggleString for Key in HMAC #263 2018-10-12 13:05:32 +02:00
Chris van Marle
a276378887 Enable parsing of negative decimals #176 2018-10-12 10:08:24 +02:00
Chris van Marle
3b3c27072f Fix lint errors 2018-10-11 15:50:58 +02:00
Klaxon
3089c39369 add test 2018-10-11 22:26:44 +10:00
Chris van Marle
0cbb17f7ce Support hexadecimal and other bases in numeric sorting 2018-10-11 14:23:05 +02:00
Klaxon
54793f2b78 update operation 2018-10-11 21:52:49 +10:00
Klaxon
f1ffe19ec8 Merge branch 'master' into feature/remove-letter-accents 2018-10-11 21:28:04 +10:00
Klaxon
04ee2fb3e4 add function to replace accent chars with latin chars 2018-10-03 13:26:01 +10:00
Klaxon
ac2466a304 create operation from npm run newop 2018-10-03 13:11:22 +10:00
178 changed files with 7488 additions and 1948 deletions

View File

@@ -1,19 +0,0 @@
{
"presets": [
["@babel/preset-env", {
"targets": {
"chrome": 40,
"firefox": 35,
"edge": 14,
"node": "6.5"
},
"modules": false,
"useBuiltIns": "entry"
}]
],
"plugins": [
["babel-plugin-transform-builtin-extend", {
"globals": ["Error"]
}]
]
}

View File

@@ -9,6 +9,6 @@ trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[{package.json,.travis.yml}]
[{package.json,.travis.yml,nightwatch.json}]
indent_style = space
indent_size = 2

View File

@@ -87,6 +87,15 @@
"no-var": "error",
"prefer-const": "error"
},
"overrides": [
{
"files": "tests/**/*",
"rules": {
"no-unused-expressions": "off",
"no-console": "off"
}
}
],
"globals": {
"$": false,
"jQuery": false,

1
.gitignore vendored
View File

@@ -9,4 +9,5 @@ docs/*
src/core/config/modules/*
src/core/config/OperationConfig.json
src/core/operations/index.mjs
tests/browser/output/*

View File

@@ -1,15 +1,19 @@
language: node_js
node_js:
- node
addons:
chrome: stable
install: npm install
before_script:
- npm install -g grunt
- export NODE_OPTIONS=--max_old_space_size=2048
script:
- grunt lint
- grunt test
- grunt docs
- grunt node
- grunt prod --msg="$COMPILE_MSG"
- xvfb-run --server-args="-screen 0 1200x800x24" grunt testui
before_deploy:
- grunt exec:sitemap
- grunt copy:ghPages

View File

@@ -1,5 +1,48 @@
# Changelog
All notable changes to CyberChef will be documented in this file.
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).
### [8.22.0] - 2019-01-10
- 'Subsection' operation added [@j433866] | [#467]
### [8.21.0] - 2019-01-10
- 'To Case Insensitive Regex' and 'From Case Insensitive Regex' operations added [@masq] | [#461]
### [8.20.0] - 2019-01-09
- 'Generate Lorem Ipsum' operation added [@klaxon1] | [#455]
### [8.19.0] - 2018-12-30
- UI test suite added to confirm that the app loads correctly in a reasonable time and that various operations from each module can be run [@n1474335] | [#458]
### [8.18.0] - 2018-12-26
- 'Split Colour Channels' operation added [@artemisbot] | [#449]
### [8.17.0] - 2018-12-25
- 'Generate QR Code' and 'Parse QR Code' operations added [@j433866] | [#448]
### [8.16.0] - 2018-12-19
- 'Play Media' operation added [@anthony-arnold] | [#446]
### [8.15.0] - 2018-12-18
- 'Text Encoding Brute Force' operation added [@Cynser] | [#439]
### [8.14.0] - 2018-12-18
- 'To Base62' and 'From Base62' operations added [@tcode2k16] | [#443]
### [8.13.0] - 2018-12-15
- 'A1Z26 Cipher Encode' and 'A1Z26 Cipher Decode' operations added [@jarmovanlenthe] | [#441]
### [8.12.0] - 2018-11-21
- 'Citrix CTX1 Encode' and 'Citrix CTX1 Decode' operations added [@bwhitn] | [#428]
### [8.11.0] - 2018-11-13
- 'CSV to JSON' and 'JSON to CSV' operations added [@n1474335] | [#277]
### [8.10.0] - 2018-11-07
- 'Remove Diacritics' operation added [@klaxon1] | [#387]
### [8.9.0] - 2018-11-07
- 'Defang URL' operation added [@arnydo] | [#394]
### [8.8.0] - 2018-10-10
- 'Parse TLV' operation added [@GCHQ77703] | [#351]
@@ -8,7 +51,7 @@ All notable changes to CyberChef will be documented in this file.
- 'JWT Sign', 'JWT Verify' and 'JWT Decode' operations added [@GCHQ77703] | [#348]
### [8.6.0] - 2018-08-29
- 'To Geohash' and 'From Geohash' operations added [@GCHQ77703] | [#344]
- 'To Geohash' and 'From Geohash' operations added [@GCHQ77703] | [#344]
### [8.5.0] - 2018-08-23
- 'To Braille' and 'From Braille' operations added [@n1474335] | [#255]
@@ -43,7 +86,7 @@ All notable changes to CyberChef will be documented in this file.
- Added support for loading, processing and downloading files up to 500MB [@n1474335] | [#224]
## [6.0.0] - 2017-09-19
- Threading support added. All recipe processing moved into a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) to increase performance and allowing long-running operations to be cancelled [@n1474335] | [#173]
- Threading support added. All recipe processing moved into a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) to increase performance and to allow long-running operations to be cancelled [@n1474335] | [#173]
- Module system created so that operations relying on large libraries can be downloaded separately as required, reducing the initial loading time for the app [@n1474335] | [#173]
## [5.0.0] - 2017-03-30
@@ -53,6 +96,21 @@ All notable changes to CyberChef will be documented in this file.
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
[8.22.0]: https://github.com/gchq/CyberChef/releases/tag/v8.22.0
[8.21.0]: https://github.com/gchq/CyberChef/releases/tag/v8.21.0
[8.20.0]: https://github.com/gchq/CyberChef/releases/tag/v8.20.0
[8.19.0]: https://github.com/gchq/CyberChef/releases/tag/v8.19.0
[8.18.0]: https://github.com/gchq/CyberChef/releases/tag/v8.18.0
[8.17.0]: https://github.com/gchq/CyberChef/releases/tag/v8.17.0
[8.16.0]: https://github.com/gchq/CyberChef/releases/tag/v8.16.0
[8.15.0]: https://github.com/gchq/CyberChef/releases/tag/v8.15.0
[8.14.0]: https://github.com/gchq/CyberChef/releases/tag/v8.14.0
[8.13.0]: https://github.com/gchq/CyberChef/releases/tag/v8.13.0
[8.12.0]: https://github.com/gchq/CyberChef/releases/tag/v8.12.0
[8.11.0]: https://github.com/gchq/CyberChef/releases/tag/v8.11.0
[8.10.0]: https://github.com/gchq/CyberChef/releases/tag/v8.10.0
[8.9.0]: https://github.com/gchq/CyberChef/releases/tag/v8.9.0
[8.8.0]: https://github.com/gchq/CyberChef/releases/tag/v8.8.0
[8.7.0]: https://github.com/gchq/CyberChef/releases/tag/v8.7.0
[8.6.0]: https://github.com/gchq/CyberChef/releases/tag/v8.6.0
@@ -69,6 +127,7 @@ All notable changes to CyberChef will be documented in this file.
[@n1474335]: https://github.com/n1474335
[@d98762625]: https://github.com/d98762625
[@j433866]: https://github.com/j433866
[@GCHQ77703]: https://github.com/GCHQ77703
[@artemisbot]: https://github.com/artemisbot
[@picapi]: https://github.com/picapi
@@ -76,6 +135,14 @@ All notable changes to CyberChef will be documented in this file.
[@JustAnotherMark]: https://github.com/JustAnotherMark
[@sevzero]: https://github.com/sevzero
[@PenguinGeorge]: https://github.com/PenguinGeorge
[@arnydo]: https://github.com/arnydo
[@klaxon1]: https://github.com/klaxon1
[@bwhitn]: https://github.com/bwhitn
[@jarmovanlenthe]: https://github.com/jarmovanlenthe
[@tcode2k16]: https://github.com/tcode2k16
[@Cynser]: https://github.com/Cynser
[@anthony-arnold]: https://github.com/anthony-arnold
[@masq]: https://github.com/masq
[#95]: https://github.com/gchq/CyberChef/pull/299
[#173]: https://github.com/gchq/CyberChef/pull/173
@@ -83,6 +150,7 @@ All notable changes to CyberChef will be documented in this file.
[#239]: https://github.com/gchq/CyberChef/pull/239
[#248]: https://github.com/gchq/CyberChef/pull/248
[#255]: https://github.com/gchq/CyberChef/issues/255
[#277]: https://github.com/gchq/CyberChef/issues/277
[#281]: https://github.com/gchq/CyberChef/pull/281
[#284]: https://github.com/gchq/CyberChef/pull/284
[#294]: https://github.com/gchq/CyberChef/pull/294
@@ -95,3 +163,16 @@ All notable changes to CyberChef will be documented in this file.
[#344]: https://github.com/gchq/CyberChef/pull/344
[#348]: https://github.com/gchq/CyberChef/pull/348
[#351]: https://github.com/gchq/CyberChef/pull/351
[#387]: https://github.com/gchq/CyberChef/pull/387
[#394]: https://github.com/gchq/CyberChef/pull/394
[#428]: https://github.com/gchq/CyberChef/pull/428
[#439]: https://github.com/gchq/CyberChef/pull/439
[#441]: https://github.com/gchq/CyberChef/pull/441
[#443]: https://github.com/gchq/CyberChef/pull/443
[#446]: https://github.com/gchq/CyberChef/pull/446
[#448]: https://github.com/gchq/CyberChef/pull/448
[#449]: https://github.com/gchq/CyberChef/pull/449
[#455]: https://github.com/gchq/CyberChef/pull/455
[#458]: https://github.com/gchq/CyberChef/pull/458
[#461]: https://github.com/gchq/CyberChef/pull/461
[#467]: https://github.com/gchq/CyberChef/pull/467

View File

@@ -2,6 +2,7 @@
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const NodeExternals = require("webpack-node-externals");
const Inliner = require("web-resource-inliner");
const glob = require("glob");
@@ -29,8 +30,12 @@ module.exports = function (grunt) {
["clean:node", "clean:config", "exec:generateConfig", "webpack:node", "chmod:build"]);
grunt.registerTask("test",
"A task which runs all the tests in test/tests.",
["exec:generateConfig", "exec:tests"]);
"A task which runs all the operation tests in the tests directory.",
["exec:generateConfig", "exec:opTests"]);
grunt.registerTask("testui",
"A task which runs all the UI tests in the tests directory. The prod task must already have been run.",
["connect:prod", "exec:browserTests"]);
grunt.registerTask("docs",
"Compiles documentation in the /docs directory.",
@@ -66,6 +71,7 @@ module.exports = function (grunt) {
grunt.loadNpmTasks("grunt-exec");
grunt.loadNpmTasks("grunt-accessibility");
grunt.loadNpmTasks("grunt-concurrent");
grunt.loadNpmTasks("grunt-contrib-connect");
// Project configuration
@@ -143,11 +149,11 @@ module.exports = function (grunt) {
options: {
configFile: "./.eslintrc.json"
},
configs: ["Gruntfile.js"],
configs: ["*.{js,mjs}"],
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
web: ["src/web/**/*.{js,mjs}"],
node: ["src/node/**/*.{js,mjs}"],
tests: ["test/**/*.{js,mjs}"],
tests: ["tests/**/*.{js,mjs}"],
},
jsdoc: {
options: {
@@ -179,37 +185,44 @@ module.exports = function (grunt) {
},
webpack: {
options: webpackConfig,
web: {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js",
sitemap: "./src/web/static/sitemap.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod"
},
resolve: {
alias: {
"./config/modules/OpModules": "./config/modules/Default"
}
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
minify: {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true
web: () => {
return {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js",
sitemap: "./src/web/static/sitemap.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod"
},
resolve: {
alias: {
"./config/modules/OpModules": "./config/modules/Default"
}
}),
]
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
minify: {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true
}
}),
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: "BundleAnalyzerReport.html",
openAnalyzer: false
}),
]
};
},
webInline: {
mode: "production",
@@ -238,19 +251,6 @@ module.exports = function (grunt) {
}),
]
},
tests: {
mode: "development",
target: "node",
entry: "./test/index.mjs",
externals: [NodeExternals()],
output: {
filename: "index.js",
path: __dirname + "/build/test"
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS)
]
},
node: {
mode: "production",
target: "node",
@@ -312,6 +312,14 @@ module.exports = function (grunt) {
}
}
},
connect: {
prod: {
options: {
port: 8000,
base: "build/prod/"
}
}
},
copy: {
ghPages: {
options: {
@@ -391,8 +399,11 @@ module.exports = function (grunt) {
"echo '--- Config scripts finished. ---\n'"
].join(";")
},
tests: {
command: "node --experimental-modules --no-warnings --no-deprecation test/index.mjs"
opTests: {
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
},
browserTests: {
command: "./node_modules/.bin/nightwatch --env prod,inline"
}
},
});

23
babel.config.js Normal file
View File

@@ -0,0 +1,23 @@
module.exports = function(api) {
api.cache.forever();
return {
"presets": [
["@babel/preset-env", {
"targets": {
"chrome": 40,
"firefox": 35,
"edge": 14,
"node": "6.5"
},
"modules": false,
"useBuiltIns": "entry"
}]
],
"plugins": [
["babel-plugin-transform-builtin-extend", {
"globals": ["Error"]
}]
]
};
};

34
nightwatch.json Normal file
View File

@@ -0,0 +1,34 @@
{
"src_folders": ["tests/browser"],
"output_folder": "tests/browser/output",
"test_settings": {
"default": {
"launch_url": "http://localhost:8080",
"webdriver": {
"start_process": true,
"server_path": "./node_modules/.bin/chromedriver",
"port": 9515,
"log_path": false
},
"desiredCapabilities": {
"browserName": "chrome"
}
},
"dev": {
"launch_url": "http://localhost:8080"
},
"prod": {
"launch_url": "http://localhost:8000/index.html"
},
"inline": {
"launch_url": "http://localhost:8000/cyberchef.htm"
}
}
}

4903
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "8.8.8",
"version": "8.22.1",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -30,22 +30,24 @@
"main": "build/node/CyberChef.js",
"bugs": "https://github.com/gchq/CyberChef/issues",
"devDependencies": {
"@babel/core": "^7.1.5",
"@babel/preset-env": "^7.1.5",
"autoprefixer": "^9.3.1",
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.2.3",
"autoprefixer": "^9.4.3",
"babel-loader": "^8.0.4",
"bootstrap": "^4.1.3",
"colors": "^1.3.2",
"css-loader": "^1.0.1",
"eslint": "^5.8.0",
"bootstrap": "^4.2.1",
"chromedriver": "^2.45.0",
"colors": "^1.3.3",
"css-loader": "^2.1.0",
"eslint": "^5.11.1",
"exports-loader": "^0.7.0",
"extract-text-webpack-plugin": "^4.0.0-alpha0",
"file-loader": "^2.0.0",
"file-loader": "^3.0.1",
"grunt": "^1.0.3",
"grunt-accessibility": "~6.0.0",
"grunt-chmod": "~1.1.1",
"grunt-concurrent": "^2.3.1",
"grunt-contrib-clean": "~2.0.0",
"grunt-contrib-connect": "^2.0.0",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^21.0.0",
@@ -56,7 +58,8 @@
"imports-loader": "^0.8.0",
"ink-docstrap": "^1.3.2",
"jsdoc-babel": "^0.5.0",
"node-sass": "^4.10.0",
"nightwatch": "^1.0.18",
"node-sass": "^4.11.0",
"postcss-css-variables": "^0.11.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
@@ -66,8 +69,9 @@
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"web-resource-inliner": "^4.2.1",
"webpack": "^4.25.1",
"webpack-dev-server": "^3.1.10",
"webpack": "^4.28.3",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-dev-server": "^3.1.14",
"webpack-node-externals": "^1.7.2",
"worker-loader": "^2.0.0"
},
@@ -79,7 +83,7 @@
"bignumber.js": "^8.0.1",
"bootstrap-colorpicker": "^2.5.3",
"bootstrap-material-design": "^4.1.1",
"bson": "^3.0.2",
"bson": "^4.0.1",
"chi-squared": "^1.1.0",
"crypto-api": "^0.8.3",
"crypto-js": "^3.1.9-1",
@@ -90,33 +94,35 @@
"esmangle": "^1.0.1",
"esprima": "^4.0.1",
"exif-parser": "^0.1.12",
"file-saver": "^2.0.0-rc.4",
"file-saver": "^2.0.0",
"highlight.js": "^9.13.1",
"jimp": "^0.6.0",
"jquery": "^3.3.1",
"js-crc": "^0.2.0",
"js-sha3": "^0.8.0",
"jsbn": "^1.1.0",
"jsesc": "^2.5.1",
"jsesc": "^2.5.2",
"jsonpath": "^1.0.0",
"jsonwebtoken": "^8.3.0",
"jsonwebtoken": "^8.4.0",
"jsqr": "^1.1.1",
"jsrsasign": "8.0.12",
"kbpgp": "^2.0.82",
"lodash": "^4.17.11",
"loglevel": "^1.6.1",
"loglevel-message-prefix": "^3.0.0",
"moment": "^2.22.2",
"moment": "^2.23.0",
"moment-timezone": "^0.5.23",
"ngeohash": "^0.6.0",
"ngeohash": "^0.6.3",
"node-forge": "^0.7.6",
"node-md6": "^0.1.0",
"notepack.io": "^2.1.3",
"notepack.io": "^2.2.0",
"nwmatcher": "^1.4.4",
"otp": "^0.1.3",
"popper.js": "^1.14.4",
"popper.js": "^1.14.6",
"qr-image": "^3.2.0",
"scryptsy": "^2.0.0",
"snackbarjs": "^1.1.0",
"sortablejs": "^1.7.0",
"split.js": "^1.5.9",
"sortablejs": "^1.8.0-rc1",
"split.js": "^1.5.10",
"ssdeep.js": "0.0.2",
"ua-parser-js": "^0.7.19",
"utf8": "^3.0.0",
@@ -130,6 +136,7 @@
"start": "grunt dev",
"build": "grunt prod",
"test": "grunt test",
"testui": "grunt testui",
"docs": "grunt docs",
"lint": "grunt lint",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"

View File

@@ -6,6 +6,7 @@
*/
import Utils from "./Utils";
import DishError from "./errors/DishError";
import BigNumber from "bignumber.js";
import log from "loglevel";
@@ -61,7 +62,7 @@ class Dish {
case "list<file>":
return Dish.LIST_FILE;
default:
throw "Invalid data type string. No matching enum.";
throw new DishError("Invalid data type string. No matching enum.");
}
}
@@ -93,7 +94,7 @@ class Dish {
case Dish.LIST_FILE:
return "List<File>";
default:
throw "Invalid data type enum. No matching type.";
throw new DishError("Invalid data type enum. No matching type.");
}
}
@@ -117,7 +118,7 @@ class Dish {
if (!this.valid()) {
const sample = Utils.truncate(JSON.stringify(this.value), 13);
throw "Data is not a valid " + Dish.enumLookup(type) + ": " + sample;
throw new DishError(`Data is not a valid ${Dish.enumLookup(type)}: ${sample}`);
}
}
@@ -151,77 +152,85 @@ class Dish {
const byteArrayToStr = notUTF8 ? Utils.byteArrayToChars : Utils.byteArrayToUtf8;
// Convert data to intermediate byteArray type
switch (this.type) {
case Dish.STRING:
this.value = this.value ? Utils.strToByteArray(this.value) : [];
break;
case Dish.NUMBER:
this.value = typeof this.value === "number" ? Utils.strToByteArray(this.value.toString()) : [];
break;
case Dish.HTML:
this.value = this.value ? Utils.strToByteArray(Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true))) : [];
break;
case Dish.ARRAY_BUFFER:
// Array.from() would be nicer here, but it's slightly slower
this.value = Array.prototype.slice.call(new Uint8Array(this.value));
break;
case Dish.BIG_NUMBER:
this.value = this.value instanceof BigNumber ? Utils.strToByteArray(this.value.toFixed()) : [];
break;
case Dish.JSON:
this.value = this.value ? Utils.strToByteArray(JSON.stringify(this.value, null, 4)) : [];
break;
case Dish.FILE:
this.value = await Utils.readFile(this.value);
this.value = Array.prototype.slice.call(this.value);
break;
case Dish.LIST_FILE:
this.value = await Promise.all(this.value.map(async f => Utils.readFile(f)));
this.value = this.value.map(b => Array.prototype.slice.call(b));
this.value = [].concat.apply([], this.value);
break;
default:
break;
try {
switch (this.type) {
case Dish.STRING:
this.value = this.value ? Utils.strToByteArray(this.value) : [];
break;
case Dish.NUMBER:
this.value = typeof this.value === "number" ? Utils.strToByteArray(this.value.toString()) : [];
break;
case Dish.HTML:
this.value = this.value ? Utils.strToByteArray(Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true))) : [];
break;
case Dish.ARRAY_BUFFER:
// Array.from() would be nicer here, but it's slightly slower
this.value = Array.prototype.slice.call(new Uint8Array(this.value));
break;
case Dish.BIG_NUMBER:
this.value = this.value instanceof BigNumber ? Utils.strToByteArray(this.value.toFixed()) : [];
break;
case Dish.JSON:
this.value = this.value ? Utils.strToByteArray(JSON.stringify(this.value, null, 4)) : [];
break;
case Dish.FILE:
this.value = await Utils.readFile(this.value);
this.value = Array.prototype.slice.call(this.value);
break;
case Dish.LIST_FILE:
this.value = await Promise.all(this.value.map(async f => Utils.readFile(f)));
this.value = this.value.map(b => Array.prototype.slice.call(b));
this.value = [].concat.apply([], this.value);
break;
default:
break;
}
} catch (err) {
throw new DishError(`Error translating from ${Dish.enumLookup(this.type)} to byteArray: ${err}`);
}
this.type = Dish.BYTE_ARRAY;
// Convert from byteArray to toType
switch (toType) {
case Dish.STRING:
case Dish.HTML:
this.value = this.value ? byteArrayToStr(this.value) : "";
this.type = Dish.STRING;
break;
case Dish.NUMBER:
this.value = this.value ? parseFloat(byteArrayToStr(this.value)) : 0;
this.type = Dish.NUMBER;
break;
case Dish.ARRAY_BUFFER:
this.value = new Uint8Array(this.value).buffer;
this.type = Dish.ARRAY_BUFFER;
break;
case Dish.BIG_NUMBER:
try {
this.value = new BigNumber(byteArrayToStr(this.value));
} catch (err) {
this.value = new BigNumber(NaN);
}
this.type = Dish.BIG_NUMBER;
break;
case Dish.JSON:
this.value = JSON.parse(byteArrayToStr(this.value));
this.type = Dish.JSON;
break;
case Dish.FILE:
this.value = new File(this.value, "unknown");
break;
case Dish.LIST_FILE:
this.value = [new File(this.value, "unknown")];
this.type = Dish.LIST_FILE;
break;
default:
break;
try {
switch (toType) {
case Dish.STRING:
case Dish.HTML:
this.value = this.value ? byteArrayToStr(this.value) : "";
this.type = Dish.STRING;
break;
case Dish.NUMBER:
this.value = this.value ? parseFloat(byteArrayToStr(this.value)) : 0;
this.type = Dish.NUMBER;
break;
case Dish.ARRAY_BUFFER:
this.value = new Uint8Array(this.value).buffer;
this.type = Dish.ARRAY_BUFFER;
break;
case Dish.BIG_NUMBER:
try {
this.value = new BigNumber(byteArrayToStr(this.value));
} catch (err) {
this.value = new BigNumber(NaN);
}
this.type = Dish.BIG_NUMBER;
break;
case Dish.JSON:
this.value = JSON.parse(byteArrayToStr(this.value));
this.type = Dish.JSON;
break;
case Dish.FILE:
this.value = new File(this.value, "unknown");
break;
case Dish.LIST_FILE:
this.value = [new File(this.value, "unknown")];
this.type = Dish.LIST_FILE;
break;
default:
break;
}
} catch (err) {
throw new DishError(`Error translating from byteArray to ${Dish.enumLookup(toType)}: ${err}`);
}
}
@@ -357,7 +366,7 @@ class Dish {
);
break;
default:
throw new Error("Cannot clone Dish, unknown type");
throw new DishError("Cannot clone Dish, unknown type");
}
return newDish;

View File

@@ -25,6 +25,7 @@ class Ingredient {
this.hint = "";
this.toggleValues = [];
this.target = null;
this.defaultIndex = 0;
if (ingredientConfig) {
this._parseConfig(ingredientConfig);
@@ -46,6 +47,7 @@ class Ingredient {
this.hint = ingredientConfig.hint || false;
this.toggleValues = ingredientConfig.toggleValues;
this.target = typeof ingredientConfig.target !== "undefined" ? ingredientConfig.target : null;
this.defaultIndex = typeof ingredientConfig.defaultIndex !== "undefined" ? ingredientConfig.defaultIndex : 0;
}
@@ -93,6 +95,7 @@ class Ingredient {
case "binaryString":
case "binaryShortString":
case "editableOption":
case "editableOptionShort":
return Utils.parseEscapedChars(data);
case "byteArray":
if (typeof data == "string") {

View File

@@ -181,6 +181,7 @@ class Operation {
if (ing.hint) conf.hint = ing.hint;
if (ing.disabled) conf.disabled = ing.disabled;
if (ing.target) conf.target = ing.target;
if (ing.defaultIndex) conf.defaultIndex = ing.defaultIndex;
return conf;
});
}

View File

@@ -4,10 +4,10 @@
* @license Apache-2.0
*/
// import Operation from "./Operation.js";
import OpModules from "./config/modules/OpModules";
import OperationConfig from "./config/OperationConfig.json";
import OperationError from "./errors/OperationError";
import DishError from "./errors/DishError";
import log from "loglevel";
/**
@@ -183,6 +183,10 @@ class Recipe {
// native types is not fully supported yet.
dish.set(err.message, "string");
return i;
} else if (err instanceof DishError ||
(err.type && err.type === "DishError")) {
dish.set(err.message, "string");
return i;
} else {
const e = typeof err == "string" ? { message: err } : err;

View File

@@ -5,10 +5,10 @@
*/
import utf8 from "utf8";
import moment from "moment-timezone";
import {fromBase64} from "./lib/Base64";
import {fromBase64, toBase64} from "./lib/Base64";
import {fromHex} from "./lib/Hex";
import {fromDecimal} from "./lib/Decimal";
import {fromBinary} from "./lib/Binary";
/**
@@ -298,7 +298,7 @@ class Utils {
* Accepts hex, Base64, UTF8 and Latin1 strings.
*
* @param {string} str
* @param {string} type - One of "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
* @param {string} type - One of "Binary", "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
* @returns {byteArray}
*
* @example
@@ -313,6 +313,8 @@ class Utils {
*/
static convertToByteArray(str, type) {
switch (type.toLowerCase()) {
case "binary":
return fromBinary(str);
case "hex":
return fromHex(str);
case "decimal":
@@ -333,7 +335,7 @@ class Utils {
* Accepts hex, Base64, UTF8 and Latin1 strings.
*
* @param {string} str
* @param {string} type - One of "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
* @param {string} type - One of "Binary", "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
* @returns {string}
*
* @example
@@ -348,6 +350,8 @@ class Utils {
*/
static convertToByteString(str, type) {
switch (type.toLowerCase()) {
case "binary":
return Utils.byteArrayToChars(fromBinary(str));
case "hex":
return Utils.byteArrayToChars(fromHex(str));
case "decimal":
@@ -568,6 +572,10 @@ class Utils {
cell = "";
lines.push(line);
line = [];
// Skip next byte if it is also a line delim (e.g. \r\n)
if (lineDelims.indexOf(next) >= 0 && next !== b) {
i++;
}
} else {
cell += b;
}
@@ -788,38 +796,6 @@ class Utils {
}
/**
* Expresses a number of milliseconds in a human readable format.
*
* Range | Sample Output
* -----------------------------|-------------------------------
* 0 to 45 seconds | a few seconds ago
* 45 to 90 seconds | a minute ago
* 90 seconds to 45 minutes | 2 minutes ago ... 45 minutes ago
* 45 to 90 minutes | an hour ago
* 90 minutes to 22 hours | 2 hours ago ... 22 hours ago
* 22 to 36 hours | a day ago
* 36 hours to 25 days | 2 days ago ... 25 days ago
* 25 to 45 days | a month ago
* 45 to 345 days | 2 months ago ... 11 months ago
* 345 to 545 days (1.5 years) | a year ago
* 546 days+ | 2 years ago ... 20 years ago
*
* @param {number} ms
* @returns {string}
*
* @example
* // returns "3 minutes"
* Utils.fuzzyTime(152435);
*
* // returns "5 days"
* Utils.fuzzyTime(456851321);
*/
static fuzzyTime(ms) {
return moment.duration(ms, "milliseconds").humanize();
}
/**
* Formats a list of files or directories.
*
@@ -841,6 +817,17 @@ class Utils {
return html;
};
const formatContent = function (buff, type) {
if (type.startsWith("image")) {
let dataURI = "data:";
dataURI += type + ";";
dataURI += "base64," + toBase64(buff);
return "<img style='max-width: 100%;' src='" + dataURI + "'>";
} else {
return `<pre>${Utils.escapeHtml(Utils.arrayBufferToStr(buff.buffer))}</pre>`;
}
};
const formatFile = async function(file, i) {
const buff = await Utils.readFile(file);
const blob = new Blob(
@@ -870,7 +857,7 @@ class Utils {
</div>
<div id='collapse${i}' class='collapse' aria-labelledby='heading${i}' data-parent="#files">
<div class='card-body'>
<pre>${Utils.escapeHtml(Utils.arrayBufferToStr(buff.buffer))}</pre>
${formatContent(buff, file.type)}
</div>
</div>
</div>`;

View File

@@ -25,6 +25,8 @@
"From Base32",
"To Base58",
"From Base58",
"To Base62",
"From Base62",
"To Base85",
"From Base85",
"To Base",
@@ -49,12 +51,15 @@
"Change IP format",
"Encode text",
"Decode text",
"Text Encoding Brute Force",
"Swap endianness",
"To MessagePack",
"From MessagePack",
"To Braille",
"From Braille",
"Parse TLV"
"Parse TLV",
"CSV to JSON",
"JSON to CSV"
]
},
{
@@ -84,6 +89,8 @@
"Bifid Cipher Decode",
"Affine Cipher Encode",
"Affine Cipher Decode",
"A1Z26 Cipher Encode",
"A1Z26 Cipher Decode",
"Atbash Cipher",
"Substitute",
"Derive PBKDF2 key",
@@ -93,6 +100,8 @@
"JWT Sign",
"JWT Verify",
"JWT Decode",
"Citrix CTX1 Encode",
"Citrix CTX1 Decode",
"Pseudo-Random Number Generator"
]
},
@@ -159,7 +168,8 @@
"Change IP format",
"Group IP addresses",
"Encode NetBIOS Name",
"Decode NetBIOS Name"
"Decode NetBIOS Name",
"Defang URL"
]
},
{
@@ -167,6 +177,7 @@
"ops": [
"Encode text",
"Decode text",
"Remove Diacritics",
"Unescape Unicode Characters"
]
},
@@ -178,6 +189,8 @@
"Remove null bytes",
"To Upper case",
"To Lower case",
"To Case Insensitive Regex",
"From Case Insensitive Regex",
"Add line numbers",
"Remove line numbers",
"To Table",
@@ -330,23 +343,40 @@
"From MessagePack"
]
},
{
"name": "Forensics",
"ops": [
"Detect File Type",
"Scan for Embedded Files",
"Remove EXIF",
"Extract EXIF"
]
},
{
"name": "Multimedia",
"ops": [
"Render Image",
"Play Media",
"Remove EXIF",
"Extract EXIF",
"Split Colour Channels"
]
},
{
"name": "Other",
"ops": [
"Entropy",
"Frequency distribution",
"Chi Square",
"Detect File Type",
"Scan for Embedded Files",
"Disassemble x86",
"Pseudo-Random Number Generator",
"Generate UUID",
"Generate TOTP",
"Generate HOTP",
"Generate QR Code",
"Parse QR Code",
"Haversine distance",
"Render Image",
"Remove EXIF",
"Extract EXIF",
"Generate Lorem Ipsum",
"Numberwang",
"XKCD Random Number"
]
@@ -356,6 +386,7 @@
"ops": [
"Magic",
"Fork",
"Subsection",
"Merge",
"Register",
"Label",

View File

@@ -222,7 +222,7 @@ export default ${moduleName};
console.log(`\nNext steps:
1. Add your operation to ${colors.green("src/core/config/Categories.json")}
2. Write your operation code.
3. Write tests in ${colors.green("test/tests/operations/")}
3. Write tests in ${colors.green("tests/operations/tests/")}
4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);

View File

@@ -0,0 +1,26 @@
/**
* Custom error type for handling Dish type errors.
* i.e. where the Dish cannot be successfully translated between types
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
class DishError extends Error {
/**
* Standard error constructor. Adds no new behaviour.
*
* @param args - Standard error args
*/
constructor(...args) {
super(...args);
this.type = "DishError";
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DishError);
}
}
}
export default DishError;

View File

@@ -126,14 +126,14 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
* Base64 alphabets.
*/
export const ALPHABET_OPTIONS = [
{name: "Standard: A-Za-z0-9+/=", value: "A-Za-z0-9+/="},
{name: "URL safe: A-Za-z0-9-_", value: "A-Za-z0-9-_"},
{name: "Standard (RFC 4648): A-Za-z0-9+/=", value: "A-Za-z0-9+/="},
{name: "URL safe (RFC 4648 \u00A75): A-Za-z0-9-_", value: "A-Za-z0-9-_"},
{name: "Filename safe: A-Za-z0-9+-=", value: "A-Za-z0-9+\\-="},
{name: "itoa64: ./0-9A-Za-z=", value: "./0-9A-Za-z="},
{name: "XML: A-Za-z0-9_.", value: "A-Za-z0-9_."},
{name: "y64: A-Za-z0-9._-", value: "A-Za-z0-9._-"},
{name: "z64: 0-9a-zA-Z+/=", value: "0-9a-zA-Z+/="},
{name: "Radix-64: 0-9A-Za-z+/=", value: "0-9A-Za-z+/="},
{name: "Radix-64 (RFC 4880): 0-9A-Za-z+/=", value: "0-9A-Za-z+/="},
{name: "Uuencoding: [space]-_", value: " -_"},
{name: "Xxencoding: +-0-9A-Za-z", value: "+\\-0-9A-Za-z"},
{name: "BinHex: !-,-0-689@A-NP-VX-Z[`a-fh-mp-r", value: "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r"},

70
src/core/lib/Binary.mjs Normal file
View File

@@ -0,0 +1,70 @@
/**
* Binary functions.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Utils from "../Utils";
/**
* Convert a byte array into a binary string.
*
* @param {Uint8Array|byteArray} data
* @param {string} [delim="Space"]
* @param {number} [padding=8]
* @returns {string}
*
* @example
* // returns "00010000 00100000 00110000"
* toBinary([10,20,30]);
*
* // returns "00010000 00100000 00110000"
* toBinary([10,20,30], ":");
*/
export function toBinary(data, delim="Space", padding=8) {
if (!data) return "";
delim = Utils.charRep(delim);
let output = "";
for (let i = 0; i < data.length; i++) {
output += data[i].toString(2).padStart(padding, "0") + delim;
}
if (delim.length) {
return output.slice(0, -delim.length);
} else {
return output;
}
}
/**
* Convert a binary string into a byte array.
*
* @param {string} data
* @param {string} [delim]
* @param {number} [byteLen=8]
* @returns {byteArray}
*
* @example
* // returns [10,20,30]
* fromBinary("00010000 00100000 00110000");
*
* // returns [10,20,30]
* fromBinary("00010000:00100000:00110000", "Colon");
*/
export function fromBinary(data, delim="Space", byteLen=8) {
const delimRegex = Utils.regexRep(delim);
data = data.replace(delimRegex, "");
const output = [];
for (let i = 0; i < data.length; i += byteLen) {
output.push(parseInt(data.substr(i, byteLen), 2));
}
return output;
}

View File

@@ -116,3 +116,9 @@ export function sub(operand, key) {
const result = operand - key;
return (result < 0) ? 256 + result : result;
}
/**
* Delimiter options for bitwise operations
*/
export const BITWISE_OP_DELIMS = ["Hex", "Decimal", "Binary", "Base64", "UTF8", "Latin1"];

View File

@@ -39,3 +39,21 @@ export function search (input, searchRegex, removeRegex, includeTotal) {
return output;
}
/**
* URL regular expression
*/
const protocol = "[A-Z]+://",
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
port = ":\\d+",
path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*" +
"(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:" + path + ")?", "ig");
/**
* Domain name regular expression
*/
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;

230
src/core/lib/LoremIpsum.mjs Normal file
View File

@@ -0,0 +1,230 @@
/**
* Lorem Ipsum generator.
*
* @author Klaxon [klaxon@veyr.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
/**
* Generate lorem ipsum paragraphs.
*
* @param {number} length
* @returns {string}
*/
export function GenerateParagraphs(length=3) {
const paragraphs = [];
while (paragraphs.length < length) {
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
const sentences = [];
while (sentences.length < paragraphLength) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
const sentence = getWords(sentenceLength);
sentences.push(formatSentence(sentence));
}
paragraphs.push(formatParagraph(sentences));
}
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -2);
paragraphs[0] = replaceStart(paragraphs[0]);
return paragraphs.join("");
}
/**
* Generate lorem ipsum sentences.
*
* @param {number} length
* @returns {string}
*/
export function GenerateSentences(length=3) {
const sentences = [];
while (sentences.length < length) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
const sentence = getWords(sentenceLength);
sentences.push(formatSentence(sentence));
}
const paragraphs = sentencesToParagraphs(sentences);
return paragraphs.join("");
}
/**
* Generate lorem ipsum words.
*
* @param {number} length
* @returns {string}
*/
export function GenerateWords(length=3) {
const words = getWords(length);
const sentences = wordsToSentences(words);
const paragraphs = sentencesToParagraphs(sentences);
return paragraphs.join("");
}
/**
* Generate lorem ipsum bytes.
*
* @param {number} length
* @returns {string}
*/
export function GenerateBytes(length=3) {
const str = GenerateWords(length/3);
return str.slice(0, length);
}
/**
* Get array of randomly selected words from the lorem ipsum wordList.
*
* @param {number} length
* @returns {string[]}
* @private
*/
function getWords(length=3) {
const words = [];
let word;
let previousWord;
while (words.length < length){
do {
word = wordList[Math.floor(Math.random() * wordList.length)];
} while (previousWord === word);
words.push(word);
previousWord = word;
}
return words;
}
/**
* Convert an array of words into an array of sentences
*
* @param {string[]} words
* @returns {string[]}
* @private
*/
function wordsToSentences(words) {
const sentences = [];
while (words.length > 0) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
if (sentenceLength <= words.length) {
sentences.push(formatSentence(words.splice(0, sentenceLength)));
} else {
sentences.push(formatSentence(words.splice(0, words.length)));
}
}
return sentences;
}
/**
* Convert an array of sentences into an array of paragraphs
*
* @param {string[]} sentences
* @returns {string[]}
* @private
*/
function sentencesToParagraphs(sentences) {
const paragraphs = [];
while (sentences.length > 0) {
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
paragraphs.push(formatParagraph(sentences.splice(0, paragraphLength)));
}
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -1);
paragraphs[0] = replaceStart(paragraphs[0]);
return paragraphs;
}
/**
* Format an array of words into a sentence.
*
* @param {string[]} words
* @returns {string}
* @private
*/
function formatSentence(words) {
// 0.35 chance of a comma being added randomly to the sentence.
if (Math.random() < PROBABILITY_OF_A_COMMA) {
const pos = Math.round(Math.random()*(words.length-1));
words[pos] +=",";
}
let sentence = words.join(" ");
sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1);
sentence += ".";
return sentence;
}
/**
* Format an array of sentences into a paragraph.
*
* @param {string[]} sentences
* @returns {string}
* @private
*/
function formatParagraph(sentences) {
let paragraph = sentences.join(" ");
paragraph += "\n\n";
return paragraph;
}
/**
* Get a random number based on a mean and standard deviation.
*
* @param {number} mean
* @param {number} stdDev
* @returns {number}
* @private
*/
function getRandomLength(mean, stdDev) {
let length;
do {
length = Math.round((Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1)*stdDev+mean);
} while (length <= 0);
return length;
}
/**
* Replace first 5 words with "Lorem ipsum dolor sit amet"
*
* @param {string[]} str
* @returns {string[]}
* @private
*/
function replaceStart(str) {
let words = str.split(" ");
if (words.length > 5) {
words.splice(0, 5, "Lorem", "ipsum", "dolor", "sit", "amet");
return words.join(" ");
} else {
const lorem = ["Lorem", "ipsum", "dolor", "sit", "amet"];
words = lorem.slice(0, words.length);
str = words.join(" ");
str += ".";
return str;
}
}
const SENTENCE_LENGTH_MEAN = 15;
const SENTENCE_LENGTH_STD_DEV = 9;
const PARAGRAPH_LENGTH_MEAN = 5;
const PARAGRAPH_LENGTH_STD_DEV = 2;
const PROBABILITY_OF_A_COMMA = 0.35;
const wordList = [
"ad", "adipisicing", "aliqua", "aliquip", "amet", "anim",
"aute", "cillum", "commodo", "consectetur", "consequat", "culpa",
"cupidatat", "deserunt", "do", "dolor", "dolore", "duis",
"ea", "eiusmod", "elit", "enim", "esse", "est",
"et", "eu", "ex", "excepteur", "exercitation", "fugiat",
"id", "in", "incididunt", "ipsum", "irure", "labore",
"laboris", "laborum", "Lorem", "magna", "minim", "mollit",
"nisi", "non", "nostrud", "nulla", "occaecat", "officia",
"pariatur", "proident", "qui", "quis", "reprehenderit", "sint",
"sit", "sunt", "tempor", "ullamco", "ut", "velit",
"veniam", "voluptate",
];

View File

@@ -265,9 +265,10 @@ class Magic {
* performance)
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
* @param {boolean} [useful=false] - Whether the current recipe should be scored highly
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation output
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
*/
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false) {
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null) {
if (depth < 0) return [];
// Find any operations that can be run on this data
@@ -284,9 +285,9 @@ class Magic {
isUTF8: this.isUTF8(),
entropy: this.calcEntropy(),
matchingOps: matchingOps,
useful: useful
useful: useful,
matchesCrib: crib && crib.test(this.inputStr)
});
const prevOp = recipeConfig[recipeConfig.length - 1];
// Execute each of the matching operations, then recursively call the speculativeExecution()
@@ -305,7 +306,7 @@ class Magic {
const magic = new Magic(output, this.opPatterns),
speculativeResults = await magic.speculativeExecution(
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful);
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
results = results.concat(speculativeResults);
}));
@@ -317,7 +318,7 @@ class Magic {
await Promise.all(bfEncodings.map(async enc => {
const magic = new Magic(enc.data, this.opPatterns),
bfResults = await magic.speculativeExecution(
depth-1, extLang, false, [...recipeConfig, enc.conf]);
depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
results = results.concat(bfResults);
}));

View File

@@ -0,0 +1,63 @@
/**
* @author Jarmo van Lenthe [github.com/jarmovanlenthe]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import Utils from "../Utils";
import {DELIM_OPTIONS} from "../lib/Delim";
import OperationError from "../errors/OperationError";
/**
* A1Z26 Cipher Decode operation
*/
class A1Z26CipherDecode extends Operation {
/**
* A1Z26CipherDecode constructor
*/
constructor() {
super();
this.name = "A1Z26 Cipher Decode";
this.module = "Ciphers";
this.description = "Converts alphabet order numbers into their corresponding alphabet character.<br><br>e.g. <code>1</code> becomes <code>a</code> and <code>2</code> becomes <code>b</code>.";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Delimiter",
type: "option",
value: DELIM_OPTIONS
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const delim = Utils.charRep(args[0] || "Space");
if (input.length === 0) {
return [];
}
const bites = input.split(delim);
let latin1 = "";
for (let i = 0; i < bites.length; i++) {
if (bites[i] < 1 || bites[i] > 26) {
throw new OperationError("Error: all numbers must be between 1 and 26.");
}
latin1 += Utils.chr(parseInt(bites[i], 10) + 96);
}
return latin1;
}
}
export default A1Z26CipherDecode;

View File

@@ -0,0 +1,61 @@
/**
* @author Jarmo van Lenthe [github.com/jarmovanlenthe]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import Utils from "../Utils";
import {DELIM_OPTIONS} from "../lib/Delim";
/**
* A1Z26 Cipher Encode operation
*/
class A1Z26CipherEncode extends Operation {
/**
* A1Z26CipherEncode constructor
*/
constructor() {
super();
this.name = "A1Z26 Cipher Encode";
this.module = "Ciphers";
this.description = "Converts alphabet characters into their corresponding alphabet order number.<br><br>e.g. <code>a</code> becomes <code>1</code> and <code>b</code> becomes <code>2</code>.<br><br>Non-alphabet characters are dropped.";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Delimiter",
type: "option",
value: DELIM_OPTIONS
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const delim = Utils.charRep(args[0] || "Space");
let output = "";
const sanitizedinput = input.toLowerCase(),
charcode = Utils.strToCharcode(sanitizedinput);
for (let i = 0; i < charcode.length; i++) {
const ordinal = charcode[i] - 96;
if (ordinal > 0 && ordinal <= 26) {
output += ordinal.toString(10) + delim;
}
}
return output.slice(0, -delim.length);
}
}
export default A1Z26CipherEncode;

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation";
import Utils from "../Utils";
import { bitOp, add } from "../lib/BitwiseOp";
import { bitOp, add, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
/**
* ADD operation
@@ -30,7 +30,7 @@ class ADD extends Operation {
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
"toggleValues": BITWISE_OP_DELIMS
}
];
}

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation";
import Utils from "../Utils";
import { bitOp, and } from "../lib/BitwiseOp";
import { bitOp, and, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
/**
* AND operation
@@ -30,7 +30,7 @@ class AND extends Operation {
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
"toggleValues": BITWISE_OP_DELIMS
}
];
}

View File

@@ -19,7 +19,7 @@ class Adler32Checksum extends Operation {
super();
this.name = "Adler-32 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).<br><br>Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.";
this.infoURL = "https://wikipedia.org/wiki/Adler-32";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class AnalyseHash extends Operation {
super();
this.name = "Analyse hash";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Tries to determine information about a given hash and suggests which algorithm may have been used to generate it based on its length.";
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
this.inputType = "string";

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation";
import bsonjs from "bson";
import bson from "bson";
import OperationError from "../errors/OperationError";
/**
@@ -36,8 +36,6 @@ class BSONDeserialise extends Operation {
run(input, args) {
if (!input.byteLength) return "";
const bson = new bsonjs();
try {
const data = bson.deserialize(new Buffer(input));
return JSON.stringify(data, null, 2);

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation";
import bsonjs from "bson";
import bson from "bson";
import OperationError from "../errors/OperationError";
/**
@@ -36,8 +36,6 @@ class BSONSerialise extends Operation {
run(input, args) {
if (!input) return new ArrayBuffer();
const bson = new bsonjs();
try {
const data = JSON.parse(input);
return bson.serialize(data).buffer;

View File

@@ -19,7 +19,7 @@ class Bcrypt extends Operation {
super();
this.name = "Bcrypt";
this.module = "Hashing";
this.module = "Crypto";
this.description = "bcrypt is a password hashing function designed by Niels Provos and David Mazi\xe8res, based on the Blowfish cipher, and presented at USENIX in 1999. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count (rounds) can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.<br><br>Enter the password in the input to generate its hash.";
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
this.inputType = "string";

View File

@@ -19,7 +19,7 @@ class BcryptCompare extends Operation {
super();
this.name = "Bcrypt compare";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Tests whether the input matches the given bcrypt hash. To test multiple possible passwords, use the 'Fork' operation.";
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
this.inputType = "string";

View File

@@ -20,7 +20,7 @@ class BcryptParse extends Operation {
super();
this.name = "Bcrypt parse";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Parses a bcrypt hash to determine the number of rounds used, the salt, and the password hash.";
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
this.inputType = "string";

View File

@@ -19,7 +19,7 @@ class CRC16Checksum extends Operation {
super();
this.name = "CRC-16 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class CRC32Checksum extends Operation {
super();
this.name = "CRC-32 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.";
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
this.inputType = "ArrayBuffer";

View File

@@ -0,0 +1,80 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import Utils from "../Utils";
/**
* CSV to JSON operation
*/
class CSVToJSON extends Operation {
/**
* CSVToJSON constructor
*/
constructor() {
super();
this.name = "CSV to JSON";
this.module = "Default";
this.description = "Converts a CSV file to JSON format.";
this.infoURL = "https://wikipedia.org/wiki/Comma-separated_values";
this.inputType = "string";
this.outputType = "JSON";
this.args = [
{
name: "Cell delimiters",
type: "binaryShortString",
value: ","
},
{
name: "Row delimiters",
type: "binaryShortString",
value: "\\r\\n"
},
{
name: "Format",
type: "option",
value: ["Array of dictionaries", "Array of arrays"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {JSON}
*/
run(input, args) {
const [cellDelims, rowDelims, format] = args;
let json, header;
try {
json = Utils.parseCSV(input, cellDelims.split(""), rowDelims.split(""));
} catch (err) {
throw new OperationError("Unable to parse CSV: " + err);
}
switch (format) {
case "Array of dictionaries":
header = json[0];
return json.slice(1).map(row => {
const obj = {};
header.forEach((h, i) => {
obj[h] = row[i];
});
return obj;
});
case "Array of arrays":
default:
return json;
}
}
}
export default CSVToJSON;

View File

@@ -19,7 +19,7 @@ class CTPH extends Operation {
super();
this.name = "CTPH";
this.module = "Hashing";
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.inputType = "string";

View File

@@ -0,0 +1,58 @@
/**
* @author bwhitn [brian.m.whitney@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import cptable from "../vendor/js-codepage/cptable.js";
/**
* Citrix CTX1 Decode operation
*/
class CitrixCTX1Decode extends Operation {
/**
* CitrixCTX1Decode constructor
*/
constructor() {
super();
this.name = "Citrix CTX1 Decode";
this.module = "Encodings";
this.description = "Decodes strings in a Citrix CTX1 password format to plaintext.";
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
this.inputType = "byteArray";
this.outputType = "string";
this.args = [];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
if (input.length % 4 !== 0) {
throw new OperationError("Incorrect hash length");
}
const revinput = input.reverse();
const result = [];
let temp = 0;
for (let i = 0; i < revinput.length; i += 2) {
if (i + 2 >= revinput.length) {
temp = 0;
} else {
temp = ((revinput[i + 2] - 0x41) & 0xf) ^ (((revinput[i + 3]- 0x41) << 4) & 0xf0);
}
temp = (((revinput[i] - 0x41) & 0xf) ^ (((revinput[i + 1] - 0x41) << 4) & 0xf0)) ^ 0xa5 ^ temp;
result.push(temp);
}
// Decodes a utf-16le string
return cptable.utils.decode(1200, result.reverse());
}
}
export default CitrixCTX1Decode;

View File

@@ -0,0 +1,50 @@
/**
* @author bwhitn [brian.m.whitney@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import cptable from "../vendor/js-codepage/cptable.js";
/**
* Citrix CTX1 Encode operation
*/
class CitrixCTX1Encode extends Operation {
/**
* CitrixCTX1Encode constructor
*/
constructor() {
super();
this.name = "Citrix CTX1 Encode";
this.module = "Encodings";
this.description = "Encodes strings to Citrix CTX1 password format.";
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
this.inputType = "string";
this.outputType = "byteArray";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
const utf16pass = Array.from(cptable.utils.encode(1200, input));
const result = [];
let temp = 0;
for (let i = 0; i < utf16pass.length; i++) {
temp = utf16pass[i] ^ 0xa5 ^ temp;
result.push(((temp >>> 4) & 0xf) + 0x41);
result.push((temp & 0xf) + 0x41);
}
return result;
}
}
export default CitrixCTX1Encode;

View File

@@ -22,7 +22,7 @@ class CompareCTPHHashes extends Operation {
super();
this.name = "Compare CTPH hashes";
this.module = "Hashing";
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.inputType = "string";

View File

@@ -22,7 +22,7 @@ class CompareSSDEEPHashes extends Operation {
super();
this.name = "Compare SSDEEP hashes";
this.module = "Hashing";
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.inputType = "string";

View File

@@ -20,7 +20,7 @@ class DecodeText extends Operation {
super();
this.name = "Decode text";
this.module = "CharEnc";
this.module = "Encodings";
this.description = [
"Decodes text from the chosen character encoding.",
"<br><br>",

View File

@@ -0,0 +1,102 @@
/**
* @author arnydo [arnydo@protonmail.com]
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import {URL_REGEX, DOMAIN_REGEX} from "../lib/Extract";
/**
* DefangURL operation
*/
class DefangURL extends Operation {
/**
* DefangURL constructor
*/
constructor() {
super();
this.name = "Defang URL";
this.module = "Default";
this.description = "Takes a Universal Resource Locator (URL) and 'Defangs' it; meaning the URL becomes invalid, neutralising the risk of accidentally clicking on a malicious link.<br><br>This is often used when dealing with malicious links or IOCs.<br><br>Works well when combined with the 'Extract URLs' operation.";
this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Escape dots",
type: "boolean",
value: true
},
{
name: "Escape http",
type: "boolean",
value: true
},
{
name: "Escape ://",
type: "boolean",
value: true
},
{
name: "Process",
type: "option",
value: ["Valid domains and full URLs", "Only full URLs", "Everything"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [dots, http, slashes, process] = args;
switch (process) {
case "Valid domains and full URLs":
input = input.replace(URL_REGEX, x => {
return defangURL(x, dots, http, slashes);
});
input = input.replace(DOMAIN_REGEX, x => {
return defangURL(x, dots, http, slashes);
});
break;
case "Only full URLs":
input = input.replace(URL_REGEX, x => {
return defangURL(x, dots, http, slashes);
});
break;
case "Everything":
input = defangURL(input, dots, http, slashes);
break;
}
return input;
}
}
/**
* Defangs a given URL
*
* @param {string} url
* @param {boolean} dots
* @param {boolean} http
* @param {boolean} slashes
* @returns {string}
*/
function defangURL(url, dots, http, slashes) {
if (dots) url = url.replace(/\./g, "[.]");
if (http) url = url.replace(/http/gi, "hxxp");
if (slashes) url = url.replace(/:\/\//g, "[://]");
return url;
}
export default DefangURL;

View File

@@ -20,7 +20,7 @@ class EncodeText extends Operation {
super();
this.name = "Encode text";
this.module = "CharEnc";
this.module = "Encodings";
this.description = [
"Encodes text into the chosen character encoding.",
"<br><br>",

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation";
import { search } from "../lib/Extract";
import { search, DOMAIN_REGEX } from "../lib/Extract";
/**
* Extract domains operation
@@ -38,10 +38,8 @@ class ExtractDomains extends Operation {
* @returns {string}
*/
run(input, args) {
const displayTotal = args[0],
regex = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
return search(input, regex, null, displayTotal);
const displayTotal = args[0];
return search(input, DOMAIN_REGEX, null, displayTotal);
}
}

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation";
import { search } from "../lib/Extract";
import { search, URL_REGEX } from "../lib/Extract";
/**
* Extract URLs operation
@@ -38,16 +38,8 @@ class ExtractURLs extends Operation {
* @returns {string}
*/
run(input, args) {
const displayTotal = args[0],
protocol = "[A-Z]+://",
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
port = ":\\d+";
let path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*";
path += "(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
const regex = new RegExp(protocol + hostname + "(?:" + port +
")?(?:" + path + ")?", "ig");
return search(input, regex, null, displayTotal);
const displayTotal = args[0];
return search(input, URL_REGEX, null, displayTotal);
}
}

View File

@@ -19,7 +19,7 @@ class Fletcher16Checksum extends Operation {
super();
this.name = "Fletcher-16 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-16";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class Fletcher32Checksum extends Operation {
super();
this.name = "Fletcher-32 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-32";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class Fletcher64Checksum extends Operation {
super();
this.name = "Fletcher-64 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-64";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class Fletcher8Checksum extends Operation {
super();
this.name = "Fletcher-8 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum";
this.inputType = "byteArray";

View File

@@ -0,0 +1,58 @@
/**
* @author tcode2k16 [tcode2k16@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import BigNumber from "bignumber.js";
import Utils from "../Utils";
/**
* From Base62 operation
*/
class FromBase62 extends Operation {
/**
* FromBase62 constructor
*/
constructor() {
super();
this.name = "From Base62";
this.module = "Default";
this.description = "Base62 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers. The high number base results in shorter strings than with the decimal or hexadecimal system.";
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
this.inputType = "string";
this.outputType = "byteArray";
this.args = [
{
name: "Alphabet",
type: "string",
value: "0-9A-Za-z"
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
if (input.length < 1) return [];
const ALPHABET = Utils.expandAlphRange(args[0]).join("");
const BN = BigNumber.clone({ ALPHABET });
const re = new RegExp("[^" + ALPHABET.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
input = input.replace(re, "");
const number = new BN(input, 62);
return Utils.convertToByteArray(number.toString(16), "Hex");
}
}
export default FromBase62;

View File

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

View File

@@ -7,6 +7,7 @@
import Operation from "../Operation";
import Utils from "../Utils";
import {BIN_DELIM_OPTIONS} from "../lib/Delim";
import {fromBinary} from "../lib/Binary";
/**
* From Binary operation
@@ -77,15 +78,7 @@ class FromBinary extends Operation {
* @returns {byteArray}
*/
run(input, args) {
const delimRegex = Utils.regexRep(args[0] || "Space");
input = input.replace(delimRegex, "");
const output = [];
const byteLen = 8;
for (let i = 0; i < input.length; i += byteLen) {
output.push(parseInt(input.substr(i, byteLen), 2));
}
return output;
return fromBinary(input, args[0]);
}
/**

View File

@@ -0,0 +1,39 @@
/**
* @author masq [github.cyberchef@masq.cc]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
/**
* From Case Insensitive Regex operation
*/
class FromCaseInsensitiveRegex extends Operation {
/**
* FromCaseInsensitiveRegex constructor
*/
constructor() {
super();
this.name = "From Case Insensitive Regex";
this.module = "Default";
this.description = "Converts a case-insensitive regex string to a case sensitive regex string (no guarantee on it being the proper original casing) in case the i flag wasn't available at the time but now is, or you need it to be case-sensitive again.<br><br>e.g. <code>[mM][oO][zZ][iI][lL][lL][aA]/[0-9].[0-9] .*</code> becomes <code>Mozilla/[0-9].[0-9] .*</code>";
this.infoURL = "https://wikipedia.org/wiki/Regular_expression";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
return input.replace(/\[[a-z]{2}\]/ig, m => m[1].toUpperCase() === m[2].toUpperCase() ? m[1] : m);
}
}
export default FromCaseInsensitiveRegex;

View File

@@ -29,38 +29,43 @@ class FromDecimal extends Operation {
"name": "Delimiter",
"type": "option",
"value": DELIM_OPTIONS
},
{
"name": "Support signed values",
"type": "boolean",
"value": false
}
];
this.patterns = [
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Space"]
args: ["Space", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Comma"]
args: ["Comma", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Semi-colon"]
args: ["Semi-colon", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Colon"]
args: ["Colon", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["Line feed"]
args: ["Line feed", false]
},
{
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
flags: "",
args: ["CRLF"]
args: ["CRLF", false]
},
];
}
@@ -71,7 +76,11 @@ class FromDecimal extends Operation {
* @returns {byteArray}
*/
run(input, args) {
return fromDecimal(input, args[0]);
let data = fromDecimal(input, args[0]);
if (args[1]) { // Convert negatives
data = data.map(v => v < 0 ? 0xFF + v + 1 : v);
}
return data;
}
}

View File

@@ -19,7 +19,7 @@ class FromGeohash extends Operation {
super();
this.name = "From Geohash";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Converts Geohash strings into Lat/Long coordinates. For example, <code>ww8p1r4t8</code> becomes <code>37.8324,112.5584</code>.";
this.infoURL = "https://wikipedia.org/wiki/Geohash";
this.inputType = "string";

View File

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

View File

@@ -41,7 +41,7 @@ class GenerateAllHashes extends Operation {
super();
this.name = "Generate all hashes";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Generates all available hashes and checksums for the input.";
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
this.inputType = "ArrayBuffer";

View File

@@ -0,0 +1,70 @@
/**
* @author klaxon [klaxon@veyr.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import { GenerateParagraphs, GenerateSentences, GenerateWords, GenerateBytes } from "../lib/LoremIpsum";
/**
* Generate Lorem Ipsum operation
*/
class GenerateLoremIpsum extends Operation {
/**
* GenerateLoremIpsum constructor
*/
constructor() {
super();
this.name = "Generate Lorem Ipsum";
this.module = "Default";
this.description = "Generate varying length lorem ipsum placeholder text.";
this.infoURL = "https://wikipedia.org/wiki/Lorem_ipsum";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Length",
"type": "number",
"value": "3"
},
{
"name": "Length in",
"type": "option",
"value": ["Paragraphs", "Sentences", "Words", "Bytes"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [length, lengthType] = args;
if (length < 1){
throw new OperationError("Length must be greater than 0");
}
switch (lengthType) {
case "Paragraphs":
return GenerateParagraphs(length);
case "Sentences":
return GenerateSentences(length);
case "Words":
return GenerateWords(length);
case "Bytes":
return GenerateBytes(length);
default:
throw new OperationError("Invalid length type");
}
}
}
export default GenerateLoremIpsum;

View File

@@ -0,0 +1,119 @@
/**
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import qr from "qr-image";
import { toBase64 } from "../lib/Base64";
import Magic from "../lib/Magic";
import Utils from "../Utils";
/**
* Generate QR Code operation
*/
class GenerateQRCode extends Operation {
/**
* GenerateQRCode constructor
*/
constructor() {
super();
this.name = "Generate QR Code";
this.module = "Image";
this.description = "Generates a Quick Response (QR) code from the input text.<br><br>A QR code is a type of matrix barcode (or two-dimensional barcode) first designed in 1994 for the automotive industry in Japan. A barcode is a machine-readable optical label that contains information about the item to which it is attached.";
this.infoURL = "https://wikipedia.org/wiki/QR_code";
this.inputType = "string";
this.outputType = "byteArray";
this.presentType = "html";
this.args = [
{
"name": "Image Format",
"type": "option",
"value": ["PNG", "SVG", "EPS", "PDF"]
},
{
"name": "Module size (px)",
"type": "number",
"value": 5
},
{
"name": "Margin (num modules)",
"type": "number",
"value": 2
},
{
"name": "Error correction",
"type": "option",
"value": ["Low", "Medium", "Quartile", "High"],
"defaultIndex": 1
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
const [format, size, margin, errorCorrection] = args;
// Create new QR image from the input data, and convert it to a buffer
const qrImage = qr.imageSync(input, {
type: format,
size: size,
margin: margin,
"ec_level": errorCorrection.charAt(0).toUpperCase()
});
if (qrImage == null) {
throw new OperationError("Error generating QR code.");
}
switch (format) {
case "SVG":
case "EPS":
case "PDF":
return [...Buffer.from(qrImage)];
case "PNG":
// Return the QR image buffer as a byte array
return [...qrImage];
default:
throw new OperationError("Unsupported QR code format.");
}
}
/**
* Displays the QR image using HTML for web apps
*
* @param {byteArray} data
* @returns {html}
*/
present(data, args) {
if (!data.length) return "";
const [format] = args;
if (format === "PNG") {
let dataURI = "data:";
const type = Magic.magicFileType(data);
if (type && type.mime.indexOf("image") === 0){
dataURI += type.mime + ";";
} else {
throw new OperationError("Invalid PNG file generated by QR image");
}
dataURI += "base64," + toBase64(data);
return `<img src="${dataURI}">`;
}
return Utils.byteArrayToChars(data);
}
}
export default GenerateQRCode;

View File

@@ -22,7 +22,7 @@ class GroupIPAddresses extends Operation {
super();
this.name = "Group IP addresses";
this.module = "JSBN";
this.module = "Default";
this.description = "Groups a list of IP addresses into subnets. Supports both IPv4 and IPv6 addresses.";
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
this.inputType = "string";

View File

@@ -19,7 +19,7 @@ class HAS160 extends Operation {
super();
this.name = "HAS-160";
this.module = "Hashing";
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.infoURL = "https://wikipedia.org/wiki/HAS-160";
this.inputType = "ArrayBuffer";

View File

@@ -20,7 +20,7 @@ class HMAC extends Operation {
super();
this.name = "HMAC";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Keyed-Hash Message Authentication Codes (HMAC) are a mechanism for message authentication using cryptographic hash functions.";
this.infoURL = "https://wikipedia.org/wiki/HMAC";
this.inputType = "ArrayBuffer";
@@ -28,8 +28,9 @@ class HMAC extends Operation {
this.args = [
{
"name": "Key",
"type": "binaryString",
"value": ""
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
},
{
"name": "Hashing function",
@@ -66,12 +67,12 @@ class HMAC extends Operation {
* @returns {string}
*/
run(input, args) {
const key = args[0],
const key = Utils.convertToByteString(args[0].string || "", args[0].option),
hashFunc = args[1].toLowerCase(),
msg = Utils.arrayBufferToStr(input, false),
hasher = CryptoApi.getHasher(hashFunc);
const mac = CryptoApi.getHmac(CryptoApi.encoder.fromUtf(key), hasher);
const mac = CryptoApi.getHmac(key, hasher);
mac.update(msg);
return CryptoApi.encoder.toHex(mac.finalize());
}

View File

@@ -1,5 +1,6 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @author Phillip Nordwall [phillip.nordwall@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
@@ -27,7 +28,12 @@ class JSONBeautify extends Operation {
{
"name": "Indent string",
"type": "binaryShortString",
"value": "\\t"
"value": " "
},
{
"name": "Sort Object Keys",
"type": "boolean",
"value": false
}
];
}
@@ -38,11 +44,35 @@ class JSONBeautify extends Operation {
* @returns {string}
*/
run(input, args) {
const indentStr = args[0];
const [indentStr, sortBool] = args;
if (!input) return "";
if (sortBool) {
input = JSON.stringify(JSONBeautify._sort(JSON.parse(input)));
}
return vkbeautify.json(input, indentStr);
}
/**
* Sort JSON representation of an object
*
* @author Phillip Nordwall [phillip.nordwall@gmail.com]
* @private
* @param {object} o
* @returns {object}
*/
static _sort(o) {
if (Array.isArray(o)) {
return o.map(JSONBeautify._sort);
} else if ("[object Object]" === Object.prototype.toString.call(o)) {
return Object.keys(o).sort().reduce(function(a, k) {
a[k] = JSONBeautify._sort(o[k]);
return a;
}, {});
}
return o;
}
}
export default JSONBeautify;

View File

@@ -0,0 +1,111 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
/**
* JSON to CSV operation
*/
class JSONToCSV extends Operation {
/**
* JSONToCSV constructor
*/
constructor() {
super();
this.name = "JSON to CSV";
this.module = "Default";
this.description = "Converts JSON data to a CSV based on the definition in RFC 4180.";
this.infoURL = "https://wikipedia.org/wiki/Comma-separated_values";
this.inputType = "JSON";
this.outputType = "string";
this.args = [
{
name: "Cell delimiter",
type: "binaryShortString",
value: ","
},
{
name: "Row delimiter",
type: "binaryShortString",
value: "\\r\\n"
}
];
}
/**
* @param {JSON} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [cellDelim, rowDelim] = args;
// Record values so they don't have to be passed to other functions explicitly
this.cellDelim = cellDelim;
this.rowDelim = rowDelim;
const self = this;
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;
} catch (err) {
throw new OperationError("Unable to parse JSON to CSV: " + err.toString());
}
}
/**
* Correctly escapes a cell's contents based on the cell and row delimiters.
*
* @param {string} data
* @returns {string}
*/
escapeCellContents(data) {
// Double quotes should be doubled up
data = data.replace(/"/g, '""');
// If the cell contains a cell or row delimiter or a double quote, it mut be enclosed in double quotes
if (
data.indexOf(this.cellDelim) >= 0 ||
data.indexOf(this.rowDelim) >= 0 ||
data.indexOf("\n") >= 0 ||
data.indexOf("\r") >= 0 ||
data.indexOf('"') >= 0
) {
data = `"${data}"`;
}
return data;
}
}
export default JSONToCSV;

View File

@@ -20,7 +20,7 @@ class Keccak extends Operation {
super();
this.name = "Keccak";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Keccak hash algorithm was designed by Guido Bertoni, Joan Daemen, Micha\xebl Peeters, and Gilles Van Assche, building upon RadioGat\xfan. It was selected as the winner of the SHA-3 design competition.<br><br>This version of the algorithm is Keccak[c=2d] and differs from the SHA-3 specification.";
this.infoURL = "https://wikipedia.org/wiki/SHA-3";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class MD2 extends Operation {
super();
this.name = "MD2";
this.module = "Hashing";
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.infoURL = "https://wikipedia.org/wiki/MD2_(cryptography)";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class MD4 extends Operation {
super();
this.name = "MD4";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The MD4 (Message-Digest 4) algorithm is a cryptographic hash function developed by Ronald Rivest in 1990. The digest length is 128 bits. The algorithm has influenced later designs, such as the MD5, SHA-1 and RIPEMD algorithms.<br><br>The security of MD4 has been severely compromised.";
this.infoURL = "https://wikipedia.org/wiki/MD4";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class MD5 extends Operation {
super();
this.name = "MD5";
this.module = "Hashing";
this.module = "Crypto";
this.description = "MD5 (Message-Digest 5) is a widely used hash function. It has been used in a variety of security applications and is also commonly used to check the integrity of files.<br><br>However, MD5 is not collision resistant and it isn't suitable for applications like SSL/TLS certificates or digital signatures that rely on this property.";
this.infoURL = "https://wikipedia.org/wiki/MD5";
this.inputType = "ArrayBuffer";

View File

@@ -20,7 +20,7 @@ class MD6 extends Operation {
super();
this.name = "MD6";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The MD6 (Message-Digest 6) algorithm is a cryptographic hash function. It uses a Merkle tree-like structure to allow for immense parallel computation of hashes for very long inputs.";
this.infoURL = "https://wikipedia.org/wiki/MD6";
this.inputType = "string";

View File

@@ -23,7 +23,7 @@ class Magic extends Operation {
this.name = "Magic";
this.flowControl = true;
this.module = "Default";
this.description = "The Magic operation attempts to detect various properties of the input data and suggests which operations could help to make more sense of it.<br><br><b>Options</b><br><u>Depth:</u> If an operation appears to match the data, it will be run and the result will be analysed further. This argument controls the maximum number of levels of recursion.<br><br><u>Intensive mode:</u> When this is turned on, various operations like XOR, bit rotates, and character encodings are brute-forced to attempt to detect valid data underneath. To improve performance, only the first 100 bytes of the data is brute-forced.<br><br><u>Extensive language support:</u> At each stage, the relative byte frequencies of the data will be compared to average frequencies for a number of languages. The default set consists of ~40 of the most commonly used languages on the Internet. The extensive list consists of 284 languages and can result in many languages matching the data if their byte frequencies are similar.";
this.description = "The Magic operation attempts to detect various properties of the input data and suggests which operations could help to make more sense of it.<br><br><b>Options</b><br><u>Depth:</u> If an operation appears to match the data, it will be run and the result will be analysed further. This argument controls the maximum number of levels of recursion.<br><br><u>Intensive mode:</u> When this is turned on, various operations like XOR, bit rotates, and character encodings are brute-forced to attempt to detect valid data underneath. To improve performance, only the first 100 bytes of the data is brute-forced.<br><br><u>Extensive language support:</u> At each stage, the relative byte frequencies of the data will be compared to average frequencies for a number of languages. The default set consists of ~40 of the most commonly used languages on the Internet. The extensive list consists of 284 languages and can result in many languages matching the data if their byte frequencies are similar.<br><br>Optionally enter a regular expression to match a string you expect to find to filter results (crib).";
this.infoURL = "https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic";
this.inputType = "ArrayBuffer";
this.outputType = "JSON";
@@ -43,6 +43,11 @@ class Magic extends Operation {
"name": "Extensive language support",
"type": "boolean",
"value": false
},
{
"name": "Crib (known plaintext string or regex)",
"type": "string",
"value": ""
}
];
}
@@ -56,10 +61,16 @@ class Magic extends Operation {
*/
async run(state) {
const ings = state.opList[state.progress].ingValues,
[depth, intensive, extLang] = ings,
[depth, intensive, extLang, crib] = ings,
dish = state.dish,
magic = new MagicLib(await dish.get(Dish.ARRAY_BUFFER)),
options = await magic.speculativeExecution(depth, extLang, intensive);
cribRegex = (crib && crib.length) ? new RegExp(crib, "i") : null;
let options = await magic.speculativeExecution(depth, extLang, intensive, [], false, cribRegex);
// Filter down to results which matched the crib
if (cribRegex) {
options = options.filter(option => option.matchesCrib);
}
// Record the current state for use when presenting
this.state = state;

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation";
import Utils from "../Utils";
import { bitOp, or } from "../lib/BitwiseOp";
import { bitOp, or, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
/**
* OR operation
@@ -30,7 +30,7 @@ class OR extends Operation {
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
"toggleValues": BITWISE_OP_DELIMS
}
];
}

View File

@@ -21,7 +21,7 @@ class ParseIPRange extends Operation {
super();
this.name = "Parse IP range";
this.module = "JSBN";
this.module = "Default";
this.description = "Given a CIDR range (e.g. <code>10.0.0.0/24</code>), hyphenated range (e.g. <code>10.0.0.0 - 10.0.1.0</code>), or a list of IPs and/or CIDR ranges (separated by a new line), this operation provides network information and enumerates all IP addresses in the range.<br><br>IPv6 is supported but will not be enumerated.";
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
this.inputType = "string";

View File

@@ -23,7 +23,7 @@ class ParseIPv4Header extends Operation {
super();
this.name = "Parse IPv4 header";
this.module = "JSBN";
this.module = "Default";
this.description = "Given an IPv4 header, this operations parses and displays each field in an easily readable format.";
this.infoURL = "https://wikipedia.org/wiki/IPv4#Header";
this.inputType = "string";

View File

@@ -8,7 +8,7 @@ import Operation from "../Operation";
import Utils from "../Utils";
import OperationError from "../errors/OperationError";
import {strToIpv6, ipv6ToStr, ipv4ToStr, IPV6_REGEX} from "../lib/IP";
import BigInteger from "jsbn";
import BigNumber from "bignumber.js";
/**
* Parse IPv6 address operation
@@ -22,7 +22,7 @@ class ParseIPv6Address extends Operation {
super();
this.name = "Parse IPv6 address";
this.module = "JSBN";
this.module = "Default";
this.description = "Displays the longhand and shorthand versions of a valid IPv6 address.<br><br>Recognises all reserved ranges and parses encapsulated or tunnelled addresses including Teredo and 6to4.";
this.infoURL = "https://wikipedia.org/wiki/IPv6_address";
this.inputType = "string";
@@ -147,7 +147,7 @@ class ParseIPv6Address extends Operation {
const v4Addr = ipv4ToStr((ipv6[1] << 16) + ipv6[2]),
slaId = ipv6[3],
interfaceIdStr = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
interfaceId = new BigInteger(interfaceIdStr, 16);
interfaceId = new BigNumber(interfaceIdStr, 16);
output += "\n\nEncapsulated IPv4 address: " + v4Addr +
"\nSLA ID: " + slaId +

View File

@@ -0,0 +1,107 @@
/**
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import Magic from "../lib/Magic";
import jsqr from "jsqr";
import jimp from "jimp";
/**
* Parse QR Code operation
*/
class ParseQRCode extends Operation {
/**
* ParseQRCode constructor
*/
constructor() {
super();
this.name = "Parse QR Code";
this.module = "Image";
this.description = "Reads an image file and attempts to detect and read a Quick Response (QR) code from the image.<br><br><u>Normalise Image</u><br>Attempts to normalise the image before parsing it to improve detection of a QR code.";
this.infoURL = "https://wikipedia.org/wiki/QR_code";
this.inputType = "byteArray";
this.outputType = "string";
this.args = [
{
"name": "Normalise image",
"type": "boolean",
"value": false
}
];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const type = Magic.magicFileType(input);
const [normalise] = args;
// Make sure that the input is an image
if (type && type.mime.indexOf("image") === 0) {
let image = input;
if (normalise) {
// Process the image to be easier to read by jsqr
// Disables the alpha channel
// Sets the image default background to white
// Normalises the image colours
// Makes the image greyscale
// Converts image to a JPEG
image = await new Promise((resolve, reject) => {
jimp.read(Buffer.from(input))
.then(image => {
image
.rgba(false)
.background(0xFFFFFFFF)
.normalize()
.greyscale()
.getBuffer(jimp.MIME_JPEG, (error, result) => {
resolve(result);
});
})
.catch(err => {
reject(new OperationError("Error reading the image file."));
});
});
}
if (image instanceof OperationError) {
throw image;
}
return new Promise((resolve, reject) => {
jimp.read(Buffer.from(image))
.then(image => {
if (image.bitmap != null) {
const qrData = jsqr(image.bitmap.data, image.getWidth(), image.getHeight());
if (qrData != null) {
resolve(qrData.data);
} else {
reject(new OperationError("Couldn't read a QR code from the image."));
}
} else {
reject(new OperationError("Error reading the image file."));
}
})
.catch(err => {
reject(new OperationError("Error reading the image file."));
});
});
} else {
throw new OperationError("Invalid file type.");
}
}
}
export default ParseQRCode;

View File

@@ -181,8 +181,8 @@ class ParseX509Certificate extends Operation {
Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn})
Algorithm ID: ${cert.getSignatureAlgorithmField()}
Validity
Not Before: ${nbDate} (dd-mm-yy hh:mm:ss) (${cert.getNotBefore()})
Not After: ${naDate} (dd-mm-yy hh:mm:ss) (${cert.getNotAfter()})
Not Before: ${nbDate} (dd-mm-yyyy hh:mm:ss) (${cert.getNotBefore()})
Not After: ${naDate} (dd-mm-yyyy hh:mm:ss) (${cert.getNotAfter()})
Issuer
${issuerStr}
Subject
@@ -206,12 +206,15 @@ ${extensions}`;
* @returns {string}
*/
function formatDate (dateStr) {
return dateStr[4] + dateStr[5] + "/" +
dateStr[2] + dateStr[3] + "/" +
dateStr[0] + dateStr[1] + " " +
dateStr[6] + dateStr[7] + ":" +
if (dateStr.length === 13) { // UTC Time
dateStr = (dateStr[0] < "5" ? "20" : "19") + dateStr;
}
return dateStr[6] + dateStr[7] + "/" +
dateStr[4] + dateStr[5] + "/" +
dateStr[0] + dateStr[1] + dateStr[2] + dateStr[3] + " " +
dateStr[8] + dateStr[9] + ":" +
dateStr[10] + dateStr[11];
dateStr[10] + dateStr[11] + ":" +
dateStr[12] + dateStr[13];
}
export default ParseX509Certificate;

View File

@@ -0,0 +1,102 @@
/**
* @author anthony-arnold [anthony.arnold@uqconnect.edu.au]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import { fromBase64, toBase64 } from "../lib/Base64";
import { fromHex } from "../lib/Hex";
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import Utils from "../Utils";
import Magic from "../lib/Magic";
/**
* PlayMedia operation
*/
class PlayMedia extends Operation {
/**
* PlayMedia constructor
*/
constructor() {
super();
this.name = "Play Media";
this.module = "Default";
this.description = "Plays the input as audio or video depending on the type.<br><br>Tags: sound, movie, mp3, mp4, mov, webm, wav, ogg";
this.infoURL = "";
this.inputType = "string";
this.outputType = "byteArray";
this.presentType = "html";
this.args = [
{
"name": "Input format",
"type": "option",
"value": ["Raw", "Base64", "Hex"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray} The multimedia data as bytes.
*/
run(input, args) {
const [inputFormat] = args;
if (!input.length) return [];
// Convert input to raw bytes
switch (inputFormat) {
case "Hex":
input = fromHex(input);
break;
case "Base64":
// Don't trust the Base64 entered by the user.
// Unwrap it first, then re-encode later.
input = fromBase64(input, undefined, "byteArray");
break;
case "Raw":
default:
input = Utils.strToByteArray(input);
break;
}
// Determine file type
const type = Magic.magicFileType(input);
if (!(type && /^audio|video/.test(type.mime))) {
throw new OperationError("Invalid or unrecognised file type");
}
return input;
}
/**
* Displays an audio or video element that may be able to play the media
* file.
*
* @param data {byteArray} Data containing an audio or video file.
* @returns {string} Markup to display a media player.
*/
async present(data) {
if (!data.length) return "";
const type = Magic.magicFileType(data);
const matches = /^audio|video/.exec(type.mime);
if (!matches) {
throw new OperationError("Invalid file type");
}
const dataURI = `data:${type.mime};base64,${toBase64(data)}`;
const element = matches[0];
let html = `<${element} src='${dataURI}' type='${type.mime}' controls>`;
html += "<p>Unsupported media type.</p>";
html += `</${element}>`;
return html;
}
}
export default PlayMedia;

View File

@@ -19,7 +19,7 @@ class RIPEMD extends Operation {
super();
this.name = "RIPEMD";
this.module = "Hashing";
this.module = "Crypto";
this.description = "RIPEMD (RACE Integrity Primitives Evaluation Message Digest) is a family of cryptographic hash functions developed in Leuven, Belgium, by Hans Dobbertin, Antoon Bosselaers and Bart Preneel at the COSIC research group at the Katholieke Universiteit Leuven, and first published in 1996.<br><br>RIPEMD was based upon the design principles used in MD4, and is similar in performance to the more popular SHA-1.<br><br>";
this.infoURL = "https://wikipedia.org/wiki/RIPEMD";
this.inputType = "ArrayBuffer";

View File

@@ -228,40 +228,29 @@ function regexList (input, regex, displayTotal, matches, captureGroups) {
function regexHighlight (input, regex, displayTotal) {
let output = "",
title = "",
m,
hl = 1,
i = 0,
total = 0;
while ((m = regex.exec(input))) {
// Moves pointer when an empty string is matched (prevents infinite loop)
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
output = input.replace(regex, (match, ...args) => {
args.pop(); // Throw away full string
const offset = args.pop(),
groups = args;
// Add up to match
output += Utils.escapeHtml(input.slice(i, m.index));
title = `Offset: ${m.index}\n`;
if (m.length > 1) {
title = `Offset: ${offset}\n`;
if (groups.length) {
title += "Groups:\n";
for (let n = 1; n < m.length; ++n) {
title += `\t${n}: ${m[n]}\n`;
for (let i = 0; i < groups.length; i++) {
title += `\t${i+1}: ${Utils.escapeHtml(groups[i])}\n`;
}
}
// Add match with highlighting
output += "<span class='hl"+hl+"' title='"+title+"'>" + Utils.escapeHtml(m[0]) + "</span>";
// Switch highlight
hl = hl === 1 ? 2 : 1;
i = regex.lastIndex;
total++;
}
// Add all after final match
output += Utils.escapeHtml(input.slice(i, input.length));
return `<span class='hl${hl}' title='${title}'>${Utils.escapeHtml(match)}</span>`;
});
if (displayTotal)
output = "Total found: " + total + "\n\n" + output;

View File

@@ -0,0 +1,41 @@
/**
* @author Klaxon [klaxon@veyr.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
/**
* Remove Diacritics operation
*/
class RemoveDiacritics extends Operation {
/**
* RemoveDiacritics constructor
*/
constructor() {
super();
this.name = "Remove Diacritics";
this.module = "Default";
this.description = "Replaces accented characters with their latin character equivalent.";
this.infoURL = "https://wikipedia.org/wiki/Diacritic";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
// reference: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463
return input.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
}
}
export default RemoveDiacritics;

View File

@@ -19,7 +19,7 @@ class SHA0 extends Operation {
super();
this.name = "SHA0";
this.module = "Hashing";
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.infoURL = "https://wikipedia.org/wiki/SHA-1#SHA-0";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class SHA1 extends Operation {
super();
this.name = "SHA1";
this.module = "Hashing";
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.infoURL = "https://wikipedia.org/wiki/SHA-1";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class SHA2 extends Operation {
super();
this.name = "SHA2";
this.module = "Hashing";
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.infoURL = "https://wikipedia.org/wiki/SHA-2";
this.inputType = "ArrayBuffer";

View File

@@ -20,7 +20,7 @@ class SHA3 extends Operation {
super();
this.name = "SHA3";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The SHA-3 (Secure Hash Algorithm 3) hash functions were released by NIST on August 5, 2015. Although part of the same series of standards, SHA-3 is internally quite different from the MD5-like structure of SHA-1 and SHA-2.<br><br>SHA-3 is a subset of the broader cryptographic primitive family Keccak designed by Guido Bertoni, Joan Daemen, Micha\xebl Peeters, and Gilles Van Assche, building upon RadioGat\xfan.";
this.infoURL = "https://wikipedia.org/wiki/SHA-3";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class SSDEEP extends Operation {
super();
this.name = "SSDEEP";
this.module = "Hashing";
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.inputType = "string";

View File

@@ -6,7 +6,7 @@
import Operation from "../Operation";
import Utils from "../Utils";
import { bitOp, sub } from "../lib/BitwiseOp";
import { bitOp, sub, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
/**
* SUB operation
@@ -30,7 +30,7 @@ class SUB extends Operation {
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
"toggleValues": BITWISE_OP_DELIMS
}
];
}

View File

@@ -21,7 +21,7 @@ class Scrypt extends Operation {
super();
this.name = "Scrypt";
this.module = "Hashing";
this.module = "Crypto";
this.description = "scrypt is a password-based key derivation function (PBKDF) created by Colin Percival. The algorithm was specifically designed to make it costly to perform large-scale custom hardware attacks by requiring large amounts of memory. In 2016, the scrypt algorithm was published by IETF as RFC 7914.<br><br>Enter the password in the input to generate its hash.";
this.infoURL = "https://wikipedia.org/wiki/Scrypt";
this.inputType = "string";

View File

@@ -20,7 +20,7 @@ class Shake extends Operation {
super();
this.name = "Shake";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Shake is an Extendable Output Function (XOF) of the SHA-3 hash algorithm, part of the Keccak family, allowing for variable output length/size.";
this.infoURL = "https://wikipedia.org/wiki/SHA-3#Instances";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class Snefru extends Operation {
super();
this.name = "Snefru";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Snefru is a cryptographic hash function invented by Ralph Merkle in 1990 while working at Xerox PARC. The function supports 128-bit and 256-bit output. It was named after the Egyptian Pharaoh Sneferu, continuing the tradition of the Khufu and Khafre block ciphers.<br><br>The original design of Snefru was shown to be insecure by Eli Biham and Adi Shamir who were able to use differential cryptanalysis to find hash collisions. The design was then modified by increasing the number of iterations of the main pass of the algorithm from two to eight.";
this.infoURL = "https://wikipedia.org/wiki/Snefru";
this.inputType = "ArrayBuffer";

View File

@@ -38,7 +38,7 @@ class Sort extends Operation {
{
"name": "Order",
"type": "option",
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric"]
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric", "Numeric (hexadecimal)"]
}
];
}
@@ -62,6 +62,8 @@ class Sort extends Operation {
sorted = sorted.sort(Sort._ipSort);
} else if (order === "Numeric") {
sorted = sorted.sort(Sort._numericSort);
} else if (order === "Numeric (hexadecimal)") {
sorted = sorted.sort(Sort._hexadecimalSort);
}
if (sortReverse) sorted.reverse();
@@ -131,6 +133,44 @@ class Sort extends Operation {
return a.localeCompare(b);
}
/**
* Comparison operation for sorting of hexadecimal values.
*
* @author Chris van Marle
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
static _hexadecimalSort(a, b) {
let a_ = a.split(/([^\da-f]+)/i),
b_ = b.split(/([^\da-f]+)/i);
a_ = a_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
b_ = b_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(a_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return a.localeCompare(b);
}
}
export default Sort;

View File

@@ -26,12 +26,12 @@ class Split extends Operation {
this.args = [
{
"name": "Split delimiter",
"type": "editableOption",
"type": "editableOptionShort",
"value": SPLIT_DELIM_OPTIONS
},
{
"name": "Join delimiter",
"type": "editableOption",
"type": "editableOptionShort",
"value": JOIN_DELIM_OPTIONS
}
];

View File

@@ -0,0 +1,105 @@
/**
* @author Matt C [matt@artemisbot.uk]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import Utils from "../Utils";
import Magic from "../lib/Magic";
import jimp from "jimp";
/**
* Split Colour Channels operation
*/
class SplitColourChannels extends Operation {
/**
* SplitColourChannels constructor
*/
constructor() {
super();
this.name = "Split Colour Channels";
this.module = "Image";
this.description = "Splits the given image into its red, green and blue colour channels.";
this.infoURL = "https://wikipedia.org/wiki/Channel_(digital_image)";
this.inputType = "byteArray";
this.outputType = "List<File>";
this.presentType = "html";
this.args = [];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {List<File>}
*/
async run(input, args) {
const type = Magic.magicFileType(input);
// Make sure that the input is an image
if (type && type.mime.indexOf("image") === 0) {
const parsedImage = await jimp.read(Buffer.from(input));
const red = new Promise(async (resolve, reject) => {
try {
const split = parsedImage
.clone()
.color([
{apply: "blue", params: [-255]},
{apply: "green", params: [-255]}
])
.getBufferAsync(jimp.MIME_PNG);
resolve(new File([new Uint8Array((await split).values())], "red.png", {type: "image/png"}));
} catch (err) {
reject(new OperationError(`Could not split red channel: ${err}`));
}
});
const green = new Promise(async (resolve, reject) => {
try {
const split = parsedImage.clone()
.color([
{apply: "red", params: [-255]},
{apply: "blue", params: [-255]},
]).getBufferAsync(jimp.MIME_PNG);
resolve(new File([new Uint8Array((await split).values())], "green.png", {type: "image/png"}));
} catch (err) {
reject(new OperationError(`Could not split green channel: ${err}`));
}
});
const blue = new Promise(async (resolve, reject) => {
try {
const split = parsedImage
.color([
{apply: "red", params: [-255]},
{apply: "green", params: [-255]},
]).getBufferAsync(jimp.MIME_PNG);
resolve(new File([new Uint8Array((await split).values())], "blue.png", {type: "image/png"}));
} catch (err) {
reject(new OperationError(`Could not split blue channel: ${err}`));
}
});
return await Promise.all([red, green, blue]);
} else {
throw new OperationError("Invalid file type.");
}
}
/**
* Displays the files in HTML for web apps.
*
* @param {File[]} files
* @returns {html}
*/
async present(files) {
return await Utils.displayFilesAsHTML(files);
}
}
export default SplitColourChannels;

View File

@@ -0,0 +1,153 @@
/**
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import XRegExp from "xregexp";
import Operation from "../Operation";
import Recipe from "../Recipe";
import Dish from "../Dish";
/**
* Subsection operation
*/
class Subsection extends Operation {
/**
* Subsection constructor
*/
constructor() {
super();
this.name = "Subsection";
this.flowControl = true;
this.module = "Regex";
this.description = "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.<br><br>You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on.";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Section (regex)",
"type": "string",
"value": ""
},
{
"name": "Case sensitive matching",
"type": "boolean",
"value": true
},
{
"name": "Global matching",
"type": "boolean",
"value": true
},
{
"name": "Ignore errors",
"type": "boolean",
"value": false
}
];
}
/**
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on
* @param {Operation[]} state.opList - The list of operations in the recipe
* @returns {Object} - The updated state of the recipe
*/
async run(state) {
const opList = state.opList,
inputType = opList[state.progress].inputType,
outputType = opList[state.progress].outputType,
input = await state.dish.get(inputType),
ings = opList[state.progress].ingValues,
[section, caseSensitive, global, ignoreErrors] = ings,
subOpList = [];
if (input && section !== "") {
// Create subOpList for each tranche to operate on
// all remaining operations unless we encounter a Merge
for (let i = state.progress + 1; i < opList.length; i++) {
if (opList[i].name === "Merge" && !opList[i].disabled) {
break;
} else {
subOpList.push(opList[i]);
}
}
let flags = "",
inOffset = 0,
output = "",
m,
progress = 0;
if (!caseSensitive) flags += "i";
if (global) flags += "g";
const regex = new XRegExp(section, flags),
recipe = new Recipe();
recipe.addOperations(subOpList);
state.forkOffset += state.progress + 1;
// Take a deep(ish) copy of the ingredient values
const ingValues = subOpList.map(op => JSON.parse(JSON.stringify(op.ingValues)));
let matched = false;
// Run recipe over each match
while ((m = regex.exec(input))) {
matched = true;
// Add up to match
let matchStr = m[0];
if (m.length === 1) { // No capture groups
output += input.slice(inOffset, m.index);
inOffset = m.index + m[0].length;
} else if (m.length >= 2) {
matchStr = m[1];
// Need to add some of the matched string that isn't in the capture group
output += input.slice(inOffset, m.index + m[0].indexOf(m[1]));
// Set i to be after the end of the first capture group
inOffset = m.index + m[0].indexOf(m[1]) + m[1].length;
}
// Baseline ing values for each tranche so that registers are reset
subOpList.forEach((op, i) => {
op.ingValues = JSON.parse(JSON.stringify(ingValues[i]));
});
const dish = new Dish();
dish.set(matchStr, inputType);
try {
progress = await recipe.execute(dish, 0, state);
} catch (err) {
if (!ignoreErrors) {
throw err;
}
progress = err.progress + 1;
}
output += await dish.get(outputType);
if (!regex.global) break;
}
// If no matches were found, advance progress to after a Merge op
// Otherwise, the operations below Subsection will be run on all the input data
if (!matched) {
state.progress += subOpList.length + 1;
}
output += input.slice(inOffset);
state.progress += progress;
state.dish.set(output, outputType);
}
return state;
}
}
export default Subsection;

View File

@@ -20,7 +20,7 @@ class Substitute extends Operation {
this.name = "Substitute";
this.module = "Default";
this.description = "A substitution cipher allowing you to specify bytes to replace with other byte values. This can be used to create Caesar ciphers but is more powerful as any byte value can be substituted, not just letters, and the substitution values need not be in order.<br><br>Enter the bytes you want to replace in the Plaintext field and the bytes to replace them with in the Ciphertext field.<br><br>Non-printable bytes can be specified using string escape notation. For example, a line feed character can be written as either <code>\n</code> or <code>\x0a</code>.<br><br>Byte ranges can be specified using a hyphen. For example, the sequence <code>0123456789</code> can be written as <code>0-9</code>.";
this.description = "A substitution cipher allowing you to specify bytes to replace with other byte values. This can be used to create Caesar ciphers but is more powerful as any byte value can be substituted, not just letters, and the substitution values need not be in order.<br><br>Enter the bytes you want to replace in the Plaintext field and the bytes to replace them with in the Ciphertext field.<br><br>Non-printable bytes can be specified using string escape notation. For example, a line feed character can be written as either <code>\\n</code> or <code>\\x0a</code>.<br><br>Byte ranges can be specified using a hyphen. For example, the sequence <code>0123456789</code> can be written as <code>0-9</code>.<br><br>Note that blackslash characters are used to escape special characters, so will need to be escaped themselves if you want to use them on their own (e.g.<code>\\\\</code>).";
this.infoURL = "https://wikipedia.org/wiki/Substitution_cipher";
this.inputType = "string";
this.outputType = "string";

View File

@@ -19,7 +19,7 @@ class TCPIPChecksum extends Operation {
super();
this.name = "TCP/IP Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Calculates the checksum for a TCP (Transport Control Protocol) or IP (Internet Protocol) header from an input of raw bytes.";
this.infoURL = "https://wikipedia.org/wiki/IPv4_header_checksum";
this.inputType = "byteArray";

View File

@@ -0,0 +1,92 @@
/**
* @author Cynser
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import Utils from "../Utils";
import cptable from "../vendor/js-codepage/cptable.js";
import {IO_FORMAT} from "../lib/ChrEnc";
/**
* Text Encoding Brute Force operation
*/
class TextEncodingBruteForce extends Operation {
/**
* TextEncodingBruteForce constructor
*/
constructor() {
super();
this.name = "Text Encoding Brute Force";
this.module = "Encodings";
this.description = [
"Enumerates all supported text encodings for the input, allowing you to quickly spot the correct one.",
"<br><br>",
"Supported charsets are:",
"<ul>",
Object.keys(IO_FORMAT).map(e => `<li>${e}</li>`).join("\n"),
"</ul>"
].join("\n");
this.infoURL = "https://wikipedia.org/wiki/Character_encoding";
this.inputType = "string";
this.outputType = "json";
this.presentType = "html";
this.args = [
{
name: "Mode",
type: "option",
value: ["Encode", "Decode"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {json}
*/
run(input, args) {
const output = {},
charsets = Object.keys(IO_FORMAT),
mode = args[0];
charsets.forEach(charset => {
try {
if (mode === "Decode") {
output[charset] = cptable.utils.decode(IO_FORMAT[charset], input);
} else {
output[charset] = Utils.arrayBufferToStr(cptable.utils.encode(IO_FORMAT[charset], input));
}
} catch (err) {
output[charset] = "Could not decode.";
}
});
return output;
}
/**
* Displays the encodings in an HTML table for web apps.
*
* @param {Object[]} encodings
* @returns {html}
*/
present(encodings) {
let table = "<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>Encoding</th><th>Value</th></tr>";
for (const enc in encodings) {
const value = Utils.printable(encodings[enc], true);
table += `<tr><td>${enc}</td><td>${value}</td></tr>`;
}
table += "<table>";
return table;
}
}
export default TextEncodingBruteForce;

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