mirror of
https://github.com/gchq/CyberChef
synced 2026-02-04 10:44:01 +00:00
Compare commits
28 Commits
fix/docker
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa34e2fafc | ||
|
|
1542cadde8 | ||
|
|
64399ad60e | ||
|
|
96c93b95f2 | ||
|
|
9df82113c4 | ||
|
|
55ef47f645 | ||
|
|
5e53fe113d | ||
|
|
5c49f87727 | ||
|
|
e0c4957da4 | ||
|
|
9512444eee | ||
|
|
dd26c09003 | ||
|
|
a30f5f1b50 | ||
|
|
b885e8423d | ||
|
|
2092e5b20c | ||
|
|
621331b03e | ||
|
|
2a1294f1c0 | ||
|
|
fb968da64f | ||
|
|
314a14a45b | ||
|
|
dc8121e7fc | ||
|
|
554a3b071e | ||
|
|
9fc91b3fc6 | ||
|
|
6dd651a4df | ||
|
|
54a63b37bd | ||
|
|
3aed784ce2 | ||
|
|
77a43b4f78 | ||
|
|
d58e162bfa | ||
|
|
77c2b7923d | ||
|
|
73a39fa3ce |
2
.github/workflows/master.yml
vendored
2
.github/workflows/master.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Production Build
|
- name: Production Build
|
||||||
if: success()
|
if: success()
|
||||||
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>"
|
run: npx grunt prod --msg=""
|
||||||
|
|
||||||
- name: Generate sitemap
|
- name: Generate sitemap
|
||||||
run: npx grunt exec:sitemap
|
run: npx grunt exec:sitemap
|
||||||
|
|||||||
16
.github/workflows/pull_requests.yml
vendored
16
.github/workflows/pull_requests.yml
vendored
@@ -34,20 +34,20 @@ jobs:
|
|||||||
if: success()
|
if: success()
|
||||||
run: npx grunt prod
|
run: npx grunt prod
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Production Image Build
|
- name: Production Image Build
|
||||||
if: success()
|
if: success()
|
||||||
id: build-image
|
id: build-image
|
||||||
uses: redhat-actions/buildah-build@v2
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
# Not being uploaded to any registry, use a simple name to allow Buildah to build correctly.
|
# Not being uploaded to any registry, use a simple name to allow Buildah to build correctly.
|
||||||
image: cyberchef
|
image: cyberchef
|
||||||
containerfiles: ./Dockerfile
|
platforms: linux/amd64,linux/arm64
|
||||||
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
|
- name: UI Tests
|
||||||
if: success()
|
if: success()
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
36
.github/workflows/releases.yml
vendored
36
.github/workflows/releases.yml
vendored
@@ -45,6 +45,12 @@ jobs:
|
|||||||
sudo apt-get install xvfb
|
sudo apt-get install xvfb
|
||||||
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Image Metadata
|
- name: Image Metadata
|
||||||
id: image-metadata
|
id: image-metadata
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v4
|
||||||
@@ -55,30 +61,22 @@ jobs:
|
|||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
|
|
||||||
- name: Production Image Build
|
- name: Log in to GHCR
|
||||||
id: build-image
|
uses: docker/login-action@v3
|
||||||
uses: redhat-actions/buildah-build@v2
|
|
||||||
with:
|
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 }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ env.REGISTRY_USER }}
|
username: ${{ env.REGISTRY_USER }}
|
||||||
password: ${{ env.REGISTRY_PASSWORD }}
|
password: ${{ env.REGISTRY_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Publish to GHCR
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.image-metadata.outputs.tags }}
|
||||||
|
labels: ${{ steps.image-metadata.outputs.labels }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|
||||||
- name: Upload Release Assets
|
- name: Upload Release Assets
|
||||||
id: upload-release-assets
|
id: upload-release-assets
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
|||||||
165
CHANGELOG.md
165
CHANGELOG.md
@@ -13,6 +13,75 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
### [10.20.0] - 2026-01-28
|
||||||
|
- Fixed Optical Character Recognition and added tests [@n1474335] | [ab37c1e]
|
||||||
|
- Fixed JA4 version fallback value [@n1474335] | [7a5225c]
|
||||||
|
- Updated chromedriver [@n1474335] | [0e82e4b]
|
||||||
|
- Fixed RSA Sign and Verify character encodings [@n1474335] | [895a929]
|
||||||
|
- Updated chromedriver [@n1474335] | [d3adfc7]
|
||||||
|
- Added message format arg to RSA Verify operation [@n1474335] | [47c85a1]
|
||||||
|
- Add operation for parsing X.509 CRLs [@robinsandhu] | [#1887]
|
||||||
|
- Fix typo in description of JWT Sign recipe [@GuilhermoReadonly] | [#1961]
|
||||||
|
- Corrected path to generateNodeIndex.mjs [@simonarnell] | [#1959]
|
||||||
|
- Add 'header' ingredient to JWT Sign operation [@RandomByte] | [#1957]
|
||||||
|
- Add Parse TLS record operation [@c65722] | [#1936]
|
||||||
|
- Automatically detect chrome driver version [@gchq] | [#1972]
|
||||||
|
- Add Strip UDP header operation [@c65722] | [#1900]
|
||||||
|
- Add Strip TCP header operation [@c65722] | [#1898]
|
||||||
|
- Webpack compress with gzip and brotli [@max0x53] | [#1955]
|
||||||
|
- add offset field to 'Add Line Numbers' operation [@Adamkadaban] | [#1866]
|
||||||
|
- Disable flakey URL test [@a3957273] | [#1973]
|
||||||
|
- Add Strip IPv4 header operation [@c65722] | [#1899]
|
||||||
|
- IPv6 Transition Operation [@jb30795] | [#1780]
|
||||||
|
- fix: Blowfish - ignore IV length in ECB mode [@FranciscoPombal] | [#1902]
|
||||||
|
- Add 'Drop nth bytes' operation [@Oshawk] | [#1914]
|
||||||
|
- Add 'Take nth bytes' operation [@Oshawk] | [#1915]
|
||||||
|
- Add Leet Speak [@bartblaze] | [#1971]
|
||||||
|
- Fix Generate TOTP & HOPT [@exactlyaron] | [#1966]
|
||||||
|
- Updated luhn checksum operation to work with different bases [@k3ach] | [#1933]
|
||||||
|
- automatically theme mode based on user preference [@vs4vijay] | [#1921]
|
||||||
|
- fix: DES/Triple DES - misleading error messages [@FranciscoPombal] | [#1904]
|
||||||
|
- fix: ROT13 - shifting numbers by negative amounts [@FranciscoPombal] | [#1903]
|
||||||
|
- Introduce Yubico's Modhex for Conversion [@linuxgemini] | [#1105]
|
||||||
|
- Feature: MIME RFC2047 Decoding [@MShwed] | [#630]
|
||||||
|
- CC-1889 add _ option [@depperm] | [#1977]
|
||||||
|
- chore(root): add cspell [@evenstensberg] | [#1976]
|
||||||
|
- Preserve uppercase for Leet Speak [@bartblaze] | [#1981]
|
||||||
|
- Load the user's preferred color scheme if the URL contains an invalid theme [@0xh3xa] | [#2007]
|
||||||
|
- Add SM2 Encrypt and Decrypt Operations [@flakjacket95] | [#1909]
|
||||||
|
- Support jq as an operation. [@zhzy0077] | [#1604]
|
||||||
|
- Add fingerprints to the 'Parse X.509 certificate' operation [@JSCU-CNI] | [#1863]
|
||||||
|
- Added a JSON to YAML and a YAML to JSON operation [@ccarpo] | [#1286]
|
||||||
|
- Add CRC Operation [@r4mos] | [#1993]
|
||||||
|
- Bug Fix: selected theme not loading when refreshing [@0xh3xa] | [#2006]
|
||||||
|
- Fix(RecipeWaiter): sanitize user input in addOperation to prevent XSS [@0xh3xa] | [#2014]
|
||||||
|
- Docker multiplatform build support [@PathToLife] | [#1974]
|
||||||
|
- Add Base32 Hex Extended Alphabet and Base32 Tests. [@peterc-s] | [#1991]
|
||||||
|
- Add ECB/NoPadding and CBC/NoPadding support to AES encryption [@plvie] | [#2013]
|
||||||
|
- Add new operation: PHP Serialize [@brun0ne] | [#1548]
|
||||||
|
- Push input through postmessage [@kenduguay1] | [#1992]
|
||||||
|
- Add jsonata query operation [@jonking-ajar] | [#1587]
|
||||||
|
- Re-enable Npm Release in github workflows [@PathToLife] | [#2031]
|
||||||
|
- Add to ECDSA Verify the message format [@r4mos] | [#2027]
|
||||||
|
- Added alternating caps functionality [@sw5678] | [#1897]
|
||||||
|
- XOR Checksum operation added [@jg42526] | [#2035]
|
||||||
|
- Add GenerateAllChecksums operation * Remove checksums from GenerateAllHashes operation [@es45411] | [66d445c]
|
||||||
|
- Update GenerateAllChecksums infoURL [@es45411] | [#2037]
|
||||||
|
- Add toggle "+" character to URLDecode operation [@es45411] | [#2040]
|
||||||
|
- Workaround for Safari load bug [@GCHQDeveloper94872] | [#2038]
|
||||||
|
- Updated Dockerfile to correctly build on ARM64 platforms [@Sma-Das] | [#2042]
|
||||||
|
- Addresses bug report #2008 Added explicit support for octal IP addresses. Changed approach to IPv4 regex to be string manipulation generated. Added some unit tests for IP address parsing - probably not full coverage. Added lookahead and lookbehind tricks to resolve warned issue that 1.2.3.256 would still be extracted as 1.2.3.25. Now only accepts valid IP addresses. Warning replaced with clause about infinite length dotted decimal forms. [@gchqdev364] | [#2041]
|
||||||
|
- Remove trim from rail fence [@Odyhibit] | [#1986]
|
||||||
|
- Fix email regex [@ericli-splunk] | [#2025]
|
||||||
|
- Add Blake3 hashing [@xumptex] | [#2023]
|
||||||
|
- Use defaultIndex instead of 0 in transformArgs [@bartvanandel] | [#2015]
|
||||||
|
- Add "Generate UUID" and "Analyse UUID" operations [@bartvanandel] | [#2011]
|
||||||
|
- Add new operation: Template [@kendallgoto] | [#2021]
|
||||||
|
- Add more clear build instructions [@remingtr] | [#1873]
|
||||||
|
- Show On Map updated to use leaflet over WikiMedia [@0xff1ce] | [#1884]
|
||||||
|
- Fixed ToDecimal signed logic [@starplanet] | [#1545]
|
||||||
|
- Use BigInt for encoding/decoding VarInt [@mikecat] | [#1978]
|
||||||
|
|
||||||
### [10.19.0] - 2024-06-21
|
### [10.19.0] - 2024-06-21
|
||||||
- Add support for ECDSA and DSA in 'Parse CSR' [@robinsandhu] | [#1828]
|
- Add support for ECDSA and DSA in 'Parse CSR' [@robinsandhu] | [#1828]
|
||||||
- Fix typos in SIGABA.mjs [@eltociear] | [#1834]
|
- Fix typos in SIGABA.mjs [@eltociear] | [#1834]
|
||||||
@@ -440,6 +509,7 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
## [4.0.0] - 2016-11-28
|
## [4.0.0] - 2016-11-28
|
||||||
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
||||||
|
|
||||||
|
[10.20.0]: https://github.com/gchq/CyberChef/releases/tag/v10.20.0
|
||||||
[10.19.0]: https://github.com/gchq/CyberChef/releases/tag/v10.19.0
|
[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.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.17.0]: https://github.com/gchq/CyberChef/releases/tag/v10.17.0
|
||||||
@@ -630,6 +700,60 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[@cplussharp]: https://github.com/cplussharp
|
[@cplussharp]: https://github.com/cplussharp
|
||||||
[@robinsandhu]: https://github.com/robinsandhu
|
[@robinsandhu]: https://github.com/robinsandhu
|
||||||
[@eltociear]: https://github.com/eltociear
|
[@eltociear]: https://github.com/eltociear
|
||||||
|
[@GuilhermoReadonly]: https://github.com/GuilhermoReadonly
|
||||||
|
[@simonarnell]: https://github.com/simonarnell
|
||||||
|
[@RandomByte]: https://github.com/RandomByte
|
||||||
|
[@c65722]: https://github.com/c65722
|
||||||
|
[@c65722]: https://github.com/c65722
|
||||||
|
[@c65722]: https://github.com/c65722
|
||||||
|
[@max0x53]: https://github.com/max0x53
|
||||||
|
[@Adamkadaban]: https://github.com/Adamkadaban
|
||||||
|
[@c65722]: https://github.com/c65722
|
||||||
|
[@jb30795]: https://github.com/jb30795
|
||||||
|
[@FranciscoPombal]: https://github.com/FranciscoPombal
|
||||||
|
[@Oshawk]: https://github.com/Oshawk
|
||||||
|
[@Oshawk]: https://github.com/Oshawk
|
||||||
|
[@bartblaze]: https://github.com/bartblaze
|
||||||
|
[@exactlyaron]: https://github.com/exactlyaron
|
||||||
|
[@k3ach]: https://github.com/k3ach
|
||||||
|
[@vs4vijay]: https://github.com/vs4vijay
|
||||||
|
[@FranciscoPombal]: https://github.com/FranciscoPombal
|
||||||
|
[@FranciscoPombal]: https://github.com/FranciscoPombal
|
||||||
|
[@linuxgemini]: https://github.com/linuxgemini
|
||||||
|
[@depperm]: https://github.com/depperm
|
||||||
|
[@evenstensberg]: https://github.com/evenstensberg
|
||||||
|
[@bartblaze]: https://github.com/bartblaze
|
||||||
|
[@0xh3xa]: https://github.com/0xh3xa
|
||||||
|
[@flakjacket95]: https://github.com/flakjacket95
|
||||||
|
[@zhzy0077]: https://github.com/zhzy0077
|
||||||
|
[@JSCU-CNI]: https://github.com/JSCU-CNI
|
||||||
|
[@ccarpo]: https://github.com/ccarpo
|
||||||
|
[@r4mos]: https://github.com/r4mos
|
||||||
|
[@0xh3xa]: https://github.com/0xh3xa
|
||||||
|
[@0xh3xa]: https://github.com/0xh3xa
|
||||||
|
[@PathToLife]: https://github.com/PathToLife
|
||||||
|
[@peterc-s]: https://github.com/peterc-s
|
||||||
|
[@plvie]: https://github.com/plvie
|
||||||
|
[@kenduguay1]: https://github.com/kenduguay1
|
||||||
|
[@jonking-ajar]: https://github.com/jonking-ajar
|
||||||
|
[@PathToLife]: https://github.com/PathToLife
|
||||||
|
[@r4mos]: https://github.com/r4mos
|
||||||
|
[@jg42526]: https://github.com/jg42526
|
||||||
|
[@es45411]: https://github.com/es45411
|
||||||
|
[@gchq]: https://github.com/gchq
|
||||||
|
[@gchqdev364]: https://github.com/gchqdev364
|
||||||
|
[@GCHQDeveloper94872]: https://github.com/GCHQDeveloper94872
|
||||||
|
[@Sma-Das]: https://github.com/Sma-Das
|
||||||
|
[@gchq]: https://github.com/gchq
|
||||||
|
[@Odyhibit]: https://github.com/Odyhibit
|
||||||
|
[@ericli-splunk]: https://github.com/ericli-splunk
|
||||||
|
[@xumptex]: https://github.com/xumptex
|
||||||
|
[@bartvanandel]: https://github.com/bartvanandel
|
||||||
|
[@bartvanandel]: https://github.com/bartvanandel
|
||||||
|
[@kendallgoto]: https://github.com/kendallgoto
|
||||||
|
[@remingtr]: https://github.com/remingtr
|
||||||
|
[@0xff1ce]: https://github.com/0xff1ce
|
||||||
|
[@starplanet]: https://github.com/starplanet
|
||||||
|
|
||||||
|
|
||||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||||
@@ -642,6 +766,46 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[760eff4]: https://github.com/gchq/CyberChef/commit/760eff49b5307aaa3104c5e5b437ffe62299acd1
|
[760eff4]: https://github.com/gchq/CyberChef/commit/760eff49b5307aaa3104c5e5b437ffe62299acd1
|
||||||
[65ffd8d]: https://github.com/gchq/CyberChef/commit/65ffd8d65d88eb369f6f61a5d1d0f807179bffb7
|
[65ffd8d]: https://github.com/gchq/CyberChef/commit/65ffd8d65d88eb369f6f61a5d1d0f807179bffb7
|
||||||
[0a353ee]: https://github.com/gchq/CyberChef/commit/0a353eeb378b9ca5d49e23c7dfc175ae07107b08
|
[0a353ee]: https://github.com/gchq/CyberChef/commit/0a353eeb378b9ca5d49e23c7dfc175ae07107b08
|
||||||
|
[66d445c]: https://github.com/gchq/CyberChef/commit/66d445c5ef4e8bd896fd15396e3ce2d660d8ace1
|
||||||
|
[ab37c1e]: https://github.com/gchq/CyberChef/commit/ab37c1e562dbee0495ed32876ecbb8225282af25
|
||||||
|
[965570d]: https://github.com/gchq/CyberChef/commit/965570d2504c17ee1f96211a1dc10ed40cd2b332
|
||||||
|
[a477f47]: https://github.com/gchq/CyberChef/commit/a477f47aecd01d78b11fe186ed4b20d9c487cfac
|
||||||
|
[7a5225c]: https://github.com/gchq/CyberChef/commit/7a5225c961a5e0d192b03152117cd10a761f73d6
|
||||||
|
[5f88ae4]: https://github.com/gchq/CyberChef/commit/5f88ae44ec77228d9bed8f11e8cc8e7dcfb36914
|
||||||
|
[0e82e4b]: https://github.com/gchq/CyberChef/commit/0e82e4b7c6c77cadb8be61cb145e081d6ecfdc88
|
||||||
|
[d635cca]: https://github.com/gchq/CyberChef/commit/d635cca2106aae2a59caf0e5d7e3633ee1ea3155
|
||||||
|
[895a929]: https://github.com/gchq/CyberChef/commit/895a9299255525cb57886deb9d9fd4ba17ae9548
|
||||||
|
[270a333]: https://github.com/gchq/CyberChef/commit/270a33317944612d27ea1cc15275ad6b0ed097e5
|
||||||
|
[d3adfc7]: https://github.com/gchq/CyberChef/commit/d3adfc7c3e5719279524356bce5261bd8350c0f8
|
||||||
|
[47c85a1]: https://github.com/gchq/CyberChef/commit/47c85a105ddbdd4cabfa44ddddbc56e3907a8c33
|
||||||
|
[3822c6c]: https://github.com/gchq/CyberChef/commit/3822c6c520a0b4200abc675c33f46082f5b9efc6
|
||||||
|
[66d445c]: https://github.com/gchq/CyberChef/commit/66d445c5ef4e8bd896fd15396e3ce2d660d8ace1
|
||||||
|
[ab37c1e]: https://github.com/gchq/CyberChef/commit/ab37c1e562dbee0495ed32876ecbb8225282af25
|
||||||
|
[965570d]: https://github.com/gchq/CyberChef/commit/965570d2504c17ee1f96211a1dc10ed40cd2b332
|
||||||
|
[a477f47]: https://github.com/gchq/CyberChef/commit/a477f47aecd01d78b11fe186ed4b20d9c487cfac
|
||||||
|
[7a5225c]: https://github.com/gchq/CyberChef/commit/7a5225c961a5e0d192b03152117cd10a761f73d6
|
||||||
|
[5f88ae4]: https://github.com/gchq/CyberChef/commit/5f88ae44ec77228d9bed8f11e8cc8e7dcfb36914
|
||||||
|
[0e82e4b]: https://github.com/gchq/CyberChef/commit/0e82e4b7c6c77cadb8be61cb145e081d6ecfdc88
|
||||||
|
[d635cca]: https://github.com/gchq/CyberChef/commit/d635cca2106aae2a59caf0e5d7e3633ee1ea3155
|
||||||
|
[895a929]: https://github.com/gchq/CyberChef/commit/895a9299255525cb57886deb9d9fd4ba17ae9548
|
||||||
|
[270a333]: https://github.com/gchq/CyberChef/commit/270a33317944612d27ea1cc15275ad6b0ed097e5
|
||||||
|
[d3adfc7]: https://github.com/gchq/CyberChef/commit/d3adfc7c3e5719279524356bce5261bd8350c0f8
|
||||||
|
[47c85a1]: https://github.com/gchq/CyberChef/commit/47c85a105ddbdd4cabfa44ddddbc56e3907a8c33
|
||||||
|
[3822c6c]: https://github.com/gchq/CyberChef/commit/3822c6c520a0b4200abc675c33f46082f5b9efc6
|
||||||
|
[66d445c]: https://github.com/gchq/CyberChef/commit/66d445c5ef4e8bd896fd15396e3ce2d660d8ace1
|
||||||
|
[ab37c1e]: https://github.com/gchq/CyberChef/commit/ab37c1e562dbee0495ed32876ecbb8225282af25
|
||||||
|
[965570d]: https://github.com/gchq/CyberChef/commit/965570d2504c17ee1f96211a1dc10ed40cd2b332
|
||||||
|
[a477f47]: https://github.com/gchq/CyberChef/commit/a477f47aecd01d78b11fe186ed4b20d9c487cfac
|
||||||
|
[7a5225c]: https://github.com/gchq/CyberChef/commit/7a5225c961a5e0d192b03152117cd10a761f73d6
|
||||||
|
[5f88ae4]: https://github.com/gchq/CyberChef/commit/5f88ae44ec77228d9bed8f11e8cc8e7dcfb36914
|
||||||
|
[0e82e4b]: https://github.com/gchq/CyberChef/commit/0e82e4b7c6c77cadb8be61cb145e081d6ecfdc88
|
||||||
|
[d635cca]: https://github.com/gchq/CyberChef/commit/d635cca2106aae2a59caf0e5d7e3633ee1ea3155
|
||||||
|
[895a929]: https://github.com/gchq/CyberChef/commit/895a9299255525cb57886deb9d9fd4ba17ae9548
|
||||||
|
[270a333]: https://github.com/gchq/CyberChef/commit/270a33317944612d27ea1cc15275ad6b0ed097e5
|
||||||
|
[d3adfc7]: https://github.com/gchq/CyberChef/commit/d3adfc7c3e5719279524356bce5261bd8350c0f8
|
||||||
|
[47c85a1]: https://github.com/gchq/CyberChef/commit/47c85a105ddbdd4cabfa44ddddbc56e3907a8c33
|
||||||
|
[3822c6c]: https://github.com/gchq/CyberChef/commit/3822c6c520a0b4200abc675c33f46082f5b9efc6
|
||||||
|
[66d445c]: https://github.com/gchq/CyberChef/commit/66d445c5ef4e8bd896fd15396e3ce2d660d8ace1
|
||||||
|
|
||||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||||
@@ -778,4 +942,3 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[#512]: https://github.com/gchq/CyberChef/issues/512
|
[#512]: https://github.com/gchq/CyberChef/issues/512
|
||||||
[#1732]: https://github.com/gchq/CyberChef/issues/1732
|
[#1732]: https://github.com/gchq/CyberChef/issues/1732
|
||||||
[#1789]: https://github.com/gchq/CyberChef/issues/1789
|
[#1789]: https://github.com/gchq/CyberChef/issues/1789
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ RUN npm run build
|
|||||||
#########################################
|
#########################################
|
||||||
# Package static build files into nginx #
|
# 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
|
FROM nginx:stable-alpine AS cyberchef
|
||||||
# Remove TARGETARCH if docker buildx is supported in the CI release as --platform=$TARGETPLATFORM will be automatically set
|
|
||||||
ARG TARGETPLATFORM
|
|
||||||
FROM --platform=${TARGETPLATFORM} nginx:stable-alpine AS cyberchef
|
|
||||||
|
|
||||||
COPY --from=builder /app/build/prod /usr/share/nginx/html/
|
COPY --from=builder /app/build/prod /usr/share/nginx/html/
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -20,21 +20,36 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur
|
|||||||
|
|
||||||
[A live demo can be found here][1] - have fun!
|
[A live demo can be found here][1] - have fun!
|
||||||
|
|
||||||
## Containers
|
## Running Locally with Docker
|
||||||
|
|
||||||
If you would like to try out CyberChef locally you can either build it yourself:
|
**Prerequisites**
|
||||||
|
|
||||||
|
- [Docker](hhttps://www.docker.com/products/docker-desktop/)
|
||||||
|
- Docker Desktop must be open and running on your machine
|
||||||
|
|
||||||
|
|
||||||
|
#### Option 1: Build the Docker Image Yourself
|
||||||
|
|
||||||
|
1. Build the docker image
|
||||||
```bash
|
```bash
|
||||||
docker build --tag cyberchef --ulimit nofile=10000 .
|
docker build --tag cyberchef --ulimit nofile=10000 .
|
||||||
|
```
|
||||||
|
2. Run the docker container
|
||||||
|
```bash
|
||||||
docker run -it -p 8080:80 cyberchef
|
docker run -it -p 8080:80 cyberchef
|
||||||
```
|
```
|
||||||
|
3. Navigate to `http://localhost:8080` in your browser
|
||||||
|
|
||||||
Or you can use our image directly:
|
#### Option 2: Use the pre-built Docker Image
|
||||||
|
|
||||||
|
If you prefer to skip the build process, you can use the pre-built image
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it -p 8080:80 ghcr.io/gchq/cyberchef:latest
|
docker run -it -p 8080:80 ghcr.io/gchq/cyberchef:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Just like before, navigate to `http://localhost:8080` in your browser.
|
||||||
|
|
||||||
This image is built and published through our [GitHub Workflows](.github/workflows/releases.yml)
|
This image is built and published through our [GitHub Workflows](.github/workflows/releases.yml)
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|||||||
178
package-lock.json
generated
178
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "10.19.4",
|
"version": "10.20.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "10.19.4",
|
"version": "10.20.0",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"chi-squared": "^1.1.0",
|
"chi-squared": "^1.1.0",
|
||||||
"codepage": "^1.15.0",
|
"codepage": "^1.15.0",
|
||||||
"crypto-api": "^0.8.5",
|
"crypto-api": "^0.8.5",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"ctph.js": "0.0.5",
|
"ctph.js": "0.0.5",
|
||||||
"d3": "7.9.0",
|
"d3": "7.9.0",
|
||||||
@@ -57,11 +57,11 @@
|
|||||||
"jsesc": "^3.0.2",
|
"jsesc": "^3.0.2",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"jsonata": "^2.0.3",
|
"jsonata": "^2.0.3",
|
||||||
"jsonpath-plus": "^9.0.0",
|
"jsonpath-plus": "^10.3.0",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
"jsrsasign": "^11.1.0",
|
"jsrsasign": "^11.1.0",
|
||||||
"kbpgp": "2.1.15",
|
"kbpgp": "^2.1.17",
|
||||||
"libbzip2-wasm": "0.0.4",
|
"libbzip2-wasm": "0.0.4",
|
||||||
"libyara-wasm": "^1.2.1",
|
"libyara-wasm": "^1.2.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
@@ -5137,7 +5137,6 @@
|
|||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||||
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
|
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"possible-typed-array-names": "^1.0.0"
|
"possible-typed-array-names": "^1.0.0"
|
||||||
@@ -8741,6 +8740,22 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-set-tostringtag": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"get-intrinsic": "^1.2.6",
|
||||||
|
"has-tostringtag": "^1.0.2",
|
||||||
|
"hasown": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/es6-object-assign": {
|
"node_modules/es6-object-assign": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
|
||||||
@@ -9844,7 +9859,6 @@
|
|||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-callable": "^1.1.3"
|
"is-callable": "^1.1.3"
|
||||||
@@ -9904,14 +9918,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||||
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -11706,7 +11722,6 @@
|
|||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||||
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -12057,6 +12072,21 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-typed-array": {
|
||||||
|
"version": "1.1.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
|
||||||
|
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"which-typed-array": "^1.1.16"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-unc-path": {
|
"node_modules/is-unc-path": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
|
||||||
@@ -12503,21 +12533,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jsonpath-plus": {
|
"node_modules/jsonpath-plus": {
|
||||||
"version": "9.0.0",
|
"version": "10.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-9.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz",
|
||||||
"integrity": "sha512-bqE77VIDStrOTV/czspZhTn+o27Xx9ZJRGVkdVShEtPoqsIx5yALv3lWVU6y+PqYvWPJNWE7ORCQheQkEe0DDA==",
|
"integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsep-plugin/assignment": "^1.2.1",
|
"@jsep-plugin/assignment": "^1.3.0",
|
||||||
"@jsep-plugin/regex": "^1.0.3",
|
"@jsep-plugin/regex": "^1.0.4",
|
||||||
"jsep": "^1.3.8"
|
"jsep": "^1.4.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"jsonpath": "bin/jsonpath-cli.js",
|
"jsonpath": "bin/jsonpath-cli.js",
|
||||||
"jsonpath-plus": "bin/jsonpath-cli.js"
|
"jsonpath-plus": "bin/jsonpath-cli.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jsonwebtoken": {
|
"node_modules/jsonwebtoken": {
|
||||||
@@ -12601,9 +12631,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/kbpgp": {
|
"node_modules/kbpgp": {
|
||||||
"version": "2.1.15",
|
"version": "2.1.17",
|
||||||
"resolved": "https://registry.npmjs.org/kbpgp/-/kbpgp-2.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/kbpgp/-/kbpgp-2.1.17.tgz",
|
||||||
"integrity": "sha512-iFdQT+m2Mi2DB14kEFydF2joNe9x3E2VZCGZUt7UXsiZnQx5TtSl4KofP7EPtjHvf7weCxNKlEPSYiiCNMZ2jA==",
|
"integrity": "sha512-pnjH7amyg6dZLXyF42BKbCTST0l0r1ErunqtFRrJCkHkGJb83cZZmx1pnqNFr+d/ls+5gvcHrZLPfUG5q7oRYw==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bn": "^1.0.5",
|
"bn": "^1.0.5",
|
||||||
@@ -13983,9 +14013,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-forge": {
|
"node_modules/node-forge": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz",
|
||||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
|
"integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==",
|
||||||
"license": "(BSD-3-Clause OR GPL-2.0)",
|
"license": "(BSD-3-Clause OR GPL-2.0)",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6.13.0"
|
"node": ">= 6.13.0"
|
||||||
@@ -14900,19 +14930,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pbkdf2": {
|
"node_modules/pbkdf2": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz",
|
||||||
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
|
"integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"create-hash": "^1.1.2",
|
"create-hash": "^1.2.0",
|
||||||
"create-hmac": "^1.1.4",
|
"create-hmac": "^1.1.7",
|
||||||
"ripemd160": "^2.0.1",
|
"ripemd160": "^2.0.3",
|
||||||
"safe-buffer": "^5.0.1",
|
"safe-buffer": "^5.2.1",
|
||||||
"sha.js": "^2.4.8"
|
"sha.js": "^2.4.12",
|
||||||
|
"to-buffer": "^1.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.12"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/peek-readable": {
|
"node_modules/peek-readable": {
|
||||||
@@ -15170,7 +15201,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
||||||
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
|
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -16149,13 +16179,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ripemd160": {
|
"node_modules/ripemd160": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz",
|
||||||
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
|
"integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hash-base": "^3.0.0",
|
"hash-base": "^3.1.2",
|
||||||
"inherits": "^2.0.1"
|
"inherits": "^2.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ripemd160/node_modules/hash-base": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.4",
|
||||||
|
"readable-stream": "^2.3.8",
|
||||||
|
"safe-buffer": "^5.2.1",
|
||||||
|
"to-buffer": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rison": {
|
"node_modules/rison": {
|
||||||
@@ -16617,16 +16665,23 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/sha.js": {
|
"node_modules/sha.js": {
|
||||||
"version": "2.4.11",
|
"version": "2.4.12",
|
||||||
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz",
|
||||||
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
"integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==",
|
||||||
"license": "(MIT AND BSD-3-Clause)",
|
"license": "(MIT AND BSD-3-Clause)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"inherits": "^2.0.1",
|
"inherits": "^2.0.4",
|
||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.2.1",
|
||||||
|
"to-buffer": "^1.2.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"sha.js": "bin.js"
|
"sha.js": "bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
@@ -17663,6 +17718,26 @@
|
|||||||
"node": ">=14.14"
|
"node": ">=14.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/to-buffer": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": "^2.0.5",
|
||||||
|
"safe-buffer": "^5.2.1",
|
||||||
|
"typed-array-buffer": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/to-buffer/node_modules/isarray": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/to-fast-properties": {
|
"node_modules/to-fast-properties": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
|
||||||
@@ -17845,6 +17920,20 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/typed-array-buffer": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bound": "^1.0.3",
|
||||||
|
"es-errors": "^1.3.0",
|
||||||
|
"is-typed-array": "^1.1.14"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ua-parser-js": {
|
"node_modules/ua-parser-js": {
|
||||||
"version": "1.0.40",
|
"version": "1.0.40",
|
||||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz",
|
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz",
|
||||||
@@ -18855,7 +18944,6 @@
|
|||||||
"version": "1.1.18",
|
"version": "1.1.18",
|
||||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz",
|
||||||
"integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==",
|
"integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"available-typed-arrays": "^1.0.7",
|
"available-typed-arrays": "^1.0.7",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "10.19.4",
|
"version": "10.20.0",
|
||||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||||
"author": "n1474335 <n1474335@gmail.com>",
|
"author": "n1474335 <n1474335@gmail.com>",
|
||||||
"homepage": "https://gchq.github.io/CyberChef",
|
"homepage": "https://gchq.github.io/CyberChef",
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
"chi-squared": "^1.1.0",
|
"chi-squared": "^1.1.0",
|
||||||
"codepage": "^1.15.0",
|
"codepage": "^1.15.0",
|
||||||
"crypto-api": "^0.8.5",
|
"crypto-api": "^0.8.5",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"ctph.js": "0.0.5",
|
"ctph.js": "0.0.5",
|
||||||
"d3": "7.9.0",
|
"d3": "7.9.0",
|
||||||
@@ -143,11 +143,11 @@
|
|||||||
"jsesc": "^3.0.2",
|
"jsesc": "^3.0.2",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"jsonata": "^2.0.3",
|
"jsonata": "^2.0.3",
|
||||||
"jsonpath-plus": "^9.0.0",
|
"jsonpath-plus": "^10.3.0",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
"jsrsasign": "^11.1.0",
|
"jsrsasign": "^11.1.0",
|
||||||
"kbpgp": "2.1.15",
|
"kbpgp": "^2.1.17",
|
||||||
"libbzip2-wasm": "0.0.4",
|
"libbzip2-wasm": "0.0.4",
|
||||||
"libyara-wasm": "^1.2.1",
|
"libyara-wasm": "^1.2.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ class Utils {
|
|||||||
*/
|
*/
|
||||||
static printable(str, preserveWs=false, onlyAscii=false) {
|
static printable(str, preserveWs=false, onlyAscii=false) {
|
||||||
if (onlyAscii) {
|
if (onlyAscii) {
|
||||||
return str.replace(/[^\x20-\x7f]/g, ".");
|
return str.replace(/[^\x20-\x7e]/g, ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-misleading-character-class
|
// eslint-disable-next-line no-misleading-character-class
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
"From Base45",
|
"From Base45",
|
||||||
"To Base58",
|
"To Base58",
|
||||||
"From Base58",
|
"From Base58",
|
||||||
|
"To Bech32",
|
||||||
|
"From Bech32",
|
||||||
"To Base62",
|
"To Base62",
|
||||||
"From Base62",
|
"From Base62",
|
||||||
"To Base64",
|
"To Base64",
|
||||||
|
|||||||
371
src/core/lib/Bech32.mjs
Normal file
371
src/core/lib/Bech32.mjs
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
/**
|
||||||
|
* Pure JavaScript implementation of Bech32 and Bech32m encoding.
|
||||||
|
*
|
||||||
|
* Bech32 is defined in BIP-0173: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
||||||
|
* Bech32m is defined in BIP-0350: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
|
||||||
|
*
|
||||||
|
* @author Medjedtxm
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/** Bech32 character set (32 characters, excludes 1, b, i, o) */
|
||||||
|
const CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||||
|
|
||||||
|
/** Reverse lookup table for decoding */
|
||||||
|
const CHARSET_REV = {};
|
||||||
|
for (let i = 0; i < CHARSET.length; i++) {
|
||||||
|
CHARSET_REV[CHARSET[i]] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checksum constant for Bech32 (BIP-0173) */
|
||||||
|
const BECH32_CONST = 1;
|
||||||
|
|
||||||
|
/** Checksum constant for Bech32m (BIP-0350) */
|
||||||
|
const BECH32M_CONST = 0x2bc830a3;
|
||||||
|
|
||||||
|
/** Generator polynomial coefficients for checksum */
|
||||||
|
const GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the polymod checksum
|
||||||
|
* @param {number[]} values - Array of 5-bit values
|
||||||
|
* @returns {number} - Checksum value
|
||||||
|
*/
|
||||||
|
function polymod(values) {
|
||||||
|
let chk = 1;
|
||||||
|
for (const v of values) {
|
||||||
|
const top = chk >> 25;
|
||||||
|
chk = ((chk & 0x1ffffff) << 5) ^ v;
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
if ((top >> i) & 1) {
|
||||||
|
chk ^= GENERATOR[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand HRP for checksum computation
|
||||||
|
* @param {string} hrp - Human-readable part (lowercase)
|
||||||
|
* @returns {number[]} - Expanded values
|
||||||
|
*/
|
||||||
|
function hrpExpand(hrp) {
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < hrp.length; i++) {
|
||||||
|
result.push(hrp.charCodeAt(i) >> 5);
|
||||||
|
}
|
||||||
|
result.push(0);
|
||||||
|
for (let i = 0; i < hrp.length; i++) {
|
||||||
|
result.push(hrp.charCodeAt(i) & 31);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify checksum of a Bech32/Bech32m string
|
||||||
|
* @param {string} hrp - Human-readable part (lowercase)
|
||||||
|
* @param {number[]} data - Data including checksum (5-bit values)
|
||||||
|
* @param {string} encoding - "Bech32" or "Bech32m"
|
||||||
|
* @returns {boolean} - True if checksum is valid
|
||||||
|
*/
|
||||||
|
function verifyChecksum(hrp, data, encoding) {
|
||||||
|
const constant = encoding === "Bech32m" ? BECH32M_CONST : BECH32_CONST;
|
||||||
|
return polymod(hrpExpand(hrp).concat(data)) === constant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create checksum for Bech32/Bech32m encoding
|
||||||
|
* @param {string} hrp - Human-readable part (lowercase)
|
||||||
|
* @param {number[]} data - Data values (5-bit)
|
||||||
|
* @param {string} encoding - "Bech32" or "Bech32m"
|
||||||
|
* @returns {number[]} - 6 checksum values
|
||||||
|
*/
|
||||||
|
function createChecksum(hrp, data, encoding) {
|
||||||
|
const constant = encoding === "Bech32m" ? BECH32M_CONST : BECH32_CONST;
|
||||||
|
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
|
||||||
|
const mod = polymod(values) ^ constant;
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
result.push((mod >> (5 * (5 - i))) & 31);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert 8-bit bytes to 5-bit words
|
||||||
|
* @param {number[]|Uint8Array} data - Input bytes
|
||||||
|
* @returns {number[]} - 5-bit words
|
||||||
|
*/
|
||||||
|
export function toWords(data) {
|
||||||
|
let value = 0;
|
||||||
|
let bits = 0;
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
value = (value << 8) | data[i];
|
||||||
|
bits += 8;
|
||||||
|
|
||||||
|
while (bits >= 5) {
|
||||||
|
bits -= 5;
|
||||||
|
result.push((value >> bits) & 31);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pad remaining bits
|
||||||
|
if (bits > 0) {
|
||||||
|
result.push((value << (5 - bits)) & 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert 5-bit words to 8-bit bytes
|
||||||
|
* @param {number[]} words - 5-bit words
|
||||||
|
* @returns {number[]} - Output bytes
|
||||||
|
*/
|
||||||
|
export function fromWords(words) {
|
||||||
|
let value = 0;
|
||||||
|
let bits = 0;
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < words.length; i++) {
|
||||||
|
value = (value << 5) | words[i];
|
||||||
|
bits += 5;
|
||||||
|
|
||||||
|
while (bits >= 8) {
|
||||||
|
bits -= 8;
|
||||||
|
result.push((value >> bits) & 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for invalid padding per BIP-0173
|
||||||
|
// Condition 1: Cannot have 5+ bits remaining (would indicate incomplete byte)
|
||||||
|
if (bits >= 5) {
|
||||||
|
throw new OperationError("Invalid padding: too many bits remaining");
|
||||||
|
}
|
||||||
|
// Condition 2: Remaining padding bits must all be zero
|
||||||
|
if (bits > 0) {
|
||||||
|
const paddingValue = (value << (8 - bits)) & 255;
|
||||||
|
if (paddingValue !== 0) {
|
||||||
|
throw new OperationError("Invalid padding: non-zero bits in padding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode data to Bech32/Bech32m string
|
||||||
|
*
|
||||||
|
* @param {string} hrp - Human-readable part
|
||||||
|
* @param {number[]|Uint8Array} data - Data bytes to encode
|
||||||
|
* @param {string} encoding - "Bech32" or "Bech32m"
|
||||||
|
* @param {boolean} segwit - If true, treat first byte as witness version (for Bitcoin SegWit)
|
||||||
|
* @returns {string} - Encoded Bech32/Bech32m string
|
||||||
|
*/
|
||||||
|
export function encode(hrp, data, encoding = "Bech32", segwit = false) {
|
||||||
|
// Validate HRP
|
||||||
|
if (!hrp || hrp.length === 0) {
|
||||||
|
throw new OperationError("Human-Readable Part (HRP) cannot be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check HRP characters (ASCII 33-126)
|
||||||
|
for (let i = 0; i < hrp.length; i++) {
|
||||||
|
const c = hrp.charCodeAt(i);
|
||||||
|
if (c < 33 || c > 126) {
|
||||||
|
throw new OperationError(`HRP contains invalid character at position ${i}. Only printable ASCII characters (33-126) are allowed.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert HRP to lowercase
|
||||||
|
const hrpLower = hrp.toLowerCase();
|
||||||
|
|
||||||
|
let words;
|
||||||
|
if (segwit && data.length >= 2) {
|
||||||
|
// SegWit encoding: first byte is witness version (0-16), rest is witness program
|
||||||
|
const witnessVersion = data[0];
|
||||||
|
if (witnessVersion > 16) {
|
||||||
|
throw new OperationError(`Invalid witness version: ${witnessVersion}. Must be 0-16.`);
|
||||||
|
}
|
||||||
|
const witnessProgram = Array.prototype.slice.call(data, 1);
|
||||||
|
|
||||||
|
// Validate witness program length per BIP-0141
|
||||||
|
if (witnessProgram.length < 2 || witnessProgram.length > 40) {
|
||||||
|
throw new OperationError(`Invalid witness program length: ${witnessProgram.length}. Must be 2-40 bytes.`);
|
||||||
|
}
|
||||||
|
if (witnessVersion === 0 && witnessProgram.length !== 20 && witnessProgram.length !== 32) {
|
||||||
|
throw new OperationError(`Invalid witness program length for v0: ${witnessProgram.length}. Must be 20 or 32 bytes.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Witness version is kept as single 5-bit value, program is converted
|
||||||
|
words = [witnessVersion].concat(toWords(witnessProgram));
|
||||||
|
} else {
|
||||||
|
// Generic encoding: convert all bytes to 5-bit words
|
||||||
|
words = toWords(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create checksum
|
||||||
|
const checksum = createChecksum(hrpLower, words, encoding);
|
||||||
|
|
||||||
|
// Build result string
|
||||||
|
let result = hrpLower + "1";
|
||||||
|
for (const w of words.concat(checksum)) {
|
||||||
|
result += CHARSET[w];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check maximum length (90 characters)
|
||||||
|
if (result.length > 90) {
|
||||||
|
throw new OperationError(`Encoded string exceeds maximum length of 90 characters (got ${result.length}). Consider using smaller input data.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode a Bech32/Bech32m string
|
||||||
|
*
|
||||||
|
* @param {string} str - Bech32/Bech32m encoded string
|
||||||
|
* @param {string} encoding - "Bech32", "Bech32m", or "Auto-detect"
|
||||||
|
* @returns {{hrp: string, data: number[]}} - Decoded HRP and data bytes
|
||||||
|
*/
|
||||||
|
export function decode(str, encoding = "Auto-detect") {
|
||||||
|
// Check for empty input
|
||||||
|
if (!str || str.length === 0) {
|
||||||
|
throw new OperationError("Input cannot be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check maximum length
|
||||||
|
if (str.length > 90) {
|
||||||
|
throw new OperationError(`Invalid Bech32 string: exceeds maximum length of 90 characters (got ${str.length}).`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for mixed case
|
||||||
|
const hasUpper = /[A-Z]/.test(str);
|
||||||
|
const hasLower = /[a-z]/.test(str);
|
||||||
|
if (hasUpper && hasLower) {
|
||||||
|
throw new OperationError("Invalid Bech32 string: mixed case is not allowed. Use all uppercase or all lowercase.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to lowercase for processing
|
||||||
|
str = str.toLowerCase();
|
||||||
|
|
||||||
|
// Find separator (last occurrence of '1')
|
||||||
|
const sepIndex = str.lastIndexOf("1");
|
||||||
|
if (sepIndex === -1) {
|
||||||
|
throw new OperationError("Invalid Bech32 string: no separator '1' found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sepIndex === 0) {
|
||||||
|
throw new OperationError("Invalid Bech32 string: Human-Readable Part (HRP) cannot be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sepIndex + 7 > str.length) {
|
||||||
|
throw new OperationError("Invalid Bech32 string: data part is too short (minimum 6 characters for checksum).");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract HRP and data part
|
||||||
|
const hrp = str.substring(0, sepIndex);
|
||||||
|
const dataPart = str.substring(sepIndex + 1);
|
||||||
|
|
||||||
|
// Validate HRP characters
|
||||||
|
for (let i = 0; i < hrp.length; i++) {
|
||||||
|
const c = hrp.charCodeAt(i);
|
||||||
|
if (c < 33 || c > 126) {
|
||||||
|
throw new OperationError(`HRP contains invalid character at position ${i}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode data characters to 5-bit values
|
||||||
|
const data = [];
|
||||||
|
for (let i = 0; i < dataPart.length; i++) {
|
||||||
|
const c = dataPart[i];
|
||||||
|
if (CHARSET_REV[c] === undefined) {
|
||||||
|
throw new OperationError(`Invalid character '${c}' at position ${sepIndex + 1 + i}.`);
|
||||||
|
}
|
||||||
|
data.push(CHARSET_REV[c]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify checksum
|
||||||
|
let usedEncoding;
|
||||||
|
if (encoding === "Bech32") {
|
||||||
|
if (!verifyChecksum(hrp, data, "Bech32")) {
|
||||||
|
throw new OperationError("Invalid Bech32 checksum.");
|
||||||
|
}
|
||||||
|
usedEncoding = "Bech32";
|
||||||
|
} else if (encoding === "Bech32m") {
|
||||||
|
if (!verifyChecksum(hrp, data, "Bech32m")) {
|
||||||
|
throw new OperationError("Invalid Bech32m checksum.");
|
||||||
|
}
|
||||||
|
usedEncoding = "Bech32m";
|
||||||
|
} else {
|
||||||
|
// Auto-detect: try Bech32 first, then Bech32m
|
||||||
|
if (verifyChecksum(hrp, data, "Bech32")) {
|
||||||
|
usedEncoding = "Bech32";
|
||||||
|
} else if (verifyChecksum(hrp, data, "Bech32m")) {
|
||||||
|
usedEncoding = "Bech32m";
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid Bech32/Bech32m string: checksum verification failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove checksum (last 6 values)
|
||||||
|
const words = data.slice(0, data.length - 6);
|
||||||
|
|
||||||
|
// Check if this is likely a SegWit address (Bitcoin, Litecoin, etc.)
|
||||||
|
// For SegWit, the first 5-bit word is the witness version (0-16)
|
||||||
|
// and should be extracted separately, not bit-converted with the rest
|
||||||
|
const segwitHrps = ["bc", "tb", "ltc", "tltc", "bcrt"];
|
||||||
|
const couldBeSegWit = segwitHrps.includes(hrp) && words.length > 0 && words[0] <= 16;
|
||||||
|
|
||||||
|
let bytes;
|
||||||
|
let witnessVersion = null;
|
||||||
|
|
||||||
|
if (couldBeSegWit) {
|
||||||
|
// Try SegWit decode first
|
||||||
|
try {
|
||||||
|
witnessVersion = words[0];
|
||||||
|
const programWords = words.slice(1);
|
||||||
|
const programBytes = fromWords(programWords);
|
||||||
|
|
||||||
|
// Validate SegWit witness program length (20 or 32 bytes for v0, 2-40 for others)
|
||||||
|
const validV0 = witnessVersion === 0 && (programBytes.length === 20 || programBytes.length === 32);
|
||||||
|
const validOther = witnessVersion !== 0 && programBytes.length >= 2 && programBytes.length <= 40;
|
||||||
|
|
||||||
|
if (validV0 || validOther) {
|
||||||
|
// Valid SegWit address
|
||||||
|
bytes = [witnessVersion, ...programBytes];
|
||||||
|
} else {
|
||||||
|
// Not valid SegWit, fall back to generic decode
|
||||||
|
witnessVersion = null;
|
||||||
|
bytes = fromWords(words);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// SegWit decode failed, try generic decode
|
||||||
|
witnessVersion = null;
|
||||||
|
try {
|
||||||
|
bytes = fromWords(words);
|
||||||
|
} catch (e2) {
|
||||||
|
throw new OperationError(`Failed to decode data: ${e2.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Generic Bech32: convert all words
|
||||||
|
try {
|
||||||
|
bytes = fromWords(words);
|
||||||
|
} catch (e) {
|
||||||
|
throw new OperationError(`Failed to decode data: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
hrp: hrp,
|
||||||
|
data: bytes,
|
||||||
|
encoding: usedEncoding,
|
||||||
|
witnessVersion: witnessVersion
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -91,9 +91,7 @@ export function toJA4(bytes) {
|
|||||||
let alpn = "00";
|
let alpn = "00";
|
||||||
for (const ext of tlsr.handshake.value.extensions.value) {
|
for (const ext of tlsr.handshake.value.extensions.value) {
|
||||||
if (ext.type.value === "application_layer_protocol_negotiation") {
|
if (ext.type.value === "application_layer_protocol_negotiation") {
|
||||||
alpn = parseFirstALPNValue(ext.value.data);
|
alpn = alpnFingerprint(parseFirstALPNValue(ext.value.data));
|
||||||
alpn = alpn.charAt(0) + alpn.charAt(alpn.length - 1);
|
|
||||||
if (alpn.charCodeAt(0) > 127) alpn = "99";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,9 +210,7 @@ export function toJA4S(bytes) {
|
|||||||
let alpn = "00";
|
let alpn = "00";
|
||||||
for (const ext of tlsr.handshake.value.extensions.value) {
|
for (const ext of tlsr.handshake.value.extensions.value) {
|
||||||
if (ext.type.value === "application_layer_protocol_negotiation") {
|
if (ext.type.value === "application_layer_protocol_negotiation") {
|
||||||
alpn = parseFirstALPNValue(ext.value.data);
|
alpn = alpnFingerprint(parseFirstALPNValue(ext.value.data));
|
||||||
alpn = alpn.charAt(0) + alpn.charAt(alpn.length - 1);
|
|
||||||
if (alpn.charCodeAt(0) > 127) alpn = "99";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,3 +258,33 @@ function tlsVersionMapper(version) {
|
|||||||
default: return "00"; // Unknown
|
default: return "00"; // Unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a byte is ASCII alphanumeric (0-9, A-Z, a-z).
|
||||||
|
* @param {number} byte
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isAlphanumeric(byte) {
|
||||||
|
return (byte >= 0x30 && byte <= 0x39) ||
|
||||||
|
(byte >= 0x41 && byte <= 0x5A) ||
|
||||||
|
(byte >= 0x61 && byte <= 0x7A);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the 2-character ALPN fingerprint from raw ALPN bytes.
|
||||||
|
* If both first and last bytes are ASCII alphanumeric, returns their characters.
|
||||||
|
* Otherwise, returns first hex digit of first byte + last hex digit of last byte.
|
||||||
|
* @param {Uint8Array|null} rawBytes
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function alpnFingerprint(rawBytes) {
|
||||||
|
if (!rawBytes || rawBytes.length === 0) return "00";
|
||||||
|
const firstByte = rawBytes[0];
|
||||||
|
const lastByte = rawBytes[rawBytes.length - 1];
|
||||||
|
if (isAlphanumeric(firstByte) && isAlphanumeric(lastByte)) {
|
||||||
|
return String.fromCharCode(firstByte) + String.fromCharCode(lastByte);
|
||||||
|
}
|
||||||
|
const firstHex = firstByte.toString(16).padStart(2, "0");
|
||||||
|
const lastHex = lastByte.toString(16).padStart(2, "0");
|
||||||
|
return firstHex[0] + lastHex[1];
|
||||||
|
}
|
||||||
|
|||||||
@@ -863,15 +863,15 @@ export function parseHighestSupportedVersion(bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the application_layer_protocol_negotiation extension and returns the first value.
|
* Parses the application_layer_protocol_negotiation extension and returns the first value as raw bytes.
|
||||||
* @param {Uint8Array} bytes
|
* @param {Uint8Array} bytes
|
||||||
* @returns {number}
|
* @returns {Uint8Array|null}
|
||||||
*/
|
*/
|
||||||
export function parseFirstALPNValue(bytes) {
|
export function parseFirstALPNValue(bytes) {
|
||||||
const s = new Stream(bytes);
|
const s = new Stream(bytes);
|
||||||
const alpnExtLen = s.readInt(2);
|
const alpnExtLen = s.readInt(2);
|
||||||
if (alpnExtLen < 3) return "00";
|
if (alpnExtLen < 2) return null;
|
||||||
const strLen = s.readInt(1);
|
const strLen = s.readInt(1);
|
||||||
if (strLen < 2) return "00";
|
if (strLen < 1) return null;
|
||||||
return s.readString(strLen);
|
return s.getBytes(strLen);
|
||||||
}
|
}
|
||||||
|
|||||||
149
src/core/operations/FromBech32.mjs
Normal file
149
src/core/operations/FromBech32.mjs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
/**
|
||||||
|
* @author Medjedtxm
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import { decode } from "../lib/Bech32.mjs";
|
||||||
|
import { toHex } from "../lib/Hex.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From Bech32 operation
|
||||||
|
*/
|
||||||
|
class FromBech32 extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FromBech32 constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "From Bech32";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Bech32 is an encoding scheme primarily used for Bitcoin SegWit addresses (BIP-0173). It uses a 32-character alphabet that excludes easily confused characters (1, b, i, o) and includes a checksum for error detection.<br><br>Bech32m (BIP-0350) is an updated version used for Bitcoin Taproot addresses.<br><br>Auto-detect will attempt Bech32 first, then Bech32m if the checksum fails.<br><br>Output format options allow you to see the Human-Readable Part (HRP) along with the decoded data.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Bech32";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Encoding",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Auto-detect", "Bech32", "Bech32m"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output Format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Raw", "Hex", "Bitcoin scriptPubKey", "HRP: Hex", "JSON"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
// Bitcoin mainnet SegWit/Taproot addresses
|
||||||
|
pattern: "^bc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{6,87}$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Auto-detect", "Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Bitcoin testnet addresses
|
||||||
|
pattern: "^tb1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{6,87}$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Auto-detect", "Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AGE public keys
|
||||||
|
pattern: "^age1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{6,87}$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Auto-detect", "HRP: Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AGE secret keys
|
||||||
|
pattern: "^AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{6,87}$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Auto-detect", "HRP: Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Litecoin mainnet addresses
|
||||||
|
pattern: "^ltc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{6,87}$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Auto-detect", "Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Generic bech32 pattern
|
||||||
|
pattern: "^[a-z]{1,83}1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{6,}$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Auto-detect", "Hex"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const encoding = args[0];
|
||||||
|
const outputFormat = args[1];
|
||||||
|
|
||||||
|
input = input.trim();
|
||||||
|
|
||||||
|
if (input.length === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const decoded = decode(input, encoding);
|
||||||
|
|
||||||
|
// Format output based on selected option
|
||||||
|
switch (outputFormat) {
|
||||||
|
case "Raw":
|
||||||
|
return decoded.data.map(b => String.fromCharCode(b)).join("");
|
||||||
|
|
||||||
|
case "Hex":
|
||||||
|
return toHex(decoded.data, "");
|
||||||
|
|
||||||
|
case "Bitcoin scriptPubKey": {
|
||||||
|
// Convert to Bitcoin scriptPubKey format as shown in BIP-0173/BIP-0350
|
||||||
|
// Format: [OP_version][length][witness_program]
|
||||||
|
// OP_0 = 0x00, OP_1-OP_16 = 0x51-0x60
|
||||||
|
if (decoded.witnessVersion === null || decoded.data.length < 2) {
|
||||||
|
// Not a SegWit address, fall back to hex
|
||||||
|
return toHex(decoded.data, "");
|
||||||
|
}
|
||||||
|
const witnessVersion = decoded.data[0];
|
||||||
|
const witnessProgram = decoded.data.slice(1);
|
||||||
|
|
||||||
|
// Convert witness version to OP code
|
||||||
|
let opCode;
|
||||||
|
if (witnessVersion === 0) {
|
||||||
|
opCode = 0x00; // OP_0
|
||||||
|
} else if (witnessVersion >= 1 && witnessVersion <= 16) {
|
||||||
|
opCode = 0x50 + witnessVersion; // OP_1 = 0x51, ..., OP_16 = 0x60
|
||||||
|
} else {
|
||||||
|
// Invalid witness version, fall back to hex
|
||||||
|
return toHex(decoded.data, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build scriptPubKey: [OP_version][length][program]
|
||||||
|
const scriptPubKey = [opCode, witnessProgram.length, ...witnessProgram];
|
||||||
|
return toHex(scriptPubKey, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
case "HRP: Hex":
|
||||||
|
return `${decoded.hrp}: ${toHex(decoded.data, "")}`;
|
||||||
|
|
||||||
|
case "JSON":
|
||||||
|
return JSON.stringify({
|
||||||
|
hrp: decoded.hrp,
|
||||||
|
encoding: decoded.encoding,
|
||||||
|
data: toHex(decoded.data, "")
|
||||||
|
}, null, 2);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return toHex(decoded.data, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FromBech32;
|
||||||
@@ -43,7 +43,7 @@ class FromHexdump extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const output = [],
|
const output = [],
|
||||||
regex = /^\s*(?:[\dA-F]{4,16}h?:?)?[ \t]+((?:[\dA-F]{2} ){1,8}(?:[ \t]|[\dA-F]{2}-)(?:[\dA-F]{2} ){1,8}|(?:[\dA-F]{4} )*[\dA-F]{4}|(?:[\dA-F]{2} )*[\dA-F]{2})/igm;
|
regex = /^\s*(?:[\dA-F]{4,16}h?:?)?[ \t]+((?:[\dA-F]{2} ){1,8}(?:[ \t]|[\dA-F]{2}-)(?:[\dA-F]{2} ){1,8}|(?:[\dA-F]{4} )+(?:[\dA-F]{2})?|(?:[\dA-F]{2} )*[\dA-F]{2})/igm;
|
||||||
let block, line;
|
let block, line;
|
||||||
|
|
||||||
while ((block = regex.exec(input))) {
|
while ((block = regex.exec(input))) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @author j433866 [j433866@gmail.com]
|
* @author j433866 [j433866@gmail.com]
|
||||||
* @copyright Crown Copyright 2019
|
* @author 0xff1ce [github.com/0xff1ce]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ class ShowOnMap extends Operation {
|
|||||||
this.name = "Show on map";
|
this.name = "Show on map";
|
||||||
this.module = "Hashing";
|
this.module = "Hashing";
|
||||||
this.description = "Displays co-ordinates on a slippy map.<br><br>Co-ordinates will be converted to decimal degrees before being shown on the map.<br><br>Supported formats:<ul><li>Degrees Minutes Seconds (DMS)</li><li>Degrees Decimal Minutes (DDM)</li><li>Decimal Degrees (DD)</li><li>Geohash</li><li>Military Grid Reference System (MGRS)</li><li>Ordnance Survey National Grid (OSNG)</li><li>Universal Transverse Mercator (UTM)</li></ul><br>This operation will not work offline.";
|
this.description = "Displays co-ordinates on a slippy map.<br><br>Co-ordinates will be converted to decimal degrees before being shown on the map.<br><br>Supported formats:<ul><li>Degrees Minutes Seconds (DMS)</li><li>Degrees Decimal Minutes (DDM)</li><li>Decimal Degrees (DD)</li><li>Geohash</li><li>Military Grid Reference System (MGRS)</li><li>Ordnance Survey National Grid (OSNG)</li><li>Universal Transverse Mercator (UTM)</li></ul><br>This operation will not work offline.";
|
||||||
this.infoURL = "https://foundation.wikimedia.org/wiki/Maps_Terms_of_Use";
|
this.infoURL = "https://osmfoundation.org/wiki/Terms_of_Use";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.presentType = "html";
|
this.presentType = "html";
|
||||||
@@ -85,10 +86,10 @@ class ShowOnMap extends Operation {
|
|||||||
data = "0, 0";
|
data = "0, 0";
|
||||||
}
|
}
|
||||||
const zoomLevel = args[0];
|
const zoomLevel = args[0];
|
||||||
const tileUrl = "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png",
|
const tileUrl = "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
tileAttribution = "<a href=\"https://wikimediafoundation.org/wiki/Maps_Terms_of_Use\">Wikimedia maps</a> | © <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors",
|
tileAttribution = "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors",
|
||||||
leafletUrl = "https://unpkg.com/leaflet@1.5.0/dist/leaflet.js",
|
leafletUrl = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js",
|
||||||
leafletCssUrl = "https://unpkg.com/leaflet@1.5.0/dist/leaflet.css";
|
leafletCssUrl = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css";
|
||||||
return `<link rel="stylesheet" href="${leafletCssUrl}" crossorigin=""/>
|
return `<link rel="stylesheet" href="${leafletCssUrl}" crossorigin=""/>
|
||||||
<style>
|
<style>
|
||||||
#output-text .cm-content,
|
#output-text .cm-content,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class ToBase85 extends Operation {
|
|||||||
value: ALPHABET_OPTIONS
|
value: ALPHABET_OPTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Include delimeter",
|
name: "Include delimiter",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false
|
value: false
|
||||||
}
|
}
|
||||||
|
|||||||
92
src/core/operations/ToBech32.mjs
Normal file
92
src/core/operations/ToBech32.mjs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* @author Medjedtxm
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import { encode } from "../lib/Bech32.mjs";
|
||||||
|
import { fromHex } from "../lib/Hex.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Bech32 operation
|
||||||
|
*/
|
||||||
|
class ToBech32 extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToBech32 constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "To Bech32";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Bech32 is an encoding scheme primarily used for Bitcoin SegWit addresses (BIP-0173). It uses a 32-character alphabet that excludes easily confused characters (1, b, i, o) and includes a checksum for error detection.<br><br>Bech32m (BIP-0350) is an updated version that fixes a weakness in the original Bech32 checksum and is used for Bitcoin Taproot addresses.<br><br>The Human-Readable Part (HRP) identifies the network or purpose (e.g., 'bc' for Bitcoin mainnet, 'tb' for testnet, 'age' for AGE encryption keys).<br><br>Maximum output length is 90 characters as per specification.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Bech32";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Human-Readable Part (HRP)",
|
||||||
|
"type": "string",
|
||||||
|
"value": "bc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Encoding",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Bech32", "Bech32m"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Input Format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Raw bytes", "Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mode",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Generic", "Bitcoin SegWit"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Witness Version",
|
||||||
|
"type": "number",
|
||||||
|
"value": 0,
|
||||||
|
"hint": "SegWit witness version (0-16). Only used in Bitcoin SegWit mode."
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const hrp = args[0];
|
||||||
|
const encoding = args[1];
|
||||||
|
const inputFormat = args[2];
|
||||||
|
const mode = args[3];
|
||||||
|
const witnessVersion = args[4];
|
||||||
|
|
||||||
|
let inputArray;
|
||||||
|
if (inputFormat === "Hex") {
|
||||||
|
// Convert hex string to bytes
|
||||||
|
const hexStr = new TextDecoder().decode(new Uint8Array(input)).replace(/\s/g, "");
|
||||||
|
inputArray = fromHex(hexStr);
|
||||||
|
} else {
|
||||||
|
inputArray = new Uint8Array(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === "Bitcoin SegWit") {
|
||||||
|
// Prepend witness version to the input data
|
||||||
|
const withVersion = new Uint8Array(inputArray.length + 1);
|
||||||
|
withVersion[0] = witnessVersion;
|
||||||
|
withVersion.set(inputArray, 1);
|
||||||
|
return encode(hrp, withVersion, encoding, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return encode(hrp, inputArray, encoding, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToBech32;
|
||||||
@@ -45,11 +45,12 @@ class ToDecimal extends Operation {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
input = new Uint8Array(input);
|
|
||||||
const delim = Utils.charRep(args[0]),
|
const delim = Utils.charRep(args[0]),
|
||||||
signed = args[1];
|
signed = args[1];
|
||||||
if (signed) {
|
if (signed) {
|
||||||
input = input.map(v => v > 0x7F ? v - 0xFF - 1 : v);
|
input = new Int8Array(input);
|
||||||
|
} else {
|
||||||
|
input = new Uint8Array(input);
|
||||||
}
|
}
|
||||||
return input.join(delim);
|
return input.join(delim);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class VarIntDecode extends Operation {
|
|||||||
this.description = "Decodes a VarInt encoded integer. VarInt is an efficient way of encoding variable length integers and is commonly used with Protobuf.";
|
this.description = "Decodes a VarInt encoded integer. VarInt is an efficient way of encoding variable length integers and is commonly used with Protobuf.";
|
||||||
this.infoURL = "https://developers.google.com/protocol-buffers/docs/encoding#varints";
|
this.infoURL = "https://developers.google.com/protocol-buffers/docs/encoding#varints";
|
||||||
this.inputType = "byteArray";
|
this.inputType = "byteArray";
|
||||||
this.outputType = "number";
|
this.outputType = "string";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,18 @@ class VarIntDecode extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
try {
|
try {
|
||||||
return Protobuf.varIntDecode(input);
|
if (typeof BigInt === "function") {
|
||||||
|
let result = BigInt(0);
|
||||||
|
let offset = BigInt(0);
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
result |= BigInt(input[i] & 0x7f) << offset;
|
||||||
|
if (!(input[i] & 0x80)) break;
|
||||||
|
offset += BigInt(7);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
} else {
|
||||||
|
return Protobuf.varIntDecode(input).toString();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(err);
|
throw new OperationError(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,19 +23,31 @@ class VarIntEncode extends Operation {
|
|||||||
this.module = "Default";
|
this.module = "Default";
|
||||||
this.description = "Encodes a Vn integer as a VarInt. VarInt is an efficient way of encoding variable length integers and is commonly used with Protobuf.";
|
this.description = "Encodes a Vn integer as a VarInt. VarInt is an efficient way of encoding variable length integers and is commonly used with Protobuf.";
|
||||||
this.infoURL = "https://developers.google.com/protocol-buffers/docs/encoding#varints";
|
this.infoURL = "https://developers.google.com/protocol-buffers/docs/encoding#varints";
|
||||||
this.inputType = "number";
|
this.inputType = "string";
|
||||||
this.outputType = "byteArray";
|
this.outputType = "byteArray";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} input
|
* @param {string} input
|
||||||
* @param {Object[]} args
|
* @param {Object[]} args
|
||||||
* @returns {byteArray}
|
* @returns {byteArray}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
try {
|
try {
|
||||||
return Protobuf.varIntEncode(input);
|
if (typeof BigInt === "function") {
|
||||||
|
let value = BigInt(input);
|
||||||
|
if (value < 0) throw new OperationError("Negative values cannot be represented as VarInt");
|
||||||
|
const result = [];
|
||||||
|
while (value >= 0x80) {
|
||||||
|
result.push(Number(value & BigInt(0x7f)) | 0x80);
|
||||||
|
value >>= BigInt(7);
|
||||||
|
}
|
||||||
|
result.push(Number(value));
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return Protobuf.varIntEncode(Number(input));
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(err);
|
throw new OperationError(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -650,7 +650,7 @@ class App {
|
|||||||
|
|
||||||
// const compareURL = `https://github.com/gchq/CyberChef/compare/v${prev.join(".")}...v${PKG_VERSION}`;
|
// const compareURL = `https://github.com/gchq/CyberChef/compare/v${prev.join(".")}...v${PKG_VERSION}`;
|
||||||
|
|
||||||
let compileInfo = `<a href='https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md'>Last build: ${timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1)} ago</a>`;
|
let compileInfo = `<a href='https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md'>Last build: ${timeSinceCompile.substring(0, 1).toUpperCase() + timeSinceCompile.substring(1)} ago</a>`;
|
||||||
|
|
||||||
if (window.compileMessage !== "") {
|
if (window.compileMessage !== "") {
|
||||||
compileInfo += " - " + window.compileMessage;
|
compileInfo += " - " + window.compileMessage;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import sm from "sitemap";
|
import sm from "sitemap";
|
||||||
import OperationConfig from "../../core/config/OperationConfig.json" assert {type: "json"};
|
import OperationConfig from "../../core/config/OperationConfig.json" assert { type: "json" };
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an XML sitemap for all CyberChef operations and a number of recipes.
|
* Generates an XML sitemap for all CyberChef operations and a number of recipes.
|
||||||
@@ -10,25 +9,25 @@ import OperationConfig from "../../core/config/OperationConfig.json" assert {typ
|
|||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const smStream = new sm.SitemapStream({
|
const baseUrl = "https://gchq.github.io/CyberChef/";
|
||||||
hostname: "https://gchq.github.io/CyberChef",
|
|
||||||
});
|
const smStream = new sm.SitemapStream({});
|
||||||
|
|
||||||
smStream.write({
|
smStream.write({
|
||||||
url: "/",
|
url: baseUrl,
|
||||||
changefreq: "weekly",
|
changefreq: "weekly",
|
||||||
priority: 1.0
|
priority: 1.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const op in OperationConfig) {
|
for (const op in OperationConfig) {
|
||||||
smStream.write({
|
smStream.write({
|
||||||
url: `/?op=${encodeURIComponent(op)}`,
|
url: `${baseUrl}?op=${encodeURIComponent(op)}`,
|
||||||
changeFreq: "yearly",
|
changeFreq: "yearly",
|
||||||
priority: 0.5
|
priority: 0.5,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
smStream.end();
|
smStream.end();
|
||||||
|
|
||||||
sm.streamToPromise(smStream).then(
|
sm.streamToPromise(smStream).then(
|
||||||
buffer => console.log(buffer.toString()) // eslint-disable-line no-console
|
(buffer) => console.log(buffer.toString()), // eslint-disable-line no-console
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,4 +20,10 @@ TestRegister.addApiTests([
|
|||||||
assert.equal(Utils.parseEscapedChars("\\\\\\'"), "\\'");
|
assert.equal(Utils.parseEscapedChars("\\\\\\'"), "\\'");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
it("Utils: should replace delete character", () => {
|
||||||
|
assert.equal(
|
||||||
|
Utils.printable("\x7e\x7f\x80\xa7", false, true),
|
||||||
|
"\x7e...",
|
||||||
|
);
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import "./tests/Base64.mjs";
|
|||||||
import "./tests/Base85.mjs";
|
import "./tests/Base85.mjs";
|
||||||
import "./tests/Base92.mjs";
|
import "./tests/Base92.mjs";
|
||||||
import "./tests/BCD.mjs";
|
import "./tests/BCD.mjs";
|
||||||
|
import "./tests/Bech32.mjs";
|
||||||
import "./tests/BitwiseOp.mjs";
|
import "./tests/BitwiseOp.mjs";
|
||||||
import "./tests/BLAKE2b.mjs";
|
import "./tests/BLAKE2b.mjs";
|
||||||
import "./tests/BLAKE2s.mjs";
|
import "./tests/BLAKE2s.mjs";
|
||||||
|
|||||||
702
tests/operations/tests/Bech32.mjs
Normal file
702
tests/operations/tests/Bech32.mjs
Normal file
@@ -0,0 +1,702 @@
|
|||||||
|
/**
|
||||||
|
* Bech32 tests.
|
||||||
|
*
|
||||||
|
* Test vectors from official BIP specifications:
|
||||||
|
* BIP-0173: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
||||||
|
* BIP-0350: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
|
||||||
|
*
|
||||||
|
* AGE key test vectors from:
|
||||||
|
* https://asecuritysite.com/age/go_age5
|
||||||
|
*
|
||||||
|
* @author Medjedtxm
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
// ============= To Bech32 Tests =============
|
||||||
|
{
|
||||||
|
name: "To Bech32: empty input",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "bc1gmk9yu",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32: single byte",
|
||||||
|
input: "A",
|
||||||
|
expectedOutput: "bc1gyufle22",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32: Hello",
|
||||||
|
input: "Hello",
|
||||||
|
expectedOutput: "bc1fpjkcmr0gzsgcg",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32: custom HRP",
|
||||||
|
input: "test",
|
||||||
|
expectedOutput: "custom1w3jhxaq593qur",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["custom", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32: testnet HRP",
|
||||||
|
input: "data",
|
||||||
|
expectedOutput: "tb1v3shgcg3x07jr",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["tb", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32m: empty input",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "bc1a8xfp7",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32m", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32m: single byte",
|
||||||
|
input: "A",
|
||||||
|
expectedOutput: "bc1gyf4040g",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32m", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32m: Hello",
|
||||||
|
input: "Hello",
|
||||||
|
expectedOutput: "bc1fpjkcmr0a7qya2",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32m", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32: empty HRP error",
|
||||||
|
input: "test",
|
||||||
|
expectedOutput: "Human-Readable Part (HRP) cannot be empty.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= From Bech32 Tests (Raw output) =============
|
||||||
|
{
|
||||||
|
name: "From Bech32: decode single byte (Raw)",
|
||||||
|
input: "bc1gyufle22",
|
||||||
|
expectedOutput: "A",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: decode Hello (Raw)",
|
||||||
|
input: "bc1fpjkcmr0gzsgcg",
|
||||||
|
expectedOutput: "Hello",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: auto-detect Bech32 (Raw)",
|
||||||
|
input: "bc1fpjkcmr0gzsgcg",
|
||||||
|
expectedOutput: "Hello",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32m: decode Hello (Raw)",
|
||||||
|
input: "bc1fpjkcmr0a7qya2",
|
||||||
|
expectedOutput: "Hello",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: auto-detect Bech32m (Raw)",
|
||||||
|
input: "bc1fpjkcmr0a7qya2",
|
||||||
|
expectedOutput: "Hello",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: uppercase input (Raw)",
|
||||||
|
input: "BC1FPJKCMR0GZSGCG",
|
||||||
|
expectedOutput: "Hello",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: custom HRP (Raw)",
|
||||||
|
input: "custom1w3jhxaq593qur",
|
||||||
|
expectedOutput: "test",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: empty input",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: empty data part (Hex)",
|
||||||
|
input: "bc1gmk9yu",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= From Bech32 HRP Output Tests =============
|
||||||
|
{
|
||||||
|
name: "From Bech32: HRP: Hex output format",
|
||||||
|
input: "bc1fpjkcmr0gzsgcg",
|
||||||
|
expectedOutput: "bc: 48656c6c6f",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: JSON output format",
|
||||||
|
input: "bc1fpjkcmr0gzsgcg",
|
||||||
|
expectedOutput: "{\n \"hrp\": \"bc\",\n \"encoding\": \"Bech32\",\n \"data\": \"48656c6c6f\"\n}",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "JSON"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: Hex output format",
|
||||||
|
input: "bc1fpjkcmr0gzsgcg",
|
||||||
|
expectedOutput: "48656c6c6f",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= AGE Key Test Vectors =============
|
||||||
|
// From: https://asecuritysite.com/age/go_age5
|
||||||
|
{
|
||||||
|
name: "From Bech32: AGE public key 1 (HRP: Hex)",
|
||||||
|
input: "age1kk86t4lr4s9uwvnqjzp2e35rflvcpnjt33q99547ct23xzk0ssss3ma49j",
|
||||||
|
expectedOutput: "age: b58fa5d7e3ac0bc732609082acc6834fd980ce4b8c4052d2bec2d5130acf8421",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: AGE private key 1 (HRP: Hex)",
|
||||||
|
input: "AGE-SECRET-KEY-1Z5N23X54Y4E9NLMPNH6EZDQQX9V883TMKJ3ZJF5QXXMKNZ2RPFXQUQF74G",
|
||||||
|
expectedOutput: "age-secret-key-: 1526a89a95257259ff619df5913400315873c57bb4a229268031b76989430a4c",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: AGE public key 2 (HRP: Hex)",
|
||||||
|
input: "age1nwt7gkq7udvalagqn7l8a4jgju7wtenkg925pvuqvn7cfcry6u2qkae4ad",
|
||||||
|
expectedOutput: "age: 9b97e4581ee359dff5009fbe7ed648973ce5e676415540b38064fd84e064d714",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: AGE private key 2 (HRP: Hex)",
|
||||||
|
input: "AGE-SECRET-KEY-137M0YVE3CL6M8C4ET9L2KU67FPQHJZTW547QD5CK0R5A5T09ZGJSQGR9LX",
|
||||||
|
expectedOutput: "age-secret-key-: 8fb6f23331c7f5b3e2b9597eab735e484179096ea57c06d31678e9da2de51225",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: AGE public key 1 (JSON)",
|
||||||
|
input: "age1kk86t4lr4s9uwvnqjzp2e35rflvcpnjt33q99547ct23xzk0ssss3ma49j",
|
||||||
|
expectedOutput: "{\n \"hrp\": \"age\",\n \"encoding\": \"Bech32\",\n \"data\": \"b58fa5d7e3ac0bc732609082acc6834fd980ce4b8c4052d2bec2d5130acf8421\"\n}",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "JSON"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= Error Cases =============
|
||||||
|
{
|
||||||
|
name: "From Bech32: mixed case error",
|
||||||
|
input: "bc1FpjKcmr0gzsgcg",
|
||||||
|
expectedOutput: "Invalid Bech32 string: mixed case is not allowed. Use all uppercase or all lowercase.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: no separator error",
|
||||||
|
input: "noseparator",
|
||||||
|
expectedOutput: "Invalid Bech32 string: no separator '1' found.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: empty HRP error",
|
||||||
|
input: "1qqqqqqqqqqqqqqqq",
|
||||||
|
expectedOutput: "Invalid Bech32 string: Human-Readable Part (HRP) cannot be empty.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: invalid checksum",
|
||||||
|
input: "bc1fpjkcmr0gzsgcx",
|
||||||
|
expectedOutput: "Invalid Bech32/Bech32m string: checksum verification failed.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: data too short",
|
||||||
|
input: "bc1abc",
|
||||||
|
expectedOutput: "Invalid Bech32 string: data part is too short (minimum 6 characters for checksum).",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: wrong encoding specified",
|
||||||
|
input: "bc1fpjkcmr0gzsgcg",
|
||||||
|
expectedOutput: "Invalid Bech32m checksum.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= BIP-0173 Test Vectors (Bech32) =============
|
||||||
|
{
|
||||||
|
name: "From Bech32: BIP-0173 A12UEL5L (empty data)",
|
||||||
|
input: "A12UEL5L",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: BIP-0173 a12uel5l lowercase",
|
||||||
|
input: "a12uel5l",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: BIP-0173 long HRP with bio",
|
||||||
|
input: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: BIP-0173 abcdef with data",
|
||||||
|
input: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
|
||||||
|
expectedOutput: "abcdef: 00443214c74254b635cf84653a56d7c675be77df",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: BIP-0173 split HRP",
|
||||||
|
input: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
|
||||||
|
expectedOutput: "split: c5f38b70305f519bf66d85fb6cf03058f3dde463ecd7918f2dc743918f2d",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: BIP-0173 question mark HRP",
|
||||||
|
input: "?1ezyfcl",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= BIP-0350 Test Vectors (Bech32m) =============
|
||||||
|
{
|
||||||
|
name: "From Bech32m: BIP-0350 A1LQFN3A (empty data)",
|
||||||
|
input: "A1LQFN3A",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32m: BIP-0350 a1lqfn3a lowercase",
|
||||||
|
input: "a1lqfn3a",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32m: BIP-0350 long HRP",
|
||||||
|
input: "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32m: BIP-0350 abcdef with data",
|
||||||
|
input: "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx",
|
||||||
|
expectedOutput: "abcdef: ffbbcdeb38bdab49ca307b9ac5a928398a418820",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32m: BIP-0350 split HRP",
|
||||||
|
input: "split1checkupstagehandshakeupstreamerranterredcaperredlc445v",
|
||||||
|
expectedOutput: "split: c5f38b70305f519bf66d85fb6cf03058f3dde463ecd7918f2dc743918f2d",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "HRP: Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32m: BIP-0350 question mark HRP",
|
||||||
|
input: "?1v759aa",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= Bitcoin scriptPubKey Output Format Tests =============
|
||||||
|
// Test vectors from BIP-0173 and BIP-0350
|
||||||
|
{
|
||||||
|
name: "From Bech32: Bitcoin scriptPubKey v0 P2WPKH",
|
||||||
|
input: "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
|
||||||
|
expectedOutput: "0014751e76e8199196d454941c45d1b3a323f1433bd6",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Bitcoin scriptPubKey"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: Bitcoin scriptPubKey v0 P2WSH",
|
||||||
|
input: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
|
||||||
|
expectedOutput: "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Bitcoin scriptPubKey"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: Bitcoin scriptPubKey v1 Taproot (Bech32m)",
|
||||||
|
input: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0",
|
||||||
|
expectedOutput: "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Bitcoin scriptPubKey"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: Bitcoin scriptPubKey v16",
|
||||||
|
input: "BC1SW50QGDZ25J",
|
||||||
|
expectedOutput: "6002751e",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Bitcoin scriptPubKey"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Bech32: Bitcoin scriptPubKey v2",
|
||||||
|
input: "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
|
||||||
|
expectedOutput: "5210751e76e8199196d454941c45d1b3a323",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Bitcoin scriptPubKey"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= Bitcoin SegWit Encoding Tests =============
|
||||||
|
{
|
||||||
|
name: "To Bech32: Bitcoin SegWit v0 P2WPKH",
|
||||||
|
input: "751e76e8199196d454941c45d1b3a323f1433bd6",
|
||||||
|
expectedOutput: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32", "Hex", "Bitcoin SegWit", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32: Bitcoin SegWit v0 P2WSH testnet",
|
||||||
|
input: "1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
|
||||||
|
expectedOutput: "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["tb", "Bech32", "Hex", "Bitcoin SegWit", 0]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32m: Bitcoin Taproot v1",
|
||||||
|
input: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
|
||||||
|
expectedOutput: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32m", "Hex", "Bitcoin SegWit", 1]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Bech32m: Bitcoin SegWit v16",
|
||||||
|
input: "751e",
|
||||||
|
expectedOutput: "bc1sw50qgdz25j",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32m", "Hex", "Bitcoin SegWit", 16]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============= Round-trip Tests =============
|
||||||
|
{
|
||||||
|
name: "Bech32: encode then decode round-trip",
|
||||||
|
input: "The quick brown fox jumps over the lazy dog",
|
||||||
|
expectedOutput: "The quick brown fox jumps over the lazy dog",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["test", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bech32m: encode then decode round-trip",
|
||||||
|
input: "The quick brown fox jumps over the lazy dog",
|
||||||
|
expectedOutput: "The quick brown fox jumps over the lazy dog",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["test", "Bech32m", "Raw bytes", "Generic", 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32m", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bech32: binary data round-trip",
|
||||||
|
input: "0001020304050607",
|
||||||
|
expectedOutput: "0001020304050607",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Hex",
|
||||||
|
"args": ["Auto"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["bc", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Bech32", "Hex"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bech32: auto-detect round-trip",
|
||||||
|
input: "CyberChef Bech32 Test",
|
||||||
|
expectedOutput: "CyberChef Bech32 Test",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["cyberchef", "Bech32", "Raw bytes", "Generic", 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bech32m: auto-detect round-trip",
|
||||||
|
input: "CyberChef Bech32m Test",
|
||||||
|
expectedOutput: "CyberChef Bech32m Test",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Bech32",
|
||||||
|
"args": ["cyberchef", "Bech32m", "Raw bytes", "Generic", 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "From Bech32",
|
||||||
|
"args": ["Auto-detect", "Raw"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
@@ -322,8 +322,21 @@ TestRegister.addTests([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
expectedMatch: /^Invalid JPath expression: jsonPath: self is not defined:/
|
expectedMatch: /^Invalid JPath expression: Unexpected "{" at character 1/
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "JPath Expression: Script-based RCE",
|
||||||
|
input: "[{}]",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JPath expression",
|
||||||
|
"args": [
|
||||||
|
"$..[?(p=\"console.log(this.process.mainModule.require('child_process').execSync('id').toString())\";a=''[['constructor']][['constructor']](p);a())]",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
expectedMatch: /^Invalid JPath expression: jsonPath: Cannot read properties of {2}\(reading 'constructor'\): / },
|
||||||
{
|
{
|
||||||
name: "CSS selector",
|
name: "CSS selector",
|
||||||
input: '<div id="test">\n<p class="a">hello</p>\n<p>world</p>\n<p class="a">again</p>\n</div>',
|
input: '<div id="test">\n<p class="a">hello</p>\n<p>world</p>\n<p class="a">again</p>\n</div>',
|
||||||
|
|||||||
@@ -152,6 +152,17 @@ TestRegister.addTests([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "From Hexdump: xxd format, odd number of bytes",
|
||||||
|
input: "00000000: 6162 6364 65 abcde",
|
||||||
|
expectedOutput: "abcde",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hexdump",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "From Hexdump: Wireshark",
|
name: "From Hexdump: Wireshark",
|
||||||
input: `00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ........ ........
|
input: `00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ........ ........
|
||||||
|
|||||||
@@ -30,6 +30,28 @@ TestRegister.addTests([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "JA4 Fingerprint: TLS 1.3 with whitespace-only ALPN",
|
||||||
|
input: "1603010200010001fc0303ed338a18e711d670cdc472ff570a5b59f1ace12e5365918bf68bf845019147b6207e4437bfb062d98a4aeb753be8f09022a9dc9413d7694dad4db57fcdcf076e820024130213031301c02cc030c02bc02fcca9cca8c024c028c023c027009f009e006b006700ff0100018f0000001800160000136465762e636f6e74656e74677261622e6e6574000b000403000102000a00160014001d0017001e00190018010001010102010301040023000000100004000201200016000000170000000d002a0028040305030603080708080809080a080b080408050806040105010601030303010302040205020602002b00050403040303002d00020101003300260024001d00207af053336d5e2c1675aa4c6ce78de5e5fdbd296538113f051ea17ccb64289f22001500d2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
expectedOutput: "t13d181220_85036bcba153_d41ae481755e",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4 Fingerprint",
|
||||||
|
"args": ["Hex", "JA4"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JA4 Fingerprint: TLS 1.3 with ALPN containing a whitespace",
|
||||||
|
input: "1603010200010001fc0303273682a603be3f64dd025df4ad0f4d2d13043c3a233405a68bb29b865808749a20f4dfc40242b2fce38fae26c516ef9bef20a1b9349eba3c003780168d72471f5c0024130213031301c02cc030c02bc02fcca9cca8c024c028c023c027009f009e006b006700ff0100018f0000001800160000136465762e636f6e74656e74677261622e6e6574000b000403000102000a00160014001d0017001e0019001801000101010201030104002300000010000500030261200016000000170000000d002a0028040305030603080708080809080a080b080408050806040105010601030303010302040205020602002b00050403040303002d00020101003300260024001d0020f4dd1567bd858d3a9f1d88db1fee6a10ab0ea1aa6afe96ffb6a7c4d79dea4075001500d10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
expectedOutput: "t13d181260_85036bcba153_d41ae481755e",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4 Fingerprint",
|
||||||
|
"args": ["Hex", "JA4"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "JA4 Fingerprint: TLS 1.2",
|
name: "JA4 Fingerprint: TLS 1.2",
|
||||||
input: "1603010200010001fc0303ecb2691addb2bf6c599c7aaae23de5f42561cc04eb41029acc6fc050a16ac1d22046f8617b580ac9358e2aa44e306d52466bcc989c87c8ca64309f5faf50ba7b4d0022130113031302c02bc02fcca9cca8c02cc030c00ac009c013c014009c009d002f00350100019100000021001f00001c636f6e74696c652e73657276696365732e6d6f7a696c6c612e636f6d00170000ff01000100000a000e000c001d00170018001901000101000b00020100002300000010000e000c02683208687474702f312e310005000501000000000022000a000804030503060302030033006b0069001d00208909858fbeb6ed2f1248ba5b9e2978bead0e840110192c61daed0096798b184400170041044d183d91f5eed35791fa982464e3b0214aaa5f5d1b78616d9b9fbebc22d11f535b2f94c686143136aa795e6e5a875d6c08064ad5b76d44caad766e2483012748002b00050403040303000d0018001604030503060308040805080604010501060102030201002d00020101001c000240010015007a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
input: "1603010200010001fc0303ecb2691addb2bf6c599c7aaae23de5f42561cc04eb41029acc6fc050a16ac1d22046f8617b580ac9358e2aa44e306d52466bcc989c87c8ca64309f5faf50ba7b4d0022130113031302c02bc02fcca9cca8c02cc030c00ac009c013c014009c009d002f00350100019100000021001f00001c636f6e74696c652e73657276696365732e6d6f7a696c6c612e636f6d00170000ff01000100000a000e000c001d00170018001901000101000b00020100002300000010000e000c02683208687474702f312e310005000501000000000022000a000804030503060302030033006b0069001d00208909858fbeb6ed2f1248ba5b9e2978bead0e840110192c61daed0096798b184400170041044d183d91f5eed35791fa982464e3b0214aaa5f5d1b78616d9b9fbebc22d11f535b2f94c686143136aa795e6e5a875d6c08064ad5b76d44caad766e2483012748002b00050403040303000d0018001604030503060308040805080604010501060102030201002d00020101001c000240010015007a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
|||||||
Reference in New Issue
Block a user