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

Compare commits

...

135 Commits

Author SHA1 Message Date
n1474335
ed8bd34915 9.48.0 2022-10-15 00:15:49 +01:00
n1474335
5c72791279 Updated CHANGELOG 2022-10-15 00:15:39 +01:00
n1474335
142f91425c Added 'LM Hash' opertaion 2022-10-15 00:13:39 +01:00
n1474335
d6344760ec Merge branch 'master' of https://github.com/brun0ne/CyberChef 2022-10-14 18:45:47 +01:00
n1474335
64c009f266 9.47.5 2022-10-14 16:28:10 +01:00
n1474335
a73decc792 Merge branch 'master' of https://github.com/gariev/CyberChef 2022-10-14 16:26:08 +01:00
n1474335
f332ca4617 9.47.4 2022-10-14 16:24:33 +01:00
n1474335
937791d33d Merge branch 'jwt-magic' of https://github.com/whs/CyberChef 2022-10-14 16:24:19 +01:00
n1474335
a63a130723 Merge branch 'ci/actions' of https://github.com/Fdawgs/CyberChef 2022-10-14 16:21:53 +01:00
n1474335
0f1175bf15 9.47.3 2022-10-14 16:20:38 +01:00
n1474335
e4db23f857 Removed extra comment from Raw Inflate 2022-10-14 16:20:34 +01:00
n1474335
32e7dd030e Merge branch 'master' of https://github.com/XlogicX/CyberChef 2022-10-14 16:19:32 +01:00
n1474335
e33950961e 9.47.2 2022-10-14 16:10:19 +01:00
n1474335
5d65cb419f Tidied up 'Generate all hashes' operation 2022-10-14 16:10:01 +01:00
n1474335
536053d5f9 Merge branch 'hash' of https://github.com/jl2168/CyberChef 2022-10-14 14:53:00 +01:00
n1474335
04ef095b88 9.47.1 2022-10-14 14:47:30 +01:00
n1474335
66277cd71f Added more DNS request types 2022-10-14 14:47:19 +01:00
n1474335
58f01d0464 Merge branch 'PTR-option' of https://github.com/CyberGoat/CyberChef 2022-10-14 14:14:17 +01:00
n1474335
9ba9c56361 9.47.0 2022-10-14 14:07:47 +01:00
n1474335
11902e3220 Updated CHANGELOG 2022-10-14 14:07:42 +01:00
n1474335
c3f79c4b2c Merge branch 'feature/lzma' of https://github.com/mattnotmitt/CyberChef 2022-10-14 14:03:57 +01:00
n1474335
576905e8b8 9.46.7 2022-10-14 14:01:05 +01:00
n1474335
77a3b91afe Merge branch 'ssh-ed25519' of https://github.com/cplussharp/CyberChef 2022-10-14 14:00:03 +01:00
n1474335
40b58aa144 9.46.6 2022-10-14 13:57:35 +01:00
n1474335
d5bcdc8eed Dependency fixes 2022-10-14 13:57:00 +01:00
Manatsawin Hanmongkolchai
674649ca7f Added checks to JWTDecode operation 2022-10-09 14:57:02 +07:00
XlogicX
1a9a070c3b Removal of unnecessary error condition
This situation occurs because the dependancy (zlibjs/bin/rawinflate.min.js) doesn't do a sanity check on distances going back farther than the current buffer.

For example:
DEFLATE data of '123' and then a length of 9 going back a distance of 6
ASCIIHEX: 333432869300

! infgen 3.0 output
!
last			! 1
fixed			! 01
literal '1		! 10000110
literal '2		! 01000110
literal '3		! 11000110
match 9 6		! 1 00100 1110000
infgen warning: distance too far back (6/3)
end			! 0000000
			! 0

We only have 3 characters, we shouldn't be able to seek 6 characters back. But rawinflate.min.js doesn't check for this like the infgen debug tool (and others) would. So CyberChef would happily provide this as the result:
123...123...
Where the dots are just nulls of likley empty memory preceding the actual buffer

So with the example in this source
// e.g. Input data of [8b, 1d, dc, 44]

last			! 1
fixed			! 01
literal ']		! 10110001
match 158 5		! 0 00100 11011 10000011
infgen warning: distance too far back (5/1)

This means we have a literal ']' and then we are asking for 158 more characters and to find them a distance of 5 back. This explains why the ']', why it repeats every 5, and why it is a length > 158.

This code should just be removed; it isn't justified. Being that this issue is a lack of sanity checking in a dependancy, and that this routine only catches the symptom of one of the nearly unlimited edge cases like this, AND it could filter out correct inputs, such as a recipe of this as input to RAWDEFLATE
]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX
Then getting an error with the INFLATE even though the input is actually valid.
2022-10-06 14:02:27 -04:00
XlogicX
32bee35f85 Removal of unnecessary error checking routine
This situation occurs because the dependancy (zlibjs/bin/rawinflate.min.js) doesn't do a sanity check on distances going back farther than the current buffer.

For example:
DEFLATE data of '123' and then a length of 9 going back a distance of 6
ASCIIHEX: 333432869300

! infgen 3.0 output
!
last			! 1
fixed			! 01
literal '1		! 10000110
literal '2		! 01000110
literal '3		! 11000110
match 9 6		! 1 00100 1110000
infgen warning: distance too far back (6/3)
end			! 0000000
			! 0

We only have 3 characters, we shouldn't be able to seek 6 characters back. But rawinflate.min.js doesn't check for this like the infgen debug tool (and others) would. So CyberChef would happily provide this as the result:
123...123...
Where the dots are just nulls of likley empty memory preceding the actual buffer

So with the example in this source
// e.g. Input data of [8b, 1d, dc, 44]

last			! 1
fixed			! 01
literal ']		! 10110001
match 158 5		! 0 00100 11011 10000011
infgen warning: distance too far back (5/1)

This means we have a literal ']' and then we are asking for 158 more characters and to find them a distance of 5 back. This explains why the ']', why it repeats every 5, and why it is a length > 158.

This code should just be removed; it isn't justified. Being that this issue is a lack of sanity checking in a dependancy, and that this routine only catches the symptom of one of the nearly unlimited edge cases like this, AND it could filter out correct inputs, such as a recipe of this as input to RAWDEFLATE
]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX[]OMG[]HAX
Then getting an error with the INFLATE even though the input is actually valid.
2022-10-06 13:53:32 -04:00
Frazer Smith
a68ce5a5af Update GitHub Actions 2022-10-06 13:58:01 +01:00
Igor Gariev
026e9ca9c3 Added escape sequence "\a" (audible bell, 0x07) to Utils.parseEscapedChars().
The sequece is part of C and C++ standard, as well as protocol buffer encoding.

- https://en.wikipedia.org/wiki/Escape_sequences_in_C
- https://en.cppreference.com/w/cpp/language/escape
- https://developers.google.com/protocol-buffers/docs/text-format-spec#string
2022-09-28 20:32:21 -07:00
BrunonDEV
f1ce67d79b Added NTLM operation
Hashing operation - MD4 on UTF16LE-encoded input
2022-09-27 23:13:22 +02:00
john19696
312be4772c rsdix 2022-09-23 11:38:15 +01:00
john19696
be97a0062e linted 2022-09-22 16:53:29 +01:00
john19696
00f0101723 author fix 2022-09-22 16:39:51 +01:00
john19696
f450240094 Parameterise All hashes 2022-09-22 16:30:36 +01:00
Ethan Block
a7b8378736 Adding PTR to possiable values for Resolver 2022-09-21 11:37:06 -04:00
Matt C
98a70c2dd2 Add tests and handle decompress returning string or array 2022-09-19 17:33:55 +01:00
Matt C
d502dd9857 Add LZMA Decompress operation 2022-09-19 14:24:09 +01:00
Matt C
1ec7033d46 Add LZMA Compress operation 2022-09-19 14:24:09 +01:00
Matt C
28ec56a27f Update libyara package to fix bug with compile messages and add support for console module 2022-09-18 16:11:04 +01:00
CPlusSharp
bf2afcd2ef Support Ed25519 SSH host key parsing 2022-09-18 12:47:55 +02:00
Matt C
8f710461da Update yara to 4.2.3 and fix output reading 0 matches 2022-09-17 23:48:11 +01:00
n1474335
c2cf535f88 Added node builder script to package.json 2022-09-16 14:37:31 +01:00
n1474335
ced9ab68fa 9.46.5 2022-09-16 14:16:42 +01:00
n1474335
cdb197a9c3 Reverted to local copies of Tesseract trainddata in order to remain self-contained. 2022-09-16 14:15:54 +01:00
Sean Marpo
c8eacb9942 Linting fixes 2022-09-09 14:45:06 -07:00
Sean Marpo
1c8e37cb64 Update tesseract, fix API for tesseract 3.0 2022-09-09 14:33:49 -07:00
n1474335
1b0ced9f9b 9.46.4 2022-09-09 21:23:09 +01:00
n1474335
7b245b084a Updated to Node v18 and removed node-sass dependency 2022-09-09 21:22:55 +01:00
n1474335
b00f64518f Merge branch 'nodejs18' of https://github.com/john19696/CyberChef 2022-09-09 20:55:18 +01:00
n1474335
c3434e894d 9.46.3 2022-09-09 20:53:37 +01:00
n1474335
dd66f728b3 Merge branch 'fix-protobuf-order' of https://github.com/oliverrahner/CyberChef 2022-09-09 20:52:36 +01:00
n1474335
e40142b8c5 9.46.2 2022-09-09 20:39:35 +01:00
n1474335
1dd1b839b8 Switched jsonpath library to jsonpath-plus. Fixes #1318 2022-09-09 20:39:28 +01:00
n1474335
d90d845f27 9.46.1 2022-09-09 16:51:38 +01:00
n1474335
8c9ad81039 Merge branch 'feat-primitive' of https://github.com/jeiea/CyberChef 2022-09-09 16:49:12 +01:00
n1474335
cef7a7b27d Lint 2022-09-09 16:44:41 +01:00
n1474335
3e715ef21a Merge branch 'fix-select' of https://github.com/IsSafrullah/CyberChef 2022-09-09 16:43:15 +01:00
n1474335
86b43b4ffa Updated README 2022-09-09 16:39:10 +01:00
IsSafrullah
65d883496b fix select when change theme 2022-09-06 03:52:42 +07:00
jeiea
69e59916e2 feat: support boolean and null in JSON to CSV 2022-08-17 02:12:39 +09:00
Philippe Arteau
475282984b Minor typos 2022-07-29 14:32:46 -04:00
Oliver Rahner
2f89130f41 fix protobuf field order 2022-07-21 16:36:15 +02:00
john19696
e9dd7eceb8 upgrade to nodejs v18 2022-07-14 14:27:59 +01:00
n1474335
037590f831 Updated CHANGELOG 2022-07-08 17:18:20 +01:00
n1474335
85496684d8 9.46.0 2022-07-08 17:17:23 +01:00
n1474335
4200ed4eb9 Tidied Cetacean ciphers 2022-07-08 17:16:35 +01:00
n1474335
6b16f11d3b Merge branch 'master' of https://github.com/valdelaseras/CyberChef 2022-07-08 17:02:06 +01:00
n1474335
683bd3e5db Updated CHANGELOG 2022-07-08 16:34:21 +01:00
n1474335
6a10e94bfd 9.45.0 2022-07-08 16:33:33 +01:00
n1474335
25086386c6 Tidied ROT8000 2022-07-08 16:33:16 +01:00
n1474335
d99ee32cc4 Merge branch 'ROT8000' of https://github.com/thomasleplus/CyberChef 2022-07-08 16:28:42 +01:00
n1474335
f1d318f229 Updated CHANGELOG 2022-07-08 16:25:59 +01:00
n1474335
a7fc455e05 9.44.0 2022-07-08 16:24:47 +01:00
n1474335
c02c4a72e4 Merge branch 'add-lz-string' of https://github.com/crespyl/CyberChef 2022-07-08 16:23:15 +01:00
n1474335
f97ce18ff9 Updated CHANGELOG 2022-07-08 16:03:42 +01:00
n1474335
dfd9afc2c4 9.43.0 2022-07-08 16:02:35 +01:00
n1474335
eb5663a1ed Tidied ROT brute forcing ops 2022-07-08 16:02:24 +01:00
n1474335
418a7962a5 Merge branch 'rot_bruteforce' of https://github.com/mikecat/CyberChef 2022-07-08 15:55:27 +01:00
n1474335
2ffce23c67 Updated CHANGELOG 2022-07-08 15:52:00 +01:00
n1474335
b828b50ccc 9.42.0 2022-07-08 15:47:42 +01:00
n1474335
a6aa40db97 Tidied LS47 operations 2022-07-08 15:47:35 +01:00
n1474335
45ede4beaf Merge branch 'LS47Cipher' of https://github.com/n1073645/CyberChef 2022-07-08 15:41:16 +01:00
n1474335
98a95c8bbf Updated CHANGELOG 2022-07-08 15:38:12 +01:00
n1474335
74bb8d92dc 9.41.0 2022-07-08 15:36:36 +01:00
n1474335
6cccc2c786 Tidied Caesar Box Cipher 2022-07-08 15:36:30 +01:00
n1474335
99a0a05947 Merge branch 'caesarBoxCipher' of https://github.com/n1073645/CyberChef 2022-07-08 15:32:56 +01:00
n1474335
94700dab89 Updated CHANGELOG 2022-07-08 15:28:39 +01:00
n1474335
c9d29c89bb 9.40.0 2022-07-08 15:27:01 +01:00
n1474335
7d4e554571 Tweaks to P-List Viewer operation 2022-07-08 15:26:33 +01:00
n1474335
2858a74cbf Merge branch 'plistViewer' of https://github.com/n1073645/CyberChef 2022-07-08 15:18:50 +01:00
n1474335
28e599a835 Merge branch 'improve-subsection-description' of https://github.com/n1073645/CyberChef 2022-07-08 15:17:31 +01:00
n1474335
1fb1d9cbb7 9.39.6 2022-07-08 15:16:00 +01:00
n1474335
2f097e5dfc Tidied up Base85 issues 2022-07-08 15:15:53 +01:00
n1474335
b71e3241be Merge branch 'master' of https://github.com/benediktwerner/CyberChef 2022-07-08 15:04:09 +01:00
n1474335
4b018bf421 9.39.5 2022-07-08 14:55:32 +01:00
n1474335
f751de896f Merge branch 'base' of https://github.com/john19696/CyberChef 2022-07-08 14:55:20 +01:00
n1474335
65aeae9c1e 9.39.4 2022-07-08 14:53:07 +01:00
n1474335
80943b0c26 Merge branch 'fix-merge' of https://github.com/n1073645/CyberChef 2022-07-08 14:52:56 +01:00
n1474335
a9657ac5c7 9.39.3 2022-07-08 14:51:08 +01:00
n1474335
6fa2e49f3a Merge branch 'webp-extractor' of https://github.com/n1073645/CyberChef 2022-07-08 14:50:57 +01:00
n1474335
50f0f70805 9.39.2 2022-07-08 14:49:50 +01:00
n1474335
fc95d82c49 Tweaked Extract Files minimum size 2022-07-08 14:49:40 +01:00
n1474335
bb6c1c54ff Merge branch 'extract-files-min-size' of https://github.com/n1073645/CyberChef 2022-07-08 13:57:06 +01:00
n1474335
c4414bd910 Fixed dropdown toggle height 2022-07-08 13:53:19 +01:00
n1073645
42c911838d Add min size to Extract Files 2022-06-17 11:18:49 +01:00
n1073645
8917eabfd1 Implemented webp extractor 2022-06-17 09:56:36 +01:00
n1073645
fc91469807 Added nesting to Merge/Fork/Subsection 2022-06-17 09:26:00 +01:00
John L
1735d9c091 remove logging 2022-06-15 15:07:39 +01:00
John L
00d754d466 lint fixes 2022-06-14 15:57:04 +01:00
John L
906727f133 Base85 improvements 2022-06-14 10:23:13 +01:00
n1073645
191d7f11f7 Improve the subsection description 2022-06-10 15:25:12 +01:00
Thomas Leplus
e712af33b7 Adding ROT8000 2022-04-11 18:44:14 -07:00
Robin Scholtes
578a61d331 add cetacean cipher encoder and decoder operations, tests. Update .gitignore to exclude idea generated files 2022-01-17 23:37:24 +13:00
Peter Jacobs
671ae6558f Added 'LZString Decompress' and 'LZString Compress' operations 2021-10-29 15:26:31 -05:00
MikeCAT
e8f91316ff Added ROT13/47 Brute Force 2021-10-20 21:28:48 +09:00
n1073645
667dfd820e info url added 2020-07-06 16:46:40 +01:00
n1073645
3e3c526a62 Caesar Box Cipher Added 2020-07-06 16:35:14 +01:00
Benedikt Werner
f5a7db03cd Base85: Only require 15 continuous base85 chars 2020-06-10 15:50:26 +02:00
Benedikt Werner
ee408f7add Base85: Update magic regexes to require 20 non-whitespace base85 chars 2020-05-22 03:30:57 +02:00
Benedikt Werner
1294d764e2 Base85: Only remove start and end markers with standard/ascii85 encoding 2020-05-22 03:30:15 +02:00
Benedikt Werner
eab1be0e2c Magic base85: Remove 'i' flag 2020-05-20 00:23:50 +02:00
Benedikt Werner
15dd9d4c93 Add magic checks for base85 2020-05-16 00:42:50 +02:00
Benedikt Werner
103ecff6a7 Base85: Ignore whitespace 2020-05-16 00:42:31 +02:00
Benedikt Werner
0182cdda69 Base85: Fix alphabetName 2020-05-16 00:42:02 +02:00
n1073645
e91e993fb5 Update LS47.mjs 2020-02-14 13:43:30 +00:00
n1073645
e71794d362 Tests added for LS47 2020-02-14 12:28:12 +00:00
n1073645
6fd929160d Comments and linting. 2020-01-28 10:35:01 +00:00
n1073645
5cdd062ed9 Linting done 2020-01-28 09:40:03 +00:00
n1073645
0259ed8314 LS47 implemented, needs linting 2020-01-27 16:07:54 +00:00
n1073645
d8405e5f81 Linting on PLIST viewer operation. 2019-11-25 10:37:30 +00:00
n1073645
0295d0c9b4 Tided up presentation of the PLIST 2019-11-25 10:35:45 +00:00
n1073645
8e1e1d56ca Plist viewer operation added. 2019-11-22 15:39:43 +00:00
n1073645
63bb19d48d Began implementing the PLIST viewer operation 2019-11-22 08:32:46 +00:00
n1073645
e92ed13864 PLIST viewer. 2019-11-21 12:53:44 +00:00
72 changed files with 2999 additions and 3379 deletions

View File

@@ -22,12 +22,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@@ -10,12 +10,12 @@ jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set node version
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: '17.x'
node-version: '18.x'
- name: Install
run: |
@@ -47,7 +47,7 @@ jobs:
- name: Deploy to GitHub Pages
if: success() && github.ref == 'refs/heads/master'
uses: crazy-max/ghaction-github-pages@v2
uses: crazy-max/ghaction-github-pages@v3
with:
target_branch: gh-pages
build_dir: ./build/prod

View File

@@ -9,12 +9,12 @@ jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set node version
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: '17.x'
node-version: '18.x'
- name: Install
run: |

View File

@@ -10,12 +10,12 @@ jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set node version
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: '17.x'
node-version: '18.x'
- name: Install
run: |

2
.nvmrc
View File

@@ -1 +1 @@
17
18

View File

@@ -13,6 +13,33 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [9.48.0] - 2022-10-14
- Added 'LM Hash' and 'NT Hash' operations [@n1474335] [@brun0ne] | [#1427]
### [9.47.0] - 2022-10-14
- Added 'LZMA Decompress' and 'LZMA Compress' operations [@mattnotmitt] | [#1421]
### [9.46.0] - 2022-07-08
- Added 'Cetacean Cipher Encode' and 'Cetacean Cipher Decode' operations [@valdelaseras] | [#1308]
### [9.45.0] - 2022-07-08
- Added 'ROT8000' operation [@thomasleplus] | [#1250]
### [9.44.0] - 2022-07-08
- Added 'LZString Compress' and 'LZString Decompress' operations [@crespyl] | [#1266]
### [9.43.0] - 2022-07-08
- Added 'ROT13 Brute Force' and 'ROT47 Brute Force' operations [@mikecat] | [#1264]
### [9.42.0] - 2022-07-08
- Added 'LS47 Encrypt' and 'LS47 Decrypt' operations [@n1073645] | [#951]
### [9.41.0] - 2022-07-08
- Added 'Caesar Box Cipher' operation [@n1073645] | [#1066]
### [9.40.0] - 2022-07-08
- Added 'P-list Viewer' operation [@n1073645] | [#906]
### [9.39.0] - 2022-06-09
- Added 'ELF Info' operation [@n1073645] | [#1364]
@@ -294,6 +321,15 @@ All major and minor version changes will be documented in this file. Details of
[9.48.0]: https://github.com/gchq/CyberChef/releases/tag/v9.48.0
[9.47.0]: https://github.com/gchq/CyberChef/releases/tag/v9.47.0
[9.46.0]: https://github.com/gchq/CyberChef/releases/tag/v9.46.0
[9.45.0]: https://github.com/gchq/CyberChef/releases/tag/v9.45.0
[9.44.0]: https://github.com/gchq/CyberChef/releases/tag/v9.44.0
[9.43.0]: https://github.com/gchq/CyberChef/releases/tag/v9.43.0
[9.42.0]: https://github.com/gchq/CyberChef/releases/tag/v9.42.0
[9.41.0]: https://github.com/gchq/CyberChef/releases/tag/v9.41.0
[9.40.0]: https://github.com/gchq/CyberChef/releases/tag/v9.40.0
[9.39.0]: https://github.com/gchq/CyberChef/releases/tag/v9.39.0
[9.38.0]: https://github.com/gchq/CyberChef/releases/tag/v9.38.0
[9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0
@@ -418,6 +454,11 @@ All major and minor version changes will be documented in this file. Details of
[@t-8ch]: https://github.com/t-8ch
[@hettysymes]: https://github.com/hettysymes
[@swesven]: https://github.com/swesven
[@mikecat]: https://github.com/mikecat
[@crespyl]: https://github.com/crespyl
[@thomasleplus]: https://github.com/thomasleplus
[@valdelaseras]: https://github.com/valdelaseras
[@brun0ne]: https://github.com/brun0ne
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
@@ -491,10 +532,12 @@ All major and minor version changes will be documented in this file. Details of
[#674]: https://github.com/gchq/CyberChef/pull/674
[#683]: https://github.com/gchq/CyberChef/pull/683
[#865]: https://github.com/gchq/CyberChef/pull/865
[#906]: https://github.com/gchq/CyberChef/pull/906
[#912]: https://github.com/gchq/CyberChef/pull/912
[#917]: https://github.com/gchq/CyberChef/pull/917
[#934]: https://github.com/gchq/CyberChef/pull/934
[#948]: https://github.com/gchq/CyberChef/pull/948
[#951]: https://github.com/gchq/CyberChef/pull/951
[#952]: https://github.com/gchq/CyberChef/pull/952
[#965]: https://github.com/gchq/CyberChef/pull/965
[#966]: https://github.com/gchq/CyberChef/pull/966
@@ -506,6 +549,7 @@ All major and minor version changes will be documented in this file. Details of
[#1045]: https://github.com/gchq/CyberChef/pull/1045
[#1049]: https://github.com/gchq/CyberChef/pull/1049
[#1065]: https://github.com/gchq/CyberChef/pull/1065
[#1066]: https://github.com/gchq/CyberChef/pull/1066
[#1083]: https://github.com/gchq/CyberChef/pull/1083
[#1189]: https://github.com/gchq/CyberChef/pull/1189
[#1242]: https://github.com/gchq/CyberChef/pull/1242
@@ -513,3 +557,10 @@ All major and minor version changes will be documented in this file. Details of
[#1313]: https://github.com/gchq/CyberChef/pull/1313
[#1326]: https://github.com/gchq/CyberChef/pull/1326
[#1364]: https://github.com/gchq/CyberChef/pull/1364
[#1264]: https://github.com/gchq/CyberChef/pull/1264
[#1266]: https://github.com/gchq/CyberChef/pull/1266
[#1250]: https://github.com/gchq/CyberChef/pull/1250
[#1308]: https://github.com/gchq/CyberChef/pull/1308
[#1421]: https://github.com/gchq/CyberChef/pull/1421
[#1427]: https://github.com/gchq/CyberChef/pull/1427

View File

@@ -54,7 +54,7 @@ You can use as many operations as you like in simple or complex ways. Some examp
- Whenever you modify the input or the recipe, CyberChef will automatically "bake" for you and produce the output immediately.
- This can be turned off and operated manually if it is affecting performance (if the input is very large, for instance).
- Automated encoding detection
- CyberChef uses [a number of techniques](https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic) to attempt to automatically detect which encodings your data is under. If it finds a suitable operation which can make sense of your data, it displays the 'magic' icon in the Output field which you can click to decode your data.
- CyberChef uses [a number of techniques](https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic) to attempt to automatically detect which encodings your data is under. If it finds a suitable operation that make sense of your data, it displays the 'magic' icon in the Output field which you can click to decode your data.
- Breakpoints
- You can set breakpoints on any operation in your recipe to pause execution before running it.
- You can also step through the recipe one operation at a time to see what the data looks like at each stage.
@@ -66,7 +66,7 @@ You can use as many operations as you like in simple or complex ways. Some examp
- Highlighting
- When you highlight text in the input or output, the offset and length values will be displayed and, if possible, the corresponding data will be highlighted in the output or input respectively (example: [highlight the word 'question' in the input to see where it appears in the output][11]).
- Save to file and load from file
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field. Files up to around 2GB are supported (depending on your browser), however some operations may take a very long time to run over this much data.
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field. Files up to around 2GB are supported (depending on your browser), however, some operations may take a very long time to run over this much data.
- CyberChef is entirely client-side
- It should be noted that none of your recipe configuration or input (either text or files) is ever sent to the CyberChef web server - all processing is carried out within your browser, on your own computer.
- Due to this feature, CyberChef can be downloaded and run locally. You can use the link in the top left corner of the app to download a full copy of CyberChef and drop it into a virtual machine, share it with other people, or host it in a closed network.
@@ -74,10 +74,10 @@ You can use as many operations as you like in simple or complex ways. Some examp
## Deep linking
By manipulation of CyberChef's URL hash, you can change the initial settings with which the page opens.
By manipulating CyberChef's URL hash, you can change the initial settings with which the page opens.
The format is `https://gchq.github.io/CyberChef/#recipe=Operation()&input=...`
Supported arguments are `recipe`, `input` (encoded in Base64), and `theme`.
Supported arguments are `recipe`, `input` (encoded in Base64), and `theme`.
## Browser support
@@ -90,12 +90,12 @@ CyberChef is built to support
## Node.js support
CyberChef is built to fully support Node.js `v10` and partially supports `v12`. Named imports using a deep import specifier does not work in `v12`. For more information, see the Node API page in the project [wiki pages](https://github.com/gchq/CyberChef/wiki)
CyberChef is built to fully support Node.js `v16`. For more information, see the Node API page in the project [wiki pages](https://github.com/gchq/CyberChef/wiki)
## Contributing
Contributing a new operation to CyberChef is super easy! There is a quickstart script which will walk you through the process. If you can write basic JavaScript, you can write a CyberChef operation.
Contributing a new operation to CyberChef is super easy! The quickstart script will walk you through the process. If you can write basic JavaScript, you can write a CyberChef operation.
An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki).

3594
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.39.1",
"version": "9.48.0",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -49,7 +49,7 @@
"babel-loader": "^8.2.5",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-transform-builtin-extend": "1.1.2",
"chromedriver": "^101.0.0",
"chromedriver": "^103.0.0",
"cli-progress": "^3.11.1",
"colors": "^1.4.0",
"copy-webpack-plugin": "^11.0.0",
@@ -77,7 +77,6 @@
"postcss-import": "^14.1.0",
"postcss-loader": "^7.0.0",
"prompt": "^1.3.0",
"sass-loader": "^13.0.0",
"sitemap": "^7.1.1",
"terser": "^5.14.0",
"webpack": "^5.73.0",
@@ -88,6 +87,7 @@
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@blu3r4y/lzma": "^2.3.3",
"arrive": "^2.4.1",
"avsc": "^5.7.4",
"bcryptjs": "^2.4.3",
@@ -123,25 +123,26 @@
"js-sha3": "^0.8.0",
"jsesc": "^3.0.2",
"json5": "^2.2.1",
"jsonpath": "^1.1.1",
"jsonpath-plus": "^7.2.0",
"jsonwebtoken": "^8.5.1",
"jsqr": "^1.4.0",
"jsrsasign": "^10.5.23",
"kbpgp": "2.1.15",
"libbzip2-wasm": "0.0.4",
"libyara-wasm": "^1.1.0",
"libyara-wasm": "^1.2.1",
"lodash": "^4.17.21",
"loglevel": "^1.8.0",
"loglevel-message-prefix": "^3.0.0",
"lz-string": "^1.4.4",
"markdown-it": "^13.0.1",
"moment": "^2.29.3",
"moment-timezone": "^0.5.34",
"ngeohash": "^0.6.3",
"node-forge": "^1.3.1",
"node-md6": "^0.1.0",
"node-sass": "^7.0.1",
"nodom": "^2.4.0",
"notepack.io": "^3.0.1",
"ntlm": "^0.1.3",
"nwmatcher": "^1.4.4",
"otp": "0.1.3",
"path": "^0.12.7",
@@ -155,7 +156,7 @@
"split.js": "^1.6.5",
"ssdeep.js": "0.0.3",
"stream-browserify": "^3.0.0",
"tesseract.js": "2.1.5",
"tesseract.js": "3.0.2",
"ua-parser-js": "^1.0.2",
"unorm": "^1.6.0",
"utf8": "^3.0.0",
@@ -168,8 +169,9 @@
"scripts": {
"start": "npx grunt dev",
"build": "npx grunt prod",
"node": "npx grunt node",
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings src/node/repl.mjs",
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/operations/index.mjs",
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider tests/operations/index.mjs",
"testnodeconsumer": "npx grunt testnodeconsumer",
"testui": "npx grunt testui",
"testuidev": "npx nightwatch --env=dev",

View File

@@ -206,7 +206,7 @@ class Utils {
* Utils.parseEscapedChars("\\n");
*/
static parseEscapedChars(str) {
return str.replace(/\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a) {
return str.replace(/\\([abfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a) {
switch (a[0]) {
case "\\":
return "\\";
@@ -219,6 +219,8 @@ class Utils {
case "6":
case "7":
return String.fromCharCode(parseInt(a, 8));
case "a":
return String.fromCharCode(7);
case "b":
return "\b";
case "t":

View File

@@ -79,6 +79,8 @@
"DES Decrypt",
"Triple DES Encrypt",
"Triple DES Decrypt",
"LS47 Encrypt",
"LS47 Decrypt",
"RC2 Encrypt",
"RC2 Decrypt",
"RC4",
@@ -86,7 +88,10 @@
"SM4 Encrypt",
"SM4 Decrypt",
"ROT13",
"ROT13 Brute Force",
"ROT47",
"ROT47 Brute Force",
"ROT8000",
"XOR",
"XOR Brute Force",
"Vigenère Encode",
@@ -97,6 +102,7 @@
"Bacon Cipher Decode",
"Bifid Cipher Encode",
"Bifid Cipher Decode",
"Caesar Box Cipher",
"Affine Cipher Encode",
"Affine Cipher Decode",
"A1Z26 Cipher Encode",
@@ -106,6 +112,8 @@
"Atbash Cipher",
"CipherSaber2 Encrypt",
"CipherSaber2 Decrypt",
"Cetacean Cipher Encode",
"Cetacean Cipher Decode",
"Substitute",
"Derive PBKDF2 key",
"Derive EVP key",
@@ -176,7 +184,8 @@
"Bit shift right",
"Rotate left",
"Rotate right",
"ROT13"
"ROT13",
"ROT8000"
]
},
{
@@ -320,7 +329,11 @@
"Bzip2 Decompress",
"Bzip2 Compress",
"Tar",
"Untar"
"Untar",
"LZString Decompress",
"LZString Compress",
"LZMA Decompress",
"LZMA Compress"
]
},
{
@@ -356,6 +369,8 @@
"Bcrypt compare",
"Bcrypt parse",
"Scrypt",
"NT Hash",
"LM Hash",
"Fletcher-8 Checksum",
"Fletcher-16 Checksum",
"Fletcher-32 Checksum",
@@ -457,6 +472,7 @@
"Frequency distribution",
"Index of Coincidence",
"Chi Square",
"P-list Viewer",
"Disassemble x86",
"Pseudo-Random Number Generator",
"Generate UUID",

View File

@@ -1,3 +1,5 @@
import Utils from "../Utils.mjs";
/**
* Base85 resources.
*
@@ -32,13 +34,12 @@ export const ALPHABET_OPTIONS = [
* @returns {string}
*/
export function alphabetName(alphabet) {
alphabet = alphabet.replace(/'/g, "&apos;");
alphabet = alphabet.replace(/"/g, "&quot;");
alphabet = alphabet.replace(/\\/g, "&bsol;");
alphabet = escape(alphabet);
let name;
ALPHABET_OPTIONS.forEach(function(a) {
if (escape(alphabet) === escape(a.value)) name = a.name;
const expanded = Utils.expandAlphRange(a.value).join("");
if (alphabet === escape(expanded)) name = a.name;
});
return name;

View File

@@ -70,7 +70,7 @@ export const FILE_SIGNATURES = {
10: 0x42,
11: 0x50
},
extractor: null
extractor: extractWEBP
},
{
name: "Camera Image File Format",
@@ -3032,6 +3032,30 @@ export function extractPNG(bytes, offset) {
}
/**
* WEBP extractor.
*
* @param {Uint8Array} bytes
* @param {number} offset
* @returns {Uint8Array}
*/
export function extractWEBP(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to file size offset.
stream.moveForwardsBy(4);
// Read file size field.
const fileSize = stream.readInt(4, "le");
// Move to end of file.
// There is no need to minus 8 from the size as the size factors in the offset.
stream.moveForwardsBy(fileSize);
return stream.carve();
}
/**
* BMP extractor.
*

244
src/core/lib/LS47.mjs Normal file
View File

@@ -0,0 +1,244 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
const letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
const tiles = [];
/**
* Initialises the tiles with values and positions.
*/
export function initTiles() {
for (let i = 0; i < 49; i++)
tiles.push([letters.charAt(i), [Math.floor(i/7), i % 7]]);
}
/**
* Rotates the key "down".
*
* @param {string} key
* @param {number} col
* @param {number} n
* @returns {string}
*/
function rotateDown(key, col, n) {
const lines = [];
for (let i = 0; i < 7; i++)
lines.push(key.slice(i*7, (i + 1) * 7));
const lefts = [];
let mids = [];
const rights = [];
lines.forEach((element) => {
lefts.push(element.slice(0, col));
mids.push(element.charAt(col));
rights.push(element.slice(col+1));
});
n = (7 - n % 7) % 7;
mids = mids.slice(n).concat(mids.slice(0, n));
let result = "";
for (let i = 0; i < 7; i++)
result += lefts[i] + mids[i] + rights[i];
return result;
}
/**
* Rotates the key "right".
*
* @param {string} key
* @param {number} row
* @param {number} n
* @returns {string}
*/
function rotateRight(key, row, n) {
const mid = key.slice(row * 7, (row + 1) * 7);
n = (7 - n % 7) % 7;
return key.slice(0, 7 * row) + mid.slice(n) + mid.slice(0, n) + key.slice(7 * (row + 1));
}
/**
* Finds the position of a letter in the tiles.
*
* @param {string} letter
* @returns {string}
*/
function findIx(letter) {
for (let i = 0; i < tiles.length; i++)
if (tiles[i][0] === letter)
return tiles[i][1];
throw new OperationError("Letter " + letter + " is not included in LS47");
}
/**
* Derives key from the input password.
*
* @param {string} password
* @returns {string}
*/
export function deriveKey(password) {
let i = 0;
let k = letters;
for (const c of password) {
const [row, col] = findIx(c);
k = rotateDown(rotateRight(k, i, col), i, row);
i = (i + 1) % 7;
}
return k;
}
/**
* Checks the key is a valid key.
*
* @param {string} key
*/
function checkKey(key) {
if (key.length !== letters.length)
throw new OperationError("Wrong key size");
const counts = new Array();
for (let i = 0; i < letters.length; i++)
counts[letters.charAt(i)] = 0;
for (const elem of letters) {
if (letters.indexOf(elem) === -1)
throw new OperationError("Letter " + elem + " not in LS47");
counts[elem]++;
if (counts[elem] > 1)
throw new OperationError("Letter duplicated in the key");
}
}
/**
* Finds the position of a letter in they key.
*
* @param {letter} key
* @param {string} letter
* @returns {object}
*/
function findPos (key, letter) {
const index = key.indexOf(letter);
if (index >= 0 && index < 49)
return [Math.floor(index/7), index%7];
throw new OperationError("Letter " + letter + " is not in the key");
}
/**
* Returns the character at the position on the tiles.
*
* @param {string} key
* @param {object} coord
* @returns {string}
*/
function findAtPos(key, coord) {
return key.charAt(coord[1] + (coord[0] * 7));
}
/**
* Returns new position by adding two positions.
*
* @param {object} a
* @param {object} b
* @returns {object}
*/
function addPos(a, b) {
return [(a[0] + b[0]) % 7, (a[1] + b[1]) % 7];
}
/**
* Returns new position by subtracting two positions.
* Note: We have to manually do the remainder division, since JS does not
* operate correctly on negative numbers (e.g. -3 % 4 = -3 when it should be 1).
*
* @param {object} a
* @param {object} b
* @returns {object}
*/
function subPos(a, b) {
const asub = a[0] - b[0];
const bsub = a[1] - b[1];
return [asub - (Math.floor(asub/7) * 7), bsub - (Math.floor(bsub/7) * 7)];
}
/**
* Encrypts the plaintext string.
*
* @param {string} key
* @param {string} plaintext
* @returns {string}
*/
function encrypt(key, plaintext) {
checkKey(key);
let mp = [0, 0];
let ciphertext = "";
for (const p of plaintext) {
const pp = findPos(key, p);
const mix = findIx(findAtPos(key, mp));
let cp = addPos(pp, mix);
const c = findAtPos(key, cp);
ciphertext += c;
key = rotateRight(key, pp[0], 1);
cp = findPos(key, c);
key = rotateDown(key, cp[1], 1);
mp = addPos(mp, findIx(c));
}
return ciphertext;
}
/**
* Decrypts the ciphertext string.
*
* @param {string} key
* @param {string} ciphertext
* @returns {string}
*/
function decrypt(key, ciphertext) {
checkKey(key);
let mp = [0, 0];
let plaintext = "";
for (const c of ciphertext) {
let cp = findPos(key, c);
const mix = findIx(findAtPos(key, mp));
const pp = subPos(cp, mix);
const p = findAtPos(key, pp);
plaintext += p;
key = rotateRight(key, pp[0], 1);
cp = findPos(key, c);
key = rotateDown(key, cp[1], 1);
mp = addPos(mp, findIx(c));
}
return plaintext;
}
/**
* Adds padding to the input.
*
* @param {string} key
* @param {string} plaintext
* @param {string} signature
* @param {number} paddingSize
* @returns {string}
*/
export function encryptPad(key, plaintext, signature, paddingSize) {
initTiles();
checkKey(key);
let padding = "";
for (let i = 0; i < paddingSize; i++) {
padding += letters.charAt(Math.floor(Math.random() * letters.length));
}
return encrypt(key, padding+plaintext+"---"+signature);
}
/**
* Removes padding from the ouput.
*
* @param {string} key
* @param {string} ciphertext
* @param {number} paddingSize
* @returns {string}
*/
export function decryptPad(key, ciphertext, paddingSize) {
initTiles();
checkKey(key);
return decrypt(key, ciphertext).slice(paddingSize);
}

21
src/core/lib/LZString.mjs Normal file
View File

@@ -0,0 +1,21 @@
/**
* lz-string exports.
*
* @author crespyl [peter@crespyl.net]
* @copyright Peter Jacobs 2021
* @license Apache-2.0
*/
import LZString from "lz-string";
export const COMPRESSION_OUTPUT_FORMATS = ["default", "UTF16", "Base64"];
export const COMPRESSION_FUNCTIONS = {
"default": LZString.compress,
"UTF16": LZString.compressToUTF16,
"Base64": LZString.compressToBase64,
};
export const DECOMPRESSION_FUNCTIONS = {
"default": LZString.decompress,
"UTF16": LZString.decompressFromUTF16,
"Base64": LZString.decompressFromBase64,
};

View File

@@ -184,7 +184,7 @@ class Protobuf {
bytes: String,
longs: Number,
enums: String,
defualts: true
defaults: true
});
const output = {};

View File

@@ -0,0 +1,61 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Caesar Box Cipher operation
*/
class CaesarBoxCipher extends Operation {
/**
* CaesarBoxCipher constructor
*/
constructor() {
super();
this.name = "Caesar Box Cipher";
this.module = "Ciphers";
this.description = "Caesar Box is a transposition cipher used in the Roman Empire, in which letters of the message are written in rows in a square (or a rectangle) and then, read by column.";
this.infoURL = "https://www.dcode.fr/caesar-box-cipher";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Box Height",
type: "number",
value: 1
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const tableHeight = args[0];
const tableWidth = Math.ceil(input.length / tableHeight);
while (input.indexOf(" ") !== -1)
input = input.replace(" ", "");
for (let i = 0; i < (tableHeight * tableWidth) - input.length; i++) {
input += "\x00";
}
let result = "";
for (let i = 0; i < tableHeight; i++) {
for (let j = i; j < input.length; j += tableHeight) {
if (input.charAt(j) !== "\x00") {
result += input.charAt(j);
}
}
}
return result;
}
}
export default CaesarBoxCipher;

View File

@@ -0,0 +1,63 @@
/**
* @author dolphinOnKeys [robin@weird.io]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Cetacean Cipher Decode operation
*/
class CetaceanCipherDecode extends Operation {
/**
* CetaceanCipherDecode constructor
*/
constructor() {
super();
this.name = "Cetacean Cipher Decode";
this.module = "Ciphers";
this.description = "Decode Cetacean Cipher input. <br/><br/>e.g. <code>EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe</code> becomes <code>hi</code>";
this.infoURL = "https://hitchhikers.fandom.com/wiki/Dolphins";
this.inputType = "string";
this.outputType = "string";
this.checks = [
{
pattern: "^(?:[eE]{16,})(?: [eE]{16,})*$",
flags: "",
args: []
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const binaryArray = [];
for (const char of input) {
if (char === " ") {
binaryArray.push(...[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]);
} else {
binaryArray.push(char === "e" ? 1 : 0);
}
}
const byteArray = [];
for (let i = 0; i < binaryArray.length; i += 16) {
byteArray.push(binaryArray.slice(i, i + 16).join(""));
}
return byteArray.map(byte =>
String.fromCharCode(parseInt(byte, 2))
).join("");
}
}
export default CetaceanCipherDecode;

View File

@@ -0,0 +1,51 @@
/**
* @author dolphinOnKeys [robin@weird.io]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import {toBinary} from "../lib/Binary.mjs";
/**
* Cetacean Cipher Encode operation
*/
class CetaceanCipherEncode extends Operation {
/**
* CetaceanCipherEncode constructor
*/
constructor() {
super();
this.name = "Cetacean Cipher Encode";
this.module = "Ciphers";
this.description = "Converts any input into Cetacean Cipher. <br/><br/>e.g. <code>hi</code> becomes <code>EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe</code>";
this.infoURL = "https://hitchhikers.fandom.com/wiki/Dolphins";
this.inputType = "string";
this.outputType = "string";
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const result = [];
const charArray = input.split("");
charArray.map(character => {
if (character === " ") {
result.push(character);
} else {
const binaryArray = toBinary(character.charCodeAt(0), "None", 16).split("");
result.push(binaryArray.map(str => str === "1" ? "e" : "E").join(""));
}
});
return result.join("");
}
}
export default CetaceanCipherEncode;

View File

@@ -51,10 +51,27 @@ class DNSOverHTTPS extends Operation {
value: [
"A",
"AAAA",
"TXT",
"MX",
"ANAME",
"CERT",
"CNAME",
"DNSKEY",
"NS"
"HTTPS",
"IPSECKEY",
"LOC",
"MX",
"NS",
"OPENPGPKEY",
"PTR",
"RRSIG",
"SIG",
"SOA",
"SPF",
"SRV",
"SSHFP",
"TA",
"TXT",
"URI",
"ANY"
]
},
{

View File

@@ -38,7 +38,7 @@ class ExtractFiles extends Operation {
<li>
${supportedExts.join("</li><li>")}
</li>
</ul>`;
</ul>Minimum File Size can be used to prune small false positives.`;
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=File_Carving";
this.inputType = "ArrayBuffer";
this.outputType = "List<File>";
@@ -54,6 +54,11 @@ class ExtractFiles extends Operation {
name: "Ignore failed extractions",
type: "boolean",
value: true
},
{
name: "Minimum File Size",
type: "number",
value: 100
}
]);
}
@@ -66,6 +71,7 @@ class ExtractFiles extends Operation {
run(input, args) {
const bytes = new Uint8Array(input),
categories = [],
minSize = args.pop(1),
ignoreFailedExtractions = args.pop(1);
args.forEach((cat, i) => {
@@ -80,7 +86,9 @@ class ExtractFiles extends Operation {
const errors = [];
detectedFiles.forEach(detectedFile => {
try {
files.push(extractFile(bytes, detectedFile.fileDetails, detectedFile.offset));
const file = extractFile(bytes, detectedFile.fileDetails, detectedFile.offset);
if (file.size >= minSize)
files.push(file);
} catch (err) {
if (!ignoreFailedExtractions && err.message.indexOf("No extraction algorithm available") < 0) {
errors.push(

View File

@@ -65,12 +65,21 @@ class Fork extends Operation {
if (input)
inputs = input.split(splitDelim);
// Set to 1 as if we are here, then there is one, the current one.
let numOp = 1;
// Create subOpList for each tranche to operate on
// (all remaining operations unless we encounter a Merge)
// all remaining operations unless we encounter a Merge
for (i = state.progress + 1; i < opList.length; i++) {
if (opList[i].name === "Merge" && !opList[i].disabled) {
break;
numOp--;
if (numOp === 0 || opList[i].ingValues[0])
break;
else
// Not this Fork's Merge.
subOpList.push(opList[i]);
} else {
if (opList[i].name === "Fork" || opList[i].name === "Subsection")
numOp++;
subOpList.push(opList[i]);
}
}

View File

@@ -32,7 +32,12 @@ class FromBase45 extends Operation {
name: "Alphabet",
type: "string",
value: ALPHABET
}
},
{
name: "Remove non-alphabet chars",
type: "boolean",
value: true
},
];
this.highlight = highlightFromBase45;
@@ -46,10 +51,17 @@ class FromBase45 extends Operation {
*/
run(input, args) {
if (!input) return [];
const alphabet = Utils.expandAlphRange(args[0]);
const alphabet = Utils.expandAlphRange(args[0]).join("");
const removeNonAlphChars = args[1];
const res = [];
// Remove non-alphabet characters
if (removeNonAlphChars) {
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
input = input.replace(re, "");
}
for (const triple of Utils.chunked(input, 3)) {
triple.reverse();
let b = 0;

View File

@@ -32,6 +32,40 @@ class FromBase85 extends Operation {
type: "editableOption",
value: ALPHABET_OPTIONS
},
{
name: "Remove non-alphabet chars",
type: "boolean",
value: true
},
];
this.checks = [
{
pattern:
"^\\s*(?:<~)?" + // Optional whitespace and starting marker
"[\\s!-uz]*" + // Any amount of base85 characters and whitespace
"[!-uz]{15}" + // At least 15 continoues base85 characters without whitespace
"[\\s!-uz]*" + // Any amount of base85 characters and whitespace
"(?:~>)?\\s*$", // Optional ending marker and whitespace
args: ["!-u"],
},
{
pattern:
"^" +
"[\\s0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]*" +
"[0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]{15}" + // At least 15 continoues base85 characters without whitespace
"[\\s0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]*" +
"$",
args: ["0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#"],
},
{
pattern:
"^" +
"[\\s0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]*" +
"[0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]{15}" + // At least 15 continoues base85 characters without whitespace
"[\\s0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]*" +
"$",
args: ["0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~"],
},
];
}
@@ -43,6 +77,7 @@ class FromBase85 extends Operation {
run(input, args) {
const alphabet = Utils.expandAlphRange(args[0]).join(""),
encoding = alphabetName(alphabet),
removeNonAlphChars = args[1],
result = [];
if (alphabet.length !== 85 ||
@@ -50,11 +85,18 @@ class FromBase85 extends Operation {
throw new OperationError("Alphabet must be of length 85");
}
if (input.length === 0) return [];
const matches = input.match(/<~(.+?)~>/);
// Remove delimiters if present
const matches = input.match(/^<~(.+?)~>$/);
if (matches !== null) input = matches[1];
// Remove non-alphabet characters
if (removeNonAlphChars) {
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
input = input.replace(re, "");
}
if (input.length === 0) return [];
let i = 0;
let block, blockBytes;
while (i < input.length) {
@@ -69,7 +111,7 @@ class FromBase85 extends Operation {
.map((chr, idx) => {
const digit = alphabet.indexOf(chr);
if (digit < 0 || digit > 84) {
throw `Invalid character '${chr}' at index ${idx}`;
throw `Invalid character '${chr}' at index ${i + idx}`;
}
return digit;
});

View File

@@ -1,5 +1,6 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @author john19696 [john19696@protonmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
@@ -33,6 +34,9 @@ import BLAKE2b from "./BLAKE2b.mjs";
import BLAKE2s from "./BLAKE2s.mjs";
import Streebog from "./Streebog.mjs";
import GOSTHash from "./GOSTHash.mjs";
import LMHash from "./LMHash.mjs";
import NTHash from "./NTHash.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Generate all hashes operation
@@ -51,7 +55,75 @@ class GenerateAllHashes extends Operation {
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [];
this.args = [
{
name: "Length (bits)",
type: "option",
value: [
"All", "128", "160", "224", "256", "320", "384", "512"
]
},
{
name: "Include names",
type: "boolean",
value: true
},
];
this.hashes = [
{name: "MD2", algo: (new MD2()), inputType: "arrayBuffer", params: []},
{name: "MD4", algo: (new MD4()), inputType: "arrayBuffer", params: []},
{name: "MD5", algo: (new MD5()), inputType: "arrayBuffer", params: []},
{name: "MD6", algo: (new MD6()), inputType: "str", params: []},
{name: "SHA0", algo: (new SHA0()), inputType: "arrayBuffer", params: []},
{name: "SHA1", algo: (new SHA1()), inputType: "arrayBuffer", params: []},
{name: "SHA2 224", algo: (new SHA2()), inputType: "arrayBuffer", params: ["224"]},
{name: "SHA2 256", algo: (new SHA2()), inputType: "arrayBuffer", params: ["256"]},
{name: "SHA2 384", algo: (new SHA2()), inputType: "arrayBuffer", params: ["384"]},
{name: "SHA2 512", algo: (new SHA2()), inputType: "arrayBuffer", params: ["512"]},
{name: "SHA3 224", algo: (new SHA3()), inputType: "arrayBuffer", params: ["224"]},
{name: "SHA3 256", algo: (new SHA3()), inputType: "arrayBuffer", params: ["256"]},
{name: "SHA3 384", algo: (new SHA3()), inputType: "arrayBuffer", params: ["384"]},
{name: "SHA3 512", algo: (new SHA3()), inputType: "arrayBuffer", params: ["512"]},
{name: "Keccak 224", algo: (new Keccak()), inputType: "arrayBuffer", params: ["224"]},
{name: "Keccak 256", algo: (new Keccak()), inputType: "arrayBuffer", params: ["256"]},
{name: "Keccak 384", algo: (new Keccak()), inputType: "arrayBuffer", params: ["384"]},
{name: "Keccak 512", algo: (new Keccak()), inputType: "arrayBuffer", params: ["512"]},
{name: "Shake 128", algo: (new Shake()), inputType: "arrayBuffer", params: ["128", 256]},
{name: "Shake 256", algo: (new Shake()), inputType: "arrayBuffer", params: ["256", 512]},
{name: "RIPEMD-128", algo: (new RIPEMD()), inputType: "arrayBuffer", params: ["128"]},
{name: "RIPEMD-160", algo: (new RIPEMD()), inputType: "arrayBuffer", params: ["160"]},
{name: "RIPEMD-256", algo: (new RIPEMD()), inputType: "arrayBuffer", params: ["256"]},
{name: "RIPEMD-320", algo: (new RIPEMD()), inputType: "arrayBuffer", params: ["320"]},
{name: "HAS-160", algo: (new HAS160()), inputType: "arrayBuffer", params: []},
{name: "Whirlpool-0", algo: (new Whirlpool()), inputType: "arrayBuffer", params: ["Whirlpool-0"]},
{name: "Whirlpool-T", algo: (new Whirlpool()), inputType: "arrayBuffer", params: ["Whirlpool-T"]},
{name: "Whirlpool", algo: (new Whirlpool()), inputType: "arrayBuffer", params: ["Whirlpool"]},
{name: "BLAKE2b-128", algo: (new BLAKE2b), inputType: "arrayBuffer", params: ["128", "Hex", {string: "", option: "UTF8"}]},
{name: "BLAKE2b-160", algo: (new BLAKE2b), inputType: "arrayBuffer", params: ["160", "Hex", {string: "", option: "UTF8"}]},
{name: "BLAKE2b-256", algo: (new BLAKE2b), inputType: "arrayBuffer", params: ["256", "Hex", {string: "", option: "UTF8"}]},
{name: "BLAKE2b-384", algo: (new BLAKE2b), inputType: "arrayBuffer", params: ["384", "Hex", {string: "", option: "UTF8"}]},
{name: "BLAKE2b-512", algo: (new BLAKE2b), inputType: "arrayBuffer", params: ["512", "Hex", {string: "", option: "UTF8"}]},
{name: "BLAKE2s-128", algo: (new BLAKE2s), inputType: "arrayBuffer", params: ["128", "Hex", {string: "", option: "UTF8"}]},
{name: "BLAKE2s-160", algo: (new BLAKE2s), inputType: "arrayBuffer", params: ["160", "Hex", {string: "", option: "UTF8"}]},
{name: "BLAKE2s-256", algo: (new BLAKE2s), inputType: "arrayBuffer", params: ["256", "Hex", {string: "", option: "UTF8"}]},
{name: "Streebog-256", algo: (new Streebog), inputType: "arrayBuffer", params: ["256"]},
{name: "Streebog-512", algo: (new Streebog), inputType: "arrayBuffer", params: ["512"]},
{name: "GOST", algo: (new GOSTHash), inputType: "arrayBuffer", params: ["D-A"]},
{name: "LM Hash", algo: (new LMHash), inputType: "str", params: []},
{name: "NT Hash", algo: (new NTHash), inputType: "str", params: []},
{name: "SSDEEP", algo: (new SSDEEP()), inputType: "str"},
{name: "CTPH", algo: (new CTPH()), inputType: "str"}
];
this.checksums = [
{name: "Fletcher-8", algo: (new Fletcher8Checksum), inputType: "byteArray", params: []},
{name: "Fletcher-16", algo: (new Fletcher16Checksum), inputType: "byteArray", params: []},
{name: "Fletcher-32", algo: (new Fletcher32Checksum), inputType: "byteArray", params: []},
{name: "Fletcher-64", algo: (new Fletcher64Checksum), inputType: "byteArray", params: []},
{name: "Adler-32", algo: (new Adler32Checksum), inputType: "byteArray", params: []},
{name: "CRC-8", algo: (new CRC8Checksum), inputType: "arrayBuffer", params: ["CRC-8"]},
{name: "CRC-16", algo: (new CRC16Checksum), inputType: "arrayBuffer", params: []},
{name: "CRC-32", algo: (new CRC32Checksum), inputType: "arrayBuffer", params: []}
];
}
/**
@@ -60,63 +132,74 @@ class GenerateAllHashes extends Operation {
* @returns {string}
*/
run(input, args) {
const arrayBuffer = input,
str = Utils.arrayBufferToStr(arrayBuffer, false),
byteArray = new Uint8Array(arrayBuffer),
output = "MD2: " + (new MD2()).run(arrayBuffer, []) +
"\nMD4: " + (new MD4()).run(arrayBuffer, []) +
"\nMD5: " + (new MD5()).run(arrayBuffer, []) +
"\nMD6: " + (new MD6()).run(str, []) +
"\nSHA0: " + (new SHA0()).run(arrayBuffer, []) +
"\nSHA1: " + (new SHA1()).run(arrayBuffer, []) +
"\nSHA2 224: " + (new SHA2()).run(arrayBuffer, ["224"]) +
"\nSHA2 256: " + (new SHA2()).run(arrayBuffer, ["256"]) +
"\nSHA2 384: " + (new SHA2()).run(arrayBuffer, ["384"]) +
"\nSHA2 512: " + (new SHA2()).run(arrayBuffer, ["512"]) +
"\nSHA3 224: " + (new SHA3()).run(arrayBuffer, ["224"]) +
"\nSHA3 256: " + (new SHA3()).run(arrayBuffer, ["256"]) +
"\nSHA3 384: " + (new SHA3()).run(arrayBuffer, ["384"]) +
"\nSHA3 512: " + (new SHA3()).run(arrayBuffer, ["512"]) +
"\nKeccak 224: " + (new Keccak()).run(arrayBuffer, ["224"]) +
"\nKeccak 256: " + (new Keccak()).run(arrayBuffer, ["256"]) +
"\nKeccak 384: " + (new Keccak()).run(arrayBuffer, ["384"]) +
"\nKeccak 512: " + (new Keccak()).run(arrayBuffer, ["512"]) +
"\nShake 128: " + (new Shake()).run(arrayBuffer, ["128", 256]) +
"\nShake 256: " + (new Shake()).run(arrayBuffer, ["256", 512]) +
"\nRIPEMD-128: " + (new RIPEMD()).run(arrayBuffer, ["128"]) +
"\nRIPEMD-160: " + (new RIPEMD()).run(arrayBuffer, ["160"]) +
"\nRIPEMD-256: " + (new RIPEMD()).run(arrayBuffer, ["256"]) +
"\nRIPEMD-320: " + (new RIPEMD()).run(arrayBuffer, ["320"]) +
"\nHAS-160: " + (new HAS160()).run(arrayBuffer, []) +
"\nWhirlpool-0: " + (new Whirlpool()).run(arrayBuffer, ["Whirlpool-0"]) +
"\nWhirlpool-T: " + (new Whirlpool()).run(arrayBuffer, ["Whirlpool-T"]) +
"\nWhirlpool: " + (new Whirlpool()).run(arrayBuffer, ["Whirlpool"]) +
"\nBLAKE2b-128: " + (new BLAKE2b).run(arrayBuffer, ["128", "Hex", {string: "", option: "UTF8"}]) +
"\nBLAKE2b-160: " + (new BLAKE2b).run(arrayBuffer, ["160", "Hex", {string: "", option: "UTF8"}]) +
"\nBLAKE2b-256: " + (new BLAKE2b).run(arrayBuffer, ["256", "Hex", {string: "", option: "UTF8"}]) +
"\nBLAKE2b-384: " + (new BLAKE2b).run(arrayBuffer, ["384", "Hex", {string: "", option: "UTF8"}]) +
"\nBLAKE2b-512: " + (new BLAKE2b).run(arrayBuffer, ["512", "Hex", {string: "", option: "UTF8"}]) +
"\nBLAKE2s-128: " + (new BLAKE2s).run(arrayBuffer, ["128", "Hex", {string: "", option: "UTF8"}]) +
"\nBLAKE2s-160: " + (new BLAKE2s).run(arrayBuffer, ["160", "Hex", {string: "", option: "UTF8"}]) +
"\nBLAKE2s-256: " + (new BLAKE2s).run(arrayBuffer, ["256", "Hex", {string: "", option: "UTF8"}]) +
"\nStreebog-256: " + (new Streebog).run(arrayBuffer, ["256"]) +
"\nStreebog-512: " + (new Streebog).run(arrayBuffer, ["512"]) +
"\nGOST: " + (new GOSTHash).run(arrayBuffer, ["D-A"]) +
"\nSSDEEP: " + (new SSDEEP()).run(str) +
"\nCTPH: " + (new CTPH()).run(str) +
"\n\nChecksums:" +
"\nFletcher-8: " + (new Fletcher8Checksum).run(byteArray, []) +
"\nFletcher-16: " + (new Fletcher16Checksum).run(byteArray, []) +
"\nFletcher-32: " + (new Fletcher32Checksum).run(byteArray, []) +
"\nFletcher-64: " + (new Fletcher64Checksum).run(byteArray, []) +
"\nAdler-32: " + (new Adler32Checksum).run(byteArray, []) +
"\nCRC-8: " + (new CRC8Checksum).run(arrayBuffer, ["CRC-8"]) +
"\nCRC-16: " + (new CRC16Checksum).run(arrayBuffer, []) +
"\nCRC-32: " + (new CRC32Checksum).run(arrayBuffer, []);
const [length, includeNames] = args;
this.inputArrayBuffer = input;
this.inputStr = Utils.arrayBufferToStr(input, false);
this.inputByteArray = new Uint8Array(input);
let digest, output = "";
// iterate over each of the hashes
this.hashes.forEach(hash => {
digest = this.executeAlgo(hash.algo, hash.inputType, hash.params || []);
output += this.formatDigest(digest, length, includeNames, hash.name);
});
if (length === "All") {
output += "\nChecksums:\n";
this.checksums.forEach(checksum => {
digest = this.executeAlgo(checksum.algo, checksum.inputType, checksum.params || []);
output += this.formatDigest(digest, length, includeNames, checksum.name);
});
}
return output;
}
/**
* Executes a hash or checksum algorithm
*
* @param {Function} algo - The hash or checksum algorithm
* @param {string} inputType
* @param {Object[]} [params=[]]
* @returns {string}
*/
executeAlgo(algo, inputType, params=[]) {
let digest = null;
switch (inputType) {
case "arrayBuffer":
digest = algo.run(this.inputArrayBuffer, params);
break;
case "str":
digest = algo.run(this.inputStr, params);
break;
case "byteArray":
digest = algo.run(this.inputByteArray, params);
break;
default:
throw new OperationError("Unknown hash input type: " + inputType);
}
return digest;
}
/**
* Formats the digest depending on user-specified arguments
* @param {string} digest
* @param {string} length
* @param {boolean} includeNames
* @param {string} name
* @returns {string}
*/
formatDigest(digest, length, includeNames, name) {
if (length !== "All" && (digest.length * 4) !== parseInt(length, 10))
return "";
if (!includeNames)
return digest + "\n";
return `${name}:${" ".repeat(13-name.length)}${digest}\n`;
}
}
export default GenerateAllHashes;

View File

@@ -4,7 +4,7 @@
* @license Apache-2.0
*/
import jpath from "jsonpath";
import {JSONPath} from "jsonpath-plus";
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
@@ -27,14 +27,20 @@ class JPathExpression extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Query",
"type": "string",
"value": ""
name: "Query",
type: "string",
value: ""
},
{
"name": "Result delimiter",
"type": "binaryShortString",
"value": "\\n"
name: "Result delimiter",
type: "binaryShortString",
value: "\\n"
},
{
name: "Prevent eval",
type: "boolean",
value: true,
description: "Evaluated expressions are disabled by default for security reasons"
}
];
}
@@ -45,18 +51,21 @@ class JPathExpression extends Operation {
* @returns {string}
*/
run(input, args) {
const [query, delimiter] = args;
let results,
obj;
const [query, delimiter, preventEval] = args;
let results, jsonObj;
try {
obj = JSON.parse(input);
jsonObj = JSON.parse(input);
} catch (err) {
throw new OperationError(`Invalid input JSON: ${err.message}`);
}
try {
results = jpath.query(obj, query);
results = JSONPath({
path: query,
json: jsonObj,
preventEval: preventEval
});
} catch (err) {
throw new OperationError(`Invalid JPath expression: ${err.message}`);
}

View File

@@ -114,8 +114,11 @@ class JSONToCSV extends Operation {
* @returns {string}
*/
escapeCellContents(data, force=false) {
if (typeof data === "number") data = data.toString();
if (force && typeof data !== "string") data = JSON.stringify(data);
if (data !== "string") {
const isPrimitive = data == null || typeof data !== "object";
if (isPrimitive) data = `${data}`;
else if (force) data = JSON.stringify(data);
}
// Double quotes should be doubled up
data = data.replace(/"/g, '""');

View File

@@ -26,6 +26,13 @@ class JWTDecode extends Operation {
this.inputType = "string";
this.outputType = "JSON";
this.args = [];
this.checks = [
{
pattern: "^ey([A-Za-z0-9_-]+)\\.ey([A-Za-z0-9_-]+)\\.([A-Za-z0-9_-]+)$",
flags: "",
args: []
},
];
}
/**

View File

@@ -0,0 +1,41 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import {smbhash} from "ntlm";
/**
* LM Hash operation
*/
class LMHash extends Operation {
/**
* LMHash constructor
*/
constructor() {
super();
this.name = "LM Hash";
this.module = "Crypto";
this.description = "An LM Hash, or LAN Manager Hash, is a deprecated way of storing passwords on old Microsoft operating systems. It is particularly weak and can be cracked in seconds on modern hardware using rainbow tables.";
this.infoURL = "https://wikipedia.org/wiki/LAN_Manager#Password_hashing_algorithm";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
return smbhash.lmhash(input);
}
}
export default LMHash;

View File

@@ -0,0 +1,57 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import * as LS47 from "../lib/LS47.mjs";
/**
* LS47 Decrypt operation
*/
class LS47Decrypt extends Operation {
/**
* LS47Decrypt constructor
*/
constructor() {
super();
this.name = "LS47 Decrypt";
this.module = "Crypto";
this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.<br>The LS47 alphabet consists of following characters: <code>_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()</code><br>An LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption.";
this.infoURL = "https://github.com/exaexa/ls47";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Password",
type: "string",
value: ""
},
{
name: "Padding",
type: "number",
value: 10
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
this.paddingSize = parseInt(args[1], 10);
LS47.initTiles();
const key = LS47.deriveKey(args[0]);
return LS47.decryptPad(key, input, this.paddingSize);
}
}
export default LS47Decrypt;

View File

@@ -0,0 +1,62 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import * as LS47 from "../lib/LS47.mjs";
/**
* LS47 Encrypt operation
*/
class LS47Encrypt extends Operation {
/**
* LS47Encrypt constructor
*/
constructor() {
super();
this.name = "LS47 Encrypt";
this.module = "Crypto";
this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.<br>The LS47 alphabet consists of following characters: <code>_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()</code><br>A LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption.";
this.infoURL = "https://github.com/exaexa/ls47";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Password",
type: "string",
value: ""
},
{
name: "Padding",
type: "number",
value: 10
},
{
name: "Signature",
type: "string",
value: ""
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
this.paddingSize = parseInt(args[1], 10);
LS47.initTiles();
const key = LS47.deriveKey(args[0]);
return LS47.encryptPad(key, input, args[2], this.paddingSize);
}
}
export default LS47Encrypt;

View File

@@ -0,0 +1,64 @@
/**
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { compress } from "@blu3r4y/lzma";
import {isWorkerEnvironment} from "../Utils.mjs";
/**
* LZMA Compress operation
*/
class LZMACompress extends Operation {
/**
* LZMACompress constructor
*/
constructor() {
super();
this.name = "LZMA Compress";
this.module = "Compression";
this.description = "Compresses data using the Lempel\u2013Ziv\u2013Markov chain algorithm. Compression mode determines the speed and effectiveness of the compression: 1 is fastest and less effective, 9 is slowest and most effective";
this.infoURL = "https://wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm";
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
this.args = [
{
name: "Compression Mode",
type: "option",
value: [
"1", "2", "3", "4", "5", "6", "7", "8", "9"
],
"defaultIndex": 6
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
async run(input, args) {
const mode = Number(args[0]);
return new Promise((resolve, reject) => {
compress(new Uint8Array(input), mode, (result, error) => {
if (error) {
reject(new OperationError(`Failed to compress input: ${error.message}`));
}
// The compression returns as an Int8Array, but we can just get the unsigned data from the buffer
resolve(new Int8Array(result).buffer);
}, (percent) => {
if (isWorkerEnvironment()) self.sendStatusMessage(`Compressing input: ${(percent*100).toFixed(2)}%`);
});
});
}
}
export default LZMACompress;

View File

@@ -0,0 +1,57 @@
/**
* @author Matt C [me@mitt.dev]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import {decompress} from "@blu3r4y/lzma";
import Utils, {isWorkerEnvironment} from "../Utils.mjs";
/**
* LZMA Decompress operation
*/
class LZMADecompress extends Operation {
/**
* LZMADecompress constructor
*/
constructor() {
super();
this.name = "LZMA Decompress";
this.module = "Compression";
this.description = "Decompresses data using the Lempel-Ziv-Markov chain Algorithm.";
this.infoURL = "https://wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm";
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
async run(input, args) {
return new Promise((resolve, reject) => {
decompress(new Uint8Array(input), (result, error) => {
if (error) {
reject(new OperationError(`Failed to decompress input: ${error.message}`));
}
// The decompression returns either a String or an untyped unsigned int8 array, but we can just get the unsigned data from the buffer
if (typeof result == "string") {
resolve(Utils.strToArrayBuffer(result));
} else {
resolve(new Int8Array(result).buffer);
}
}, (percent) => {
if (isWorkerEnvironment()) self.sendStatusMessage(`Decompressing input: ${(percent*100).toFixed(2)}%`);
});
});
}
}
export default LZMADecompress;

View File

@@ -0,0 +1,55 @@
/**
* @author crespyl [peter@crespyl.net]
* @copyright Peter Jacobs 2021
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import {COMPRESSION_OUTPUT_FORMATS, COMPRESSION_FUNCTIONS} from "../lib/LZString.mjs";
/**
* LZString Compress operation
*/
class LZStringCompress extends Operation {
/**
* LZStringCompress constructor
*/
constructor() {
super();
this.name = "LZString Compress";
this.module = "Compression";
this.description = "Compress the input with lz-string.";
this.infoURL = "https://pieroxy.net/blog/pages/lz-string/index.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Compression Format",
type: "option",
defaultIndex: 0,
value: COMPRESSION_OUTPUT_FORMATS
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const compress = COMPRESSION_FUNCTIONS[args[0]];
if (compress) {
return compress(input);
} else {
throw new OperationError("Unable to find compression function");
}
}
}
export default LZStringCompress;

View File

@@ -0,0 +1,56 @@
/**
* @author crespyl [peter@crespyl.net]
* @copyright Peter Jacobs 2021
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import {COMPRESSION_OUTPUT_FORMATS, DECOMPRESSION_FUNCTIONS} from "../lib/LZString.mjs";
/**
* LZString Decompress operation
*/
class LZStringDecompress extends Operation {
/**
* LZStringDecompress constructor
*/
constructor() {
super();
this.name = "LZString Decompress";
this.module = "Compression";
this.description = "Decompresses data that was compressed with lz-string.";
this.infoURL = "https://pieroxy.net/blog/pages/lz-string/index.html";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Compression Format",
type: "option",
defaultIndex: 0,
value: COMPRESSION_OUTPUT_FORMATS
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const decompress = DECOMPRESSION_FUNCTIONS[args[0]];
if (decompress) {
return decompress(input);
} else {
throw new OperationError("Unable to find decompression function");
}
}
}
export default LZStringDecompress;

View File

@@ -20,10 +20,16 @@ class Merge extends Operation {
this.name = "Merge";
this.flowControl = true;
this.module = "Default";
this.description = "Consolidate all branches back into a single trunk. The opposite of Fork.";
this.description = "Consolidate all branches back into a single trunk. The opposite of Fork. Unticking the Merge All checkbox will only consolidate all branches up to the nearest Fork/Subsection.";
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.args = [
{
name: "Merge All",
type: "boolean",
value: true,
}
];
}
/**

View File

@@ -0,0 +1,46 @@
/**
* @author brun0ne [brunonblok@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import cptable from "codepage";
import {runHash} from "../lib/Hash.mjs";
/**
* NT Hash operation
*/
class NTHash extends Operation {
/**
* NTHash constructor
*/
constructor() {
super();
this.name = "NT Hash";
this.module = "Crypto";
this.description = "An NT Hash, sometimes referred to as an NTLM hash, is a method of storing passwords on Windows systems. It works by running MD4 on UTF-16LE encoded input. NTLM hashes are considered weak because they can be brute-forced very easily with modern hardware.";
this.infoURL = "https://wikipedia.org/wiki/NT_LAN_Manager";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const format = 1200; // UTF-16LE
const encoded = cptable.utils.encode(format, input);
const hashed = runHash("md4", encoded);
return hashed.toUpperCase();
}
}
export default NTHash;

View File

@@ -12,10 +12,8 @@ import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import Tesseract from "tesseract.js";
const { createWorker } = Tesseract;
import process from "process";
import { createWorker } from "tesseract.js";
/**
* Optical Character Recognition operation
@@ -55,7 +53,7 @@ class OpticalCharacterRecognition extends Operation {
const type = isImage(input);
if (!type) {
throw new OperationError("Invalid File Type");
throw new OperationError("Unsupported file type (supported: jpg,png,pbm,bmp) or no file provided");
}
const assetDir = isWorkerEnvironment() ? `${self.docURL}/assets/` : `${process.cwd()}/src/core/vendor/`;
@@ -74,7 +72,7 @@ class OpticalCharacterRecognition extends Operation {
}
});
await worker.load();
self.sendStatusMessage("Loading English language...");
self.sendStatusMessage(`Loading English language pack...`);
await worker.loadLanguage("eng");
self.sendStatusMessage("Intialising Tesseract API...");
await worker.initialize("eng");

View File

@@ -0,0 +1,133 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* P-list Viewer operation
*/
class PlistViewer extends Operation {
/**
* PlistViewer constructor
*/
constructor() {
super();
this.name = "P-list Viewer";
this.module = "Default";
this.description = "In the macOS, iOS, NeXTSTEP, and GNUstep programming frameworks, property list files are files that store serialized objects. Property list files use the filename extension .plist, and thus are often referred to as p-list files.<br><br>This operation displays plist files in a human readable format.";
this.infoURL = "https://wikipedia.org/wiki/Property_list";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
// Regexes are designed to transform the xml format into a more readable string format.
input = input.slice(input.indexOf("<plist"))
.replace(/<plist.+>/g, "plist => ")
.replace(/<dict>/g, "{")
.replace(/<\/dict>/g, "}")
.replace(/<array>/g, "[")
.replace(/<\/array>/g, "]")
.replace(/<key>.+<\/key>/g, m => `${m.slice(5, m.indexOf(/<\/key>/g)-5)}\t=> `)
.replace(/<real>.+<\/real>/g, m => `${m.slice(6, m.indexOf(/<\/real>/g)-6)}\n`)
.replace(/<string>.+<\/string>/g, m => `"${m.slice(8, m.indexOf(/<\/string>/g)-8)}"\n`)
.replace(/<integer>.+<\/integer>/g, m => `${m.slice(9, m.indexOf(/<\/integer>/g)-9)}\n`)
.replace(/<false\/>/g, m => "false")
.replace(/<true\/>/g, m => "true")
.replace(/<\/plist>/g, "/plist")
.replace(/<date>.+<\/date>/g, m => `${m.slice(6, m.indexOf(/<\/integer>/g)-6)}`)
.replace(/<data>(\s|.)+?<\/data>/g, m => `${m.slice(6, m.indexOf(/<\/data>/g)-6)}`)
.replace(/[ \t\r\f\v]/g, "");
/**
* Depending on the type of brace, it will increment the depth and amount of arrays accordingly.
*
* @param {string} elem
* @param {array} vals
* @param {number} offset
*/
function braces(elem, vals, offset) {
const temp = vals.indexOf(elem);
if (temp !== -1) {
depthCount += offset;
if (temp === 1)
arrCount += offset;
}
}
let result = "";
let arrCount = 0;
let depthCount = 0;
/**
* Formats the input after the regex has replaced all of the relevant parts.
*
* @param {array} input
* @param {number} index
*/
function printIt(input, index) {
if (!(input.length))
return;
let temp = "";
const origArr = arrCount;
let currElem = input[0];
// If the current position points at a larger dynamic structure.
if (currElem.indexOf("=>") !== -1) {
// If the LHS also points at a larger structure (nested plists in a dictionary).
if (input[1].indexOf("=>") !== -1)
temp = currElem.slice(0, -2) + " => " + input[1].slice(0, -2) + " =>\n";
else
temp = currElem.slice(0, -2) + " => " + input[1] + "\n";
input = input.slice(1);
} else {
// Controls the tab depth for how many closing braces there have been.
braces(currElem, ["}", "]"], -1);
// Has to be here since the formatting breaks otherwise.
temp = currElem + "\n";
}
currElem = input[0];
// Tab out to the correct distance.
result += ("\t".repeat(depthCount));
// If it is enclosed in an array show index.
if (arrCount > 0 && currElem !== "]")
result += index.toString() + " => ";
result += temp;
// Controls the tab depth for how many opening braces there have been.
braces(currElem, ["{", "["], 1);
// If there has been a new array then reset index.
if (arrCount > origArr)
return printIt(input.slice(1), 0);
return printIt(input.slice(1), ++index);
}
input = input.split("\n").filter(e => e !== "");
printIt(input, 0);
return result;
}
}
export default PlistViewer;

View File

@@ -23,7 +23,7 @@ class ParseSSHHostKey extends Operation {
this.name = "Parse SSH Host Key";
this.module = "Default";
this.description = "Parses a SSH host key and extracts fields from it.<br>The key type can be:<ul><li>ssh-rsa</li><li>ssh-dss</li><li>ecdsa-sha2</li></ul>The key format can be either Hex or Base64.";
this.description = "Parses a SSH host key and extracts fields from it.<br>The key type can be:<ul><li>ssh-rsa</li><li>ssh-dss</li><li>ecdsa-sha2</li><li>ssh-ed25519</li></ul>The key format can be either Hex or Base64.";
this.infoURL = "https://wikipedia.org/wiki/Secure_Shell";
this.inputType = "string";
this.outputType = "string";
@@ -71,6 +71,8 @@ class ParseSSHHostKey extends Operation {
} else if (keyType.startsWith("ecdsa-sha2")) {
output += `\nCurve: ${Utils.byteArrayToChars(fromHex(fields[1]))}`;
output += `\nPoint: 0x${fields.slice(2)}`;
} else if (keyType === "ssh-ed25519") {
output += `\nx: 0x${fields[1]}`;
} else {
output += "\nUnsupported key type.";
output += `\nParameters: ${fields.slice(1)}`;

View File

@@ -0,0 +1,102 @@
/**
* @author MikeCAT
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
/**
* ROT13 Brute Force operation.
*/
class ROT13BruteForce extends Operation {
/**
* ROT13BruteForce constructor
*/
constructor() {
super();
this.name = "ROT13 Brute Force";
this.module = "Default";
this.description = "Try all meaningful amounts for ROT13.<br><br>Optionally you can enter your known plaintext (crib) to filter the result.";
this.infoURL = "https://wikipedia.org/wiki/ROT13";
this.inputType = "byteArray";
this.outputType = "string";
this.args = [
{
name: "Rotate lower case chars",
type: "boolean",
value: true
},
{
name: "Rotate upper case chars",
type: "boolean",
value: true
},
{
name: "Rotate numbers",
type: "boolean",
value: false
},
{
name: "Sample length",
type: "number",
value: 100
},
{
name: "Sample offset",
type: "number",
value: 0
},
{
name: "Print amount",
type: "boolean",
value: true
},
{
name: "Crib (known plaintext string)",
type: "string",
value: ""
}
];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [rotateLower, rotateUpper, rotateNum, sampleLength, sampleOffset, printAmount, crib] = args;
const sample = input.slice(sampleOffset, sampleOffset + sampleLength);
const cribLower = crib.toLowerCase();
const lowerStart = "a".charCodeAt(0), upperStart = "A".charCodeAt(0), numStart = "0".charCodeAt(0);
const result = [];
for (let amount = 1; amount < 26; amount++) {
const rotated = sample.slice();
for (let i = 0; i < rotated.length; i++) {
if (rotateLower && lowerStart <= rotated[i] && rotated[i] < lowerStart + 26) {
rotated[i] = (rotated[i] - lowerStart + amount) % 26 + lowerStart;
} else if (rotateUpper && upperStart <= rotated[i] && rotated[i] < upperStart + 26) {
rotated[i] = (rotated[i] - upperStart + amount) % 26 + upperStart;
} else if (rotateNum && numStart <= rotated[i] && rotated[i] < numStart + 10) {
rotated[i] = (rotated[i] - numStart + amount) % 10 + numStart;
}
}
const rotatedString = Utils.byteArrayToUtf8(rotated);
if (rotatedString.toLowerCase().indexOf(cribLower) >= 0) {
const rotatedStringPrintable = Utils.printable(rotatedString, false);
if (printAmount) {
const amountStr = "Amount = " + (" " + amount).slice(-2) + ": ";
result.push(amountStr + rotatedStringPrintable);
} else {
result.push(rotatedStringPrintable);
}
}
}
return result.join("\n");
}
}
export default ROT13BruteForce;

View File

@@ -0,0 +1,82 @@
/**
* @author MikeCAT
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
/**
* ROT47 Brute Force operation.
*/
class ROT47BruteForce extends Operation {
/**
* ROT47BruteForce constructor
*/
constructor() {
super();
this.name = "ROT47 Brute Force";
this.module = "Default";
this.description = "Try all meaningful amounts for ROT47.<br><br>Optionally you can enter your known plaintext (crib) to filter the result.";
this.infoURL = "https://wikipedia.org/wiki/ROT13#Variants";
this.inputType = "byteArray";
this.outputType = "string";
this.args = [
{
name: "Sample length",
type: "number",
value: 100
},
{
name: "Sample offset",
type: "number",
value: 0
},
{
name: "Print amount",
type: "boolean",
value: true
},
{
name: "Crib (known plaintext string)",
type: "string",
value: ""
}
];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [sampleLength, sampleOffset, printAmount, crib] = args;
const sample = input.slice(sampleOffset, sampleOffset + sampleLength);
const cribLower = crib.toLowerCase();
const result = [];
for (let amount = 1; amount < 94; amount++) {
const rotated = sample.slice();
for (let i = 0; i < rotated.length; i++) {
if (33 <= rotated[i] && rotated[i] <= 126) {
rotated[i] = (rotated[i] - 33 + amount) % 94 + 33;
}
}
const rotatedString = Utils.byteArrayToUtf8(rotated);
if (rotatedString.toLowerCase().indexOf(cribLower) >= 0) {
const rotatedStringPrintable = Utils.printable(rotatedString, false);
if (printAmount) {
const amountStr = "Amount = " + (" " + amount).slice(-2) + ": ";
result.push(amountStr + rotatedStringPrintable);
} else {
result.push(rotatedStringPrintable);
}
}
}
return result.join("\n");
}
}
export default ROT47BruteForce;

View File

@@ -0,0 +1,123 @@
/**
* @author Daniel Temkin [http://danieltemkin.com]
* @author Thomas Leplus [https://www.leplus.org]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* ROT8000 operation.
*/
class ROT8000 extends Operation {
/**
* ROT8000 constructor
*/
constructor() {
super();
this.name = "ROT8000";
this.module = "Default";
this.description = "The simple Caesar-cypher encryption that replaces each Unicode character with the one 0x8000 places forward or back along the alphabet.";
this.infoURL = "https://rot8000.com/info";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
// Inspired from https://github.com/rottytooth/rot8000/blob/main/rot8000.js
// these come from the valid-code-point-transitions.json file generated from the c# proj
// this is done bc: 1) don't trust JS's understanging of surrogate pairs and 2) consistency with original rot8000
const validCodePoints = {
"33": true,
"127": false,
"161": true,
"5760": false,
"5761": true,
"8192": false,
"8203": true,
"8232": false,
"8234": true,
"8239": false,
"8240": true,
"8287": false,
"8288": true,
"12288": false,
"12289": true,
"55296": false,
"57344": true
};
const bmpSize = 0x10000;
const rotList = {}; // the mapping of char to rotated char
const hiddenBlocks = [];
let startBlock = 0;
for (const key in validCodePoints) {
if (Object.prototype.hasOwnProperty.call(validCodePoints, key)) {
if (validCodePoints[key] === true)
hiddenBlocks.push({ start: startBlock, end: parseInt(key, 10) - 1 });
else
startBlock = parseInt(key, 10);
}
}
const validIntList = []; // list of all valid chars
let currValid = false;
for (let i = 0; i < bmpSize; i++) {
if (validCodePoints[i] !== undefined) {
currValid = validCodePoints[i];
}
if (currValid) validIntList.push(i);
}
const rotateNum = Object.keys(validIntList).length / 2;
// go through every valid char and find its match
for (let i = 0; i < validIntList.length; i++) {
rotList[String.fromCharCode(validIntList[i])] =
String.fromCharCode(validIntList[(i + rotateNum) % (rotateNum * 2)]);
}
let output = "";
for (let count = 0; count < input.length; count++) {
// if it is not in the mappings list, just add it directly (no rotation)
if (rotList[input[count]] === undefined) {
output += input[count];
continue;
}
// otherwise, rotate it and add it to the string
output += rotList[input[count]];
}
return output;
}
/**
* Highlight ROT8000
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight(pos, args) {
return pos;
}
/**
* Highlight ROT8000 in reverse
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlightReverse(pos, args) {
return pos;
}
}
export default ROT8000;

View File

@@ -7,7 +7,6 @@
import Operation from "../Operation.mjs";
import {INFLATE_BUFFER_TYPE} from "../lib/Zlib.mjs";
import rawinflate from "zlibjs/bin/rawinflate.min.js";
import OperationError from "../errors/OperationError.mjs";
const Zlib = rawinflate.Zlib;
@@ -83,25 +82,6 @@ class RawInflate extends Operation {
}),
result = new Uint8Array(inflate.decompress());
// Raw Inflate sometimes messes up and returns nonsense like this:
// ]....]....]....]....]....]....]....]....]....]....]....]....]....]...
// e.g. Input data of [8b, 1d, dc, 44]
// Look for the first two square brackets:
if (result.length > 158 && result[0] === 93 && result[5] === 93) {
// If the first two square brackets are there, check that the others
// are also there. If they are, throw an error. If not, continue.
let valid = false;
for (let i = 0; i < 155; i += 5) {
if (result[i] !== 93) {
valid = true;
}
}
if (!valid) {
throw new OperationError("Error: Unable to inflate data");
}
}
// This seems to be the easiest way...
return result.buffer;
}

View File

@@ -22,7 +22,7 @@ class Subsection extends Operation {
this.name = "Subsection";
this.flowControl = true;
this.module = "Default";
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.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.<br><br>Use the Merge operation to reset the effects of subsection.";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
@@ -67,12 +67,21 @@ class Subsection extends Operation {
subOpList = [];
if (input && section !== "") {
// Set to 1 as if we are here, then there is one, the current one.
let numOp = 1;
// 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;
numOp--;
if (numOp === 0 || opList[i].ingValues[0])
break;
else
// Not this subsection's Merge.
subOpList.push(opList[i]);
} else {
if (opList[i].name === "Fork" || opList[i].name === "Subsection")
numOp++;
subOpList.push(opList[i]);
}
}

View File

@@ -52,7 +52,17 @@ class YARARules extends Operation {
name: "Show counts",
type: "boolean",
value: true
}
},
{
name: "Show rule warnings",
type: "boolean",
value: true
},
{
name: "Show console module messages",
type: "boolean",
value: true
},
];
}
@@ -64,7 +74,7 @@ class YARARules extends Operation {
async run(input, args) {
if (isWorkerEnvironment())
self.sendStatusMessage("Instantiating YARA...");
const [rules, showStrings, showLengths, showMeta, showCounts] = args;
const [rules, showStrings, showLengths, showMeta, showCounts, showRuleWarns, showConsole] = args;
return new Promise((resolve, reject) => {
Yara().then(yara => {
if (isWorkerEnvironment()) self.sendStatusMessage("Converting data for YARA.");
@@ -83,11 +93,19 @@ class YARARules extends Operation {
const compileError = resp.compileErrors.get(i);
if (!compileError.warning) {
reject(new OperationError(`Error on line ${compileError.lineNumber}: ${compileError.message}`));
} else {
matchString += `Warning on line ${compileError.lineNumber}: ${compileError.message}`;
} else if (showRuleWarns) {
matchString += `Warning on line ${compileError.lineNumber}: ${compileError.message}\n`;
}
}
}
if (showConsole) {
const consoleLogs = resp.consoleLogs;
for (let i = 0; i < consoleLogs.size(); i++) {
matchString += consoleLogs.get(i) + "\n";
}
}
const matchedRules = resp.matchedRules;
for (let i = 0; i < matchedRules.size(); i++) {
const rule = matchedRules.get(i);
@@ -100,11 +118,11 @@ class YARARules extends Operation {
}
meta = meta.slice(0, -2) + "]";
}
const countString = showCounts ? `${matches.size()} time${matches.size() > 1 ? "s" : ""}` : "";
const countString = matches.size() === 0 ? "" : (showCounts ? ` (${matches.size()} time${matches.size() > 1 ? "s" : ""})` : "");
if (matches.size() === 0 || !(showStrings || showLengths)) {
matchString += `Input matches rule "${rule.ruleName}"${meta}${countString.length > 0 ? ` ${countString}`: ""}.\n`;
} else {
matchString += `Rule "${rule.ruleName}"${meta} matches (${countString}):\n`;
matchString += `Rule "${rule.ruleName}"${meta} matches${countString}:\n`;
for (let j = 0; j < matches.size(); j++) {
const match = matches.get(j);
if (showStrings || showLengths) {

View File

@@ -186,7 +186,7 @@ div.toggle-string {
}
.ingredients .dropdown-toggle-split {
height: 41px !important;
height: 40px !important;
}
.boolean-arg {

View File

@@ -10,7 +10,7 @@
import "highlight.js/styles/vs.css";
/* Frameworks */
import "./vendors/bootstrap.scss";
import "bootstrap-material-design/dist/css/bootstrap-material-design.css";
import "bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css";
/* CyberChef styles */

View File

@@ -82,7 +82,17 @@ a:focus {
border-color: var(--btn-success-hover-border-colour);
}
select.form-control:not([size]):not([multiple]), select.custom-file-control:not([size]):not([multiple]) {
select.form-control,
select.form-control:focus {
background-color: var(--primary-background-colour) !important;
}
select.form-control:focus {
transition: none !important;
}
select.form-control:not([size]):not([multiple]),
select.custom-file-control:not([size]):not([multiple]) {
height: unset !important;
}
@@ -145,7 +155,8 @@ optgroup {
color: var(--primary-font-colour);
}
.table-bordered th, .table-bordered td {
.table-bordered th,
.table-bordered td {
border: 1px solid var(--table-border-colour);
}
@@ -172,7 +183,9 @@ optgroup {
color: var(--subtext-font-colour);
}
.nav-tabs>li>a.nav-link.active, .nav-tabs>li>a.nav-link.active:focus, .nav-tabs>li>a.nav-link.active:hover {
.nav-tabs>li>a.nav-link.active,
.nav-tabs>li>a.nav-link.active:focus,
.nav-tabs>li>a.nav-link.active:hover {
background-color: var(--secondary-background-colour);
border-color: var(--secondary-border-colour);
border-bottom-color: transparent;
@@ -183,7 +196,8 @@ optgroup {
border-color: var(--primary-border-colour);
}
.nav a.nav-link:focus, .nav a.nav-link:hover {
.nav a.nav-link:focus,
.nav a.nav-link:hover {
background-color: var(--secondary-border-colour);
}
@@ -199,7 +213,8 @@ optgroup {
color: var(--primary-font-colour);
}
.dropdown-menu a:focus, .dropdown-menu a:hover {
.dropdown-menu a:focus,
.dropdown-menu a:hover {
background-color: var(--secondary-background-colour);
color: var(--primary-font-colour);
}

View File

@@ -1,23 +0,0 @@
/**
* Bootstrap Material Design with overrides
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
@import "~bootstrap-material-design/scss/variables/colors";
$theme-colors: (
primary: $blue-700,
success: $green,
info: $light-blue,
warning: $deep-orange,
danger: $red,
light: $grey-100,
dark: $grey-800
);
$bmd-form-line-height: 1.25;
@import "~bootstrap-material-design/scss/core";

View File

@@ -249,6 +249,7 @@ module.exports = {
// testOp(browser, "RIPEMD", "test input", "test_output");
// testOp(browser, "ROT13", "test input", "test_output");
// testOp(browser, "ROT47", "test input", "test_output");
// testOp(browser, "ROT8000", "test input", "test_output");
// testOp(browser, "Rail Fence Cipher Decode", "test input", "test_output");
// testOp(browser, "Rail Fence Cipher Encode", "test input", "test_output");
// testOp(browser, "Randomize Colour Palette", "test input", "test_output");

View File

@@ -12,6 +12,7 @@
import Chef from "../../src/core/Chef.mjs";
import Utils from "../../src/core/Utils.mjs";
import cliProgress from "cli-progress";
import log from "loglevel";
/**
* Object to store and run the list of tests.
@@ -50,6 +51,9 @@ class TestRegister {
* Runs all the tests in the register.
*/
async runTests () {
// Turn off logging to avoid messy errors
log.setLevel("silent", false);
const progBar = new cliProgress.SingleBar({
format: formatter,
stopOnComplete: true
@@ -84,7 +88,17 @@ class TestRegister {
if (result.error) {
if (test.expectedError) {
ret.status = "passing";
if (result.error.displayStr === test.expectedOutput) {
ret.status = "passing";
} else {
ret.status = "failing";
ret.output = [
"Expected",
"\t" + test.expectedOutput.replace(/\n/g, "\n\t"),
"Received",
"\t" + result.error.displayStr.replace(/\n/g, "\n\t"),
].join("\n");
}
} else {
ret.status = "erroring";
ret.output = result.error.displayStr;
@@ -118,6 +132,9 @@ class TestRegister {
progBar.increment();
}
// Turn logging back on
log.setLevel("info", false);
return testResults;
}

View File

@@ -24,9 +24,12 @@ import "./tests/Base45.mjs";
import "./tests/Base58.mjs";
import "./tests/Base64.mjs";
import "./tests/Base62.mjs";
import "./tests/Base85.mjs";
import "./tests/BitwiseOp.mjs";
import "./tests/ByteRepr.mjs";
import "./tests/CartesianProduct.mjs";
import "./tests/CetaceanCipherEncode.mjs";
import "./tests/CetaceanCipherDecode.mjs";
import "./tests/CharEnc.mjs";
import "./tests/ChangeIPFormat.mjs";
import "./tests/Charts.mjs";
@@ -42,6 +45,7 @@ import "./tests/DateTime.mjs";
import "./tests/ExtractEmailAddresses.mjs";
import "./tests/Fork.mjs";
import "./tests/FromDecimal.mjs";
import "./tests/GenerateAllHashes.mjs";
import "./tests/Gzip.mjs";
import "./tests/Gunzip.mjs";
import "./tests/Hash.mjs";
@@ -114,7 +118,12 @@ import "./tests/HASSH.mjs";
import "./tests/GetAllCasings.mjs";
import "./tests/SIGABA.mjs";
import "./tests/ELFInfo.mjs";
import "./tests/Subsection.mjs";
import "./tests/CaesarBoxCipher.mjs";
import "./tests/UnescapeString.mjs";
import "./tests/LS47.mjs";
import "./tests/LZString.mjs";
import "./tests/NTLM.mjs";
// Cannot test operations that use the File type yet
// import "./tests/SplitColourChannels.mjs";

View File

@@ -0,0 +1,48 @@
/**
* Base85 tests
*
* @author john19696
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
// Example from Wikipedia
const wpExample = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";
// Escape newline, quote & backslash
const wpOutput = "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,O<\
DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKYi(\
DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIal(\
DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G>u\
D.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c";
TestRegister.addTests([
{
name: "To Base85",
input: wpExample,
expectedOutput: wpOutput,
recipeConfig: [
{ "op": "To Base85",
"args": ["!-u"] }
]
},
{
name: "From Base85",
input: wpOutput + "\n",
expectedOutput: wpExample,
recipeConfig: [
{ "op": "From Base85",
"args": ["!-u", true] }
]
},
{
name: "From Base85",
input: wpOutput + "v",
expectedError: true,
expectedOutput: "From Base85 - Invalid character 'v' at index 337",
recipeConfig: [
{ "op": "From Base85",
"args": ["!-u", false] }
]
},
]);

View File

@@ -0,0 +1,45 @@
/**
* Caesar Box Cipher tests.
*
* @author n1073645 [n1073645@gmail.com]
*
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Caesar Box Cipher: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "Caesar Box Cipher",
args: ["1"],
},
],
},
{
name: "Caesar Box Cipher: Hello World!",
input: "Hello World!",
expectedOutput: "Hlodeor!lWl",
recipeConfig: [
{
op: "Caesar Box Cipher",
args: ["3"],
},
],
},
{
name: "Caesar Box Cipher: Hello World!",
input: "Hlodeor!lWl",
expectedOutput: "HelloWorld!",
recipeConfig: [
{
op: "Caesar Box Cipher",
args: ["4"],
},
],
}
]);

View File

@@ -0,0 +1,22 @@
/**
* CetaceanCipher Encode tests
*
* @author dolphinOnKeys
* @copyright Crown Copyright 2022
* @licence Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Cetacean Cipher Decode",
input: "EEEEEEEEEeeEEEEe EEEEEEEEEeeEEEeE EEEEEEEEEeeEEEee EEeeEEEEEeeEEeee",
expectedOutput: "a b c で",
recipeConfig: [
{
op: "Cetacean Cipher Decode",
args: []
},
],
}
]);

View File

@@ -0,0 +1,22 @@
/**
* CetaceanCipher Encode tests
*
* @author dolphinOnKeys
* @copyright Crown Copyright 2022
* @licence Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Cetacean Cipher Encode",
input: "a b c で",
expectedOutput: "EEEEEEEEEeeEEEEe EEEEEEEEEeeEEEeE EEEEEEEEEeeEEEee EEeeEEEEEeeEEeee",
recipeConfig: [
{
op: "Cetacean Cipher Encode",
args: []
},
],
}
]);

View File

@@ -185,11 +185,11 @@ TestRegister.addTests([
{
name: "JPath Expression: Empty expression",
input: JSON.stringify(JSON_TEST_DATA),
expectedOutput: "Invalid JPath expression: we need a path",
expectedOutput: "",
recipeConfig: [
{
"op": "JPath expression",
"args": ["", "\n"]
"args": ["", "\n", true]
}
],
},
@@ -205,7 +205,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$.store.book[*].author", "\n"]
"args": ["$.store.book[*].author", "\n", true]
}
],
},
@@ -223,7 +223,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$..title", "\n"]
"args": ["$..title", "\n", true]
}
],
},
@@ -238,7 +238,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$.store.*", "\n"]
"args": ["$.store.*", "\n", true]
}
],
},
@@ -249,7 +249,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$..book[-1:]", "\n"]
"args": ["$..book[-1:]", "\n", true]
}
],
},
@@ -263,7 +263,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$..book[:2]", "\n"]
"args": ["$..book[:2]", "\n", true]
}
],
},
@@ -277,7 +277,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$..book[?(@.isbn)]", "\n"]
"args": ["$..book[?(@.isbn)]", "\n", false]
}
],
},
@@ -292,7 +292,7 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$..book[?(@.price<30 && @.category==\"fiction\")]", "\n"]
"args": ["$..book[?(@.price<30 && @.category==\"fiction\")]", "\n", false]
}
],
},
@@ -306,10 +306,25 @@ TestRegister.addTests([
recipeConfig: [
{
"op": "JPath expression",
"args": ["$..book[?(@.price<10)]", "\n"]
"args": ["$..book[?(@.price<10)]", "\n", false]
}
],
},
{
name: "JPath Expression: Script-based expression",
input: "[{}]",
recipeConfig: [
{
"op": "JPath expression",
"args": [
"$..[?(({__proto__:[].constructor}).constructor(\"self.postMessage({action:'bakeComplete',data:{bakeId:1,dish:{type:1,value:''},duration:1,error:false,id:undefined,inputNum:2,progress:1,result:'<iframe/onload=debugger>',type: 'html'}});\")();)]",
"\n",
true
]
}
],
expectedOutput: "Invalid JPath expression: Eval [?(expr)] prevented in JSONPath expression."
},
{
name: "CSS selector",
input: '<div id="test">\n<p class="a">hello</p>\n<p>world</p>\n<p class="a">again</p>\n</div>',

View File

@@ -23,4 +23,56 @@ TestRegister.addTests([
}
],
},
{
name: "LZMA compress & decompress",
input: "The cat sat on the mat.",
// Generated using command `echo -n "The cat sat on the mat." | lzma -z -6 | xxd -p`
expectedOutput: "The cat sat on the mat.",
recipeConfig: [
{
"op": "LZMA Compress",
"args": ["6"]
},
{
"op": "LZMA Decompress",
"args": []
},
],
},
{
name: "LZMA decompress: binary",
// Generated using command `echo "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10" | xxd -r -p | lzma -z -6 | xxd -p`
input: "5d00008000ffffffffffffffff00000052500a84f99bb28021a969d627e03e8a922effffbd160000",
expectedOutput: "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10",
recipeConfig: [
{
"op": "From Hex",
"args": ["Space"]
},
{
"op": "LZMA Decompress",
"args": []
},
{
"op": "To Hex",
"args": ["Space", 0]
}
],
},
{
name: "LZMA decompress: string",
// Generated using command `echo -n "The cat sat on the mat." | lzma -z -6 | xxd -p`
input: "5d00008000ffffffffffffffff002a1a08a202b1a4b814b912c94c4152e1641907d3fd8cd903ffff4fec0000",
expectedOutput: "The cat sat on the mat.",
recipeConfig: [
{
"op": "From Hex",
"args": ["Space"]
},
{
"op": "LZMA Decompress",
"args": []
}
],
},
]);

View File

@@ -31,7 +31,7 @@ TestRegister.addTests([
},
{
op: "Merge",
args: [],
args: [true],
},
],
},
@@ -50,7 +50,7 @@ TestRegister.addTests([
},
{
op: "Merge",
args: [],
args: [true],
},
],
},
@@ -66,5 +66,16 @@ TestRegister.addTests([
{"op": "Label", "args": ["skipReturn"]},
{"op": "To Base64", "args": ["A-Za-z0-9+/="]}
]
}
},
{
name: "Fork, Partial Merge",
input: "Hello World",
expectedOutput: "48656c6c6f 576f726c64",
recipeConfig: [
{ "op": "Fork", "args": [" ", " ", false] },
{ "op": "Fork", "args": ["l", "l", false] },
{ "op": "Merge", "args": [false] },
{ "op": "To Hex", "args": ["None", 0] },
]
},
]);

View File

@@ -0,0 +1,115 @@
/**
* GenerateAllHashes tests.
*
* @author john19696 [john19696@protonmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Full generate all hashes",
input: "test",
expectedOutput: `MD2: dd34716876364a02d0195e2fb9ae2d1b
MD4: db346d691d7acc4dc2625db19f9e3f52
MD5: 098f6bcd4621d373cade4e832627b4f6
MD6: 93c8a7d0ff132f325138a82b2baa98c12a7c9ac982feb6c5b310a1ca713615bd
SHA0: f8d3b312442a67706057aeb45b983221afb4f035
SHA1: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
SHA2 224: 90a3ed9e32b2aaf4c61c410eb925426119e1a9dc53d4286ade99a809
SHA2 256: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
SHA2 384: 768412320f7b0aa5812fce428dc4706b3cae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf17a0a9
SHA2 512: ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff
SHA3 224: 3797bf0afbbfca4a7bbba7602a2b552746876517a7f9b7ce2db0ae7b
SHA3 256: 36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80
SHA3 384: e516dabb23b6e30026863543282780a3ae0dccf05551cf0295178d7ff0f1b41eecb9db3ff219007c4e097260d58621bd
SHA3 512: 9ece086e9bac491fac5c1d1046ca11d737b92a2b2ebd93f005d7b710110c0a678288166e7fbe796883a4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14
Keccak 224: 3be30a9ff64f34a5861116c5198987ad780165f8366e67aff4760b5e
Keccak 256: 9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658
Keccak 384: 53d0ba137307d4c2f9b6674c83edbd58b70c0f4340133ed0adc6fba1d2478a6a03b7788229e775d2de8ae8c0759d0527
Keccak 512: 1e2e9fc2002b002d75198b7503210c05a1baac4560916a3c6d93bcce3a50d7f00fd395bf1647b9abb8d1afcc9c76c289b0c9383ba386a956da4b38934417789e
Shake 128: d3b0aa9cd8b7255622cebc631e867d4093d6f6010191a53973c45fec9b07c774
Shake 256: b54ff7255705a71ee2925e4a3e30e41aed489a579d5595e0df13e32e1e4dd202a7c7f68b31d6418d9845eb4d757adda6ab189e1bb340db818e5b3bc725d992fa
RIPEMD-128: f1abb5083c9ff8a9dbbca9cd2b11fead
RIPEMD-160: 5e52fee47e6b070565f74372468cdc699de89107
RIPEMD-256: fe0289110d07daeee9d9500e14c57787d9083f6ba10e6bcb256f86bb4fe7b981
RIPEMD-320: 3b0a2e841e589cf583634a5dd265d2b5d497c4cc44b241e34e0f62d03e98c1b9dc72970b9bc20eb5
HAS-160: cb15e491eec6e769771d1f811315139c93071084
Whirlpool-0: d50ff71342b521974bae166539871922669afcfc7181250ebbae015c317ebb797173a69e7a05afd11099a9f0918159cd5bc88434d3ca44513d7263caea9244fe
Whirlpool-T: e6b4aa087751b4428171777f1893ba585404c7e0171787720eba0d8bccd710dc2c42f874c572bfae4cedabf50f2c80bf923805d4e31c504b86ca3bc59265e7dd
Whirlpool: b913d5bbb8e461c2c5961cbe0edcdadfd29f068225ceb37da6defcf89849368f8c6c2eb6a4c4ac75775d032a0ecfdfe8550573062b653fe92fc7b8fb3b7be8d6
BLAKE2b-128: 44a8995dd50b6657a037a7839304535b
BLAKE2b-160: a34fc3b6d2cce8beb3216c2bbb5e55739e8121ed
BLAKE2b-256: 928b20366943e2afd11ebc0eae2e53a93bf177a4fcf35bcc64d503704e65e202
BLAKE2b-384: 8a84b8666c8fcfb69f2ec41f578d7c85fbdb504ea6510fb05b50fcbf7ed8153c77943bc2da73abb136834e1a0d4f22cb
BLAKE2b-512: a71079d42853dea26e453004338670a53814b78137ffbed07603a41d76a483aa9bc33b582f77d30a65e6f29a896c0411f38312e1d66e0bf16386c86a89bea572
BLAKE2s-128: e9ddd9926b9dcb382e09be39ba403d2c
BLAKE2s-160: d6197dabec2bd6f4ff303b8e519e8f15d42a453d
BLAKE2s-256: f308fc02ce9172ad02a7d75800ecfc027109bc67987ea32aba9b8dcc7b10150e
Streebog-256: 12a50838191b5504f1e5f2fd078714cf6b592b9d29af99d0b10d8d02881c3857
Streebog-512: 7200bf5dea560f0d7960d07fdc8874ad9f3b86ece2e45f5502ae2e176f2c928e0e581152281f5aee818318bed7cbe6aa69999589234723ceb33175598365b5c8
GOST: ee67303696d205ddd2b2363e8e01b4b7199a80957d94d7678eaad3fc834c5a27
LM Hash: 01FC5A6BE7BC6929AAD3B435B51404EE
NT Hash: 0CB6948805F797BF2A82807973B89537
SSDEEP: 3:Hn:Hn
CTPH: A:E:E
Checksums:
Fletcher-8: 3d
Fletcher-16: 5dc1
Fletcher-32: 045901c0
Fletcher-64: 00000459000001c0
Adler-32: 045d01c1
CRC-8: b9
CRC-16: f82e
CRC-32: d87f7e0c
`,
recipeConfig: [
{
"op": "Generate all hashes",
"args": ["All", true]
}
]
},
{
name: "Hashes with length 32",
input: "test",
expectedOutput: `MD2: dd34716876364a02d0195e2fb9ae2d1b
MD4: db346d691d7acc4dc2625db19f9e3f52
MD5: 098f6bcd4621d373cade4e832627b4f6
RIPEMD-128: f1abb5083c9ff8a9dbbca9cd2b11fead
BLAKE2b-128: 44a8995dd50b6657a037a7839304535b
BLAKE2s-128: e9ddd9926b9dcb382e09be39ba403d2c
LM Hash: 01FC5A6BE7BC6929AAD3B435B51404EE
NT Hash: 0CB6948805F797BF2A82807973B89537
`,
recipeConfig: [
{
"op": "Generate all hashes",
"args": ["128", true]
}
]
},
{
name: "Hashes without names",
input: "test",
expectedOutput: `93c8a7d0ff132f325138a82b2baa98c12a7c9ac982feb6c5b310a1ca713615bd
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80
9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658
d3b0aa9cd8b7255622cebc631e867d4093d6f6010191a53973c45fec9b07c774
fe0289110d07daeee9d9500e14c57787d9083f6ba10e6bcb256f86bb4fe7b981
928b20366943e2afd11ebc0eae2e53a93bf177a4fcf35bcc64d503704e65e202
f308fc02ce9172ad02a7d75800ecfc027109bc67987ea32aba9b8dcc7b10150e
12a50838191b5504f1e5f2fd078714cf6b592b9d29af99d0b10d8d02881c3857
ee67303696d205ddd2b2363e8e01b4b7199a80957d94d7678eaad3fc834c5a27
`,
recipeConfig: [
{
"op": "Generate all hashes",
"args": ["256", false]
}
]
}
]);

View File

@@ -46,6 +46,17 @@ TestRegister.addTests([
},
],
},
{
name: "JSON to CSV: boolean and null as values",
input: JSON.stringify({a: false, b: null, c: 3}),
expectedOutput: "a,b,c\r\nfalse,null,3\r\n",
recipeConfig: [
{
op: "JSON to CSV",
args: [",", "\\r\\n"]
},
],
},
{
name: "JSON to CSV: JSON as an array",
input: JSON.stringify([{a: 1, b: "2", c: 3}]),

View File

@@ -0,0 +1,45 @@
/**
* LS47 tests.
*
* @author n1073645 [n1073645@gmail.com]
*
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "LS47 Encrypt",
input: "thequickbrownfoxjumped",
expectedOutput: "(,t74ci78cp/8trx*yesu:alp1wqy",
recipeConfig: [
{
op: "LS47 Encrypt",
args: ["helloworld", 0, "test"],
},
],
},
{
name: "LS47 Decrypt",
input: "(,t74ci78cp/8trx*yesu:alp1wqy",
expectedOutput: "thequickbrownfoxjumped---test",
recipeConfig: [
{
op: "LS47 Decrypt",
args: ["helloworld", 0],
},
],
},
{
name: "LS47 Encrypt",
input: "thequickbrownfoxjumped",
expectedOutput: "Letter H is not included in LS47",
recipeConfig: [
{
op: "LS47 Encrypt",
args: ["Helloworld", 0, "test"],
},
],
}
]);

View File

@@ -0,0 +1,33 @@
/**
* LZString tests.
*
* @author crespyl [peter@crespyl.net]
* @copyright Peter Jacobs 2021
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "LZString Compress To Base64",
input: "hello world",
expectedOutput: "BYUwNmD2AEDukCcwBMg=",
recipeConfig: [
{
"op": "LZString Compress",
"args": ["Base64"]
}
],
},
{
name: "LZString Decompress From Base64",
input: "BYUwNmD2AEDukCcwBMg=",
expectedOutput: "hello world",
recipeConfig: [
{
"op": "LZString Decompress",
"args": ["Base64"]
}
],
}
]);

View File

@@ -0,0 +1,34 @@
/**
* NTLM test.
*
* @author brun0ne [brunonblok@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "NT Hash",
input: "QWERTYUIOPASDFGHJKLZXCVBNM1234567890!@#$%^&*()_+.,?/",
expectedOutput: "C5FA1C40E55734A8E528DBFE21766D23",
recipeConfig: [
{
op: "NT Hash",
args: [],
},
],
},
{
name: "LM Hash",
input: "QWERTYUIOPASDFGHJKLZXCVBNM1234567890!@#$%^&*()_+.,?/",
expectedOutput: "6D9DF16655336CA75A3C13DD18BA8156",
recipeConfig: [
{
op: "LM Hash",
args: [],
},
],
},
]);

View File

@@ -49,6 +49,18 @@ Point: 0x046c59592006272250a15070142a6be36d1e45464313f930d985a6e6f0eba3cd39d0367
}
]
},
{
name: "SSH Host Key: Ed25519",
input: "AAAAC3NzaC1lZDI1NTE5AAAAIBOF6r99IkvqGu1kwZrHHIqjpTB5w79bpv67B/Aw3+WJ",
expectedOutput: `Key type: ssh-ed25519
x: 0x1385eabf7d224bea1aed64c19ac71c8aa3a53079c3bf5ba6febb07f030dfe589`,
recipeConfig: [
{
op: "Parse SSH Host Key",
args: ["Base64"]
}
]
},
{
name: "SSH Host Key: Extract key",
input: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDiJZ/9W9Ix/Dk9b+K4E+RGCug1AtkGXaJ9vNIY0YHFHLpWsB8DAuh/cGEI9TLbL1gzR2wG+RJNQ2EAQVWe6ypkK63Jm4zw4re+vhEiszpnP889J0h5N9yzyTndesrl4d3cQtv861FcKDPxUJbRALdtl6gwOB7BCL8gsXJLLVLO4EesrbPXD454qpVt7CgJXEXByOFjcIm3XwkdOnXMPHHnMSD7EIN1SvQMD6PfIDrbDd6KQt5QXW/Rc/BsfX5cbUIV1QW5A/GbepXHHKmWRtLC2J/mH3hW2Zq/hITPEaJdG1CtIilQmJaZGXpfGIwFeb0Av9pSL926arZZ6vDi9ctF test@test",

View File

@@ -40,10 +40,10 @@ TestRegister.addTests([
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
]
],
"Banana": "You"
}, null, 4),
recipeConfig: [
{
@@ -72,10 +72,10 @@ TestRegister.addTests([
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
]
],
"Banana": "You"
},
"Unknown Fields": {
"4": 43,
@@ -111,10 +111,10 @@ TestRegister.addTests([
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
],
"Banana": "You",
"Date": 43,
"Elderberry": {
"Fig": "abc123",
@@ -154,10 +154,10 @@ TestRegister.addTests([
input: "0d1c0000001203596f751a024d65202b2a0a0a06616263313233120031ba32a96cc10200003801",
expectedOutput: JSON.stringify({
"Test": {
"Banana (string)": "You",
"Carrot (string)": [
"Me"
],
"Banana (string)": "You",
"Date (int32)": 43,
"Imbe (Options)": "Option1"
},

View File

@@ -212,4 +212,37 @@ TestRegister.addTests([
},
],
},
{
name: "ROT8000: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "ROT8000",
args: []
},
],
},
{
name: "ROT8000: normal",
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
expectedOutput: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
recipeConfig: [
{
op: "ROT8000",
args: []
},
],
},
{
name: "ROT8000: backward",
input: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.",
recipeConfig: [
{
op: "ROT8000",
args: []
},
],
},
]);

View File

@@ -0,0 +1,102 @@
/**
* Subsection Tests.
*
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Subsection: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
"op": "Subsection",
"args": ["", true, true, false],
},
],
},
{
name: "Subsection, Full Merge: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
"op": "Subsection",
"args": ["", true, true, false],
},
{
"op": "Merge",
"args": [true],
},
],
},
{
name: "Subsection, Partial Merge: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
"op": "Subsection",
"args": ["", true, true, false],
},
{
"op": "Merge",
"args": [false],
},
],
},
{
name: "Subsection, Full Merge: Base64 with Hex",
input: "SGVsbG38675629ybGQ=",
expectedOutput: "Hello World",
recipeConfig: [
{
"op": "Subsection",
"args": ["386756", true, true, false],
},
{
"op": "From Hex",
"args": ["Auto"],
},
{
"op": "Merge",
"args": [true],
},
{
"op": "From Base64",
"args": ["A-Za-z0-9+/=", true, false],
},
],
},
{
name: "Subsection, Partial Merge: Base64 with Hex surrounded by binary data.",
input: "000000000SGVsbG38675629ybGQ=0000000000",
expectedOutput: "000000000Hello World0000000000",
recipeConfig: [
{
"op": "Subsection",
"args": ["SGVsbG38675629ybGQ=", true, true, false],
},
{
"op": "Subsection",
"args": ["386756", true, true, false],
},
{
"op": "From Hex",
"args": ["Auto"],
},
{
"op": "Merge",
"args": [false],
},
{
"op": "From Base64",
"args": ["A-Za-z0-9+/=", true, false],
},
],
},
]);

View File

@@ -0,0 +1,55 @@
/**
* UnescapeString tests.
*
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "UnescapeString: escape sequences",
input: "\\a\\b\\f\\n\\r\\t\\v\\'\\\"",
expectedOutput: String.fromCharCode(0x07, 0x08, 0x0c, 0x0a, 0x0d, 0x09,
0x0b, 0x27, 0x22),
recipeConfig: [
{
op: "Unescape string",
args: [],
},
],
},
{
name: "UnescapeString: octals",
input: "\\0\\01\\012\\1\\12",
expectedOutput: String.fromCharCode(0, 1, 10, 1, 10),
recipeConfig: [
{
op: "Unescape string",
args: [],
},
],
},
{
name: "UnescapeString: hexadecimals",
input: "\\x00\\xAA\\xaa",
expectedOutput: String.fromCharCode(0, 170, 170),
recipeConfig: [
{
op: "Unescape string",
args: [],
},
],
},
{
name: "UnescapeString: unicode",
input: "\\u0061\\u{0062}",
expectedOutput: "ab",
recipeConfig: [
{
op: "Unescape string",
args: [],
},
],
},
]);

View File

@@ -8,6 +8,22 @@
*/
import TestRegister from "../../lib/TestRegister.mjs";
const CONSOLE_COMPILE_WARNING_RULE = `import "console"
rule a
{
strings:
$s=" "
condition:
$s and console.log("log rule a")
}
rule b
{
strings:
$s=" "
condition:
$s and console.hex("log rule b: int8(0)=", int8(0))
}`;
TestRegister.addTests([
{
name: "YARA Match: simple foobar",
@@ -20,5 +36,56 @@ TestRegister.addTests([
}
],
},
{
name: "YARA Match: hashing rules",
input: "Hello World!",
expectedOutput: "Input matches rule \"HelloWorldMD5\".\nInput matches rule \"HelloWorldSHA256\".\n",
recipeConfig: [
{
"op": "YARA Rules",
"args": [
`import "hash"
rule HelloWorldMD5 {
condition:
hash.md5(0,filesize) == "ed076287532e86365e841e92bfc50d8c"
}
rule HelloWorldSHA256 {
condition:
hash.sha256(0,filesize) == "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
}`,
true, true, true, true, false, false
],
}
],
},
{
name: "YARA Match: compile warnings",
input: "CyberChef Yara",
expectedOutput: "Warning on line 5: string \"$s\" may slow down scanning\n" +
"Warning on line 12: string \"$s\" may slow down scanning\n" +
"Input matches rule \"a\".\n" +
"Input matches rule \"b\".\n",
recipeConfig: [
{
"op": "YARA Rules",
"args": [CONSOLE_COMPILE_WARNING_RULE, false, false, false, false, true, false],
}
],
},
{
name: "YARA Match: console messages",
input: "CyberChef Yara",
expectedOutput: "log rule a\n" +
"log rule b: int8(0)=0x43\n" +
"Input matches rule \"a\".\n" +
"Input matches rule \"b\".\n",
recipeConfig: [
{
"op": "YARA Rules",
"args": [CONSOLE_COMPILE_WARNING_RULE, false, false, false, false, false, true],
}
],
},
]);

View File

@@ -109,7 +109,8 @@ module.exports = {
"buffer": require.resolve("buffer/"),
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify"),
"zlib": require.resolve("browserify-zlib")
"zlib": require.resolve("browserify-zlib"),
"process": false
}
},
module: {
@@ -164,19 +165,6 @@ module.exports = {
"postcss-loader",
]
},
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../"
}
},
"css-loader",
"sass-loader",
]
},
{
test: /\.(ico|eot|ttf|woff|woff2)$/,
type: "asset/resource",