mirror of
https://github.com/gchq/CyberChef
synced 2025-12-05 23:53:27 +00:00
Compare commits
125 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47f1f4c549 | ||
|
|
4b9d5a7685 | ||
|
|
fc7c6312e6 | ||
|
|
c7377da37f | ||
|
|
62dfa8f9dd | ||
|
|
7582abfa27 | ||
|
|
3f89a94df2 | ||
|
|
c5e880628a | ||
|
|
abd9024097 | ||
|
|
314b925ec9 | ||
|
|
d700d1d459 | ||
|
|
1a2207a045 | ||
|
|
2b85336c71 | ||
|
|
4b95ab2477 | ||
|
|
a0729304d1 | ||
|
|
dbdcb460e5 | ||
|
|
7588e50f9f | ||
|
|
40a4872f70 | ||
|
|
3b265322e0 | ||
|
|
0da30813da | ||
|
|
9829b419b9 | ||
|
|
19194a7eb0 | ||
|
|
c13997bdb1 | ||
|
|
35c2d437fa | ||
|
|
a54522f796 | ||
|
|
6c971876de | ||
|
|
d8be3dfa27 | ||
|
|
2b57f94ccd | ||
|
|
a3944fe1d1 | ||
|
|
cfc8a506f7 | ||
|
|
afcf46561a | ||
|
|
59b97bfccb | ||
|
|
20db43c0a8 | ||
|
|
dc7760247b | ||
|
|
56a8e02bb8 | ||
|
|
e532248701 | ||
|
|
73100896d4 | ||
|
|
a95be3b4c5 | ||
|
|
75c4e196fa | ||
|
|
0359a2eccf | ||
|
|
b118932451 | ||
|
|
fd77152343 | ||
|
|
5afecdb11a | ||
|
|
1916137c3c | ||
|
|
c3b89efd9a | ||
|
|
0f3cd72dd3 | ||
|
|
ed59f6a67a | ||
|
|
592745f380 | ||
|
|
10b0d91bdc | ||
|
|
dea2b3a2c0 | ||
|
|
df151eabf9 | ||
|
|
22a873c73e | ||
|
|
c6da0c623d | ||
|
|
44b566789f | ||
|
|
940f78a8a7 | ||
|
|
06c912be72 | ||
|
|
91639ee836 | ||
|
|
b78533bb02 | ||
|
|
a045c4ffec | ||
|
|
856ba1cf50 | ||
|
|
6510773789 | ||
|
|
7b280b3369 | ||
|
|
1618e112e1 | ||
|
|
c08a7dc6ce | ||
|
|
57731706b3 | ||
|
|
e9e926d054 | ||
|
|
5fa3d691cf | ||
|
|
d022dbc406 | ||
|
|
f96607c81b | ||
|
|
0bf7852e83 | ||
|
|
aaff2e687d | ||
|
|
77042abc23 | ||
|
|
ac18b74e66 | ||
|
|
76ba630d59 | ||
|
|
362755b22f | ||
|
|
6c63302d62 | ||
|
|
6ed9d4554a | ||
|
|
2dcd345349 | ||
|
|
81924b4a7e | ||
|
|
5a0c3a3b47 | ||
|
|
7b599fe7f7 | ||
|
|
4faaa07188 | ||
|
|
fa228b2571 | ||
|
|
9a216dc1bf | ||
|
|
0e0bafdeb6 | ||
|
|
5f0f037c46 | ||
|
|
6b01cf0c1a | ||
|
|
30f9286ce9 | ||
|
|
e9ff8707ed | ||
|
|
12082ba3cc | ||
|
|
6d3ca3f56c | ||
|
|
4262e6f6f7 | ||
|
|
1bc88728f0 | ||
|
|
7bb0649b27 | ||
|
|
e46a7448d9 | ||
|
|
d102e1b15c | ||
|
|
0a0217cb66 | ||
|
|
3faa9d3a1e | ||
|
|
d902c7e30c | ||
|
|
25fe7bba67 | ||
|
|
ca340cdd7b | ||
|
|
266fbab8fd | ||
|
|
e57fd2a408 | ||
|
|
3328ae8afd | ||
|
|
1caecf70a2 | ||
|
|
6e347742d9 | ||
|
|
2e2dcfa416 | ||
|
|
4bb10a34e1 | ||
|
|
1632e23c78 | ||
|
|
11fca557af | ||
|
|
1cf14c6f01 | ||
|
|
1bba10e7c2 | ||
|
|
8f3096af0a | ||
|
|
4a356476b1 | ||
|
|
e58744c63a | ||
|
|
b0c9a1850d | ||
|
|
764bd4b9ae | ||
|
|
bca4c34b3a | ||
|
|
2fab1028c5 | ||
|
|
dee2dc3777 | ||
|
|
d5b72548fc | ||
|
|
2c822314df | ||
|
|
822a4fab86 | ||
|
|
44a164ed28 | ||
|
|
1f09c03d48 |
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
build
|
||||
14
.github/workflows/pull_requests.yml
vendored
14
.github/workflows/pull_requests.yml
vendored
@@ -33,6 +33,20 @@ jobs:
|
||||
if: success()
|
||||
run: npx grunt prod
|
||||
|
||||
- name: Production Image Build
|
||||
if: success()
|
||||
id: build-image
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
with:
|
||||
# Not being uploaded to any registry, use a simple name to allow Buildah to build correctly.
|
||||
image: cyberchef
|
||||
containerfiles: ./Dockerfile
|
||||
platforms: linux/amd64
|
||||
oci: true
|
||||
# Webpack seems to use a lot of open files, increase the max open file limit to accomodate.
|
||||
extra-args: |
|
||||
--ulimit nofile=10000
|
||||
|
||||
- name: UI Tests
|
||||
if: success()
|
||||
run: |
|
||||
|
||||
46
.github/workflows/releases.yml
vendored
46
.github/workflows/releases.yml
vendored
@@ -6,9 +6,17 @@ on:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
REGISTRY_USER: ${{ github.actor }}
|
||||
REGISTRY_PASSWORD: ${{ github.token }}
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -19,7 +27,7 @@ jobs:
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
npm install
|
||||
npm ci
|
||||
npm run setheapsize
|
||||
|
||||
- name: Lint
|
||||
@@ -31,17 +39,38 @@ jobs:
|
||||
npm run testnodeconsumer
|
||||
|
||||
- name: Production Build
|
||||
if: success()
|
||||
run: npx grunt prod
|
||||
|
||||
- name: UI Tests
|
||||
if: success()
|
||||
run: |
|
||||
sudo apt-get install xvfb
|
||||
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||
|
||||
- name: Image Metadata
|
||||
id: image-metadata
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=semver,pattern={{major}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Production Image Build
|
||||
id: build-image
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
with:
|
||||
tags: ${{ steps.image-metadata.outputs.tags }}
|
||||
labels: ${{ steps.image-metadata.outputs.labels }}
|
||||
containerfiles: ./Dockerfile
|
||||
platforms: linux/amd64
|
||||
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: Upload Release Assets
|
||||
if: success()
|
||||
id: upload-release-assets
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
@@ -53,7 +82,14 @@ jobs:
|
||||
body: "See the [CHANGELOG](https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md) and [commit messages](https://github.com/gchq/CyberChef/commits/master) for details."
|
||||
|
||||
- name: Publish to NPM
|
||||
if: success()
|
||||
uses: JS-DevTools/npm-publish@v1
|
||||
with:
|
||||
token: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Publish to GHCR
|
||||
uses: redhat-actions/push-to-registry@v2
|
||||
with:
|
||||
tags: ${{ steps.build-image.outputs.tags }}
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ env.REGISTRY_USER }}
|
||||
password: ${{ env.REGISTRY_PASSWORD }}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@ npm-debug.log
|
||||
travis.log
|
||||
build
|
||||
.vscode
|
||||
.idea
|
||||
.*.swp
|
||||
src/core/config/modules/*
|
||||
src/core/config/OperationConfig.json
|
||||
|
||||
66
CHANGELOG.md
66
CHANGELOG.md
@@ -13,6 +13,36 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
## Details
|
||||
|
||||
### [10.8.0] - 2024-02-13
|
||||
- Add official Docker images [@AshCorr] | [#1699]
|
||||
|
||||
### [10.7.0] - 2024-02-09
|
||||
- Added 'File Tree' operation [@sw5678] | [#1667]
|
||||
- Added 'RISON' operation [@sg5506844] | [#1555]
|
||||
- Added 'MurmurHash3' operation [@AliceGrey] | [#1694]
|
||||
|
||||
### [10.6.0] - 2024-02-03
|
||||
- Updated 'Forensics Wiki' URLs to new domain [@a3957273] | [#1703]
|
||||
- Added 'LZNT1 Decompress' operation [@0xThiebaut] | [#1675]
|
||||
- Updated 'Regex Expression' UUID matcher [@cnotin] | [#1678]
|
||||
- Removed duplicate 'hover' message within baking info [@KevinSJ] | [#1541]
|
||||
|
||||
### [10.5.0] - 2023-07-14
|
||||
- Added GOST Encrypt, Decrypt, Sign, Verify, Key Wrap, and Key Unwrap operations [@n1474335] | [#592]
|
||||
|
||||
### [10.4.0] - 2023-03-24
|
||||
- Added 'Generate De Bruijn Sequence' operation [@gchq77703] | [#493]
|
||||
|
||||
### [10.3.0] - 2023-03-24
|
||||
- Added 'Argon2' and 'Argon2 compare' operations [@Xenonym] | [#661]
|
||||
|
||||
### [10.2.0] - 2023-03-23
|
||||
- Added 'Derive HKDF key' operation [@mikecat] | [#1528]
|
||||
|
||||
### [10.1.0] - 2023-03-23
|
||||
- Added 'Levenshtein Distance' operation [@mikecat] | [#1498]
|
||||
- Added 'Swap case' operation [@mikecat] | [#1499]
|
||||
|
||||
## [10.0.0] - 2023-03-22
|
||||
- [Full details explained here](https://github.com/gchq/CyberChef/wiki/Character-encoding,-EOL-separators,-and-editor-features)
|
||||
- Status bars added to the Input and Output [@n1474335] | [#1405]
|
||||
@@ -356,8 +386,14 @@ All major and minor version changes will be documented in this file. Details of
|
||||
## [4.0.0] - 2016-11-28
|
||||
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
||||
|
||||
|
||||
|
||||
[10.8.0]: https://github.com/gchq/CyberChef/releases/tag/v10.7.0
|
||||
[10.7.0]: https://github.com/gchq/CyberChef/releases/tag/v10.7.0
|
||||
[10.6.0]: https://github.com/gchq/CyberChef/releases/tag/v10.6.0
|
||||
[10.5.0]: https://github.com/gchq/CyberChef/releases/tag/v10.5.0
|
||||
[10.4.0]: https://github.com/gchq/CyberChef/releases/tag/v10.4.0
|
||||
[10.3.0]: https://github.com/gchq/CyberChef/releases/tag/v10.3.0
|
||||
[10.2.0]: https://github.com/gchq/CyberChef/releases/tag/v10.2.0
|
||||
[10.1.0]: https://github.com/gchq/CyberChef/releases/tag/v10.1.0
|
||||
[10.0.0]: https://github.com/gchq/CyberChef/releases/tag/v10.0.0
|
||||
[9.55.0]: https://github.com/gchq/CyberChef/releases/tag/v9.55.0
|
||||
[9.54.0]: https://github.com/gchq/CyberChef/releases/tag/v9.54.0
|
||||
@@ -505,6 +541,17 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[@valdelaseras]: https://github.com/valdelaseras
|
||||
[@brun0ne]: https://github.com/brun0ne
|
||||
[@joostrijneveld]: https://github.com/joostrijneveld
|
||||
[@Xenonym]: https://github.com/Xenonym
|
||||
[@gchq77703]: https://github.com/gchq77703
|
||||
[@a3957273]: https://github.com/a3957273
|
||||
[@0xThiebaut]: https://github.com/0xThiebaut
|
||||
[@cnotin]: https://github.com/cnotin
|
||||
[@KevinSJ]: https://github.com/KevinSJ
|
||||
[@sw5678]: https://github.com/sw5678
|
||||
[@sg5506844]: https://github.com/sg5506844
|
||||
[@AliceGrey]: https://github.com/AliceGrey
|
||||
[@AshCorr]: https://github.com/AshCorr
|
||||
|
||||
|
||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
|
||||
@@ -617,4 +664,17 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[#1466]: https://github.com/gchq/CyberChef/pull/1466
|
||||
[#1456]: https://github.com/gchq/CyberChef/pull/1456
|
||||
[#1450]: https://github.com/gchq/CyberChef/pull/1450
|
||||
|
||||
[#1498]: https://github.com/gchq/CyberChef/pull/1498
|
||||
[#1499]: https://github.com/gchq/CyberChef/pull/1499
|
||||
[#1528]: https://github.com/gchq/CyberChef/pull/1528
|
||||
[#661]: https://github.com/gchq/CyberChef/pull/661
|
||||
[#493]: https://github.com/gchq/CyberChef/pull/493
|
||||
[#592]: https://github.com/gchq/CyberChef/issues/592
|
||||
[#1703]: https://github.com/gchq/CyberChef/issues/1703
|
||||
[#1675]: https://github.com/gchq/CyberChef/issues/1675
|
||||
[#1678]: https://github.com/gchq/CyberChef/issues/1678
|
||||
[#1541]: https://github.com/gchq/CyberChef/issues/1541
|
||||
[#1667]: https://github.com/gchq/CyberChef/issues/1667
|
||||
[#1555]: https://github.com/gchq/CyberChef/issues/1555
|
||||
[#1694]: https://github.com/gchq/CyberChef/issues/1694
|
||||
[#1699]: https://github.com/gchq/CyberChef/issues/1694
|
||||
|
||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
FROM node:18-alpine AS build
|
||||
|
||||
COPY . .
|
||||
RUN npm ci
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:1.25-alpine3.18 AS cyberchef
|
||||
|
||||
COPY --from=build ./build/prod /usr/share/nginx/html/
|
||||
@@ -197,6 +197,7 @@ module.exports = function (grunt) {
|
||||
},
|
||||
webpack: {
|
||||
options: webpackConfig,
|
||||
myConfig: webpackConfig,
|
||||
web: webpackProdConf(),
|
||||
},
|
||||
"webpack-dev-server": {
|
||||
|
||||
20
README.md
20
README.md
@@ -20,6 +20,22 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur
|
||||
|
||||
[A live demo can be found here][1] - have fun!
|
||||
|
||||
## Containers
|
||||
|
||||
If you would like to try out CyberChef locally you can either build it yourself:
|
||||
|
||||
```bash
|
||||
docker build --tag cyberchef --ulimit nofile=10000 .
|
||||
docker run -it -p 8080:80 cyberchef
|
||||
```
|
||||
|
||||
Or you can use our image directly:
|
||||
|
||||
```bash
|
||||
docker run -it -p 8080:80 ghcr.io/gchq/cyberchef:latest
|
||||
```
|
||||
|
||||
This image is built and published through our [GitHub Workflows](.github/workflows/releases.yml)
|
||||
|
||||
## How it works
|
||||
|
||||
@@ -89,14 +105,14 @@ CyberChef is built to support
|
||||
|
||||
## Node.js support
|
||||
|
||||
CyberChef is built to fully support Node.js `v16`. For more information, see the Node API page in the project [wiki pages](https://github.com/gchq/CyberChef/wiki)
|
||||
CyberChef is built to fully support Node.js `v16`. For more information, see the ["Node API" wiki page](https://github.com/gchq/CyberChef/wiki/Node-API)
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributing a new operation to CyberChef is super easy! The quickstart script will walk you through the process. If you can write basic JavaScript, you can write a CyberChef operation.
|
||||
|
||||
An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki).
|
||||
An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the ["Contributing" wiki page](https://github.com/gchq/CyberChef/wiki/Contributing).
|
||||
|
||||
- Push your changes to your fork.
|
||||
- Submit a pull request. If you are doing this for the first time, you will be prompted to sign the [GCHQ Contributor Licence Agreement](https://cla-assistant.io/gchq/CyberChef) via the CLA assistant on the pull request. This will also ask whether you are happy for GCHQ to contact you about a token of thanks for your contribution, or about job opportunities at GCHQ.
|
||||
|
||||
15054
package-lock.json
generated
15054
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
120
package.json
120
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "10.0.1",
|
||||
"version": "10.8.0",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@@ -39,54 +39,55 @@
|
||||
"node >= 16"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.20.0",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@codemirror/commands": "^6.2.1",
|
||||
"@codemirror/language": "^6.6.0",
|
||||
"@codemirror/search": "^6.2.3",
|
||||
"@codemirror/state": "^6.2.0",
|
||||
"@codemirror/view": "^6.9.2",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"babel-loader": "^9.1.2",
|
||||
"@babel/core": "^7.23.9",
|
||||
"@babel/eslint-parser": "^7.23.10",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.23.3",
|
||||
"@babel/plugin-transform-runtime": "^7.23.9",
|
||||
"@babel/preset-env": "^7.23.9",
|
||||
"@babel/runtime": "^7.23.9",
|
||||
"@codemirror/commands": "^6.3.3",
|
||||
"@codemirror/language": "^6.10.1",
|
||||
"@codemirror/search": "^6.5.5",
|
||||
"@codemirror/state": "^6.4.0",
|
||||
"@codemirror/view": "^6.23.1",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"chromedriver": "^110.0.0",
|
||||
"base64-loader": "^1.0.0",
|
||||
"chromedriver": "^121.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
"colors": "^1.4.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"core-js": "^3.29.0",
|
||||
"css-loader": "6.7.3",
|
||||
"eslint": "^8.35.0",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"core-js": "^3.35.1",
|
||||
"css-loader": "6.10.0",
|
||||
"eslint": "^8.56.0",
|
||||
"grunt": "^1.6.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-concurrent": "^3.0.0",
|
||||
"grunt-contrib-clean": "~2.0.1",
|
||||
"grunt-contrib-connect": "^3.0.0",
|
||||
"grunt-contrib-connect": "^4.0.0",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"grunt-eslint": "^24.0.1",
|
||||
"grunt-eslint": "^24.3.0",
|
||||
"grunt-exec": "~3.0.0",
|
||||
"grunt-webpack": "^5.0.0",
|
||||
"grunt-zip": "^0.20.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"imports-loader": "^4.0.1",
|
||||
"mini-css-extract-plugin": "2.7.3",
|
||||
"grunt-webpack": "^6.0.0",
|
||||
"grunt-zip": "^1.0.0",
|
||||
"html-webpack-plugin": "^5.6.0",
|
||||
"imports-loader": "^5.0.0",
|
||||
"mini-css-extract-plugin": "2.8.0",
|
||||
"modify-source-webpack-plugin": "^3.0.0",
|
||||
"nightwatch": "^2.6.16",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss-css-variables": "^0.18.0",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-loader": "^7.0.2",
|
||||
"nightwatch": "^3.4.0",
|
||||
"postcss": "^8.4.33",
|
||||
"postcss-css-variables": "^0.19.0",
|
||||
"postcss-import": "^16.0.0",
|
||||
"postcss-loader": "^8.1.0",
|
||||
"prompt": "^1.3.0",
|
||||
"sitemap": "^7.1.1",
|
||||
"terser": "^5.16.6",
|
||||
"webpack": "^5.76.0",
|
||||
"webpack-bundle-analyzer": "^4.8.0",
|
||||
"webpack-dev-server": "4.11.1",
|
||||
"terser": "^5.27.0",
|
||||
"webpack": "^5.90.1",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
@@ -94,10 +95,12 @@
|
||||
"@astronautlabs/amf": "^0.0.6",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@blu3r4y/lzma": "^2.3.3",
|
||||
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
||||
"argon2-browser": "^1.18.0",
|
||||
"arrive": "^2.4.1",
|
||||
"avsc": "^5.7.7",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bignumber.js": "^9.1.1",
|
||||
"bignumber.js": "^9.1.2",
|
||||
"blakejs": "^1.2.1",
|
||||
"bootstrap": "4.6.2",
|
||||
"bootstrap-colorpicker": "^3.4.0",
|
||||
@@ -105,45 +108,45 @@
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"bson": "^4.7.2",
|
||||
"buffer": "^6.0.3",
|
||||
"cbor": "8.1.0",
|
||||
"cbor": "9.0.2",
|
||||
"chi-squared": "^1.1.0",
|
||||
"codepage": "^1.15.0",
|
||||
"crypto-api": "^0.8.5",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"crypto-js": "^4.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"ctph.js": "0.0.5",
|
||||
"d3": "7.8.2",
|
||||
"d3": "7.8.5",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"diff": "^5.1.0",
|
||||
"es6-promisify": "^7.0.0",
|
||||
"escodegen": "^2.0.0",
|
||||
"escodegen": "^2.1.0",
|
||||
"esprima": "^4.0.1",
|
||||
"exif-parser": "^0.1.12",
|
||||
"file-saver": "^2.0.5",
|
||||
"flat": "^5.0.2",
|
||||
"flat": "^6.0.1",
|
||||
"geodesy": "1.1.3",
|
||||
"highlight.js": "^11.7.0",
|
||||
"highlight.js": "^11.9.0",
|
||||
"jimp": "^0.16.13",
|
||||
"jquery": "3.6.4",
|
||||
"jquery": "3.7.1",
|
||||
"js-crc": "^0.2.0",
|
||||
"js-sha3": "^0.8.0",
|
||||
"js-sha3": "^0.9.3",
|
||||
"jsesc": "^3.0.2",
|
||||
"json5": "^2.2.3",
|
||||
"jsonpath-plus": "^7.2.0",
|
||||
"jsonpath-plus": "^8.0.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jsqr": "^1.4.0",
|
||||
"jsrsasign": "^10.6.1",
|
||||
"jsrsasign": "^11.1.0",
|
||||
"kbpgp": "2.1.15",
|
||||
"libbzip2-wasm": "0.0.4",
|
||||
"libyara-wasm": "^1.2.1",
|
||||
"lodash": "^4.17.21",
|
||||
"loglevel": "^1.8.1",
|
||||
"loglevel": "^1.9.1",
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"lz-string": "^1.5.0",
|
||||
"lz4js": "^0.2.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"moment-timezone": "^0.5.41",
|
||||
"markdown-it": "^14.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.44",
|
||||
"ngeohash": "^0.6.3",
|
||||
"node-forge": "^1.3.1",
|
||||
"node-md6": "^0.1.0",
|
||||
@@ -155,22 +158,23 @@
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^7.2.2",
|
||||
"protobufjs": "^7.2.6",
|
||||
"qr-image": "^3.2.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"reflect-metadata": "^0.2.1",
|
||||
"rison": "^0.1.1",
|
||||
"scryptsy": "^2.1.0",
|
||||
"snackbarjs": "^1.1.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"sortablejs": "^1.15.2",
|
||||
"split.js": "^1.6.5",
|
||||
"ssdeep.js": "0.0.3",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"tesseract.js": "3.0.3",
|
||||
"ua-parser-js": "^1.0.34",
|
||||
"tesseract.js": "5.0.4",
|
||||
"ua-parser-js": "^1.0.37",
|
||||
"unorm": "^1.6.0",
|
||||
"utf8": "^3.0.0",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"xmldom": "^0.6.0",
|
||||
"xpath": "0.0.32",
|
||||
"xpath": "0.0.34",
|
||||
"xregexp": "^5.1.1",
|
||||
"zlibjs": "^0.3.1"
|
||||
},
|
||||
@@ -178,8 +182,8 @@
|
||||
"start": "npx grunt dev",
|
||||
"build": "npx grunt prod",
|
||||
"node": "npx grunt node",
|
||||
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings src/node/repl.mjs",
|
||||
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider tests/operations/index.mjs",
|
||||
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-experimental-fetch --no-warnings src/node/repl.mjs",
|
||||
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch --trace-uncaught tests/operations/index.mjs",
|
||||
"testnodeconsumer": "npx grunt testnodeconsumer",
|
||||
"testui": "npx grunt testui",
|
||||
"testuidev": "npx nightwatch --env=dev",
|
||||
|
||||
@@ -892,6 +892,23 @@ class Utils {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a string to it's title case equivalent.
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns string
|
||||
*
|
||||
* @example
|
||||
* // return "A Tiny String"
|
||||
* Utils.toTitleCase("a tIny String");
|
||||
*/
|
||||
static toTitleCase(str) {
|
||||
return str.replace(/\w\S*/g, function(txt) {
|
||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a URI fragment (#) or query (?) using a minimal amount of percent-encoding.
|
||||
*
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"To Base64",
|
||||
"From Base64",
|
||||
"Show Base64 offsets",
|
||||
"To Base92",
|
||||
"From Base92",
|
||||
"To Base85",
|
||||
"From Base85",
|
||||
"To Base",
|
||||
@@ -67,7 +69,9 @@
|
||||
"JSON to CSV",
|
||||
"Avro to JSON",
|
||||
"CBOR Encode",
|
||||
"CBOR Decode"
|
||||
"CBOR Decode",
|
||||
"Rison Encode",
|
||||
"Rison Decode"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -91,6 +95,12 @@
|
||||
"Rabbit",
|
||||
"SM4 Encrypt",
|
||||
"SM4 Decrypt",
|
||||
"GOST Encrypt",
|
||||
"GOST Decrypt",
|
||||
"GOST Sign",
|
||||
"GOST Verify",
|
||||
"GOST Key Wrap",
|
||||
"GOST Key Unwrap",
|
||||
"ROT13",
|
||||
"ROT13 Brute Force",
|
||||
"ROT47",
|
||||
@@ -121,6 +131,7 @@
|
||||
"Substitute",
|
||||
"Derive PBKDF2 key",
|
||||
"Derive EVP key",
|
||||
"Derive HKDF key",
|
||||
"Bcrypt",
|
||||
"Scrypt",
|
||||
"JWT Sign",
|
||||
@@ -247,6 +258,7 @@
|
||||
"Remove null bytes",
|
||||
"To Upper case",
|
||||
"To Lower case",
|
||||
"Swap case",
|
||||
"To Case Insensitive Regex",
|
||||
"From Case Insensitive Regex",
|
||||
"Add line numbers",
|
||||
@@ -271,6 +283,7 @@
|
||||
"Fuzzy Match",
|
||||
"Offset checker",
|
||||
"Hamming Distance",
|
||||
"Levenshtein Distance",
|
||||
"Convert distance",
|
||||
"Convert area",
|
||||
"Convert mass",
|
||||
@@ -285,7 +298,8 @@
|
||||
"Escape string",
|
||||
"Unescape string",
|
||||
"Pseudo-Random Number Generator",
|
||||
"Sleep"
|
||||
"Sleep",
|
||||
"File Tree"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -342,7 +356,8 @@
|
||||
"LZMA Decompress",
|
||||
"LZMA Compress",
|
||||
"LZ4 Decompress",
|
||||
"LZ4 Compress"
|
||||
"LZ4 Compress",
|
||||
"LZNT1 Decompress"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -359,6 +374,7 @@
|
||||
"SHA2",
|
||||
"SHA3",
|
||||
"SM3",
|
||||
"MurmurHash3",
|
||||
"Keccak",
|
||||
"Shake",
|
||||
"RIPEMD",
|
||||
@@ -367,7 +383,7 @@
|
||||
"Snefru",
|
||||
"BLAKE2b",
|
||||
"BLAKE2s",
|
||||
"GOST hash",
|
||||
"GOST Hash",
|
||||
"Streebog",
|
||||
"SSDEEP",
|
||||
"CTPH",
|
||||
@@ -378,6 +394,8 @@
|
||||
"Bcrypt",
|
||||
"Bcrypt compare",
|
||||
"Bcrypt parse",
|
||||
"Argon2",
|
||||
"Argon2 compare",
|
||||
"Scrypt",
|
||||
"NT Hash",
|
||||
"LM Hash",
|
||||
@@ -485,6 +503,7 @@
|
||||
"P-list Viewer",
|
||||
"Disassemble x86",
|
||||
"Pseudo-Random Number Generator",
|
||||
"Generate De Bruijn Sequence",
|
||||
"Generate UUID",
|
||||
"Generate TOTP",
|
||||
"Generate HOTP",
|
||||
|
||||
44
src/core/lib/Base92.mjs
Normal file
44
src/core/lib/Base92.mjs
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Base92 resources.
|
||||
*
|
||||
* @author sg5506844 [sg5506844@gmail.com]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Base92 alphabet char
|
||||
*
|
||||
* @param {number} val
|
||||
* @returns {number}
|
||||
*/
|
||||
export function base92Chr(val) {
|
||||
if (val < 0 || val >= 91) {
|
||||
throw new OperationError("Invalid value");
|
||||
}
|
||||
if (val === 0)
|
||||
return "!".charCodeAt(0);
|
||||
else if (val <= 61)
|
||||
return "#".charCodeAt(0) + val - 1;
|
||||
else
|
||||
return "a".charCodeAt(0) + val - 62;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base92 alphabet ord
|
||||
*
|
||||
* @param {string} val
|
||||
* @returns {number}
|
||||
*/
|
||||
export function base92Ord(val) {
|
||||
if (val === "!")
|
||||
return 0;
|
||||
else if ("#" <= val && val <= "_")
|
||||
return val.charCodeAt(0) - "#".charCodeAt(0) + 1;
|
||||
else if ("a" <= val && val <= "}")
|
||||
return val.charCodeAt(0) - "a".charCodeAt(0) + 62;
|
||||
throw new OperationError(`${val} is not a base92 character`);
|
||||
}
|
||||
|
||||
88
src/core/lib/LZNT1.mjs
Normal file
88
src/core/lib/LZNT1.mjs
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
*
|
||||
* LZNT1 Decompress.
|
||||
*
|
||||
* @author 0xThiebaut [thiebaut.dev]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* https://github.com/Velocidex/go-ntfs/blob/master/parser%2Flznt1.go
|
||||
*/
|
||||
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
const COMPRESSED_MASK = 1 << 15,
|
||||
SIZE_MASK = (1 << 12) - 1;
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @returns {number}
|
||||
*/
|
||||
function getDisplacement(offset) {
|
||||
let result = 0;
|
||||
while (offset >= 0x10) {
|
||||
offset >>= 1;
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} compressed
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
export function decompress(compressed) {
|
||||
const decompressed = Array();
|
||||
let coffset = 0;
|
||||
|
||||
while (coffset + 2 <= compressed.length) {
|
||||
const doffset = decompressed.length;
|
||||
|
||||
const blockHeader = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little");
|
||||
coffset += 2;
|
||||
|
||||
const size = blockHeader & SIZE_MASK;
|
||||
const blockEnd = coffset + size + 1;
|
||||
|
||||
if (size === 0) {
|
||||
break;
|
||||
} else if (compressed.length < coffset + size) {
|
||||
throw new OperationError("Malformed LZNT1 stream: Block too small! Has the stream been truncated?");
|
||||
}
|
||||
|
||||
if ((blockHeader & COMPRESSED_MASK) !== 0) {
|
||||
while (coffset < blockEnd) {
|
||||
let header = compressed[coffset++];
|
||||
|
||||
for (let i = 0; i < 8 && coffset < blockEnd; i++) {
|
||||
if ((header & 1) === 0) {
|
||||
decompressed.push(compressed[coffset++]);
|
||||
} else {
|
||||
const pointer = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little");
|
||||
coffset += 2;
|
||||
|
||||
const displacement = getDisplacement(decompressed.length - doffset - 1);
|
||||
const symbolOffset = (pointer >> (12 - displacement)) + 1;
|
||||
const symbolLength = (pointer & (0xFFF >> displacement)) + 2;
|
||||
const shiftOffset = decompressed.length - symbolOffset;
|
||||
|
||||
for (let shiftDelta = 0; shiftDelta < symbolLength + 1; shiftDelta++) {
|
||||
const shift = shiftOffset + shiftDelta;
|
||||
if (shift < 0 || decompressed.length <= shift) {
|
||||
throw new OperationError("Malformed LZNT1 stream: Invalid shift!");
|
||||
}
|
||||
decompressed.push(decompressed[shift]);
|
||||
}
|
||||
}
|
||||
header >>= 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decompressed.push(...compressed.slice(coffset, coffset + size + 1));
|
||||
coffset += size + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return decompressed;
|
||||
}
|
||||
117
src/core/operations/Argon2.mjs
Normal file
117
src/core/operations/Argon2.mjs
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @author Tan Zhen Yong [tzy@beyondthesprawl.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import argon2 from "argon2-browser";
|
||||
|
||||
/**
|
||||
* Argon2 operation
|
||||
*/
|
||||
class Argon2 extends Operation {
|
||||
|
||||
/**
|
||||
* Argon2 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Argon2";
|
||||
this.module = "Crypto";
|
||||
this.description = "Argon2 is a key derivation function that was selected as the winner of the Password Hashing Competition in July 2015. It was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich from the University of Luxembourg.<br><br>Enter the password in the input to generate its hash.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Argon2";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Salt",
|
||||
"type": "toggleString",
|
||||
"value": "somesalt",
|
||||
"toggleValues": ["UTF8", "Hex", "Base64", "Latin1"]
|
||||
},
|
||||
{
|
||||
"name": "Iterations",
|
||||
"type": "number",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"name": "Memory (KiB)",
|
||||
"type": "number",
|
||||
"value": 4096
|
||||
},
|
||||
{
|
||||
"name": "Parallelism",
|
||||
"type": "number",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"name": "Hash length (bytes)",
|
||||
"type": "number",
|
||||
"value": 32
|
||||
},
|
||||
{
|
||||
"name": "Type",
|
||||
"type": "option",
|
||||
"value": ["Argon2i", "Argon2d", "Argon2id"],
|
||||
"defaultIndex": 0
|
||||
},
|
||||
{
|
||||
"name": "Output format",
|
||||
"type": "option",
|
||||
"value": ["Encoded hash", "Hex hash", "Raw hash"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const argon2Types = {
|
||||
"Argon2i": argon2.ArgonType.Argon2i,
|
||||
"Argon2d": argon2.ArgonType.Argon2d,
|
||||
"Argon2id": argon2.ArgonType.Argon2id
|
||||
};
|
||||
|
||||
const salt = Utils.convertToByteString(args[0].string || "", args[0].option),
|
||||
time = args[1],
|
||||
mem = args[2],
|
||||
parallelism = args[3],
|
||||
hashLen = args[4],
|
||||
type = argon2Types[args[5]],
|
||||
outFormat = args[6];
|
||||
|
||||
try {
|
||||
const result = await argon2.hash({
|
||||
pass: input,
|
||||
salt,
|
||||
time,
|
||||
mem,
|
||||
parallelism,
|
||||
hashLen,
|
||||
type,
|
||||
});
|
||||
|
||||
switch (outFormat) {
|
||||
case "Hex hash":
|
||||
return result.hashHex;
|
||||
case "Raw hash":
|
||||
return Utils.arrayBufferToStr(result.hash);
|
||||
case "Encoded hash":
|
||||
default:
|
||||
return result.encoded;
|
||||
}
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Argon2;
|
||||
58
src/core/operations/Argon2Compare.mjs
Normal file
58
src/core/operations/Argon2Compare.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @author Tan Zhen Yong [tzy@beyondthesprawl.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import argon2 from "argon2-browser";
|
||||
|
||||
/**
|
||||
* Argon2 compare operation
|
||||
*/
|
||||
class Argon2Compare extends Operation {
|
||||
|
||||
/**
|
||||
* Argon2Compare constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Argon2 compare";
|
||||
this.module = "Crypto";
|
||||
this.description = "Tests whether the input matches the given Argon2 hash. To test multiple possible passwords, use the 'Fork' operation.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Argon2";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Encoded hash",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const encoded = args[0];
|
||||
|
||||
try {
|
||||
await argon2.verify({
|
||||
pass: input,
|
||||
encoded
|
||||
});
|
||||
|
||||
return `Match: ${input}`;
|
||||
} catch (err) {
|
||||
return "No match";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Argon2Compare;
|
||||
@@ -21,7 +21,7 @@ class CTPH extends Operation {
|
||||
this.name = "CTPH";
|
||||
this.module = "Crypto";
|
||||
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
|
||||
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing";
|
||||
this.infoURL = "https://forensics.wiki/context_triggered_piecewise_hashing/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
|
||||
@@ -24,7 +24,7 @@ class CompareCTPHHashes extends Operation {
|
||||
this.name = "Compare CTPH hashes";
|
||||
this.module = "Crypto";
|
||||
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing";
|
||||
this.infoURL = "https://forensics.wiki/context_triggered_piecewise_hashing/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "Number";
|
||||
this.args = [
|
||||
|
||||
@@ -24,7 +24,7 @@ class CompareSSDEEPHashes extends Operation {
|
||||
this.name = "Compare SSDEEP hashes";
|
||||
this.module = "Crypto";
|
||||
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Ssdeep";
|
||||
this.infoURL = "https://forensics.wiki/ssdeep/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "Number";
|
||||
this.args = [
|
||||
|
||||
138
src/core/operations/DeriveHKDFKey.mjs
Normal file
138
src/core/operations/DeriveHKDFKey.mjs
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @author mikecat
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import CryptoApi from "crypto-api/src/crypto-api.mjs";
|
||||
|
||||
/**
|
||||
* Derive HKDF Key operation
|
||||
*/
|
||||
class DeriveHKDFKey extends Operation {
|
||||
|
||||
/**
|
||||
* DeriveHKDFKey constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Derive HKDF key";
|
||||
this.module = "Crypto";
|
||||
this.description = "A simple Hashed Message Authenticaton Code (HMAC)-based key derivation function (HKDF), defined in RFC5869.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/HKDF";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Salt",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
},
|
||||
{
|
||||
"name": "Info",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
},
|
||||
{
|
||||
"name": "Hashing function",
|
||||
"type": "option",
|
||||
"value": [
|
||||
"MD2",
|
||||
"MD4",
|
||||
"MD5",
|
||||
"SHA0",
|
||||
"SHA1",
|
||||
"SHA224",
|
||||
"SHA256",
|
||||
"SHA384",
|
||||
"SHA512",
|
||||
"SHA512/224",
|
||||
"SHA512/256",
|
||||
"RIPEMD128",
|
||||
"RIPEMD160",
|
||||
"RIPEMD256",
|
||||
"RIPEMD320",
|
||||
"HAS160",
|
||||
"Whirlpool",
|
||||
"Whirlpool-0",
|
||||
"Whirlpool-T",
|
||||
"Snefru"
|
||||
],
|
||||
"defaultIndex": 6
|
||||
},
|
||||
{
|
||||
"name": "Extract mode",
|
||||
"type": "argSelector",
|
||||
"value": [
|
||||
{
|
||||
"name": "with salt",
|
||||
"on": [0]
|
||||
},
|
||||
{
|
||||
"name": "no salt",
|
||||
"off": [0]
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"off": [0]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "L (number of output octets)",
|
||||
"type": "number",
|
||||
"value": 16,
|
||||
"min": 0
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
const argSalt = Utils.convertToByteString(args[0].string || "", args[0].option),
|
||||
info = Utils.convertToByteString(args[1].string || "", args[1].option),
|
||||
hashFunc = args[2].toLowerCase(),
|
||||
extractMode = args[3],
|
||||
L = args[4],
|
||||
IKM = Utils.arrayBufferToStr(input, false),
|
||||
hasher = CryptoApi.getHasher(hashFunc),
|
||||
HashLen = hasher.finalize().length;
|
||||
|
||||
if (L < 0) {
|
||||
throw new OperationError("L must be non-negative");
|
||||
}
|
||||
if (L > 255 * HashLen) {
|
||||
throw new OperationError("L too large (maximum length for " + args[2] + " is " + (255 * HashLen) + ")");
|
||||
}
|
||||
|
||||
const hmacHash = function(key, data) {
|
||||
hasher.reset();
|
||||
const mac = CryptoApi.getHmac(key, hasher);
|
||||
mac.update(data);
|
||||
return mac.finalize();
|
||||
};
|
||||
const salt = extractMode === "with salt" ? argSalt : "\0".repeat(HashLen);
|
||||
const PRK = extractMode === "skip" ? IKM : hmacHash(salt, IKM);
|
||||
let T = "";
|
||||
let result = "";
|
||||
for (let i = 1; i <= 255 && result.length < L; i++) {
|
||||
const TNext = hmacHash(PRK, T + info + String.fromCharCode(i));
|
||||
result += TNext;
|
||||
T = TNext;
|
||||
}
|
||||
return CryptoApi.encoder.toHex(result.substring(0, L));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DeriveHKDFKey;
|
||||
@@ -39,7 +39,7 @@ class ExtractFiles extends Operation {
|
||||
${supportedExts.join("</li><li>")}
|
||||
</li>
|
||||
</ul>Minimum File Size can be used to prune small false positives.`;
|
||||
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=File_Carving";
|
||||
this.infoURL = "https://forensics.wiki/file_carving";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "List<File>";
|
||||
this.presentType = "html";
|
||||
|
||||
@@ -66,7 +66,7 @@ class ExtractIPAddresses extends Operation {
|
||||
run(input, args) {
|
||||
const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args,
|
||||
ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?",
|
||||
ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})((([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})";
|
||||
ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})(([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}";
|
||||
let ips = "";
|
||||
|
||||
if (includeIpv4 && includeIpv6) {
|
||||
|
||||
93
src/core/operations/FileTree.mjs
Normal file
93
src/core/operations/FileTree.mjs
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @author sw5678
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||
|
||||
/**
|
||||
* Unique operation
|
||||
*/
|
||||
class FileTree extends Operation {
|
||||
|
||||
/**
|
||||
* Unique constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "File Tree";
|
||||
this.module = "Default";
|
||||
this.description = "Creates file tree from list of file paths (similar to the tree command in Linux)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "File Path Delimiter",
|
||||
type: "binaryString",
|
||||
value: "/"
|
||||
},
|
||||
{
|
||||
name: "Delimiter",
|
||||
type: "option",
|
||||
value: INPUT_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
|
||||
// Set up arrow and pipe for nice output display
|
||||
const ARROW = "|---";
|
||||
const PIPE = "| ";
|
||||
|
||||
// Get args from input
|
||||
const fileDelim = args[0];
|
||||
const entryDelim = Utils.charRep(args[1]);
|
||||
|
||||
// Store path to print
|
||||
const completedList = [];
|
||||
const printList = [];
|
||||
|
||||
// Loop through all entries
|
||||
const filePaths = input.split(entryDelim).unique().sort();
|
||||
for (let i = 0; i < filePaths.length; i++) {
|
||||
// Split by file delimiter
|
||||
let path = filePaths[i].split(fileDelim);
|
||||
|
||||
if (path[0] === "") {
|
||||
path = path.slice(1, path.length);
|
||||
}
|
||||
|
||||
for (let j = 0; j < path.length; j++) {
|
||||
let printLine;
|
||||
let key;
|
||||
if (j === 0) {
|
||||
printLine = path[j];
|
||||
key = path[j];
|
||||
} else {
|
||||
printLine = PIPE.repeat(j-1) + ARROW + path[j];
|
||||
key = path.slice(0, j+1).join("/");
|
||||
}
|
||||
|
||||
// Check to see we have already added that path
|
||||
if (!completedList.includes(key)) {
|
||||
completedList.push(key);
|
||||
printList.push(printLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
return printList.join("\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FileTree;
|
||||
55
src/core/operations/FromBase92.mjs
Normal file
55
src/core/operations/FromBase92.mjs
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @author sg5506844 [sg5506844@gmail.com]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import { base92Ord } from "../lib/Base92.mjs";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* From Base92 operation
|
||||
*/
|
||||
class FromBase92 extends Operation {
|
||||
/**
|
||||
* FromBase92 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Base92";
|
||||
this.module = "Default";
|
||||
this.description = "Base92 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const res = [];
|
||||
let bitString = "";
|
||||
|
||||
for (let i = 0; i < input.length; i += 2) {
|
||||
if (i + 1 !== input.length) {
|
||||
const x = base92Ord(input[i]) * 91 + base92Ord(input[i + 1]);
|
||||
bitString += x.toString(2).padStart(13, "0");
|
||||
} else {
|
||||
const x = base92Ord(input[i]);
|
||||
bitString += x.toString(2).padStart(6, "0");
|
||||
}
|
||||
while (bitString.length >= 8) {
|
||||
res.push(parseInt(bitString.slice(0, 8), 2));
|
||||
bitString = bitString.slice(8);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export default FromBase92;
|
||||
138
src/core/operations/GOSTDecrypt.mjs
Normal file
138
src/core/operations/GOSTDecrypt.mjs
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast, fromHex } from "../lib/Hex.mjs";
|
||||
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
|
||||
|
||||
/**
|
||||
* GOST Decrypt operation
|
||||
*/
|
||||
class GOSTDecrypt extends Operation {
|
||||
|
||||
/**
|
||||
* GOSTDecrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "GOST Decrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The GOST block cipher (Magma), defined in the standard GOST 28147-89 (RFC 5830), is a Soviet and Russian government standard symmetric key block cipher with a block size of 64 bits. The original standard, published in 1989, did not give the cipher any name, but the most recent revision of the standard, GOST R 34.12-2015 (RFC 7801, RFC 8891), specifies that it may be referred to as Magma. The GOST hash function is based on this cipher. The new standard also specifies a new 128-bit block cipher called Kuznyechik.<br><br>Developed in the 1970s, the standard had been marked 'Top Secret' and then downgraded to 'Secret' in 1990. Shortly after the dissolution of the USSR, it was declassified and it was released to the public in 1994. GOST 28147 was a Soviet alternative to the United States standard algorithm, DES. Thus, the two are very similar in structure.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "IV",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Input type",
|
||||
type: "option",
|
||||
value: ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
name: "Output type",
|
||||
type: "option",
|
||||
value: ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
name: "Algorithm",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
|
||||
},
|
||||
{
|
||||
name: "Block mode",
|
||||
type: "option",
|
||||
value: ["ECB", "CFB", "OFB", "CTR", "CBC"]
|
||||
},
|
||||
{
|
||||
name: "Key meshing mode",
|
||||
type: "option",
|
||||
value: ["NO", "CP"]
|
||||
},
|
||||
{
|
||||
name: "Padding",
|
||||
type: "option",
|
||||
value: ["NO", "PKCS5", "ZERO", "RANDOM", "BIT"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [keyObj, ivObj, inputType, outputType, version, length, sBox, blockMode, keyMeshing, padding] = args;
|
||||
|
||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||
|
||||
const algorithm = {
|
||||
version: versionNum,
|
||||
length: blockLength,
|
||||
mode: "ES",
|
||||
sBox: sBoxVal,
|
||||
block: blockMode,
|
||||
keyMeshing: keyMeshing,
|
||||
padding: padding
|
||||
};
|
||||
|
||||
try {
|
||||
const Hex = CryptoGost.coding.Hex;
|
||||
if (iv) algorithm.iv = Hex.decode(iv);
|
||||
|
||||
const cipher = GostEngine.getGostCipher(algorithm);
|
||||
const out = Hex.encode(cipher.decrypt(Hex.decode(key), Hex.decode(input)));
|
||||
|
||||
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GOSTDecrypt;
|
||||
138
src/core/operations/GOSTEncrypt.mjs
Normal file
138
src/core/operations/GOSTEncrypt.mjs
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast, fromHex } from "../lib/Hex.mjs";
|
||||
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
|
||||
|
||||
/**
|
||||
* GOST Encrypt operation
|
||||
*/
|
||||
class GOSTEncrypt extends Operation {
|
||||
|
||||
/**
|
||||
* GOSTEncrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "GOST Encrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The GOST block cipher (Magma), defined in the standard GOST 28147-89 (RFC 5830), is a Soviet and Russian government standard symmetric key block cipher with a block size of 64 bits. The original standard, published in 1989, did not give the cipher any name, but the most recent revision of the standard, GOST R 34.12-2015 (RFC 7801, RFC 8891), specifies that it may be referred to as Magma. The GOST hash function is based on this cipher. The new standard also specifies a new 128-bit block cipher called Kuznyechik.<br><br>Developed in the 1970s, the standard had been marked 'Top Secret' and then downgraded to 'Secret' in 1990. Shortly after the dissolution of the USSR, it was declassified and it was released to the public in 1994. GOST 28147 was a Soviet alternative to the United States standard algorithm, DES. Thus, the two are very similar in structure.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "IV",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Input type",
|
||||
type: "option",
|
||||
value: ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
name: "Output type",
|
||||
type: "option",
|
||||
value: ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
name: "Algorithm",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
|
||||
},
|
||||
{
|
||||
name: "Block mode",
|
||||
type: "option",
|
||||
value: ["ECB", "CFB", "OFB", "CTR", "CBC"]
|
||||
},
|
||||
{
|
||||
name: "Key meshing mode",
|
||||
type: "option",
|
||||
value: ["NO", "CP"]
|
||||
},
|
||||
{
|
||||
name: "Padding",
|
||||
type: "option",
|
||||
value: ["NO", "PKCS5", "ZERO", "RANDOM", "BIT"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [keyObj, ivObj, inputType, outputType, version, length, sBox, blockMode, keyMeshing, padding] = args;
|
||||
|
||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||
|
||||
const algorithm = {
|
||||
version: versionNum,
|
||||
length: blockLength,
|
||||
mode: "ES",
|
||||
sBox: sBoxVal,
|
||||
block: blockMode,
|
||||
keyMeshing: keyMeshing,
|
||||
padding: padding
|
||||
};
|
||||
|
||||
try {
|
||||
const Hex = CryptoGost.coding.Hex;
|
||||
if (iv) algorithm.iv = Hex.decode(iv);
|
||||
|
||||
const cipher = GostEngine.getGostCipher(algorithm);
|
||||
const out = Hex.encode(cipher.encrypt(Hex.decode(key), Hex.decode(input)));
|
||||
|
||||
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GOSTEncrypt;
|
||||
@@ -7,7 +7,7 @@
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import GostDigest from "../vendor/gost/gostDigest.mjs";
|
||||
import {toHexFast} from "../lib/Hex.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
|
||||
/**
|
||||
* GOST hash operation
|
||||
@@ -20,7 +20,7 @@ class GOSTHash extends Operation {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "GOST hash";
|
||||
this.name = "GOST Hash";
|
||||
this.module = "Hashing";
|
||||
this.description = "The GOST hash function, defined in the standards GOST R 34.11-94 and GOST 34.311-95 is a 256-bit cryptographic hash function. It was initially defined in the Russian national standard GOST R 34.11-94 <i>Information Technology – Cryptographic Information Security – Hash Function</i>. The equivalent standard used by other member-states of the CIS is GOST 34.311-95.<br><br>This function must not be confused with a different Streebog hash function, which is defined in the new revision of the standard GOST R 34.11-2012.<br><br>The GOST hash function is based on the GOST block cipher.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/GOST_(hash_function)";
|
||||
@@ -28,20 +28,30 @@ class GOSTHash extends Operation {
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "S-Box",
|
||||
"type": "option",
|
||||
"value": [
|
||||
"D-A",
|
||||
"D-SC",
|
||||
"E-TEST",
|
||||
"E-A",
|
||||
"E-B",
|
||||
"E-C",
|
||||
"E-D",
|
||||
"E-SC",
|
||||
"E-Z",
|
||||
"D-TEST"
|
||||
name: "Algorithm",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (1994)",
|
||||
off: [1],
|
||||
on: [2]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.11 (Streebog, 2012)",
|
||||
on: [1],
|
||||
off: [2]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Digest length",
|
||||
type: "option",
|
||||
value: ["256", "512"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -52,13 +62,23 @@ class GOSTHash extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [version, length, sBox] = args;
|
||||
|
||||
const versionNum = version === "GOST 28147 (1994)" ? 1994 : 2012;
|
||||
const algorithm = {
|
||||
name: versionNum === 1994 ? "GOST 28147" : "GOST R 34.10",
|
||||
version: versionNum,
|
||||
mode: "HASH"
|
||||
};
|
||||
|
||||
if (versionNum === 1994) {
|
||||
algorithm.sBox = sBox;
|
||||
} else {
|
||||
algorithm.length = parseInt(length, 10);
|
||||
}
|
||||
|
||||
try {
|
||||
const sBox = args[1];
|
||||
const gostDigest = new GostDigest({
|
||||
name: "GOST R 34.11",
|
||||
version: 1994,
|
||||
sBox: sBox
|
||||
});
|
||||
const gostDigest = new GostDigest(algorithm);
|
||||
|
||||
return toHexFast(gostDigest.digest(input));
|
||||
} catch (err) {
|
||||
|
||||
129
src/core/operations/GOSTKeyUnwrap.mjs
Normal file
129
src/core/operations/GOSTKeyUnwrap.mjs
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast, fromHex } from "../lib/Hex.mjs";
|
||||
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
|
||||
|
||||
/**
|
||||
* GOST Key Unwrap operation
|
||||
*/
|
||||
class GOSTKeyUnwrap extends Operation {
|
||||
|
||||
/**
|
||||
* GOSTKeyUnwrap constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "GOST Key Unwrap";
|
||||
this.module = "Ciphers";
|
||||
this.description = "A decryptor for keys wrapped using one of the GOST block ciphers.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "User Key Material",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Input type",
|
||||
type: "option",
|
||||
value: ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
name: "Output type",
|
||||
type: "option",
|
||||
value: ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
name: "Algorithm",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
|
||||
},
|
||||
{
|
||||
name: "Key wrapping",
|
||||
type: "option",
|
||||
value: ["NO", "CP", "SC"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [keyObj, ukmObj, inputType, outputType, version, length, sBox, keyWrapping] = args;
|
||||
|
||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||
|
||||
const algorithm = {
|
||||
version: versionNum,
|
||||
length: blockLength,
|
||||
mode: "KW",
|
||||
sBox: sBoxVal,
|
||||
keyWrapping: keyWrapping
|
||||
};
|
||||
|
||||
try {
|
||||
const Hex = CryptoGost.coding.Hex;
|
||||
algorithm.ukm = Hex.decode(ukm);
|
||||
|
||||
const cipher = GostEngine.getGostCipher(algorithm);
|
||||
const out = Hex.encode(cipher.unwrapKey(Hex.decode(key), Hex.decode(input)));
|
||||
|
||||
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
|
||||
} catch (err) {
|
||||
if (err.toString().includes("Invalid typed array length")) {
|
||||
throw new OperationError("Incorrect input length. Must be a multiple of the block size.");
|
||||
}
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GOSTKeyUnwrap;
|
||||
129
src/core/operations/GOSTKeyWrap.mjs
Normal file
129
src/core/operations/GOSTKeyWrap.mjs
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast, fromHex } from "../lib/Hex.mjs";
|
||||
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
|
||||
|
||||
/**
|
||||
* GOST Key Wrap operation
|
||||
*/
|
||||
class GOSTKeyWrap extends Operation {
|
||||
|
||||
/**
|
||||
* GOSTKeyWrap constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "GOST Key Wrap";
|
||||
this.module = "Ciphers";
|
||||
this.description = "A key wrapping algorithm for protecting keys in untrusted storage using one of the GOST block cipers.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "User Key Material",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Input type",
|
||||
type: "option",
|
||||
value: ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
name: "Output type",
|
||||
type: "option",
|
||||
value: ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
name: "Algorithm",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
|
||||
},
|
||||
{
|
||||
name: "Key wrapping",
|
||||
type: "option",
|
||||
value: ["NO", "CP", "SC"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [keyObj, ukmObj, inputType, outputType, version, length, sBox, keyWrapping] = args;
|
||||
|
||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||
|
||||
const algorithm = {
|
||||
version: versionNum,
|
||||
length: blockLength,
|
||||
mode: "KW",
|
||||
sBox: sBoxVal,
|
||||
keyWrapping: keyWrapping
|
||||
};
|
||||
|
||||
try {
|
||||
const Hex = CryptoGost.coding.Hex;
|
||||
algorithm.ukm = Hex.decode(ukm);
|
||||
|
||||
const cipher = GostEngine.getGostCipher(algorithm);
|
||||
const out = Hex.encode(cipher.wrapKey(Hex.decode(key), Hex.decode(input)));
|
||||
|
||||
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
|
||||
} catch (err) {
|
||||
if (err.toString().includes("Invalid typed array length")) {
|
||||
throw new OperationError("Incorrect input length. Must be a multiple of the block size.");
|
||||
}
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GOSTKeyWrap;
|
||||
129
src/core/operations/GOSTSign.mjs
Normal file
129
src/core/operations/GOSTSign.mjs
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast, fromHex } from "../lib/Hex.mjs";
|
||||
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
|
||||
|
||||
/**
|
||||
* GOST Sign operation
|
||||
*/
|
||||
class GOSTSign extends Operation {
|
||||
|
||||
/**
|
||||
* GOSTSign constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "GOST Sign";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Sign a plaintext message using one of the GOST block ciphers.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "IV",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Input type",
|
||||
type: "option",
|
||||
value: ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
name: "Output type",
|
||||
type: "option",
|
||||
value: ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
name: "Algorithm",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
|
||||
},
|
||||
{
|
||||
name: "MAC length",
|
||||
type: "number",
|
||||
value: 32,
|
||||
min: 8,
|
||||
max: 64,
|
||||
step: 8
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [keyObj, ivObj, inputType, outputType, version, length, sBox, macLength] = args;
|
||||
|
||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||
|
||||
const algorithm = {
|
||||
version: versionNum,
|
||||
length: blockLength,
|
||||
mode: "MAC",
|
||||
sBox: sBoxVal,
|
||||
macLength: macLength
|
||||
};
|
||||
|
||||
try {
|
||||
const Hex = CryptoGost.coding.Hex;
|
||||
if (iv) algorithm.iv = Hex.decode(iv);
|
||||
|
||||
const cipher = GostEngine.getGostCipher(algorithm);
|
||||
const out = Hex.encode(cipher.sign(Hex.decode(key), Hex.decode(input)));
|
||||
|
||||
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GOSTSign;
|
||||
123
src/core/operations/GOSTVerify.mjs
Normal file
123
src/core/operations/GOSTVerify.mjs
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
|
||||
|
||||
/**
|
||||
* GOST Verify operation
|
||||
*/
|
||||
class GOSTVerify extends Operation {
|
||||
|
||||
/**
|
||||
* GOSTVerify constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "GOST Verify";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Verify the signature of a plaintext message using one of the GOST block ciphers. Enter the signature in the MAC field.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "IV",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "MAC",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Input type",
|
||||
type: "option",
|
||||
value: ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
name: "Algorithm",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [keyObj, ivObj, macObj, inputType, version, length, sBox] = args;
|
||||
|
||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
const mac = toHexFast(Utils.convertToByteArray(macObj.string, macObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||
|
||||
const algorithm = {
|
||||
version: versionNum,
|
||||
length: blockLength,
|
||||
mode: "MAC",
|
||||
sBox: sBoxVal,
|
||||
macLength: mac.length * 4
|
||||
};
|
||||
|
||||
try {
|
||||
const Hex = CryptoGost.coding.Hex;
|
||||
if (iv) algorithm.iv = Hex.decode(iv);
|
||||
|
||||
const cipher = GostEngine.getGostCipher(algorithm);
|
||||
const out = cipher.verify(Hex.decode(key), Hex.decode(mac), Hex.decode(input));
|
||||
|
||||
return out ? "The signature matches" : "The signature does not match";
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GOSTVerify;
|
||||
@@ -108,7 +108,7 @@ class GenerateAllHashes extends Operation {
|
||||
{name: "BLAKE2s-256", algo: (new BLAKE2s), inputType: "arrayBuffer", params: ["256", "Hex", {string: "", option: "UTF8"}]},
|
||||
{name: "Streebog-256", algo: (new Streebog), inputType: "arrayBuffer", params: ["256"]},
|
||||
{name: "Streebog-512", algo: (new Streebog), inputType: "arrayBuffer", params: ["512"]},
|
||||
{name: "GOST", algo: (new GOSTHash), inputType: "arrayBuffer", params: ["D-A"]},
|
||||
{name: "GOST", algo: (new GOSTHash), inputType: "arrayBuffer", params: ["GOST 28147 (1994)", "256", "D-A"]},
|
||||
{name: "LM Hash", algo: (new LMHash), inputType: "str", params: []},
|
||||
{name: "NT Hash", algo: (new NTHash), inputType: "str", params: []},
|
||||
{name: "SSDEEP", algo: (new SSDEEP()), inputType: "str"},
|
||||
|
||||
85
src/core/operations/GenerateDeBruijnSequence.mjs
Normal file
85
src/core/operations/GenerateDeBruijnSequence.mjs
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @author gchq77703 [gchq77703@gchq.gov.uk]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Generate De Bruijn Sequence operation
|
||||
*/
|
||||
class GenerateDeBruijnSequence extends Operation {
|
||||
|
||||
/**
|
||||
* GenerateDeBruijnSequence constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Generate De Bruijn Sequence";
|
||||
this.module = "Default";
|
||||
this.description = "Generates rolling keycode combinations given a certain alphabet size and key length.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/De_Bruijn_sequence";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Alphabet size (k)",
|
||||
type: "number",
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
name: "Key length (n)",
|
||||
type: "number",
|
||||
value: 3
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [k, n] = args;
|
||||
|
||||
if (k < 2 || k > 9) {
|
||||
throw new OperationError("Invalid alphabet size, required to be between 2 and 9 (inclusive).");
|
||||
}
|
||||
|
||||
if (n < 2) {
|
||||
throw new OperationError("Invalid key length, required to be at least 2.");
|
||||
}
|
||||
|
||||
if (Math.pow(k, n) > 50000) {
|
||||
throw new OperationError("Too many permutations, please reduce k^n to under 50,000.");
|
||||
}
|
||||
|
||||
const a = new Array(k * n).fill(0);
|
||||
const sequence = [];
|
||||
|
||||
(function db(t = 1, p = 1) {
|
||||
if (t > n) {
|
||||
if (n % p !== 0) return;
|
||||
for (let j = 1; j <= p; j++) {
|
||||
sequence.push(a[j]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
a[t] = a[t - p];
|
||||
db(t + 1, p);
|
||||
for (let j = a[t - p] + 1; j < k; j++) {
|
||||
a[t] = j;
|
||||
db(t + 1, t);
|
||||
}
|
||||
})();
|
||||
|
||||
return sequence.join("");
|
||||
}
|
||||
}
|
||||
|
||||
export default GenerateDeBruijnSequence;
|
||||
41
src/core/operations/LZNT1Decompress.mjs
Normal file
41
src/core/operations/LZNT1Decompress.mjs
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @author 0xThiebaut [thiebaut.dev]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import {decompress} from "../lib/LZNT1.mjs";
|
||||
|
||||
/**
|
||||
* LZNT1 Decompress operation
|
||||
*/
|
||||
class LZNT1Decompress extends Operation {
|
||||
|
||||
/**
|
||||
* LZNT1 Decompress constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "LZNT1 Decompress";
|
||||
this.module = "Compression";
|
||||
this.description = "Decompresses data using the LZNT1 algorithm.<br><br>Similar to the Windows API <code>RtlDecompressBuffer</code>.";
|
||||
this.infoURL = "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-xca/5655f4a3-6ba4-489b-959f-e1f407c52f15";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
return decompress(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default LZNT1Decompress;
|
||||
98
src/core/operations/LevenshteinDistance.mjs
Normal file
98
src/core/operations/LevenshteinDistance.mjs
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @author mikecat
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Levenshtein Distance operation
|
||||
*/
|
||||
class LevenshteinDistance extends Operation {
|
||||
|
||||
/**
|
||||
* LevenshteinDistance constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Levenshtein Distance";
|
||||
this.module = "Default";
|
||||
this.description = "Levenshtein Distance (also known as Edit Distance) is a string metric to measure a difference between two strings that counts operations (insertions, deletions, and substitutions) on single character that are required to change one string to another.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Levenshtein_distance";
|
||||
this.inputType = "string";
|
||||
this.outputType = "number";
|
||||
this.args = [
|
||||
{
|
||||
name: "Sample delimiter",
|
||||
type: "binaryString",
|
||||
value: "\\n"
|
||||
},
|
||||
{
|
||||
name: "Insertion cost",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Deletion cost",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Substitution cost",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [delim, insCost, delCost, subCost] = args;
|
||||
const samples = input.split(delim);
|
||||
if (samples.length !== 2) {
|
||||
throw new OperationError("Incorrect number of samples. Check your input and/or delimiter.");
|
||||
}
|
||||
if (insCost < 0 || delCost < 0 || subCost < 0) {
|
||||
throw new OperationError("Negative costs are not allowed.");
|
||||
}
|
||||
const src = samples[0], dest = samples[1];
|
||||
let currentCost = new Array(src.length + 1);
|
||||
let nextCost = new Array(src.length + 1);
|
||||
for (let i = 0; i < currentCost.length; i++) {
|
||||
currentCost[i] = delCost * i;
|
||||
}
|
||||
for (let i = 0; i < dest.length; i++) {
|
||||
const destc = dest.charAt(i);
|
||||
nextCost[0] = currentCost[0] + insCost;
|
||||
for (let j = 0; j < src.length; j++) {
|
||||
let candidate;
|
||||
// insertion
|
||||
let optCost = currentCost[j + 1] + insCost;
|
||||
// deletion
|
||||
candidate = nextCost[j] + delCost;
|
||||
if (candidate < optCost) optCost = candidate;
|
||||
// substitution or matched character
|
||||
candidate = currentCost[j];
|
||||
if (src.charAt(j) !== destc) candidate += subCost;
|
||||
if (candidate < optCost) optCost = candidate;
|
||||
// store calculated cost
|
||||
nextCost[j + 1] = optCost;
|
||||
}
|
||||
const tempCost = nextCost;
|
||||
nextCost = currentCost;
|
||||
currentCost = tempCost;
|
||||
}
|
||||
|
||||
return currentCost[currentCost.length - 1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default LevenshteinDistance;
|
||||
143
src/core/operations/MurmurHash3.mjs
Normal file
143
src/core/operations/MurmurHash3.mjs
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Based on murmurhash-js (https://github.com/garycourt/murmurhash-js)
|
||||
* @author Gary Court
|
||||
* @license MIT
|
||||
*
|
||||
* @author AliceGrey [alice@grey.systems]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* MurmurHash3 operation
|
||||
*/
|
||||
class MurmurHash3 extends Operation {
|
||||
|
||||
/**
|
||||
* MurmurHash3 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "MurmurHash3";
|
||||
this.module = "Default";
|
||||
this.description = "Generates a MurmurHash v3 for a string input and an optional seed input";
|
||||
this.infoURL = "https://wikipedia.org/wiki/MurmurHash";
|
||||
this.inputType = "string";
|
||||
this.outputType = "number";
|
||||
this.args = [
|
||||
{
|
||||
name: "Seed",
|
||||
type: "number",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "Convert to Signed",
|
||||
type: "boolean",
|
||||
value: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the MurmurHash3 hash of the input.
|
||||
* Based on Gary Court's JS MurmurHash implementation
|
||||
* @see http://github.com/garycourt/murmurhash-js
|
||||
* @author AliceGrey [alice@grey.systems]
|
||||
* @param {string} input ASCII only
|
||||
* @param {number} seed Positive integer only
|
||||
* @return {number} 32-bit positive integer hash
|
||||
*/
|
||||
mmh3(input, seed) {
|
||||
let h1b;
|
||||
let k1;
|
||||
const remainder = input.length & 3; // input.length % 4
|
||||
const bytes = input.length - remainder;
|
||||
let h1 = seed;
|
||||
const c1 = 0xcc9e2d51;
|
||||
const c2 = 0x1b873593;
|
||||
let i = 0;
|
||||
|
||||
while (i < bytes) {
|
||||
k1 =
|
||||
((input.charCodeAt(i) & 0xff)) |
|
||||
((input.charCodeAt(++i) & 0xff) << 8) |
|
||||
((input.charCodeAt(++i) & 0xff) << 16) |
|
||||
((input.charCodeAt(++i) & 0xff) << 24);
|
||||
++i;
|
||||
|
||||
k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = (h1 << 13) | (h1 >>> 19);
|
||||
h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
|
||||
h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
|
||||
}
|
||||
|
||||
k1 = 0;
|
||||
|
||||
if (remainder === 3) {
|
||||
k1 ^= (input.charCodeAt(i + 2) & 0xff) << 16;
|
||||
}
|
||||
|
||||
if (remainder === 3 || remainder === 2) {
|
||||
k1 ^= (input.charCodeAt(i + 1) & 0xff) << 8;
|
||||
}
|
||||
|
||||
if (remainder === 3 || remainder === 2 || remainder === 1) {
|
||||
k1 ^= (input.charCodeAt(i) & 0xff);
|
||||
|
||||
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
|
||||
k1 = (k1 << 15) | (k1 >>> 17);
|
||||
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
|
||||
h1 ^= k1;
|
||||
}
|
||||
|
||||
h1 ^= input.length;
|
||||
|
||||
h1 ^= h1 >>> 16;
|
||||
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
|
||||
h1 ^= h1 >>> 13;
|
||||
h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
|
||||
h1 ^= h1 >>> 16;
|
||||
|
||||
return h1 >>> 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an unsigned 32-bit integer to a signed 32-bit integer
|
||||
* @author AliceGrey [alice@grey.systems]
|
||||
* @param {value} 32-bit unsigned integer
|
||||
* @return {number} 32-bit signed integer
|
||||
*/
|
||||
unsignedToSigned(value) {
|
||||
if (value & 0x80000000) {
|
||||
return -0x100000000 + value;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (args && args.length >= 1) {
|
||||
const seed = args[0];
|
||||
const hash = this.mmh3(input, seed);
|
||||
if (args.length > 1 && args[1]) {
|
||||
return this.unsignedToSigned(hash);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
return this.mmh3(input);
|
||||
}
|
||||
}
|
||||
|
||||
export default MurmurHash3;
|
||||
@@ -20,7 +20,7 @@ class ParseASN1HexString extends Operation {
|
||||
|
||||
this.name = "Parse ASN.1 hex string";
|
||||
this.module = "PublicKey";
|
||||
this.description = "Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.<br><br>This operation parses arbitrary ASN.1 data and presents the resulting tree.";
|
||||
this.description = "Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking.<br><br>This operation parses arbitrary ASN.1 data (encoded as an hex string: use the 'To Hex' operation if necessary) and presents the resulting tree.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Abstract_Syntax_Notation_One";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
||||
@@ -83,6 +83,10 @@ class RegularExpression extends Operation {
|
||||
name: "Strings",
|
||||
value: "[A-Za-z\\d/\\-:.,_$%\\x27\"()<>= !\\[\\]{}@]{4,}"
|
||||
},
|
||||
{
|
||||
name: "UUID (any version)",
|
||||
value: "[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}"
|
||||
},
|
||||
],
|
||||
"target": 1
|
||||
},
|
||||
|
||||
60
src/core/operations/RisonDecode.mjs
Normal file
60
src/core/operations/RisonDecode.mjs
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @author sg5506844 [sg5506844@gmail.com]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import rison from "rison";
|
||||
|
||||
/**
|
||||
* Rison Decode operation
|
||||
*/
|
||||
class RisonDecode extends Operation {
|
||||
|
||||
/**
|
||||
* RisonDecode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Rison Decode";
|
||||
this.module = "Default";
|
||||
this.description = "Rison, a data serialization format optimized for compactness in URIs. Rison is a slight variation of JSON that looks vastly superior after URI encoding. Rison still expresses exactly the same set of data structures as JSON, so data can be translated back and forth without loss or guesswork.";
|
||||
this.infoURL = "https://github.com/Nanonid/rison";
|
||||
this.inputType = "string";
|
||||
this.outputType = "Object";
|
||||
this.args = [
|
||||
{
|
||||
name: "Decode Option",
|
||||
type: "editableOption",
|
||||
value: [
|
||||
{ name: "Decode", value: "Decode", },
|
||||
{ name: "Decode Object", value: "Decode Object", },
|
||||
{ name: "Decode Array", value: "Decode Array", },
|
||||
]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {Object}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [decodeOption] = args;
|
||||
switch (decodeOption) {
|
||||
case "Decode":
|
||||
return rison.decode(input);
|
||||
case "Decode Object":
|
||||
return rison.decode_object(input);
|
||||
case "Decode Array":
|
||||
return rison.decode_array(input);
|
||||
}
|
||||
throw new OperationError("Invalid Decode option");
|
||||
}
|
||||
}
|
||||
|
||||
export default RisonDecode;
|
||||
63
src/core/operations/RisonEncode.mjs
Normal file
63
src/core/operations/RisonEncode.mjs
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @author sg5506844 [sg5506844@gmail.com]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import rison from "rison";
|
||||
|
||||
/**
|
||||
* Rison Encode operation
|
||||
*/
|
||||
class RisonEncode extends Operation {
|
||||
|
||||
/**
|
||||
* RisonEncode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Rison Encode";
|
||||
this.module = "Default";
|
||||
this.description = "Rison, a data serialization format optimized for compactness in URIs. Rison is a slight variation of JSON that looks vastly superior after URI encoding. Rison still expresses exactly the same set of data structures as JSON, so data can be translated back and forth without loss or guesswork.";
|
||||
this.infoURL = "https://github.com/Nanonid/rison";
|
||||
this.inputType = "Object";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Encode Option",
|
||||
type: "editableOption",
|
||||
value: [
|
||||
{ name: "Encode", value: "Encode", },
|
||||
{ name: "Encode Object", value: "Encode Object", },
|
||||
{ name: "Encode Array", value: "Encode Array", },
|
||||
{ name: "Encode URI", value: "Encode URI", }
|
||||
]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [encodeOption] = args;
|
||||
switch (encodeOption) {
|
||||
case "Encode":
|
||||
return rison.encode(input);
|
||||
case "Encode Object":
|
||||
return rison.encode_object(input);
|
||||
case "Encode Array":
|
||||
return rison.encode_array(input);
|
||||
case "Encode URI":
|
||||
return rison.encode_uri(input);
|
||||
}
|
||||
throw new OperationError("Invalid encode option");
|
||||
}
|
||||
}
|
||||
|
||||
export default RisonEncode;
|
||||
@@ -21,7 +21,7 @@ class SSDEEP extends Operation {
|
||||
this.name = "SSDEEP";
|
||||
this.module = "Crypto";
|
||||
this.description = "SSDEEP is a program for computing context triggered piecewise hashes (CTPH). Also called fuzzy hashes, CTPH can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>SSDEEP hashes are now widely used for simple identification purposes (e.g. the 'Basic Properties' section in VirusTotal). Although 'better' fuzzy hashes are available, SSDEEP is still one of the primary choices because of its speed and being a de facto standard.<br><br>This operation is fundamentally the same as the CTPH operation, however their outputs differ in format.";
|
||||
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Ssdeep";
|
||||
this.infoURL = "https://forensics.wiki/ssdeep";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
|
||||
@@ -28,7 +28,7 @@ class Streebog extends Operation {
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Size",
|
||||
"name": "Digest length",
|
||||
"type": "option",
|
||||
"value": ["256", "512"]
|
||||
}
|
||||
@@ -41,13 +41,16 @@ class Streebog extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [length] = args;
|
||||
|
||||
const algorithm = {
|
||||
version: 2012,
|
||||
mode: "HASH",
|
||||
length: parseInt(length, 10)
|
||||
};
|
||||
|
||||
try {
|
||||
const length = parseInt(args[0], 10);
|
||||
const gostDigest = new GostDigest({
|
||||
name: "GOST R 34.11",
|
||||
version: 2012,
|
||||
length: length
|
||||
});
|
||||
const gostDigest = new GostDigest(algorithm);
|
||||
|
||||
return toHexFast(gostDigest.digest(input));
|
||||
} catch (err) {
|
||||
|
||||
76
src/core/operations/SwapCase.mjs
Normal file
76
src/core/operations/SwapCase.mjs
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @author mikecat
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Swap case operation
|
||||
*/
|
||||
class SwapCase extends Operation {
|
||||
|
||||
/**
|
||||
* SwapCase constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Swap case";
|
||||
this.module = "Default";
|
||||
this.description = "Converts uppercase letters to lowercase ones, and lowercase ones to uppercase ones.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let result = "";
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const c = input.charAt(i);
|
||||
const upper = c.toUpperCase();
|
||||
if (c === upper) {
|
||||
result += c.toLowerCase();
|
||||
} else {
|
||||
result += upper;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Swap case
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Swap case in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SwapCase;
|
||||
67
src/core/operations/ToBase92.mjs
Normal file
67
src/core/operations/ToBase92.mjs
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @author sg5506844 [sg5506844@gmail.com]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import { base92Chr } from "../lib/Base92.mjs";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* To Base92 operation
|
||||
*/
|
||||
class ToBase92 extends Operation {
|
||||
/**
|
||||
* ToBase92 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To Base92";
|
||||
this.module = "Default";
|
||||
this.description = "Base92 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const res = [];
|
||||
let bitString = "";
|
||||
|
||||
while (input.length > 0) {
|
||||
while (bitString.length < 13 && input.length > 0) {
|
||||
bitString += input[0].charCodeAt(0).toString(2).padStart(8, "0");
|
||||
input = input.slice(1);
|
||||
}
|
||||
if (bitString.length < 13)
|
||||
break;
|
||||
const i = parseInt(bitString.slice(0, 13), 2);
|
||||
res.push(base92Chr(Math.floor(i / 91)));
|
||||
res.push(base92Chr(i % 91));
|
||||
bitString = bitString.slice(13);
|
||||
}
|
||||
|
||||
if (bitString.length > 0) {
|
||||
if (bitString.length < 7) {
|
||||
bitString = bitString.padEnd(6, "0");
|
||||
res.push(base92Chr(parseInt(bitString, 2)));
|
||||
} else {
|
||||
bitString = bitString.padEnd(13, "0");
|
||||
const i = parseInt(bitString.slice(0, 13), 2);
|
||||
res.push(base92Chr(Math.floor(i / 91)));
|
||||
res.push(base92Chr(i % 91));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default ToBase92;
|
||||
@@ -214,7 +214,7 @@ class ToTable extends Operation {
|
||||
output += outputRow(row, longestCells);
|
||||
let rowOutput = verticalBorder;
|
||||
row.forEach(function(cell, index) {
|
||||
rowOutput += " " + headerDivider + " " + verticalBorder;
|
||||
rowOutput += " " + headerDivider.repeat(longestCells[index]) + " " + verticalBorder;
|
||||
});
|
||||
output += rowOutput += "\n";
|
||||
|
||||
|
||||
@@ -157,9 +157,9 @@ function titleFromWikiLink(urlStr) {
|
||||
pageTitle = "";
|
||||
|
||||
switch (urlObj.host) {
|
||||
case "forensicswiki.xyz":
|
||||
case "forensics.wiki":
|
||||
wikiName = "Forensics Wiki";
|
||||
pageTitle = urlObj.query.substr(6).replace(/_/g, " "); // Chop off 'title='
|
||||
pageTitle = Utils.toTitleCase(urlObj.path.replace(/\//g, "").replace(/_/g, " "));
|
||||
break;
|
||||
case "wikipedia.org":
|
||||
wikiName = "Wikipedia";
|
||||
|
||||
@@ -61,7 +61,9 @@
|
||||
"Symlinking emacs and vim to ed...",
|
||||
"Training branch predictor...",
|
||||
"Timing cache hits...",
|
||||
"Speculatively executing recipes..."
|
||||
"Speculatively executing recipes...",
|
||||
"Adding LLM hallucinations...",
|
||||
"Decompressing malware..."
|
||||
];
|
||||
|
||||
// Shuffle array using Durstenfeld algorithm
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
/* Highlighter colours */
|
||||
--hl1: #264f78;
|
||||
--hl2: #675351;
|
||||
--hl3: #ffb6b6;
|
||||
--hl3: #c40000;
|
||||
--hl4: #fcf8e3;
|
||||
--hl5: #38811b;
|
||||
|
||||
|
||||
@@ -275,7 +275,6 @@ class StatusBarPanel {
|
||||
bakingTime.textContent = this.timing.duration(this.tabNumGetter());
|
||||
|
||||
const info = this.timing.printStages(this.tabNumGetter()).replace(/\n/g, "<br>");
|
||||
bakingTimeInfo.setAttribute("title", info);
|
||||
bakingTimeInfo.setAttribute("data-original-title", info);
|
||||
} else {
|
||||
bakingTimeInfo.style.display = "none";
|
||||
|
||||
@@ -635,6 +635,10 @@ WWFkYSBZYWRh\r
|
||||
assert.strictEqual(chef.keccak("Flea Market").toString(), "c2a06880b19e453ee5440e8bd4c2024bedc15a6630096aa3f609acfd2b8f15f27cd293e1cc73933e81432269129ce954a6138889ce87831179d55dcff1cc7587");
|
||||
}),
|
||||
|
||||
it("LZNT1 Decompress", () => {
|
||||
assert.strictEqual(chef.LZNT1Decompress("\x1a\xb0\x00compress\x00edtestda\x04ta\x07\x88alot").toString(), "compressedtestdatacompressedalot");
|
||||
}),
|
||||
|
||||
it("MD6", () => {
|
||||
assert.strictEqual(chef.MD6("Head Over Heels", {key: "arty"}).toString(), "d8f7fe4931fbaa37316f76283d5f615f50ddd54afdc794b61da522556aee99ad");
|
||||
}),
|
||||
|
||||
@@ -17,122 +17,130 @@ import {
|
||||
} from "../lib/utils.mjs";
|
||||
|
||||
import TestRegister from "../lib/TestRegister.mjs";
|
||||
import "./tests/BCD.mjs";
|
||||
import "./tests/BSON.mjs";
|
||||
import "./tests/AESKeyWrap.mjs";
|
||||
import "./tests/AvroToJSON.mjs";
|
||||
import "./tests/BaconCipher.mjs";
|
||||
import "./tests/Base45.mjs";
|
||||
import "./tests/Base58.mjs";
|
||||
import "./tests/Base64.mjs";
|
||||
import "./tests/Base62.mjs";
|
||||
import "./tests/Base64.mjs";
|
||||
import "./tests/Base85.mjs";
|
||||
import "./tests/Base92.mjs";
|
||||
import "./tests/BCD.mjs";
|
||||
import "./tests/BitwiseOp.mjs";
|
||||
import "./tests/BLAKE2b.mjs";
|
||||
import "./tests/BLAKE2s.mjs";
|
||||
import "./tests/Bombe.mjs";
|
||||
import "./tests/BSON.mjs";
|
||||
import "./tests/ByteRepr.mjs";
|
||||
import "./tests/CaesarBoxCipher.mjs";
|
||||
import "./tests/CartesianProduct.mjs";
|
||||
import "./tests/CetaceanCipherEncode.mjs";
|
||||
import "./tests/CBORDecode.mjs";
|
||||
import "./tests/CBOREncode.mjs";
|
||||
import "./tests/CetaceanCipherDecode.mjs";
|
||||
import "./tests/CetaceanCipherEncode.mjs";
|
||||
import "./tests/ChaCha.mjs";
|
||||
import "./tests/CharEnc.mjs";
|
||||
import "./tests/ChangeIPFormat.mjs";
|
||||
import "./tests/CharEnc.mjs";
|
||||
import "./tests/Charts.mjs";
|
||||
import "./tests/Checksum.mjs";
|
||||
import "./tests/Ciphers.mjs";
|
||||
import "./tests/CipherSaber2.mjs";
|
||||
import "./tests/CMAC.mjs";
|
||||
import "./tests/Code.mjs";
|
||||
import "./tests/Colossus.mjs";
|
||||
import "./tests/Comment.mjs";
|
||||
import "./tests/Compress.mjs";
|
||||
import "./tests/ConditionalJump.mjs";
|
||||
import "./tests/ConvertCoordinateFormat.mjs";
|
||||
import "./tests/ConvertToNATOAlphabet.mjs";
|
||||
import "./tests/Crypt.mjs";
|
||||
import "./tests/CSV.mjs";
|
||||
import "./tests/DateTime.mjs";
|
||||
import "./tests/DefangIP.mjs";
|
||||
import "./tests/ELFInfo.mjs";
|
||||
import "./tests/Enigma.mjs";
|
||||
import "./tests/ExtractEmailAddresses.mjs";
|
||||
import "./tests/FileTree.mjs";
|
||||
import "./tests/FletcherChecksum.mjs";
|
||||
import "./tests/Fork.mjs";
|
||||
import "./tests/FromDecimal.mjs";
|
||||
import "./tests/GenerateAllHashes.mjs";
|
||||
import "./tests/Gzip.mjs";
|
||||
import "./tests/GenerateDeBruijnSequence.mjs";
|
||||
import "./tests/GetAllCasings.mjs";
|
||||
import "./tests/GOST.mjs";
|
||||
import "./tests/Gunzip.mjs";
|
||||
import "./tests/Gzip.mjs";
|
||||
import "./tests/Hash.mjs";
|
||||
import "./tests/HASSH.mjs";
|
||||
import "./tests/HaversineDistance.mjs";
|
||||
import "./tests/Hex.mjs";
|
||||
import "./tests/Hexdump.mjs";
|
||||
import "./tests/HKDF.mjs";
|
||||
import "./tests/Image.mjs";
|
||||
import "./tests/IndexOfCoincidence.mjs";
|
||||
import "./tests/Jump.mjs";
|
||||
import "./tests/JA3Fingerprint.mjs";
|
||||
import "./tests/JA3SFingerprint.mjs";
|
||||
import "./tests/JSONBeautify.mjs";
|
||||
import "./tests/JSONMinify.mjs";
|
||||
import "./tests/JSONtoCSV.mjs";
|
||||
import "./tests/Jump.mjs";
|
||||
import "./tests/JWTDecode.mjs";
|
||||
import "./tests/JWTSign.mjs";
|
||||
import "./tests/JWTVerify.mjs";
|
||||
import "./tests/MS.mjs";
|
||||
import "./tests/LevenshteinDistance.mjs";
|
||||
import "./tests/Lorenz.mjs";
|
||||
import "./tests/LS47.mjs";
|
||||
import "./tests/LuhnChecksum.mjs";
|
||||
import "./tests/LZNT1Decompress.mjs";
|
||||
import "./tests/LZString.mjs";
|
||||
import "./tests/Magic.mjs";
|
||||
import "./tests/Media.mjs";
|
||||
import "./tests/MorseCode.mjs";
|
||||
import "./tests/MS.mjs";
|
||||
import "./tests/MultipleBombe.mjs";
|
||||
import "./tests/MurmurHash3.mjs";
|
||||
import "./tests/NetBIOS.mjs";
|
||||
import "./tests/NormaliseUnicode.mjs";
|
||||
import "./tests/NTLM.mjs";
|
||||
import "./tests/OTP.mjs";
|
||||
import "./tests/ParseIPRange.mjs";
|
||||
import "./tests/ParseObjectIDTimestamp.mjs";
|
||||
import "./tests/ParseQRCode.mjs";
|
||||
import "./tests/ParseSSHHostKey.mjs";
|
||||
import "./tests/ParseTCP.mjs";
|
||||
import "./tests/ParseTLV.mjs";
|
||||
import "./tests/ParseUDP.mjs";
|
||||
import "./tests/PEMtoHex.mjs";
|
||||
import "./tests/PGP.mjs";
|
||||
import "./tests/PHP.mjs";
|
||||
import "./tests/ParseIPRange.mjs";
|
||||
import "./tests/ParseQRCode.mjs";
|
||||
import "./tests/PEMtoHex.mjs";
|
||||
import "./tests/PowerSet.mjs";
|
||||
import "./tests/Protobuf.mjs";
|
||||
import "./tests/Rabbit.mjs";
|
||||
import "./tests/Regex.mjs";
|
||||
import "./tests/Register.mjs";
|
||||
import "./tests/RisonEncodeDecode.mjs";
|
||||
import "./tests/Rotate.mjs";
|
||||
import "./tests/RSA.mjs";
|
||||
import "./tests/SeqUtils.mjs";
|
||||
import "./tests/SetDifference.mjs";
|
||||
import "./tests/SetIntersection.mjs";
|
||||
import "./tests/SetUnion.mjs";
|
||||
import "./tests/Shuffle.mjs";
|
||||
import "./tests/SIGABA.mjs";
|
||||
import "./tests/SM4.mjs";
|
||||
// import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet
|
||||
import "./tests/StrUtils.mjs";
|
||||
import "./tests/Subsection.mjs";
|
||||
import "./tests/SwapCase.mjs";
|
||||
import "./tests/SymmetricDifference.mjs";
|
||||
import "./tests/TextEncodingBruteForce.mjs";
|
||||
import "./tests/TranslateDateTimeFormat.mjs";
|
||||
import "./tests/Magic.mjs";
|
||||
import "./tests/ParseTLV.mjs";
|
||||
import "./tests/Media.mjs";
|
||||
import "./tests/ToFromInsensitiveRegex.mjs";
|
||||
import "./tests/YARA.mjs";
|
||||
import "./tests/ConvertCoordinateFormat.mjs";
|
||||
import "./tests/Enigma.mjs";
|
||||
import "./tests/Bombe.mjs";
|
||||
import "./tests/MultipleBombe.mjs";
|
||||
import "./tests/TranslateDateTimeFormat.mjs";
|
||||
import "./tests/Typex.mjs";
|
||||
import "./tests/BLAKE2b.mjs";
|
||||
import "./tests/BLAKE2s.mjs";
|
||||
import "./tests/Protobuf.mjs";
|
||||
import "./tests/ParseSSHHostKey.mjs";
|
||||
import "./tests/DefangIP.mjs";
|
||||
import "./tests/ParseUDP.mjs";
|
||||
import "./tests/ParseTCP.mjs";
|
||||
import "./tests/AvroToJSON.mjs";
|
||||
import "./tests/Lorenz.mjs";
|
||||
import "./tests/LuhnChecksum.mjs";
|
||||
import "./tests/CipherSaber2.mjs";
|
||||
import "./tests/Colossus.mjs";
|
||||
import "./tests/ParseObjectIDTimestamp.mjs";
|
||||
import "./tests/Unicode.mjs";
|
||||
import "./tests/RSA.mjs";
|
||||
import "./tests/CBOREncode.mjs";
|
||||
import "./tests/CBORDecode.mjs";
|
||||
import "./tests/JA3Fingerprint.mjs";
|
||||
import "./tests/JA3SFingerprint.mjs";
|
||||
import "./tests/HASSH.mjs";
|
||||
import "./tests/GetAllCasings.mjs";
|
||||
import "./tests/SIGABA.mjs";
|
||||
import "./tests/ELFInfo.mjs";
|
||||
import "./tests/Subsection.mjs";
|
||||
import "./tests/CaesarBoxCipher.mjs";
|
||||
import "./tests/UnescapeString.mjs";
|
||||
import "./tests/LS47.mjs";
|
||||
import "./tests/LZString.mjs";
|
||||
import "./tests/NTLM.mjs";
|
||||
import "./tests/Shuffle.mjs";
|
||||
import "./tests/FletcherChecksum.mjs";
|
||||
import "./tests/CMAC.mjs";
|
||||
import "./tests/AESKeyWrap.mjs";
|
||||
import "./tests/Rabbit.mjs";
|
||||
|
||||
// Cannot test operations that use the File type yet
|
||||
// import "./tests/SplitColourChannels.mjs";
|
||||
import "./tests/Unicode.mjs";
|
||||
import "./tests/YARA.mjs";
|
||||
|
||||
const testStatus = {
|
||||
allTestsPassing: true,
|
||||
|
||||
89
tests/operations/tests/Base92.mjs
Normal file
89
tests/operations/tests/Base92.mjs
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Base92 tests.
|
||||
*
|
||||
* @author sg5506844 [sg5506844@gmail.com]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "To Base92: nothing",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base92",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base92: Spec encoding example 1",
|
||||
input: "AB",
|
||||
expectedOutput: "8y2",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base92",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base92: Spec encoding example 2",
|
||||
input: "Hello!!",
|
||||
expectedOutput: ";K_$aOTo&",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base92",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base92: Spec encoding example 3",
|
||||
input: "base-92",
|
||||
expectedOutput: "DX2?V<Y(*",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base92",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base92: nothing",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base92",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base92: Spec decoding example 1",
|
||||
input: "G'_DW[B",
|
||||
expectedOutput: "ietf!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base92",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base92: Invalid character",
|
||||
input: "~",
|
||||
expectedOutput: "~ is not a base92 character",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base92",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
22
tests/operations/tests/FileTree.mjs
Normal file
22
tests/operations/tests/FileTree.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* File tree tests.
|
||||
*
|
||||
* @author sw5678
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
"name": "File Tree: basic example",
|
||||
"input": "/test_dir1/test_file1.txt\n/test_dir1/test_file2.txt\n/test_dir2/test_file1.txt",
|
||||
"expectedOutput": "test_dir1\n|---test_file1.txt\n|---test_file2.txt\ntest_dir2\n|---test_file1.txt",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "File Tree",
|
||||
"args": ["/", "Line feed"],
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* To Geohash tests
|
||||
*
|
||||
* @author gchq77703
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "ww8p1r4t8",
|
||||
expectedOutput: "37.83238649368286,112.55838632583618",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "ww8p1r",
|
||||
expectedOutput: "37.83416748046875,112.5604248046875",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "ww8",
|
||||
expectedOutput: "37.265625,113.203125",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "w",
|
||||
expectedOutput: "22.5,112.5",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
183
tests/operations/tests/GOST.mjs
Normal file
183
tests/operations/tests/GOST.mjs
Normal file
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* GOST tests.
|
||||
*
|
||||
* The GOST library already includes a range of tests for the correctness of
|
||||
* the algorithms. These tests are intended only to confirm that the library
|
||||
* has been correctly integrated into CyberChef.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "GOST Encrypt: Magma",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "f124ac5c0853870906dbaf9b56",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Encrypt",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "00112233" },
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"64",
|
||||
"E-SC",
|
||||
"OFB",
|
||||
"CP",
|
||||
"ZERO"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Encrypt: Kuznyechik",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "8673d490dfa4a66d5e3ff00ba316724f",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Encrypt",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "00112233" },
|
||||
{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" },
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"128",
|
||||
"E-SC",
|
||||
"CBC",
|
||||
"CP",
|
||||
"PKCS5"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Decrypt: Magma",
|
||||
input: "f124ac5c0853870906dbaf9b56",
|
||||
expectedOutput: "Hello, World!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Decrypt",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "00112233" },
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Hex",
|
||||
"Raw",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"128",
|
||||
"E-SC",
|
||||
"OFB",
|
||||
"CP",
|
||||
"ZERO"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Decrypt: Kuznyechik",
|
||||
input: "8673d490dfa4a66d5e3ff00ba316724f",
|
||||
expectedOutput: "Hello, World!\0\0\0",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Decrypt",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "00112233" },
|
||||
{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" },
|
||||
"Hex",
|
||||
"Raw",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"128",
|
||||
"E-TEST",
|
||||
"CBC",
|
||||
"CP",
|
||||
"PKCS5"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Sign",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "810d0c40e965",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Sign",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "00112233" },
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"64",
|
||||
"E-C",
|
||||
48
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Verify",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "The signature matches",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Verify",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "00112233" },
|
||||
{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" },
|
||||
{ "option": "Hex", "string": "42b77fb3d6f6bf04" },
|
||||
"Raw",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"128",
|
||||
"E-TEST"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Key Wrap",
|
||||
input: "Hello, World!123",
|
||||
expectedOutput: "0bb706e92487fceef97589911faeb28200000000000000000000000000000000\r\n6b7bfd16",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Key Wrap",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "00112233" },
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"64",
|
||||
"E-TEST",
|
||||
"CP"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Key Unwrap",
|
||||
input: "c8e58458a42d21974d50103d59b469f2c8e58458a42d21974d50103d59b469f2\r\na32a1575",
|
||||
expectedOutput: "0123456789abcdef0123456789abcdef",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST Key Unwrap",
|
||||
args: [
|
||||
{ "option": "Hex", "string": "" },
|
||||
{ "option": "Latin1", "string": "00112233" },
|
||||
"Hex",
|
||||
"Raw",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"64",
|
||||
"E-Z",
|
||||
"CP"
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
]);
|
||||
33
tests/operations/tests/GenerateDeBruijnSequence.mjs
Normal file
33
tests/operations/tests/GenerateDeBruijnSequence.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* De Brujin Sequence tests.
|
||||
*
|
||||
* @author gchq77703 [gchq77703@gchq.gov.uk]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Generate De Bruijn Sequence: Small Sequence",
|
||||
input: "",
|
||||
expectedOutput: "00010111",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Generate De Bruijn Sequence",
|
||||
"args": [2, 3]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Generate De Bruijn Sequence: Long Sequence",
|
||||
input: "",
|
||||
expectedOutput: "0000010000200003000110001200013000210002200023000310003200033001010010200103001110011200113001210012200123001310013200133002010020200203002110021200213002210022200223002310023200233003010030200303003110031200313003210032200323003310033200333010110101201013010210102201023010310103201033011020110301111011120111301121011220112301131011320113301202012030121101212012130122101222012230123101232012330130201303013110131201313013210132201323013310133201333020210202202023020310203202033021030211102112021130212102122021230213102132021330220302211022120221302221022220222302231022320223302303023110231202313023210232202323023310233202333030310303203033031110311203113031210312203123031310313203133032110321203213032210322203223032310323203233033110331203313033210332203323033310333203333111112111131112211123111321113311212112131122211223112321123311312113131132211323113321133312122121231213212133122131222212223122321223312313123221232312332123331313213133132221322313232132331332213323133321333322222322233223232233323233233333",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Generate De Bruijn Sequence",
|
||||
"args": [4, 5]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
180
tests/operations/tests/HKDF.mjs
Normal file
180
tests/operations/tests/HKDF.mjs
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @author mikecat
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 1",
|
||||
"input": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
|
||||
"expectedOutput": "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c"},
|
||||
{"option": "Hex", "string": "f0f1f2f3f4f5f6f7f8f9"},
|
||||
"SHA256", "with salt", 42,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 2",
|
||||
"input": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
|
||||
"expectedOutput": "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"},
|
||||
{"option": "Hex", "string": "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"},
|
||||
"SHA256", "with salt", 82,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 3",
|
||||
"input": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
|
||||
"expectedOutput": "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": ""},
|
||||
{"option": "Hex", "string": ""},
|
||||
"SHA256", "with salt", 42,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 4",
|
||||
"input": "0b0b0b0b0b0b0b0b0b0b0b",
|
||||
"expectedOutput": "085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c"},
|
||||
{"option": "Hex", "string": "f0f1f2f3f4f5f6f7f8f9"},
|
||||
"SHA1", "with salt", 42,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 5",
|
||||
"input": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
|
||||
"expectedOutput": "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"},
|
||||
{"option": "Hex", "string": "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"},
|
||||
"SHA1", "with salt", 82,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 6",
|
||||
"input": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
|
||||
"expectedOutput": "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": ""},
|
||||
{"option": "Hex", "string": ""},
|
||||
"SHA1", "with salt", 42,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 7",
|
||||
"input": "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
|
||||
"expectedOutput": "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": ""},
|
||||
{"option": "Hex", "string": ""},
|
||||
"SHA1", "no salt", 42,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: RFC5869 Test Case 1 with skip extract",
|
||||
"input": "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5",
|
||||
"expectedOutput": "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": ""},
|
||||
{"option": "Hex", "string": "f0f1f2f3f4f5f6f7f8f9"},
|
||||
"SHA256", "skip", 42,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "HKDF: too large L",
|
||||
"input": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
|
||||
"expectedOutput": "L too large (maximum length for SHA256 is 8160)",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"],
|
||||
},
|
||||
{
|
||||
"op": "Derive HKDF key",
|
||||
"args": [
|
||||
{"option": "Hex", "string": "000102030405060708090a0b0c"},
|
||||
{"option": "Hex", "string": "f0f1f2f3f4f5f6f7f8f9"},
|
||||
"SHA256", "with salt", 8161,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -1094,8 +1094,8 @@ TestRegister.addTests([
|
||||
expectedOutput: "981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST hash",
|
||||
args: ["D-A"]
|
||||
op: "GOST Hash",
|
||||
args: ["GOST 28147 (1994)", "256", "D-A"]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1105,11 +1105,11 @@ TestRegister.addTests([
|
||||
expectedOutput: "2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "GOST hash",
|
||||
args: ["D-A"]
|
||||
op: "GOST Hash",
|
||||
args: ["GOST 28147 (1994)", "256", "D-A"]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
/* { // This takes a LONG time to run (over a minute usually).
|
||||
name: "Scrypt: RFC test vector 4",
|
||||
input: "pleaseletmein",
|
||||
@@ -1127,4 +1127,36 @@ TestRegister.addTests([
|
||||
}
|
||||
]
|
||||
}, */
|
||||
{
|
||||
name: "Argon2",
|
||||
input: "argon2password",
|
||||
expectedOutput: "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$s43my9eBljQADuF/LWCG8vGqwAJzOorKQ0Yog8jFvbw",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Argon2",
|
||||
args: [
|
||||
{"option": "UTF8", "string": "somesalt"},
|
||||
3,
|
||||
4096,
|
||||
1,
|
||||
32,
|
||||
"Argon2i",
|
||||
"Encoded hash"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Argon2 compare",
|
||||
input: "argon2password",
|
||||
expectedOutput: "Match: argon2password",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Argon2 compare",
|
||||
args: [
|
||||
"$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$s43my9eBljQADuF/LWCG8vGqwAJzOorKQ0Yog8jFvbw"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
22
tests/operations/tests/LZNT1Decompress.mjs
Normal file
22
tests/operations/tests/LZNT1Decompress.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* LZNT1 Decompress tests.
|
||||
*
|
||||
* @author 0xThiebaut [thiebaut.dev]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "LZNT1 Decompress",
|
||||
input: "\x1a\xb0\x00compress\x00edtestda\x04ta\x07\x88alot",
|
||||
expectedOutput: "compressedtestdatacompressedalot",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "LZNT1 Decompress",
|
||||
args: []
|
||||
}
|
||||
],
|
||||
}
|
||||
]);
|
||||
165
tests/operations/tests/LevenshteinDistance.mjs
Normal file
165
tests/operations/tests/LevenshteinDistance.mjs
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @author mikecat
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
"name": "Levenshtein Distance: Wikipedia example 1",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "3",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1, 1, 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: Wikipedia example 2",
|
||||
"input": "saturday\nsunday",
|
||||
"expectedOutput": "3",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1, 1, 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: Wikipedia example 1 with substitution cost 2",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "5",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1, 1, 2,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: varied costs 1",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "230",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 10, 100, 1000,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: varied costs 2",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "1020",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1000, 100, 10,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: another delimiter",
|
||||
"input": "kitten sitting",
|
||||
"expectedOutput": "3",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
" ", 1, 1, 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: too few samples",
|
||||
"input": "kitten",
|
||||
"expectedOutput": "Incorrect number of samples. Check your input and/or delimiter.",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1, 1, 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: too many samples",
|
||||
"input": "kitten\nsitting\nkitchen",
|
||||
"expectedOutput": "Incorrect number of samples. Check your input and/or delimiter.",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1, 1, 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: negative insertion cost",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "Negative costs are not allowed.",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", -1, 1, 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: negative deletion cost",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "Negative costs are not allowed.",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1, -1, 1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: negative substitution cost",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "Negative costs are not allowed.",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 1, 1, -1,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Levenshtein Distance: cost zero",
|
||||
"input": "kitten\nsitting",
|
||||
"expectedOutput": "0",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Levenshtein Distance",
|
||||
"args": [
|
||||
"\\n", 0, 0, 0,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
77
tests/operations/tests/MurmurHash3.mjs
Normal file
77
tests/operations/tests/MurmurHash3.mjs
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* MurmurHash3 tests
|
||||
* @author AliceGrey [alice@grey.systems]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "To MurmurHash3: nothing",
|
||||
input: "",
|
||||
expectedOutput: "0",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "MurmurHash3",
|
||||
args: [0],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To MurmurHash3: 1",
|
||||
input: "1",
|
||||
expectedOutput: "2484513939",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "MurmurHash3",
|
||||
args: [0],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To MurmurHash3: Hello World!",
|
||||
input: "Hello World!",
|
||||
expectedOutput: "3691591037",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "MurmurHash3",
|
||||
args: [0],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To MurmurHash3: Hello World! with seed",
|
||||
input: "Hello World!",
|
||||
expectedOutput: "1148600031",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "MurmurHash3",
|
||||
args: [1337],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To MurmurHash3: foo",
|
||||
input: "foo",
|
||||
expectedOutput: "4138058784",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "MurmurHash3",
|
||||
args: [0],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To MurmurHash3: foo signed",
|
||||
input: "foo",
|
||||
expectedOutput: "-156908512",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "MurmurHash3",
|
||||
args: [0, true],
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
66
tests/operations/tests/RisonEncodeDecode.mjs
Normal file
66
tests/operations/tests/RisonEncodeDecode.mjs
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @author sg5506844 [sg5506844@gmail.com]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Rison Encode: Encoding example 1",
|
||||
input: JSON.stringify({ any: "json", yes: true }),
|
||||
expectedOutput: "(any:json,yes:!t)",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Rison Encode",
|
||||
args: ["Encode"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Rison Encode: Encoding example 2",
|
||||
input: JSON.stringify({ supportsObjects: true, ints: 435 }),
|
||||
expectedOutput: "ints:435,supportsObjects:!t",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Rison Encode",
|
||||
args: ["Encode Object"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Rison Encode: Encoding example 3",
|
||||
input: JSON.stringify(["A", "B", { supportsObjects: true }]),
|
||||
expectedOutput: "A,B,(supportsObjects:!t)",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Rison Encode",
|
||||
args: ["Encode Array"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Rison Encode: Object for an array",
|
||||
input: JSON.stringify({ supportsObjects: true, ints: 435 }),
|
||||
expectedOutput: "Rison Encode - rison.encode_array expects an array argument",
|
||||
expectedError: "Rison Encode - rison.encode_array expects an array argument",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Rison Encode",
|
||||
args: ["Encode Array"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Rison Decode: Decoding example 1",
|
||||
input: "(any:json,yes:!t)",
|
||||
expectedOutput: JSON.stringify({ any: "json", yes: true }, null, 4),
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Rison Decode",
|
||||
args: ["Decode"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
33
tests/operations/tests/SwapCase.mjs
Normal file
33
tests/operations/tests/SwapCase.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @author mikecat
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
"name": "Swap Case: basic example",
|
||||
"input": "Hello, World!",
|
||||
"expectedOutput": "hELLO, wORLD!",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Swap case",
|
||||
"args": [
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Swap Case: empty input",
|
||||
"input": "",
|
||||
"expectedOutput": "",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Swap case",
|
||||
"args": [
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* To Geohash tests
|
||||
*
|
||||
* @author gchq77703
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "To Geohash",
|
||||
input: "37.8324,112.5584",
|
||||
expectedOutput: "ww8p1r4t8",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Geohash",
|
||||
args: [9],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Geohash",
|
||||
input: "37.9324,-112.2584",
|
||||
expectedOutput: "9w8pv3ruj",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Geohash",
|
||||
args: [9],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Geohash",
|
||||
input: "37.8324,112.5584",
|
||||
expectedOutput: "ww8",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Geohash",
|
||||
args: [3],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Geohash",
|
||||
input: "37.9324,-112.2584",
|
||||
expectedOutput: "9w8pv3rujxy5b99",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Geohash",
|
||||
args: [15],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -114,6 +114,8 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
module: {
|
||||
// argon2-browser loads argon2.wasm by itself, so Webpack should not load it
|
||||
noParse: /argon2\.wasm$/,
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
@@ -133,6 +135,12 @@ module.exports = {
|
||||
additionalCode: "var jQuery = false;"
|
||||
}
|
||||
},
|
||||
{
|
||||
// Load argon2.wasm as base64-encoded binary file expected by argon2-browser
|
||||
test: /argon2\.wasm$/,
|
||||
loader: "base64-loader",
|
||||
type: "javascript/auto"
|
||||
},
|
||||
{
|
||||
test: /prime.worker.min.js$/,
|
||||
type: "asset/source"
|
||||
|
||||
Reference in New Issue
Block a user