Compare commits

...

1172 commits

Author SHA1 Message Date
a3957273
7c8be12d52
Merge pull request #1548 from brun0ne/add-php-serialization
Some checks failed
CodeQL Analysis / Analyze (push) Has been cancelled
Master Build, Test & Deploy / main (push) Has been cancelled
Add new operation: PHP Serialize
2025-04-05 19:06:23 +01:00
a3957273
e849569b10
Merge pull request #2013 from plvie/master
Add ECB/NoPadding and CBC/NoPadding support to AES encryption
2025-04-05 19:04:08 +01:00
Paul Vié
fa559fdbed split edit 2025-04-05 14:28:14 +02:00
a3957273
74d631c71e
Merge pull request #1991 from peterc-s/master
Some checks are pending
CodeQL Analysis / Analyze (push) Waiting to run
Master Build, Test & Deploy / main (push) Waiting to run
Add Base32 Hex Extended Alphabet and Base32 Tests.
2025-04-05 05:57:56 +01:00
a3957273
305a02c8a2
Merge pull request #1974 from PathToLife/feature/docker-multiplatform-build
Docker multiplatform build support
2025-04-05 05:42:01 +01:00
a3957273
5a3b7bc4c0
Merge pull request #2014 from 0xh3xa/master
Fix(RecipeWaiter): sanitize user input in addOperation to prevent XSS
2025-04-05 05:14:58 +01:00
heaprc
c83e1ac4fb Fix(RecipeWaiter): eslint format error 2025-04-05 00:42:37 +02:00
heaprc
857576dbe4 fix(RecipeWaiter): sanitize user input in addOperation to prevent XSS 2025-04-05 00:18:54 +02:00
Paul Vié
e00a636fc0 fix semicolon 2025-04-04 18:40:27 +02:00
Garab
6f4cbd8688
Merge branch 'gchq:master' into master 2025-04-04 18:32:40 +02:00
a3957273
848660f8e1
Merge pull request #2006 from 0xh3xa/master
Some checks failed
CodeQL Analysis / Analyze (push) Has been cancelled
Master Build, Test & Deploy / main (push) Has been cancelled
Bug Fix: selected theme not loading when refreshing
2025-04-03 19:15:02 +01:00
heaprc
0e7b1f7c78 resolve conflict in applyPreferredColorScheme method 2025-04-03 09:31:53 +02:00
0xh3xa
bbb211d819
Merge branch 'master' into master 2025-04-03 09:23:39 +02:00
0xh3xa
9ca0152aac
Merge branch 'master' into master 2025-04-03 09:22:38 +02:00
a3957273
4b72484ca4
Merge pull request #1993 from r4mos/master
Some checks are pending
CodeQL Analysis / Analyze (push) Waiting to run
Master Build, Test & Deploy / main (push) Waiting to run
Add CRC Operation
2025-04-03 08:22:11 +01:00
a3957273
e469f00fc7
Merge pull request #1286 from ccarpo/master
Added a JSON to YAML and a YAML to JSON operation
2025-04-03 08:19:20 +01:00
a3957273
75e3f35932
Merge pull request #1863 from JSCU-CNI/x509_fingerprints
Add fingerprints to the 'Parse X.509 certificate' operation
2025-04-03 08:18:04 +01:00
a3957273
9a8804ab94
Merge pull request #1604 from zhzy0077/jq
Support jq as an operation.
2025-04-03 08:15:35 +01:00
a3957273
f5b5227e53
Merge pull request #1909 from flakjacket95/master
Add SM2 Encrypt and Decrypt Operations
2025-04-03 08:14:23 +01:00
a3957273
14472d3b40
Merge pull request #2007 from 0xh3xa/bugfix/invalid-theme-option
Load the user's preferred color scheme if the URL contains an invalid theme
2025-04-03 08:00:39 +01:00
heaprc
9f30dd0e7a fix invalid theme error 2025-03-29 04:40:29 +01:00
0xh3xa
49d69a293b
Fix selected theme not loading when refreshing 2025-03-29 01:27:38 +01:00
Paul Vié
23de98f892 Add ECB/NoPadding and CBC/NoPadding Encryption 2025-03-26 11:46:47 +01:00
Dan Flack
8852712f0d
Merge branch 'master' into master 2025-03-16 00:44:31 -04:00
zhzy0077
b62def3d3e making it a seperate module. 2025-03-12 20:15:23 +08:00
zhzy0077
464c92e7bf Rename to "Jq" 2025-03-12 20:15:09 +08:00
zhzy0077
95044ab767 Making it depending on 0.5.1 version. 2025-03-12 20:15:00 +08:00
CCarpo
a809321b63 renamed function for clarity 2025-03-10 20:55:35 +01:00
Computer Network Investigation
b6f0f9b200
Merge branch 'master' into x509_fingerprints 2025-03-10 16:44:41 +01:00
PathToLife
a42c7de112
test buildah platforms flag environment variables 2025-03-10 18:00:49 +13:00
PathToLife
b85036b78f
Dockerfile manual architecture selection for multiplatform build. Disable NPM Publish for testing 2025-03-10 17:28:20 +13:00
PathToLife
3b75e13287
ci release error fix, apply detect chrome driver version npm install env var 2025-03-10 12:46:34 +13:00
CCarpo
98ef5d0110
Merge branch 'master' into master 2025-03-07 15:03:33 +01:00
ccarpo
2c21d72a6a Merge branch 'master' of https://github.com/ccarpo/CyberChef 2025-03-07 12:39:30 +01:00
r4mos
42efc0187c Fixed Test for non-working buttons 2025-03-04 08:46:41 +01:00
r4mos
d5f007deea Fixed non-working buttons 2025-03-04 08:43:16 +01:00
r4mos
566b423065 Correct forgotten test 2025-03-03 17:33:54 +01:00
r4mos
1b4760c447 Add Custom CRC 2025-03-03 17:15:26 +01:00
r4mos
3025391821 Browser test changed to adapt to new CRC operation 2025-03-03 09:19:01 +01:00
r4mos
4e62aa6e1d The CRC Operation is implemented natively with all currently known CRC's. Old Operations (CRC8, CRC16 and CRC32) and their dependencies are removed 2025-03-02 01:51:09 +01:00
r4mos
fcecd029c7 The CRC Operation is implemented natively with all currently known CRC's. Old Operations (CRC8, CRC16 and CRC32) and their dependencies are removed 2025-03-02 01:41:12 +01:00
peterc-s
3057a20791
Add Base32 Hex Extended option. 2025-02-28 16:52:15 +00:00
PathToLife
b2981d3cc7
Merge branch 'master' into feature/docker-multiplatform-build 2025-02-24 04:47:35 +00:00
a3957273
d3357d2acd
Merge pull request #1981 from bartblaze/master 2025-02-21 22:12:47 +00:00
bartblaze
7babef6f93 Preserve uppercase
This will preserve uppercase.
2025-02-17 17:35:22 +01:00
Brunon Blok
a40aed2b47
Merge branch 'master' into add-php-serialization 2025-02-17 14:09:03 +01:00
CCarpo
5cef2b13a3 fixed typo in categories. 2025-02-17 08:46:28 +01:00
CCarpo
c2936a6f2c removed old data format 2025-02-17 08:44:42 +01:00
CCarpo
06b7f0129f fixed linter issues. 2025-02-17 08:42:14 +01:00
CCarpo
e44e6fed35
Merge branch 'master' into master 2025-02-17 08:36:14 +01:00
Zhiyuan Zheng
a74e2e585e add lock. 2025-02-17 13:49:17 +08:00
Zhiyuan Zheng
d602897221 Merge branch 'master' into jq 2025-02-17 13:47:34 +08:00
a3957273
1b8c229df2
Merge pull request #1976 from evenstensberg/feat/cspell
chore(root): add cspell
2025-02-16 18:48:31 +00:00
a3957273
aa7bbc1a62
Merge pull request #1977 from depperm/CC-1889
CC-1889 add _ option
2025-02-16 18:37:00 +00:00
David Marshall
6ccbc892c7 CC-1889 2025-02-16 09:03:46 -05:00
Even Stensberg
7b3980a5e2
chore(root): add cspell 2025-02-16 13:53:36 +01:00
a3957273
7906f9d560
Merge pull request #630 from MShwed/feature/mime-rfc2047
Feature: MIME RFC2047 Decoding
2025-02-16 12:11:02 +00:00
mshwed
2ae923b73e Updated category and fixed imports 2025-02-15 23:03:05 -05:00
mshwed
15bbed093c fixed formatting 2025-02-15 22:23:49 -05:00
mshwed
23faeadea2 Fixed linting issues 2025-02-15 22:20:42 -05:00
mshwed
50c0d4bcd6 Added test case for ISO and ASCII 2025-02-15 22:20:42 -05:00
mshwed
7f97afd3e0 Added parsing of headers. 2025-02-15 22:20:41 -05:00
mshwed
c3994aa8e3 Added support for converting hex characters 2025-02-15 22:16:58 -05:00
mshwed
8166f981ae in progress 2025-02-15 22:16:58 -05:00
a3957273
1cfbc2babb
Merge pull request #1105 from linuxgemini/linuxgemini-patch-modhex
Introduce Yubico's Modhex for Conversion
2025-02-16 02:18:30 +00:00
a3957273
eb912547ac
Merge branch 'master' into linuxgemini-patch-modhex 2025-02-16 01:55:11 +00:00
a3957273
bcf62ec73d
Merge pull request #1903 from FranciscoPombal/rot13_numbers_negative_shift_amount
fix: ROT13 - shifting numbers by negative amounts
2025-02-16 01:47:09 +00:00
a3957273
004ef7f5dc
Merge pull request #1904 from FranciscoPombal/des_triple_des_error_message
fix: DES/Triple DES - misleading error messages
2025-02-16 01:43:36 +00:00
a3957273
9ab990ff59
Merge pull request #1921 from vs4vijay/theme-auto-detection
automatically theme mode based on user preference
2025-02-16 01:36:28 +00:00
a3957273
fb8e1be9f0
Merge pull request #1933 from k3ach/master
Updated luhn checksum operation to work with different bases
2025-02-16 01:30:37 +00:00
PathToLife
324560aeae
Merge branch 'gchq:master' into feature/docker-multiplatform-build 2025-02-16 00:54:09 +00:00
a3957273
95c6406d05
Merge pull request #1966 from exactlyaron/fix/generate-totp-issue-1964
Fix Generate TOTP & HOPT
2025-02-15 23:06:55 +00:00
a3957273
51b9fe644b
Merge pull request #1971 from bartblaze/master
Add Leet Speak
2025-02-15 22:55:52 +00:00
a3957273
fed10f3ee6
Merge pull request #1915 from Oshawk/take-nth-bytes
Add 'Take nth bytes' operation
2025-02-14 15:45:27 +00:00
a3957273
7cc3e5804b
Merge branch 'master' into take-nth-bytes 2025-02-14 15:44:12 +00:00
a3957273
dcf0bbb02b
Merge pull request #1914 from Oshawk/drop-nth-bytes
Add 'Drop nth bytes' operation
2025-02-14 15:43:41 +00:00
PathToLife
f8b613b4e7
Docker multiplatform build support. Pending CI workflow test 2025-02-13 20:57:45 +13:00
a3957273
e48fc4c8d8
Merge pull request #1902 from FranciscoPombal/blowfish_ecr_iv
fix: Blowfish - ignore IV length in ECB mode
2025-02-12 22:37:31 +00:00
a3957273
1b53b8d23f
Merge pull request #1780 from jb30795/master
IPv6 Transition Operation
2025-02-12 22:35:29 +00:00
a3957273
355566736a
Merge branch 'master' into blowfish_ecr_iv 2025-02-12 20:08:47 +00:00
a3957273
b99a76f9a6
Merge branch 'master' into master 2025-02-12 20:08:43 +00:00
a3957273
912bbe54aa
Merge branch 'master' into drop-nth-bytes 2025-02-12 20:08:30 +00:00
a3957273
26a16b6945
Merge branch 'master' into take-nth-bytes 2025-02-12 20:08:24 +00:00
a3957273
feaf3dd119
Merge branch 'master' into theme-auto-detection 2025-02-12 19:59:44 +00:00
a3957273
3187ff6322
Merge branch 'master' into master 2025-02-12 19:53:55 +00:00
a3957273
13f94a23f8
Merge pull request #1899 from c65722/strip_ipv4_header
Add Strip IPv4 header operation
2025-02-12 19:53:34 +00:00
a3957273
592e660deb
Merge pull request #1973 from gchq/bug/disable-loading-from-url
Disable flakey URL test
2025-02-12 19:53:24 +00:00
a3957273
3cdbdf4223
Merge branch 'master' into master 2025-02-12 19:51:20 +00:00
c65722
8cd875d06a
Merge branch 'master' into strip_ipv4_header 2025-02-11 10:11:18 +00:00
a3957273
bf36fe8143
Merge pull request #1866 from Adamkadaban/master
add offset field to 'Add Line Numbers' operation
2025-02-11 00:50:03 +00:00
a3957273
d3ee16f38b Disable flakey URL test 2025-02-11 00:49:14 +00:00
a3957273
41c5403700
Merge branch 'master' into master 2025-02-11 00:46:18 +00:00
a3957273
e1d3af26da
Merge pull request #1955 from max0x53/compress
Webpack compress with gzip and brotli
2025-02-11 00:43:36 +00:00
a3957273
5a7cb9e047
Merge branch 'master' into fix/generate-totp-issue-1964 2025-02-11 00:42:41 +00:00
a3957273
a41068e633
Merge branch 'master' into master 2025-02-11 00:40:26 +00:00
a3957273
bce04609a5
Merge branch 'master' into theme-auto-detection 2025-02-11 00:40:11 +00:00
a3957273
d4da81fa91
Merge branch 'master' into master 2025-02-11 00:39:40 +00:00
a3957273
d3e31890ae
Merge branch 'master' into strip_ipv4_header 2025-02-11 00:38:21 +00:00
a3957273
9d014aeaa5
Merge pull request #1898 from c65722/strip_tcp_header
Add Strip TCP header operation
2025-02-11 00:38:01 +00:00
a3957273
156de53dc1
Merge branch 'master' into strip_tcp_header 2025-02-11 00:27:38 +00:00
a3957273
9f2527d736
Merge branch 'master' into strip_ipv4_header 2025-02-11 00:27:19 +00:00
a3957273
7ecc235b31
Merge pull request #1900 from c65722/strip_udp_header
Add Strip UDP header operation
2025-02-11 00:26:59 +00:00
a3957273
51ed3b2fc1
Merge branch 'master' into strip_tcp_header 2025-02-11 00:26:52 +00:00
a3957273
306e29da76
Merge pull request #1972 from gchq/feature/detect-chromedriver
Automatically detect chrome driver version
2025-02-11 00:23:11 +00:00
a3957273
9cc84b1c62
Merge branch 'master' into feature/detect-chromedriver 2025-02-11 00:23:00 +00:00
a3957273
f02b3f22ad
Merge pull request #1936 from c65722/parse_tls_record
Add Parse TLS record operation
2025-02-11 00:22:12 +00:00
a3957273
e9b8163626
Merge pull request #1957 from RandomByte/jwt-sign/add-header-option
Add 'header' ingredient to JWT Sign operation
2025-02-11 00:13:56 +00:00
a3957273
20390ae08e
Merge pull request #1959 from simonarnell/patch-1
Corrected path to generateNodeIndex.mjs
2025-02-11 00:08:24 +00:00
a3957273
fcdcce7ee4
Merge pull request #1961 from GuilhermoReadonly/patch-1
Fix typo in description of JWT Sign recipe
2025-02-11 00:06:21 +00:00
a3957273
3d017d5f84 Add it to the correct file. 2025-02-11 00:02:39 +00:00
Alexander
5455061e15 Atomatically detect chrome driver version 2025-02-10 23:53:55 +00:00
a3957273
caa373c1be
Merge branch 'master' into master 2025-02-10 23:38:41 +00:00
a3957273
f4995dbc30
Merge pull request #1887 from robinsandhu/feature/parse-crl
Add operation for parsing X.509 CRLs
2025-02-10 23:35:58 +00:00
bartblaze
f14c423c64 Add Leet Speak
Not too many use cases, but something I thought of (and have seen in a few skiddie malware samples).

Will also resolve #1234
2025-02-05 18:34:59 +01:00
exactlyaron
6f63de81b1 style: fix linting 2025-01-23 11:46:01 +00:00
exactlyaron
75991321de tests: fix tests 2025-01-23 11:41:26 +00:00
exactlyaron
b560d74b8e tests: comment out Generate HOTP test 2025-01-23 11:28:24 +00:00
exactlyaron
90133e3f90 fix: refactor GenerateHOTP to use optauth 2025-01-23 11:28:13 +00:00
exactlyaron
672cb5dea4 fix: refactor GenerateTOTP to use optauth 2025-01-23 11:28:04 +00:00
exactlyaron
7eb9e08ad2 build(deps): use optauth instead of opt 2025-01-23 11:27:45 +00:00
exactlyaron
2007b26d57 build(deps): update otp 0.1.3 → 1.1.2 2025-01-23 00:25:59 +00:00
exactlyaron
e804555278 fix: refactor GenerateTOTP 2025-01-23 00:24:20 +00:00
Adamkadaban
6b75ba8903 fix bug where no input leads to error in console 2025-01-13 15:48:18 -05:00
Adam Hassan
54e559c5a6
Merge branch 'master' into master 2025-01-13 12:24:45 -05:00
Guilhem Radonde
cc7cc7f8fd
misc: typo 2025-01-10 09:32:41 +01:00
Simon Arnell
6a92f922cb
corrected path to generateNodeIndex.mjs 2025-01-09 12:32:57 +02:00
Merlin Beutlberger
71c8c8aac0 Add 'header' ingredient to JWT Sign operation
Expose the 'header' option of the jsonwebtoken module [1] as an ingredient.
This allows for adding and overwriting JWT header fields such as 'type' or 'kid'.

[1]: https://github.com/auth0/node-jsonwebtoken?tab=readme-ov-file#usage
2025-01-04 18:31:24 +01:00
Max S
304266020d Webpack compress with gzip and brotli 2024-12-28 17:20:15 +00:00
Vijay Soni
02f45e545d
Merge branch 'master' into theme-auto-detection 2024-12-27 13:41:39 +05:30
Robin Sandhu
3deb121043
Merge branch 'master' into feature/parse-crl 2024-12-01 16:04:01 +00:00
k3a.ch
bab0a7ffed fixed typo 2024-11-30 20:57:56 +01:00
c65722
1fcc365d9e
Add Parse TLS record operation 2024-11-02 16:58:19 +00:00
Pascal Burri
b92c1e7da0 fixed code format, added tests 2024-10-27 22:36:53 +01:00
k3ach
0c6c45b152
Merge branch 'gchq:master' into master 2024-10-26 15:50:30 +02:00
Pascal Burri
802c576c60 Updated luhn checksum to to work with base 2-36 2024-10-26 15:49:24 +02:00
n1474335
3822c6c520
10.19.4 2024-10-23 16:10:44 +01:00
n1474335
47c85a105d
Added message format arg to RSA Verify operation 2024-10-23 16:02:08 +01:00
n1474335
d3adfc7c3e
Updated chromedriver 2024-10-23 15:53:07 +01:00
n1474335
270a333179
10.19.3 2024-10-23 14:03:18 +01:00
n1474335
895a929925
Fixed RSA Sign and Verify character encodings 2024-10-23 14:03:09 +01:00
Vijay Soni
e484d426fe automatically theme mode based on user preference
Related to #1901

Implemented automatic dark theme change based on user preference using the `prefers-color-scheme` media query.
2024-10-07 01:28:46 +05:30
Oshawk
4c6dcf182d Merge remote-tracking branch 'upstream/master' into take-nth-bytes 2024-09-25 18:57:20 +01:00
Oshawk
4bb1e335ea Merge remote-tracking branch 'upstream/master' into drop-nth-bytes 2024-09-25 18:14:57 +01:00
Dan Flack
ae9054dc37 Remove highlighting and correct one module mismatch 2024-09-22 18:58:36 +02:00
Dan Flack
f61bdf06c6 Additional linter corrections 2024-09-21 12:00:37 +02:00
Dan Flack
0f16fa0ce1 Updates for linter 2024-09-21 11:47:01 +02:00
flackjacket95
84ce8e6f30 Add tests 2024-09-21 11:40:57 +02:00
Dan Flack
9eff9e5018 Set default paramater indices 2024-09-21 11:40:32 +02:00
Dan Flack
857d3b6d17 Fully functional encrypt/decrypt 2024-09-21 11:40:32 +02:00
Dan Flack
54cfb17145 Initial migration to library; add decryption operation 2024-09-21 11:40:32 +02:00
Dan Flack
99ba6b487c Add comments, docs, and some additional restructuring 2024-09-21 11:40:32 +02:00
flakjacket
a1647b02cb Initial SM2 changes 2024-09-21 11:40:12 +02:00
jb30795
b15322467b
Merge branch 'master' into master 2024-09-20 10:59:28 +01:00
jb30795
9229fe9ac7 Remove console.log statement 2024-09-20 10:49:13 +01:00
jb30795
488c458720 updates to operation and addition of more tests 2024-09-20 10:46:09 +01:00
Francisco Pombal
784b2631a8 fix: DES/Triple DES - failing tests 2024-09-16 15:44:28 +01:00
Francisco Pombal
3eb1af0278 fix: DES/Triple DES - misleading error messages
Fixes https://github.com/gchq/CyberChef/issues/1843.
2024-09-16 15:36:57 +01:00
Francisco Pombal
7e5eb01a5e fix: ROT13 - shifting numbers by negative amounts
Fixes https://github.com/gchq/CyberChef/issues/1886.
2024-09-15 23:51:48 +01:00
Francisco Pombal
1fce8e5112 fix: Blowfish - ignore IV length in ECB mode
Fixes https://github.com/gchq/CyberChef/issues/1895.
2024-09-15 22:21:10 +01:00
c65722
748379f0b0
Add Strip TCP header operation 2024-09-15 18:49:17 +01:00
c65722
da74d9b22d
Add Strip UDP header operation 2024-09-15 18:14:21 +01:00
c65722
738e6feda0
Add Strip IPv4 header operation 2024-09-15 17:46:47 +01:00
Robin Sandhu
1fde2fba29
Add basic tests for Parse X.509 CRL operations 2024-08-25 14:28:55 +01:00
Robin Sandhu
a50d4d63eb Format issuerAltName CRL extension 2024-08-25 14:15:00 +01:00
Robin Sandhu
dbc90090cf
Add support for multiple input format
i.e. DER Hex, Base64, Raw
2024-08-25 05:47:29 +01:00
Robin Sandhu
e65869a10b
Add operation for parsing X.509 CRLs
Signed-off-by: Robin Sandhu <er.robinsandhu@gmail.com>
2024-08-25 05:02:59 +01:00
Computer Network Investigation
7877a0d7d0
Merge branch 'master' into x509_fingerprints 2024-08-15 18:03:58 +02:00
n1474335
d635cca210
10.19.2 2024-08-14 15:35:17 +01:00
n1474335
0e82e4b7c6
Updated chromedriver 2024-08-14 15:35:12 +01:00
n1474335
5f88ae44ec
10.19.1 2024-08-14 15:22:06 +01:00
n1474335
7a5225c961
Fixed JA4 version fallback value 2024-08-14 15:21:57 +01:00
jb30795
a80b1568ac Lint errors 2024-08-09 14:32:31 +01:00
jb30795
a616e46b50 Handling of /24 ranges 2024-08-09 14:28:50 +01:00
jb30795
752ce789c2 Updating tests 2024-08-07 21:19:13 +01:00
jb30795
660069865a Updating description 2024-08-07 21:02:00 +01:00
jb30795
9169254fff minor wording update 2024-08-07 19:13:44 +01:00
jb30795
e12b00485e Merge branch 'master' of ssh://github.com/jb30795/CyberChef-IPv6-Transition 2024-08-07 18:50:13 +01:00
jb30795
51a07a27db Formatting updates 2024-08-07 18:49:58 +01:00
jb30795
c8c9e572a6
Merge branch 'master' into master 2024-08-07 18:42:08 +01:00
jb30795
7fb4824cd6 Merge branch 'master' of ssh://github.com/jb30795/CyberChef-IPv6-Transition 2024-08-07 18:39:08 +01:00
jb30795
5e763b86dc Option to remove headers and ignore blank input rows 2024-08-07 18:17:00 +01:00
jb30795
b090ce0428 Update to accept multiple inputs 2024-08-07 17:06:15 +01:00
Adamkadaban
3dddb516c9 add offset field to 'Add Line Numbers' operation 2024-07-27 20:06:18 -07:00
JSCU-CNI
fb3c36af85 Add fingerprints to 'Parse X.509 certificate' operation 2024-07-24 14:23:40 +02:00
n1474335
a477f47aec
Merge branch 'master' of github.com:gchq/CyberChef 2024-06-21 14:14:59 +01:00
n1474335
965570d250
10.18.9 2024-06-21 14:12:36 +01:00
n1474335
ab37c1e562
Fixed Optical Character Recognition and added tests 2024-06-21 14:12:28 +01:00
a3957273
40fda00db4 Bump to 10.19.0 2024-06-21 08:09:53 +00:00
a3957273
d5374454f4
Merge pull request #1828 from robinsandhu/feat/support-other-keys-in-parse-csr 2024-06-21 09:00:12 +01:00
İlteriş Yağıztegin Eroğlu
edd22372d8 feat(Modhex): Introduce basic Modhex conversion
Signed-off-by: İlteriş Yağıztegin Eroğlu <ilteris@asenkron.com.tr>
2024-06-17 23:58:58 +00:00
a3957273
4c5577ddeb
Merge pull request #1834 from eltociear/patch-1 2024-06-18 00:35:50 +01:00
Ikko Eltociear Ashimine
534ab23d9b
chore: update SIGABA.mjs
intial -> initial
2024-06-14 00:38:25 +09:00
Robin Sandhu
fe9f4fa7a9
Fix linting errors 2024-06-12 19:00:35 +01:00
Robin Sandhu
a8b1050d75
Merge branch 'master' into feat/support-other-keys-in-parse-csr 2024-06-12 18:57:04 +01:00
Robin Sandhu
e80d3d59bc
Refactor code 2024-06-12 18:54:04 +01:00
a3957273
1efbd9dfd1
Merge pull request #1200 from AlfredBerg/master 2024-06-12 00:01:11 +01:00
a3957273
6c30c9c6b8
Merge branch 'master' into master 2024-06-11 23:49:11 +01:00
a3957273
4528a1bdb6
Merge branch 'master' into feat/support-other-keys-in-parse-csr 2024-06-11 22:51:32 +01:00
n1474335
c23a8de5a0
Merge branch 'master' of github.com:gchq/CyberChef 2024-06-11 18:07:33 +01:00
n1474335
0cd4d41cdc
10.18.8 2024-06-11 18:07:28 +01:00
n1474335
2b275f0897
Updated eslint, Jimp, and other dependencies 2024-06-11 18:07:22 +01:00
a3957273
63913f4d45
Merge pull request #1829 from piguagua/master 2024-06-11 11:26:42 +01:00
piguagua
b6c95492f1 chore: remove repeat words
Signed-off-by: piguagua <piguagua@aliyun.com>
2024-06-10 17:36:17 +08:00
Robin Sandhu
ae03e34489
Add support for ECDSA and DSA keys to Parse CSR operation 2024-06-09 01:00:20 +01:00
n1474335
7eb887ca51
10.18.7 2024-06-06 17:08:58 +01:00
n1474335
74d0166682
Fixed GOST sBox arg bug 2024-06-06 17:08:37 +01:00
n1474335
18159ce806
10.18.6 2024-05-16 18:09:22 +01:00
n1474335
86d59783fa
Improved GOST algorithm naming and block size selection 2024-05-16 18:09:12 +01:00
n1474335
fb818c3149
10.18.5 2024-05-16 14:29:46 +01:00
n1474335
37398188f9
Improved testing to account for race conditions 2024-05-16 14:29:32 +01:00
n1474335
d1a0da3f8d
10.18.4 2024-05-13 17:48:41 +01:00
n1474335
57c8c6dbc6
Added operation counts to categories and ops list with option to hide by default for categories. 2024-05-13 17:48:09 +01:00
n1474335
bbebba6481
Added pause after setting complex input to avoid race conditions 2024-04-25 18:10:59 +01:00
n1474335
f0a49fefa4
Extended time for autoBake to trigger in a test 2024-04-25 17:51:31 +01:00
n1474335
48f3bf9ea7
10.18.3 2024-04-24 18:09:21 +01:00
n1474335
b7a7eebc78
More test tweaks 2024-04-24 18:09:15 +01:00
n1474335
2e76e44a5a
Tweaked UI test 2024-04-24 17:40:16 +01:00
n1474335
718ce9ea11
10.18.2 2024-04-24 17:13:57 +01:00
n1474335
a79be1e3ef
Removed autoBakePause flag and statechange trigger in InputWaiter.set() as they are redundant. 2024-04-24 17:13:44 +01:00
n1474335
0a709acafe
Merge branch 'zb3-fix-testui-race-condition' 2024-04-24 16:43:38 +01:00
n1474335
29efd77eaf
Merge branch 'fix-testui-race-condition' of https://github.com/zb3/CyberChef into zb3-fix-testui-race-condition 2024-04-24 16:35:12 +01:00
n1474335
2d6ac8023e
10.18.1 2024-04-24 13:27:07 +01:00
n1474335
2f42f515b0
Updated chromedriver 2024-04-24 13:26:57 +01:00
n1474335
f304f0832b
10.18.0 2024-04-24 13:11:20 +01:00
n1474335
801f3a578d
Updated CHANGELOG 2024-04-24 13:11:16 +01:00
n1474335
0a353eeb37
Improved XXTEA operations. Added XXTEA Decrypt. 2024-04-24 13:09:17 +01:00
n1474335
2e2490ce47
10.17.1 2024-04-23 18:29:43 +01:00
n1474335
361a35b44c
Removed trailing spaces from RAKE 2024-04-23 18:29:04 +01:00
n1474335
e61d64f618
Wording and stats improvements 2024-04-23 18:28:08 +01:00
a3957273
42ad9a49f3
Merge pull request #1786 from zb3/fix-overwritten-output 2024-04-15 01:17:49 +01:00
a3957273
7538be68c5
Merge pull request #1275 from cplussharp/ec-asn1 2024-04-15 01:15:36 +01:00
CPlusSharp
21ac516248 ECDSA JSON Web Signature format
used e.g. by JWT
2024-04-14 17:18:06 +02:00
CPlusSharp
7e7195c291 ECDSA: Output keys as JSONWebKeySet instead of two JWK 2024-04-14 16:53:09 +02:00
CPlusSharp
1fbc7e03f0 make the ECDSA JSON signature parsing more robust
also rename the format to "Raw JSON"
as I will later introduce "JSON Web Signature"
2024-04-14 16:46:55 +02:00
CPlusSharp
7b54d9e873 ECDSA rename signature format "Concat HEX" to "P1363 HEX"
this format name is more specific and easier to search for on the internet
2024-04-14 15:20:41 +02:00
a3957273
8ab2256b88 v10.17.0 2024-04-13 22:15:03 +00:00
a3957273
6e8c759dde
Merge pull request #1788 from EvieHarv/master 2024-04-13 22:24:10 +01:00
a3957273
a429902d41
Merge pull request #1751 from sw5678/master 2024-04-13 22:20:53 +01:00
a3957273
f6c5a04088
Merge branch 'master' into master 2024-04-13 22:04:53 +01:00
a3957273
edc23a860d
Merge pull request #1642 from cplussharp/pubkey-from-cert 2024-04-13 21:24:27 +01:00
a3957273
67195f65e7
Merge pull request #1277 from cplussharp/jwk 2024-04-13 20:54:38 +01:00
a3957273
4619a511d4
Merge pull request #541 from TheZ3ro/hide-recipe-options 2024-04-13 20:22:31 +01:00
CPlusSharp
cbf990fab9 JWK conversion from/to PEM 2024-04-13 13:30:46 +02:00
CPlusSharp
8f182e4a9b Sign/Verify Operations for ECDSA
also an Operation for ECDSA signature conversion,
as there could be multiple formats of the signature
2024-04-13 12:57:14 +02:00
CPlusSharp
7a2c9ddbc4 Operation: Generate ECDSA Key Pair 2024-04-13 12:55:21 +02:00
CPlusSharp
28e2a391b8 Public Key from Private Key 2024-04-13 12:39:58 +02:00
CPlusSharp
f86817bc86 Public Key from Certificate 2024-04-13 12:38:14 +02:00
n1474335
cc28c6af1a
10.16.0 2024-04-12 14:55:21 +01:00
n1474335
d21a6c8598
Updated CHANGELOG 2024-04-12 14:55:13 +01:00
n1474335
7b2d572902
Added 'JA4Server Fingerprint' operation 2024-04-12 14:41:00 +01:00
sw5678
0cfb67bd06 Improved readability and efficiency of RAKE 2024-04-12 11:27:29 +01:00
sw5678
f606d4b25f
Merge branch 'gchq:master' into master 2024-04-12 10:43:52 +01:00
sw5678
2191d20fb5 Removed trailing whitespace 2024-04-12 10:40:33 +01:00
a3957273
d13218caaf
Merge pull request #1739 from e218736/options-dialog-keyboard-navigation 2024-04-11 15:24:57 +01:00
Ethan Harvey
00f7914c5c Fix affine encode testcase 2024-04-10 23:57:53 +00:00
Ethan Harvey
a09f8451fd Require (a, 26) to be coprime in affine encode 2024-04-10 23:19:50 +00:00
TheZ3ro
670c370b90
Merge branch 'master' into hide-recipe-options 2024-04-09 09:22:03 +02:00
a3957273
b2e400f474
Merge pull request #1743 from e218736/button-aria-labels 2024-04-09 00:44:48 +01:00
jb30795
66d3b6e9ed
Merge branch 'master' into master 2024-04-08 11:06:45 +01:00
a3957273
8c283c7b19
Merge pull request #1783 from zb3/fix-expectOutput 2024-04-07 21:59:30 +01:00
zb3
db331e94ee fix ui test code style 2024-04-07 01:20:11 +02:00
zb3
2e284d3842 Fix autobake ui test 2024-04-07 00:37:09 +02:00
zb3
a81b2064d4 Abort the previous bake when attempting the next autobake 2024-04-07 00:23:17 +02:00
zb3
a23e47d8f9
Merge branch 'master' into fix-expectOutput 2024-04-06 13:35:28 +02:00
zb3
e3033173d7 Merge branch 'master' into fix-testui-race-condition 2024-04-06 13:33:59 +02:00
TheZ3ro
1fbf6c94cd
Merge branch 'master' into hide-recipe-options 2024-04-06 11:48:59 +02:00
thez3ro
bf9066ae2e fix: make the linter happy 2024-04-06 09:30:52 +00:00
n1474335
33a473c09b
10.15.1 2024-04-05 18:12:26 +01:00
n1474335
409e795ce9
Moved UUID regex in list 2024-04-05 18:12:06 +01:00
n1474335
6ca60cb013
Improvements to HEIF file signature and GIF file extractor 2024-04-05 18:11:51 +01:00
n1474335
ef52195167
Fixed and improved some infoURLs 2024-04-05 18:10:57 +01:00
n1474335
ed930d2364
Moved ops to different modules 2024-04-05 18:10:14 +01:00
n1474335
1b870e559e
Updated copyright declarations to a range up to the latest commit 2024-04-05 18:09:07 +01:00
n1474335
d3fb8bd6e9
Fixed typos 2024-04-05 18:08:21 +01:00
zb3
1adc2ff930 Make loadURIParams set input non-silently
Silent input changes might be overwritten due to the debounce logic present inside inputChange.
2024-04-05 18:52:50 +02:00
zb3
fc40580dce Avoid calling inputChange when setting encoding inside loadURIParams
Otherwise the debounce logic sometimes causes the input to be overriden by the previous value.
2024-04-05 18:48:45 +02:00
zb3
4652608297 Fix character encoding io test
Since the output encoding autodetection was introduced, this test was no longer correct.
That wasn't detected because of the expectOutput bug.
2024-04-05 17:14:05 +02:00
zb3
0f0efefbf7 Make expectOutput actually check the output 2024-04-05 17:13:05 +02:00
n1474335
ab0493f53a
Update CHANGELOG 2024-04-05 15:56:31 +01:00
TheZ3ro
a1892d4411
Merge branch 'master' into hide-recipe-options 2024-04-05 13:23:28 +02:00
jb30795
036f80d734 indentation 2024-04-04 17:00:14 +01:00
jb30795
3ca4c2fd45 Initial commit for new IPv6 Transition operation 2024-04-04 15:54:43 +01:00
a3957273
016825d4de
Update CHANGELOG.md 2024-04-02 22:27:15 +01:00
a3957273
c35557aea5 Merge branch 'master' of https://github.com/gchq/CyberChef 2024-04-02 20:40:19 +00:00
a3957273
b5959c6f01 10.15.0 2024-04-02 20:40:09 +00:00
a3957273
2000938040
Merge pull request #1732 from tomgond/date-delta 2024-04-02 21:38:18 +01:00
a3957273
c795271502 Change output to 'html' 2024-04-02 20:27:48 +00:00
a3957273
1d4c810554
Merge pull request #512 from MShwed/feature/extract-hashes 2024-04-02 21:22:51 +01:00
a3957273
ccd3839a9b
Merge pull request #1504 from jkataja/parse-csr 2024-04-02 21:17:51 +01:00
Janne Kataja
fda77cf37a add option to show Parse CSR only supports RSA 2024-04-02 21:30:59 +02:00
a3957273
dc8c185c39
Merge pull request #1769 from gchq/revert-1753-jsonwebtoken-vuln 2024-04-02 18:10:01 +01:00
a3957273
99efcb521d
Revert "Updated jsonwebtoken dependency to 9+" 2024-04-02 18:09:48 +01:00
Matt Shwed
d2bd397e8c
Merge branch 'master' into feature/extract-hashes 2024-04-02 09:13:16 -04:00
a3957273
944810614a
Merge pull request #1767 from zb3/fix-evpkey 2024-04-02 10:59:05 +01:00
Matt Shwed
21e5641196
Merge branch 'master' into feature/extract-hashes 2024-04-01 22:30:46 -04:00
mshwed
077b11e33b Fixed op name in test 2024-04-01 22:30:18 -04:00
mshwed
8d4ad6ae75 Minor changes. Added test cases. 2024-04-01 22:22:43 -04:00
zb3
ab47b3557f Fix CryptoJS argument passing in DeriveEVPKey
CryptoJS treats strings as Utf8, so for binary strings, Latin1 needs to be used.
2024-04-01 23:04:00 +02:00
Janne Kataja
c5e5ed2b4d add Certificate Signing Request (CSR) parse action 2024-04-01 22:41:21 +02:00
tomgond
dd2cfe8bac
Merge branch 'master' into date-delta 2024-04-01 23:32:13 +03:00
a3957273
8a17abae45
Merge pull request #1765 from zb3/fix-ciphersaber2 2024-04-01 18:05:32 +01:00
tomgond
dfedfa9f4c
Fix test to fit new time-delta format 2024-04-01 19:42:56 +03:00
tomgond
56f92afbf4
Change time-delta argument to be per time unit
Day, hour, minute, second. Instead of a single string.
2024-04-01 19:41:44 +03:00
zb3
52709f0ecb Fix Ciphersaber2 key concatenation
The concat method does not handle typed arrays as arguments.
2024-04-01 18:40:00 +02:00
a3957273
df140b5098
Merge pull request #1764 from gchq/bug/disable-extract-tests 2024-04-01 17:11:19 +01:00
a3957273
6b95ba7dd6 Fix regular expresion crash in extract hashes 2024-04-01 16:10:42 +00:00
a3957273
61295a968e Lower case 'hash' 2024-04-01 16:01:48 +00:00
a3957273
0717407bea Disable 'Extract ID3' Nightwatch tests 2024-04-01 15:59:49 +00:00
a3957273
c46660a0d9
Merge pull request #1763 from zb3/fix-base58 2024-04-01 16:55:45 +01:00
zb3
4c6200f233 Fix Base58 handling of strings with only null characters 2024-04-01 17:31:36 +02:00
mshwed
3983e1a8e2 Updated imports 2024-03-31 10:57:03 -04:00
mshwed
a6b774da81 Fixed issues with const/let and changed default character length 2024-03-31 10:44:40 -04:00
mshwed
de8ed6962d Improved description of operation 2024-03-31 10:44:40 -04:00
mshwed
98edef389c Corrected module type 2024-03-31 10:44:40 -04:00
mshwed
1b16c26699 Operation: Added extract hash feature 2024-03-31 10:44:36 -04:00
a3957273
866c9a94ae 10.14.0 2024-03-31 02:24:39 +00:00
a3957273
6677317e27 update x86 disassembly tests 2024-03-31 01:21:17 +00:00
a3957273
5c563c2bdf
Merge pull request #1361 from devcydo/xxtea_encryption 2024-03-31 00:45:36 +00:00
a3957273
8647b50cca
Merge pull request #933 from cbeuw/blowfish-keyfix 2024-03-31 00:39:33 +00:00
a3957273
21dc5d9de0
Merge pull request #1197 from evanreichard/disassembler_update 2024-03-31 00:37:50 +00:00
a3957273
e258e5a783
Merge pull request #1606 from joostrijneveld/fix/chacha-raw 2024-03-30 19:08:18 +00:00
a3957273
75a28b558e
Merge pull request #1762 from gchq/feature/floats 2024-03-30 18:34:07 +00:00
a3957273
6efa2ddfa4 Merge branch 'master' into tcode2k16/master 2024-03-30 17:05:33 +00:00
a3957273
b88fbcc960 Merge branch 'master' of https://github.com/gchq/CyberChef 2024-03-30 14:34:19 +00:00
a3957273
7ccf8cbacd 10.13.0 2024-03-30 14:34:12 +00:00
a3957273
a1f6960d4e
Merge pull request #1761 from gchq/origin/add_fangurl 2024-03-30 14:31:45 +00:00
a3957273
2784978eb5 Fix slash regular expression bug 2024-03-30 14:20:28 +00:00
a3957273
b4133a0afd Merge branch 'master' into addfangurl-master 2024-03-30 14:16:01 +00:00
tomgond
d59ebdd0dc
Merge branch 'master' into date-delta 2024-03-29 12:47:42 +03:00
Joost Rijneveld
3b5225a94f
Merge branch 'master' into fix/chacha-raw 2024-03-29 05:52:06 +01:00
a3957273
acce7ca717 Bump package version 2024-03-29 02:36:56 +00:00
a3957273
d29dbe78d3 Merge branch 'master' of https://github.com/gchq/CyberChef 2024-03-29 02:35:04 +00:00
a3957273
4fdea84534 10.12.0 2024-03-29 02:34:49 +00:00
a3957273
0f14d23599
Merge pull request #1750 from joostrijneveld/feature/salsa20 2024-03-29 02:33:20 +00:00
a3957273
877c83eae7 Fix changelog links 2024-03-29 02:03:21 +00:00
a3957273
27b7e3c4d6 Release v10.11.0 2024-03-29 02:02:00 +00:00
a3957273
77b7d7ee0b
Merge pull request #1752 from chriswhite199/xmldom-upgrade 2024-03-29 00:58:04 +00:00
a3957273
6edf731d46
Merge pull request #1753 from chriswhite199/jsonwebtoken-vuln 2024-03-29 00:56:17 +00:00
n1474335
6fd00e2598
Merge branch 'master' of github.com:gchq/CyberChef 2024-03-27 18:32:05 +00:00
n1474335
862cfdf0ae
10.10.0 2024-03-27 18:29:13 +00:00
n1474335
943d01c208
Updated CHANGELOG 2024-03-27 18:28:41 +00:00
n1474335
ef59634c15
Added 'JA4 Fingerprint' operation 2024-03-27 18:02:17 +00:00
a3957273
674c8c7c87
Merge pull request #1757 from simonw/heic-heif 2024-03-27 11:24:48 +00:00
Simon Willison
953861ab30 File signatures for heic/heif, refs #1613 2024-03-26 16:26:17 -07:00
n1474335
0026d77b7b
More test tweaking 2024-03-26 16:34:36 +00:00
n1474335
ee77e0a1e4
More test tweaking 2024-03-26 16:10:44 +00:00
n1474335
f1dcc339b3
More test tweaking 2024-03-26 15:42:21 +00:00
n1474335
1f316a2f32
More test tweaking 2024-03-26 15:37:18 +00:00
n1474335
a5f9a8726b
Fixed erroring test 2024-03-26 15:19:35 +00:00
n1474335
64111b8b7b
Downgrade chromedriver version for GitHub Actions 2024-03-26 14:57:58 +00:00
n1474335
762cf3ca41
10.9.0 2024-03-26 14:40:39 +00:00
n1474335
70ff3a52ca
Updated CHANGELOG 2024-03-26 14:40:33 +00:00
n1474335
e4077fb63b
Lint and dependency update 2024-03-26 14:38:27 +00:00
n1474335
65ffd8d65d
Automatically detect UTF8 character encoding in output 2024-03-26 13:44:59 +00:00
n1474335
16dfb3fac6
Automatically detect EOL from paste events and output setting 2024-03-26 13:44:58 +00:00
Chris White
ef5ff5bec6 Updated jsonwebtoken dependency to 9+
updated JWTSign operation for backwards compatibility with insecure keys and invalid asym key types
2024-03-13 10:26:23 -07:00
Chris White
e1c73a64ad Updated xmldom package to new namespace for vuln remediation 2024-03-13 09:51:22 -07:00
sw5678
81e1abd682 Improving efficency of RAKE 2024-03-11 16:57:28 +00:00
Joost Rijneveld
9068b6c17a Add Salsa20 and XSalsa20 operation 2024-03-10 17:05:19 +01:00
Joost Rijneveld
5992ba12f1
Merge branch 'master' into fix/chacha-raw 2024-03-08 16:06:31 +01:00
e218736
bf833a39fc favourites button aria label 2024-02-29 14:32:47 +00:00
e218736
fccc3584d8 aria labels/aria hidden to input/output buttons 2024-02-29 12:11:41 +00:00
e218736
963e2839ce add css styling on focus 2024-02-27 14:41:07 +00:00
tomgond
e85acee509
Update DateTimeDelta.mjs
Another commit for re-build
2024-02-23 07:09:04 +02:00
tomgond
4e9567f539
Update DateTimeDelta.mjs
Some change to re-run tests.
2024-02-22 21:49:24 +02:00
tomgond
a9c00a5856
Merge branch 'master' into date-delta 2024-02-22 18:33:30 +02:00
a3957273
c4e7c41a6e
Merge pull request #501 from kassi/fernet
Add Fernet encryption/decryption operation
2024-02-22 01:15:24 +00:00
a3957273
210186e754 Fix tests 2024-02-22 01:00:11 +00:00
a3957273
b4c14219b6 Fix encrypt 2024-02-22 00:42:30 +00:00
a3957273
299a3c48a1 Update imports from Fernet module 2024-02-22 00:26:32 +00:00
a3957273
cd0aee7626 Remove deprecated code 2024-02-22 00:22:19 +00:00
a3957273
bc82f590d4 Merge branch 'master' into fernet 2024-02-22 00:20:40 +00:00
a3957273
bebb216df2 Bump CyberChef to v10.8.2 2024-02-21 21:14:23 +00:00
tomgond
6331c20306
Add code for DateTime Delta to calculate operation 2024-02-21 19:58:13 +02:00
tomgond
4dc4c7edd2
Update Categories.json
Add DateTime Delta to categories
2024-02-21 19:56:42 +02:00
tomgond
d2ff03cea4
Update DateTime.mjs
Add test for time-delta
2024-02-21 19:55:09 +02:00
a3957273
61d587a4a5
Merge pull request #1704 from mattnotmitt/add-dev-container
Add devcontainer configuration and .gitattributes
2024-02-18 03:53:43 +00:00
Matt C
85da5f83b5 Add gh-cli, add extensions, node_modules as a volume 2024-02-17 10:06:19 +00:00
Andrew
6c0c53d00f Add dev container config file 2024-02-17 10:06:19 +00:00
a3957273
196bce04cc
Merge pull request #1715 from sw5678/RAKE
Rake
2024-02-16 00:35:33 +00:00
a3957273
ba82941cef
Merge pull request #1719 from GoForceX/master
Fix JSON folder folding in Firefox
2024-02-15 01:01:18 +00:00
GoForceX
63449872da
Fix JSON folder folding in Firefox 2024-02-14 11:09:14 +00:00
a3957273
14ee3f0f4b
Merge pull request #1695 from Kalkran/master
Add Caret/M-decode Operation
2024-02-13 13:51:48 +00:00
sw5678
774828823c Adding RAKE test import back after merge conflict 2024-02-13 11:52:19 +00:00
sw5678
9e73e2555b Merging master into branch 2024-02-13 11:50:28 +00:00
Ted Kruijff
dc68b7d9bf
add to tests, fix test, fix a comma 2024-02-13 10:22:54 +01:00
a3957273
7a38504015
Merge branch 'master' into master 2024-02-13 01:37:53 +00:00
a3957273
26fa5f3d1d
Merge pull request #1623 from jlaundry/master
change Diff to output <ins>, <del>
2024-02-13 01:04:25 +00:00
a3957273
112d52cb99 Remove specified permissions 2024-02-13 00:42:41 +00:00
a3957273
47f1f4c549 Bump to 10.8.0 2024-02-13 00:18:08 +00:00
a3957273
4b9d5a7685
Merge pull request #1699 from AshCorr/ash/Containers!
Bundle CyberChef into a container and publish to GCHR
2024-02-13 00:12:18 +00:00
a3957273
fc7c6312e6
Merge pull request #1714 from sw5678/master
Adding and removing tests
2024-02-12 23:54:52 +00:00
sw5678
8b5b17b8e0
Merge branch 'gchq:master' into RAKE 2024-02-12 17:06:10 +00:00
sw5678
c7377da37f Adding and removing tests 2024-02-12 16:52:43 +00:00
sw5678
7cfb5e0b2a Added RAKE functionality into CC 2024-02-12 14:52:46 +00:00
Ashleigh Carr
62dfa8f9dd Point to the correct workflow in the README for Container releases. 2024-02-12 10:46:28 +00:00
Ashleigh Carr
7582abfa27 Fix PR workflow, Buildah requires atleast an image name if no tags specified 2024-02-12 10:46:28 +00:00
Ashleigh Carr
3f89a94df2 Remove image property from Container build & push actions 2024-02-12 10:46:28 +00:00
Ashleigh Carr
c5e880628a Fix CI using Containerfile 2024-02-12 10:46:28 +00:00
Ashleigh Carr
abd9024097 Add a .dockerignore file 2024-02-12 10:46:28 +00:00
Ashleigh Carr
314b925ec9 Add a comment to the README about using Docker 2024-02-12 10:46:28 +00:00
Ashleigh Carr
d700d1d459 Switch to using Dockerfile 2024-02-12 10:46:28 +00:00
Ashleigh Carr
1a2207a045 Swtich to nginx for container 2024-02-12 10:46:28 +00:00
Ashleigh Carr
2b85336c71 Remove ARM64 Container build from release workflow 2024-02-12 10:46:28 +00:00
Ashleigh Carr
4b95ab2477 Increase nofile limit to 10,000 when building container on PR workflow too 2024-02-12 10:46:28 +00:00
Ashleigh Carr
a0729304d1 Add packages write permission 2024-02-12 10:46:28 +00:00
Ashleigh Carr
dbdcb460e5 Remove unecessary if: success() from Github release workflow 2024-02-12 10:46:28 +00:00
Ashleigh Carr
7588e50f9f Remove unecessary QEMU install step 2024-02-12 10:46:28 +00:00
Ashleigh Carr
40a4872f70 Generate prod build inside container 2024-02-12 10:46:28 +00:00
Ashleigh Carr
3b265322e0 Build container on PR (but don't publish) to verify Containerfile syntax 2024-02-12 10:46:28 +00:00
Ashleigh Carr
0da30813da Add new steps to publish a containerized CyberChef to GHCR 2024-02-12 10:46:28 +00:00
Jed Laundry
e973ea6f08 update Diff sanity check test 2024-02-11 01:18:52 +00:00
Jed Laundry
a942fe92fd
Merge branch 'master' into master 2024-02-11 13:31:58 +13:00
a3957273
9829b419b9
Merge pull request #1709 from dougburks/patch-1
Fix typo in FileTree.mjs
2024-02-09 16:00:46 +00:00
Doug Burks
19194a7eb0
Fix typo in FileTree.mjs 2024-02-09 07:41:32 -05:00
a3957273
c13997bdb1
Merge pull request #1553 from sg5506844/base92
Feature: Add Base92 operations
2024-02-09 00:42:05 +00:00
a3957273
35c2d437fa Merge branch 'master' of https://github.com/gchq/CyberChef 2024-02-09 00:37:51 +00:00
a3957273
a54522f796 10.7.0 2024-02-09 00:37:15 +00:00
a3957273
6c971876de
Merge pull request #1667 from sw5678/master
Added file tree functionality
2024-02-09 00:31:48 +00:00
a3957273
d8be3dfa27
Merge pull request #1555 from sg5506844/rison-operation
RISON operation
2024-02-09 00:30:53 +00:00
a3957273
2b57f94ccd Merge branch 'master' into rison-operation 2024-02-09 00:23:01 +00:00
a3957273
a3944fe1d1
Merge pull request #1694 from AliceGrey/master
Add MurmurHash3 Operation
2024-02-08 18:15:41 +00:00
Alice
cfc8a506f7 Fix calculation bug and add Convert to Signed
A signed output is often needed for Shodan and other favicon searches.
2024-02-06 15:21:39 -05:00
Allie
afcf46561a
Rename Murmurhash3.mjs to MurmurHash3.mjs 2024-02-06 13:13:43 -05:00
Alice
59b97bfccb Add MurmurHash3 Tests and normalize filename 2024-02-06 13:04:09 -05:00
Alice
20db43c0a8 Add MIT License 2024-02-06 13:04:09 -05:00
Alice
dc7760247b Add MurmurHash3 2024-02-06 13:04:09 -05:00
a3957273
56a8e02bb8
Merge pull request #1705 from gchq/chore/update-packages
Update node packages
2024-02-04 23:25:56 +00:00
a3957273
e532248701
Merge branch 'master' into chore/update-packages 2024-02-04 15:20:50 +00:00
a3957273
73100896d4 Downgrade Jimp 2024-02-04 02:14:27 +00:00
a3957273
a95be3b4c5 Downgrade bootstrap version 2024-02-04 02:04:11 +00:00
a3957273
75c4e196fa
Merge pull request #1549 from brun0ne/fix-xss
Fixed xss in addOperation
2024-02-04 01:41:56 +00:00
a3957273
0359a2eccf
Merge branch 'master' into fix-xss 2024-02-04 01:33:02 +00:00
a3957273
b118932451
Merge branch 'master' into base92 2024-02-04 01:31:34 +00:00
a3957273
fd77152343
Merge pull request #1554 from sg5506844/Bcrypt-hash-detection-to-Analyse-hash
Add Bcrypt hash detection to "Analyse hash"
2024-02-04 01:19:30 +00:00
a3957273
5afecdb11a Update node packages 2024-02-04 01:08:15 +00:00
a3957273
1916137c3c
Merge branch 'master' into rison-operation 2024-02-04 01:04:24 +00:00
a3957273
c3b89efd9a
Merge branch 'master' into master 2024-02-04 00:45:33 +00:00
a3957273
0f3cd72dd3 Add links to Changelog 2024-02-04 00:34:24 +00:00
a3957273
ed59f6a67a
Merge pull request #1658 from cnotin/patch-1
Describe that "Parse ASN.1 hex string" operation requires an hex string input
2024-02-03 16:44:33 +00:00
a3957273
592745f380
Merge pull request #1661 from BlacAmDK/BlacAmDK-patch-1
Fix ExtractIPAddresses IPv6 regexp
2024-02-03 16:44:00 +00:00
a3957273
10b0d91bdc
Merge branch 'master' into BlacAmDK-patch-1 2024-02-03 16:11:01 +00:00
a3957273
dea2b3a2c0
Merge branch 'master' into patch-1 2024-02-03 16:07:31 +00:00
a3957273
df151eabf9 10.6.0 2024-02-03 14:19:50 +00:00
Clément Notin
22a873c73e Describe that "Parse ASN.1 hex string" operation requires an hex string input
Just in case the title of the operation doesn't make it clear enough
2024-02-03 15:07:57 +01:00
a3957273
c6da0c623d
Merge pull request #1678 from cnotin/patch-3
Add UUID regex to 'Regular expression' operation
2024-02-03 14:06:23 +00:00
a3957273
44b566789f
Merge pull request #1675 from 0xThiebaut/LZNT1
Add support for LZNT1 decompression.
2024-02-03 13:31:13 +00:00
a3957273
940f78a8a7
Merge branch 'master' into LZNT1 2024-02-03 13:08:03 +00:00
a3957273
06c912be72
Merge branch 'master' into patch-3 2024-02-03 13:05:42 +00:00
a3957273
91639ee836
Merge pull request #1703 from gchq/feature/update-forensic-wiki-address
Update forensics wiki address
2024-02-03 02:19:54 +00:00
a3957273
b78533bb02 Update forensics wiki address 2024-02-03 02:02:13 +00:00
a3957273
b5e3a6c5a3
Merge branch 'master' into master 2024-02-03 01:25:55 +00:00
a3957273
a045c4ffec
Merge pull request #1541 from KevinSJ/fix/baking-time-info
fix: incorrect hover on baking info
2024-02-03 00:54:17 +00:00
a3957273
856ba1cf50
Merge pull request #1702 from gchq/chore/can-i-use-update
Update 'can-i-use' browser list targets
2024-02-03 00:21:53 +00:00
a3957273
6510773789 Update 'can-i-use' browser list targets 2024-02-03 00:11:50 +00:00
a3957273
7b280b3369
Merge pull request #1701 from gchq/sec/fix-forensics-url
Update 'ExtractFiles' information URL
2024-02-03 00:04:00 +00:00
a3957273
1618e112e1 Update 'ExtractFiles' information URL 2024-02-02 23:56:27 +00:00
a3957273
c08a7dc6ce
Merge pull request #1700 from gchq/chore/update-chromedriver
Update chrome driver version
2024-02-02 23:54:11 +00:00
a3957273
57731706b3 Revert 'can-i-use' upgrade 2024-02-02 23:46:36 +00:00
a3957273
e9e926d054 Update 'can-i-use' to pass tests 2024-02-02 23:37:07 +00:00
a3957273
5fa3d691cf Update chrome driver version 2024-02-02 22:35:42 +00:00
a3957273
d022dbc406
Merge pull request #1676 from cnotin/patch-2
Add links to wiki pages
2024-02-02 22:06:43 +00:00
a3957273
f96607c81b
Merge pull request #1656 from pandaninjas/patch-3
Update chromedriver to v119 so that it is compatible with the chrome …
2024-02-02 18:21:29 +00:00
Ted Kruijff
24cd4033c4
Add Caret/M-decode Operation 2024-01-26 15:52:41 +01:00
Clément Notin
0bf7852e83
Add UUID regex to 'Regular expression' operation
I use this one often so I'm sure others will like it too :)
2023-12-26 15:59:32 +01:00
Clément Notin
aaff2e687d
Add links to wiki pages 2023-12-26 15:43:49 +01:00
Maxime THIEBAUT
77042abc23 Add support for LZNT1 decompression. 2023-12-25 23:06:11 +01:00
sw5678
ac18b74e66 Fixed linting issues 2023-12-13 09:38:26 +00:00
sw5678
76ba630d59 Added file tree functionality 2023-12-13 09:19:16 +00:00
BlacAmDK
362755b22f
Fix ExtractIPAddresses IPv6 regexp
IPv6 regexp shouldn't match IPv4 address.
2023-12-05 14:40:37 +08:00
ccarpo
cc21fe18ca fixed typo. 2023-11-21 09:24:54 +01:00
ccarpo
4255d8d543 Renamed JSON to Yaml to Beautify JSON 2023-11-21 09:19:58 +01:00
ccarpo
7353315baa Renamed JSON to Yaml to Beautify JSON 2023-11-21 08:56:20 +01:00
Jocelyn Castellano
6c63302d62
Update chromedriver to v119 so that it is compatible with the chrome version in CI 2023-11-20 11:01:00 -08:00
Jed Laundry
efda16b039 change Diff to output <ins>, <del> 2023-08-31 03:20:20 +00:00
Joost Rijneveld
cb98672549 Fix ChaCha operation Raw output
Previously, an array type error prevented any output when selecting
the 'Raw' output option for the ChaCha operation. This did not
show up in tests, as they all compared to hex values.

This also adds a test (relying on the 'To Hex' operation) that
catches this.
2023-07-30 17:02:36 +02:00
zhzy0077
721061d054 fix typo. 2023-07-25 14:48:03 +08:00
zhzy0077
d2da11c79a Support jq. 2023-07-25 14:42:43 +08:00
n1474335
6ed9d4554a
10.5.2 2023-07-14 19:01:41 +01:00
n1474335
2dcd345349
Updated chromedriver 2023-07-14 19:01:35 +01:00
n1474335
81924b4a7e
10.5.1 2023-07-14 18:54:03 +01:00
n1474335
5a0c3a3b47
Fixed webpack config 2023-07-14 18:53:56 +01:00
n1474335
7b599fe7f7
10.5.0 2023-07-14 18:41:44 +01:00
n1474335
4faaa07188
Updated CHANGELOG 2023-07-14 18:41:32 +01:00
n1474335
fa228b2571
Added a range of GOST operations 2023-07-14 18:37:02 +01:00
sg5506844
9a216dc1bf RISON operation 2023-04-12 15:09:07 +05:30
sg5506844
0e0bafdeb6 Add Bcrypt hash detection to "Analyse hash" 2023-04-12 11:20:18 +05:30
sg5506844
5f0f037c46 Feature: Add Base92 operations 2023-04-12 10:37:16 +05:30
Brunon Blok
c0e84dcd50 change comments 2023-04-09 19:06:59 +00:00
Brunon Blok
6b01cf0c1a
Merge pull request #1 from brun0ne/test-xss
different fix which does not break any tests
2023-04-07 14:50:50 +02:00
Brunon Blok
30f9286ce9 different fix 2023-04-07 12:36:10 +00:00
Brunon Blok
e9ff8707ed comply with eslint 2023-04-07 01:02:33 +00:00
Brunon Blok
12082ba3cc escape only angle brackets 2023-04-07 00:59:51 +00:00
Brunon Blok
6d3ca3f56c fix xss in addOperation 2023-04-06 23:31:45 +00:00
Brunon Blok
15b426ebb6 clean up code formatting and fix missing entries 2023-04-06 21:03:46 +00:00
Brunon Blok
bf1e708a4c added PHP Serialize operation 2023-04-06 20:32:50 +00:00
Kevin Jiang
4262e6f6f7 fix: incorrect hover on baking info 2023-03-28 22:06:08 +13:00
n1474335
1bc88728f0
10.4.0 2023-03-24 22:41:40 +00:00
n1474335
7bb0649b27
Updated CHANGELOG 2023-03-24 22:41:24 +00:00
n1474335
e46a7448d9
Fixed De Bruijn test import 2023-03-24 22:40:07 +00:00
n1474335
d102e1b15c
Tidied 'Generate De Bruijn Sequence' operation 2023-03-24 22:39:08 +00:00
n1474335
0a0217cb66
Merge branch 'debruijn' of https://github.com/GCHQ77703/CyberChef 2023-03-24 22:33:43 +00:00
n1474335
3faa9d3a1e
10.3.0 2023-03-24 22:17:19 +00:00
n1474335
d902c7e30c
Updated CHANGELOG 2023-03-24 22:17:11 +00:00
n1474335
25fe7bba67
Tidied up Argon2 operations 2023-03-24 22:15:21 +00:00
n1474335
ca340cdd7b
Merge branch 'feature/add-argon2-operation' of https://github.com/Xenonym/CyberChef 2023-03-24 20:48:42 +00:00
Matt Coomber
266fbab8fd
Fix loading messages
Missing comma in array
2023-03-24 09:57:06 +00:00
n1474335
e57fd2a408
10.2.0 2023-03-23 18:22:37 +00:00
n1474335
3328ae8afd
Updated CHANGELOG 2023-03-23 18:22:27 +00:00
n1474335
1caecf70a2
Fixed HKDF op name 2023-03-23 18:21:43 +00:00
n1474335
6e347742d9
Merge branch 'hkdf' of https://github.com/mikecat/CyberChef 2023-03-23 18:18:25 +00:00
n1474335
2e2dcfa416
10.1.0 2023-03-23 18:00:13 +00:00
n1474335
4bb10a34e1
Updated CHANGELOG 2023-03-23 17:59:56 +00:00
n1474335
1632e23c78
Merge branch 'markdown-beautify' of https://github.com/JatinSanghvi/CyberChef 2023-03-23 17:53:31 +00:00
n1474335
11fca557af
Merge branch 'fix_dark_theme_highlight' of https://github.com/SamueleFacenda/CyberChef 2023-03-23 17:52:41 +00:00
n1474335
1cf14c6f01
Merge branch 'master' of https://github.com/mattnotmax/CyberChef 2023-03-23 17:48:05 +00:00
n1474335
1bba10e7c2
Merge branch 'swap-case' of https://github.com/mikecat/CyberChef 2023-03-23 17:46:47 +00:00
n1474335
8f3096af0a
Merge branch 'levenshtein-distance' of https://github.com/mikecat/CyberChef 2023-03-23 17:42:16 +00:00
n1474335
6fdf37e2f2 10.0.1 2023-03-23 12:42:28 +00:00
n1474335
a4d6e1f92c TextNode characters are re-escaped in htmlWidgets now. Fixes #1533 2023-03-23 12:42:22 +00:00
mattnotmax
4a356476b1
Merge branch 'gchq:master' into master 2023-03-23 21:28:39 +11:00
n1474335
c2171a08f2 Added preventDefault to contextual help key press listener 2023-03-22 16:54:39 +00:00
n1474335
84aad167d5 Tweaked compile message 2023-03-22 11:59:35 +00:00
n1474335
493b1eee1e Removed excess whitespace from banner links 2023-03-22 11:36:03 +00:00
n1474335
6c5b260ece 10.0.0 2023-03-22 11:31:55 +00:00
n1474335
7394bb45d4 Updated CHANGELOG 2023-03-22 11:31:47 +00:00
n1474335
5d3302f6d7 Added a few more UI tests 2023-03-22 11:19:01 +00:00
n1474335
92dada8a80 Final tweaks to download wording 2023-03-22 11:16:49 +00:00
n1474335
c6569b7c47 Added compile message to master build chain 2023-03-22 10:30:42 +00:00
n1474335
ea56efae47 Added Download pane 2023-03-21 15:39:31 +00:00
n1474335
7419009745 Added more help topics and added filetype detection to the 'save output' button 2023-03-20 17:23:14 +00:00
mattnotmax
e58744c63a Update index.html
Added new loading message
2023-03-18 21:35:03 +11:00
n1474335
4c7fe147bc Merge branch 'fix-translatedatetimeformat-xss' of https://github.com/mikecat/CyberChef into v10 2023-03-17 18:12:50 +00:00
n1474335
7605d48f0b Fixed IO folder tests with unpredictable file ordering 2023-03-17 18:06:28 +00:00
n1474335
d6f8e0a520 Added a contextual help feature and started writing help descriptions 2023-03-17 17:46:13 +00:00
MikeCAT
ab283fc801 use Utils.escapeHtml instead of manual escaping 2023-03-18 00:54:43 +09:00
MikeCAT
d9d6b7aa37 fix XSS in operation TranslateDateTimeFormat 2023-03-18 00:32:06 +09:00
MikeCAT
b0c9a1850d add operaton HKDF 2023-03-17 23:50:24 +09:00
Samuele Facenda
764bd4b9ae
Update dark theme highligh 2023-03-15 08:38:56 +01:00
n1474335
a24fdf4250 Regex improvements 2023-03-13 18:28:05 +00:00
n1474335
13e3dba784 Removed LGTM badge from README 2023-03-13 18:21:31 +00:00
n1474335
ccea5cdf88 Fixed bad HTML filtering 2023-03-13 18:13:54 +00:00
n1474335
51e2b97595 Updated CodeQL action 2023-03-13 18:03:33 +00:00
n1474335
61501a7cbc Updated dependencies and fixed some code scanning findings 2023-03-13 17:51:25 +00:00
Tan Zhen Yong
bca4c34b3a
Add Argon2 hash compare operation 2023-03-12 00:33:28 +08:00
Tan Zhen Yong
2fab1028c5
Add Argon2 hash operation 2023-03-12 00:32:46 +08:00
n1474335
5d3c66f615 Removed call to cptable from NTHash operation 2023-03-09 18:06:32 +00:00
n1474335
cab83cae35 Switched arg layout to use flexbox instead of css grid 2023-03-09 17:31:46 +00:00
n1474335
bd16378e23 Fixed postinstall scipts to work on msys shells 2023-03-09 14:12:17 +00:00
n1474335
65e431bd9e Merge branch 'fix/postinstall-msys' of https://github.com/ParkerM/CyberChef into v10 2023-03-09 14:09:20 +00:00
n1474335
b9f2bddffc Added UI tests back into Github Actions scripts 2023-03-09 14:01:21 +00:00
n1474335
80e8b2339d Improved HTML output sizing 2023-03-08 18:08:17 +00:00
n1474335
7eda2fd4a6 Added UI tests for all HTML operations 2023-03-08 17:44:51 +00:00
n1474335
36aafb9246 Added test for alert bar 2023-03-06 14:53:20 +00:00
n1474335
acc1df2031 Merge branch 'fix-xss-datetime' of https://github.com/ntomoya/CyberChef into v10 2023-03-05 15:39:41 +00:00
n1474335
c5766c89f6 Further operation tests 2023-03-05 15:32:53 +00:00
n1474335
73f5069971 Added more IO tests and created browser test utils 2023-03-05 14:58:11 +00:00
n1474335
819e4a574c Added more tests, fixed length count bug and IO clearance bug 2023-03-03 17:33:42 +00:00
n1474335
8c0e23e196 Further IO tests added 2023-03-02 19:50:08 +00:00
n1474335
05160227a3 Added initial input and output UI tests 2023-03-02 18:10:52 +00:00
Tomoya Nakanishi
5cfc1abf41
Fixed XSS in TranslateDateTimeFormat 2023-03-01 03:39:57 +09:00
n1474335
046a0917e7 Nightwatch test improvements 2023-02-27 18:30:01 +00:00
n1474335
9cbf217d42 Fixed UI tests to work with new input and output areas 2023-02-27 18:21:06 +00:00
n1474335
bf949c0320 Fixed operational tests and updated some dependencies 2023-02-27 17:55:52 +00:00
n1474335
9e679f411c Fixed progress bug 2023-02-27 15:52:05 +00:00
n1474335
dd6eae52ef Folders can now be dropped into the CyberChef input 2023-02-27 15:32:52 +00:00
n1474335
cdde7166cf Changing tabs no longer triggers a bake 2023-02-24 17:34:35 +00:00
n1474335
251bd86ce5 Large inputs with long line lengths are now handled better. Issues with toggleLoader fixed. 2023-02-24 17:09:40 +00:00
Jatin Sanghvi
dee2dc3777 Align Markdown table column separators 2023-02-17 11:32:05 +05:30
n1474335
533047a3a2 Improved file type detection and timing output 2023-02-03 17:39:12 +00:00
n1474335
659325c85a Improved performance of str/array buffer conversions 2023-02-03 17:10:33 +00:00
n1474335
7a2517fd61 Fixed 'Clear All IO' button 2023-02-03 15:54:45 +00:00
n1474335
0b2cb7e68c Added fine-grain timing for aspects of the bake. Improved efficiency of autobakes and moved output decoding into a worker. 2023-02-03 14:55:15 +00:00
Parker Mauney
4e747b3697 Use process.platform to detect OS during postinstall 2023-01-22 18:57:57 -05:00
n1474335
84f0750525 Reviewed HTML and options 2023-01-19 17:47:07 +00:00
n1474335
fa21768931 Reviewed Highlighter and Options waiters 2023-01-19 17:14:24 +00:00
n1474335
934efcc5a0 Reviewed InputWorker 2023-01-19 16:56:07 +00:00
n1474335
91f1be8c70 Reviewed Input and Output Waiters and improved logging in workers 2023-01-18 18:07:06 +00:00
n1474335
56d1a016da Tidied InputWaiter and made inputChange debounce delay variable based on input length 2023-01-13 18:00:36 +00:00
n1474335
d6159cc154 Event bug fixes 2023-01-13 16:46:41 +00:00
n1474335
e9d7a8363c Removed treatAsUTF8 option 2023-01-13 14:38:50 +00:00
n1474335
4e512a9a7b Updated dependencies 2023-01-13 14:25:40 +00:00
n1474335
c1394e299a Fixed replace input with output button 2023-01-13 14:14:57 +00:00
n1474335
17c349973d Fixed file loading bug where the wrong input is set 2023-01-13 13:51:16 +00:00
n1474335
f2bd838596 Fixed CSS for theme highlighting and status bar dropup height 2023-01-13 13:12:01 +00:00
MikeCAT
d5b72548fc add new operation: Swap case 2023-01-11 05:48:05 +09:00
MikeCAT
2c822314df add new operation: Levenshtein Distance 2023-01-11 05:16:37 +09:00
n1474335
1b3d55f051 Status bar widgets are disabled for HTML output 2022-12-09 21:23:25 +00:00
n1474335
ff45f61b68 Fixed the snackbar 2022-12-09 20:46:01 +00:00
n1474335
771a013c9f Removed output-file markup and handlers 2022-12-09 20:12:15 +00:00
n1474335
b354f61502 Updated dependencies 2022-12-09 19:44:31 +00:00
n1474335
2e201c747a Merge remote-tracking branch 'origin/master' into v10 2022-12-09 19:28:41 +00:00
n1474335
c1d2970f1e File details can now be hidden 2022-12-09 19:24:43 +00:00
n1474335
2efd075803 9.55.0 2022-12-09 11:40:35 +00:00
n1474335
4b4d3c6845 Updated CHANGELOG 2022-12-09 11:40:25 +00:00
n1474335
760eff49b5 Added 'AMF Encode' and 'AMF Decode' operations 2022-12-09 11:39:22 +00:00
n1474335
ba12ad8e7c 9.54.0 2022-11-25 16:49:41 +00:00
n1474335
249af2ded1 Updated CHANGELOG 2022-11-25 16:49:37 +00:00
n1474335
7403666a11 Tidied up Rabbit operations 2022-11-25 16:48:54 +00:00
n1474335
1cc8b150f3 Merge branch 'rabbit-stream-cipher' of https://github.com/mikecat/CyberChef 2022-11-25 16:36:42 +00:00
n1474335
faa25ee662 9.53.0 2022-11-25 16:29:31 +00:00
n1474335
aa981ccd4a Updated CHANGELOG 2022-11-25 16:29:25 +00:00
n1474335
04378c1f91 Moved AES Key wrapping operations in Categories.json 2022-11-25 16:28:15 +00:00
n1474335
53179a158e Merge branch 'aes-key-wrap' of https://github.com/mikecat/CyberChef 2022-11-25 16:25:36 +00:00
n1474335
7ecde9fd2a 9.52.1 2022-11-25 16:11:28 +00:00
n1474335
320f79fe0d Added maxLength property for string arguments 2022-11-25 16:11:14 +00:00
n1474335
157346b055 Merge branch 'master' of https://github.com/TheSavageTeddy/CyberChef 2022-11-25 15:38:10 +00:00
n1474335
904c08c436 9.52.0 2022-11-25 15:31:31 +00:00
n1474335
fa238545a0 Updated CHANGELOG 2022-11-25 15:31:27 +00:00
n1474335
3f85c32c7c Lint 2022-11-25 15:30:32 +00:00
n1474335
55809b2e87 Merge branch 'feature/chacha' of https://github.com/joostrijneveld/CyberChef 2022-11-25 15:15:03 +00:00
n1474335
5c32c1bdaa Fixed tests for CMAC 2022-11-25 15:13:54 +00:00
TheSavageTeddy
f84c11f63d im dumb, please pass the test now 2022-11-25 22:40:40 +08:00
TheSavageTeddy
2bcfb693b7 fix 2022-11-25 22:32:23 +08:00
TheSavageTeddy
897d2bef6e fix output 2022-11-25 22:23:15 +08:00
TheSavageTeddy
0a3d219ad5 fixed linting 2022-11-25 22:13:53 +08:00
TheSavageTeddy
ba0dfe91c3 added all-zero edge cases for standard alphabet 2022-11-25 22:08:51 +08:00
TheSavageTeddy
bf4e62b4b7 added choice for base85 all-zero character 2022-11-25 21:36:17 +08:00
n1474335
657f8940fa 9.51.0 2022-11-25 12:47:20 +00:00
n1474335
74d629c491 Updated CHANGELOG 2022-11-25 12:47:12 +00:00
n1474335
130e9d8192 Lint 2022-11-25 12:46:15 +00:00
n1474335
0fb3743b6d Merge branch 'aes-cmac' of https://github.com/mikecat/CyberChef 2022-11-25 12:41:41 +00:00
n1474335
a19aea1516 9.50.12 2022-11-25 12:38:03 +00:00
n1474335
137f8d9471 Merge branch 'fix-fletcher-checksum' of https://github.com/mikecat/CyberChef 2022-11-25 12:37:24 +00:00
n1474335
1f57f1f000 9.50.11 2022-11-25 12:28:33 +00:00
n1474335
468071ee98 Tidied JSDoc comment 2022-11-25 12:28:26 +00:00
n1474335
23403f55a5 Merge branch 'master' of https://github.com/DidierStevens/CyberChef 2022-11-25 12:26:53 +00:00
n1474335
c25cf44d92 9.50.10 2022-11-25 12:25:15 +00:00
n1474335
e5644b5712 Merge branch 'master' of https://github.com/samgbell/CyberChef 2022-11-25 12:23:14 +00:00
n1474335
9321b79d81 9.50.9 2022-11-25 12:21:51 +00:00
n1474335
e97d535ff8 Merge branch 'fix-option-in-parse-asn1-hex-string' of https://github.com/mikecat/CyberChef 2022-11-25 12:21:42 +00:00
n1474335
7589361e58 9.50.8 2022-11-25 12:19:31 +00:00
n1474335
f15ef81693 Merge branch 'put-required-margin' of https://github.com/mikecat/CyberChef 2022-11-25 12:19:22 +00:00
n1474335
d5f4968664 9.50.7 2022-11-25 12:18:33 +00:00
n1474335
74e9edbccf Merge branch 'user-friendly-parse-x509-certificate' of https://github.com/mikecat/CyberChef 2022-11-25 12:15:29 +00:00
n1474335
51229d85cb 9.50.6 2022-11-25 12:11:17 +00:00
n1474335
b979b051cb Merge branch 'triple-des-with-16byte-key' of https://github.com/mikecat/CyberChef 2022-11-25 12:08:58 +00:00
n1474335
17cf154bc2 9.50.5 2022-11-25 12:07:07 +00:00
n1474335
c7f6954b97 Merge branch 'view-bit-plane-use-bytelength-not-length' of https://github.com/mikecat/CyberChef 2022-11-25 12:07:01 +00:00
n1474335
9ccc1613cf 9.50.4 2022-11-25 12:05:32 +00:00
n1474335
9730ce1f6a Merge branch 'fix-windows-filetime' of https://github.com/mikecat/CyberChef 2022-11-25 12:05:22 +00:00
n1474335
55a7981547 9.50.3 2022-11-25 12:03:57 +00:00
n1474335
2d99c365dd Merge branch 'fix-reverse-character' of https://github.com/mikecat/CyberChef 2022-11-25 12:02:46 +00:00
n1474335
59d8be511a 9.50.2 2022-11-25 12:00:32 +00:00
n1474335
8349ffc001 Merge branch 'from-hex-use-delimiter-as-delimiter' of https://github.com/mikecat/CyberChef 2022-11-25 11:59:25 +00:00
n1474335
c1368c4ecb 9.50.1 2022-11-25 11:55:53 +00:00
n1474335
c6935e040d Updated newMinorVersion script 2022-11-25 11:55:48 +00:00
n1474335
f79c3ae91a Merge branch 'use-lowercase-for-asn1' of https://github.com/mikecat/CyberChef 2022-11-25 11:55:19 +00:00
n1474335
bc27cd2772 9.50.0 2022-11-25 11:51:34 +00:00
n1474335
2b02c44ca4 Updated CHANGELOG 2022-11-25 11:51:22 +00:00
n1474335
59fe8d1c4b Simplified 'Shuffle' operation to work in the same way as 'Sort' and 'Unique' 2022-11-25 11:50:27 +00:00
n1474335
9a5d62c4c3 Merge branch 'shuffle-operation' of https://github.com/mikecat/CyberChef 2022-11-25 11:24:47 +00:00
n1474335
9fa82150ee 9.49.2 2022-11-25 11:23:38 +00:00
n1474335
d7561ec208 Tidied Substitute 2022-11-25 11:23:32 +00:00
n1474335
743b834f6d Merge branch 'SamueleFacendaSubstitution' of https://github.com/SamueleFacenda/CyberChef 2022-11-25 11:21:04 +00:00
n1474335
0658836f87 9.49.1 2022-11-25 11:15:16 +00:00
n1474335
a4e20c7059 Merge branch 'large-prng' of https://github.com/mikecat/CyberChef 2022-11-25 11:13:05 +00:00
TheSavageTeddy
d77f8ba747 fix linting again 2022-11-25 11:08:01 +08:00
TheSavageTeddy
78d35ecec3 better boolean statement 2022-11-25 10:59:04 +08:00
TheSavageTeddy
c79bf5caaf fixed linting 2022-11-25 10:49:56 +08:00
TheSavageTeddy
66cbc6908a Better delimeter parsing for From Base85 2022-11-25 10:36:08 +08:00
MikeCAT
c04f409d23 PseudoRandomNumberGenerator: support larger output than 65536 bytes 2022-11-17 20:24:54 +09:00
Samuele Facenda
1a9833132d Added ignoreCase feature in Substitute operation. 2022-11-13 14:41:01 +01:00
Samuele Facenda
9c3ddca269 Added ignoreCase feature in Substitute operation. 2022-11-13 14:37:19 +01:00
n1474335
72889d1c20 9.49.0 2022-11-11 16:29:13 +00:00
n1474335
6c5433b226 Updated CHANGELOG 2022-11-11 16:29:03 +00:00
n1474335
31a7f83b82 Added 'LZ4 Compress' and 'LZ4 Decompress' operations. Closes #1116 2022-11-11 16:27:14 +00:00
MikeCAT
39143fa6a1 add Shuffle operation 2022-11-11 22:26:41 +09:00
n1474335
a116a2a423 Input tab headers now show the filename for file inputs 2022-11-04 18:45:52 +00:00
n1474335
61d4c0ea63 File loading progress is now updated 2022-11-04 18:29:53 +00:00
n1474335
44c7a1e92d Output loading messages are displayed properly again 2022-11-04 14:58:37 +00:00
n1474335
09fd333997 Fixed bug where input would not be loaded from deep links if a chrenc was not set 2022-11-04 14:38:30 +00:00
Joost Rijneveld
ebe2a29543 Add ChaCha stream cipher operation 2022-11-03 15:17:33 +01:00
MikeCAT
1e83e0e935 convert hex string to lower before parsing as ASN.1 2022-11-03 21:43:24 +09:00
MikeCAT
fe9eb08648 allow 16-byte keys for Triple DES in CMAC operation 2022-11-03 01:20:37 +09:00
MikeCAT
2255c5b360 allow 16-byte keys for Triple DES 2022-11-03 01:12:01 +09:00
MikeCAT
c046cf5695 have "From Hex" treat the delimiter as delimiter, not what to erase 2022-11-03 00:21:20 +09:00
MikeCAT
3086c25079 improve treatment of Hex(little endian) for Windows Filetime converter 2022-11-02 23:14:48 +09:00
MikeCAT
3700780d14 improve "Reverse" operation
* Make "Character" option actually reverse characters
* Add new option "Byte" that behaves as previous "Character" option
2022-11-02 22:37:09 +09:00
MikeCAT
5b134d7e9e fix Fletcher-32/64 Checksum
* Operate on words, not bytes
* Add tests
2022-11-02 21:54:45 +09:00
MikeCAT
58b1fb8de5 ViewBitPlane.mjs: use byteLength instead of length to check validity of ArrayBuffer 2022-11-02 08:29:26 +09:00
MikeCAT
c0bd6645ce add new operation: CMAC 2022-11-02 02:07:16 +09:00
MikeCAT
c6b79cd1c6 add new operations: AES Key Wrap/Unwrap 2022-11-01 00:35:27 +09:00
Didier Stevens
cb023089bb Operation Sort: added value Length to option Order 2022-10-30 15:33:11 +01:00
MikeCAT
5a507aa1ba have "Parse X.509 certificate" emit user-friendly message on certificate load error 2022-10-30 08:25:31 +09:00
MikeCAT
d23b88e2b8 use typed arrays for status of Rabbit instead of normal arrays 2022-10-29 03:33:30 +09:00
MikeCAT
3ac2ed20d2 add operation "Rabbit Stream Cipher" 2022-10-29 03:09:41 +09:00
MikeCAT
d5ffbbb14c ParseASN1HexString.mjs: fix the name of option to use 2022-10-28 21:33:56 +09:00
n1474335
b92501ee35 Introduced use of conditional chaining operator 2022-10-28 13:24:03 +01:00
n1474335
570206af77 Line ending sequences for the current tab are included in the deep link URL 2022-10-28 12:44:06 +01:00
n1474335
f6ae89587c EOL sequences are now preserved between tabs 2022-10-28 12:24:16 +01:00
MikeCAT
fa30f597ad GenerateQRCode.mjs: set default margin to 4 modules 2022-10-27 20:02:49 +09:00
n1474335
bdb8c02d5a Input and Output encodings are now saved per tab 2022-10-21 18:29:52 +01:00
n1474335
5efd125d9b Simplified TabWaiter structure 2022-10-21 13:57:46 +01:00
n1474335
01508a2459 Merge branch 'master' into v10 2022-10-21 11:56:25 +01:00
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
samgbell
8e57354307
Fixing some eslint and JSDoc issues 2022-10-13 12:03:22 +02:00
samgbell
126debf44e
Adding Markdown format for To Table operation 2022-10-13 11:52:19 +02: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
a07b8f693b Input and Output character encodings are now stored in the URL, allowing for accuate deeplinking 2022-09-16 19:24:57 +01:00
n1474335
a141873db8 Highlighting now takes account of character set width 2022-09-16 16:00:39 +01:00
n1474335
08b91fd7ff Removed ioDisplayThreshold option 2022-09-16 16:00:03 +01:00
n1474335
cd7156dc55 Merge branch 'master' into v10 2022-09-16 14:48:52 +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
n1474335
3893c22275 Changing the output encoding no longer triggers a full bake 2022-09-09 16:35:21 +01:00
IsSafrullah
65d883496b fix select when change theme 2022-09-06 03:52:42 +07:00
n1474335
406da9fa2c Efficiency improvements to reduce unnecessary casting 2022-09-02 20:15:07 +01:00
n1474335
16b79e32f6 File details are now displayed in a side panel and the input is still editable 2022-09-02 14:34:23 +01:00
n1474335
e93aa42697 Input and output character encodings can now be set 2022-09-02 12:56:04 +01: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
n1474335
7c8a185a3d HTML outputs can now be selected and handle control characters correctly 2022-07-18 18:39:41 +01:00
john19696
e9dd7eceb8 upgrade to nodejs v18 2022-07-14 14:27:59 +01:00
Luis Martinez
1dfb231033 xxtea bug fix 2022-07-11 19:42:30 -05:00
Luis Martinez
4f0fa2a299
Merge branch 'gchq:master' into xxtea_encryption 2022-07-11 19:41:02 -05:00
Luis Martinez
c14098a27c tests added and XXTEA not working correctly fixed 2022-07-11 19:38:59 -05:00
Luis Martinez
653af6a300 xxtea encryption added 2022-07-11 18:59:53 -05:00
Luis Martinez
893b84d042 xxtea encryption added 2022-07-11 18:59:53 -05:00
n1474335
0dc2322269 Fixed dropping text in the input 2022-07-11 13:57:28 +01:00
n1474335
5c8aac5572 Improved input change update responsiveness 2022-07-11 13:43:19 +01:00
n1474335
157dacb3a5 Improved highlighting colours and selection ranges 2022-07-11 11:43:48 +01:00
n1474335
890f645eeb Overhauled Highlighting to work with new editor and support multiple selections 2022-07-10 22:01:22 +01:00
n1474335
2785459257 Merge branch 'master' into io-overhaul 2022-07-10 19:06:48 +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
n1474335
68733c74cc Output now uses CodeMirror editor 2022-07-02 19:23:03 +01:00
n1474335
bc949b47d9 Improved Controls CSS 2022-07-01 12:01:48 +01:00
n1474335
85ffe48743 Input now uses CodeMirror editor 2022-06-29 18:02:49 +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
n1474335
54fdc05e3a 9.39.1 2022-06-09 16:32:32 +01:00
n1474335
2267569c8d Fixed lint 2022-06-09 16:32:23 +01:00
n1474335
2f53ee3974 Merge branch 'fix_loop_counter' of https://github.com/sec65/CyberChef 2022-06-09 16:23:01 +01:00
n1474335
a3b846638f 9.39.0 2022-06-09 15:17:14 +01:00
n1474335
cc3033266c Updated CHANGELOG 2022-06-09 15:17:08 +01:00
n1474335
23b168515c Merge branch 'elf-info' of https://github.com/n1073645/CyberChef 2022-06-09 15:04:46 +01:00
n1073645
049690fea2 Linting modifications 2022-06-09 10:15:47 +01:00
n1073645
d3de91de85 Modify stream library to support reading until a null byte 2022-06-09 10:12:19 +01:00
n1073645
64eae37788 Added tests for ELF-Info 2022-06-09 10:02:38 +01:00
n1474335
8c71b0b8df 9.38.9 2022-06-08 18:59:36 +01:00
n1474335
2bf1ac6b9c 'Parse X.509 Certificate' Issuer and Subject name parsing improved. Closes #1365 2022-06-08 18:59:27 +01:00
n1474335
7197a434c2 9.38.8 2022-06-08 18:07:32 +01:00
n1474335
5349115b94 'JSON Beautify' operation now supports formatting, collapsing and syntax highlighting. Closes #203. 2022-06-08 18:07:11 +01:00
n1474335
4274e8f3a2 Fixed PEM wiki link 2022-06-06 15:20:31 +01:00
n1474335
7610e159a3 9.38.7 2022-06-06 14:54:27 +01:00
n1474335
9ec94434bb Fixed 'From Base64' bug adding null bytes. Closes #1362 2022-06-06 14:54:06 +01:00
n1073645
1ab444bda2 Fix tabs in tests file. 2022-06-05 18:40:46 +01:00
n1073645
3990ba774f Implemented readelf-like functionality. 2022-06-05 18:35:02 +01:00
sec65
1fea9a25a5 reset loop counter after last run 2022-06-05 17:22:42 +02:00
n1474335
3f57711c39 9.38.6 2022-06-03 22:58:23 +01:00
n1474335
dc46018757 Tidied up 'PEM to Hex' operation 2022-06-03 22:57:49 +01:00
n1474335
1464e5d5e4 Merge branch 'pem' of https://github.com/cplussharp/CyberChef 2022-06-03 22:21:37 +01:00
n1474335
95f7ed0de4 9.38.5 2022-06-03 22:13:50 +01:00
n1474335
6e7240026a Updated dependencies 2022-06-03 22:13:44 +01:00
n1474335
8bae7bf809 9.38.4 2022-06-03 21:41:44 +01:00
n1474335
b78bb2d3d6 Added 'Strict mode' to 'From Base64' operation 2022-06-03 21:41:37 +01:00
n1474335
f9a6402825 Merge branch 'strict_base64' of https://github.com/mikecat/CyberChef 2022-06-03 13:18:41 +01:00
n1474335
8ec5f3cb18 9.38.3 2022-06-03 13:15:25 +01:00
n1474335
c330394ff2 Fixed toBinary delim adjustment 2022-06-03 13:15:18 +01:00
n1474335
36e66ad5b4 Merge branch 'master' of https://github.com/michaellrowley/CyberChef 2022-06-03 13:10:59 +01:00
n1474335
a5a89efc06 9.38.2 2022-06-03 12:58:50 +01:00
n1474335
1078c37043 Merge branch 'master' of https://github.com/LukeSerne/CyberChef 2022-06-03 12:55:56 +01:00
n1474335
535c7188a8 9.38.1 2022-06-03 12:53:22 +01:00
n1474335
d6f9e216a6 Merge branch 'fix-to-base45' of https://github.com/mikecat/CyberChef 2022-06-03 12:50:45 +01:00
n1474335
7d6a879a67 Added script for updating the CHANGELOG 2022-05-31 00:20:19 +01:00
n1474335
668eac1f9e Fixed Split.js issues when resizing to around 1000px wide 2022-05-30 22:53:17 +01:00
n1474335
ff99436ce6 Fixed 'To Hex' highlighting 2022-05-30 19:43:59 +01:00
n1474335
ec577fc075 Fixed CSS for maximising output pane 2022-05-30 19:25:41 +01:00
n1474335
cc9d51b7be 9.38.0 2022-05-30 18:14:46 +01:00
n1474335
cf2b54e8c0 Update CHANGELOG 2022-05-30 18:14:41 +01:00
n1474335
a895d1d82a Added 'Parse TCP' operation 2022-05-30 18:06:15 +01:00
Luis Martinez
19423cc437 xxtea encryption added 2022-05-28 00:20:51 -05:00
Luis Martinez
3ea12a2e1b xxtea encryption added 2022-05-28 00:17:59 -05:00
MikeCAT
11da4188ee fix "To Base45" ( #1351 ) 2022-05-20 11:59:04 +00:00
Luke Serné
5b68bad185 Support UTF8 encoded characters in Substitution operation
This adds support for UTF8-encoded characters in the input and the parameters.
2022-05-13 17:35:50 +02:00
n1474335
477e4a7421 9.37.3 2022-04-14 18:08:23 +01:00
n1474335
9a982f05ac Extract operations now offer built-in Sort and Unique options. Unique operation offers option to count occurances. Closes #1334. 2022-04-14 18:08:16 +01:00
n1474335
6959e2cf01 9.37.2 2022-04-14 16:57:51 +01:00
n1474335
f5fe79326a CodeQL fixes 2022-04-14 16:57:46 +01:00
n1474335
f77633cee9 9.37.1 2022-04-14 13:17:43 +01:00
n1474335
c858970573 Merge branch 'john19696-testui' 2022-04-14 13:17:32 +01:00
n1474335
fb3eceaee0 Tidied up UI tests 2022-04-14 13:16:36 +01:00
n1474335
8e37fec8f8 Merge branch 'testui' of https://github.com/john19696/CyberChef into john19696-testui 2022-04-14 11:55:56 +01:00
n1474335
ccaabfaee8 Fixed incorrect wording for RC4 Drop argument. 2022-04-14 11:55:34 +01:00
Thomas Leplus
e712af33b7 Adding ROT8000 2022-04-11 18:44:14 -07:00
John L
c431fb30c5 added logging & jsdoc 2022-04-06 10:54:20 +01:00
John L
1c04848480 added log_path 2022-04-06 10:51:52 +01:00
John L
ca1a0797fb Merge branch 'master' into testui 2022-04-04 17:54:02 +01:00
John L
7b497181fd refactor samples, and more tests 2022-04-04 17:40:58 +01:00
John L
92767b1078 Try import 2022-03-31 19:32:41 +01:00
n1474335
7c66dacc40 9.37.0 2022-03-29 18:05:55 +01:00
n1474335
632277f9bd Updated CHANGELOG 2022-03-29 18:05:47 +01:00
n1474335
3c23ae03f5 Merge branch 'swesven-master' 2022-03-29 18:02:09 +01:00
n1474335
8117926ca3 Tidied up SM4 ops and NoPadding options for AES, DES and TripleDES 2022-03-29 18:01:57 +01:00
n1474335
31e9d27f1a Merge branch 'master' of https://github.com/swesven/CyberChef into swesven-master 2022-03-29 17:30:22 +01:00
n1474335
0c067d60d8 9.36.1 2022-03-29 17:26:17 +01:00
n1474335
1171d6b165 Merge branch 'pH-T-master' 2022-03-29 17:22:50 +01:00
n1474335
18022a2a48 Merge branch 'master' of https://github.com/pH-T/CyberChef into pH-T-master 2022-03-29 17:22:34 +01:00
n1474335
1400b5cca4 9.36.0 2022-03-29 12:48:47 +01:00
n1474335
98b5f9cc29 Updated CHANGELOG 2022-03-29 12:48:43 +01:00
n1474335
e766cb009e Merge branch 'hettysymes-SIGABA' 2022-03-29 12:45:56 +01:00
n1474335
993e276858 Tidied up Bletchley ops 2022-03-29 12:45:42 +01:00
n1474335
a762fb4df4 Merge branch 'SIGABA' of https://github.com/hettysymes/CyberChef into hettysymes-SIGABA 2022-03-29 12:26:39 +01:00
n1474335
00781fa459 Fixed lint 2022-03-29 11:55:41 +01:00
n1474335
c6e7367a4e 9.35.1 2022-03-28 17:15:51 +01:00
n1474335
3749bb1222 Merge branch 'AlexAndHisScripts-master' 2022-03-28 17:15:39 +01:00
n1474335
f3c83b2009 Merge branch 'master' of https://github.com/AlexAndHisScripts/CyberChef into AlexAndHisScripts-master 2022-03-28 17:14:57 +01:00
n1474335
d3583c31bc 9.35.0 2022-03-28 16:19:55 +01:00
n1474335
2f638d8c0c Updated CHANGELOG 2022-03-28 16:19:51 +01:00
n1474335
74e43ff65a Merge branch 't-8ch-base45' 2022-03-28 16:18:02 +01:00
n1474335
4f0b160ed3 Tidied up Base45 ops 2022-03-28 16:15:37 +01:00
n1474335
709b8696fc Merge branch 'base45' of https://github.com/t-8ch/CyberChef into t-8ch-base45 2022-03-28 16:04:34 +01:00
n1474335
e080c5d72e 9.34.2 2022-03-28 15:57:00 +01:00
n1474335
9cc177a9ad Code quality improvements 2022-03-28 15:56:15 +01:00
Paul Hager
9ad4e2525e fix: GetAllCasings.mjs test 2022-03-28 16:52:59 +02:00
n1474335
60b5fe0e76 9.34.1 2022-03-28 15:42:16 +01:00
n1474335
9273f97d88 Updated dependencies 2022-03-28 15:42:11 +01:00
Paul Hager
e2b7ac68ef fix: GetAllCasings.mjs - newline bug 2022-03-28 14:46:41 +02:00
n1474335
98a6baf55a 9.34.0 2022-03-28 11:40:04 +01:00
n1474335
b5677387f5 Updated CHANGELOG 2022-03-28 11:39:57 +01:00
n1474335
cd3eaa4762 Merge branch 'n1073645-variationsOfString' 2022-03-28 11:37:42 +01:00
n1474335
9733bf65de Merge branch 'nodejs16' of https://github.com/john19696/CyberChef into john19696-nodejs16 2022-03-28 11:37:23 +01:00
n1474335
bc433f0234 9.33.1 2022-03-28 11:23:19 +01:00
n1474335
ad7283ee6f Merge branch 'Gitoffthelawn-patch-1' 2022-03-28 11:21:49 +01:00
n1474335
5b941358a9 Merge branch 'patch-1' of https://github.com/Gitoffthelawn/CyberChef into Gitoffthelawn-patch-1 2022-03-28 11:21:22 +01:00
n1474335
f19e898c57 Merge branch 'Wingless-Archangel-patch-1' 2022-03-28 11:20:29 +01:00
n1474335
590ffa184d Merge branch 'patch-1' of https://github.com/Wingless-Archangel/CyberChef into Wingless-Archangel-patch-1 2022-03-28 11:20:10 +01:00
n1474335
46de51512f Merge branch 'adamkdean-patch-1' 2022-03-28 11:15:48 +01:00
n1474335
a13f2f26e4 Merge branch 'patch-1' of https://github.com/adamkdean/CyberChef into adamkdean-patch-1 2022-03-28 11:15:28 +01:00
n1474335
c9c26f6f9f Merge branch 'eljeffeg-patch-1' 2022-03-28 11:13:44 +01:00
n1474335
787c29e42b Merge branch 'patch-1' of https://github.com/eljeffeg/CyberChef into eljeffeg-patch-1 2022-03-28 11:13:26 +01:00
n1474335
1c0b83d833 9.33.0 2022-03-28 10:58:30 +01:00
n1474335
5c767d09b0 Updated CHANGELOG 2022-03-28 10:58:25 +01:00
n1474335
75dba51f56 Improve CJS and ESM module support #1037 2022-03-28 10:52:28 +01:00
n1474335
78a1827af8 Merge branch 'john19696-nodejs16' 2022-03-25 18:33:22 +00:00
n1474335
9e3733b33b Fixed Node imports 2022-03-25 18:28:01 +00:00
n1474335
4ef65589e8 Actions can now be triggered manually 2022-03-25 15:24:21 +00:00
n1474335
cf9e670309 Updated eslint 2022-03-25 15:17:00 +00:00
n1474335
b09f98fbb4 Updated to Node 17 2022-03-25 14:59:54 +00:00
n1474335
e43e010163 Merge branch 'nodejs16' of https://github.com/john19696/CyberChef into john19696-nodejs16 2022-03-25 13:26:31 +00:00
n1073645
2a5cee0bd3 9.32.4 2022-03-23 09:31:17 +00:00
n1073645
c962bb79f5 Updated Dependencies 2022-03-23 09:28:32 +00:00
John L
add745551b WIP 2022-02-11 16:56:58 +00:00
john19696
7b8213e1f6
Merge pull request #3 from john19696/nodejs16
Nodejs16 upgrade
2022-02-11 13:04:49 +00:00
John L
2e23a33dfc Merge branch 'nodejs16' of https://github.com/john19696/CyberChef into nodejs16 2022-02-04 11:03:05 +00:00
John L
bca296ee37 GitHub actions update 2022-02-04 11:02:52 +00:00
John L
2dbd647868 nodeFlags needs quote change 2022-01-31 11:39:17 +00:00
john19696
2991e7d1fe
Update Gruntfile.js
add nodeFlags
2022-01-31 10:31:19 +00:00
John L
f6f12fc193 chromedriver update 2022-01-27 17:18:31 +00:00
john19696
1fac8c1cea
Merge pull request #1 from t-8ch/nodejs16
Node 16 compatibility
2022-01-21 15:05:16 +00:00
Adam K Dean
590462e2e4
Fixed Crown Copyright link
Closes #1310
2022-01-18 22:07:59 +00: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
Michael Rowley
ed542582f9 Added more error-handling to ToUpperCase() 2021-12-29 19:59:48 +00:00
Michael Rowley
2574a63975 Minor adjustments 2021-12-29 19:32:39 +00:00
ElJeffe
291c55befd
Spelling
Someone noticed this in another project that includes CyberChef
2021-12-14 08:47:55 -05:00
Philipp Arnold
23763363ba Added a JSON to YAML and a YALM to JSON operation 2021-12-10 23:22:57 +01:00
CPlusSharp
b7a978505f PEMToHex: add magic check so it gets found 2021-11-17 20:19:42 +01:00
Thomas Weißschuh
7db1f39473 base45: Implement highlighting 2021-11-09 21:12:49 +01:00
Thomas Weißschuh
6017578964 Add Base45 operations
Closes #1219

Co-developed-by: Cyril Delétré <cyril.deletre@gmail.com>
2021-11-09 21:12:44 +01:00
CPlusSharp
1dbcd2ac84 PEMtoHex: Support arbitrary PEMs
previous implementation only supported some PEMs (e.g. Certificate)

the new implementation is more general,
it just extracts the base64 between
header and footer and decodes that to hex
2021-11-07 11:21:17 +01:00
Peter Jacobs
671ae6558f Added 'LZString Decompress' and 'LZString Compress' operations 2021-10-29 15:26:31 -05:00
Alex Chambers_Jones
d2174725a9 Fixed reflected XSS described in issue 1265 2021-10-29 17:59:02 +01:00
Wingless-Archangel
f630c499d5
Update .gitignore
add .node-version file for supporting [nodeenv](https://github.com/ekalinin/nodeenv)
2021-10-29 14:41:35 +02:00
MikeCAT
e8f91316ff Added ROT13/47 Brute Force 2021-10-20 21:28:48 +09:00
MikeCAT
a7cdb095d2 Added input validation to fromBase64() 2021-10-04 22:39:16 +09:00
Thomas Weißschuh
cfc29ef821 Always use mjs imports
This is needed for Node/NPM 16 compat
2021-09-17 08:48:04 +02:00
Thomas Weißschuh
83c6775038 Support json modules
This is need for builds on Node/NPM 16
2021-09-17 08:45:56 +02:00
n1474335
ae1b12c120 9.32.3 2021-09-03 14:58:53 +01:00
n1474335
c423de545f Switch XOR input and output differential logic. Fixes #1155 2021-09-03 14:58:48 +01:00
n1474335
84011371b7 9.32.2 2021-08-26 16:51:50 +01:00
n1474335
f831ec6b7e Fixed issues in Protobuf parsing 2021-08-26 16:51:42 +01:00
n1474335
05bfa9158d 9.32.1 2021-08-19 12:06:30 +01:00
n1474335
649016bc85 Updated dependencies 2021-08-19 12:06:26 +01:00
n1474335
7492b874cf 9.32.0 2021-08-18 17:23:43 +01:00
n1474335
9ea21af61f Updated CHANGELOG 2021-08-18 17:23:38 +01:00
n1474335
dd18e52993 Protobuf operations improved to enable full and partial schema support 2021-08-18 17:22:09 +01:00
Gitoffthelawn
7712ee7f35
Improved consistency
Changed "or" to "and" because all the other sentence sections use "and".
2021-08-11 01:55:47 -07:00
n1474335
a4a13666e6 9.31.0 2021-08-10 16:51:28 +01:00
n1474335
07ef4da892 Updated CHANGELOG 2021-08-10 16:50:59 +01:00
n1474335
e9ca4dc9ca Added HASSH operations 2021-08-10 16:48:35 +01:00
n1474335
57bb8fbc45 9.30.0 2021-08-10 15:00:10 +01:00
n1474335
9175624210 Updated CHANGELOG 2021-08-10 15:00:04 +01:00
n1474335
289a417dfb Added 'JA3S Fingerprint' operation 2021-08-10 14:57:34 +01:00
n1474335
8379a9b275 Skipping UI tests in GitHub Actions 2021-08-10 14:26:33 +01:00
n1474335
5b1fad118f Fixed chromedriver path 2021-07-28 15:56:01 +01:00
n1474335
5e8985810e 9.29.2 2021-07-28 15:35:29 +01:00
n1474335
d2568e2a29 Updated dependencies 2021-07-28 15:35:24 +01:00
n1474335
6dfc21ef06 9.29.1 2021-07-28 14:58:17 +01:00
n1474335
1f19f2f58c Updated chromedriver 2021-07-28 14:58:09 +01:00
n1474335
1728cc7a85 9.29.0 2021-07-28 14:37:05 +01:00
n1474335
fa2fc2ba33 Updated CHANGELOG 2021-07-28 14:36:14 +01:00
n1474335
9a33498fed Added 'TLS JA3 Fingerprint' operation 2021-07-28 14:32:39 +01:00
Alfred Berg
5001adf221 Xpath accept slightly malformed xml (html) 2021-05-13 17:36:50 +02:00
Evan Reichard
cd4e70b24b Fixed right shift 32 problem 2021-05-03 21:07:58 -04:00
n1474335
a3b873fd96 9.28.0 2021-03-26 14:09:51 +00:00
n1474335
97bd03799e Updated CHANGELOG 2021-03-26 14:09:37 +00:00
n1474335
ffaaaae2b4 Merge branch 'Danh4-issue-991' 2021-03-26 14:07:18 +00:00
n1474335
ff88d30d2f Tidied up CBOR operations 2021-03-26 14:07:02 +00:00
n1474335
88e3c2ccb2 Merge branch 'issue-991' of https://github.com/Danh4/CyberChef into Danh4-issue-991 2021-03-26 13:59:16 +00:00
swesven
6155634d3b Add the SM4 block cipher, also a no-padding option for block ciphers.
This adds an implementation of the SM4 block cipher, and operations
to encrypt and decrypt using it with CBC,ECB,CFB,OFB,CTR modes.

Also, a "no padding" option is added for AES,DES,3DES and SM4
decryption in ECB/CBC modes. This variant does not attempt to
validate the last block as being PKCS#7 padded.

This is useful, both since other padding schemes exist, and also
for decrypting data where the final block is missing.
2021-03-24 00:58:54 +01:00
n1474335
5029356514 Added link to FAQ description about output handling 2021-03-05 10:50:38 +00:00
n1474335
e57d5a7e75 9.27.6 2021-02-23 15:11:22 +00:00
n1474335
2bbe54cdcd Added further deconstruction of IPv6 Multicast Addresses in the 'Parse IPv6 Address' operation 2021-02-23 15:11:16 +00:00
n1474335
0e2423c390 9.27.5 2021-02-22 19:33:56 +00:00
n1474335
8fadad5891 AES Additional data can now be entered in a range of formats. #1011 2021-02-22 19:33:52 +00:00
n1474335
32455cd20f 9.27.4 2021-02-22 19:13:47 +00:00
n1474335
1e0e7f16a7 Added numeric validation for arguments in Binary and Hex operattions. Fixes #1178 2021-02-22 19:13:38 +00:00
n1474335
95884d77cf Extractable file formats are now listed properly in the 'Extract Files' description 2021-02-17 15:01:42 +00:00
n1474335
b69373f5e7 Fixed 'JSON to CSV' data flattening. 2021-02-16 14:48:56 +00:00
n1474335
61e85474d3 9.27.3 2021-02-16 14:36:36 +00:00
n1474335
3a9bdc58af Fixed 'JSON to CSV' handling of complex structures. Closes #637 2021-02-16 14:36:31 +00:00
n1474335
59c1c45d78 Updated dependencies 2021-02-16 14:17:09 +00:00
n1474335
b5f6cedd30 9.27.2 2021-02-16 14:12:18 +00:00
n1474335
c879af6860 Fixed 'Save recipe' URL generation issue. Closes #1176 2021-02-16 14:12:14 +00:00
n1474335
22fe5a6ae7 9.27.1 2021-02-12 17:55:36 +00:00
n1474335
57714c86a6 Escape HTML input in Fuzzy Match operation 2021-02-12 17:55:28 +00:00
n1474335
70cd375049 9.27.0 2021-02-12 13:54:52 +00:00
n1474335
e27e1dd42f Updated CHANGELOG 2021-02-12 13:53:59 +00:00
n1474335
8ad18bc7db Added 'Fuzzy Match' operation 2021-02-12 13:51:51 +00:00
n1474335
5893ac1a37 9.26.3 2021-02-12 12:12:08 +00:00
n1474335
83c3ab97f9 Merge branch 'n1073645-base64Alphabets' 2021-02-12 12:11:53 +00:00
n1474335
9b6be140fa Merge branch 'base64Alphabets' of https://github.com/n1073645/CyberChef into n1073645-base64Alphabets 2021-02-12 12:08:56 +00:00
n1474335
a6a60392c2 9.26.2 2021-02-12 12:05:03 +00:00
n1474335
ccfa0b991e Updated dependencies 2021-02-12 12:04:59 +00:00
n1474335
73b0e68993 Added code quality badge to README 2021-02-12 11:54:54 +00:00
n1474335
31a4eef001 9.26.1 2021-02-11 19:06:58 +00:00
n1474335
d6e2c9a6b9 Merge branch 'n1073645-HexdumpAsciiFix' 2021-02-11 19:06:47 +00:00
n1474335
e069f5db13 Tidied up hexdump UNIX format 2021-02-11 19:06:35 +00:00
n1474335
96b59cf0df Merge branch 'HexdumpAsciiFix' of https://github.com/n1073645/CyberChef into n1073645-HexdumpAsciiFix 2021-02-11 18:59:51 +00:00
n1474335
c1e1d4b7e3 9.26.0 2021-02-11 18:50:09 +00:00
n1474335
32d869231e Updated CHANGELOG 2021-02-11 18:50:03 +00:00
n1474335
6f95f01dda Merge branch 'n1073645-EPOCH' 2021-02-11 18:47:59 +00:00
n1474335
61a1c44f26 Renamed 'Generate Current Epoch' to 'Get Time'. It now uses the W3C High Resolution Time API and supports microsecond granularity 2021-02-11 18:47:44 +00:00
n1474335
e6c7899569 Merge branch 'EPOCH' of https://github.com/n1073645/CyberChef into n1073645-EPOCH 2021-02-11 18:08:55 +00:00
n1474335
a74a14145e 9.25.0 2021-02-11 18:03:45 +00:00
n1474335
04022b22be Updated CHANGELOG 2021-02-11 18:03:40 +00:00
n1474335
4f3010691c Merge branch 'n1073645-ID3Tags' 2021-02-11 18:01:24 +00:00
n1474335
672b477751 Extract ID3 operation now returns a JSON blob and presents an HTML table 2021-02-11 18:01:08 +00:00
n1474335
19360391a6 Merge branch 'ID3Tags' of https://github.com/n1073645/CyberChef into n1073645-ID3Tags 2021-02-11 16:16:33 +00:00
n1474335
447be8af34 9.24.8 2021-02-11 16:14:48 +00:00
n1474335
0989550e5c Merge branch 'n1073645-keychainExtractor' 2021-02-11 16:14:34 +00:00
n1474335
4d9b48b4d8 Tidied whitespace 2021-02-11 16:14:23 +00:00
n1474335
979652387d Merge branch 'keychainExtractor' of https://github.com/n1073645/CyberChef into n1073645-keychainExtractor 2021-02-11 16:12:57 +00:00
n1474335
de84fbdd1c Renamed workflows 2021-02-10 18:37:46 +00:00
n1474335
170e564319 Fixed incomplete multi-character sanitization and incomplete URL substring sanitization issues. 2021-02-10 17:41:39 +00:00
n1474335
530836876f 9.24.7 2021-02-10 13:13:25 +00:00
n1474335
1abc46058c Added a CodeQL workflow to check for bugs through code analysis. Fixed numerous bugs and implemented safeguards as already reported. 2021-02-10 13:13:19 +00:00
n1474335
892a3716ed Added Crypt lib for common resources 2021-02-09 15:00:35 +00:00
n1474335
5d982a9c8d 9.24.6 2021-02-09 14:50:17 +00:00
n1474335
6206224f1e Merge branch 'alblue-master' 2021-02-09 14:46:19 +00:00
n1474335
766310e2c7 Frequency Distribution operation now displays an HTML table 2021-02-09 14:46:04 +00:00
n1474335
02a397d2ae Merge branch 'master' of https://github.com/alblue/CyberChef into alblue-master 2021-02-09 14:30:03 +00:00
n1474335
4563c86acd 9.24.5 2021-02-09 14:24:08 +00:00
n1474335
0a59f8068e Merge branch 'aussieklutz-master' 2021-02-09 14:23:18 +00:00
n1474335
24548e3a48 Tidied up JWT tests 2021-02-09 14:23:02 +00:00
n1474335
f4784d49e7 Merge branch 'master' of https://github.com/aussieklutz/CyberChef into aussieklutz-master 2021-02-09 14:16:36 +00:00
n1474335
14d5069c6e Merge branch 'mt3571-1073-jwt-verify' 2021-02-09 14:15:12 +00:00
n1474335
9fdd55c5c6 Tidied up JWT ops 2021-02-09 14:14:59 +00:00
n1474335
5bc523aeff Merge branch '1073-jwt-verify' of https://github.com/mt3571/CyberChef into mt3571-1073-jwt-verify 2021-02-09 14:02:21 +00:00
n1474335
3ae2e2e2c8 Fixed highlighting of op names where only the description has hit 2021-02-09 11:50:20 +00:00
n1474335
83e49da7f6 Fixed description hiighlighting issue 2021-02-09 11:37:25 +00:00
n1474335
fe6df8778f Fixed year in CHANGELOG records. Closes #1168 2021-02-09 11:26:00 +00:00
Alex Blewitt
69073c9d99 Add ASCII output for frequency table
When showing results in the frequency distribution table, it's quite
helpful to see the distribution of the ASCII letters, if any. Provide an
option to show this to show the characters alongside the code.

Fixes #1169.

Signed-off-by: Alex Blewitt <alex.blewitt@gmail.com>
2021-02-07 16:22:13 +00:00
aussieklutz
d5a0adea0c
Update JWTVerify.mjs 2021-02-06 18:35:46 +10:00
aussieklutz
1bcb8e433d
Update JWTVerify.mjs 2021-02-06 18:10:54 +10:00
aussieklutz
fa05cf1d78
Update JWTVerify.mjs
Enabled ESRSA verification.
2021-02-06 17:58:49 +10:00
aussieklutz
63dff0d34d
Update JWTVerify.mjs
Enabled validation of ECSHA256 JWT tokens in the tests
2021-02-06 17:55:44 +10:00
aussieklutz
e228b197f9
Update JWTVerify.mjs 2021-02-06 17:45:42 +10:00
aussieklutz
4bbeb6caa3
Update JWTVerify.mjs
Add expectation for working RSASHA256 test, and comment out unused privatekey.
2021-02-06 17:42:42 +10:00
aussieklutz
139d25dff9
Update JWTVerify.mjs
Update RSASHA256 test with the public key derived from the pre-existing private key, and expect a working testcase.
2021-02-06 17:40:04 +10:00
aussieklutz
6984258404
Update JWTVerify.mjs
Enable verification of RSASHA256 and 512 tokens
2021-02-06 17:27:54 +10:00
n1474335
ba66fd6546 Fixed recursive matching arguments 2021-02-05 19:04:27 +00:00
n1474335
47bbefd81f Fixed recursive scoring results in fuzzy match lib 2021-02-05 18:24:15 +00:00
n1474335
50f796049c Fixed search test 2021-02-05 18:07:20 +00:00
n1474335
618da545b1 9.24.4 2021-02-05 17:55:10 +00:00
n1474335
21236f1938 Added fuzzy search for operations 2021-02-05 17:54:57 +00:00
n1474335
4169a15066 9.24.3 2021-02-03 19:07:46 +00:00
n1474335
6b10f61e11 Moved postinstall script to a Grunt task to fix relative calls. npm scripts now use local grunt install. 2021-02-03 19:07:39 +00:00
n1474335
83f119f7e4 9.24.2 2021-02-03 17:54:57 +00:00
n1474335
041c899a35 Comments are now treated as disabled so that they do not interfere with the Dish type. Closes #1126 and #1132. Thanks to @mt3571 for the suggestion. 2021-02-03 17:54:49 +00:00
n1474335
5412fc01b3 Merge branch 'Prinzhorn-base_64_order' 2021-02-02 17:36:23 +00:00
n1474335
76926d9252 Merge branch 'base_64_order' of https://github.com/Prinzhorn/CyberChef into Prinzhorn-base_64_order 2021-02-02 17:36:10 +00:00
n1474335
3270961574 Merge branch 'n1073645-microsoftDecoderMagic' 2021-02-02 17:29:41 +00:00
n1474335
9a1ef71aec Merge branch 'microsoftDecoderMagic' of https://github.com/n1073645/CyberChef into n1073645-microsoftDecoderMagic 2021-02-02 17:29:25 +00:00
n1474335
ba878925ad Merge branch 'Prinzhorn-boolean_args' 2021-02-02 17:23:23 +00:00
n1474335
8d6b71bfaa Merge branch 'boolean_args' of https://github.com/Prinzhorn/CyberChef into Prinzhorn-boolean_args 2021-02-02 17:23:05 +00:00
n1474335
b6845aa03c 9.24.1 2021-02-02 17:18:49 +00:00
n1474335
4a673bd92a AES Decrypt now supports Additional Authenticated Data in GCM mode. Added tests for ADD at each AES size. 2021-02-02 17:18:35 +00:00
n1474335
fdffabfdd4 Merge branch 'n1073645-AESGCMAAD' 2021-02-02 16:11:03 +00:00
n1474335
ba8591293b Merge branch 'AESGCMAAD' of https://github.com/n1073645/CyberChef into n1073645-AESGCMAAD 2021-02-02 16:10:47 +00:00
n1474335
9b3aae10cf 9.24.0 2021-02-02 16:07:57 +00:00
n1474335
5c85c4df63 Updated CHANGELOG 2021-02-02 16:07:52 +00:00
n1474335
8ece2603fb Merge branch 'n1073645-SM3' 2021-02-02 16:06:49 +00:00
n1474335
1b54584820 Tweaks to various hashing functions to improve config options 2021-02-02 16:06:37 +00:00
n1474335
3ce3866000 Merge branch 'SM3' of https://github.com/n1073645/CyberChef into n1073645-SM3 2021-02-02 11:58:36 +00:00
n1474335
becc258b6c Updated CHANGELOG 2021-02-02 11:12:52 +00:00
n1474335
16c9e7119d Updated CHANGELOG 2021-02-02 11:02:23 +00:00
n1474335
f5888fea9c 9.23.1 2021-02-01 19:29:47 +00:00
n1474335
b5162c7549 Merge branch 'maqifrnswa-master' 2021-02-01 19:27:42 +00:00
n1474335
1baea1da3d Merge branch 'master' of https://github.com/maqifrnswa/CyberChef into maqifrnswa-master 2021-02-01 19:27:24 +00:00
mt3571
887ea0cf06 Changed an incorrect name 2020-12-01 13:49:34 +00:00
mt3571
3e0525ee9e Added in a new file to store the list of JWT algorithms that can be used, as this error was occurring due to a mismatch between what you could sign and what you could verify 2020-12-01 13:38:01 +00:00
thezero
ed7baf57f0 replace "options" with "arguments", invert global hide-icon if needed 2020-10-21 00:26:30 +02:00
thezero
3bb6a40f82 add button to hide all recipe options 2020-10-19 21:18:02 +02:00
thezero
6b76b7004a add button to hide recipe's options 2020-10-19 21:18:02 +02:00
n1073645
7989f119d3
Linting Modifications 2020-07-16 09:56:30 +01:00
Scott Howard
2e0aa7ae87 Don't pad rail fence decode fixes #1069 2020-07-15 22:05:15 -04:00
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
n1073645
c01ce90e06 Tests Added 2020-07-06 11:20:54 +01:00
n1073645
d68c8cb845 Casing Variations 2020-07-06 10:44:05 +01:00
Benedikt Werner
f5a7db03cd
Base85: Only require 15 continuous base85 chars 2020-06-10 15:50:26 +02:00
hettysymes
88947b9d42 Added operation description note and modified comment formatting 2020-06-08 12:27:40 +01:00
hettysymes
3c68ad1302 Modified control rotor stepping so the next control rotor steps once the previous rotor reaches "O" and added tests 2020-06-07 17:45:17 +01:00
hettysymes
e2b3389da6 Added SIGABA simple test 2020-06-06 19:47:15 +01:00
hettysymes
938385c18b Fixed grunt lint errors 2020-06-06 19:46:42 +01:00
hettysymes
5d01b06877 Added copyright and clarified description 2020-06-06 19:46:42 +01:00
hettysymes
f007c093eb Emulation of the WW2 SIGABA machine
I have created an emulation of the SIGABA machine and have tested it against some test data from a Master's thesis by Miao Ai: https://scholarworks.sjsu.edu/cgi/viewcontent.cgi?article=1237&context=etd_projects
2020-06-06 19:46:42 +01:00
n1073645
7526f4d7b1 Generate Epoch Time Operation Added 2020-06-01 13:47:51 +01: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
fae96af17d Info for sm3 added 2020-04-24 14:13:55 +01:00
n1073645
57c1a03c4f Option structures added for hashing algorithms 2020-04-24 14:04:13 +01:00
Alexander Prinzhorn
cb8fe42c66 Put Base64 after Base62 2020-04-16 10:20:38 +02:00
Alexander Prinzhorn
7f4b2574b0 Use proper booleans instead of relying on truthy/falsy values 2020-04-16 09:59:43 +02:00
n1073645
cc35127459 AAD for AES Added 2020-04-07 13:03:24 +01:00
n1073645
1f0fddd0e9 Added magic signature to Microsoft Script Decoder 2020-04-07 10:33:15 +01:00
n1073645
cd8a85975c Info and description 2020-04-02 15:59:58 +01:00
n1073645
2f94ec20b0 Added to categories 2020-04-02 15:58:03 +01:00
n1073645
09d9deae43 ID3 Extractor Added. 2020-04-02 15:43:55 +01:00
71819
209fc07eac Issue 991: Add CBOR Decode operation 2020-03-30 11:31:25 +01:00
71819
ae70cb89ed Issue 991: Add CBOR Encode operation 2020-03-30 11:31:25 +01:00
n1073645
bda36e508a Regexes for magic for the new alphabets 2020-03-27 13:27:56 +00:00
n1073645
d2ea1273da Merge remote-tracking branch 'upstream/master' into base64Alphabets 2020-03-27 13:09:03 +00:00
n1073645
2e0af64ac3 PGP secring signatures and Mac OS X keyring extractor added 2020-03-17 14:53:05 +00:00
n1073645
30bc8dfbe9 UNIX Format Added for ToHexdump 2020-03-13 10:38:37 +00:00
n1073645
53a579028c Added only ASCII flag to ToHexdump 2020-03-12 09:30:48 +00: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
3a2580fbc2 Extra Base64 Alphabets 2020-01-22 10:35:11 +00:00
Andy Wang
81605b2222 Grammar typo 2020-01-11 10:47:40 +00:00
Andy Wang
9e17825b53 Add variable key size tests 2020-01-09 15:15:01 +00:00
Andy Wang
c689cf7f13 Fix #930 by allowing variable key sizes 2020-01-09 15:14:33 +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
Oshawk
518b336431 Add tests to index
Added tests to index.
2019-10-21 21:01:33 +01:00
Oshawk
b125f82784 Add tests
Added tests for 'Drop nth bytes' operation.
2019-10-21 20:59:04 +01:00
Oshawk
30349dbcb9 Add operation
Added 'Drop nth bytes' operation.
2019-10-21 20:44:57 +01:00
Oshawk
02f6537973 Add tests
Added tests for the 'Take nth byte' operation.
2019-10-21 20:16:14 +01:00
Oshawk
502f126986 Fix linting
Fixed linting.
2019-10-21 20:15:45 +01:00
Oshawk
7c7d1823ca Fix formatting issue
Fixed issue where new lines were truncated.
2019-10-21 19:53:57 +01:00
Oshawk
ce6d38860d Add operation
Added 'Take nth bytes' operation.
2019-10-21 19:39:01 +01:00
Kyle Parrish
3546ee30a2
Update escaped chars 2019-10-07 16:09:22 -04:00
Alan C
794e0effba Add "To Float" and "From Float" operations 2019-10-07 20:02:28 +08:00
Kyle Parrish
cd15a8c406
Create FangURL.mjs 2019-10-02 09:58:28 -04:00
Kyle Parrish
be2080259e
Add Fang URL to categories 2019-10-02 09:57:50 -04:00
Karsten Silkenbäumer
55cac17456 Change author URL 2019-03-03 17:19:07 +01:00
Karsten Silkenbäumer
846e84d3a4 Add fernet encryption/decryption operation 2019-03-03 16:41:00 +01:00
GCHQ 77703
822a4fab86 Fix operation linting 2019-02-19 10:16:51 +00:00
GCHQ 77703
44a164ed28 Fix test script linter 2019-02-19 09:56:38 +00:00
GCHQ 77703
1f09c03d48 Add De Bruijn Operation 2019-02-15 14:23:16 +00:00
514 changed files with 58894 additions and 17032 deletions

17
.cspell.json Normal file
View file

@ -0,0 +1,17 @@
{
"version": "0.2",
"language": "en,en-gb",
"words": [],
"dictionaries": [
"npm",
"softwareTerms",
"node",
"html",
"css",
"bash",
"en-gb",
"misc"
],
"ignorePaths": ["package.json", "package-lock.json", "node_modules"]
}

View file

@ -0,0 +1,41 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
{
"name": "CyberChef",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18-bookworm",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/github-cli": "latest"
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [8080],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": {
"npm": "bash -c \"sudo chown node node_modules && npm install\""
},
"containerEnv": {
"DISPLAY": ":99"
},
"mounts": [
"source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
],
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"GitHub.vscode-github-actions"
]
}
}
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
node_modules
build

View file

@ -1 +0,0 @@
src/core/vendor/**

View file

@ -1,115 +0,0 @@
{
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 9,
"ecmaFeatures": {
"impliedStrict": true
},
"sourceType": "module",
"allowImportExportEverywhere": true
},
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"rules": {
// enable additional rules
"no-eval": "error",
"no-implied-eval": "error",
"dot-notation": "error",
"eqeqeq": ["error", "smart"],
"no-caller": "error",
"no-extra-bind": "error",
"no-unused-expressions": "error",
"no-useless-call": "error",
"no-useless-return": "error",
"radix": "warn",
// modify rules from base configurations
"no-unused-vars": ["error", {
"args": "none",
"vars": "all"
}],
"no-empty": ["error", {
"allowEmptyCatch": true
}],
// disable rules from base configurations
"no-control-regex": "off",
"require-atomic-updates": "off",
"no-async-promise-executor": "off",
// stylistic conventions
"brace-style": ["error", "1tbs"],
"space-before-blocks": ["error", "always"],
"block-spacing": "error",
"array-bracket-spacing": "error",
"comma-spacing": "error",
"spaced-comment": ["error", "always", { "exceptions": ["/"] } ],
"comma-style": "error",
"computed-property-spacing": "error",
"no-trailing-spaces": "warn",
"eol-last": "error",
"func-call-spacing": "error",
"key-spacing": ["warn", {
"mode": "minimum"
}],
"indent": ["error", 4, {
"ignoreComments": true,
"ArrayExpression": "first",
"SwitchCase": 1
}],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", {
"avoidEscape": true
}],
"camelcase": ["error", {
"properties": "always"
}],
"semi": ["error", "always"],
"unicode-bom": "error",
"require-jsdoc": ["error", {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"ClassDeclaration": true,
"ArrowFunctionExpression": true
}
}],
"keyword-spacing": ["error", {
"before": true,
"after": true
}],
"no-multiple-empty-lines": ["warn", {
"max": 2,
"maxEOF": 1,
"maxBOF": 0
}],
"no-whitespace-before-property": "error",
"operator-linebreak": ["error", "after"],
"space-in-parens": "error",
"no-var": "error",
"prefer-const": "error"
},
"overrides": [
{
"files": "tests/**/*",
"rules": {
"no-unused-expressions": "off",
"no-console": "off"
}
}
],
"globals": {
"$": false,
"jQuery": false,
"log": false,
"app": false,
"COMPILE_TIME": false,
"COMPILE_MSG": false,
"PKG_VERSION": false
}
}

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto eol=lf

40
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: "CodeQL Analysis"
on:
workflow_dispatch:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
types: [synchronize, opened, reopened]
schedule:
- cron: '22 17 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

View file

@ -1,6 +1,7 @@
name: Master
name: "Master Build, Test & Deploy"
on:
workflow_dispatch:
push:
branches:
- master
@ -9,17 +10,18 @@ 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: '10.x'
node-version: '18.x'
- name: Install
run: |
export DETECT_CHROMEDRIVER_VERSION=true
npm install
export NODE_OPTIONS=--max_old_space_size=2048
npm run setheapsize
- name: Lint
run: npx grunt lint
@ -27,18 +29,20 @@ jobs:
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
npm run testnodeconsumer
- name: Production Build
if: success()
run: npx grunt prod
run: npx grunt prod --msg="Version 10 is here! Read about the new features <a href='https://github.com/gchq/CyberChef/wiki/Character-encoding,-EOL-separators,-and-editor-features'>here</a>"
- name: Generate sitemap
run: npx grunt exec:sitemap
- name: UI Tests
if: success()
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
run: |
sudo apt-get install xvfb
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
- name: Prepare for GitHub Pages
if: success()
@ -46,7 +50,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

@ -1,6 +1,7 @@
name: PRs
name: "Pull Requests"
on:
workflow_dispatch:
pull_request:
types: [synchronize, opened, reopened]
@ -8,17 +9,18 @@ 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: '10.x'
node-version: '18.x'
- name: Install
run: |
export DETECT_CHROMEDRIVER_VERSION=true
npm install
export NODE_OPTIONS=--max_old_space_size=2048
npm run setheapsize
- name: Lint
run: npx grunt lint
@ -26,12 +28,28 @@ jobs:
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
npm run testnodeconsumer
- name: Production Build
if: success()
run: npx grunt prod
- name: Production Image Build
if: success()
id: build-image
uses: redhat-actions/buildah-build@v2
with:
# Not being uploaded to any registry, use a simple name to allow Buildah to build correctly.
image: cyberchef
containerfiles: ./Dockerfile
platforms: linux/amd64
oci: true
# Webpack seems to use a lot of open files, increase the max open file limit to accomodate.
extra-args: |
--ulimit nofile=10000
- name: UI Tests
if: success()
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
run: |
sudo apt-get install xvfb
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui

View file

@ -1,25 +1,33 @@
name: Release
name: "Releases"
on:
workflow_dispatch:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
REGISTRY_USER: ${{ github.actor }}
REGISTRY_PASSWORD: ${{ github.token }}
IMAGE_NAME: ${{ github.repository }}
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: '10.x'
node-version: '18.x'
- name: Install
run: |
npm install
export NODE_OPTIONS=--max_old_space_size=2048
export DETECT_CHROMEDRIVER_VERSION=true
npm ci
npm run setheapsize
- name: Lint
run: npx grunt lint
@ -27,18 +35,51 @@ jobs:
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
npm run testnodeconsumer
- name: Production Build
if: success()
run: npx grunt prod
- name: UI Tests
if: success()
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
run: |
sudo apt-get install xvfb
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
- name: Image Metadata
id: image-metadata
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{version}}
- name: Production Image Build
id: build-image
uses: redhat-actions/buildah-build@v2
with:
tags: ${{ steps.image-metadata.outputs.tags }}
labels: ${{ steps.image-metadata.outputs.labels }}
containerfiles: ./Dockerfile
platforms: linux/amd64,linux/arm64
oci: true
# enable build layer caching between platforms
layers: true
# Webpack seems to use a lot of open files, increase the max open file limit to accomodate.
extra-args: |
--ulimit nofile=10000
- name: Publish to GHCR
uses: redhat-actions/push-to-registry@v2
with:
image: ${{ steps.build-image.outputs.image }}
tags: ${{ steps.build-image.outputs.tags }}
registry: ${{ env.REGISTRY }}
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}
- name: Upload Release Assets
if: success()
id: upload-release-assets
uses: svenstaro/upload-release-action@v2
with:
@ -47,9 +88,10 @@ jobs:
tag: ${{ github.ref }}
overwrite: true
file_glob: true
body: "See the [CHANGELOG](https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md) and [commit messages](https://github.com/gchq/CyberChef/commits/master) for details."
- name: Publish to NPM
if: success()
uses: JS-DevTools/npm-publish@v1
if: false
with:
token: ${{ secrets.NPM_TOKEN }}
token: ${{ secrets.NPM_TOKEN }}

3
.gitignore vendored
View file

@ -3,6 +3,7 @@ npm-debug.log
travis.log
build
.vscode
.idea
.*.swp
src/core/config/modules/*
src/core/config/OperationConfig.json
@ -11,4 +12,4 @@ src/node/config/OperationConfig.json
src/node/index.mjs
**/*.DS_Store
tests/browser/output/*
.node-version

2
.nvmrc
View file

@ -1 +1 @@
lts/dubnium
18

View file

@ -1,7 +1,220 @@
# Changelog
## Versioning
CyberChef uses the [semver](https://semver.org/) system to manage versioning: `<MAJOR>.<MINOR>.<PATCH>`.
- MAJOR version changes represent a significant change to the fundamental architecture of CyberChef and may (but don't always) make breaking changes that are not backwards compatible.
- MINOR version changes usually mean the addition of new operations or reasonably significant new features.
- PATCH versions are used for bug fixes and any other small tweaks that modify or improve existing capabilities.
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
## Details
### [10.19.0] - 2024-06-21
- Add support for ECDSA and DSA in 'Parse CSR' [@robinsandhu] | [#1828]
- Fix typos in SIGABA.mjs [@eltociear] | [#1834]
### [10.18.0] - 2024-04-24
- Added 'XXTEA Encrypt' and 'XXTEA Decrypt' operations [@n1474335] | [0a353ee]
### [10.17.0] - 2024-04-13
- Fix unit test 'expectOutput' implementation [@zb3] | [#1783]
- Add accessibility labels for icons [@e218736] | [#1743]
- Add focus styling for keyboard navigation [@e218736] | [#1739]
- Add support for operation option hiding [@TheZ3ro] | [#541]
- Improve efficiency of RAKE implementation [@sw5678] | [#1751]
- Require (a, 26) to be coprime in 'Affine Encode' [@EvieHarv] | [#1788]
- Added 'JWK to PEM' operation [@cplussharp] | [#1277]
- Added 'PEM to JWK' operation [@cplussharp] | [#1277]
- Added 'Public Key from Certificate' operation [@cplussharp] | [#1642]
- Added 'Public Key from Private Key' operation [@cplussharp] | [#1642]
### [10.16.0] - 2024-04-12
- Added 'JA4Server Fingerprint' operation [@n1474335] | [#1789]
### [10.15.0] - 2024-04-02
- Fix Ciphersaber2 key concatenation [@zb3] | [#1765]
- Fix DeriveEVPKey's array parsing [@zb3] | [#1767]
- Fix JWT operations [@a3957273] | [#1769]
- Added 'Parse Certificate Signing Request' operation [@jkataja] | [#1504]
- Added 'Extract Hash Values' operation [@MShwed] | [#512]
- Added 'DateTime Delta' operation [@tomgond] | [#1732]
### [10.14.0] - 2024-03-31
- Added 'To Float' and 'From Float' operations [@tcode2k16] | [#1762]
- Fix ChaCha raw export option [@joostrijneveld] | [#1606]
- Update x86 disassembler vendor library [@evanreichard] | [#1197]
- Allow variable Blowfish key sizes [@cbeuw] | [#933]
- Added 'XXTEA' operation [@devcydo] | [#1361]
### [10.13.0] - 2024-03-30
- Added 'FangURL' operation [@breakersall] [@arnydo] | [#1591] [#654]
### [10.12.0] - 2024-03-29
- Added 'Salsa20' and 'XSalsa20' operation [@joostrijneveld] | [#1750]
### [10.11.0] - 2024-03-29
- Add HEIC/HEIF file signatures [@simonw] | [#1757]
- Update xmldom to fix medium security vulnerability [@chriswhite199] | [#1752]
- Update JSONWebToken to fix medium security vulnerability [@chriswhite199] | [#1753]
### [10.10.0] - 2024-03-27
- Added 'JA4 Fingerprint' operation [@n1474335] | [#1759]
### [10.9.0] - 2024-03-26
- Line ending sequences and UTF-8 character encoding are now detected automatically [@n1474335] | [65ffd8d]
### [10.8.0] - 2024-02-13
- Add official Docker images [@AshCorr] | [#1699]
### [10.7.0] - 2024-02-09
- Added 'File Tree' operation [@sw5678] | [#1667]
- Added 'RISON' operation [@sg5506844] | [#1555]
- Added 'MurmurHash3' operation [@AliceGrey] | [#1694]
### [10.6.0] - 2024-02-03
- Updated 'Forensics Wiki' URLs to new domain [@a3957273] | [#1703]
- Added 'LZNT1 Decompress' operation [@0xThiebaut] | [#1675]
- Updated 'Regex Expression' UUID matcher [@cnotin] | [#1678]
- Removed duplicate 'hover' message within baking info [@KevinSJ] | [#1541]
### [10.5.0] - 2023-07-14
- Added GOST Encrypt, Decrypt, Sign, Verify, Key Wrap, and Key Unwrap operations [@n1474335] | [#592]
### [10.4.0] - 2023-03-24
- Added 'Generate De Bruijn Sequence' operation [@gchq77703] | [#493]
### [10.3.0] - 2023-03-24
- Added 'Argon2' and 'Argon2 compare' operations [@Xenonym] | [#661]
### [10.2.0] - 2023-03-23
- Added 'Derive HKDF key' operation [@mikecat] | [#1528]
### [10.1.0] - 2023-03-23
- Added 'Levenshtein Distance' operation [@mikecat] | [#1498]
- Added 'Swap case' operation [@mikecat] | [#1499]
## [10.0.0] - 2023-03-22
- [Full details explained here](https://github.com/gchq/CyberChef/wiki/Character-encoding,-EOL-separators,-and-editor-features)
- Status bars added to the Input and Output [@n1474335] | [#1405]
- Character encoding selection added to the Input and Output [@n1474335] | [#1405]
- End of line separator selection added to the Input and Output [@n1474335] | [#1405]
- Non-printable characters are rendered as control character pictures [@n1474335] | [#1405]
- Loaded files can now be edited in the Input [@n1474335] | [#1405]
- Various editor features added such as multiple selections and bracket matching [@n1474335] | [#1405]
- Contextual help added, activated by pressing F1 while hovering over features [@n1474335] | [#1405]
- Many, many UI tests added for I/O features and operations [@n1474335] | [#1405]
<details>
<summary>Click to expand v9 minor versions</summary>
### [9.55.0] - 2022-12-09
- Added 'AMF Encode' and 'AMF Decode' operations [@n1474335] | [760eff4]
### [9.54.0] - 2022-11-25
- Added 'Rabbit' operation [@mikecat] | [#1450]
### [9.53.0] - 2022-11-25
- Added 'AES Key Wrap' and 'AES Key Unwrap' operations [@mikecat] | [#1456]
### [9.52.0] - 2022-11-25
- Added 'ChaCha' operation [@joostrijneveld] | [#1466]
### [9.51.0] - 2022-11-25
- Added 'CMAC' operation [@mikecat] | [#1457]
### [9.50.0] - 2022-11-25
- Added 'Shuffle' operation [@mikecat] | [#1472]
### [9.49.0] - 2022-11-11
- Added 'LZ4 Compress' and 'LZ4 Decompress' operations [@n1474335] | [31a7f83]
### [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]
### [9.38.0] - 2022-05-30
- Added 'Parse TCP' operation [@n1474335] | [a895d1d]
### [9.37.0] - 2022-03-29
- 'SM4 Encrypt' and 'SM4 Decrypt' operations added [@swesven] | [#1189]
- NoPadding options added for CBC and ECB modes in AES, DES and Triple DES Decrypt operations [@swesven] | [#1189]
### [9.36.0] - 2022-03-29
- 'SIGABA' operation added [@hettysymes] | [#934]
### [9.35.0] - 2022-03-28
- 'To Base45' and 'From Base45' operations added [@t-8ch] | [#1242]
### [9.34.0] - 2022-03-28
- 'Get All Casings' operation added [@n1073645] | [#1065]
### [9.33.0] - 2022-03-25
- Updated to support Node 17 [@n1474335] [@john19696] [@t-8ch] | [[#1326] [#1313] [#1244]
- Improved CJS and ESM module support [@d98762625] | [#1037]
### [9.32.0] - 2021-08-18
- 'Protobuf Encode' operation added and decode operation modified to allow decoding with full and partial schemas [@n1474335] | [dd18e52]
### [9.31.0] - 2021-08-10
- 'HASSH Client Fingerprint' and 'HASSH Server Fingerprint' operations added [@n1474335] | [e9ca4dc]
### [9.30.0] - 2021-08-10
- 'JA3S Fingerprint' operation added [@n1474335] | [289a417]
### [9.29.0] - 2021-07-28
- 'JA3 Fingerprint' operation added [@n1474335] | [9a33498]
### [9.28.0] - 2021-03-26
- 'CBOR Encode' and 'CBOR Decode' operations added [@Danh4] | [#999]
### [9.27.0] - 2021-02-12
- 'Fuzzy Match' operation added [@n1474335] | [8ad18b]
### [9.26.0] - 2021-02-11
- 'Get Time' operation added [@n1073645] [@n1474335] | [#1045]
### [9.25.0] - 2021-02-11
- 'Extract ID3' operation added [@n1073645] [@n1474335] | [#1006]
### [9.24.0] - 2021-02-02
- 'SM3' hashing function added along with more configuration options for other hashing operations [@n1073645] [@n1474335] | [#1022]
### [9.23.0] - 2021-02-01
- Various RSA operations added to encrypt, decrypt, sign, verify and generate keys [@mattnotmitt] [@GCHQ77703] | [#652]
### [9.22.0] - 2021-02-01
- 'Unicode Text Format' operation added [@mattnotmitt] | [#1083]
### [9.21.0] - 2020-06-12
- Node API now exports `magic` operation [@d98762625] | [#1049]
@ -66,6 +279,8 @@ All major and minor version changes will be documented in this file. Details of
- 'Parse SSH Host Key' operation added [@j433866] | [#595]
- 'Defang IP Addresses' operation added [@h345983745] | [#556]
</details>
## [9.0.0] - 2019-07-09
- [Multiple inputs](https://github.com/gchq/CyberChef/wiki/Multiple-Inputs) are now supported in the main web UI, allowing you to upload and process multiple files at once [@j433866] | [#566]
- A [Node.js API](https://github.com/gchq/CyberChef/wiki/Node-API) has been implemented, meaning that CyberChef can now be used as a library, either to provide specific operations, or an entire baking environment [@d98762625] | [#291]
@ -74,7 +289,7 @@ All major and minor version changes will be documented in this file. Details of
<details>
<summary>Click to expand v8 minor versions</summary>
### [8.38.0] - 2019-07-03
- 'Streebog' and 'GOST hash' operations added [@MShwed] [@n1474335] | [#530]
@ -225,8 +440,61 @@ All major and minor version changes will be documented in this file. Details of
## [4.0.0] - 2016-11-28
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
[10.19.0]: https://github.com/gchq/CyberChef/releases/tag/v10.19.0
[10.18.0]: https://github.com/gchq/CyberChef/releases/tag/v10.18.0
[10.17.0]: https://github.com/gchq/CyberChef/releases/tag/v10.17.0
[10.16.0]: https://github.com/gchq/CyberChef/releases/tag/v10.16.0
[10.15.0]: https://github.com/gchq/CyberChef/releases/tag/v10.15.0
[10.14.0]: https://github.com/gchq/CyberChef/releases/tag/v10.14.0
[10.13.0]: https://github.com/gchq/CyberChef/releases/tag/v10.13.0
[10.12.0]: https://github.com/gchq/CyberChef/releases/tag/v10.12.0
[10.11.0]: https://github.com/gchq/CyberChef/releases/tag/v10.11.0
[10.10.0]: https://github.com/gchq/CyberChef/releases/tag/v10.10.0
[10.9.0]: https://github.com/gchq/CyberChef/releases/tag/v10.9.0
[10.8.0]: https://github.com/gchq/CyberChef/releases/tag/v10.7.0
[10.7.0]: https://github.com/gchq/CyberChef/releases/tag/v10.7.0
[10.6.0]: https://github.com/gchq/CyberChef/releases/tag/v10.6.0
[10.5.0]: https://github.com/gchq/CyberChef/releases/tag/v10.5.0
[10.4.0]: https://github.com/gchq/CyberChef/releases/tag/v10.4.0
[10.3.0]: https://github.com/gchq/CyberChef/releases/tag/v10.3.0
[10.2.0]: https://github.com/gchq/CyberChef/releases/tag/v10.2.0
[10.1.0]: https://github.com/gchq/CyberChef/releases/tag/v10.1.0
[10.0.0]: https://github.com/gchq/CyberChef/releases/tag/v10.0.0
[9.55.0]: https://github.com/gchq/CyberChef/releases/tag/v9.55.0
[9.54.0]: https://github.com/gchq/CyberChef/releases/tag/v9.54.0
[9.53.0]: https://github.com/gchq/CyberChef/releases/tag/v9.53.0
[9.52.0]: https://github.com/gchq/CyberChef/releases/tag/v9.52.0
[9.51.0]: https://github.com/gchq/CyberChef/releases/tag/v9.51.0
[9.50.0]: https://github.com/gchq/CyberChef/releases/tag/v9.50.0
[9.49.0]: https://github.com/gchq/CyberChef/releases/tag/v9.49.0
[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
[9.36.0]: https://github.com/gchq/CyberChef/releases/tag/v9.36.0
[9.35.0]: https://github.com/gchq/CyberChef/releases/tag/v9.35.0
[9.34.0]: https://github.com/gchq/CyberChef/releases/tag/v9.34.0
[9.33.0]: https://github.com/gchq/CyberChef/releases/tag/v9.33.0
[9.32.0]: https://github.com/gchq/CyberChef/releases/tag/v9.32.0
[9.31.0]: https://github.com/gchq/CyberChef/releases/tag/v9.31.0
[9.30.0]: https://github.com/gchq/CyberChef/releases/tag/v9.30.0
[9.29.0]: https://github.com/gchq/CyberChef/releases/tag/v9.29.0
[9.28.0]: https://github.com/gchq/CyberChef/releases/tag/v9.28.0
[9.27.0]: https://github.com/gchq/CyberChef/releases/tag/v9.27.0
[9.26.0]: https://github.com/gchq/CyberChef/releases/tag/v9.26.0
[9.25.0]: https://github.com/gchq/CyberChef/releases/tag/v9.25.0
[9.24.0]: https://github.com/gchq/CyberChef/releases/tag/v9.24.0
[9.23.0]: https://github.com/gchq/CyberChef/releases/tag/v9.23.0
[9.22.0]: https://github.com/gchq/CyberChef/releases/tag/v9.22.0
[9.21.0]: https://github.com/gchq/CyberChef/releases/tag/v9.21.0
[9.20.0]: https://github.com/gchq/CyberChef/releases/tag/v9.20.0
[9.19.0]: https://github.com/gchq/CyberChef/releases/tag/v9.19.0
[9.18.0]: https://github.com/gchq/CyberChef/releases/tag/v9.18.0
@ -326,6 +594,54 @@ All major and minor version changes will be documented in this file. Details of
[@pointhi]: https://github.com/pointhi
[@MarvinJWendt]: https://github.com/MarvinJWendt
[@dmfj]: https://github.com/dmfj
[@mattnotmitt]: https://github.com/mattnotmitt
[@Danh4]: https://github.com/Danh4
[@john19696]: https://github.com/john19696
[@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
[@joostrijneveld]: https://github.com/joostrijneveld
[@Xenonym]: https://github.com/Xenonym
[@gchq77703]: https://github.com/gchq77703
[@a3957273]: https://github.com/a3957273
[@0xThiebaut]: https://github.com/0xThiebaut
[@cnotin]: https://github.com/cnotin
[@KevinSJ]: https://github.com/KevinSJ
[@sw5678]: https://github.com/sw5678
[@sg5506844]: https://github.com/sg5506844
[@AliceGrey]: https://github.com/AliceGrey
[@AshCorr]: https://github.com/AshCorr
[@simonw]: https://github.com/simonw
[@chriswhite199]: https://github.com/chriswhite199
[@breakersall]: https://github.com/breakersall
[@evanreichard]: https://github.com/evanreichard
[@devcydo]: https://github.com/devcydo
[@zb3]: https://github.com/zb3
[@jkataja]: https://github.com/jkataja
[@tomgond]: https://github.com/tomgond
[@e218736]: https://github.com/e218736
[@TheZ3ro]: https://github.com/TheZ3ro
[@EvieHarv]: https://github.com/EvieHarv
[@cplussharp]: https://github.com/cplussharp
[@robinsandhu]: https://github.com/robinsandhu
[@eltociear]: https://github.com/eltociear
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
[289a417]: https://github.com/gchq/CyberChef/commit/289a417dfb5923de5e1694354ec42a08d9395bfe
[e9ca4dc]: https://github.com/gchq/CyberChef/commit/e9ca4dc9caf98f33fd986431cd400c88082a42b8
[dd18e52]: https://github.com/gchq/CyberChef/commit/dd18e529939078b89867297b181a584e8b2cc7da
[a895d1d]: https://github.com/gchq/CyberChef/commit/a895d1d82a2f92d440a0c5eca2bc7c898107b737
[31a7f83]: https://github.com/gchq/CyberChef/commit/31a7f83b82e78927f89689f323fcb9185144d6ff
[760eff4]: https://github.com/gchq/CyberChef/commit/760eff49b5307aaa3104c5e5b437ffe62299acd1
[65ffd8d]: https://github.com/gchq/CyberChef/commit/65ffd8d65d88eb369f6f61a5d1d0f807179bffb7
[0a353ee]: https://github.com/gchq/CyberChef/commit/0a353eeb378b9ca5d49e23c7dfc175ae07107b08
[#95]: https://github.com/gchq/CyberChef/pull/299
[#173]: https://github.com/gchq/CyberChef/pull/173
@ -387,14 +703,79 @@ All major and minor version changes will be documented in this file. Details of
[#625]: https://github.com/gchq/CyberChef/pull/625
[#627]: https://github.com/gchq/CyberChef/pull/627
[#632]: https://github.com/gchq/CyberChef/pull/632
[#652]: https://github.com/gchq/CyberChef/pull/652
[#653]: https://github.com/gchq/CyberChef/pull/653
[#674]: https://github.com/gchq/CyberChef/pull/674
[#683]: https://github.com/gchq/CyberChef/pull/683
[#865]: https://github.com/gchq/CyberChef/pull/865
[#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
[#987]: https://github.com/gchq/CyberChef/pull/987
[#999]: https://github.com/gchq/CyberChef/pull/999
[#1006]: https://github.com/gchq/CyberChef/pull/1006
[#1022]: https://github.com/gchq/CyberChef/pull/1022
[#1037]: https://github.com/gchq/CyberChef/pull/1037
[#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
[#1244]: https://github.com/gchq/CyberChef/pull/1244
[#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
[#1405]: https://github.com/gchq/CyberChef/pull/1405
[#1421]: https://github.com/gchq/CyberChef/pull/1421
[#1427]: https://github.com/gchq/CyberChef/pull/1427
[#1472]: https://github.com/gchq/CyberChef/pull/1472
[#1457]: https://github.com/gchq/CyberChef/pull/1457
[#1466]: https://github.com/gchq/CyberChef/pull/1466
[#1456]: https://github.com/gchq/CyberChef/pull/1456
[#1450]: https://github.com/gchq/CyberChef/pull/1450
[#1498]: https://github.com/gchq/CyberChef/pull/1498
[#1499]: https://github.com/gchq/CyberChef/pull/1499
[#1528]: https://github.com/gchq/CyberChef/pull/1528
[#661]: https://github.com/gchq/CyberChef/pull/661
[#493]: https://github.com/gchq/CyberChef/pull/493
[#592]: https://github.com/gchq/CyberChef/issues/592
[#1703]: https://github.com/gchq/CyberChef/issues/1703
[#1675]: https://github.com/gchq/CyberChef/issues/1675
[#1678]: https://github.com/gchq/CyberChef/issues/1678
[#1541]: https://github.com/gchq/CyberChef/issues/1541
[#1667]: https://github.com/gchq/CyberChef/issues/1667
[#1555]: https://github.com/gchq/CyberChef/issues/1555
[#1694]: https://github.com/gchq/CyberChef/issues/1694
[#1699]: https://github.com/gchq/CyberChef/issues/1699
[#1757]: https://github.com/gchq/CyberChef/issues/1757
[#1752]: https://github.com/gchq/CyberChef/issues/1752
[#1753]: https://github.com/gchq/CyberChef/issues/1753
[#1750]: https://github.com/gchq/CyberChef/issues/1750
[#1591]: https://github.com/gchq/CyberChef/issues/1591
[#654]: https://github.com/gchq/CyberChef/issues/654
[#1762]: https://github.com/gchq/CyberChef/issues/1762
[#1606]: https://github.com/gchq/CyberChef/issues/1606
[#1197]: https://github.com/gchq/CyberChef/issues/1197
[#933]: https://github.com/gchq/CyberChef/issues/933
[#1361]: https://github.com/gchq/CyberChef/issues/1361
[#1765]: https://github.com/gchq/CyberChef/issues/1765
[#1767]: https://github.com/gchq/CyberChef/issues/1767
[#1769]: https://github.com/gchq/CyberChef/issues/1769
[#1759]: https://github.com/gchq/CyberChef/issues/1759
[#1504]: https://github.com/gchq/CyberChef/issues/1504
[#512]: https://github.com/gchq/CyberChef/issues/512
[#1732]: https://github.com/gchq/CyberChef/issues/1732
[#1789]: https://github.com/gchq/CyberChef/issues/1789

36
Dockerfile Normal file
View file

@ -0,0 +1,36 @@
#####################################
# Build the app to a static website #
#####################################
# Modifier --platform=$BUILDPLATFORM limits the platform to "BUILDPLATFORM" during buildx multi-platform builds
# This is because npm "chromedriver" package is not compatiable with all platforms
# For more info see: https://docs.docker.com/build/building/multi-platform/#cross-compilation
FROM --platform=$BUILDPLATFORM node:18-alpine AS builder
WORKDIR /app
COPY package.json .
COPY package-lock.json .
# Install dependencies
# --ignore-scripts prevents postinstall script (which runs grunt) as it depends on files other than package.json
RUN npm ci --ignore-scripts
# Copy files needed for postinstall and build
COPY . .
# npm postinstall runs grunt, which depends on files other than package.json
RUN npm run postinstall
# Build the app
RUN npm run build
#########################################
# Package static build files into nginx #
#########################################
# We are using Github Actions: redhat-actions/buildah-build@v2 which needs manual selection of arch in base image
# Remove TARGETARCH if docker buildx is supported in the CI release as --platform=$TARGETPLATFORM will be automatically set
ARG TARGETARCH
ARG TARGETPLATFORM
FROM ${TARGETARCH}/nginx:stable-alpine AS cyberchef
COPY --from=builder /app/build/prod /usr/share/nginx/html/

View file

@ -6,6 +6,8 @@ const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPl
const glob = require("glob");
const path = require("path");
const nodeFlags = "--experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings --no-deprecation";
/**
* Grunt configuration for building the app in various formats.
*
@ -27,7 +29,7 @@ module.exports = function (grunt) {
"Creates a production-ready build. Use the --msg flag to add a compile message.",
[
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "findModules", "webpack:web",
"copy:standalone", "zip:standalone", "clean:standalone", "chmod"
"copy:standalone", "zip:standalone", "clean:standalone", "exec:calcDownloadHash", "chmod"
]);
grunt.registerTask("node",
@ -48,7 +50,7 @@ module.exports = function (grunt) {
grunt.registerTask("testnodeconsumer",
"A task which checks whether consuming CJS and ESM apps work with the CyberChef build",
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:testESMDeepImportNodeConsumer", "exec:teardownNodeConsumers"]);
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:teardownNodeConsumers"]);
grunt.registerTask("default",
"Lints the code base",
@ -84,10 +86,12 @@ module.exports = function (grunt) {
// Project configuration
const compileTime = grunt.template.today("UTC:dd/mm/yyyy HH:MM:ss") + " UTC",
const compileYear = grunt.template.today("UTC:yyyy"),
compileTime = grunt.template.today("UTC:dd/mm/yyyy HH:MM:ss") + " UTC",
pkg = grunt.file.readJSON("package.json"),
webpackConfig = require("./webpack.config.js"),
BUILD_CONSTANTS = {
COMPILE_YEAR: JSON.stringify(compileYear),
COMPILE_TIME: JSON.stringify(compileTime),
COMPILE_MSG: JSON.stringify(grunt.option("compile-msg") || grunt.option("msg") || ""),
PKG_VERSION: JSON.stringify(pkg.version),
@ -123,6 +127,7 @@ module.exports = function (grunt) {
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileYear: compileYear,
compileTime: compileTime,
version: pkg.version,
minify: {
@ -174,7 +179,7 @@ module.exports = function (grunt) {
// previous one fails. & would coninue on a fail
.join("&&")
// Windows does not support \n properly
.replace("\n", "\\n");
.replace(/\n/g, "\\n");
}
grunt.initConfig({
@ -187,9 +192,6 @@ module.exports = function (grunt) {
standalone: ["build/prod/CyberChef*.html"]
},
eslint: {
options: {
configFile: "./.eslintrc.json"
},
configs: ["*.{js,mjs}"],
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
web: ["src/web/**/*.{js,mjs}", "!src/web/static/**/*"],
@ -198,53 +200,41 @@ module.exports = function (grunt) {
},
webpack: {
options: webpackConfig,
myConfig: webpackConfig,
web: webpackProdConf(),
},
"webpack-dev-server": {
options: {
webpack: webpackConfig,
host: "0.0.0.0",
port: grunt.option("port") || 8080,
disableHostCheck: true,
overlay: true,
inline: false,
clientLogLevel: "error",
stats: {
children: false,
chunks: false,
modules: false,
entrypoints: false,
warningsFilter: [
/source-map/,
/dependency is an expression/,
/export 'default'/,
/Can't resolve 'sodium'/
],
}
},
options: webpackConfig,
start: {
webpack: {
mode: "development",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
mode: "development",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
},
devServer: {
port: grunt.option("port") || 8080,
client: {
logging: "error",
overlay: true
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
})
]
}
hot: "only"
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileYear: compileYear,
compileTime: compileTime,
version: pkg.version,
})
]
}
},
zip: {
@ -338,6 +328,22 @@ module.exports = function (grunt) {
}
},
exec: {
calcDownloadHash: {
command: function () {
switch (process.platform) {
case "darwin":
return chainCommands([
`shasum -a 256 build/prod/CyberChef_v${pkg.version}.zip | awk '{print $1;}' > build/prod/sha256digest.txt`,
`sed -i '' -e "s/DOWNLOAD_HASH_PLACEHOLDER/$(cat build/prod/sha256digest.txt)/" build/prod/index.html`
]);
default:
return chainCommands([
`sha256sum build/prod/CyberChef_v${pkg.version}.zip | awk '{print $1;}' > build/prod/sha256digest.txt`,
`sed -i -e "s/DOWNLOAD_HASH_PLACEHOLDER/$(cat build/prod/sha256digest.txt)/" build/prod/index.html`
]);
}
},
},
repoSize: {
command: chainCommands([
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
@ -349,15 +355,15 @@ module.exports = function (grunt) {
command: "git gc --prune=now --aggressive"
},
sitemap: {
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml",
command: `node ${nodeFlags} src/web/static/sitemap.mjs > build/prod/sitemap.xml`,
sync: true
},
generateConfig: {
command: chainCommands([
"echo '\n--- Regenerating config files. ---'",
"echo [] > src/core/config/OperationConfig.json",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
`node ${nodeFlags} src/core/config/scripts/generateOpsIndex.mjs`,
`node ${nodeFlags} src/core/config/scripts/generateConfig.mjs`,
"echo '--- Config scripts finished. ---\n'"
]),
sync: true
@ -365,7 +371,7 @@ module.exports = function (grunt) {
generateNodeIndex: {
command: chainCommands([
"echo '\n--- Regenerating node index ---'",
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
`node ${nodeFlags} src/node/config/scripts/generateNodeIndex.mjs`,
"echo '--- Node index generated. ---\n'"
]),
sync: true
@ -393,24 +399,51 @@ module.exports = function (grunt) {
testCJSNodeConsumer: {
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings cjs-consumer.js",
`node ${nodeFlags} cjs-consumer.js`,
]),
stdout: false,
},
testESMNodeConsumer: {
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-consumer.mjs",
`node ${nodeFlags} esm-consumer.mjs`,
]),
stdout: false,
},
testESMDeepImportNodeConsumer: {
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
]),
stdout: false,
fixCryptoApiImports: {
command: function () {
switch (process.platform) {
case "darwin":
return `find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i '' -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`;
default:
return `find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`;
}
},
stdout: false
},
fixSnackbarMarkup: {
command: function () {
switch (process.platform) {
case "darwin":
return `sed -i '' 's/<div id=snackbar-container\\/>/<div id=snackbar-container>/g' ./node_modules/snackbarjs/src/snackbar.js`;
default:
return `sed -i 's/<div id=snackbar-container\\/>/<div id=snackbar-container>/g' ./node_modules/snackbarjs/src/snackbar.js`;
}
},
stdout: false
},
fixJimpModule: {
command: function () {
switch (process.platform) {
case "darwin":
// Space added before comma to prevent multiple modifications
return `sed -i '' 's/"es\\/index.js",/"es\\/index.js" ,\\n "type": "module",/' ./node_modules/jimp/package.json`;
default:
return `sed -i 's/"es\\/index.js",/"es\\/index.js" ,\\n "type": "module",/' ./node_modules/jimp/package.json`;
}
},
stdout: false
}
},
});
};

View file

@ -1,7 +1,6 @@
# CyberChef
[![Build Status](https://travis-ci.org/gchq/CyberChef.svg?branch=master)](https://travis-ci.org/gchq/CyberChef)
[![dependencies Status](https://david-dm.org/gchq/CyberChef/status.svg)](https://david-dm.org/gchq/CyberChef)
[![](https://github.com/gchq/CyberChef/workflows/Master%20Build,%20Test%20&%20Deploy/badge.svg)](https://github.com/gchq/CyberChef/actions?query=workflow%3A%22Master+Build%2C+Test+%26+Deploy%22)
[![npm](https://img.shields.io/npm/v/cyberchef.svg)](https://www.npmjs.com/package/cyberchef)
[![](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/gchq/CyberChef/blob/master/LICENSE)
[![Gitter](https://badges.gitter.im/gchq/CyberChef.svg)](https://gitter.im/gchq/CyberChef?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
@ -9,7 +8,7 @@
#### *The Cyber Swiss Army Knife*
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR and Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years.
@ -21,6 +20,22 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur
[A live demo can be found here][1] - have fun!
## Containers
If you would like to try out CyberChef locally you can either build it yourself:
```bash
docker build --tag cyberchef --ulimit nofile=10000 .
docker run -it -p 8080:80 cyberchef
```
Or you can use our image directly:
```bash
docker run -it -p 8080:80 ghcr.io/gchq/cyberchef:latest
```
This image is built and published through our [GitHub Workflows](.github/workflows/releases.yml)
## How it works
@ -54,7 +69,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 +81,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 +89,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,14 +105,14 @@ 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" wiki page](https://github.com/gchq/CyberChef/wiki/Node-API)
## 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).
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 ["Contributing" wiki page](https://github.com/gchq/CyberChef/wiki/Contributing).
- Push your changes to your fork.
- Submit a pull request. If you are doing this for the first time, you will be prompted to sign the [GCHQ Contributor Licence Agreement](https://cla-assistant.io/gchq/CyberChef) via the CLA assistant on the pull request. This will also ask whether you are happy for GCHQ to contact you about a token of thanks for your contribution, or about job opportunities at GCHQ.
@ -105,7 +120,7 @@ An installation walkthrough, how-to guides for adding new operations and themes,
## Licencing
CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/licenses/LICENSE-2.0) and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/copyright-and-re-use/crown-copyright/).
CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/licenses/LICENSE-2.0) and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/).
[1]: https://gchq.github.io/CyberChef

View file

@ -11,6 +11,7 @@ module.exports = function(api) {
],
"plugins": [
"dynamic-import-node",
"@babel/plugin-syntax-import-assertions",
[
"babel-plugin-transform-builtin-extend", {
"globals": ["Error"]

129
eslint.config.mjs Executable file
View file

@ -0,0 +1,129 @@
import babelParser from "@babel/eslint-parser";
import jsdoc from "eslint-plugin-jsdoc";
import js from "@eslint/js";
import globals from "globals";
export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2022,
parser: babelParser,
parserOptions: {
ecmaVersion: 2022,
ecmaFeatures: {
impliedStrict: true
},
sourceType: "module",
allowImportExportEverywhere: true
},
globals: {
...globals.browser,
...globals.node,
...globals.es6,
"$": false,
"jQuery": false,
"log": false,
"app": false,
"COMPILE_TIME": false,
"COMPILE_MSG": false,
"PKG_VERSION": false
},
},
ignores: ["src/core/vendor/**"],
plugins: {
jsdoc
},
rules: {
// enable additional rules
"no-eval": "error",
"no-implied-eval": "error",
"dot-notation": "error",
"eqeqeq": ["error", "smart"],
"no-caller": "error",
"no-extra-bind": "error",
"no-unused-expressions": "error",
"no-useless-call": "error",
"no-useless-return": "error",
"radix": "warn",
// modify rules from base configurations
"no-unused-vars": ["error", {
"args": "none",
"vars": "all",
"caughtErrors": "none"
}],
"no-empty": ["error", {
"allowEmptyCatch": true
}],
// disable rules from base configurations
"no-control-regex": "off",
"require-atomic-updates": "off",
"no-async-promise-executor": "off",
// stylistic conventions
"brace-style": ["error", "1tbs"],
"space-before-blocks": ["error", "always"],
"block-spacing": "error",
"array-bracket-spacing": "error",
"comma-spacing": "error",
"spaced-comment": ["error", "always", { "exceptions": ["/"] }],
"comma-style": "error",
"computed-property-spacing": "error",
"no-trailing-spaces": "warn",
"eol-last": "error",
"func-call-spacing": "error",
"key-spacing": ["warn", {
"mode": "minimum"
}],
"indent": ["error", 4, {
"ignoreComments": true,
"ArrayExpression": "first",
"SwitchCase": 1
}],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", {
"avoidEscape": true,
"allowTemplateLiterals": true
}],
"camelcase": ["error", {
"properties": "always"
}],
"semi": ["error", "always"],
"unicode-bom": "error",
"jsdoc/require-jsdoc": ["error", {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"ClassDeclaration": true,
"ArrowFunctionExpression": false
}
}],
"keyword-spacing": ["error", {
"before": true,
"after": true
}],
"no-multiple-empty-lines": ["warn", {
"max": 2,
"maxEOF": 1,
"maxBOF": 0
}],
"no-whitespace-before-property": "error",
"operator-linebreak": ["error", "after"],
"space-in-parens": "error",
"no-var": "error",
"prefer-const": "error",
"no-console": "error"
},
},
// File-pattern specific overrides
{
files: ["tests/**/*"],
rules: {
"no-unused-expressions": "off",
"no-console": "off"
}
},
];

View file

@ -1,5 +1,6 @@
{
"src_folders": ["tests/browser"],
"exclude": ["tests/browser/browserUtils.js"],
"output_folder": "tests/browser/output",
"test_settings": {
@ -10,11 +11,12 @@
"start_process": true,
"server_path": "./node_modules/.bin/chromedriver",
"port": 9515,
"log_path": false
"log_path": "tests/browser/output"
},
"desiredCapabilities": {
"browserName": "chrome"
}
},
"enable_fail_fast": true
},
"dev": {

27219
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.23.0",
"version": "10.19.4",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@ -27,152 +27,179 @@
"type": "git",
"url": "https://github.com/gchq/CyberChef/"
},
"main": "src/node/cjs.js",
"module": "src/node/index.mjs",
"main": "src/node/wrapper.js",
"exports": {
"import": "./src/node/index.mjs",
"require": "./src/node/wrapper.js"
},
"bugs": "https://github.com/gchq/CyberChef/issues",
"browserslist": [
"Chrome >= 50",
"Firefox >= 38",
"node >= 10"
"node >= 16"
],
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"autoprefixer": "^10.2.4",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"@babel/core": "^7.24.7",
"@babel/eslint-parser": "^7.24.7",
"@babel/plugin-syntax-import-assertions": "^7.24.7",
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"@babel/runtime": "^7.24.7",
"@codemirror/commands": "^6.6.0",
"@codemirror/language": "^6.10.2",
"@codemirror/search": "^6.5.6",
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.28.0",
"autoprefixer": "^10.4.19",
"babel-loader": "^9.1.3",
"babel-plugin-dynamic-import-node": "^2.3.3",
"chromedriver": "^88.0.0",
"cli-progress": "^3.9.0",
"babel-plugin-transform-builtin-extend": "1.1.2",
"base64-loader": "^1.0.0",
"chromedriver": "^130.0.0",
"cli-progress": "^3.12.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.1",
"eslint": "^7.19.0",
"exports-loader": "^2.0.0",
"file-loader": "^6.2.0",
"grunt": "^1.3.0",
"compression-webpack-plugin": "^11.1.0",
"copy-webpack-plugin": "^12.0.2",
"core-js": "^3.37.1",
"cspell": "^8.17.3",
"css-loader": "7.1.2",
"eslint": "^9.4.0",
"eslint-plugin-jsdoc": "^48.2.9",
"globals": "^15.4.0",
"grunt": "^1.6.1",
"grunt-chmod": "~1.1.1",
"grunt-concurrent": "^3.0.0",
"grunt-contrib-clean": "~2.0.0",
"grunt-contrib-connect": "^3.0.0",
"grunt-contrib-clean": "~2.0.1",
"grunt-contrib-connect": "^4.0.0",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^23.0.0",
"grunt-eslint": "^25.0.0",
"grunt-exec": "~3.0.0",
"grunt-webpack": "^4.0.2",
"grunt-zip": "^0.18.2",
"html-webpack-plugin": "^4.5.1",
"imports-loader": "^2.0.0",
"mini-css-extract-plugin": "^1.3.5",
"nightwatch": "^1.5.1",
"node-sass": "^5.0.0",
"postcss": "^8.2.4",
"postcss-css-variables": "^0.17.0",
"postcss-import": "^14.0.0",
"postcss-loader": "^4.2.0",
"prompt": "^1.1.0",
"sass-loader": "^10.1.1",
"sitemap": "^6.3.5",
"style-loader": "^2.0.0",
"svg-url-loader": "^7.1.1",
"url-loader": "^4.1.1",
"webpack": "^5.19.0",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-dev-server": "^3.11.2",
"webpack-node-externals": "^2.5.2",
"worker-loader": "^3.0.7"
"grunt-webpack": "^6.0.0",
"grunt-zip": "^1.0.0",
"html-webpack-plugin": "^5.6.0",
"imports-loader": "^5.0.0",
"mini-css-extract-plugin": "2.9.0",
"modify-source-webpack-plugin": "^4.1.0",
"nightwatch": "^3.6.3",
"postcss": "^8.4.38",
"postcss-css-variables": "^0.19.0",
"postcss-import": "^16.1.0",
"postcss-loader": "^8.1.1",
"prompt": "^1.3.0",
"sitemap": "^8.0.0",
"terser": "^5.31.1",
"webpack": "^5.91.0",
"webpack-bundle-analyzer": "^4.10.2",
"webpack-dev-server": "5.0.4",
"webpack-node-externals": "^3.0.0",
"worker-loader": "^3.0.8"
},
"dependencies": {
"@astronautlabs/amf": "^0.0.6",
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.12.5",
"@blu3r4y/lzma": "^2.3.3",
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
"@xmldom/xmldom": "^0.8.10",
"argon2-browser": "^1.18.0",
"arrive": "^2.4.1",
"avsc": "^5.5.3",
"babel-plugin-transform-builtin-extend": "1.1.2",
"avsc": "^5.7.7",
"bcryptjs": "^2.4.3",
"bignumber.js": "^9.0.1",
"blakejs": "^1.1.0",
"bootstrap": "4.6.0",
"bootstrap-colorpicker": "^3.2.0",
"bignumber.js": "^9.1.2",
"blakejs": "^1.2.1",
"bootstrap": "4.6.2",
"bootstrap-colorpicker": "^3.4.0",
"bootstrap-material-design": "^4.1.3",
"browserify-zlib": "^0.2.0",
"bson": "^4.2.2",
"bson": "^4.7.2",
"buffer": "^6.0.3",
"cbor": "9.0.2",
"chi-squared": "^1.1.0",
"codepage": "^1.14.0",
"core-js": "^3.8.3",
"codepage": "^1.15.0",
"crypto-api": "^0.8.5",
"crypto-browserify": "^3.12.0",
"crypto-js": "^4.0.0",
"crypto-js": "^4.2.0",
"ctph.js": "0.0.5",
"d3": "^6.5.0",
"d3": "7.9.0",
"d3-hexbin": "^0.2.2",
"diff": "^5.0.0",
"es6-promisify": "^6.1.1",
"escodegen": "^2.0.0",
"esm": "^3.2.25",
"diff": "^5.2.0",
"dompurify": "^3.2.5",
"es6-promisify": "^7.0.0",
"escodegen": "^2.1.0",
"esprima": "^4.0.1",
"exif-parser": "^0.1.12",
"fernet": "^0.4.0",
"file-saver": "^2.0.5",
"flat": "^5.0.2",
"geodesy": "^1.1.3",
"highlight.js": "^10.5.0",
"jimp": "^0.16.1",
"jquery": "3.5.1",
"js-crc": "^0.2.0",
"js-sha3": "^0.8.0",
"flat": "^6.0.1",
"geodesy": "1.1.3",
"highlight.js": "^11.9.0",
"ieee754": "^1.2.1",
"jimp": "^0.22.12",
"jq-web": "^0.5.1",
"jquery": "3.7.1",
"js-sha3": "^0.9.3",
"jsesc": "^3.0.2",
"jsonpath": "^1.1.0",
"jsonwebtoken": "^8.5.1",
"jsqr": "^1.3.1",
"jsrsasign": "10.1.5",
"json5": "^2.2.3",
"jsonpath-plus": "^9.0.0",
"jsonwebtoken": "8.5.1",
"jsqr": "^1.4.0",
"jsrsasign": "^11.1.0",
"kbpgp": "2.1.15",
"libbzip2-wasm": "0.0.4",
"libyara-wasm": "^1.1.0",
"lodash": "^4.17.20",
"loglevel": "^1.7.1",
"libyara-wasm": "^1.2.1",
"lodash": "^4.17.21",
"loglevel": "^1.9.1",
"loglevel-message-prefix": "^3.0.0",
"markdown-it": "^12.0.4",
"moment": "^2.29.1",
"moment-timezone": "^0.5.32",
"lz-string": "^1.5.0",
"lz4js": "^0.2.0",
"markdown-it": "^14.1.0",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
"ngeohash": "^0.6.3",
"node-forge": "^0.10.0",
"node-forge": "^1.3.1",
"node-md6": "^0.1.0",
"nodom": "^2.4.0",
"notepack.io": "^2.3.0",
"notepack.io": "^3.0.1",
"ntlm": "^0.1.3",
"nwmatcher": "^1.4.4",
"otp": "^0.1.3",
"otpauth": "9.3.6",
"path": "^0.12.7",
"popper.js": "^1.16.1",
"process": "^0.11.10",
"protobufjs": "^7.3.1",
"qr-image": "^3.2.0",
"reflect-metadata": "^0.2.2",
"rison": "^0.1.1",
"scryptsy": "^2.1.0",
"snackbarjs": "^1.1.0",
"sortablejs": "^1.13.0",
"split.js": "^1.6.2",
"ssdeep.js": "0.0.2",
"sortablejs": "^1.15.2",
"split.js": "^1.6.5",
"ssdeep.js": "0.0.3",
"stream-browserify": "^3.0.0",
"terser": "^5.5.1",
"tesseract.js": "^2.1.1",
"ua-parser-js": "^0.7.23",
"tesseract.js": "5.1.0",
"ua-parser-js": "^1.0.38",
"unorm": "^1.6.0",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3",
"xmldom": "^0.4.0",
"xpath": "0.0.32",
"xregexp": "^4.4.1",
"xpath": "0.0.34",
"xregexp": "^5.1.1",
"zlibjs": "^0.3.1"
},
"scripts": {
"start": "grunt dev",
"build": "grunt prod",
"repl": "node src/node/repl.js",
"test": "grunt configTests && node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs",
"test-node-consumer": "grunt testnodeconsumer",
"testui": "grunt testui",
"start": "npx grunt dev",
"build": "npx grunt prod",
"node": "npx grunt node",
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-experimental-fetch --no-warnings src/node/repl.mjs",
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch --trace-uncaught tests/operations/index.mjs",
"testnodeconsumer": "npx grunt testnodeconsumer",
"testui": "npx grunt testui",
"testuidev": "npx nightwatch --env=dev",
"lint": "grunt lint",
"postinstall": "bash postinstall.sh",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
"lint": "npx grunt lint",
"lint:grammar": "cspell ./src",
"postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup && npx grunt exec:fixJimpModule",
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
"setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048"
}
}

View file

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

View file

@ -27,8 +27,8 @@ class Chef {
*
* @param {string|ArrayBuffer} input - The input data as a string or ArrayBuffer
* @param {Object[]} recipeConfig - The recipe configuration object
* @param {Object} options - The options object storing various user choices
* @param {boolean} options.attempHighlight - Whether or not to attempt highlighting
* @param {Object} [options={}] - The options object storing various user choices
* @param {string} [options.returnType] - What type to return the result as
*
* @returns {Object} response
* @returns {string} response.result - The output of the recipe
@ -37,12 +37,11 @@ class Chef {
* @returns {number} response.duration - The number of ms it took to execute the recipe
* @returns {number} response.error - The error object thrown by a failed operation (false if no error)
*/
async bake(input, recipeConfig, options) {
async bake(input, recipeConfig, options={}) {
log.debug("Chef baking");
const startTime = Date.now(),
recipe = new Recipe(recipeConfig),
containsFc = recipe.containsFlowControl(),
notUTF8 = options && "treatAsUtf8" in options && !options.treatAsUtf8;
containsFc = recipe.containsFlowControl();
let error = false,
progress = 0;
@ -68,20 +67,13 @@ class Chef {
// Present the raw result
await recipe.present(this.dish);
// Depending on the size of the output, we may send it back as a string or an ArrayBuffer.
// This can prevent unnecessary casting as an ArrayBuffer can be easily downloaded as a file.
// The threshold is specified in KiB.
const threshold = (options.ioDisplayThreshold || 1024) * 1024;
const returnType =
this.dish.type === Dish.HTML ?
Dish.HTML :
this.dish.size > threshold ?
Dish.ARRAY_BUFFER :
Dish.STRING;
this.dish.type === Dish.HTML ? Dish.HTML :
options?.returnType ? options.returnType : Dish.ARRAY_BUFFER;
return {
dish: rawDish,
result: await this.dish.get(returnType, notUTF8),
result: await this.dish.get(returnType),
type: Dish.enumLookup(this.dish.type),
progress: progress,
duration: Date.now() - startTime,

View file

@ -7,18 +7,10 @@
*/
import Chef from "./Chef.mjs";
import OperationConfig from "./config/OperationConfig.json";
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
import OpModules from "./config/modules/OpModules.mjs";
// Add ">" to the start of all log messages in the Chef Worker
import loglevelMessagePrefix from "loglevel-message-prefix";
loglevelMessagePrefix(log, {
prefixes: [],
staticPrefixes: [">"],
prefixFormat: "%p"
});
// Set up Chef instance
self.chef = new Chef();
@ -56,7 +48,7 @@ self.postMessage({
self.addEventListener("message", function(e) {
// Handle message
const r = e.data;
log.debug("ChefWorker receiving command '" + r.action + "'");
log.debug(`Receiving command '${r.action}'`);
switch (r.action) {
case "bake":
@ -86,6 +78,12 @@ self.addEventListener("message", function(e) {
case "setLogLevel":
log.setLevel(r.data, false);
break;
case "setLogPrefix":
loglevelMessagePrefix(log, {
prefixes: [],
staticPrefixes: [r.data]
});
break;
default:
break;
}
@ -101,14 +99,17 @@ async function bake(data) {
// Ensure the relevant modules are loaded
self.loadRequiredModules(data.recipeConfig);
try {
self.inputNum = (data.inputNum !== undefined) ? data.inputNum : -1;
self.inputNum = data.inputNum === undefined ? -1 : data.inputNum;
const response = await self.chef.bake(
data.input, // The user's input
data.recipeConfig, // The configuration of the recipe
data.options // Options set by the user
);
const transferable = (data.input instanceof ArrayBuffer) ? [data.input] : undefined;
const transferable = (response.dish.value instanceof ArrayBuffer) ?
[response.dish.value] :
undefined;
self.postMessage({
action: "bakeComplete",
data: Object.assign(response, {
@ -186,7 +187,7 @@ async function getDishTitle(data) {
*
* @param {Object[]} recipeConfig
* @param {string} direction
* @param {Object} pos - The position object for the highlight.
* @param {Object[]} pos - The position object for the highlight.
* @param {number} pos.start - The start offset.
* @param {number} pos.end - The end offset.
*/
@ -212,7 +213,7 @@ self.loadRequiredModules = function(recipeConfig) {
if (!(module in OpModules)) {
log.info(`Loading ${module} module`);
self.sendStatusMessage(`Loading ${module} module`);
self.importScripts(`${self.docURL}/modules/${module}.js`);
self.importScripts(`${self.docURL}/modules/${module}.js`); // lgtm [js/client-side-unvalidated-url-redirection]
self.sendStatusMessage("");
}
});

View file

@ -128,10 +128,9 @@ class Dish {
* If running in a browser, get is asynchronous.
*
* @param {number} type - The data type of value, see Dish enums.
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
* @returns {* | Promise} - (Browser) A promise | (Node) value of dish in given type
*/
get(type, notUTF8=false) {
get(type) {
if (typeof type === "string") {
type = Dish.typeEnum(type);
}
@ -140,13 +139,13 @@ class Dish {
// Node environment => _translate is sync
if (isNodeEnvironment()) {
this._translate(type, notUTF8);
this._translate(type);
return this.value;
// Browser environment => _translate is async
} else {
return new Promise((resolve, reject) => {
this._translate(type, notUTF8)
this._translate(type)
.then(() => {
resolve(this.value);
})
@ -190,12 +189,11 @@ class Dish {
* @Node
*
* @param {number} type - The data type of value, see Dish enums.
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
* @returns {Dish | Promise} - (Browser) A promise | (Node) value of dish in given type
*/
presentAs(type, notUTF8=false) {
presentAs(type) {
const clone = this.clone();
return clone.get(type, notUTF8);
return clone.get(type);
}
@ -207,7 +205,7 @@ class Dish {
const data = new Uint8Array(this.value.slice(0, 2048)),
types = detectFileType(data);
if (!types.length || !types[0].mime || !types[0].mime === "text/plain") {
if (!types.length || !types[0].mime || !(types[0].mime === "text/plain")) {
return null;
} else {
return types[0].mime;
@ -414,17 +412,16 @@ class Dish {
* If running in the browser, _translate is asynchronous.
*
* @param {number} toType - The data type of value, see Dish enums.
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
* @returns {Promise || undefined}
*/
_translate(toType, notUTF8=false) {
_translate(toType) {
log.debug(`Translating Dish from ${Dish.enumLookup(this.type)} to ${Dish.enumLookup(toType)}`);
// Node environment => translate is sync
if (isNodeEnvironment()) {
this._toArrayBuffer();
this.type = Dish.ARRAY_BUFFER;
this._fromArrayBuffer(toType, notUTF8);
this._fromArrayBuffer(toType);
// Browser environment => translate is async
} else {
@ -486,18 +483,17 @@ class Dish {
* Convert this.value to the given type from ArrayBuffer
*
* @param {number} toType - the Dish enum to convert to
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
*/
_fromArrayBuffer(toType, notUTF8) {
_fromArrayBuffer(toType) {
// Using 'bind' here to allow this.value to be mutated within translation functions
const toTypeFunctions = {
[Dish.STRING]: () => DishString.fromArrayBuffer.bind(this)(notUTF8),
[Dish.NUMBER]: () => DishNumber.fromArrayBuffer.bind(this)(notUTF8),
[Dish.HTML]: () => DishHTML.fromArrayBuffer.bind(this)(notUTF8),
[Dish.STRING]: () => DishString.fromArrayBuffer.bind(this)(),
[Dish.NUMBER]: () => DishNumber.fromArrayBuffer.bind(this)(),
[Dish.HTML]: () => DishHTML.fromArrayBuffer.bind(this)(),
[Dish.ARRAY_BUFFER]: () => {},
[Dish.BIG_NUMBER]: () => DishBigNumber.fromArrayBuffer.bind(this)(notUTF8),
[Dish.JSON]: () => DishJSON.fromArrayBuffer.bind(this)(notUTF8),
[Dish.BIG_NUMBER]: () => DishBigNumber.fromArrayBuffer.bind(this)(),
[Dish.JSON]: () => DishJSON.fromArrayBuffer.bind(this)(),
[Dish.FILE]: () => DishFile.fromArrayBuffer.bind(this)(),
[Dish.LIST_FILE]: () => DishListFile.fromArrayBuffer.bind(this)(),
[Dish.BYTE_ARRAY]: () => DishByteArray.fromArrayBuffer.bind(this)(),

View file

@ -27,6 +27,7 @@ class Ingredient {
this.toggleValues = [];
this.target = null;
this.defaultIndex = 0;
this.maxLength = null;
this.min = null;
this.max = null;
this.step = 1;
@ -53,6 +54,7 @@ class Ingredient {
this.toggleValues = ingredientConfig.toggleValues;
this.target = typeof ingredientConfig.target !== "undefined" ? ingredientConfig.target : null;
this.defaultIndex = typeof ingredientConfig.defaultIndex !== "undefined" ? ingredientConfig.defaultIndex : 0;
this.maxLength = ingredientConfig.maxLength || null;
this.min = ingredientConfig.min;
this.max = ingredientConfig.max;
this.step = ingredientConfig.step;

View file

@ -184,6 +184,7 @@ class Operation {
if (ing.disabled) conf.disabled = ing.disabled;
if (ing.target) conf.target = ing.target;
if (ing.defaultIndex) conf.defaultIndex = ing.defaultIndex;
if (ing.maxLength) conf.maxLength = ing.maxLength;
if (typeof ing.min === "number") conf.min = ing.min;
if (typeof ing.max === "number") conf.max = ing.max;
if (ing.step) conf.step = ing.step;

View file

@ -4,7 +4,7 @@
* @license Apache-2.0
*/
import OperationConfig from "./config/OperationConfig.json";
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
import OperationError from "./errors/OperationError.mjs";
import Operation from "./Operation.mjs";
import DishError from "./errors/DishError.mjs";
@ -46,7 +46,7 @@ class Recipe {
module: OperationConfig[c.op].module,
ingValues: c.args,
breakpoint: c.breakpoint,
disabled: c.disabled,
disabled: c.disabled || c.op === "Comment",
});
});
}
@ -230,14 +230,12 @@ class Recipe {
this.lastRunOp = op;
} catch (err) {
// Return expected errors as output
if (err instanceof OperationError ||
(err.type && err.type === "OperationError")) {
if (err instanceof OperationError || err?.type === "OperationError") {
// Cannot rely on `err instanceof OperationError` here as extending
// native types is not fully supported yet.
dish.set(err.message, "string");
return i;
} else if (err instanceof DishError ||
(err.type && err.type === "DishError")) {
} else if (err instanceof DishError || err?.type === "DishError") {
dish.set(err.message, "string");
return i;
} else {

View file

@ -4,6 +4,8 @@
* @license Apache-2.0
*/
// loglevel import required for Node API
import log from "loglevel";
import utf8 from "utf8";
import {fromBase64, toBase64} from "./lib/Base64.mjs";
import {fromHex} from "./lib/Hex.mjs";
@ -170,16 +172,17 @@ class Utils {
*
* @param {string} str - The input string to display.
* @param {boolean} [preserveWs=false] - Whether or not to print whitespace.
* @param {boolean} [onlyAscii=false] - Whether or not to replace non ASCII characters.
* @returns {string}
*/
static printable(str, preserveWs=false) {
if (isWebEnvironment() && window.app && !window.app.options.treatAsUtf8) {
str = Utils.byteArrayToChars(Utils.strToByteArray(str));
static printable(str, preserveWs=false, onlyAscii=false) {
if (onlyAscii) {
return str.replace(/[^\x20-\x7f]/g, ".");
}
// eslint-disable-next-line no-misleading-character-class
const re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
const wsRe = /[\x09-\x10\x0D\u2028\u2029]/g;
const wsRe = /[\x09-\x10\u2028\u2029]/g;
str = str.replace(re, ".");
if (!preserveWs) str = str.replace(wsRe, ".");
@ -187,6 +190,21 @@ class Utils {
}
/**
* Returns a string with whitespace represented as special characters from the
* Unicode Private Use Area, which CyberChef will display as control characters.
* Private Use Area characters are in the range U+E000..U+F8FF.
* https://en.wikipedia.org/wiki/Private_Use_Areas
* @param {string} str
* @returns {string}
*/
static escapeWhitespace(str) {
return str.replace(/[\x09-\x10]/g, function(c) {
return String.fromCharCode(0xe000 + c.charCodeAt(0));
});
}
/**
* Parse a string entered by a user and replace escaped chars with the bytes they represent.
*
@ -201,7 +219,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 "\\";
@ -214,6 +232,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":
@ -375,6 +395,70 @@ class Utils {
}
/**
* Converts a byte array to an integer.
*
* @param {byteArray} byteArray
* @param {string} byteorder - "little" or "big"
* @returns {integer}
*
* @example
* // returns 67305985
* Utils.byteArrayToInt([1, 2, 3, 4], "little");
*
* // returns 16909060
* Utils.byteArrayToInt([1, 2, 3, 4], "big");
*/
static byteArrayToInt(byteArray, byteorder) {
let value = 0;
if (byteorder === "big") {
for (let i = 0; i < byteArray.length; i++) {
value = (value * 256) + byteArray[i];
}
} else {
for (let i = byteArray.length - 1; i >= 0; i--) {
value = (value * 256) + byteArray[i];
}
}
return value;
}
/**
* Converts an integer to a byte array of {length} bytes.
*
* @param {integer} value
* @param {integer} length
* @param {string} byteorder - "little" or "big"
* @returns {byteArray}
*
* @example
* // returns [5, 255, 109, 1]
* Utils.intToByteArray(23985925, 4, "little");
*
* // returns [1, 109, 255, 5]
* Utils.intToByteArray(23985925, 4, "big");
*
* // returns [0, 0, 0, 0, 1, 109, 255, 5]
* Utils.intToByteArray(23985925, 8, "big");
*/
static intToByteArray(value, length, byteorder) {
const arr = new Array(length);
if (byteorder === "little") {
for (let i = 0; i < length; i++) {
arr[i] = value & 0xFF;
value = value >>> 8;
}
} else {
for (let i = length - 1; i >= 0; i--) {
arr[i] = value & 0xFF;
value = value >>> 8;
}
}
return arr;
}
/**
* Converts a string to an ArrayBuffer.
* Treats the string as UTF-8 if any values are over 255.
@ -390,6 +474,9 @@ class Utils {
* Utils.strToArrayBuffer("你好");
*/
static strToArrayBuffer(str) {
log.debug(`Converting string[${str?.length}] to array buffer`);
if (!str) return new ArrayBuffer;
const arr = new Uint8Array(str.length);
let i = str.length, b;
while (i--) {
@ -416,17 +503,20 @@ class Utils {
* Utils.strToUtf8ArrayBuffer("你好");
*/
static strToUtf8ArrayBuffer(str) {
const utf8Str = utf8.encode(str);
log.debug(`Converting string[${str?.length}] to UTF8 array buffer`);
if (!str) return new ArrayBuffer;
if (str.length !== utf8Str.length) {
if (isWorkerEnvironment()) {
const buffer = new TextEncoder("utf-8").encode(str);
if (str.length !== buffer.length) {
if (isWorkerEnvironment() && self && typeof self.setOption === "function") {
self.setOption("attemptHighlight", false);
} else if (isWebEnvironment()) {
window.app.options.attemptHighlight = false;
}
}
return Utils.strToArrayBuffer(utf8Str);
return buffer.buffer;
}
@ -445,6 +535,8 @@ class Utils {
* Utils.strToByteArray("你好");
*/
static strToByteArray(str) {
log.debug(`Converting string[${str?.length}] to byte array`);
if (!str) return [];
const byteArray = new Array(str.length);
let i = str.length, b;
while (i--) {
@ -471,6 +563,8 @@ class Utils {
* Utils.strToUtf8ByteArray("你好");
*/
static strToUtf8ByteArray(str) {
log.debug(`Converting string[${str?.length}] to UTF8 byte array`);
if (!str) return [];
const utf8Str = utf8.encode(str);
if (str.length !== utf8Str.length) {
@ -499,6 +593,8 @@ class Utils {
* Utils.strToCharcode("你好");
*/
static strToCharcode(str) {
log.debug(`Converting string[${str?.length}] to charcode`);
if (!str) return [];
const charcode = [];
for (let i = 0; i < str.length; i++) {
@ -533,20 +629,26 @@ class Utils {
* Utils.byteArrayToUtf8([228,189,160,229,165,189]);
*/
static byteArrayToUtf8(byteArray) {
const str = Utils.byteArrayToChars(byteArray);
log.debug(`Converting byte array[${byteArray?.length}] to UTF8`);
if (!byteArray || !byteArray.length) return "";
if (!(byteArray instanceof Uint8Array))
byteArray = new Uint8Array(byteArray);
try {
const utf8Str = utf8.decode(str);
if (str.length !== utf8Str.length) {
const str = new TextDecoder("utf-8", {fatal: true}).decode(byteArray);
if (str.length !== byteArray.length) {
if (isWorkerEnvironment()) {
self.setOption("attemptHighlight", false);
} else if (isWebEnvironment()) {
window.app.options.attemptHighlight = false;
}
}
return utf8Str;
return str;
} catch (err) {
// If it fails, treat it as ANSI
return str;
return Utils.byteArrayToChars(byteArray);
}
}
@ -565,11 +667,13 @@ class Utils {
* Utils.byteArrayToChars([20320,22909]);
*/
static byteArrayToChars(byteArray) {
if (!byteArray) return "";
log.debug(`Converting byte array[${byteArray?.length}] to chars`);
if (!byteArray || !byteArray.length) return "";
let str = "";
// String concatenation appears to be faster than an array join
for (let i = 0; i < byteArray.length;) {
str += String.fromCharCode(byteArray[i++]);
// Maxiumum arg length for fromCharCode is 65535, but the stack may already be fairly deep,
// so don't get too near it.
for (let i = 0; i < byteArray.length; i += 20000) {
str += String.fromCharCode(...(byteArray.slice(i, i+20000)));
}
return str;
}
@ -587,6 +691,8 @@ class Utils {
* Utils.arrayBufferToStr(Uint8Array.from([104,101,108,108,111]).buffer);
*/
static arrayBufferToStr(arrayBuffer, utf8=true) {
log.debug(`Converting array buffer[${arrayBuffer?.byteLength}] to str`);
if (!arrayBuffer || !arrayBuffer.byteLength) return "";
const arr = new Uint8Array(arrayBuffer);
return utf8 ? Utils.byteArrayToUtf8(arr) : Utils.byteArrayToChars(arr);
}
@ -704,10 +810,24 @@ class Utils {
* Utils.stripHtmlTags("<div>Test</div>");
*/
static stripHtmlTags(htmlStr, removeScriptAndStyle=false) {
if (removeScriptAndStyle) {
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
/**
* Recursively remove a pattern from a string until there are no more matches.
* Avoids incomplete sanitization e.g. "aabcbc".replace(/abc/g, "") === "abc"
*
* @param {RegExp} pattern
* @param {string} str
* @returns {string}
*/
function recursiveRemove(pattern, str) {
const newStr = str.replace(pattern, "");
return newStr.length === str.length ? newStr : recursiveRemove(pattern, newStr);
}
return htmlStr.replace(/<[^>]+>/g, "");
if (removeScriptAndStyle) {
htmlStr = recursiveRemove(/<script[^>]*>(\s|\S)*?<\/script[^>]*>/gi, htmlStr);
htmlStr = recursiveRemove(/<style[^>]*>(\s|\S)*?<\/style[^>]*>/gi, htmlStr);
}
return recursiveRemove(/<[^>]+>/g, htmlStr);
}
@ -715,6 +835,11 @@ class Utils {
* Escapes HTML tags in a string to stop them being rendered.
* https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
*
* Null bytes are a special case and are converted to a character from the Unicode
* Private Use Area, which CyberChef will display as a control character picture.
* This is done due to null bytes not being rendered or stored correctly in HTML
* DOM building.
*
* @param {string} str
* @returns string
*
@ -729,13 +854,13 @@ class Utils {
">": "&gt;",
'"': "&quot;",
"'": "&#x27;", // &apos; not recommended because it's not in the HTML spec
"/": "&#x2F;", // forward slash is included as it helps end an HTML entity
"`": "&#x60;"
"`": "&#x60;",
"\u0000": "\ue000"
};
return str.replace(/[&<>"'/`]/g, function (match) {
return str ? str.replace(/[&<>"'`\u0000]/g, function (match) {
return HTML_CHARS[match];
});
}) : str;
}
@ -757,15 +882,33 @@ class Utils {
"&quot;": '"',
"&#x27;": "'",
"&#x2F;": "/",
"&#x60;": "`"
"&#x60;": "`",
"\ue000": "\u0000"
};
return str.replace(/&#?x?[a-z0-9]{2,4};/ig, function (match) {
return str.replace(/(&#?x?[a-z0-9]{2,4};|\ue000)/ig, function (match) {
return HTML_CHARS[match] || match;
});
}
/**
* Converts a string to its title case equivalent.
*
* @param {string} str
* @returns string
*
* @example
* // return "A Tiny String"
* Utils.toTitleCase("a tIny String");
*/
static toTitleCase(str) {
return str.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
}
/**
* Encodes a URI fragment (#) or query (?) using a minimal amount of percent-encoding.
*
@ -878,7 +1021,7 @@ class Utils {
while ((m = recipeRegex.exec(recipe))) {
// Translate strings in args back to double-quotes
args = m[2]
args = m[2] // lgtm [js/incomplete-sanitization]
.replace(/"/g, '\\"') // Escape double quotes
.replace(/(^|,|{|:)'/g, '$1"') // Replace opening ' with "
.replace(/([^\\]|(?:\\\\)+)'(,|:|}|$)/g, '$1"$2') // Replace closing ' with "
@ -1189,6 +1332,30 @@ class Utils {
}[token];
}
/**
* Iterate object in chunks of given size.
*
* @param {Iterable} iterable
* @param {number} chunksize
*/
static* chunked(iterable, chunksize) {
const iterator = iterable[Symbol.iterator]();
while (true) {
const res = [];
for (let i = 0; i < chunksize; i++) {
const next = iterator.next();
if (next.done) {
break;
}
res.push(next.value);
}
if (res.length) {
yield res;
} else {
return;
}
}
}
}
/**

136
src/core/config/Categories.json Executable file → Normal file
View file

@ -14,19 +14,25 @@
"From Charcode",
"To Decimal",
"From Decimal",
"To Float",
"From Float",
"To Binary",
"From Binary",
"To Octal",
"From Octal",
"To Base64",
"From Base64",
"Show Base64 offsets",
"To Base32",
"From Base32",
"To Base45",
"From Base45",
"To Base58",
"From Base58",
"To Base62",
"From Base62",
"To Base64",
"From Base64",
"Show Base64 offsets",
"To Base92",
"From Base92",
"To Base85",
"From Base85",
"To Base",
@ -44,6 +50,8 @@
"From Quoted Printable",
"To Punycode",
"From Punycode",
"AMF Encode",
"AMF Decode",
"To Hex Content",
"From Hex Content",
"PEM to Hex",
@ -61,7 +69,17 @@
"Parse TLV",
"CSV to JSON",
"JSON to CSV",
"Avro to JSON"
"Avro to JSON",
"CBOR Encode",
"CBOR Decode",
"YAML to JSON",
"JSON to YAML",
"Caret/M-decode",
"Rison Encode",
"Rison Decode",
"To Modhex",
"From Modhex",
"MIME Decoding"
]
},
{
@ -75,22 +93,44 @@
"DES Decrypt",
"Triple DES Encrypt",
"Triple DES Decrypt",
"Fernet Encrypt",
"Fernet Decrypt",
"LS47 Encrypt",
"LS47 Decrypt",
"RC2 Encrypt",
"RC2 Decrypt",
"RC4",
"RC4 Drop",
"ChaCha",
"Salsa20",
"XSalsa20",
"Rabbit",
"SM4 Encrypt",
"SM4 Decrypt",
"GOST Encrypt",
"GOST Decrypt",
"GOST Sign",
"GOST Verify",
"GOST Key Wrap",
"GOST Key Unwrap",
"ROT13",
"ROT13 Brute Force",
"ROT47",
"ROT47 Brute Force",
"ROT8000",
"XOR",
"XOR Brute Force",
"Vigenère Encode",
"Vigenère Decode",
"XXTEA Encrypt",
"XXTEA Decrypt",
"To Morse Code",
"From Morse Code",
"Bacon Cipher Encode",
"Bacon Cipher Decode",
"Bifid Cipher Encode",
"Bifid Cipher Decode",
"Caesar Box Cipher",
"Affine Cipher Encode",
"Affine Cipher Decode",
"A1Z26 Cipher Encode",
@ -100,9 +140,12 @@
"Atbash Cipher",
"CipherSaber2 Encrypt",
"CipherSaber2 Decrypt",
"Cetacean Cipher Encode",
"Cetacean Cipher Decode",
"Substitute",
"Derive PBKDF2 key",
"Derive EVP key",
"Derive HKDF key",
"Bcrypt",
"Scrypt",
"JWT Sign",
@ -110,24 +153,30 @@
"JWT Decode",
"Citrix CTX1 Encode",
"Citrix CTX1 Decode",
"AES Key Wrap",
"AES Key Unwrap",
"Pseudo-Random Number Generator",
"Enigma",
"Bombe",
"Multiple Bombe",
"Typex",
"Lorenz",
"Colossus"
"Colossus",
"SIGABA"
]
},
{
"name": "Public Key",
"ops": [
"Parse X.509 certificate",
"Parse X.509 CRL",
"Parse ASN.1 hex string",
"PEM to Hex",
"Hex to PEM",
"Hex to Object Identifier",
"Object Identifier to Hex",
"PEM to JWK",
"JWK to PEM",
"Generate PGP Key Pair",
"PGP Encrypt",
"PGP Decrypt",
@ -139,7 +188,16 @@
"RSA Verify",
"RSA Encrypt",
"RSA Decrypt",
"Parse SSH Host Key"
"Generate ECDSA Key Pair",
"ECDSA Signature Conversion",
"ECDSA Sign",
"ECDSA Verify",
"Parse SSH Host Key",
"Parse CSR",
"Public Key from Certificate",
"Public Key from Private Key",
"SM2 Encrypt",
"SM2 Decrypt"
]
},
{
@ -169,7 +227,8 @@
"Bit shift right",
"Rotate left",
"Rotate right",
"ROT13"
"ROT13",
"ROT8000"
]
},
{
@ -182,21 +241,35 @@
"Parse User Agent",
"Parse IP range",
"Parse IPv6 address",
"IPv6 Transition Addresses",
"Parse IPv4 header",
"Strip IPv4 header",
"Parse TCP",
"Strip TCP header",
"Parse TLS record",
"Parse UDP",
"Strip UDP header",
"Parse SSH Host Key",
"Parse URI",
"URL Encode",
"URL Decode",
"Protobuf Decode",
"Protobuf Encode",
"VarInt Encode",
"VarInt Decode",
"JA3 Fingerprint",
"JA3S Fingerprint",
"JA4 Fingerprint",
"JA4Server Fingerprint",
"HASSH Client Fingerprint",
"HASSH Server Fingerprint",
"Format MAC addresses",
"Change IP format",
"Group IP addresses",
"Encode NetBIOS Name",
"Decode NetBIOS Name",
"Defang URL",
"Fang URL",
"Defang IP Addresses"
]
},
@ -208,7 +281,8 @@
"Unicode Text Format",
"Remove Diacritics",
"Unescape Unicode Characters",
"Convert to NATO alphabet"
"Convert to NATO alphabet",
"Convert Leet Speak"
]
},
{
@ -219,13 +293,16 @@
"Remove null bytes",
"To Upper case",
"To Lower case",
"Swap case",
"To Case Insensitive Regex",
"From Case Insensitive Regex",
"Add line numbers",
"Remove line numbers",
"Get All Casings",
"To Table",
"Reverse",
"Sort",
"Shuffle",
"Unique",
"Split",
"Filter",
@ -238,8 +315,10 @@
"Pad lines",
"Find / Replace",
"Regular expression",
"Fuzzy Match",
"Offset checker",
"Hamming Distance",
"Levenshtein Distance",
"Convert distance",
"Convert area",
"Convert mass",
@ -254,7 +333,10 @@
"Escape string",
"Unescape string",
"Pseudo-Random Number Generator",
"Sleep"
"Sleep",
"File Tree",
"Take nth bytes",
"Drop nth bytes"
]
},
{
@ -266,7 +348,9 @@
"To UNIX Timestamp",
"Windows Filetime to UNIX Timestamp",
"UNIX Timestamp to Windows Filetime",
"DateTime Delta",
"Extract dates",
"Get Time",
"Sleep"
]
},
@ -281,12 +365,15 @@
"Extract domains",
"Extract file paths",
"Extract dates",
"Extract hashes",
"Regular expression",
"XPath expression",
"JPath expression",
"CSS selector",
"Extract EXIF",
"Extract Files"
"Extract ID3",
"Extract Files",
"RAKE"
]
},
{
@ -303,7 +390,14 @@
"Bzip2 Decompress",
"Bzip2 Compress",
"Tar",
"Untar"
"Untar",
"LZString Decompress",
"LZString Compress",
"LZMA Decompress",
"LZMA Compress",
"LZ4 Decompress",
"LZ4 Compress",
"LZNT1 Decompress"
]
},
{
@ -319,6 +413,7 @@
"SHA1",
"SHA2",
"SHA3",
"SM3",
"Keccak",
"Shake",
"RIPEMD",
@ -327,26 +422,30 @@
"Snefru",
"BLAKE2b",
"BLAKE2s",
"GOST hash",
"GOST Hash",
"Streebog",
"SSDEEP",
"CTPH",
"Compare SSDEEP hashes",
"Compare CTPH hashes",
"HMAC",
"CMAC",
"Bcrypt",
"Bcrypt compare",
"Bcrypt parse",
"Argon2",
"Argon2 compare",
"Scrypt",
"NT Hash",
"LM Hash",
"MurmurHash3",
"Fletcher-8 Checksum",
"Fletcher-16 Checksum",
"Fletcher-32 Checksum",
"Fletcher-64 Checksum",
"Adler-32 Checksum",
"Luhn Checksum",
"CRC-8 Checksum",
"CRC-16 Checksum",
"CRC-32 Checksum",
"CRC Checksum",
"TCP/IP Checksum"
]
},
@ -368,8 +467,10 @@
"CSS Minify",
"XPath expression",
"JPath expression",
"Jq",
"CSS selector",
"PHP Deserialize",
"PHP Serialize",
"Microsoft Script Decoder",
"Strip HTML tags",
"Diff",
@ -395,7 +496,8 @@
"Extract RGBA",
"View Bit Plane",
"Randomize Colour Palette",
"Extract LSB"
"Extract LSB",
"ELF Info"
]
},
{
@ -438,8 +540,10 @@
"Frequency distribution",
"Index of Coincidence",
"Chi Square",
"P-list Viewer",
"Disassemble x86",
"Pseudo-Random Number Generator",
"Generate De Bruijn Sequence",
"Generate UUID",
"Generate TOTP",
"Generate HOTP",

View file

@ -30,12 +30,12 @@ fs.readdirSync(path.join(dir, "../operations")).forEach(file => {
// Construct index file
let code = `/**
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
* @license Apache-2.0
*/
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
* @license Apache-2.0
*/
`;
opObjs.forEach(obj => {

View file

@ -0,0 +1,144 @@
/**
* This script updates the CHANGELOG when a new minor version is created.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
/* eslint no-console: ["off"] */
import prompt from "prompt";
import colors from "colors";
import path from "path";
import fs from "fs";
import process from "process";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: newMinorVersion.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs");
process.exit(1);
}
let changelogData = fs.readFileSync(path.join(process.cwd(), "CHANGELOG.md"), "utf8");
const lastVersion = changelogData.match(/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/);
const newVersion = [
parseInt(lastVersion[1], 10),
parseInt(lastVersion[2], 10) + 1,
0
];
let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm);
knownContributors = knownContributors.map(c => c.slice(2, -1));
const date = (new Date()).toISOString().split("T")[0];
const schema = {
properties: {
message: {
description: "A short but descriptive summary of a feature in this version",
example: "Added 'Op name' operation",
prompt: "Feature description",
type: "string",
required: true,
},
author: {
description: "The author of the feature (only one supported, edit manually to add more)",
example: "n1474335",
prompt: "Author",
type: "string",
default: "n1474335"
},
id: {
description: "The PR number or full commit hash for this feature.",
example: "1200",
prompt: "Pull request or commit ID",
type: "string"
},
another: {
description: "y/n",
example: "y",
prompt: "Add another feature?",
type: "string",
pattern: /^[yn]$/,
}
}
};
// Build schema
for (const prop in schema.properties) {
const p = schema.properties[prop];
p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt);
}
prompt.message = "";
prompt.delimiter = ":".green;
const features = [];
const authors = [];
const prIDs = [];
const commitIDs = [];
prompt.start();
const getFeature = function() {
prompt.get(schema, (err, result) => {
if (err) {
console.log("\nExiting script.");
process.exit(0);
}
features.push(result);
if (result.another === "y") {
getFeature();
} else {
let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`;
features.forEach(feature => {
const id = feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id;
message += `- ${feature.message} [@${feature.author}] | [${id}]\n`;
if (!knownContributors.includes(feature.author)) {
authors.push(`[@${feature.author}]: https://github.com/${feature.author}`);
}
if (feature.id.length > 10) {
commitIDs.push(`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`);
} else {
prIDs.push(`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`);
}
});
// Message
changelogData = changelogData.replace(/## Details\n\n/, "## Details\n\n" + message + "\n");
// Tag
const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`;
changelogData = changelogData.replace(/\n\n(\[\d+\.\d+\.\d+\]: https)/, "\n\n" + newTag + "$1");
// Author
authors.forEach(author => {
changelogData = changelogData.replace(/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, "$1" + author + "\n\n");
});
// Commit IDs
commitIDs.forEach(commitID => {
changelogData = changelogData.replace(/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, "$1" + commitID + "\n\n");
});
// PR IDs
prIDs.forEach(prID => {
changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/, "$1" + prID + "\n\n");
});
fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData);
console.log("Written CHANGELOG.md\nCommit changes and then run `npm version minor`.");
}
});
};
getFeature();

View file

@ -121,7 +121,7 @@ prompt.get(schema, (err, result) => {
const moduleName = result.opName.replace(/\w\S*/g, txt => {
return txt.charAt(0).toUpperCase() + txt.substr(1);
}).replace(/[\s-()/./]/g, "");
}).replace(/[\s-()./]/g, "");
const template = `/**
@ -147,7 +147,7 @@ class ${moduleName} extends Operation {
this.name = "${result.opName}";
this.module = "${result.module}";
this.description = "${(new EscapeString).run(result.description, ["Special chars", "Double"])}";
this.infoURL = "${result.infoURL}";
this.infoURL = "${result.infoURL}"; // Usually a Wikipedia link. Remember to remove localisation (i.e. https://wikipedia.org/etc rather than https://en.wikipedia.org/etc)
this.inputType = "${result.inputType}";
this.outputType = "${result.outputType}";
this.args = [

View file

@ -24,12 +24,11 @@ class DishBigNumber extends DishType {
/**
* convert the given value from a ArrayBuffer
* @param {boolean} notUTF8
*/
static fromArrayBuffer(notUTF8) {
static fromArrayBuffer() {
DishBigNumber.checkForValue(this.value);
try {
this.value = new BigNumber(Utils.arrayBufferToStr(this.value, !notUTF8));
this.value = new BigNumber(Utils.arrayBufferToStr(this.value));
} catch (err) {
this.value = new BigNumber(NaN);
}

View file

@ -22,11 +22,10 @@ class DishJSON extends DishType {
/**
* convert the given value from a ArrayBuffer
* @param {boolean} notUTF8
*/
static fromArrayBuffer(notUTF8) {
static fromArrayBuffer() {
DishJSON.checkForValue(this.value);
this.value = JSON.parse(Utils.arrayBufferToStr(this.value, !notUTF8));
this.value = JSON.parse(Utils.arrayBufferToStr(this.value));
}
}

View file

@ -23,11 +23,10 @@ class DishNumber extends DishType {
/**
* convert the given value from a ArrayBuffer
* @param {boolean} notUTF8
*/
static fromArrayBuffer(notUTF8) {
static fromArrayBuffer() {
DishNumber.checkForValue(this.value);
this.value = this.value ? parseFloat(Utils.arrayBufferToStr(this.value, !notUTF8)) : 0;
this.value = this.value ? parseFloat(Utils.arrayBufferToStr(this.value)) : 0;
}
}

View file

@ -23,11 +23,10 @@ class DishString extends DishType {
/**
* convert the given value from a ArrayBuffer
* @param {boolean} notUTF8
*/
static fromArrayBuffer(notUTF8) {
static fromArrayBuffer() {
DishString.checkForValue(this.value);
this.value = this.value ? Utils.arrayBufferToStr(this.value, !notUTF8) : "";
this.value = this.value ? Utils.arrayBufferToStr(this.value) : "";
}
}

View file

@ -29,9 +29,8 @@ class DishType {
/**
* convert the given value from a ArrayBuffer
* @param {boolean} notUTF8
*/
static fromArrayBuffer(notUTF8=undefined) {
static fromArrayBuffer() {
throw new Error("fromArrayBuffer has not been implemented");
}
}

View file

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

23
src/core/lib/Base32.mjs Normal file
View file

@ -0,0 +1,23 @@
// import Utils from "../Utils.mjs";
/**
* Base32 resources.
*
* @author Peter C-S [petercs@purelymail.com]
* @license Apache-2.0
*/
/**
* Base32 alphabets.
*/
export const ALPHABET_OPTIONS = [
{
name: "Standard", // https://www.rfc-editor.org/rfc/rfc4648#section-6
value: "A-Z2-7=",
},
{
name: "Hex Extended", // https://www.rfc-editor.org/rfc/rfc4648#section-7
value: "0-9A-V=",
},
];

27
src/core/lib/Base45.mjs Normal file
View file

@ -0,0 +1,27 @@
/**
* Base45 resources.
*
* @author Thomas Weißschuh [thomas@t-8ch.de]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
/**
* Highlight to Base45
*/
export function highlightToBase45(pos, args) {
pos[0].start = Math.floor(pos[0].start / 2) * 3;
pos[0].end = Math.ceil(pos[0].end / 2) * 3;
return pos;
}
/**
* Highlight from Base45
*/
export function highlightFromBase45(pos, args) {
pos[0].start = Math.floor(pos[0].start / 3) * 2;
pos[0].end = Math.ceil(pos[0].end / 3) * 2;
return pos;
}
export const ALPHABET = "0-9A-Z $%*+\\-./:";

View file

@ -25,12 +25,12 @@ import OperationError from "../errors/OperationError.mjs";
*/
export function toBase64(data, alphabet="A-Za-z0-9+/=") {
if (!data) return "";
if (typeof data == "string") {
data = Utils.strToArrayBuffer(data);
}
if (data instanceof ArrayBuffer) {
data = new Uint8Array(data);
}
if (typeof data == "string") {
data = Utils.strToByteArray(data);
}
alphabet = Utils.expandAlphRange(alphabet).join("");
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
@ -82,15 +82,46 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
* // returns [72, 101, 108, 108, 111]
* fromBase64("SGVsbG8=", null, "byteArray");
*/
export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true) {
export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true, strictMode=false) {
if (!data) {
return returnType === "string" ? "" : [];
}
alphabet = alphabet || "A-Za-z0-9+/=";
alphabet = Utils.expandAlphRange(alphabet).join("");
// Confirm alphabet is a valid length
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
throw new OperationError(`Error: Base64 alphabet should be 64 characters long, or 65 with a padding character. Found ${alphabet.length}: ${alphabet}`);
}
// Remove non-alphabet characters
if (removeNonAlphChars) {
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
data = data.replace(re, "");
}
if (strictMode) {
// Check for incorrect lengths (even without padding)
if (data.length % 4 === 1) {
throw new OperationError(`Error: Invalid Base64 input length (${data.length}). Cannot be 4n+1, even without padding chars.`);
}
if (alphabet.length === 65) { // Padding character included
const pad = alphabet.charAt(64);
const padPos = data.indexOf(pad);
if (padPos >= 0) {
// Check that the padding character is only used at the end and maximum of twice
if (padPos < data.length - 2 || data.charAt(data.length - 1) !== pad) {
throw new OperationError(`Error: Base64 padding character (${pad}) not used in the correct place.`);
}
// Check that input is padded to the correct length
if (data.length % 4 !== 0) {
throw new OperationError("Error: Base64 not padded to a multiple of 4.");
}
}
}
}
const output = [];
@ -98,31 +129,28 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
enc1, enc2, enc3, enc4,
i = 0;
if (removeNonAlphChars) {
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
data = data.replace(re, "");
}
while (i < data.length) {
enc1 = alphabet.indexOf(data.charAt(i++));
enc2 = alphabet.indexOf(data.charAt(i++) || "=");
enc3 = alphabet.indexOf(data.charAt(i++) || "=");
enc4 = alphabet.indexOf(data.charAt(i++) || "=");
// Including `|| null` forces empty strings to null so that indexOf returns -1 instead of 0
enc1 = alphabet.indexOf(data.charAt(i++) || null);
enc2 = alphabet.indexOf(data.charAt(i++) || null);
enc3 = alphabet.indexOf(data.charAt(i++) || null);
enc4 = alphabet.indexOf(data.charAt(i++) || null);
enc2 = enc2 === -1 ? 64 : enc2;
enc3 = enc3 === -1 ? 64 : enc3;
enc4 = enc4 === -1 ? 64 : enc4;
if (strictMode && (enc1 < 0 || enc2 < 0 || enc3 < 0 || enc4 < 0)) {
throw new OperationError("Error: Base64 input contains non-alphabet char(s)");
}
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output.push(chr1);
if (enc3 !== 64) {
if (chr1 >= 0 && chr1 < 256) {
output.push(chr1);
}
if (chr2 >= 0 && chr2 < 256 && enc3 !== 64) {
output.push(chr2);
}
if (enc4 !== 64) {
if (chr3 >= 0 && chr3 < 256 && enc4 !== 64) {
output.push(chr3);
}
}
@ -148,4 +176,8 @@ export const ALPHABET_OPTIONS = [
{name: "BinHex: !-,-0-689@A-NP-VX-Z[`a-fh-mp-r", value: "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r"},
{name: "ROT13: N-ZA-Mn-za-m0-9+/=", value: "N-ZA-Mn-za-m0-9+/="},
{name: "UNIX crypt: ./0-9A-Za-z", value: "./0-9A-Za-z"},
{name: "Atom128: /128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", value: "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC"},
{name: "Megan35: 3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", value: "3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5"},
{name: "Zong22: ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", value: "ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2"},
{name: "Hazz15: HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", value: "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5"}
];

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("'", "&apos;");
alphabet = alphabet.replace("\"", "&quot;");
alphabet = alphabet.replace("\\", "&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;

44
src/core/lib/Base92.mjs Normal file
View file

@ -0,0 +1,44 @@
/**
* Base92 resources.
*
* @author sg5506844 [sg5506844@gmail.com]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
/**
* Base92 alphabet char
*
* @param {number} val
* @returns {number}
*/
export function base92Chr(val) {
if (val < 0 || val >= 91) {
throw new OperationError("Invalid value");
}
if (val === 0)
return "!".charCodeAt(0);
else if (val <= 61)
return "#".charCodeAt(0) + val - 1;
else
return "a".charCodeAt(0) + val - 62;
}
/**
* Base92 alphabet ord
*
* @param {string} val
* @returns {number}
*/
export function base92Ord(val) {
if (val === "!")
return 0;
else if ("#" <= val && val <= "_")
return val.charCodeAt(0) - "#".charCodeAt(0) + 1;
else if ("a" <= val && val <= "}")
return val.charCodeAt(0) - "a".charCodeAt(0) + 62;
throw new OperationError(`${val} is not a base92 character`);
}

View file

@ -7,38 +7,45 @@
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Convert a byte array into a binary string.
*
* @param {Uint8Array|byteArray} data
* @param {Uint8Array|byteArray|number} data
* @param {string} [delim="Space"]
* @param {number} [padding=8]
* @returns {string}
*
* @example
* // returns "00010000 00100000 00110000"
* // returns "00001010 00010100 00011110"
* toBinary([10,20,30]);
*
* // returns "00010000 00100000 00110000"
* toBinary([10,20,30], ":");
* // returns "00001010:00010100:00011110"
* toBinary([10,20,30], "Colon");
*
* // returns "1010:10100:11110"
* toBinary([10,20,30], "Colon", 0);
*/
export function toBinary(data, delim="Space", padding=8) {
if (!data) return "";
if (data === undefined || data === null)
throw new OperationError("Unable to convert to binary: Empty input data enocuntered");
delim = Utils.charRep(delim);
let output = "";
for (let i = 0; i < data.length; i++) {
output += data[i].toString(2).padStart(padding, "0") + delim;
}
if (delim.length) {
return output.slice(0, -delim.length);
if (data.length) { // array
for (let i = 0; i < data.length; i++) {
output += data[i].toString(2).padStart(padding, "0");
if (i !== data.length - 1) output += delim;
}
} else if (typeof data === "number") { // Single value
return data.toString(2).padStart(padding, "0");
} else {
return output;
return "";
}
return output;
}
@ -52,12 +59,15 @@ export function toBinary(data, delim="Space", padding=8) {
*
* @example
* // returns [10,20,30]
* fromBinary("00010000 00100000 00110000");
* fromBinary("00001010 00010100 00011110");
*
* // returns [10,20,30]
* fromBinary("00010000:00100000:00110000", "Colon");
* fromBinary("00001010:00010100:00011110", "Colon");
*/
export function fromBinary(data, delim="Space", byteLen=8) {
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
throw new OperationError("Byte length must be a positive integer");
const delimRegex = Utils.regexRep(delim);
data = data.replace(delimRegex, "");

View file

@ -34,10 +34,10 @@ export function bitOp (input, key, func, nullPreserving, scheme) {
!(nullPreserving && (o === 0 || o === k))) {
switch (scheme) {
case "Input differential":
key[i % key.length] = x;
key[i % key.length] = o;
break;
case "Output differential":
key[i % key.length] = o;
key[i % key.length] = x;
break;
}
}

View file

@ -6,6 +6,7 @@
*/
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
/**
* @constant
@ -86,8 +87,8 @@ export function getScatterValues(input, recordDelimiter, fieldDelimiter, columnH
}
values = values.map(row => {
const x = parseFloat(row[0], 10),
y = parseFloat(row[1], 10);
const x = parseFloat(row[0]),
y = parseFloat(row[1]);
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
@ -121,14 +122,14 @@ export function getScatterValuesWithColour(input, recordDelimiter, fieldDelimite
}
values = values.map(row => {
const x = parseFloat(row[0], 10),
y = parseFloat(row[1], 10),
const x = parseFloat(row[0]),
y = parseFloat(row[1]),
colour = row[2];
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
return [x, y, colour];
return [x, y, Utils.escapeHtml(colour)];
});
return { headings, values };
@ -157,7 +158,7 @@ export function getSeriesValues(input, recordDelimiter, fieldDelimiter, columnHe
values.forEach(row => {
const serie = row[0],
xVal = row[1],
val = parseFloat(row[2], 10);
val = parseFloat(row[2]);
if (Number.isNaN(val)) throw new OperationError("Values must be numbers in base 10.");

View file

@ -6,10 +6,12 @@
* @license Apache-2.0
*/
import cptable from "codepage";
/**
* Character encoding format mappings.
*/
export const IO_FORMAT = {
export const CHR_ENC_CODE_PAGES = {
"UTF-8 (65001)": 65001,
"UTF-7 (65000)": 65000,
"UTF-16LE (1200)": 1200,
@ -164,6 +166,57 @@ export const IO_FORMAT = {
"Simplified Chinese GB18030 (54936)": 54936,
};
export const CHR_ENC_SIMPLE_LOOKUP = {};
export const CHR_ENC_SIMPLE_REVERSE_LOOKUP = {};
for (const name in CHR_ENC_CODE_PAGES) {
const simpleName = name.match(/(^.+)\([\d/]+\)$/)[1];
CHR_ENC_SIMPLE_LOOKUP[simpleName] = CHR_ENC_CODE_PAGES[name];
CHR_ENC_SIMPLE_REVERSE_LOOKUP[CHR_ENC_CODE_PAGES[name]] = simpleName;
}
/**
* Returns the width of the character set for the given codepage.
* For example, UTF-8 is a Single Byte Character Set, whereas
* UTF-16 is a Double Byte Character Set.
*
* @param {number} page - The codepage number
* @returns {number}
*/
export function chrEncWidth(page) {
if (typeof page !== "number") return 0;
// Raw Bytes have a width of 1
if (page === 0) return 1;
const pageStr = page.toString();
// Confirm this page is legitimate
if (!Object.prototype.hasOwnProperty.call(CHR_ENC_SIMPLE_REVERSE_LOOKUP, pageStr))
return 0;
// Statically defined code pages
if (Object.prototype.hasOwnProperty.call(cptable, pageStr))
return cptable[pageStr].dec.length > 256 ? 2 : 1;
// Cached code pages
if (cptable.utils.cache.sbcs.includes(pageStr))
return 1;
if (cptable.utils.cache.dbcs.includes(pageStr))
return 2;
// Dynamically generated code pages
if (Object.prototype.hasOwnProperty.call(cptable.utils.magic, pageStr)) {
// Generate a single character and measure it
const a = cptable.utils.encode(page, "a");
return a.length;
}
return 0;
}
/**
* Unicode Normalisation Forms
*
@ -171,8 +224,85 @@ export const IO_FORMAT = {
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
export const UNICODE_NORMALISATION_FORMS = ["NFD", "NFC", "NFKD", "NFKC"];
/**
* Character encoding format mappings.
* Detects whether the input buffer is valid UTF8.
*
* @param {ArrayBuffer} data
* @returns {number} - 0 = not UTF8, 1 = ASCII, 2 = UTF8
*/
export const UNICODE_NORMALISATION_FORMS = ["NFD", "NFC", "NFKD", "NFKC"];
export function isUTF8(data) {
const bytes = new Uint8Array(data);
let i = 0;
let onlyASCII = true;
while (i < bytes.length) {
if (( // ASCII
bytes[i] === 0x09 ||
bytes[i] === 0x0A ||
bytes[i] === 0x0D ||
(0x20 <= bytes[i] && bytes[i] <= 0x7E)
)) {
i += 1;
continue;
}
onlyASCII = false;
if (( // non-overlong 2-byte
(0xC2 <= bytes[i] && bytes[i] <= 0xDF) &&
(0x80 <= bytes[i+1] && bytes[i+1] <= 0xBF)
)) {
i += 2;
continue;
}
if (( // excluding overlongs
bytes[i] === 0xE0 &&
(0xA0 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF)
) ||
( // straight 3-byte
((0xE1 <= bytes[i] && bytes[i] <= 0xEC) ||
bytes[i] === 0xEE ||
bytes[i] === 0xEF) &&
(0x80 <= bytes[i + 1] && bytes[i+1] <= 0xBF) &&
(0x80 <= bytes[i+2] && bytes[i+2] <= 0xBF)
) ||
( // excluding surrogates
bytes[i] === 0xED &&
(0x80 <= bytes[i+1] && bytes[i+1] <= 0x9F) &&
(0x80 <= bytes[i+2] && bytes[i+2] <= 0xBF)
)) {
i += 3;
continue;
}
if (( // planes 1-3
bytes[i] === 0xF0 &&
(0x90 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
) ||
( // planes 4-15
(0xF1 <= bytes[i] && bytes[i] <= 0xF3) &&
(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
) ||
( // plane 16
bytes[i] === 0xF4 &&
(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0x8F) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
)) {
i += 4;
continue;
}
return 0;
}
return onlyASCII ? 1 : 2;
}

View file

@ -4,7 +4,7 @@
* @license Apache-2.0
*/
export function encode(tempIVP, key, rounds, input) {
const ivp = new Uint8Array(key.concat(tempIVP));
const ivp = new Uint8Array([...key, ...tempIVP]);
const state = new Array(256).fill(0);
let j = 0, i = 0;
const result = [];

View file

@ -3,6 +3,7 @@
*
* @author Matt C [matt@artemisbot.uk]
* @author n1474335 [n1474335@gmail.com]
* @author Evie H [evie@evie.sh]
*
* @copyright Crown Copyright 2018
* @license Apache-2.0
@ -10,6 +11,7 @@
*/
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import CryptoJS from "crypto-js";
/**
@ -30,6 +32,10 @@ export function affineEncode(input, args) {
throw new OperationError("The values of a and b can only be integers.");
}
if (Utils.gcd(a, 26) !== 1) {
throw new OperationError("The value of `a` must be coprime to 26.");
}
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
// Uses the affine function ax+b % m = y (where m is length of the alphabet)

9
src/core/lib/Crypt.mjs Normal file
View file

@ -0,0 +1,9 @@
/**
* Crypt resources.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
export const cryptNotice = "WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";

View file

@ -12,15 +12,15 @@
*
* @param {string} input
* @param {RegExp} searchRegex
* @param {RegExp} removeRegex - A regular expression defining results to remove from the
* @param {RegExp} [removeRegex=null] - A regular expression defining results to remove from the
* final list
* @param {boolean} includeTotal - Whether or not to include the total number of results
* @param {Function} [sortBy=null] - The sorting comparison function to apply
* @param {boolean} [unique=false] - Whether to unique the results
* @returns {string}
*/
export function search (input, searchRegex, removeRegex, includeTotal) {
let output = "",
total = 0,
match;
export function search(input, searchRegex, removeRegex=null, sortBy=null, unique=false) {
let results = [];
let match;
while ((match = searchRegex.exec(input))) {
// Moves pointer when an empty string is matched (prevents infinite loop)
@ -30,14 +30,19 @@ export function search (input, searchRegex, removeRegex, includeTotal) {
if (removeRegex && removeRegex.test(match[0]))
continue;
total++;
output += match[0] + "\n";
results.push(match[0]);
}
if (includeTotal)
output = "Total found: " + total + "\n\n" + output;
if (sortBy) {
results = results.sort(sortBy);
}
return output;
if (unique) {
results = results.unique();
}
return results;
}
@ -57,3 +62,9 @@ export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:"
* Domain name regular expression
*/
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
/**
* DMARC Domain name regular expression
*/
export const DMARC_DOMAIN_REGEX = /\b((?=[a-z0-9_-]{1,63}\.)(xn--)?[a-z0-9_]+(-[a-z0-9_]+)*\.)+[a-z]{2,63}\b/ig;

View file

@ -70,6 +70,27 @@ export const FILE_SIGNATURES = {
10: 0x42,
11: 0x50
},
extractor: extractWEBP
},
{
name: "High Efficiency Image File Format",
extension: "heic,heif",
mime: "image/heif",
description: "",
signature: {
0: 0x00,
1: 0x00,
2: 0x00,
3: [0x24, 0x18],
4: 0x66, // ftypheic
5: 0x74,
6: 0x79,
7: 0x70,
8: 0x68,
9: 0x65,
10: 0x69,
11: 0x63
},
extractor: null
},
{
@ -2197,14 +2218,14 @@ export const FILE_SIGNATURES = {
mime: "application/octet-stream",
description: "",
signature: {
0: 0x6b, // keych
0: 0x6b, // kych
1: 0x79,
2: 0x63,
3: 0x68,
4: 0x00,
5: 0x01
},
extractor: null
extractor: extractMacOSXKeychain
},
{
name: "TCP Packet",
@ -2355,6 +2376,12 @@ export const FILE_SIGNATURES = {
1: 0x03,
2: 0xc6,
3: 0x04
},
{
0: 0x95,
1: 0x05,
2: 0x86,
3: 0x04
}
],
extractor: null
@ -2721,7 +2748,7 @@ export function extractGIF(bytes, offset) {
stream.moveForwardsBy(11);
// Loop until next Graphic Control Extension.
while (stream.getBytes(2) !== [0x21, 0xf9]) {
while (!Array.from(stream.getBytes(2)).equals([0x21, 0xf9])) {
stream.moveBackwardsBy(2);
stream.moveForwardsBy(stream.readInt(1));
if (!stream.readInt(1))
@ -3026,6 +3053,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.
*
@ -3406,6 +3457,26 @@ export function extractPListXML(bytes, offset) {
}
/**
* MacOS X Keychain Extactor.
*
* @param {Uint8Array} bytes
* @param {number} offset
* @returns {Uint8Array}
*/
export function extractMacOSXKeychain(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to size field.
stream.moveTo(0x14);
// Move forwards by size.
stream.moveForwardsBy(stream.readInt(4));
return stream.carve();
}
/**
* OLE2 extractor.
*
@ -3752,8 +3823,8 @@ function parseDEFLATE(stream) {
while (!finalBlock) {
// Read header
finalBlock = stream.readBits(1);
const blockType = stream.readBits(2);
finalBlock = stream.readBits(1, "le");
const blockType = stream.readBits(2, "le");
if (blockType === 0) {
/* No compression */
@ -3772,16 +3843,16 @@ function parseDEFLATE(stream) {
/* Dynamic Huffman */
// Read the number of liternal and length codes
const hlit = stream.readBits(5) + 257;
const hlit = stream.readBits(5, "le") + 257;
// Read the number of distance codes
const hdist = stream.readBits(5) + 1;
const hdist = stream.readBits(5, "le") + 1;
// Read the number of code lengths
const hclen = stream.readBits(4) + 4;
const hclen = stream.readBits(4, "le") + 4;
// Parse code lengths
const codeLengths = new Uint8Array(huffmanOrder.length);
for (let i = 0; i < hclen; i++) {
codeLengths[huffmanOrder[i]] = stream.readBits(3);
codeLengths[huffmanOrder[i]] = stream.readBits(3, "le");
}
// Parse length table
@ -3793,16 +3864,16 @@ function parseDEFLATE(stream) {
code = readHuffmanCode(stream, codeLengthsTable);
switch (code) {
case 16:
repeat = 3 + stream.readBits(2);
repeat = 3 + stream.readBits(2, "le");
while (repeat--) lengthTable[i++] = prev;
break;
case 17:
repeat = 3 + stream.readBits(3);
repeat = 3 + stream.readBits(3, "le");
while (repeat--) lengthTable[i++] = 0;
prev = 0;
break;
case 18:
repeat = 11 + stream.readBits(7);
repeat = 11 + stream.readBits(7, "le");
while (repeat--) lengthTable[i++] = 0;
prev = 0;
break;
@ -3860,11 +3931,11 @@ function parseHuffmanBlock(stream, litTab, distTab) {
if (code < 256) continue;
// Length code
stream.readBits(lengthExtraTable[code - 257]);
stream.readBits(lengthExtraTable[code - 257], "le");
// Dist code
code = readHuffmanCode(stream, distTab);
stream.readBits(distanceExtraTable[code]);
stream.readBits(distanceExtraTable[code], "le");
}
}
@ -3922,7 +3993,7 @@ function readHuffmanCode(stream, table) {
const [codeTable, maxCodeLength] = table;
// Read max length
const bitsBuf = stream.readBits(maxCodeLength);
const bitsBuf = stream.readBits(maxCodeLength, "le");
const codeWithLength = codeTable[bitsBuf & ((1 << maxCodeLength) - 1)];
const codeLength = codeWithLength >>> 16;

View file

@ -213,7 +213,7 @@ function locatePotentialSig(buf, sig, offset) {
export function isType(type, buf) {
const types = detectFileType(buf);
if (!(types && types.length)) return false;
if (!types.length) return false;
if (typeof type === "string") {
return types.reduce((acc, t) => {

253
src/core/lib/FuzzyMatch.mjs Normal file
View file

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

View file

@ -7,6 +7,7 @@
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
@ -100,14 +101,21 @@ export function toHexFast(data) {
* fromHex("0a:14:1e", "Colon");
*/
export function fromHex(data, delim="Auto", byteLen=2) {
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
throw new OperationError("Byte length must be a positive integer");
if (delim !== "None") {
const delimRegex = delim === "Auto" ? /[^a-f\d]|(0x)/gi : Utils.regexRep(delim);
data = data.replace(delimRegex, "");
const delimRegex = delim === "Auto" ? /[^a-f\d]|0x/gi : Utils.regexRep(delim);
data = data.split(delimRegex);
} else {
data = [data];
}
const output = [];
for (let i = 0; i < data.length; i += byteLen) {
output.push(parseInt(data.substr(i, byteLen), 16));
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].length; j += byteLen) {
output.push(parseInt(data[i].substr(j, byteLen), 16));
}
}
return output;
}

264
src/core/lib/JA4.mjs Normal file
View file

@ -0,0 +1,264 @@
/**
* JA4 resources.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*
* JA4 Copyright 2023 FoxIO, LLC.
* @license BSD-3-Clause
*/
import OperationError from "../errors/OperationError.mjs";
import { parseTLSRecord, parseHighestSupportedVersion, parseFirstALPNValue } from "./TLS.mjs";
import { toHexFast } from "./Hex.mjs";
import { runHash } from "./Hash.mjs";
import Utils from "../Utils.mjs";
/**
* Calculate the JA4 from a given TLS Client Hello Stream
* @param {Uint8Array} bytes
* @returns {string}
*/
export function toJA4(bytes) {
let tlsr = {};
try {
tlsr = parseTLSRecord(bytes);
if (tlsr.handshake.value.handshakeType.value !== 0x01) {
throw new Error();
}
} catch (err) {
throw new OperationError("Data is not a valid TLS Client Hello. QUIC is not yet supported.\n" + err);
}
/* QUIC
q or t, which denotes whether the hello packet is for QUIC or TCP.
TODO: Implement QUIC
*/
const ptype = "t";
/* TLS Version
TLS version is shown in 3 different places. If extension 0x002b exists (supported_versions), then the version
is the highest value in the extension. Remember to ignore GREASE values. If the extension doesnt exist, then
the TLS version is the value of the Protocol Version. Handshake version (located at the top of the packet)
should be ignored.
*/
let version = tlsr.handshake.value.helloVersion.value;
for (const ext of tlsr.handshake.value.extensions.value) {
if (ext.type.value === "supported_versions") {
version = parseHighestSupportedVersion(ext.value.data);
break;
}
}
version = tlsVersionMapper(version);
/* SNI
If the SNI extension (0x0000) exists, then the destination of the connection is a domain, or d in the fingerprint.
If the SNI does not exist, then the destination is an IP address, or i.
*/
let sni = "i";
for (const ext of tlsr.handshake.value.extensions.value) {
if (ext.type.value === "server_name") {
sni = "d";
break;
}
}
/* Number of Ciphers
2 character number of cipher suites, so if theres 6 cipher suites in the hello packet, then the value should be 06.
If theres > 99, which there should never be, then output 99. Remember, ignore GREASE values. They dont count.
*/
let cipherLen = 0;
for (const cs of tlsr.handshake.value.cipherSuites.value) {
if (cs.value !== "GREASE") cipherLen++;
}
cipherLen = cipherLen > 99 ? "99" : cipherLen.toString().padStart(2, "0");
/* Number of Extensions
Same as counting ciphers. Ignore GREASE. Include SNI and ALPN.
*/
let extLen = 0;
for (const ext of tlsr.handshake.value.extensions.value) {
if (ext.type.value !== "GREASE") extLen++;
}
extLen = extLen > 99 ? "99" : extLen.toString().padStart(2, "0");
/* ALPN Extension Value
The first and last characters of the ALPN (Application-Layer Protocol Negotiation) first value.
If there are no ALPN values or no ALPN extension then we print 00 as the value in the fingerprint.
*/
let alpn = "00";
for (const ext of tlsr.handshake.value.extensions.value) {
if (ext.type.value === "application_layer_protocol_negotiation") {
alpn = parseFirstALPNValue(ext.value.data);
alpn = alpn.charAt(0) + alpn.charAt(alpn.length - 1);
if (alpn.charCodeAt(0) > 127) alpn = "99";
break;
}
}
/* Cipher hash
A 12 character truncated sha256 hash of the list of ciphers sorted in hex order, first 12 characters.
The list is created using the 4 character hex values of the ciphers, lower case, comma delimited, ignoring GREASE.
*/
const originalCiphersList = [];
for (const cs of tlsr.handshake.value.cipherSuites.value) {
if (cs.value !== "GREASE") {
originalCiphersList.push(toHexFast(cs.data));
}
}
const sortedCiphersList = [...originalCiphersList].sort();
const sortedCiphersRaw = sortedCiphersList.join(",");
const originalCiphersRaw = originalCiphersList.join(",");
const sortedCiphers = runHash(
"sha256",
Utils.strToArrayBuffer(sortedCiphersRaw)
).substring(0, 12);
const originalCiphers = runHash(
"sha256",
Utils.strToArrayBuffer(originalCiphersRaw)
).substring(0, 12);
/* Extension hash
A 12 character truncated sha256 hash of the list of extensions, sorted by hex value, followed by the list of signature
algorithms, in the order that they appear (not sorted).
The extension list is created using the 4 character hex values of the extensions, lower case, comma delimited, sorted
(not in the order they appear). Ignore the SNI extension (0000) and the ALPN extension (0010) as weve already captured
them in the a section of the fingerprint. These values are omitted so that the same application would have the same b
section of the fingerprint regardless of if it were going to a domain, IP, or changing ALPNs.
*/
const originalExtensionsList = [];
let signatureAlgorithms = "";
for (const ext of tlsr.handshake.value.extensions.value) {
if (ext.type.value !== "GREASE") {
originalExtensionsList.push(toHexFast(ext.type.data));
}
if (ext.type.value === "signature_algorithms") {
signatureAlgorithms = toHexFast(ext.value.data.slice(2));
signatureAlgorithms = signatureAlgorithms.replace(/(.{4})/g, "$1,");
signatureAlgorithms = signatureAlgorithms.substring(0, signatureAlgorithms.length - 1);
}
}
const sortedExtensionsList = [...originalExtensionsList].filter(e => e !== "0000" && e !== "0010").sort();
const sortedExtensionsRaw = sortedExtensionsList.join(",") + "_" + signatureAlgorithms;
const originalExtensionsRaw = originalExtensionsList.join(",") + "_" + signatureAlgorithms;
const sortedExtensions = runHash(
"sha256",
Utils.strToArrayBuffer(sortedExtensionsRaw)
).substring(0, 12);
const originalExtensions = runHash(
"sha256",
Utils.strToArrayBuffer(originalExtensionsRaw)
).substring(0, 12);
return {
"JA4": `${ptype}${version}${sni}${cipherLen}${extLen}${alpn}_${sortedCiphers}_${sortedExtensions}`,
"JA4_o": `${ptype}${version}${sni}${cipherLen}${extLen}${alpn}_${originalCiphers}_${originalExtensions}`,
"JA4_r": `${ptype}${version}${sni}${cipherLen}${extLen}${alpn}_${sortedCiphersRaw}_${sortedExtensionsRaw}`,
"JA4_ro": `${ptype}${version}${sni}${cipherLen}${extLen}${alpn}_${originalCiphersRaw}_${originalExtensionsRaw}`,
};
}
/**
* Calculate the JA4Server from a given TLS Server Hello Stream
* @param {Uint8Array} bytes
* @returns {string}
*/
export function toJA4S(bytes) {
let tlsr = {};
try {
tlsr = parseTLSRecord(bytes);
if (tlsr.handshake.value.handshakeType.value !== 0x02) {
throw new Error();
}
} catch (err) {
throw new OperationError("Data is not a valid TLS Server Hello. QUIC is not yet supported.\n" + err);
}
/* QUIC
q or t, which denotes whether the hello packet is for QUIC or TCP.
TODO: Implement QUIC
*/
const ptype = "t";
/* TLS Version
TLS version is shown in 3 different places. If extension 0x002b exists (supported_versions), then the version
is the highest value in the extension. Remember to ignore GREASE values. If the extension doesnt exist, then
the TLS version is the value of the Protocol Version. Handshake version (located at the top of the packet)
should be ignored.
*/
let version = tlsr.handshake.value.helloVersion.value;
for (const ext of tlsr.handshake.value.extensions.value) {
if (ext.type.value === "supported_versions") {
version = parseHighestSupportedVersion(ext.value.data);
break;
}
}
version = tlsVersionMapper(version);
/* Number of Extensions
2 character number of cipher suites, so if theres 6 cipher suites in the hello packet, then the value should be 06.
If theres > 99, which there should never be, then output 99.
*/
let extLen = tlsr.handshake.value.extensions.value.length;
extLen = extLen > 99 ? "99" : extLen.toString().padStart(2, "0");
/* ALPN Extension Chosen Value
The first and last characters of the ALPN (Application-Layer Protocol Negotiation) first value.
If there are no ALPN values or no ALPN extension then we print 00 as the value in the fingerprint.
*/
let alpn = "00";
for (const ext of tlsr.handshake.value.extensions.value) {
if (ext.type.value === "application_layer_protocol_negotiation") {
alpn = parseFirstALPNValue(ext.value.data);
alpn = alpn.charAt(0) + alpn.charAt(alpn.length - 1);
if (alpn.charCodeAt(0) > 127) alpn = "99";
break;
}
}
/* Chosen Cipher
The hex value of the chosen cipher suite
*/
const cipher = toHexFast(tlsr.handshake.value.cipherSuite.data);
/* Extension hash
A 12 character truncated sha256 hash of the list of extensions.
The extension list is created using the 4 character hex values of the extensions, lower case, comma delimited.
*/
const extensionsList = [];
for (const ext of tlsr.handshake.value.extensions.value) {
extensionsList.push(toHexFast(ext.type.data));
}
const extensionsRaw = extensionsList.join(",");
const extensionsHash = runHash(
"sha256",
Utils.strToArrayBuffer(extensionsRaw)
).substring(0, 12);
return {
"JA4S": `${ptype}${version}${extLen}${alpn}_${cipher}_${extensionsHash}`,
"JA4S_r": `${ptype}${version}${extLen}${alpn}_${cipher}_${extensionsRaw}`,
};
}
/**
* Takes a TLS version value and returns a JA4 TLS version string
* @param {Uint8Array} version - Two byte array of version number
* @returns {string}
*/
function tlsVersionMapper(version) {
switch (version) {
case 0x0304: return "13"; // TLS 1.3
case 0x0303: return "12"; // TLS 1.2
case 0x0302: return "11"; // TLS 1.1
case 0x0301: return "10"; // TLS 1.0
case 0x0300: return "s3"; // SSL 3.0
case 0x0200: return "s2"; // SSL 2.0
case 0x0100: return "s1"; // SSL 1.0
default: return "00"; // Unknown
}
}

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

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

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

88
src/core/lib/LZNT1.mjs Normal file
View file

@ -0,0 +1,88 @@
/**
*
* LZNT1 Decompress.
*
* @author 0xThiebaut [thiebaut.dev]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*
* https://github.com/Velocidex/go-ntfs/blob/master/parser%2Flznt1.go
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
const COMPRESSED_MASK = 1 << 15,
SIZE_MASK = (1 << 12) - 1;
/**
* @param {number} offset
* @returns {number}
*/
function getDisplacement(offset) {
let result = 0;
while (offset >= 0x10) {
offset >>= 1;
result += 1;
}
return result;
}
/**
* @param {byteArray} compressed
* @returns {byteArray}
*/
export function decompress(compressed) {
const decompressed = Array();
let coffset = 0;
while (coffset + 2 <= compressed.length) {
const doffset = decompressed.length;
const blockHeader = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little");
coffset += 2;
const size = blockHeader & SIZE_MASK;
const blockEnd = coffset + size + 1;
if (size === 0) {
break;
} else if (compressed.length < coffset + size) {
throw new OperationError("Malformed LZNT1 stream: Block too small! Has the stream been truncated?");
}
if ((blockHeader & COMPRESSED_MASK) !== 0) {
while (coffset < blockEnd) {
let header = compressed[coffset++];
for (let i = 0; i < 8 && coffset < blockEnd; i++) {
if ((header & 1) === 0) {
decompressed.push(compressed[coffset++]);
} else {
const pointer = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little");
coffset += 2;
const displacement = getDisplacement(decompressed.length - doffset - 1);
const symbolOffset = (pointer >> (12 - displacement)) + 1;
const symbolLength = (pointer & (0xFFF >> displacement)) + 2;
const shiftOffset = decompressed.length - symbolOffset;
for (let shiftDelta = 0; shiftDelta < symbolLength + 1; shiftDelta++) {
const shift = shiftOffset + shiftDelta;
if (shift < 0 || decompressed.length <= shift) {
throw new OperationError("Malformed LZNT1 stream: Invalid shift!");
}
decompressed.push(decompressed[shift]);
}
}
header >>= 1;
}
}
} else {
decompressed.push(...compressed.slice(coffset, coffset + size + 1));
coffset += size + 1;
}
}
return decompressed;
}

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

@ -1,8 +1,9 @@
import OperationConfig from "../config/OperationConfig.json";
import OperationConfig from "../config/OperationConfig.json" assert {type: "json"};
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
import Recipe from "../Recipe.mjs";
import Dish from "../Dish.mjs";
import {detectFileType, isType} from "./FileType.mjs";
import {isUTF8} from "./ChrEnc.mjs";
import chiSquared from "chi-squared";
/**
@ -111,82 +112,6 @@ class Magic {
};
}
/**
* Detects whether the input buffer is valid UTF8.
*
* @returns {boolean}
*/
isUTF8() {
const bytes = new Uint8Array(this.inputBuffer);
let i = 0;
while (i < bytes.length) {
if (( // ASCII
bytes[i] === 0x09 ||
bytes[i] === 0x0A ||
bytes[i] === 0x0D ||
(0x20 <= bytes[i] && bytes[i] <= 0x7E)
)) {
i += 1;
continue;
}
if (( // non-overlong 2-byte
(0xC2 <= bytes[i] && bytes[i] <= 0xDF) &&
(0x80 <= bytes[i+1] && bytes[i+1] <= 0xBF)
)) {
i += 2;
continue;
}
if (( // excluding overlongs
bytes[i] === 0xE0 &&
(0xA0 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF)
) ||
( // straight 3-byte
((0xE1 <= bytes[i] && bytes[i] <= 0xEC) ||
bytes[i] === 0xEE ||
bytes[i] === 0xEF) &&
(0x80 <= bytes[i + 1] && bytes[i+1] <= 0xBF) &&
(0x80 <= bytes[i+2] && bytes[i+2] <= 0xBF)
) ||
( // excluding surrogates
bytes[i] === 0xED &&
(0x80 <= bytes[i+1] && bytes[i+1] <= 0x9F) &&
(0x80 <= bytes[i+2] && bytes[i+2] <= 0xBF)
)) {
i += 3;
continue;
}
if (( // planes 1-3
bytes[i] === 0xF0 &&
(0x90 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
) ||
( // planes 4-15
(0xF1 <= bytes[i] && bytes[i] <= 0xF3) &&
(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
) ||
( // plane 16
bytes[i] === 0xF4 &&
(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0x8F) &&
(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
)) {
i += 4;
continue;
}
return false;
}
return true;
}
/**
* Calculates the Shannon entropy of the input data.
*
@ -336,7 +261,7 @@ class Magic {
data: this.inputStr.slice(0, 100),
languageScores: this.detectLanguage(extLang),
fileType: this.detectFileType(),
isUTF8: this.isUTF8(),
isUTF8: !!isUTF8(this.inputBuffer),
entropy: this.calcEntropy(),
matchingOps: matchingOps,
useful: useful,

165
src/core/lib/Modhex.mjs Normal file
View file

@ -0,0 +1,165 @@
/**
* @author linuxgemini [ilteris@asenkron.com.tr]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
import { fromHex, toHex } from "./Hex.mjs";
/**
* Modhex alphabet.
*/
const MODHEX_ALPHABET = "cbdefghijklnrtuv";
/**
* Modhex alphabet map.
*/
const MODHEX_ALPHABET_MAP = MODHEX_ALPHABET.split("");
/**
* Hex alphabet to substitute Modhex.
*/
const HEX_ALPHABET = "0123456789abcdef";
/**
* Hex alphabet map to substitute Modhex.
*/
const HEX_ALPHABET_MAP = HEX_ALPHABET.split("");
/**
* Convert a byte array into a modhex string.
*
* @param {byteArray|Uint8Array|ArrayBuffer} data
* @param {string} [delim=" "]
* @param {number} [padding=2]
* @returns {string}
*
* @example
* // returns "cl bf bu"
* toModhex([10,20,30]);
*
* // returns "cl:bf:bu"
* toModhex([10,20,30], ":");
*/
export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
if (!data) return "";
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
const regularHexString = toHex(data, "", padding, "", 0);
let modhexString = "";
for (const letter of regularHexString.split("")) {
modhexString += MODHEX_ALPHABET_MAP[HEX_ALPHABET_MAP.indexOf(letter)];
}
let output = "";
const groupingRegexp = new RegExp(`.{1,${padding}}`, "g");
const groupedModhex = modhexString.match(groupingRegexp);
for (let i = 0; i < groupedModhex.length; i++) {
const group = groupedModhex[i];
output += group + delim;
if (extraDelim) {
output += extraDelim;
}
// Add LF after each lineSize amount of bytes but not at the end
if ((i !== groupedModhex.length - 1) && ((i + 1) % lineSize === 0)) {
output += "\n";
}
}
// Remove the extraDelim at the end (if there is one)
// and remove the delim at the end, but if it's prepended there's nothing to remove
const rTruncLen = extraDelim.length + delim.length;
if (rTruncLen) {
// If rTruncLen === 0 then output.slice(0,0) will be returned, which is nothing
return output.slice(0, -rTruncLen);
} else {
return output;
}
}
/**
* Convert a byte array into a modhex string as efficiently as possible with no options.
*
* @param {byteArray|Uint8Array|ArrayBuffer} data
* @returns {string}
*
* @example
* // returns "clbfbu"
* toModhexFast([10,20,30]);
*/
export function toModhexFast(data) {
if (!data) return "";
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
const output = [];
for (let i = 0; i < data.length; i++) {
output.push(MODHEX_ALPHABET_MAP[(data[i] >> 4) & 0xf]);
output.push(MODHEX_ALPHABET_MAP[data[i] & 0xf]);
}
return output.join("");
}
/**
* Convert a modhex string into a byte array.
*
* @param {string} data
* @param {string} [delim]
* @param {number} [byteLen=2]
* @returns {byteArray}
*
* @example
* // returns [10,20,30]
* fromModhex("cl bf bu");
*
* // returns [10,20,30]
* fromModhex("cl:bf:bu", "Colon");
*/
export function fromModhex(data, delim="Auto", byteLen=2) {
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
throw new OperationError("Byte length must be a positive integer");
// The `.replace(/\s/g, "")` an interesting workaround: Hex "multiline" tests aren't actually
// multiline. Tests for Modhex fixes that, thus exposing the issue.
data = data.toLowerCase().replace(/\s/g, "");
if (delim !== "None") {
const delimRegex = delim === "Auto" ? /[^cbdefghijklnrtuv]/gi : Utils.regexRep(delim);
data = data.split(delimRegex);
} else {
data = [data];
}
let regularHexString = "";
for (let i = 0; i < data.length; i++) {
for (const letter of data[i].split("")) {
regularHexString += HEX_ALPHABET_MAP[MODHEX_ALPHABET_MAP.indexOf(letter)];
}
}
const output = fromHex(regularHexString, "None", byteLen);
return output;
}
/**
* To Modhex delimiters.
*/
export const TO_MODHEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "None"];
/**
* From Modhex delimiters.
*/
export const FROM_MODHEX_DELIM_OPTIONS = ["Auto"].concat(TO_MODHEX_DELIM_OPTIONS);

View file

@ -1,4 +1,5 @@
import Utils from "../Utils.mjs";
import protobuf from "protobufjs";
/**
* Protobuf lib. Contains functions to decode protobuf serialised
@ -32,9 +33,10 @@ class Protobuf {
this.MSB = 0x80;
this.VALUE = 0x7f;
// Declare offset and length
// Declare offset, length, and field type object
this.offset = 0;
this.LENGTH = data.length;
this.fieldTypes = {};
}
// Public Functions
@ -76,15 +78,281 @@ class Protobuf {
return pb._varInt();
}
/**
* Encode input JSON according to the given schema
*
* @param {Object} input
* @param {Object []} args
* @returns {Object}
*/
static encode(input, args) {
this.updateProtoRoot(args[0]);
if (!this.mainMessageName) {
throw new Error("Schema Error: Schema not defined");
}
const message = this.parsedProto.root.nested[this.mainMessageName];
// Convert input into instance of message, and verify instance
input = message.fromObject(input);
const error = message.verify(input);
if (error) {
throw new Error("Input Error: " + error);
}
// Encode input
const output = message.encode(input).finish();
return new Uint8Array(output).buffer;
}
/**
* Parse Protobuf data
*
* @param {byteArray} input
* @returns {Object}
*/
static decode(input) {
static decode(input, args) {
this.updateProtoRoot(args[0]);
this.showUnknownFields = args[1];
this.showTypes = args[2];
return this.mergeDecodes(input);
}
/**
* Update the parsedProto, throw parsing errors
*
* @param {string} protoText
*/
static updateProtoRoot(protoText) {
try {
this.parsedProto = protobuf.parse(protoText);
if (this.parsedProto.package) {
this.parsedProto.root = this.parsedProto.root.nested[this.parsedProto.package];
}
this.updateMainMessageName();
} catch (error) {
throw new Error("Schema " + error);
}
}
/**
* Set mainMessageName to the first instance of a message defined in the schema that is not a submessage
*
*/
static updateMainMessageName() {
const messageNames = [];
const fieldTypes = [];
this.parsedProto.root.nestedArray.forEach(block => {
if (block instanceof protobuf.Type) {
messageNames.push(block.name);
this.parsedProto.root.nested[block.name].fieldsArray.forEach(field => {
fieldTypes.push(field.type);
});
}
});
if (messageNames.length === 0) {
this.mainMessageName = null;
} else {
// for (const name of messageNames) {
// if (!fieldTypes.includes(name)) {
// this.mainMessageName = name;
// break;
// }
// }
this.mainMessageName = messageNames[0];
}
}
/**
* Decode input using Protobufjs package and raw methods, compare, and merge results
*
* @param {byteArray} input
* @returns {Object}
*/
static mergeDecodes(input) {
const pb = new Protobuf(input);
return pb._parse();
let rawDecode = pb._parse();
let message;
if (this.showTypes) {
rawDecode = this.showRawTypes(rawDecode, pb.fieldTypes);
this.parsedProto.root = this.appendTypesToFieldNames(this.parsedProto.root);
}
try {
message = this.parsedProto.root.nested[this.mainMessageName];
const packageDecode = message.toObject(message.decode(input), {
bytes: String,
longs: Number,
enums: String,
defaults: true
});
const output = {};
if (this.showUnknownFields) {
output[message.name] = packageDecode;
output["Unknown Fields"] = this.compareFields(rawDecode, message);
return output;
} else {
return packageDecode;
}
} catch (error) {
if (message) {
throw new Error("Input " + error);
} else {
return rawDecode;
}
}
}
/**
* Replace fieldnames with fieldname and type
*
* @param {Object} schemaRoot
* @returns {Object}
*/
static appendTypesToFieldNames(schemaRoot) {
for (const block of schemaRoot.nestedArray) {
if (block instanceof protobuf.Type) {
for (const [fieldName, fieldData] of Object.entries(block.fields)) {
schemaRoot.nested[block.name].remove(block.fields[fieldName]);
schemaRoot.nested[block.name].add(new protobuf.Field(`${fieldName} (${fieldData.type})`, fieldData.id, fieldData.type, fieldData.rule));
}
}
}
return schemaRoot;
}
/**
* Add field type to field name for fields in the raw decoded output
*
* @param {Object} rawDecode
* @param {Object} fieldTypes
* @returns {Object}
*/
static showRawTypes(rawDecode, fieldTypes) {
for (const [fieldNum, value] of Object.entries(rawDecode)) {
const fieldType = fieldTypes[fieldNum];
let outputFieldValue;
let outputFieldType;
// Submessages
if (isNaN(fieldType)) {
outputFieldType = 2;
// Repeated submessages
if (Array.isArray(value)) {
const fieldInstances = [];
for (const instance of Object.keys(value)) {
if (typeof(value[instance]) !== "string") {
fieldInstances.push(this.showRawTypes(value[instance], fieldType));
} else {
fieldInstances.push(value[instance]);
}
}
outputFieldValue = fieldInstances;
// Single submessage
} else {
outputFieldValue = this.showRawTypes(value, fieldType);
}
// Non-submessage field
} else {
outputFieldType = fieldType;
outputFieldValue = value;
}
// Substitute fieldNum with field number and type
rawDecode[`field #${fieldNum}: ${this.getTypeInfo(outputFieldType)}`] = outputFieldValue;
delete rawDecode[fieldNum];
}
return rawDecode;
}
/**
* Compare raw decode to package decode and return discrepancies
*
* @param rawDecodedMessage
* @param schemaMessage
* @returns {Object}
*/
static compareFields(rawDecodedMessage, schemaMessage) {
// Define message data using raw decode output and schema
const schemaFieldProperties = {};
const schemaFieldNames = Object.keys(schemaMessage.fields);
schemaFieldNames.forEach(field => schemaFieldProperties[schemaMessage.fields[field].id] = field);
// Loop over each field present in the raw decode output
for (const fieldName in rawDecodedMessage) {
let fieldId;
if (isNaN(fieldName)) {
fieldId = fieldName.match(/^field #(\d+)/)[1];
} else {
fieldId = fieldName;
}
// Check if this field is defined in the schema
if (fieldId in schemaFieldProperties) {
const schemaFieldName = schemaFieldProperties[fieldId];
// Extract the current field data from the raw decode and schema
const rawFieldData = rawDecodedMessage[fieldName];
const schemaField = schemaMessage.fields[schemaFieldName];
// Check for repeated fields
if (Array.isArray(rawFieldData) && !schemaField.repeated) {
rawDecodedMessage[`(${schemaMessage.name}) ${schemaFieldName} is a repeated field`] = rawFieldData;
}
// Check for submessage fields
if (schemaField.resolvedType instanceof protobuf.Type) {
const subMessageType = schemaMessage.fields[schemaFieldName].type;
const schemaSubMessage = this.parsedProto.root.nested[subMessageType];
const rawSubMessages = rawDecodedMessage[fieldName];
let rawDecodedSubMessage = {};
// Squash multiple submessage instances into one submessage
if (Array.isArray(rawSubMessages)) {
rawSubMessages.forEach(subMessageInstance => {
const instanceFields = Object.entries(subMessageInstance);
instanceFields.forEach(subField => {
rawDecodedSubMessage[subField[0]] = subField[1];
});
});
} else {
rawDecodedSubMessage = rawSubMessages;
}
// Treat submessage as own message and compare its fields
rawDecodedSubMessage = Protobuf.compareFields(rawDecodedSubMessage, schemaSubMessage);
if (Object.entries(rawDecodedSubMessage).length !== 0) {
rawDecodedMessage[`${schemaFieldName} (${subMessageType}) has missing fields`] = rawDecodedSubMessage;
}
}
delete rawDecodedMessage[fieldName];
}
}
return rawDecodedMessage;
}
/**
* Returns wiretype information for input wiretype number
*
* @param {number} wireType
* @returns {string}
*/
static getTypeInfo(wireType) {
switch (wireType) {
case 0:
return "VarInt (e.g. int32, bool)";
case 1:
return "64-Bit (e.g. fixed64, double)";
case 2:
return "L-delim (e.g. string, message)";
case 5:
return "32-Bit (e.g. fixed32, float)";
}
}
// Private Class Functions
@ -143,6 +411,11 @@ class Protobuf {
const header = this._fieldHeader();
const type = header.type;
const key = header.key;
if (typeof(this.fieldTypes[key]) !== "object") {
this.fieldTypes[key] = type;
}
switch (type) {
// varint
case 0:
@ -152,7 +425,7 @@ class Protobuf {
return { "key": key, "value": this._uint64() };
// length delimited
case 2:
return { "key": key, "value": this._lenDelim() };
return { "key": key, "value": this._lenDelim(key) };
// fixed 32
case 5:
return { "key": key, "value": this._uint32() };
@ -237,10 +510,10 @@ class Protobuf {
* @returns {number}
*/
_uint64() {
// Read off a Uint64
let num = this.data[this.offset++] * 0x1000000 + (this.data[this.offset++] << 16) + (this.data[this.offset++] << 8) + this.data[this.offset++];
num = num * 0x100000000 + this.data[this.offset++] * 0x1000000 + (this.data[this.offset++] << 16) + (this.data[this.offset++] << 8) + this.data[this.offset++];
return num;
// Read off a Uint64 with little-endian
const lowerHalf = this.data[this.offset++] + (this.data[this.offset++] * 0x100) + (this.data[this.offset++] * 0x10000) + this.data[this.offset++] * 0x1000000;
const upperHalf = this.data[this.offset++] + (this.data[this.offset++] * 0x100) + (this.data[this.offset++] * 0x10000) + this.data[this.offset++] * 0x1000000;
return upperHalf * 0x100000000 + lowerHalf;
}
/**
@ -249,7 +522,7 @@ class Protobuf {
* @private
* @returns {Object|string}
*/
_lenDelim() {
_lenDelim(fieldNum) {
// Read off the field length
const length = this._varInt();
const fieldBytes = this.data.slice(this.offset, this.offset + length);
@ -258,6 +531,10 @@ class Protobuf {
// Attempt to parse as a new Protobuf Object
const pbObject = new Protobuf(fieldBytes);
field = pbObject._parse();
// Set field types object
this.fieldTypes[fieldNum] = {...this.fieldTypes[fieldNum], ...pbObject.fieldTypes};
} catch (err) {
// Otherwise treat as bytes
field = Utils.byteArrayToChars(fieldBytes);
@ -276,7 +553,7 @@ class Protobuf {
_uint32() {
// Use a dataview to read off the integer
const dataview = new DataView(new Uint8Array(this.data.slice(this.offset, this.offset + 4)).buffer);
const value = dataview.getUint32(0);
const value = dataview.getUint32(0, true);
this.offset += 4;
return value;
}

50
src/core/lib/Protocol.mjs Normal file
View file

@ -0,0 +1,50 @@
/**
* Protocol parsing functions.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import BigNumber from "bignumber.js";
import {toHexFast} from "../lib/Hex.mjs";
/**
* Recursively displays a JSON object as an HTML table
*
* @param {Object} obj
* @returns string
*/
export function objToTable(obj, nested=false) {
let html = `<table
class='table table-sm table-nonfluid ${nested ? "mb-0 table-borderless" : "table-bordered"}'
style='table-layout: fixed; ${nested ? "margin: -1px !important;" : ""}'>`;
if (!nested)
html += `<tr>
<th>Field</th>
<th>Value</th>
</tr>`;
for (const key in obj) {
if (typeof obj[key] === "function")
continue;
html += `<tr><td style='word-wrap: break-word'>${key}</td>`;
if (typeof obj[key] === "object")
html += `<td style='padding: 0'>${objToTable(obj[key], true)}</td>`;
else
html += `<td>${obj[key]}</td>`;
html += "</tr>";
}
html += "</table>";
return html;
}
/**
* Converts bytes into a BigNumber string
* @param {Uint8Array} bs
* @returns {string}
*/
export function bytesToLargeNumber(bs) {
return BigNumber(toHexFast(bs), 16).toString();
}

View file

@ -9,35 +9,25 @@
import { toHex, fromHex } from "./Hex.mjs";
/**
* Formats Distinguished Name (DN) strings.
* Formats Distinguished Name (DN) objects to strings.
*
* @param {string} dnStr
* @param {Object} dnObj
* @param {number} indent
* @returns {string}
*/
export function formatDnStr (dnStr, indent) {
const fields = dnStr.substr(1).replace(/([^\\])\//g, "$1$1/").split(/[^\\]\//);
let output = "",
maxKeyLen = 0,
key,
value,
i,
str;
export function formatDnObj(dnObj, indent) {
let output = "";
for (i = 0; i < fields.length; i++) {
if (!fields[i].length) continue;
const maxKeyLen = dnObj.array.reduce((max, item) => {
return item[0].type.length > max ? item[0].type.length : max;
}, 0);
key = fields[i].split("=")[0];
for (let i = 0; i < dnObj.array.length; i++) {
if (!dnObj.array[i].length) continue;
maxKeyLen = key.length > maxKeyLen ? key.length : maxKeyLen;
}
for (i = 0; i < fields.length; i++) {
if (!fields[i].length) continue;
key = fields[i].split("=")[0];
value = fields[i].split("=")[1];
str = key.padEnd(maxKeyLen, " ") + " = " + value + "\n";
const key = dnObj.array[i][0].type;
const value = dnObj.array[i][0].value;
const str = `${key.padEnd(maxKeyLen, " ")} = ${value}\n`;
output += str.padStart(indent + str.length, " ");
}
@ -54,7 +44,7 @@ export function formatDnStr (dnStr, indent) {
* @param {number} indent
* @returns {string}
*/
export function formatByteStr (byteStr, length, indent) {
export function formatByteStr(byteStr, length, indent) {
byteStr = toHex(fromHex(byteStr), ":");
length = length * 3;
let output = "";

View file

@ -10,8 +10,7 @@ import OperationError from "../errors/OperationError.mjs";
import jsQR from "jsqr";
import qr from "qr-image";
import Utils from "../Utils.mjs";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
import Jimp from "jimp/es/index.js";
/**
* Parses a QR code image from an image
@ -23,7 +22,7 @@ const jimp = jimplib.default ? jimplib.default : jimplib;
export async function parseQrCode(input, normalise) {
let image;
try {
image = await jimp.read(input);
image = await Jimp.read(input);
} catch (err) {
throw new OperationError(`Error opening image. (${err})`);
}
@ -34,8 +33,8 @@ export async function parseQrCode(input, normalise) {
image.background(0xFFFFFFFF);
image.normalize();
image.greyscale();
image = await image.getBufferAsync(jimp.MIME_JPEG);
image = await jimp.read(image);
image = await image.getBufferAsync(Jimp.MIME_JPEG);
image = await Jimp.read(image);
}
} catch (err) {
throw new OperationError(`Error normalising image. (${err})`);

502
src/core/lib/SIGABA.mjs Normal file
View file

@ -0,0 +1,502 @@
/**
* Emulation of the SIGABA machine
*
* @author hettysymes
* @copyright hettysymes 2020
* @license Apache-2.0
*/
/**
* A set of randomised example SIGABA cipher/control rotors (these rotors are interchangeable). Cipher and control rotors can be referred to as C and R rotors respectively.
*/
export const CR_ROTORS = [
{name: "Example 1", value: "SRGWANHPJZFXVIDQCEUKBYOLMT"},
{name: "Example 2", value: "THQEFSAZVKJYULBODCPXNIMWRG"},
{name: "Example 3", value: "XDTUYLEVFNQZBPOGIRCSMHWKAJ"},
{name: "Example 4", value: "LOHDMCWUPSTNGVXYFJREQIKBZA"},
{name: "Example 5", value: "ERXWNZQIJYLVOFUMSGHTCKPBDA"},
{name: "Example 6", value: "FQECYHJIOUMDZVPSLKRTGWXBAN"},
{name: "Example 7", value: "TBYIUMKZDJSOPEWXVANHLCFQGR"},
{name: "Example 8", value: "QZUPDTFNYIAOMLEBWJXCGHKRSV"},
{name: "Example 9", value: "CZWNHEMPOVXLKRSIDGJFYBTQAU"},
{name: "Example 10", value: "ENPXJVKYQBFZTICAGMOHWRLDUS"}
];
/**
* A set of randomised example SIGABA index rotors (may be referred to as I rotors).
*/
export const I_ROTORS = [
{name: "Example 1", value: "6201348957"},
{name: "Example 2", value: "6147253089"},
{name: "Example 3", value: "8239647510"},
{name: "Example 4", value: "7194835260"},
{name: "Example 5", value: "4873205916"}
];
export const NUMBERS = "0123456789".split("");
/**
* Converts a letter to uppercase (if it already isn't)
*
* @param {char} letter - letter to convert to uppercase
* @returns {char}
*/
export function convToUpperCase(letter) {
const charCode = letter.charCodeAt();
if (97<=charCode && charCode<=122) {
return String.fromCharCode(charCode-32);
}
return letter;
}
/**
* The SIGABA machine consisting of the 3 rotor banks: cipher, control and index banks.
*/
export class SigabaMachine {
/**
* SigabaMachine constructor
*
* @param {Object[]} cipherRotors - list of CRRotors
* @param {Object[]} controlRotors - list of CRRotors
* @param {object[]} indexRotors - list of IRotors
*/
constructor(cipherRotors, controlRotors, indexRotors) {
this.cipherBank = new CipherBank(cipherRotors);
this.controlBank = new ControlBank(controlRotors);
this.indexBank = new IndexBank(indexRotors);
}
/**
* Steps all the correct rotors in the machine.
*/
step() {
const controlOut = this.controlBank.goThroughControl();
const indexOut = this.indexBank.goThroughIndex(controlOut);
this.cipherBank.step(indexOut);
}
/**
* Encrypts a letter. A space is converted to a "Z" before encryption, and a "Z" is converted to an "X". This allows spaces to be encrypted.
*
* @param {char} letter - letter to encrypt
* @returns {char}
*/
encryptLetter(letter) {
letter = convToUpperCase(letter);
if (letter === " ") {
letter = "Z";
} else if (letter === "Z") {
letter = "X";
}
const encryptedLetter = this.cipherBank.encrypt(letter);
this.step();
return encryptedLetter;
}
/**
* Decrypts a letter. A letter decrypted as a "Z" is converted to a space before it is output, since spaces are converted to "Z"s before encryption.
*
* @param {char} letter - letter to decrypt
* @returns {char}
*/
decryptLetter(letter) {
letter = convToUpperCase(letter);
let decryptedLetter = this.cipherBank.decrypt(letter);
if (decryptedLetter === "Z") {
decryptedLetter = " ";
}
this.step();
return decryptedLetter;
}
/**
* Encrypts a message of one or more letters
*
* @param {string} msg - message to encrypt
* @returns {string}
*/
encrypt(msg) {
let ciphertext = "";
for (const letter of msg) {
ciphertext = ciphertext.concat(this.encryptLetter(letter));
}
return ciphertext;
}
/**
* Decrypts a message of one or more letters
*
* @param {string} msg - message to decrypt
* @returns {string}
*/
decrypt(msg) {
let plaintext = "";
for (const letter of msg) {
plaintext = plaintext.concat(this.decryptLetter(letter));
}
return plaintext;
}
}
/**
* The cipher rotor bank consists of 5 cipher rotors in either a forward or reversed orientation.
*/
export class CipherBank {
/**
* CipherBank constructor
*
* @param {Object[]} rotors - list of CRRotors
*/
constructor(rotors) {
this.rotors = rotors;
}
/**
* Encrypts a letter through the cipher rotors (signal goes from left-to-right)
*
* @param {char} inputPos - the input position of the signal (letter to be encrypted)
* @returns {char}
*/
encrypt(inputPos) {
for (const rotor of this.rotors) {
inputPos = rotor.crypt(inputPos, "leftToRight");
}
return inputPos;
}
/**
* Decrypts a letter through the cipher rotors (signal goes from right-to-left)
*
* @param {char} inputPos - the input position of the signal (letter to be decrypted)
* @returns {char}
*/
decrypt(inputPos) {
const revOrderedRotors = [...this.rotors].reverse();
for (const rotor of revOrderedRotors) {
inputPos = rotor.crypt(inputPos, "rightToLeft");
}
return inputPos;
}
/**
* Step the cipher rotors forward according to the inputs from the index rotors
*
* @param {number[]} indexInputs - the inputs from the index rotors
*/
step(indexInputs) {
const logicDict = {0: [0, 9], 1: [7, 8], 2: [5, 6], 3: [3, 4], 4: [1, 2]};
const rotorsToMove = [];
for (const key in logicDict) {
const item = logicDict[key];
for (const i of indexInputs) {
if (item.includes(i)) {
rotorsToMove.push(this.rotors[key]);
break;
}
}
}
for (const rotor of rotorsToMove) {
rotor.step();
}
}
}
/**
* The control rotor bank consists of 5 control rotors in either a forward or reversed orientation. Signals to the control rotor bank always go from right-to-left.
*/
export class ControlBank {
/**
* ControlBank constructor. The rotors have been reversed as signals go from right-to-left through the control rotors.
*
* @param {Object[]} rotors - list of CRRotors
*/
constructor(rotors) {
this.rotors = [...rotors].reverse();
}
/**
* Encrypts a letter.
*
* @param {char} inputPos - the input position of the signal
* @returns {char}
*/
crypt(inputPos) {
for (const rotor of this.rotors) {
inputPos = rotor.crypt(inputPos, "rightToLeft");
}
return inputPos;
}
/**
* Gets the outputs of the control rotors. The inputs to the control rotors are always "F", "G", "H" and "I".
*
* @returns {number[]}
*/
getOutputs() {
const outputs = [this.crypt("F"), this.crypt("G"), this.crypt("H"), this.crypt("I")];
const logicDict = {1: "B", 2: "C", 3: "DE", 4: "FGH", 5: "IJK", 6: "LMNO", 7: "PQRST", 8: "UVWXYZ", 9: "A"};
const numberOutputs = [];
for (const key in logicDict) {
const item = logicDict[key];
for (const output of outputs) {
if (item.includes(output)) {
numberOutputs.push(key);
break;
}
}
}
return numberOutputs;
}
/**
* Steps the control rotors. Only 3 of the control rotors step: one after every encryption, one after every 26, and one after every 26 squared.
*/
step() {
const MRotor = this.rotors[1], FRotor = this.rotors[2], SRotor = this.rotors[3];
// 14 is the offset of "O" from "A" - the next rotor steps once the previous rotor reaches "O"
if (FRotor.state === 14) {
if (MRotor.state === 14) {
SRotor.step();
}
MRotor.step();
}
FRotor.step();
}
/**
* The goThroughControl function combines getting the outputs from the control rotor bank and then stepping them.
*
* @returns {number[]}
*/
goThroughControl() {
const outputs = this.getOutputs();
this.step();
return outputs;
}
}
/**
* The index rotor bank consists of 5 index rotors all placed in the forwards orientation.
*/
export class IndexBank {
/**
* IndexBank constructor
*
* @param {Object[]} rotors - list of IRotors
*/
constructor(rotors) {
this.rotors = rotors;
}
/**
* Encrypts a number.
*
* @param {number} inputPos - the input position of the signal
* @returns {number}
*/
crypt(inputPos) {
for (const rotor of this.rotors) {
inputPos = rotor.crypt(inputPos);
}
return inputPos;
}
/**
* The goThroughIndex function takes the inputs from the control rotor bank and returns the list of outputs after encryption through the index rotors.
*
* @param {number[]} controlInputs - inputs from the control rotors
* @returns {number[]}
*/
goThroughIndex(controlInputs) {
const outputs = [];
for (const inp of controlInputs) {
outputs.push(this.crypt(inp));
}
return outputs;
}
}
/**
* Rotor class
*/
export class Rotor {
/**
* Rotor constructor
*
* @param {number[]} wireSetting - the wirings within the rotor: mapping from left-to-right, the index of the number in the list maps onto the number at that index
* @param {bool} rev - true if the rotor is reversed, false if it isn't
* @param {number} key - the starting position or state of the rotor
*/
constructor(wireSetting, key, rev) {
this.state = key;
this.numMapping = this.getNumMapping(wireSetting, rev);
this.posMapping = this.getPosMapping(rev);
}
/**
* Get the number mapping from the wireSetting (only different from wireSetting if rotor is reversed)
*
* @param {number[]} wireSetting - the wirings within the rotors
* @param {bool} rev - true if reversed, false if not
* @returns {number[]}
*/
getNumMapping(wireSetting, rev) {
if (rev===false) {
return wireSetting;
} else {
const length = wireSetting.length;
const tempMapping = new Array(length);
for (let i=0; i<length; i++) {
tempMapping[wireSetting[i]] = i;
}
return tempMapping;
}
}
/**
* Get the position mapping (how the position numbers map onto the numbers of the rotor)
*
* @param {bool} rev - true if reversed, false if not
* @returns {number[]}
*/
getPosMapping(rev) {
const length = this.numMapping.length;
const posMapping = [];
if (rev===false) {
for (let i = this.state; i < this.state+length; i++) {
let res = i%length;
if (res<0) {
res += length;
}
posMapping.push(res);
}
} else {
for (let i = this.state; i > this.state-length; i--) {
let res = i%length;
if (res<0) {
res += length;
}
posMapping.push(res);
}
}
return posMapping;
}
/**
* Encrypt/decrypt data. This process is identical to the rotors of cipher machines such as Enigma or Typex.
*
* @param {number} inputPos - the input position of the signal (the data to encrypt/decrypt)
* @param {string} direction - one of "leftToRight" and "rightToLeft", states the direction in which the signal passes through the rotor
* @returns {number}
*/
cryptNum(inputPos, direction) {
const inpNum = this.posMapping[inputPos];
let outNum;
if (direction === "leftToRight") {
outNum = this.numMapping[inpNum];
} else if (direction === "rightToLeft") {
outNum = this.numMapping.indexOf(inpNum);
}
const outPos = this.posMapping.indexOf(outNum);
return outPos;
}
/**
* Steps the rotor. The number at position 0 will be moved to position 1 etc.
*/
step() {
const lastNum = this.posMapping.pop();
this.posMapping.splice(0, 0, lastNum);
this.state = this.posMapping[0];
}
}
/**
* A CRRotor is a cipher (C) or control (R) rotor. These rotors are identical and interchangeable. A C or R rotor consists of 26 contacts, one for each letter, and may be put into either a forwards of reversed orientation.
*/
export class CRRotor extends Rotor {
/**
* CRRotor constructor
*
* @param {string} wireSetting - the rotor wirings (string of letters)
* @param {char} key - initial state of rotor
* @param {bool} rev - true if reversed, false if not
*/
constructor(wireSetting, key, rev=false) {
wireSetting = wireSetting.split("").map(CRRotor.letterToNum);
super(wireSetting, CRRotor.letterToNum(key), rev);
}
/**
* Static function which converts a letter into its number i.e. its offset from the letter "A"
*
* @param {char} letter - letter to convert to number
* @returns {number}
*/
static letterToNum(letter) {
return letter.charCodeAt()-65;
}
/**
* Static function which converts a number (a letter's offset from "A") into its letter
*
* @param {number} num - number to convert to letter
* @returns {char}
*/
static numToLetter(num) {
return String.fromCharCode(num+65);
}
/**
* Encrypts/decrypts a letter.
*
* @param {char} inputPos - the input position of the signal ("A" refers to position 0 etc.)
* @param {string} direction - one of "leftToRight" and "rightToLeft"
* @returns {char}
*/
crypt(inputPos, direction) {
inputPos = CRRotor.letterToNum(inputPos);
const outPos = this.cryptNum(inputPos, direction);
return CRRotor.numToLetter(outPos);
}
}
/**
* An IRotor is an index rotor, which consists of 10 contacts each numbered from 0 to 9. Unlike C and R rotors, they cannot be put in the reversed orientation. The index rotors do not step at any point during encryption or decryption.
*/
export class IRotor extends Rotor {
/**
* IRotor constructor
*
* @param {string} wireSetting - the rotor wirings (string of numbers)
* @param {char} key - initial state of rotor
*/
constructor(wireSetting, key) {
wireSetting = wireSetting.split("").map(Number);
super(wireSetting, Number(key), false);
}
/**
* Encrypts a number
*
* @param {number} inputPos - the input position of the signal
* @returns {number}
*/
crypt(inputPos) {
return this.cryptNum(inputPos, "leftToRight");
}
}

258
src/core/lib/SM2.mjs Normal file
View file

@ -0,0 +1,258 @@
/**
* Utilities and operations utilized for SM2 encryption and decryption
* @author flakjacket95 [dflack95@gmail.com]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
import { fromHex } from "../lib/Hex.mjs";
import Utils from "../Utils.mjs";
import Sm3 from "crypto-api/src/hasher/sm3.mjs";
import {toHex} from "crypto-api/src/encoder/hex.mjs";
import r from "jsrsasign";
/**
* SM2 Class for encryption and decryption operations
*/
export class SM2 {
/**
* Constructor for SM2 class; sets up with the curve and the output format as specified in user args
*
* @param {*} curve
* @param {*} format
*/
constructor(curve, format) {
this.ecParams = null;
this.rng = new r.SecureRandom();
/*
For any additional curve definitions utilized by SM2, add another block like the below for that curve, then add the curve name to the Curve selection dropdown
*/
r.crypto.ECParameterDB.regist(
"sm2p256v1", // name / p = 2**256 - 2**224 - 2**96 + 2**64 - 1
256,
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", // p
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", // a
"28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", // b
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", // n
"1", // h
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", // gx
"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", // gy
[]
); // alias
this.ecParams = r.crypto.ECParameterDB.getByName(curve);
this.format = format;
}
/**
* Set the public key coordinates for the SM2 class
*
* @param {string} publicKeyX
* @param {string} publicKeyY
*/
setPublicKey(publicKeyX, publicKeyY) {
/*
* TODO: This needs some additional length validation; and checking for errors in the decoding process
* TODO: Can probably support other public key encoding methods here as well in the future
*/
this.publicKey = this.ecParams.curve.decodePointHex("04" + publicKeyX + publicKeyY);
if (this.publicKey.isInfinity()) {
throw new OperationError("Invalid Public Key");
}
}
/**
* Set the private key value for the SM2 class
*
* @param {string} privateKey
*/
setPrivateKey(privateKeyHex) {
this.privateKey = new r.BigInteger(privateKeyHex, 16);
}
/**
* Main encryption function; takes user input, processes encryption and returns the result in hex (with the components arranged as configured by the user args)
*
* @param {*} input
* @returns {string}
*/
encrypt(input) {
const G = this.ecParams.G;
/*
* Compute a new, random public key along the same elliptic curve to form the starting point for our encryption process (record the resulting X and Y as hex to provide as part of the operation output)
* k: Randomly generated BigInteger
* c1: Result of dotting our curve generator point `G` with the value of `k`
*/
const k = this.generatePublicKey();
const c1 = G.multiply(k);
const [hexC1X, hexC1Y] = this.getPointAsHex(c1);
/*
* Compute p2 (secret) using the public key, and the chosen k value above
*/
const p2 = this.publicKey.multiply(k);
/*
* Compute the C3 SM3 hash before we transform the array
*/
const c3 = this.c3(p2, input);
/*
* Genreate a proper length encryption key, XOR iteratively, and convert newly encrypted data to hex
*/
const key = this.kdf(p2, input.byteLength);
for (let i = 0; i < input.byteLength; i++) {
input[i] ^= Utils.ord(key[i]);
}
const c2 = Buffer.from(input).toString("hex");
/*
* Check user input specs; order the output components as selected
*/
if (this.format === "C1C3C2") {
return hexC1X + hexC1Y + c3 + c2;
} else {
return hexC1X + hexC1Y + c2 + c3;
}
}
/**
* Function to decrypt an SM2 encrypted message
*
* @param {*} input
*/
decrypt(input) {
const c1X = input.slice(0, 64);
const c1Y = input.slice(64, 128);
let c3 = "";
let c2 = "";
if (this.format === "C1C3C2") {
c3 = input.slice(128, 192);
c2 = input.slice(192);
} else {
c2 = input.slice(128, -64);
c3 = input.slice(-64);
}
c2 = Uint8Array.from(fromHex(c2));
const c1 = this.ecParams.curve.decodePointHex("04" + c1X + c1Y);
/*
* Compute the p2 (secret) value by taking the C1 point provided in the encrypted package, and multiplying by the private k value
*/
const p2 = c1.multiply(this.privateKey);
/*
* Similar to encryption; compute sufficient length key material and XOR the input data to recover the original message
*/
const key = this.kdf(p2, c2.byteLength);
for (let i = 0; i < c2.byteLength; i++) {
c2[i] ^= Utils.ord(key[i]);
}
const check = this.c3(p2, c2);
if (check === c3) {
return c2.buffer;
} else {
throw new OperationError("Decryption Error -- Computed Hashes Do Not Match");
}
}
/**
* Generates a large random number
*
* @param {*} limit
* @returns
*/
getBigRandom(limit) {
return new r.BigInteger(limit.bitLength(), this.rng)
.mod(limit.subtract(r.BigInteger.ONE))
.add(r.BigInteger.ONE);
}
/**
* Helper function for generating a large random K number; utilized for generating our initial C1 point
* TODO: Do we need to do any sort of validation on the resulting k values?
*
* @returns {BigInteger}
*/
generatePublicKey() {
const n = this.ecParams.n;
const k = this.getBigRandom(n);
return k;
}
/**
* SM2 Key Derivation Function (KDF); Takes P2 point, and generates a key material stream large enough to encrypt all of the input data
*
* @param {*} p2
* @param {*} len
* @returns {string}
*/
kdf(p2, len) {
const [hX, hY] = this.getPointAsHex(p2);
const total = Math.ceil(len / 32) + 1;
let cnt = 1;
let keyMaterial = "";
while (cnt < total) {
const num = Utils.intToByteArray(cnt, 4, "big");
const overall = fromHex(hX).concat(fromHex(hY)).concat(num);
keyMaterial += this.sm3(overall);
cnt++;
}
return keyMaterial;
}
/**
* Calculates the C3 component of our final encrypted payload; which is the SM3 hash of the P2 point and the original, unencrypted input data
*
* @param {*} p2
* @param {*} input
* @returns {string}
*/
c3(p2, input) {
const [hX, hY] = this.getPointAsHex(p2);
const overall = fromHex(hX).concat(Array.from(input)).concat(fromHex(hY));
return toHex(this.sm3(overall));
}
/**
* SM3 setup helper function; takes input data as an array, processes the hash and returns the result
*
* @param {*} data
* @returns {string}
*/
sm3(data) {
const hashData = Utils.arrayBufferToStr(Uint8Array.from(data).buffer, false);
const hasher = new Sm3();
hasher.update(hashData);
return hasher.finalize();
}
/**
* Utility function, returns an elliptic curve points X and Y values as hex;
*
* @param {EcPointFp} point
* @returns {[]}
*/
getPointAsHex(point) {
const biX = point.getX().toBigInteger();
const biY = point.getY().toBigInteger();
const charlen = this.ecParams.keycharlen;
const hX = ("0000000000" + biX.toString(16)).slice(- charlen);
const hY = ("0000000000" + biY.toString(16)).slice(- charlen);
return [hX, hY];
}
}

331
src/core/lib/SM4.mjs Normal file
View file

@ -0,0 +1,331 @@
/**
* Complete implementation of SM4 cipher encryption/decryption with
* ECB, CBC, CFB, OFB, CTR block modes.
* These modes are specified in IETF draft-ribose-cfrg-sm4-09, see:
* https://tools.ietf.org/id/draft-ribose-cfrg-sm4-09.html
* for details.
*
* Follows spec from Cryptography Standardization Technical Comittee:
* http://www.gmbz.org.cn/upload/2018-04-04/1522788048733065051.pdf
*
* @author swesven
* @copyright 2021
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
/** Number of rounds */
const NROUNDS = 32;
/** block size in bytes */
const BLOCKSIZE = 16;
/** The S box, 256 8-bit values */
const Sbox = [
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
];
/** "Fixed parameter CK" used in key expansion */
const CK = [
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
];
/** "System parameter FK" */
const FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc];
/**
* Rotating 32-bit shift left
*
* (Note that although JS integers are stored in doubles and thus have 53 bits,
* the JS bitwise operations are 32-bit)
*/
function ROL(i, n) {
return (i << n) | (i >>> (32 - n));
}
/**
* Linear transformation L
*
* @param {integer} b - a 32 bit integer
*/
function transformL(b) {
/* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
(Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
/* circular rotate and xor */
return b ^ ROL(b, 2) ^ ROL(b, 10) ^ ROL(b, 18) ^ ROL(b, 24);
}
/**
* Linear transformation L'
*
* @param {integer} b - a 32 bit integer
*/
function transformLprime(b) {
/* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
(Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
return b ^ ROL(b, 13) ^ ROL(b, 23); /* circular rotate and XOR */
}
/**
* Initialize the round key
*/
function initSM4RoundKey(rawkey) {
const K = rawkey.map((a, i) => a ^ FK[i]); /* K = rawkey ^ FK */
const roundKey = [];
for (let i = 0; i < 32; i++)
roundKey[i] = K[i + 4] = K[i] ^ transformLprime(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]);
return roundKey;
}
/**
* Encrypts/decrypts a single block X (4 32-bit values) with a prepared round key.
*
* @param {intArray} X - A cleartext block.
* @param {intArray} roundKey - The round key from initSMRoundKey for encrypting (reversed for decrypting).
* @returns {byteArray} - The cipher text.
*/
function encryptBlockSM4(X, roundKey) {
for (let i = 0; i < NROUNDS; i++)
X[i + 4] = X[i] ^ transformL(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ roundKey[i]);
return [X[35], X[34], X[33], X[32]];
}
/**
* Takes 16 bytes from an offset in an array and returns an array of 4 32-bit Big-Endian values.
* (DataView won't work portably here as we need Big-Endian)
*
* @param {byteArray} bArray - the array of bytes
* @param {integer} offset - starting offset in the array; 15 bytes must follow it.
*/
function bytesToInts(bArray, offs=0) {
let offset = offs;
const A = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
offset += 4;
const B = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
offset += 4;
const C = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
offset += 4;
const D = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
return [A, B, C, D];
}
/**
* Inverse of bytesToInts above; takes an array of 32-bit integers and turns it into an array of bytes.
* Again, Big-Endian order.
*/
function intsToBytes(ints) {
const bArr = [];
for (let i = 0; i < ints.length; i++) {
bArr.push((ints[i] >> 24) & 0xFF);
bArr.push((ints[i] >> 16) & 0xFF);
bArr.push((ints[i] >> 8) & 0xFF);
bArr.push(ints[i] & 0xFF);
}
return bArr;
}
/**
* Encrypt using SM4 using a given block cipher mode.
*
* @param {byteArray} message - The clear text message; any length under 32 Gb or so.
* @param {byteArray} key - The cipher key, 16 bytes.
* @param {byteArray} iv - The IV or nonce, 16 bytes (not used with ECB mode)
* @param {string} mode - The block cipher mode "CBC", "ECB", "CFB", "OFB", "CTR".
* @param {boolean} noPadding - Don't add PKCS#7 padding if set.
* @returns {byteArray} - The cipher text.
*/
export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
const messageLength = message.length;
if (messageLength === 0)
return [];
const roundKey = initSM4RoundKey(bytesToInts(key, 0));
/* Pad with PKCS#7 if requested for ECB/CBC else add zeroes (which are sliced off at the end) */
let padByte = 0;
let nPadding = 16 - (message.length & 0xF);
if (mode === "ECB" || mode === "CBC") {
if (noPadding) {
if (nPadding !== 16)
throw new OperationError(`No padding requested in ${mode} mode but input is not a 16-byte multiple.`);
nPadding = 0;
} else
padByte = nPadding;
}
for (let i = 0; i < nPadding; i++)
message.push(padByte);
const cipherText = [];
switch (mode) {
case "ECB":
for (let i = 0; i < message.length; i += BLOCKSIZE)
Array.prototype.push.apply(cipherText, intsToBytes(encryptBlockSM4(bytesToInts(message, i), roundKey)));
break;
case "CBC":
iv = bytesToInts(iv, 0);
for (let i = 0; i < message.length; i += BLOCKSIZE) {
const block = bytesToInts(message, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
iv = encryptBlockSM4(block, roundKey);
Array.prototype.push.apply(cipherText, intsToBytes(iv));
}
break;
case "CFB":
iv = bytesToInts(iv, 0);
for (let i = 0; i < message.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(message, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
Array.prototype.push.apply(cipherText, intsToBytes(block));
iv = block;
}
break;
case "OFB":
iv = bytesToInts(iv, 0);
for (let i = 0; i < message.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(message, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
Array.prototype.push.apply(cipherText, intsToBytes(block));
}
break;
case "CTR":
iv = bytesToInts(iv, 0);
for (let i = 0; i < message.length; i += BLOCKSIZE) {
let iv2 = [...iv]; /* containing the IV + counter */
iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
iv2 = encryptBlockSM4(iv2, roundKey);
const block = bytesToInts(message, i);
block[0] ^= iv2[0]; block[1] ^= iv2[1];
block[2] ^= iv2[2]; block[3] ^= iv2[3];
Array.prototype.push.apply(cipherText, intsToBytes(block));
}
break;
default:
throw new OperationError("Invalid block cipher mode: "+mode);
}
if (mode !== "ECB" && mode !== "CBC")
return cipherText.slice(0, messageLength);
return cipherText;
}
/**
* Decrypt using SM4 using a given block cipher mode.
*
* @param {byteArray} cipherText - The ciphertext
* @param {byteArray} key - The cipher key, 16 bytes.
* @param {byteArray} iv - The IV or nonce, 16 bytes (not used with ECB mode)
* @param {string} mode - The block cipher mode "CBC", "ECB", "CFB", "OFB", "CTR"
* @param {boolean] ignorePadding - If true, ignore padding issues in ECB/CBC mode.
* @returns {byteArray} - The cipher text.
*/
export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false) {
const originalLength = cipherText.length;
if (originalLength === 0)
return [];
let roundKey = initSM4RoundKey(bytesToInts(key, 0));
if (mode === "ECB" || mode === "CBC") {
/* Init decryption key */
roundKey = roundKey.reverse();
if ((originalLength & 0xF) !== 0 && !ignorePadding)
throw new OperationError(`With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${cipherText.length & 0xF} bytes extra)`);
} else { /* Pad dummy bytes for other modes, chop them off at the end */
while ((cipherText.length & 0xF) !== 0)
cipherText.push(0);
}
const clearText = [];
switch (mode) {
case "ECB":
for (let i = 0; i < cipherText.length; i += BLOCKSIZE)
Array.prototype.push.apply(clearText, intsToBytes(encryptBlockSM4(bytesToInts(cipherText, i), roundKey)));
break;
case "CBC":
iv = bytesToInts(iv, 0);
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
const block = encryptBlockSM4(bytesToInts(cipherText, i), roundKey);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
iv = bytesToInts(cipherText, i);
}
break;
case "CFB":
iv = bytesToInts(iv, 0);
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(cipherText, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
iv = bytesToInts(cipherText, i);
}
break;
case "OFB":
iv = bytesToInts(iv, 0);
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(cipherText, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
}
break;
case "CTR":
iv = bytesToInts(iv, 0);
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
let iv2 = [...iv]; /* containing the IV + counter */
iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
iv2 = encryptBlockSM4(iv2, roundKey);
const block = bytesToInts(cipherText, i);
block[0] ^= iv2[0]; block[1] ^= iv2[1];
block[2] ^= iv2[2]; block[3] ^= iv2[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
}
break;
default:
throw new OperationError(`Invalid block cipher mode: ${mode}`);
}
/* Check PKCS#7 padding */
if (mode === "ECB" || mode === "CBC") {
if (ignorePadding)
return clearText;
const padByte = clearText[clearText.length - 1];
if (padByte > 16)
throw new OperationError("Invalid PKCS#7 padding.");
for (let i = 0; i < padByte; i++)
if (clearText[clearText.length -i - 1] !== padByte)
throw new OperationError("Invalid PKCS#7 padding.");
return clearText.slice(0, clearText.length - padByte);
}
return clearText.slice(0, originalLength);
}

144
src/core/lib/Salsa20.mjs Normal file
View file

@ -0,0 +1,144 @@
/**
* @author joostrijneveld [joost@joostrijneveld.nl]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import Utils from "../Utils.mjs";
/**
* Computes the Salsa20 permute function
*
* @param {byteArray} x
* @param {integer} rounds
*/
function salsa20Permute(x, rounds) {
/**
* Macro to compute a 32-bit rotate-left operation
*
* @param {integer} x
* @param {integer} n
* @returns {integer}
*/
function ROL32(x, n) {
return ((x << n) & 0xFFFFFFFF) | (x >>> (32 - n));
}
/**
* Macro to compute a single Salsa20 quarterround operation
*
* @param {integer} x
* @param {integer} a
* @param {integer} b
* @param {integer} c
* @param {integer} d
* @returns {integer}
*/
function quarterround(x, a, b, c, d) {
x[b] ^= ROL32((x[a] + x[d]) & 0xFFFFFFFF, 7);
x[c] ^= ROL32((x[b] + x[a]) & 0xFFFFFFFF, 9);
x[d] ^= ROL32((x[c] + x[b]) & 0xFFFFFFFF, 13);
x[a] ^= ROL32((x[d] + x[c]) & 0xFFFFFFFF, 18);
}
for (let i = 0; i < rounds / 2; i++) {
quarterround(x, 0, 4, 8, 12);
quarterround(x, 5, 9, 13, 1);
quarterround(x, 10, 14, 2, 6);
quarterround(x, 15, 3, 7, 11);
quarterround(x, 0, 1, 2, 3);
quarterround(x, 5, 6, 7, 4);
quarterround(x, 10, 11, 8, 9);
quarterround(x, 15, 12, 13, 14);
}
}
/**
* Computes the Salsa20 block function
*
* @param {byteArray} key
* @param {byteArray} nonce
* @param {byteArray} counter
* @param {integer} rounds
* @returns {byteArray}
*/
export function salsa20Block(key, nonce, counter, rounds) {
const tau = "expand 16-byte k";
const sigma = "expand 32-byte k";
let state, c;
if (key.length === 16) {
c = Utils.strToByteArray(tau);
key = key.concat(key);
} else {
c = Utils.strToByteArray(sigma);
}
state = c.slice(0, 4);
state = state.concat(key.slice(0, 16));
state = state.concat(c.slice(4, 8));
state = state.concat(nonce);
state = state.concat(counter);
state = state.concat(c.slice(8, 12));
state = state.concat(key.slice(16, 32));
state = state.concat(c.slice(12, 16));
const x = Array();
for (let i = 0; i < 64; i += 4) {
x.push(Utils.byteArrayToInt(state.slice(i, i + 4), "little"));
}
const a = [...x];
salsa20Permute(x, rounds);
for (let i = 0; i < 16; i++) {
x[i] = (x[i] + a[i]) & 0xFFFFFFFF;
}
let output = Array();
for (let i = 0; i < 16; i++) {
output = output.concat(Utils.intToByteArray(x[i], 4, "little"));
}
return output;
}
/**
* Computes the hSalsa20 function
*
* @param {byteArray} key
* @param {byteArray} nonce
* @param {integer} rounds
* @returns {byteArray}
*/
export function hsalsa20(key, nonce, rounds) {
const tau = "expand 16-byte k";
const sigma = "expand 32-byte k";
let state, c;
if (key.length === 16) {
c = Utils.strToByteArray(tau);
key = key.concat(key);
} else {
c = Utils.strToByteArray(sigma);
}
state = c.slice(0, 4);
state = state.concat(key.slice(0, 16));
state = state.concat(c.slice(4, 8));
state = state.concat(nonce);
state = state.concat(c.slice(8, 12));
state = state.concat(key.slice(16, 32));
state = state.concat(c.slice(12, 16));
const x = Array();
for (let i = 0; i < 64; i += 4) {
x.push(Utils.byteArrayToInt(state.slice(i, i + 4), "little"));
}
salsa20Permute(x, rounds);
let output = Array();
const idx = [0, 5, 10, 15, 6, 7, 8, 9];
for (let i = 0; i < 8; i++) {
output = output.concat(Utils.intToByteArray(x[idx[i]], 4, "little"));
}
return output;
}

117
src/core/lib/Sort.mjs Normal file
View file

@ -0,0 +1,117 @@
/**
* Sorting functions
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*
*/
/**
* Comparison operation for sorting of strings ignoring case.
*
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function caseInsensitiveSort(a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
}
/**
* Comparison operation for sorting of IPv4 addresses.
*
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function ipSort(a, b) {
let a_ = a.split("."),
b_ = b.split(".");
a_ = a_[0] * 0x1000000 + a_[1] * 0x10000 + a_[2] * 0x100 + a_[3] * 1;
b_ = b_[0] * 0x1000000 + b_[1] * 0x10000 + b_[2] * 0x100 + b_[3] * 1;
if (isNaN(a_) && !isNaN(b_)) return 1;
if (!isNaN(a_) && isNaN(b_)) return -1;
if (isNaN(a_) && isNaN(b_)) return a.localeCompare(b);
return a_ - b_;
}
/**
* Comparison operation for sorting of numeric values.
*
* @author Chris van Marle
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function numericSort(a, b) {
const a_ = a.split(/([^\d]+)/),
b_ = b.split(/([^\d]+)/);
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return a.localeCompare(b);
}
/**
* Comparison operation for sorting of hexadecimal values.
*
* @author Chris van Marle
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function hexadecimalSort(a, b) {
let a_ = a.split(/([^\da-f]+)/i),
b_ = b.split(/([^\da-f]+)/i);
a_ = a_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
b_ = b_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return a.localeCompare(b);
}
/**
* Comparison operation for sorting by length
*
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function lengthSort(a, b) {
return a.length - b.length;
}

View file

@ -18,24 +18,37 @@ export default class Stream {
* Stream constructor.
*
* @param {Uint8Array} input
* @param {number} pos
* @param {number} bitPos
*/
constructor(input) {
constructor(input, pos=0, bitPos=0) {
this.bytes = input;
this.length = this.bytes.length;
this.position = 0;
this.bitPos = 0;
this.position = pos;
this.bitPos = bitPos;
}
/**
* Get a number of bytes from the current position.
* Clone this Stream returning a new identical Stream.
*
* @param {number} numBytes
* @returns {Stream}
*/
clone() {
return new Stream(this.bytes, this.position, this.bitPos);
}
/**
* Get a number of bytes from the current position, or all remaining bytes.
*
* @param {number} [numBytes=null]
* @returns {Uint8Array}
*/
getBytes(numBytes) {
getBytes(numBytes=null) {
if (this.position > this.length) return undefined;
const newPosition = this.position + numBytes;
const newPosition = numBytes !== null ?
this.position + numBytes :
this.length;
const bytes = this.bytes.slice(this.position, newPosition);
this.position = newPosition;
this.bitPos = 0;
@ -46,12 +59,14 @@ export default class Stream {
* Interpret the following bytes as a string, stopping at the next null byte or
* the supplied limit.
*
* @param {number} numBytes
* @param {number} [numBytes=-1]
* @returns {string}
*/
readString(numBytes) {
readString(numBytes=-1) {
if (this.position > this.length) return undefined;
if (numBytes === -1) numBytes = this.length - this.position;
let result = "";
for (let i = this.position; i < this.position + numBytes; i++) {
const currentByte = this.bytes[i];
@ -91,34 +106,40 @@ export default class Stream {
}
/**
* Reads a number of bits from the buffer.
*
* @TODO Add endianness
* Reads a number of bits from the buffer in big or little endian.
*
* @param {number} numBits
* @param {string} [endianness="be"]
* @returns {number}
*/
readBits(numBits) {
readBits(numBits, endianness="be") {
if (this.position > this.length) return undefined;
let bitBuf = 0,
bitBufLen = 0;
// Add remaining bits from current byte
bitBuf = (this.bytes[this.position++] & bitMask(this.bitPos)) >>> this.bitPos;
bitBuf = this.bytes[this.position++] & bitMask(this.bitPos);
if (endianness !== "be") bitBuf >>>= this.bitPos;
bitBufLen = 8 - this.bitPos;
this.bitPos = 0;
// Not enough bits yet
while (bitBufLen < numBits) {
bitBuf |= this.bytes[this.position++] << bitBufLen;
if (endianness === "be")
bitBuf = (bitBuf << bitBufLen) | this.bytes[this.position++];
else
bitBuf |= this.bytes[this.position++] << bitBufLen;
bitBufLen += 8;
}
// Reverse back to numBits
if (bitBufLen > numBits) {
const excess = bitBufLen - numBits;
bitBuf &= (1 << numBits) - 1;
if (endianness === "be")
bitBuf >>>= excess;
else
bitBuf &= (1 << numBits) - 1;
bitBufLen -= excess;
this.position--;
this.bitPos = 8 - excess;
@ -133,7 +154,9 @@ export default class Stream {
* @returns {number} The bit mask
*/
function bitMask(bitPos) {
return 256 - (1 << bitPos);
return endianness === "be" ?
(1 << (8 - bitPos)) - 1 :
256 - (1 << bitPos);
}
}
@ -177,7 +200,7 @@ export default class Stream {
// Get the skip table.
const skiptable = preprocess(val, length);
let found = true;
let found;
while (this.position < this.length) {
// Until we hit the final element of val in the stream.

877
src/core/lib/TLS.mjs Normal file
View file

@ -0,0 +1,877 @@
/**
* TLS resources.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import OperationError from "../errors/OperationError.mjs";
import Stream from "../lib/Stream.mjs";
/**
* Parse a TLS Record
* @param {Uint8Array} bytes
* @returns {JSON}
*/
export function parseTLSRecord(bytes) {
const s = new Stream(bytes);
const b = s.clone();
const r = {};
// Content type
r.contentType = {
description: "Content Type",
length: 1,
data: b.getBytes(1),
value: s.readInt(1)
};
if (r.contentType.value !== 0x16)
throw new OperationError("Not handshake data.");
// Version
r.version = {
description: "Protocol Version",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
// Length
r.length = {
description: "Record Length",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
if (s.length !== r.length.value + 5)
throw new OperationError("Incorrect handshake length.");
// Handshake
r.handshake = {
description: "Handshake",
length: r.length.value,
data: b.getBytes(r.length.value),
value: parseHandshake(s.getBytes(r.length.value))
};
return r;
}
/**
* Parse a TLS Handshake
* @param {Uint8Array} bytes
* @returns {JSON}
*/
function parseHandshake(bytes) {
const s = new Stream(bytes);
const b = s.clone();
const h = {};
// Handshake type
h.handshakeType = {
description: "Handshake Type",
length: 1,
data: b.getBytes(1),
value: s.readInt(1)
};
// Handshake length
h.handshakeLength = {
description: "Handshake Length",
length: 3,
data: b.getBytes(3),
value: s.readInt(3)
};
if (s.length !== h.handshakeLength.value + 4)
throw new OperationError("Not enough data in Handshake message.");
switch (h.handshakeType.value) {
case 0x01:
h.handshakeType.description = "Client Hello";
parseClientHello(s, b, h);
break;
case 0x02:
h.handshakeType.description = "Server Hello";
parseServerHello(s, b, h);
break;
default:
throw new OperationError("Not a known handshake message.");
}
return h;
}
/**
* Parse a TLS Client Hello
* @param {Stream} s
* @param {Stream} b
* @param {Object} h
* @returns {JSON}
*/
function parseClientHello(s, b, h) {
// Hello version
h.helloVersion = {
description: "Client Hello Version",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
// Random
h.random = {
description: "Client Random",
length: 32,
data: b.getBytes(32),
value: s.getBytes(32)
};
// Session ID Length
h.sessionIDLength = {
description: "Session ID Length",
length: 1,
data: b.getBytes(1),
value: s.readInt(1)
};
// Session ID
h.sessionID = {
description: "Session ID",
length: h.sessionIDLength.value,
data: b.getBytes(h.sessionIDLength.value),
value: s.getBytes(h.sessionIDLength.value)
};
// Cipher Suites Length
h.cipherSuitesLength = {
description: "Cipher Suites Length",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
// Cipher Suites
h.cipherSuites = {
description: "Cipher Suites",
length: h.cipherSuitesLength.value,
data: b.getBytes(h.cipherSuitesLength.value),
value: parseCipherSuites(s.getBytes(h.cipherSuitesLength.value))
};
// Compression Methods Length
h.compressionMethodsLength = {
description: "Compression Methods Length",
length: 1,
data: b.getBytes(1),
value: s.readInt(1)
};
// Compression Methods
h.compressionMethods = {
description: "Compression Methods",
length: h.compressionMethodsLength.value,
data: b.getBytes(h.compressionMethodsLength.value),
value: parseCompressionMethods(s.getBytes(h.compressionMethodsLength.value))
};
// Extensions Length
h.extensionsLength = {
description: "Extensions Length",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
// Extensions
h.extensions = {
description: "Extensions",
length: h.extensionsLength.value,
data: b.getBytes(h.extensionsLength.value),
value: parseExtensions(s.getBytes(h.extensionsLength.value))
};
return h;
}
/**
* Parse a TLS Server Hello
* @param {Stream} s
* @param {Stream} b
* @param {Object} h
* @returns {JSON}
*/
function parseServerHello(s, b, h) {
// Hello version
h.helloVersion = {
description: "Server Hello Version",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
// Random
h.random = {
description: "Server Random",
length: 32,
data: b.getBytes(32),
value: s.getBytes(32)
};
// Session ID Length
h.sessionIDLength = {
description: "Session ID Length",
length: 1,
data: b.getBytes(1),
value: s.readInt(1)
};
// Session ID
h.sessionID = {
description: "Session ID",
length: h.sessionIDLength.value,
data: b.getBytes(h.sessionIDLength.value),
value: s.getBytes(h.sessionIDLength.value)
};
// Cipher Suite
h.cipherSuite = {
description: "Selected Cipher Suite",
length: 2,
data: b.getBytes(2),
value: CIPHER_SUITES_LOOKUP[s.readInt(2)] || "Unknown"
};
// Compression Method
h.compressionMethod = {
description: "Selected Compression Method",
length: 1,
data: b.getBytes(1),
value: s.readInt(1) // TODO: Compression method name here
};
// Extensions Length
h.extensionsLength = {
description: "Extensions Length",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
// Extensions
h.extensions = {
description: "Extensions",
length: h.extensionsLength.value,
data: b.getBytes(h.extensionsLength.value),
value: parseExtensions(s.getBytes(h.extensionsLength.value))
};
}
/**
* Parse Cipher Suites
* @param {Uint8Array} bytes
* @returns {JSON}
*/
function parseCipherSuites(bytes) {
const s = new Stream(bytes);
const b = s.clone();
const cs = [];
while (s.hasMore()) {
cs.push({
description: "Cipher Suite",
length: 2,
data: b.getBytes(2),
value: CIPHER_SUITES_LOOKUP[s.readInt(2)] || "Unknown"
});
}
return cs;
}
/**
* Parse Compression Methods
* @param {Uint8Array} bytes
* @returns {JSON}
*/
function parseCompressionMethods(bytes) {
const s = new Stream(bytes);
const b = s.clone();
const cm = [];
while (s.hasMore()) {
cm.push({
description: "Compression Method",
length: 1,
data: b.getBytes(1),
value: s.readInt(1) // TODO: Compression method name here
});
}
return cm;
}
/**
* Parse Extensions
* @param {Uint8Array} bytes
* @returns {JSON}
*/
function parseExtensions(bytes) {
const s = new Stream(bytes);
const b = s.clone();
const exts = [];
while (s.hasMore()) {
const ext = {};
// Type
ext.type = {
description: "Extension Type",
length: 2,
data: b.getBytes(2),
value: EXTENSION_LOOKUP[s.readInt(2)] || "unknown"
};
// Length
ext.length = {
description: "Extension Length",
length: 2,
data: b.getBytes(2),
value: s.readInt(2)
};
// Value
ext.value = {
description: "Extension Value",
length: ext.length.value,
data: b.getBytes(ext.length.value),
value: s.getBytes(ext.length.value)
};
exts.push(ext);
}
return exts;
}
/**
* Extension type lookup table
*/
const EXTENSION_LOOKUP = {
0: "server_name",
1: "max_fragment_length",
2: "client_certificate_url",
3: "trusted_ca_keys",
4: "truncated_hmac",
5: "status_request",
6: "user_mapping",
7: "client_authz",
8: "server_authz",
9: "cert_type",
10: "supported_groups",
11: "ec_point_formats",
12: "srp",
13: "signature_algorithms",
14: "use_srtp",
15: "heartbeat",
16: "application_layer_protocol_negotiation",
17: "status_request_v2",
18: "signed_certificate_timestamp",
19: "client_certificate_type",
20: "server_certificate_type",
21: "padding",
22: "encrypt_then_mac",
23: "extended_master_secret",
24: "token_binding",
25: "cached_info",
26: "tls_lts",
27: "compress_certificate",
28: "record_size_limit",
29: "pwd_protect",
30: "pwd_clear",
31: "password_salt",
32: "ticket_pinning",
33: "tls_cert_with_extern_psk",
34: "delegated_credential",
35: "session_ticket",
36: "TLMSP",
37: "TLMSP_proxying",
38: "TLMSP_delegate",
39: "supported_ekt_ciphers",
40: "Reserved",
41: "pre_shared_key",
42: "early_data",
43: "supported_versions",
44: "cookie",
45: "psk_key_exchange_modes",
46: "Reserved",
47: "certificate_authorities",
48: "oid_filters",
49: "post_handshake_auth",
50: "signature_algorithms_cert",
51: "key_share",
52: "transparency_info",
53: "connection_id (deprecated)",
54: "connection_id",
55: "external_id_hash",
56: "external_session_id",
57: "quic_transport_parameters",
58: "ticket_request",
59: "dnssec_chain",
60: "sequence_number_encryption_algorithms",
61: "rrc",
2570: "GREASE",
6682: "GREASE",
10794: "GREASE",
14906: "GREASE",
17513: "application_settings",
19018: "GREASE",
23130: "GREASE",
27242: "GREASE",
31354: "GREASE",
35466: "GREASE",
39578: "GREASE",
43690: "GREASE",
47802: "GREASE",
51914: "GREASE",
56026: "GREASE",
60138: "GREASE",
64250: "GREASE",
64768: "ech_outer_extensions",
65037: "encrypted_client_hello",
65281: "renegotiation_info"
};
/**
* Cipher suites lookup table
*/
const CIPHER_SUITES_LOOKUP = {
0x0000: "TLS_NULL_WITH_NULL_NULL",
0x0001: "TLS_RSA_WITH_NULL_MD5",
0x0002: "TLS_RSA_WITH_NULL_SHA",
0x0003: "TLS_RSA_EXPORT_WITH_RC4_40_MD5",
0x0004: "TLS_RSA_WITH_RC4_128_MD5",
0x0005: "TLS_RSA_WITH_RC4_128_SHA",
0x0006: "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
0x0007: "TLS_RSA_WITH_IDEA_CBC_SHA",
0x0008: "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
0x0009: "TLS_RSA_WITH_DES_CBC_SHA",
0x000A: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
0x000B: "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
0x000C: "TLS_DH_DSS_WITH_DES_CBC_SHA",
0x000D: "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",
0x000E: "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
0x000F: "TLS_DH_RSA_WITH_DES_CBC_SHA",
0x0010: "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",
0x0011: "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
0x0012: "TLS_DHE_DSS_WITH_DES_CBC_SHA",
0x0013: "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
0x0014: "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
0x0015: "TLS_DHE_RSA_WITH_DES_CBC_SHA",
0x0016: "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
0x0017: "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
0x0018: "TLS_DH_anon_WITH_RC4_128_MD5",
0x0019: "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
0x001A: "TLS_DH_anon_WITH_DES_CBC_SHA",
0x001B: "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
0x001E: "TLS_KRB5_WITH_DES_CBC_SHA",
0x001F: "TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
0x0020: "TLS_KRB5_WITH_RC4_128_SHA",
0x0021: "TLS_KRB5_WITH_IDEA_CBC_SHA",
0x0022: "TLS_KRB5_WITH_DES_CBC_MD5",
0x0023: "TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
0x0024: "TLS_KRB5_WITH_RC4_128_MD5",
0x0025: "TLS_KRB5_WITH_IDEA_CBC_MD5",
0x0026: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
0x0027: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
0x0028: "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
0x0029: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
0x002A: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
0x002B: "TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
0x002C: "TLS_PSK_WITH_NULL_SHA",
0x002D: "TLS_DHE_PSK_WITH_NULL_SHA",
0x002E: "TLS_RSA_PSK_WITH_NULL_SHA",
0x002F: "TLS_RSA_WITH_AES_128_CBC_SHA",
0x0030: "TLS_DH_DSS_WITH_AES_128_CBC_SHA",
0x0031: "TLS_DH_RSA_WITH_AES_128_CBC_SHA",
0x0032: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
0x0033: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
0x0034: "TLS_DH_anon_WITH_AES_128_CBC_SHA",
0x0035: "TLS_RSA_WITH_AES_256_CBC_SHA",
0x0036: "TLS_DH_DSS_WITH_AES_256_CBC_SHA",
0x0037: "TLS_DH_RSA_WITH_AES_256_CBC_SHA",
0x0038: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
0x0039: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
0x003A: "TLS_DH_anon_WITH_AES_256_CBC_SHA",
0x003B: "TLS_RSA_WITH_NULL_SHA256",
0x003C: "TLS_RSA_WITH_AES_128_CBC_SHA256",
0x003D: "TLS_RSA_WITH_AES_256_CBC_SHA256",
0x003E: "TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
0x003F: "TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
0x0040: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
0x0041: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
0x0042: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",
0x0043: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",
0x0044: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
0x0045: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
0x0046: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
0x0067: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
0x0068: "TLS_DH_DSS_WITH_AES_256_CBC_SHA256",
0x0069: "TLS_DH_RSA_WITH_AES_256_CBC_SHA256",
0x006A: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
0x006B: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
0x006C: "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
0x006D: "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
0x0084: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
0x0085: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",
0x0086: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",
0x0087: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
0x0088: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
0x0089: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
0x008A: "TLS_PSK_WITH_RC4_128_SHA",
0x008B: "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
0x008C: "TLS_PSK_WITH_AES_128_CBC_SHA",
0x008D: "TLS_PSK_WITH_AES_256_CBC_SHA",
0x008E: "TLS_DHE_PSK_WITH_RC4_128_SHA",
0x008F: "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
0x0090: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
0x0091: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
0x0092: "TLS_RSA_PSK_WITH_RC4_128_SHA",
0x0093: "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
0x0094: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
0x0095: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA",
0x0096: "TLS_RSA_WITH_SEED_CBC_SHA",
0x0097: "TLS_DH_DSS_WITH_SEED_CBC_SHA",
0x0098: "TLS_DH_RSA_WITH_SEED_CBC_SHA",
0x0099: "TLS_DHE_DSS_WITH_SEED_CBC_SHA",
0x009A: "TLS_DHE_RSA_WITH_SEED_CBC_SHA",
0x009B: "TLS_DH_anon_WITH_SEED_CBC_SHA",
0x009C: "TLS_RSA_WITH_AES_128_GCM_SHA256",
0x009D: "TLS_RSA_WITH_AES_256_GCM_SHA384",
0x009E: "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
0x009F: "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
0x00A0: "TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
0x00A1: "TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
0x00A2: "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
0x00A3: "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
0x00A4: "TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
0x00A5: "TLS_DH_DSS_WITH_AES_256_GCM_SHA384",
0x00A6: "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
0x00A7: "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
0x00A8: "TLS_PSK_WITH_AES_128_GCM_SHA256",
0x00A9: "TLS_PSK_WITH_AES_256_GCM_SHA384",
0x00AA: "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",
0x00AB: "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",
0x00AC: "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256",
0x00AD: "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384",
0x00AE: "TLS_PSK_WITH_AES_128_CBC_SHA256",
0x00AF: "TLS_PSK_WITH_AES_256_CBC_SHA384",
0x00B0: "TLS_PSK_WITH_NULL_SHA256",
0x00B1: "TLS_PSK_WITH_NULL_SHA384",
0x00B2: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",
0x00B3: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",
0x00B4: "TLS_DHE_PSK_WITH_NULL_SHA256",
0x00B5: "TLS_DHE_PSK_WITH_NULL_SHA384",
0x00B6: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256",
0x00B7: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384",
0x00B8: "TLS_RSA_PSK_WITH_NULL_SHA256",
0x00B9: "TLS_RSA_PSK_WITH_NULL_SHA384",
0x00BA: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
0x00BB: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256",
0x00BC: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
0x00BD: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
0x00BE: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
0x00BF: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
0x00C0: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
0x00C1: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256",
0x00C2: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256",
0x00C3: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
0x00C4: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
0x00C5: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
0x00C6: "TLS_SM4_GCM_SM3",
0x00C7: "TLS_SM4_CCM_SM3",
0x00FF: "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
0x0A0A: "GREASE",
0x1301: "TLS_AES_128_GCM_SHA256",
0x1302: "TLS_AES_256_GCM_SHA384",
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
0x1304: "TLS_AES_128_CCM_SHA256",
0x1305: "TLS_AES_128_CCM_8_SHA256",
0x1306: "TLS_AEGIS_256_SHA512",
0x1307: "TLS_AEGIS_128L_SHA256",
0x1A1A: "GREASE",
0x2A2A: "GREASE",
0x3A3A: "GREASE",
0x4A4A: "GREASE",
0x5600: "TLS_FALLBACK_SCSV",
0x5A5A: "GREASE",
0x6A6A: "GREASE",
0x7A7A: "GREASE",
0x8A8A: "GREASE",
0x9A9A: "GREASE",
0xAAAA: "GREASE",
0xBABA: "GREASE",
0xC001: "TLS_ECDH_ECDSA_WITH_NULL_SHA",
0xC002: "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
0xC003: "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
0xC004: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
0xC005: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
0xC006: "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
0xC007: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
0xC008: "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
0xC009: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
0xC00A: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
0xC00B: "TLS_ECDH_RSA_WITH_NULL_SHA",
0xC00C: "TLS_ECDH_RSA_WITH_RC4_128_SHA",
0xC00D: "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
0xC00E: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
0xC00F: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
0xC010: "TLS_ECDHE_RSA_WITH_NULL_SHA",
0xC011: "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
0xC012: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
0xC013: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
0xC014: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
0xC015: "TLS_ECDH_anon_WITH_NULL_SHA",
0xC016: "TLS_ECDH_anon_WITH_RC4_128_SHA",
0xC017: "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
0xC018: "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
0xC019: "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
0xC01A: "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA",
0xC01B: "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA",
0xC01C: "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA",
0xC01D: "TLS_SRP_SHA_WITH_AES_128_CBC_SHA",
0xC01E: "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA",
0xC01F: "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA",
0xC020: "TLS_SRP_SHA_WITH_AES_256_CBC_SHA",
0xC021: "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA",
0xC022: "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA",
0xC023: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
0xC024: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
0xC025: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
0xC026: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
0xC027: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
0xC028: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
0xC029: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
0xC02A: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
0xC02B: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
0xC02C: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
0xC02D: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
0xC02E: "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
0xC02F: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
0xC030: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
0xC031: "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
0xC032: "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
0xC033: "TLS_ECDHE_PSK_WITH_RC4_128_SHA",
0xC034: "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
0xC035: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
0xC036: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
0xC037: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
0xC038: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
0xC039: "TLS_ECDHE_PSK_WITH_NULL_SHA",
0xC03A: "TLS_ECDHE_PSK_WITH_NULL_SHA256",
0xC03B: "TLS_ECDHE_PSK_WITH_NULL_SHA384",
0xC03C: "TLS_RSA_WITH_ARIA_128_CBC_SHA256",
0xC03D: "TLS_RSA_WITH_ARIA_256_CBC_SHA384",
0xC03E: "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256",
0xC03F: "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384",
0xC040: "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256",
0xC041: "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384",
0xC042: "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256",
0xC043: "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384",
0xC044: "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256",
0xC045: "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384",
0xC046: "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256",
0xC047: "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384",
0xC048: "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256",
0xC049: "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384",
0xC04A: "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256",
0xC04B: "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384",
0xC04C: "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256",
0xC04D: "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384",
0xC04E: "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256",
0xC04F: "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384",
0xC050: "TLS_RSA_WITH_ARIA_128_GCM_SHA256",
0xC051: "TLS_RSA_WITH_ARIA_256_GCM_SHA384",
0xC052: "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256",
0xC053: "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384",
0xC054: "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256",
0xC055: "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384",
0xC056: "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256",
0xC057: "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384",
0xC058: "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256",
0xC059: "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384",
0xC05A: "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256",
0xC05B: "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384",
0xC05C: "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256",
0xC05D: "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384",
0xC05E: "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256",
0xC05F: "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384",
0xC060: "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256",
0xC061: "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384",
0xC062: "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256",
0xC063: "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384",
0xC064: "TLS_PSK_WITH_ARIA_128_CBC_SHA256",
0xC065: "TLS_PSK_WITH_ARIA_256_CBC_SHA384",
0xC066: "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256",
0xC067: "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384",
0xC068: "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256",
0xC069: "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384",
0xC06A: "TLS_PSK_WITH_ARIA_128_GCM_SHA256",
0xC06B: "TLS_PSK_WITH_ARIA_256_GCM_SHA384",
0xC06C: "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256",
0xC06D: "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384",
0xC06E: "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256",
0xC06F: "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384",
0xC070: "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256",
0xC071: "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384",
0xC072: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
0xC073: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
0xC074: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
0xC075: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
0xC076: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
0xC077: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
0xC078: "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
0xC079: "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384",
0xC07A: "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256",
0xC07B: "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384",
0xC07C: "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
0xC07D: "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
0xC07E: "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
0xC07F: "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
0xC080: "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256",
0xC081: "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384",
0xC082: "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256",
0xC083: "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384",
0xC084: "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256",
0xC085: "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384",
0xC086: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
0xC087: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
0xC088: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
0xC089: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
0xC08A: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
0xC08B: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
0xC08C: "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
0xC08D: "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
0xC08E: "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256",
0xC08F: "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384",
0xC090: "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256",
0xC091: "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384",
0xC092: "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256",
0xC093: "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384",
0xC094: "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256",
0xC095: "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384",
0xC096: "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
0xC097: "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
0xC098: "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256",
0xC099: "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384",
0xC09A: "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
0xC09B: "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
0xC09C: "TLS_RSA_WITH_AES_128_CCM",
0xC09D: "TLS_RSA_WITH_AES_256_CCM",
0xC09E: "TLS_DHE_RSA_WITH_AES_128_CCM",
0xC09F: "TLS_DHE_RSA_WITH_AES_256_CCM",
0xC0A0: "TLS_RSA_WITH_AES_128_CCM_8",
0xC0A1: "TLS_RSA_WITH_AES_256_CCM_8",
0xC0A2: "TLS_DHE_RSA_WITH_AES_128_CCM_8",
0xC0A3: "TLS_DHE_RSA_WITH_AES_256_CCM_8",
0xC0A4: "TLS_PSK_WITH_AES_128_CCM",
0xC0A5: "TLS_PSK_WITH_AES_256_CCM",
0xC0A6: "TLS_DHE_PSK_WITH_AES_128_CCM",
0xC0A7: "TLS_DHE_PSK_WITH_AES_256_CCM",
0xC0A8: "TLS_PSK_WITH_AES_128_CCM_8",
0xC0A9: "TLS_PSK_WITH_AES_256_CCM_8",
0xC0AA: "TLS_PSK_DHE_WITH_AES_128_CCM_8",
0xC0AB: "TLS_PSK_DHE_WITH_AES_256_CCM_8",
0xC0AC: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM",
0xC0AD: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM",
0xC0AE: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",
0xC0AF: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",
0xC0B0: "TLS_ECCPWD_WITH_AES_128_GCM_SHA256",
0xC0B1: "TLS_ECCPWD_WITH_AES_256_GCM_SHA384",
0xC0B2: "TLS_ECCPWD_WITH_AES_128_CCM_SHA256",
0xC0B3: "TLS_ECCPWD_WITH_AES_256_CCM_SHA384",
0xC0B4: "TLS_SHA256_SHA256",
0xC0B5: "TLS_SHA384_SHA384",
0xC100: "TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC",
0xC101: "TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC",
0xC102: "TLS_GOSTR341112_256_WITH_28147_CNT_IMIT",
0xC103: "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L",
0xC104: "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L",
0xC105: "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S",
0xC106: "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S",
0xCACA: "GREASE",
0xCCA8: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
0xCCA9: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
0xCCAA: "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
0xCCAB: "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256",
0xCCAC: "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
0xCCAD: "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
0xCCAE: "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256",
0xD001: "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256",
0xD002: "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384",
0xD003: "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256",
0xD005: "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256",
0xDADA: "GREASE",
0xEAEA: "GREASE",
0xFAFA: "GREASE",
};
/**
* GREASE values
*/
export const GREASE_VALUES = [
0x0a0a,
0x1a1a,
0x2a2a,
0x3a3a,
0x4a4a,
0x5a5a,
0x6a6a,
0x7a7a,
0x8a8a,
0x9a9a,
0xaaaa,
0xbaba,
0xcaca,
0xdada,
0xeaea,
0xfafa
];
/**
* Parses the supported_versions extension and returns the highest supported version.
* @param {Uint8Array} bytes
* @returns {number}
*/
export function parseHighestSupportedVersion(bytes) {
const s = new Stream(bytes);
// The Server Hello supported_versions extension simply contains the chosen version
if (s.length === 2) {
return s.readInt(2);
}
// Length
let i = s.readInt(1);
let highestVersion = 0;
while (s.hasMore() && i-- > 0) {
const v = s.readInt(2);
if (GREASE_VALUES.includes(v)) continue;
if (v > highestVersion) highestVersion = v;
}
return highestVersion;
}
/**
* Parses the application_layer_protocol_negotiation extension and returns the first value.
* @param {Uint8Array} bytes
* @returns {number}
*/
export function parseFirstALPNValue(bytes) {
const s = new Stream(bytes);
const alpnExtLen = s.readInt(2);
if (alpnExtLen < 3) return "00";
const strLen = s.readInt(1);
if (strLen < 2) return "00";
return s.readString(strLen);
}

174
src/core/lib/XXTEA.mjs Normal file
View file

@ -0,0 +1,174 @@
/**
* XXTEA library
*
* Encryption Algorithm Authors:
* David J. Wheeler
* Roger M. Needham
*
* @author Ma Bingyao [mabingyao@gmail.com]
* @author n1474335 [n1474335@gmail.com]
* @license MIT
*/
const DELTA = 0x9E3779B9;
/**
* Convert a buffer to a Uint8Array
* @param {Uint32Array} v
* @param {boolean} includeLength
* @returns {Uint8Array}
*/
function toUint8Array(v, includeLength) {
const length = v.length;
let n = length << 2;
if (includeLength) {
const m = v[length - 1];
n -= 4;
if ((m < n - 3) || (m > n)) {
return null;
}
n = m;
}
const bytes = new Uint8Array(n);
for (let i = 0; i < n; i++) {
bytes[i] = v[i >> 2] >> ((i & 3) << 3);
}
return bytes;
}
/**
* Convert a buffer to a Uint32Array
* @param {TypedArray} bs
* @param {boolean} includeLength
* @returns {Uint32Array}
*/
function toUint32Array(bs, includeLength) {
const length = bs.length;
let n = length >> 2;
if ((length & 3) !== 0) {
++n;
}
let v;
if (includeLength) {
v = new Uint32Array(n + 1);
v[n] = length;
} else {
v = new Uint32Array(n);
}
for (let i = 0; i < length; ++i) {
v[i >> 2] |= bs[i] << ((i & 3) << 3);
}
return v;
}
/**
* Mask an int to 32 bits
* @param {number} i
* @returns {number}
*/
function int32(i) {
return i & 0xFFFFFFFF;
}
/**
* MX function for data randomisation
* @param {number} sum
* @param {number} y
* @param {number} z
* @param {number} p
* @param {number} e
* @param {number} k
* @returns {number}
*/
function mx(sum, y, z, p, e, k) {
return ((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
}
/**
* Ensure an array is a multiple of 16 bits
* @param {TypedArray} k
* @returns {TypedArray}
*/
function fixk(k) {
if (k.length < 16) {
const key = new Uint8Array(16);
key.set(k);
return key;
}
return k;
}
/**
* Performs XXTEA encryption on a Uint32Array
* @param {Uint32Array} v
* @param {Uint32Array} k
* @returns {Uint32Array}
*/
function encryptUint32Array(v, k) {
const length = v.length;
const n = length - 1;
let y, z, sum, e, p, q;
z = v[n];
sum = 0;
for (q = Math.floor(6 + 52 / length) | 0; q > 0; --q) {
sum = int32(sum + DELTA);
e = sum >>> 2 & 3;
for (p = 0; p < n; ++p) {
y = v[p + 1];
z = v[p] = int32(v[p] + mx(sum, y, z, p, e, k));
}
y = v[0];
z = v[n] = int32(v[n] + mx(sum, y, z, n, e, k));
}
return v;
}
/**
* Performs XXTEA decryption on a Uint32Array
* @param {Uint32Array} v
* @param {Uint32Array} k
* @returns {Uint32Array}
*/
function decryptUint32Array(v, k) {
const length = v.length;
const n = length - 1;
let y, z, sum, e, p;
y = v[0];
const q = Math.floor(6 + 52 / length);
for (sum = int32(q * DELTA); sum !== 0; sum = int32(sum - DELTA)) {
e = sum >>> 2 & 3;
for (p = n; p > 0; --p) {
z = v[p - 1];
y = v[p] = int32(v[p] - mx(sum, y, z, p, e, k));
}
z = v[n];
y = v[0] = int32(v[0] - mx(sum, y, z, 0, e, k));
}
return v;
}
/**
* Encrypt function
* @param {TypedArray} data
* @param {TypedArray} key
* @returns {Uint8Array}
*/
export function encrypt(data, key) {
if (data === undefined || data === null || data.length === 0) {
return data;
}
return toUint8Array(encryptUint32Array(toUint32Array(data, true), toUint32Array(fixk(key), false)), false);
}
/**
* Decrypt function
* @param {TypedArray} data
* @param {TypedArray} key
* @returns {Uint8Array}
*/
export function decrypt(data, key) {
if (data === undefined || data === null || data.length === 0) {
return data;
}
return toUint8Array(decryptUint32Array(toUint32Array(data, false), toUint32Array(fixk(key), false)), true);
}

View file

@ -22,7 +22,7 @@ class AESDecrypt extends Operation {
this.name = "AES Decrypt";
this.module = "Ciphers";
this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul><br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.";
this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul><br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.";
this.infoURL = "https://wikipedia.org/wiki/Advanced_Encryption_Standard";
this.inputType = "string";
this.outputType = "string";
@ -41,8 +41,41 @@ class AESDecrypt extends Operation {
},
{
"name": "Mode",
"type": "option",
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
"type": "argSelector",
"value": [
{
name: "CBC",
off: [5, 6]
},
{
name: "CFB",
off: [5, 6]
},
{
name: "OFB",
off: [5, 6]
},
{
name: "CTR",
off: [5, 6]
},
{
name: "GCM",
on: [5, 6]
},
{
name: "ECB",
off: [5, 6]
},
{
name: "CBC/NoPadding",
off: [5, 6]
},
{
name: "ECB/NoPadding",
off: [5, 6]
}
]
},
{
"name": "Input",
@ -59,6 +92,12 @@ class AESDecrypt extends Operation {
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "Additional Authenticated Data",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
}
];
}
@ -73,10 +112,12 @@ class AESDecrypt extends Operation {
run(input, args) {
const key = Utils.convertToByteString(args[0].string, args[0].option),
iv = Utils.convertToByteString(args[1].string, args[1].option),
mode = args[2],
mode = args[2].split("/")[0],
noPadding = args[2].endsWith("NoPadding"),
inputType = args[3],
outputType = args[4],
gcmTag = Utils.convertToByteString(args[5].string, args[5].option);
gcmTag = Utils.convertToByteString(args[5].string, args[5].option),
aad = Utils.convertToByteString(args[6].string, args[6].option);
if ([16, 24, 32].indexOf(key.length) < 0) {
throw new OperationError(`Invalid key length: ${key.length} bytes
@ -90,9 +131,18 @@ The following algorithms will be used based on the size of the key:
input = Utils.convertToByteString(input, inputType);
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
/* Allow for a "no padding" mode */
if (noPadding) {
decipher.mode.unpad = function(output, options) {
return true;
};
}
decipher.start({
iv: iv.length === 0 ? "" : iv,
tag: gcmTag
tag: mode === "GCM" ? gcmTag : undefined,
additionalData: mode === "GCM" ? aad : undefined
});
decipher.update(forge.util.createBuffer(input));
const result = decipher.finish();

View file

@ -41,8 +41,41 @@ class AESEncrypt extends Operation {
},
{
"name": "Mode",
"type": "option",
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
"type": "argSelector",
"value": [
{
name: "CBC",
off: [5]
},
{
name: "CFB",
off: [5]
},
{
name: "OFB",
off: [5]
},
{
name: "CTR",
off: [5]
},
{
name: "GCM",
on: [5]
},
{
name: "ECB",
off: [5]
},
{
name: "CBC/NoPadding",
off: [5]
},
{
name: "ECB/NoPadding",
off: [5]
}
]
},
{
"name": "Input",
@ -53,6 +86,12 @@ class AESEncrypt extends Operation {
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
},
{
"name": "Additional Authenticated Data",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
}
];
}
@ -67,9 +106,11 @@ class AESEncrypt extends Operation {
run(input, args) {
const key = Utils.convertToByteString(args[0].string, args[0].option),
iv = Utils.convertToByteString(args[1].string, args[1].option),
mode = args[2],
mode = args[2].split("/")[0],
noPadding = args[2].endsWith("NoPadding"),
inputType = args[3],
outputType = args[4];
outputType = args[4],
aad = Utils.convertToByteString(args[5].string, args[5].option);
if ([16, 24, 32].indexOf(key.length) < 0) {
throw new OperationError(`Invalid key length: ${key.length} bytes
@ -82,8 +123,20 @@ The following algorithms will be used based on the size of the key:
input = Utils.convertToByteString(input, inputType);
// Handle NoPadding modes
if (noPadding && input.length % 16 !== 0) {
throw new OperationError("Input length must be a multiple of 16 bytes for NoPadding modes.");
}
const cipher = forge.cipher.createCipher("AES-" + mode, key);
cipher.start({iv: iv});
cipher.start({
iv: iv,
additionalData: mode === "GCM" ? aad : undefined
});
if (noPadding) {
cipher.mode.pad = function(output, options) {
return true;
};
}
cipher.update(forge.util.createBuffer(input));
cipher.finish();

View file

@ -0,0 +1,128 @@
/**
* @author mikecat
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import { toHexFast } from "../lib/Hex.mjs";
import forge from "node-forge";
import OperationError from "../errors/OperationError.mjs";
/**
* AES Key Unwrap operation
*/
class AESKeyUnwrap extends Operation {
/**
* AESKeyUnwrap constructor
*/
constructor() {
super();
this.name = "AES Key Unwrap";
this.module = "Ciphers";
this.description = "Decryptor for a key wrapping algorithm defined in RFC3394, which is used to protect keys in untrusted storage or communications, using AES.<br><br>This algorithm uses an AES key (KEK: key-encryption key) and a 64-bit IV to decrypt 64-bit blocks.";
this.infoURL = "https://wikipedia.org/wiki/Key_wrap";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Key (KEK)",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "IV",
"type": "toggleString",
"value": "a6a6a6a6a6a6a6a6",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "Input",
"type": "option",
"value": ["Hex", "Raw"]
},
{
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
},
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const kek = Utils.convertToByteString(args[0].string, args[0].option),
iv = Utils.convertToByteString(args[1].string, args[1].option),
inputType = args[2],
outputType = args[3];
if (kek.length !== 16 && kek.length !== 24 && kek.length !== 32) {
throw new OperationError("KEK must be either 16, 24, or 32 bytes (currently " + kek.length + " bytes)");
}
if (iv.length !== 8) {
throw new OperationError("IV must be 8 bytes (currently " + iv.length + " bytes)");
}
const inputData = Utils.convertToByteString(input, inputType);
if (inputData.length % 8 !== 0 || inputData.length < 24) {
throw new OperationError("input must be 8n (n>=3) bytes (currently " + inputData.length + " bytes)");
}
const cipher = forge.cipher.createCipher("AES-ECB", kek);
cipher.start();
cipher.update(forge.util.createBuffer(""));
cipher.finish();
const paddingBlock = cipher.output.getBytes();
const decipher = forge.cipher.createDecipher("AES-ECB", kek);
let A = inputData.substring(0, 8);
const R = [];
for (let i = 8; i < inputData.length; i += 8) {
R.push(inputData.substring(i, i + 8));
}
let cntLower = R.length >>> 0;
let cntUpper = (R.length / ((1 << 30) * 4)) >>> 0;
cntUpper = cntUpper * 6 + ((cntLower * 6 / ((1 << 30) * 4)) >>> 0);
cntLower = cntLower * 6 >>> 0;
for (let j = 5; j >= 0; j--) {
for (let i = R.length - 1; i >= 0; i--) {
const aBuffer = Utils.strToArrayBuffer(A);
const aView = new DataView(aBuffer);
aView.setUint32(0, aView.getUint32(0) ^ cntUpper);
aView.setUint32(4, aView.getUint32(4) ^ cntLower);
A = Utils.arrayBufferToStr(aBuffer, false);
decipher.start();
decipher.update(forge.util.createBuffer(A + R[i] + paddingBlock));
decipher.finish();
const B = decipher.output.getBytes();
A = B.substring(0, 8);
R[i] = B.substring(8, 16);
cntLower--;
if (cntLower < 0) {
cntUpper--;
cntLower = 0xffffffff;
}
}
}
if (A !== iv) {
throw new OperationError("IV mismatch");
}
const P = R.join("");
if (outputType === "Hex") {
return toHexFast(Utils.strToArrayBuffer(P));
}
return P;
}
}
export default AESKeyUnwrap;

View file

@ -0,0 +1,115 @@
/**
* @author mikecat
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import { toHexFast } from "../lib/Hex.mjs";
import forge from "node-forge";
import OperationError from "../errors/OperationError.mjs";
/**
* AES Key Wrap operation
*/
class AESKeyWrap extends Operation {
/**
* AESKeyWrap constructor
*/
constructor() {
super();
this.name = "AES Key Wrap";
this.module = "Ciphers";
this.description = "A key wrapping algorithm defined in RFC3394, which is used to protect keys in untrusted storage or communications, using AES.<br><br>This algorithm uses an AES key (KEK: key-encryption key) and a 64-bit IV to encrypt 64-bit blocks.";
this.infoURL = "https://wikipedia.org/wiki/Key_wrap";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Key (KEK)",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "IV",
"type": "toggleString",
"value": "a6a6a6a6a6a6a6a6",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "Input",
"type": "option",
"value": ["Hex", "Raw"]
},
{
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
},
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const kek = Utils.convertToByteString(args[0].string, args[0].option),
iv = Utils.convertToByteString(args[1].string, args[1].option),
inputType = args[2],
outputType = args[3];
if (kek.length !== 16 && kek.length !== 24 && kek.length !== 32) {
throw new OperationError("KEK must be either 16, 24, or 32 bytes (currently " + kek.length + " bytes)");
}
if (iv.length !== 8) {
throw new OperationError("IV must be 8 bytes (currently " + iv.length + " bytes)");
}
const inputData = Utils.convertToByteString(input, inputType);
if (inputData.length % 8 !== 0 || inputData.length < 16) {
throw new OperationError("input must be 8n (n>=2) bytes (currently " + inputData.length + " bytes)");
}
const cipher = forge.cipher.createCipher("AES-ECB", kek);
let A = iv;
const R = [];
for (let i = 0; i < inputData.length; i += 8) {
R.push(inputData.substring(i, i + 8));
}
let cntLower = 1, cntUpper = 0;
for (let j = 0; j < 6; j++) {
for (let i = 0; i < R.length; i++) {
cipher.start();
cipher.update(forge.util.createBuffer(A + R[i]));
cipher.finish();
const B = cipher.output.getBytes();
const msbBuffer = Utils.strToArrayBuffer(B.substring(0, 8));
const msbView = new DataView(msbBuffer);
msbView.setUint32(0, msbView.getUint32(0) ^ cntUpper);
msbView.setUint32(4, msbView.getUint32(4) ^ cntLower);
A = Utils.arrayBufferToStr(msbBuffer, false);
R[i] = B.substring(8, 16);
cntLower++;
if (cntLower > 0xffffffff) {
cntUpper++;
cntLower = 0;
}
}
}
const C = A + R.join("");
if (outputType === "Hex") {
return toHexFast(Utils.strToArrayBuffer(C));
}
return C;
}
}
export default AESKeyWrap;

View file

@ -0,0 +1,52 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import "reflect-metadata"; // Required as a shim for the amf library
import { AMF0, AMF3 } from "@astronautlabs/amf";
/**
* AMF Decode operation
*/
class AMFDecode extends Operation {
/**
* AMFDecode constructor
*/
constructor() {
super();
this.name = "AMF Decode";
this.module = "Encodings";
this.description = "Action Message Format (AMF) is a binary format used to serialize object graphs such as ActionScript objects and XML, or send messages between an Adobe Flash client and a remote service, usually a Flash Media Server or third party alternatives.";
this.infoURL = "https://wikipedia.org/wiki/Action_Message_Format";
this.inputType = "ArrayBuffer";
this.outputType = "JSON";
this.args = [
{
name: "Format",
type: "option",
value: ["AMF0", "AMF3"],
defaultIndex: 1
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {JSON}
*/
run(input, args) {
const [format] = args;
const handler = format === "AMF0" ? AMF0 : AMF3;
const encoded = new Uint8Array(input);
return handler.Value.deserialize(encoded);
}
}
export default AMFDecode;

View file

@ -0,0 +1,52 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import "reflect-metadata"; // Required as a shim for the amf library
import { AMF0, AMF3 } from "@astronautlabs/amf";
/**
* AMF Encode operation
*/
class AMFEncode extends Operation {
/**
* AMFEncode constructor
*/
constructor() {
super();
this.name = "AMF Encode";
this.module = "Encodings";
this.description = "Action Message Format (AMF) is a binary format used to serialize object graphs such as ActionScript objects and XML, or send messages between an Adobe Flash client and a remote service, usually a Flash Media Server or third party alternatives.";
this.infoURL = "https://wikipedia.org/wiki/Action_Message_Format";
this.inputType = "JSON";
this.outputType = "ArrayBuffer";
this.args = [
{
name: "Format",
type: "option",
value: ["AMF0", "AMF3"],
defaultIndex: 1
}
];
}
/**
* @param {JSON} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
run(input, args) {
const [format] = args;
const handler = format === "AMF0" ? AMF0 : AMF3;
const output = handler.Value.any(input).serialize();
return output.buffer;
}
}
export default AMFEncode;

View file

@ -22,7 +22,13 @@ class AddLineNumbers extends Operation {
this.description = "Adds line numbers to the output.";
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.args = [
{
"name": "Offset",
"type": "number",
"value": 0
}
];
}
/**
@ -33,10 +39,11 @@ class AddLineNumbers extends Operation {
run(input, args) {
const lines = input.split("\n"),
width = lines.length.toString().length;
const offset = args[0] ? parseInt(args[0], 10) : 0;
let output = "";
for (let n = 0; n < lines.length; n++) {
output += (n+1).toString().padStart(width, " ") + " " + lines[n] + "\n";
output += (n+1+offset).toString().padStart(width, " ") + " " + lines[n] + "\n";
}
return output.slice(0, output.length-1);
}

View file

@ -9,8 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
import Jimp from "jimp/es/index.js";
/**
* Add Text To Image operation
@ -128,7 +127,7 @@ class AddTextToImage extends Operation {
let image;
try {
image = await jimp.read(input);
image = await Jimp.read(input);
} catch (err) {
throw new OperationError(`Error loading image. (${err})`);
}
@ -164,7 +163,7 @@ class AddTextToImage extends Operation {
const font = fontsMap[fontFace];
// LoadFont needs an absolute url, so append the font name to self.docURL
const jimpFont = await jimp.loadFont(self.docURL + "/" + font.default);
const jimpFont = await Jimp.loadFont(self.docURL + "/" + font.default);
jimpFont.pages.forEach(function(page) {
if (page.bitmap) {
@ -191,7 +190,7 @@ class AddTextToImage extends Operation {
});
// Create a temporary image to hold the rendered text
const textImage = new jimp(jimp.measureText(jimpFont, text), jimp.measureTextHeight(jimpFont, text));
const textImage = new Jimp(Jimp.measureText(jimpFont, text), Jimp.measureTextHeight(jimpFont, text));
textImage.print(jimpFont, 0, 0, text);
// Scale the rendered text image to the correct size
@ -199,9 +198,9 @@ class AddTextToImage extends Operation {
if (size !== 1) {
// Use bicubic for decreasing size
if (size > 1) {
textImage.scale(scaleFactor, jimp.RESIZE_BICUBIC);
textImage.scale(scaleFactor, Jimp.RESIZE_BICUBIC);
} else {
textImage.scale(scaleFactor, jimp.RESIZE_BILINEAR);
textImage.scale(scaleFactor, Jimp.RESIZE_BILINEAR);
}
}
@ -235,9 +234,9 @@ class AddTextToImage extends Operation {
let imageBuffer;
if (image.getMIME() === "image/gif") {
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
} else {
imageBuffer = await image.getBufferAsync(jimp.AUTO);
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
}
return imageBuffer.buffer;
} catch (err) {

View file

@ -0,0 +1,117 @@
/**
* @author Tan Zhen Yong [tzy@beyondthesprawl.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import argon2 from "argon2-browser";
/**
* Argon2 operation
*/
class Argon2 extends Operation {
/**
* Argon2 constructor
*/
constructor() {
super();
this.name = "Argon2";
this.module = "Crypto";
this.description = "Argon2 is a key derivation function that was selected as the winner of the Password Hashing Competition in July 2015. It was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich from the University of Luxembourg.<br><br>Enter the password in the input to generate its hash.";
this.infoURL = "https://wikipedia.org/wiki/Argon2";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Salt",
"type": "toggleString",
"value": "somesalt",
"toggleValues": ["UTF8", "Hex", "Base64", "Latin1"]
},
{
"name": "Iterations",
"type": "number",
"value": 3
},
{
"name": "Memory (KiB)",
"type": "number",
"value": 4096
},
{
"name": "Parallelism",
"type": "number",
"value": 1
},
{
"name": "Hash length (bytes)",
"type": "number",
"value": 32
},
{
"name": "Type",
"type": "option",
"value": ["Argon2i", "Argon2d", "Argon2id"],
"defaultIndex": 0
},
{
"name": "Output format",
"type": "option",
"value": ["Encoded hash", "Hex hash", "Raw hash"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const argon2Types = {
"Argon2i": argon2.ArgonType.Argon2i,
"Argon2d": argon2.ArgonType.Argon2d,
"Argon2id": argon2.ArgonType.Argon2id
};
const salt = Utils.convertToByteString(args[0].string || "", args[0].option),
time = args[1],
mem = args[2],
parallelism = args[3],
hashLen = args[4],
type = argon2Types[args[5]],
outFormat = args[6];
try {
const result = await argon2.hash({
pass: input,
salt,
time,
mem,
parallelism,
hashLen,
type,
});
switch (outFormat) {
case "Hex hash":
return result.hashHex;
case "Raw hash":
return Utils.arrayBufferToStr(result.hash);
case "Encoded hash":
default:
return result.encoded;
}
} catch (err) {
throw new OperationError(`Error: ${err.message}`);
}
}
}
export default Argon2;

View file

@ -0,0 +1,58 @@
/**
* @author Tan Zhen Yong [tzy@beyondthesprawl.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import argon2 from "argon2-browser";
/**
* Argon2 compare operation
*/
class Argon2Compare extends Operation {
/**
* Argon2Compare constructor
*/
constructor() {
super();
this.name = "Argon2 compare";
this.module = "Crypto";
this.description = "Tests whether the input matches the given Argon2 hash. To test multiple possible passwords, use the 'Fork' operation.";
this.infoURL = "https://wikipedia.org/wiki/Argon2";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Encoded hash",
"type": "string",
"value": ""
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const encoded = args[0];
try {
await argon2.verify({
pass: input,
encoded
});
return `Match: ${input}`;
} catch (err) {
return "No match";
}
}
}
export default Argon2Compare;

View file

@ -70,10 +70,14 @@ class BlowfishDecrypt extends Operation {
inputType = args[3],
outputType = args[4];
if (key.length !== 8) {
if (key.length < 4 || key.length > 56) {
throw new OperationError(`Invalid key length: ${key.length} bytes
Blowfish uses a key length of 8 bytes (64 bits).`);
Blowfish's key length needs to be between 4 and 56 bytes (32-448 bits).`);
}
if (mode !== "ECB" && iv.length !== 8) {
throw new OperationError(`Invalid IV length: ${iv.length} bytes. Expected 8 bytes.`);
}
input = Utils.convertToByteString(input, inputType);

View file

@ -70,10 +70,14 @@ class BlowfishEncrypt extends Operation {
inputType = args[3],
outputType = args[4];
if (key.length !== 8) {
if (key.length < 4 || key.length > 56) {
throw new OperationError(`Invalid key length: ${key.length} bytes
Blowfish uses a key length of 8 bytes (64 bits).`);
Blowfish's key length needs to be between 4 and 56 bytes (32-448 bits).`);
}
if (mode !== "ECB" && iv.length !== 8) {
throw new OperationError(`Invalid IV length: ${iv.length} bytes. Expected 8 bytes.`);
}
input = Utils.convertToByteString(input, inputType);

View file

@ -10,8 +10,7 @@ import { isWorkerEnvironment } from "../Utils.mjs";
import { isImage } from "../lib/FileType.mjs";
import { toBase64 } from "../lib/Base64.mjs";
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
import jimplib from "jimp/es/index.js";
const jimp = jimplib.default ? jimplib.default : jimplib;
import Jimp from "jimp/es/index.js";
/**
* Blur Image operation
@ -60,7 +59,7 @@ class BlurImage extends Operation {
let image;
try {
image = await jimp.read(input);
image = await Jimp.read(input);
} catch (err) {
throw new OperationError(`Error loading image. (${err})`);
}
@ -80,9 +79,9 @@ class BlurImage extends Operation {
let imageBuffer;
if (image.getMIME() === "image/gif") {
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
} else {
imageBuffer = await image.getBufferAsync(jimp.AUTO);
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
}
return imageBuffer.buffer;
} catch (err) {

View file

@ -1,6 +1,9 @@
/**
* Emulation of the Bombe machine.
*
* Tested against the Bombe Rebuild at Bletchley Park's TNMOC
* using a variety of inputs and settings to confirm correctness.
*
* @author s2224834
* @copyright Crown Copyright 2019
* @license Apache-2.0

View file

@ -0,0 +1,41 @@
/**
* @author Danh4 [dan.h4@ncsc.gov.uk]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Cbor from "cbor";
/**
* CBOR Decode operation
*/
class CBORDecode extends Operation {
/**
* CBORDecode constructor
*/
constructor() {
super();
this.name = "CBOR Decode";
this.module = "Serialise";
this.description = "Concise Binary Object Representation (CBOR) is a binary data serialization format loosely based on JSON. Like JSON it allows the transmission of data objects that contain namevalue pairs, but in a more concise manner. This increases processing and transfer speeds at the cost of human readability. It is defined in IETF RFC 8949.";
this.infoURL = "https://wikipedia.org/wiki/CBOR";
this.inputType = "ArrayBuffer";
this.outputType = "JSON";
this.args = [];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {JSON}
*/
run(input, args) {
return Cbor.decodeFirstSync(Buffer.from(input).toString("hex"));
}
}
export default CBORDecode;

View file

@ -0,0 +1,41 @@
/**
* @author Danh4 [dan.h4@ncsc.gov.uk]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Cbor from "cbor";
/**
* CBOR Encode operation
*/
class CBOREncode extends Operation {
/**
* CBOREncode constructor
*/
constructor() {
super();
this.name = "CBOR Encode";
this.module = "Serialise";
this.description = "Concise Binary Object Representation (CBOR) is a binary data serialization format loosely based on JSON. Like JSON it allows the transmission of data objects that contain namevalue pairs, but in a more concise manner. This increases processing and transfer speeds at the cost of human readability. It is defined in IETF RFC 8949.";
this.infoURL = "https://wikipedia.org/wiki/CBOR";
this.inputType = "JSON";
this.outputType = "ArrayBuffer";
this.args = [];
}
/**
* @param {JSON} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
run(input, args) {
return new Uint8Array(Cbor.encodeCanonical(input)).buffer;
}
}
export default CBOREncode;

View file

@ -0,0 +1,149 @@
/**
* @author mikecat
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import forge from "node-forge";
import { toHexFast } from "../lib/Hex.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* CMAC operation
*/
class CMAC extends Operation {
/**
* CMAC constructor
*/
constructor() {
super();
this.name = "CMAC";
this.module = "Crypto";
this.description = "CMAC is a block-cipher based message authentication code algorithm.<br><br>RFC4493 defines AES-CMAC that uses AES encryption with a 128-bit key.<br>NIST SP 800-38B suggests usages of AES with other key lengths and Triple DES.";
this.infoURL = "https://wikipedia.org/wiki/CMAC";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "Encryption algorithm",
"type": "option",
"value": ["AES", "Triple DES"]
}
];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const key = Utils.convertToByteString(args[0].string, args[0].option);
const algo = args[1];
const info = (function() {
switch (algo) {
case "AES":
if (key.length !== 16 && key.length !== 24 && key.length !== 32) {
throw new OperationError("The key for AES must be either 16, 24, or 32 bytes (currently " + key.length + " bytes)");
}
return {
"algorithm": "AES-ECB",
"key": key,
"blockSize": 16,
"Rb": new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x87]),
};
case "Triple DES":
if (key.length !== 16 && key.length !== 24) {
throw new OperationError("The key for Triple DES must be 16 or 24 bytes (currently " + key.length + " bytes)");
}
return {
"algorithm": "3DES-ECB",
"key": key.length === 16 ? key + key.substring(0, 8) : key,
"blockSize": 8,
"Rb": new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0x1b]),
};
default:
throw new OperationError("Undefined encryption algorithm");
}
})();
const xor = function(a, b, out) {
if (!out) out = new Uint8Array(a.length);
for (let i = 0; i < a.length; i++) {
out[i] = a[i] ^ b[i];
}
return out;
};
const leftShift1 = function(a) {
const out = new Uint8Array(a.length);
let carry = 0;
for (let i = a.length - 1; i >= 0; i--) {
out[i] = (a[i] << 1) | carry;
carry = a[i] >> 7;
}
return out;
};
const cipher = forge.cipher.createCipher(info.algorithm, info.key);
const encrypt = function(a, out) {
if (!out) out = new Uint8Array(a.length);
cipher.start();
cipher.update(forge.util.createBuffer(a));
cipher.finish();
const cipherText = cipher.output.getBytes();
for (let i = 0; i < a.length; i++) {
out[i] = cipherText.charCodeAt(i);
}
return out;
};
const L = encrypt(new Uint8Array(info.blockSize));
const K1 = leftShift1(L);
if (L[0] & 0x80) xor(K1, info.Rb, K1);
const K2 = leftShift1(K1);
if (K1[0] & 0x80) xor(K2, info.Rb, K2);
const n = Math.ceil(input.byteLength / info.blockSize);
const lastBlock = (function() {
if (n === 0) {
const data = new Uint8Array(K2);
data[0] ^= 0x80;
return data;
}
const inputLast = new Uint8Array(input, info.blockSize * (n - 1));
if (inputLast.length === info.blockSize) {
return xor(inputLast, K1, inputLast);
} else {
const data = new Uint8Array(info.blockSize);
data.set(inputLast, 0);
data[inputLast.length] = 0x80;
return xor(data, K2, data);
}
})();
const X = new Uint8Array(info.blockSize);
const Y = new Uint8Array(info.blockSize);
for (let i = 0; i < n - 1; i++) {
xor(X, new Uint8Array(input, info.blockSize * i, info.blockSize), Y);
encrypt(Y, X);
}
xor(lastBlock, X, Y);
const T = encrypt(Y);
return toHexFast(T);
}
}
export default CMAC;

View file

@ -1,41 +0,0 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import JSCRC from "js-crc";
/**
* CRC-16 Checksum operation
*/
class CRC16Checksum extends Operation {
/**
* CRC16Checksum constructor
*/
constructor() {
super();
this.name = "CRC-16 Checksum";
this.module = "Crypto";
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
return JSCRC.crc16(input);
}
}
export default CRC16Checksum;

View file

@ -1,41 +0,0 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import JSCRC from "js-crc";
/**
* CRC-32 Checksum operation
*/
class CRC32Checksum extends Operation {
/**
* CRC32Checksum constructor
*/
constructor() {
super();
this.name = "CRC-32 Checksum";
this.module = "Crypto";
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.";
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [];
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
return JSCRC.crc32(input);
}
}
export default CRC32Checksum;

View file

@ -1,157 +0,0 @@
/**
* @author mshwed [m@ttshwed.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import { toHexFast } from "../lib/Hex.mjs";
/**
* CRC-8 Checksum operation
*/
class CRC8Checksum extends Operation {
/**
* CRC8Checksum constructor
*/
constructor() {
super();
this.name = "CRC-8 Checksum";
this.module = "Crypto";
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
"name": "Algorithm",
"type": "option",
"value": [
"CRC-8",
"CRC-8/CDMA2000",
"CRC-8/DARC",
"CRC-8/DVB-S2",
"CRC-8/EBU",
"CRC-8/I-CODE",
"CRC-8/ITU",
"CRC-8/MAXIM",
"CRC-8/ROHC",
"CRC-8/WCDMA"
]
}
];
}
/**
* Generates the pre-computed lookup table for byte division
*
* @param polynomial
*/
calculateCRC8LookupTable(polynomial) {
const crc8Table = new Uint8Array(256);
let currentByte;
for (let i = 0; i < 256; i++) {
currentByte = i;
for (let bit = 0; bit < 8; bit++) {
if ((currentByte & 0x80) !== 0) {
currentByte <<= 1;
currentByte ^= polynomial;
} else {
currentByte <<= 1;
}
}
crc8Table[i] = currentByte;
}
return crc8Table;
}
/**
* Calculates the CRC-8 Checksum from an input
*
* @param {ArrayBuffer} input
* @param {number} polynomial
* @param {number} initializationValue
* @param {boolean} inputReflection
* @param {boolean} outputReflection
* @param {number} xorOut
*/
calculateCRC8(input, polynomial, initializationValue, inputReflection, outputReflection, xorOut) {
const crcSize = 8;
const crcTable = this.calculateCRC8LookupTable(polynomial);
let crc = initializationValue !== 0 ? initializationValue : 0;
let currentByte, position;
input = new Uint8Array(input);
for (const inputByte of input) {
currentByte = inputReflection ? this.reverseBits(inputByte, crcSize) : inputByte;
position = (currentByte ^ crc) & 255;
crc = crcTable[position];
}
crc = outputReflection ? this.reverseBits(crc, crcSize) : crc;
if (xorOut !== 0) crc = crc ^ xorOut;
return toHexFast(new Uint8Array([crc]));
}
/**
* Reverse the bits for a given input byte.
*
* @param {number} input
*/
reverseBits(input, hashSize) {
let reversedByte = 0;
for (let i = hashSize - 1; i >= 0; i--) {
reversedByte |= ((input & 1) << i);
input >>= 1;
}
return reversedByte;
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const algorithm = args[0];
switch (algorithm) {
case "CRC-8":
return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x0);
case "CRC-8/CDMA2000":
return this.calculateCRC8(input, 0x9B, 0xFF, false, false, 0x0);
case "CRC-8/DARC":
return this.calculateCRC8(input, 0x39, 0x0, true, true, 0x0);
case "CRC-8/DVB-S2":
return this.calculateCRC8(input, 0xD5, 0x0, false, false, 0x0);
case "CRC-8/EBU":
return this.calculateCRC8(input, 0x1D, 0xFF, true, true, 0x0);
case "CRC-8/I-CODE":
return this.calculateCRC8(input, 0x1D, 0xFD, false, false, 0x0);
case "CRC-8/ITU":
return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x55);
case "CRC-8/MAXIM":
return this.calculateCRC8(input, 0x31, 0x0, true, true, 0x0);
case "CRC-8/ROHC":
return this.calculateCRC8(input, 0x7, 0xFF, true, true, 0x0);
case "CRC-8/WCDMA":
return this.calculateCRC8(input, 0x9B, 0x0, true, true, 0x0);
default:
throw new OperationError("Unknown checksum algorithm");
}
}
}
export default CRC8Checksum;

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import xmldom from "xmldom";
import xmldom from "@xmldom/xmldom";
import nwmatcher from "nwmatcher";
/**

View file

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

View file

@ -0,0 +1,61 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* 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,98 @@
/**
* @author tedk [tedk@ted.do]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Caret/M-decode operation
*
* https://gist.githubusercontent.com/JaHIY/3c91bbf7bea5661e6abfbd1349ee81a2/raw/c7b480e9ff24bcb8f5287a8a8a2dcb9bf5628506/decode_m_notation.cpp
*/
class CaretMdecode extends Operation {
/**
* CaretMdecode constructor
*/
constructor() {
super();
this.name = "Caret/M-decode";
this.module = "Default";
this.description = "Decodes caret or M-encoded strings, i.e. ^M turns into a newline, M-^] turns into 0x9d. Sources such as `cat -v`.\n\nPlease be aware that when using `cat -v` ^_ (caret-underscore) will not be encoded, but represents a valid encoding (namely that of 0x1f).";
this.infoURL = "https://en.wikipedia.org/wiki/Caret_notation";
this.inputType = "string";
this.outputType = "byteArray";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
const bytes = [];
let prev = "";
for (let i = 0; i < input.length; i++) {
const charCode = input.charCodeAt(i);
const curChar = input.charAt(i);
if (prev === "M-^") {
if (charCode > 63 && charCode <= 95) {
bytes.push(charCode + 64);
} else if (charCode === 63) {
bytes.push(255);
} else {
bytes.push(77, 45, 94, charCode);
}
prev = "";
} else if (prev === "M-") {
if (curChar === "^") {
prev = prev + "^";
} else if (charCode >= 32 && charCode <= 126) {
bytes.push(charCode + 128);
prev = "";
} else {
bytes.push(77, 45, charCode);
prev = "";
}
} else if (prev === "M") {
if (curChar === "-") {
prev = prev + "-";
} else {
bytes.push(77, charCode);
prev = "";
}
} else if (prev === "^") {
if (charCode > 63 && charCode <= 126) {
bytes.push(charCode - 64);
} else if (charCode === 63) {
bytes.push(127);
} else {
bytes.push(94, charCode);
}
prev = "";
} else {
if (curChar === "M") {
prev = "M";
} else if (curChar === "^") {
prev = "^";
} else {
bytes.push(charCode);
}
}
}
return bytes;
}
}
export default CaretMdecode;

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