mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-09 15:55:01 -04:00
Merge branch 'gchq:master' into master
This commit is contained in:
commit
9e82629470
86 changed files with 22639 additions and 6649 deletions
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"parser": "babel-eslint",
|
"parser": "@babel/eslint-parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 9,
|
"ecmaVersion": 9,
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
|
|
1
.github/workflows/codeql.yml
vendored
1
.github/workflows/codeql.yml
vendored
|
@ -1,6 +1,7 @@
|
||||||
name: "CodeQL Analysis"
|
name: "CodeQL Analysis"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
5
.github/workflows/master.yml
vendored
5
.github/workflows/master.yml
vendored
|
@ -1,6 +1,7 @@
|
||||||
name: "Master Build, Test & Deploy"
|
name: "Master Build, Test & Deploy"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
@ -14,7 +15,7 @@ jobs:
|
||||||
- name: Set node version
|
- name: Set node version
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: '10.x'
|
node-version: '17.x'
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: |
|
run: |
|
||||||
|
@ -27,7 +28,7 @@ jobs:
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: |
|
run: |
|
||||||
npm test
|
npm test
|
||||||
npx grunt testnodeconsumer
|
npm run testnodeconsumer
|
||||||
|
|
||||||
- name: Production Build
|
- name: Production Build
|
||||||
if: success()
|
if: success()
|
||||||
|
|
5
.github/workflows/pull_requests.yml
vendored
5
.github/workflows/pull_requests.yml
vendored
|
@ -1,6 +1,7 @@
|
||||||
name: "Pull Requests"
|
name: "Pull Requests"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [synchronize, opened, reopened]
|
types: [synchronize, opened, reopened]
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ jobs:
|
||||||
- name: Set node version
|
- name: Set node version
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: '10.x'
|
node-version: '17.x'
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: |
|
run: |
|
||||||
|
@ -26,7 +27,7 @@ jobs:
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: |
|
run: |
|
||||||
npm test
|
npm test
|
||||||
npx grunt testnodeconsumer
|
npm run testnodeconsumer
|
||||||
|
|
||||||
- name: Production Build
|
- name: Production Build
|
||||||
if: success()
|
if: success()
|
||||||
|
|
5
.github/workflows/releases.yml
vendored
5
.github/workflows/releases.yml
vendored
|
@ -1,6 +1,7 @@
|
||||||
name: "Releases"
|
name: "Releases"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*'
|
- 'v*'
|
||||||
|
@ -14,7 +15,7 @@ jobs:
|
||||||
- name: Set node version
|
- name: Set node version
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: '10.x'
|
node-version: '17.x'
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: |
|
run: |
|
||||||
|
@ -27,7 +28,7 @@ jobs:
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: |
|
run: |
|
||||||
npm test
|
npm test
|
||||||
npx grunt testnodeconsumer
|
npm run testnodeconsumer
|
||||||
|
|
||||||
- name: Production Build
|
- name: Production Build
|
||||||
if: success()
|
if: success()
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,4 +11,4 @@ src/node/config/OperationConfig.json
|
||||||
src/node/index.mjs
|
src/node/index.mjs
|
||||||
**/*.DS_Store
|
**/*.DS_Store
|
||||||
tests/browser/output/*
|
tests/browser/output/*
|
||||||
|
.node-version
|
||||||
|
|
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
||||||
lts/dubnium
|
17
|
34
CHANGELOG.md
34
CHANGELOG.md
|
@ -13,6 +13,23 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
### [9.37.0] - 2022-03-29
|
||||||
|
- 'SM4 Encrypt' and 'SM4 Decrypt' operations added [@swesven] | [#1189]
|
||||||
|
- NoPadding options added for CBC and ECB modes in AES, DES and Triple DES Decrypt operations [@swesven] | [#1189]
|
||||||
|
|
||||||
|
### [9.36.0] - 2022-03-29
|
||||||
|
- 'SIGABA' operation added [@hettysymes] | [#934]
|
||||||
|
|
||||||
|
### [9.35.0] - 2022-03-28
|
||||||
|
- 'To Base45' and 'From Base45' operations added [@t-8ch] | [#1242]
|
||||||
|
|
||||||
|
### [9.34.0] - 2022-03-28
|
||||||
|
- 'Get All Casings' operation added [@n1073645] | [#1065]
|
||||||
|
|
||||||
|
### [9.33.0] - 2022-03-25
|
||||||
|
- Updated to support Node 17 [@n1474335] [@john19696] [@t-8ch] | [[#1326] [#1313] [#1244]
|
||||||
|
- Improved CJS and ESM module support [@d98762625] | [#1037]
|
||||||
|
|
||||||
### [9.32.0] - 2021-08-18
|
### [9.32.0] - 2021-08-18
|
||||||
- 'Protobuf Encode' operation added and decode operation modified to allow decoding with full and partial schemas [@n1474335] | [dd18e52]
|
- 'Protobuf Encode' operation added and decode operation modified to allow decoding with full and partial schemas [@n1474335] | [dd18e52]
|
||||||
|
|
||||||
|
@ -271,6 +288,11 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0
|
||||||
|
[9.36.0]: https://github.com/gchq/CyberChef/releases/tag/v9.36.0
|
||||||
|
[9.35.0]: https://github.com/gchq/CyberChef/releases/tag/v9.35.0
|
||||||
|
[9.34.0]: https://github.com/gchq/CyberChef/releases/tag/v9.34.0
|
||||||
|
[9.33.0]: https://github.com/gchq/CyberChef/releases/tag/v9.33.0
|
||||||
[9.32.0]: https://github.com/gchq/CyberChef/releases/tag/v9.32.0
|
[9.32.0]: https://github.com/gchq/CyberChef/releases/tag/v9.32.0
|
||||||
[9.31.0]: https://github.com/gchq/CyberChef/releases/tag/v9.31.0
|
[9.31.0]: https://github.com/gchq/CyberChef/releases/tag/v9.31.0
|
||||||
[9.30.0]: https://github.com/gchq/CyberChef/releases/tag/v9.30.0
|
[9.30.0]: https://github.com/gchq/CyberChef/releases/tag/v9.30.0
|
||||||
|
@ -384,6 +406,10 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
[@dmfj]: https://github.com/dmfj
|
[@dmfj]: https://github.com/dmfj
|
||||||
[@mattnotmitt]: https://github.com/mattnotmitt
|
[@mattnotmitt]: https://github.com/mattnotmitt
|
||||||
[@Danh4]: https://github.com/Danh4
|
[@Danh4]: https://github.com/Danh4
|
||||||
|
[@john19696]: https://github.com/john19696
|
||||||
|
[@t-8ch]: https://github.com/t-8ch
|
||||||
|
[@hettysymes]: https://github.com/hettysymes
|
||||||
|
[@swesven]: https://github.com/swesven
|
||||||
|
|
||||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||||
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
|
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
|
||||||
|
@ -458,6 +484,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
[#865]: https://github.com/gchq/CyberChef/pull/865
|
[#865]: https://github.com/gchq/CyberChef/pull/865
|
||||||
[#912]: https://github.com/gchq/CyberChef/pull/912
|
[#912]: https://github.com/gchq/CyberChef/pull/912
|
||||||
[#917]: https://github.com/gchq/CyberChef/pull/917
|
[#917]: https://github.com/gchq/CyberChef/pull/917
|
||||||
|
[#934]: https://github.com/gchq/CyberChef/pull/934
|
||||||
[#948]: https://github.com/gchq/CyberChef/pull/948
|
[#948]: https://github.com/gchq/CyberChef/pull/948
|
||||||
[#952]: https://github.com/gchq/CyberChef/pull/952
|
[#952]: https://github.com/gchq/CyberChef/pull/952
|
||||||
[#965]: https://github.com/gchq/CyberChef/pull/965
|
[#965]: https://github.com/gchq/CyberChef/pull/965
|
||||||
|
@ -466,6 +493,13 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
[#999]: https://github.com/gchq/CyberChef/pull/999
|
[#999]: https://github.com/gchq/CyberChef/pull/999
|
||||||
[#1006]: https://github.com/gchq/CyberChef/pull/1006
|
[#1006]: https://github.com/gchq/CyberChef/pull/1006
|
||||||
[#1022]: https://github.com/gchq/CyberChef/pull/1022
|
[#1022]: https://github.com/gchq/CyberChef/pull/1022
|
||||||
|
[#1037]: https://github.com/gchq/CyberChef/pull/1037
|
||||||
[#1045]: https://github.com/gchq/CyberChef/pull/1045
|
[#1045]: https://github.com/gchq/CyberChef/pull/1045
|
||||||
[#1049]: https://github.com/gchq/CyberChef/pull/1049
|
[#1049]: https://github.com/gchq/CyberChef/pull/1049
|
||||||
|
[#1065]: https://github.com/gchq/CyberChef/pull/1065
|
||||||
[#1083]: https://github.com/gchq/CyberChef/pull/1083
|
[#1083]: https://github.com/gchq/CyberChef/pull/1083
|
||||||
|
[#1189]: https://github.com/gchq/CyberChef/pull/1189
|
||||||
|
[#1242]: https://github.com/gchq/CyberChef/pull/1242
|
||||||
|
[#1244]: https://github.com/gchq/CyberChef/pull/1244
|
||||||
|
[#1313]: https://github.com/gchq/CyberChef/pull/1313
|
||||||
|
[#1326]: https://github.com/gchq/CyberChef/pull/1326
|
97
Gruntfile.js
97
Gruntfile.js
|
@ -6,6 +6,8 @@ const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPl
|
||||||
const glob = require("glob");
|
const glob = require("glob");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
|
const nodeFlags = "--experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings --no-deprecation";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grunt configuration for building the app in various formats.
|
* Grunt configuration for building the app in various formats.
|
||||||
*
|
*
|
||||||
|
@ -48,7 +50,7 @@ module.exports = function (grunt) {
|
||||||
|
|
||||||
grunt.registerTask("testnodeconsumer",
|
grunt.registerTask("testnodeconsumer",
|
||||||
"A task which checks whether consuming CJS and ESM apps work with the CyberChef build",
|
"A task which checks whether consuming CJS and ESM apps work with the CyberChef build",
|
||||||
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:testESMDeepImportNodeConsumer", "exec:teardownNodeConsumers"]);
|
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:teardownNodeConsumers"]);
|
||||||
|
|
||||||
grunt.registerTask("default",
|
grunt.registerTask("default",
|
||||||
"Lints the code base",
|
"Lints the code base",
|
||||||
|
@ -187,9 +189,6 @@ module.exports = function (grunt) {
|
||||||
standalone: ["build/prod/CyberChef*.html"]
|
standalone: ["build/prod/CyberChef*.html"]
|
||||||
},
|
},
|
||||||
eslint: {
|
eslint: {
|
||||||
options: {
|
|
||||||
configFile: "./.eslintrc.json"
|
|
||||||
},
|
|
||||||
configs: ["*.{js,mjs}"],
|
configs: ["*.{js,mjs}"],
|
||||||
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
|
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
|
||||||
web: ["src/web/**/*.{js,mjs}", "!src/web/static/**/*"],
|
web: ["src/web/**/*.{js,mjs}", "!src/web/static/**/*"],
|
||||||
|
@ -201,50 +200,35 @@ module.exports = function (grunt) {
|
||||||
web: webpackProdConf(),
|
web: webpackProdConf(),
|
||||||
},
|
},
|
||||||
"webpack-dev-server": {
|
"webpack-dev-server": {
|
||||||
options: {
|
options: webpackConfig,
|
||||||
webpack: webpackConfig,
|
|
||||||
host: "0.0.0.0",
|
|
||||||
port: grunt.option("port") || 8080,
|
|
||||||
disableHostCheck: true,
|
|
||||||
overlay: true,
|
|
||||||
inline: false,
|
|
||||||
clientLogLevel: "error",
|
|
||||||
stats: {
|
|
||||||
children: false,
|
|
||||||
chunks: false,
|
|
||||||
modules: false,
|
|
||||||
entrypoints: false,
|
|
||||||
warningsFilter: [
|
|
||||||
/source-map/,
|
|
||||||
/dependency is an expression/,
|
|
||||||
/export 'default'/,
|
|
||||||
/Can't resolve 'sodium'/
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
start: {
|
start: {
|
||||||
webpack: {
|
mode: "development",
|
||||||
mode: "development",
|
target: "web",
|
||||||
target: "web",
|
entry: Object.assign({
|
||||||
entry: Object.assign({
|
main: "./src/web/index.js"
|
||||||
main: "./src/web/index.js"
|
}, moduleEntryPoints),
|
||||||
}, moduleEntryPoints),
|
resolve: {
|
||||||
resolve: {
|
alias: {
|
||||||
alias: {
|
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
|
||||||
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
|
}
|
||||||
}
|
},
|
||||||
},
|
devServer: {
|
||||||
plugins: [
|
port: grunt.option("port") || 8080,
|
||||||
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
client: {
|
||||||
new HtmlWebpackPlugin({
|
logging: "error",
|
||||||
filename: "index.html",
|
overlay: true
|
||||||
template: "./src/web/html/index.html",
|
}
|
||||||
chunks: ["main"],
|
},
|
||||||
compileTime: compileTime,
|
plugins: [
|
||||||
version: pkg.version,
|
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
||||||
})
|
new HtmlWebpackPlugin({
|
||||||
]
|
filename: "index.html",
|
||||||
}
|
template: "./src/web/html/index.html",
|
||||||
|
chunks: ["main"],
|
||||||
|
compileTime: compileTime,
|
||||||
|
version: pkg.version,
|
||||||
|
})
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
zip: {
|
zip: {
|
||||||
|
@ -349,15 +333,15 @@ module.exports = function (grunt) {
|
||||||
command: "git gc --prune=now --aggressive"
|
command: "git gc --prune=now --aggressive"
|
||||||
},
|
},
|
||||||
sitemap: {
|
sitemap: {
|
||||||
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml",
|
command: `node ${nodeFlags} src/web/static/sitemap.mjs > build/prod/sitemap.xml`,
|
||||||
sync: true
|
sync: true
|
||||||
},
|
},
|
||||||
generateConfig: {
|
generateConfig: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
"echo '\n--- Regenerating config files. ---'",
|
"echo '\n--- Regenerating config files. ---'",
|
||||||
"echo [] > src/core/config/OperationConfig.json",
|
"echo [] > src/core/config/OperationConfig.json",
|
||||||
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
|
`node ${nodeFlags} src/core/config/scripts/generateOpsIndex.mjs`,
|
||||||
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
|
`node ${nodeFlags} src/core/config/scripts/generateConfig.mjs`,
|
||||||
"echo '--- Config scripts finished. ---\n'"
|
"echo '--- Config scripts finished. ---\n'"
|
||||||
]),
|
]),
|
||||||
sync: true
|
sync: true
|
||||||
|
@ -365,7 +349,7 @@ module.exports = function (grunt) {
|
||||||
generateNodeIndex: {
|
generateNodeIndex: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
"echo '\n--- Regenerating node index ---'",
|
"echo '\n--- Regenerating node index ---'",
|
||||||
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
|
`node ${nodeFlags} src/node/config/scripts/generateNodeIndex.mjs`,
|
||||||
"echo '--- Node index generated. ---\n'"
|
"echo '--- Node index generated. ---\n'"
|
||||||
]),
|
]),
|
||||||
sync: true
|
sync: true
|
||||||
|
@ -393,21 +377,14 @@ module.exports = function (grunt) {
|
||||||
testCJSNodeConsumer: {
|
testCJSNodeConsumer: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
`cd ${nodeConsumerTestPath}`,
|
`cd ${nodeConsumerTestPath}`,
|
||||||
"node --no-warnings cjs-consumer.js",
|
`node ${nodeFlags} cjs-consumer.js`,
|
||||||
]),
|
]),
|
||||||
stdout: false,
|
stdout: false,
|
||||||
},
|
},
|
||||||
testESMNodeConsumer: {
|
testESMNodeConsumer: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
`cd ${nodeConsumerTestPath}`,
|
`cd ${nodeConsumerTestPath}`,
|
||||||
"node --no-warnings --experimental-modules esm-consumer.mjs",
|
`node ${nodeFlags} esm-consumer.mjs`,
|
||||||
]),
|
|
||||||
stdout: false,
|
|
||||||
},
|
|
||||||
testESMDeepImportNodeConsumer: {
|
|
||||||
command: chainCommands([
|
|
||||||
`cd ${nodeConsumerTestPath}`,
|
|
||||||
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
|
|
||||||
]),
|
]),
|
||||||
stdout: false,
|
stdout: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
[](https://github.com/gchq/CyberChef/actions?query=workflow%3A%22Master+Build%2C+Test+%26+Deploy%22)
|
[](https://github.com/gchq/CyberChef/actions?query=workflow%3A%22Master+Build%2C+Test+%26+Deploy%22)
|
||||||
[](https://lgtm.com/projects/g/gchq/CyberChef/context:javascript)
|
[](https://lgtm.com/projects/g/gchq/CyberChef/context:javascript)
|
||||||
[](https://david-dm.org/gchq/CyberChef)
|
|
||||||
[](https://www.npmjs.com/package/cyberchef)
|
[](https://www.npmjs.com/package/cyberchef)
|
||||||
[](https://github.com/gchq/CyberChef/blob/master/LICENSE)
|
[](https://github.com/gchq/CyberChef/blob/master/LICENSE)
|
||||||
[](https://gitter.im/gchq/CyberChef?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
[](https://gitter.im/gchq/CyberChef?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
@ -10,7 +9,7 @@
|
||||||
|
|
||||||
#### *The Cyber Swiss Army Knife*
|
#### *The Cyber Swiss Army Knife*
|
||||||
|
|
||||||
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
|
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR and Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
|
||||||
|
|
||||||
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years.
|
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years.
|
||||||
|
|
||||||
|
@ -106,7 +105,7 @@ An installation walkthrough, how-to guides for adding new operations and themes,
|
||||||
|
|
||||||
## Licencing
|
## Licencing
|
||||||
|
|
||||||
CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/licenses/LICENSE-2.0) and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/copyright-and-re-use/crown-copyright/).
|
CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/licenses/LICENSE-2.0) and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/).
|
||||||
|
|
||||||
|
|
||||||
[1]: https://gchq.github.io/CyberChef
|
[1]: https://gchq.github.io/CyberChef
|
||||||
|
|
|
@ -11,6 +11,7 @@ module.exports = function(api) {
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"dynamic-import-node",
|
"dynamic-import-node",
|
||||||
|
"@babel/plugin-syntax-import-assertions",
|
||||||
[
|
[
|
||||||
"babel-plugin-transform-builtin-extend", {
|
"babel-plugin-transform-builtin-extend", {
|
||||||
"globals": ["Error"]
|
"globals": ["Error"]
|
||||||
|
|
|
@ -10,11 +10,12 @@
|
||||||
"start_process": true,
|
"start_process": true,
|
||||||
"server_path": "./node_modules/.bin/chromedriver",
|
"server_path": "./node_modules/.bin/chromedriver",
|
||||||
"port": 9515,
|
"port": 9515,
|
||||||
"log_path": false
|
"log_path": "tests/browser/output"
|
||||||
},
|
},
|
||||||
"desiredCapabilities": {
|
"desiredCapabilities": {
|
||||||
"browserName": "chrome"
|
"browserName": "chrome"
|
||||||
}
|
},
|
||||||
|
"enable_fail_fast": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"dev": {
|
"dev": {
|
||||||
|
|
25849
package-lock.json
generated
25849
package-lock.json
generated
File diff suppressed because it is too large
Load diff
116
package.json
116
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "9.32.3",
|
"version": "9.37.3",
|
||||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||||
"author": "n1474335 <n1474335@gmail.com>",
|
"author": "n1474335 <n1474335@gmail.com>",
|
||||||
"homepage": "https://gchq.github.io/CyberChef",
|
"homepage": "https://gchq.github.io/CyberChef",
|
||||||
|
@ -27,30 +27,34 @@
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/gchq/CyberChef/"
|
"url": "https://github.com/gchq/CyberChef/"
|
||||||
},
|
},
|
||||||
"main": "src/node/cjs.js",
|
"main": "src/node/wrapper.js",
|
||||||
"module": "src/node/index.mjs",
|
"exports": {
|
||||||
|
"import": "./src/node/index.mjs",
|
||||||
|
"require": "./src/node/wrapper.js"
|
||||||
|
},
|
||||||
"bugs": "https://github.com/gchq/CyberChef/issues",
|
"bugs": "https://github.com/gchq/CyberChef/issues",
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"Chrome >= 50",
|
"Chrome >= 50",
|
||||||
"Firefox >= 38",
|
"Firefox >= 38",
|
||||||
"node >= 10"
|
"node >= 16"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.15.0",
|
"@babel/core": "^7.17.8",
|
||||||
"@babel/plugin-transform-runtime": "^7.15.0",
|
"@babel/eslint-parser": "^7.17.0",
|
||||||
"@babel/preset-env": "^7.15.0",
|
"@babel/plugin-syntax-import-assertions": "^7.16.7",
|
||||||
"autoprefixer": "^10.3.1",
|
"@babel/plugin-transform-runtime": "^7.17.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"@babel/preset-env": "^7.16.11",
|
||||||
"babel-loader": "^8.2.2",
|
"@babel/runtime": "^7.17.8",
|
||||||
|
"autoprefixer": "^10.4.4",
|
||||||
|
"babel-loader": "^8.2.4",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
"chromedriver": "^92.0.1",
|
"chromedriver": "^99.0.0",
|
||||||
"cli-progress": "^3.9.0",
|
"cli-progress": "^3.10.0",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"copy-webpack-plugin": "^9.0.1",
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
"css-loader": "5.2.7",
|
"core-js": "^3.21.1",
|
||||||
"eslint": "^7.32.0",
|
"css-loader": "6.7.1",
|
||||||
"exports-loader": "^3.0.0",
|
"eslint": "^8.12.0",
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"grunt": "^1.4.1",
|
"grunt": "^1.4.1",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
"grunt-concurrent": "^3.0.0",
|
"grunt-concurrent": "^3.0.0",
|
||||||
|
@ -58,66 +62,60 @@
|
||||||
"grunt-contrib-connect": "^3.0.0",
|
"grunt-contrib-connect": "^3.0.0",
|
||||||
"grunt-contrib-copy": "~1.0.0",
|
"grunt-contrib-copy": "~1.0.0",
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
"grunt-eslint": "^23.0.0",
|
"grunt-eslint": "^24.0.0",
|
||||||
"grunt-exec": "~3.0.0",
|
"grunt-exec": "~3.0.0",
|
||||||
"grunt-webpack": "^4.0.3",
|
"grunt-webpack": "^5.0.0",
|
||||||
"grunt-zip": "^0.18.2",
|
"grunt-zip": "^0.18.2",
|
||||||
"html-webpack-plugin": "^5.3.2",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"imports-loader": "^3.0.0",
|
"imports-loader": "^3.1.1",
|
||||||
"mini-css-extract-plugin": "1.3.7",
|
"mini-css-extract-plugin": "2.6.0",
|
||||||
"nightwatch": "^1.7.8",
|
"nightwatch": "^2.0.10",
|
||||||
"node-sass": "^5.0.0",
|
"postcss": "^8.4.12",
|
||||||
"postcss": "^8.3.6",
|
|
||||||
"postcss-css-variables": "^0.18.0",
|
"postcss-css-variables": "^0.18.0",
|
||||||
"postcss-import": "^14.0.2",
|
"postcss-import": "^14.1.0",
|
||||||
"postcss-loader": "^6.1.1",
|
"postcss-loader": "^6.2.1",
|
||||||
"prompt": "^1.1.0",
|
"prompt": "^1.2.2",
|
||||||
"sass-loader": "^12.1.0",
|
"sass-loader": "^12.6.0",
|
||||||
"sitemap": "^7.0.0",
|
"sitemap": "^7.1.1",
|
||||||
"style-loader": "^3.2.1",
|
"terser": "^5.12.1",
|
||||||
"svg-url-loader": "^7.1.1",
|
"webpack": "^5.70.0",
|
||||||
"url-loader": "^4.1.1",
|
"webpack-bundle-analyzer": "^4.5.0",
|
||||||
"webpack": "^5.51.0",
|
"webpack-dev-server": "4.7.4",
|
||||||
"webpack-bundle-analyzer": "^4.4.2",
|
|
||||||
"webpack-dev-server": "3.11.2",
|
|
||||||
"webpack-node-externals": "^3.0.0",
|
"webpack-node-externals": "^3.0.0",
|
||||||
"worker-loader": "^3.0.8"
|
"worker-loader": "^3.0.8"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.12.1",
|
"@babel/polyfill": "^7.12.1",
|
||||||
"@babel/runtime": "^7.15.3",
|
|
||||||
"arrive": "^2.4.1",
|
"arrive": "^2.4.1",
|
||||||
"avsc": "^5.7.3",
|
"avsc": "^5.7.3",
|
||||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bignumber.js": "^9.0.1",
|
"bignumber.js": "^9.0.2",
|
||||||
"blakejs": "^1.1.1",
|
"blakejs": "^1.2.1",
|
||||||
"bootstrap": "4.6.0",
|
"bootstrap": "4.6.1",
|
||||||
"bootstrap-colorpicker": "^3.4.0",
|
"bootstrap-colorpicker": "^3.4.0",
|
||||||
"bootstrap-material-design": "^4.1.3",
|
"bootstrap-material-design": "^4.1.3",
|
||||||
"browserify-zlib": "^0.2.0",
|
"browserify-zlib": "^0.2.0",
|
||||||
"bson": "^4.4.1",
|
"bson": "^4.6.2",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"cbor": "5.0.1",
|
"cbor": "8.1.0",
|
||||||
"chi-squared": "^1.1.0",
|
"chi-squared": "^1.1.0",
|
||||||
"codepage": "^1.15.0",
|
"codepage": "^1.15.0",
|
||||||
"core-js": "^3.16.2",
|
|
||||||
"crypto-api": "^0.8.5",
|
"crypto-api": "^0.8.5",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"ctph.js": "0.0.5",
|
"ctph.js": "0.0.5",
|
||||||
"d3": "6.5.0",
|
"d3": "7.3.0",
|
||||||
"d3-hexbin": "^0.2.2",
|
"d3-hexbin": "^0.2.2",
|
||||||
"diff": "^5.0.0",
|
"diff": "^5.0.0",
|
||||||
"es6-promisify": "^7.0.0",
|
"es6-promisify": "^7.0.0",
|
||||||
"escodegen": "^2.0.0",
|
"escodegen": "^2.0.0",
|
||||||
"esm": "^3.2.25",
|
|
||||||
"esprima": "^4.0.1",
|
"esprima": "^4.0.1",
|
||||||
"exif-parser": "^0.1.12",
|
"exif-parser": "^0.1.12",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"flat": "^5.0.2",
|
"flat": "^5.0.2",
|
||||||
"geodesy": "1.1.3",
|
"geodesy": "1.1.3",
|
||||||
"highlight.js": "^11.2.0",
|
"highlight.js": "^11.5.0",
|
||||||
"jimp": "^0.16.1",
|
"jimp": "^0.16.1",
|
||||||
"jquery": "3.6.0",
|
"jquery": "3.6.0",
|
||||||
"js-crc": "^0.2.0",
|
"js-crc": "^0.2.0",
|
||||||
|
@ -126,19 +124,20 @@
|
||||||
"jsonpath": "^1.1.1",
|
"jsonpath": "^1.1.1",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
"jsrsasign": "^10.4.0",
|
"jsrsasign": "^10.5.14",
|
||||||
"kbpgp": "2.1.15",
|
"kbpgp": "2.1.15",
|
||||||
"libbzip2-wasm": "0.0.4",
|
"libbzip2-wasm": "0.0.4",
|
||||||
"libyara-wasm": "^1.1.0",
|
"libyara-wasm": "^1.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"loglevel": "^1.7.1",
|
"loglevel": "^1.8.0",
|
||||||
"loglevel-message-prefix": "^3.0.0",
|
"loglevel-message-prefix": "^3.0.0",
|
||||||
"markdown-it": "^12.2.0",
|
"markdown-it": "^12.3.2",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"moment-timezone": "^0.5.33",
|
"moment-timezone": "^0.5.34",
|
||||||
"ngeohash": "^0.6.3",
|
"ngeohash": "^0.6.3",
|
||||||
"node-forge": "^0.10.0",
|
"node-forge": "^1.3.0",
|
||||||
"node-md6": "^0.1.0",
|
"node-md6": "^0.1.0",
|
||||||
|
"node-sass": "^7.0.1",
|
||||||
"nodom": "^2.4.0",
|
"nodom": "^2.4.0",
|
||||||
"notepack.io": "^2.3.0",
|
"notepack.io": "^2.3.0",
|
||||||
"nwmatcher": "^1.4.4",
|
"nwmatcher": "^1.4.4",
|
||||||
|
@ -150,13 +149,12 @@
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"scryptsy": "^2.1.0",
|
"scryptsy": "^2.1.0",
|
||||||
"snackbarjs": "^1.1.0",
|
"snackbarjs": "^1.1.0",
|
||||||
"sortablejs": "^1.14.0",
|
"sortablejs": "^1.15.0",
|
||||||
"split.js": "^1.6.4",
|
"split.js": "^1.6.5",
|
||||||
"ssdeep.js": "0.0.3",
|
"ssdeep.js": "0.0.3",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"terser": "^5.7.1",
|
|
||||||
"tesseract.js": "2.1.5",
|
"tesseract.js": "2.1.5",
|
||||||
"ua-parser-js": "^0.7.28",
|
"ua-parser-js": "^1.0.2",
|
||||||
"unorm": "^1.6.0",
|
"unorm": "^1.6.0",
|
||||||
"utf8": "^3.0.0",
|
"utf8": "^3.0.0",
|
||||||
"vkbeautify": "^0.99.3",
|
"vkbeautify": "^0.99.3",
|
||||||
|
@ -168,14 +166,14 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npx grunt dev",
|
"start": "npx grunt dev",
|
||||||
"build": "npx grunt prod",
|
"build": "npx grunt prod",
|
||||||
"repl": "node src/node/repl.js",
|
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings src/node/repl.mjs",
|
||||||
"test": "npx grunt configTests && node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs",
|
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/operations/index.mjs",
|
||||||
"test-node-consumer": "npx grunt testnodeconsumer",
|
"testnodeconsumer": "npx grunt testnodeconsumer",
|
||||||
"testui": "npx grunt testui",
|
"testui": "npx grunt testui",
|
||||||
"testuidev": "npx nightwatch --env=dev",
|
"testuidev": "npx nightwatch --env=dev",
|
||||||
"lint": "npx grunt lint",
|
"lint": "npx grunt lint",
|
||||||
"postinstall": "npx grunt exec:fixCryptoApiImports",
|
"postinstall": "npx grunt exec:fixCryptoApiImports",
|
||||||
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs",
|
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
|
||||||
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
|
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
|
||||||
"setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048"
|
"setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048"
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Chef from "./Chef.mjs";
|
import Chef from "./Chef.mjs";
|
||||||
import OperationConfig from "./config/OperationConfig.json";
|
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
|
||||||
import OpModules from "./config/modules/OpModules.mjs";
|
import OpModules from "./config/modules/OpModules.mjs";
|
||||||
|
|
||||||
// Add ">" to the start of all log messages in the Chef Worker
|
// Add ">" to the start of all log messages in the Chef Worker
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import OperationConfig from "./config/OperationConfig.json";
|
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
|
||||||
import OperationError from "./errors/OperationError.mjs";
|
import OperationError from "./errors/OperationError.mjs";
|
||||||
import Operation from "./Operation.mjs";
|
import Operation from "./Operation.mjs";
|
||||||
import DishError from "./errors/DishError.mjs";
|
import DishError from "./errors/DishError.mjs";
|
||||||
|
|
|
@ -723,7 +723,8 @@ class Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (removeScriptAndStyle) {
|
if (removeScriptAndStyle) {
|
||||||
htmlStr = recursiveRemove(/<(script|style)[^>]*>.*?<\/(script|style)>/gi, htmlStr);
|
htmlStr = recursiveRemove(/<script[^>]*>.*?<\/script[^>]*>/gi, htmlStr);
|
||||||
|
htmlStr = recursiveRemove(/<style[^>]*>.*?<\/style[^>]*>/gi, htmlStr);
|
||||||
}
|
}
|
||||||
return htmlStr.replace(/<[^>]+>/g, "");
|
return htmlStr.replace(/<[^>]+>/g, "");
|
||||||
}
|
}
|
||||||
|
@ -1206,6 +1207,30 @@ class Utils {
|
||||||
}[token];
|
}[token];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate object in chunks of given size.
|
||||||
|
*
|
||||||
|
* @param {Iterable} iterable
|
||||||
|
* @param {number} chunksize
|
||||||
|
*/
|
||||||
|
static* chunked(iterable, chunksize) {
|
||||||
|
const iterator = iterable[Symbol.iterator]();
|
||||||
|
while (true) {
|
||||||
|
const res = [];
|
||||||
|
for (let i = 0; i < chunksize; i++) {
|
||||||
|
const next = iterator.next();
|
||||||
|
if (next.done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res.push(next.value);
|
||||||
|
}
|
||||||
|
if (res.length) {
|
||||||
|
yield res;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
"From Octal",
|
"From Octal",
|
||||||
"To Base32",
|
"To Base32",
|
||||||
"From Base32",
|
"From Base32",
|
||||||
|
"To Base45",
|
||||||
|
"From Base45",
|
||||||
"To Base58",
|
"To Base58",
|
||||||
"From Base58",
|
"From Base58",
|
||||||
"To Base62",
|
"To Base62",
|
||||||
|
@ -81,6 +83,8 @@
|
||||||
"RC2 Decrypt",
|
"RC2 Decrypt",
|
||||||
"RC4",
|
"RC4",
|
||||||
"RC4 Drop",
|
"RC4 Drop",
|
||||||
|
"SM4 Encrypt",
|
||||||
|
"SM4 Decrypt",
|
||||||
"ROT13",
|
"ROT13",
|
||||||
"ROT47",
|
"ROT47",
|
||||||
"XOR",
|
"XOR",
|
||||||
|
@ -118,7 +122,8 @@
|
||||||
"Multiple Bombe",
|
"Multiple Bombe",
|
||||||
"Typex",
|
"Typex",
|
||||||
"Lorenz",
|
"Lorenz",
|
||||||
"Colossus"
|
"Colossus",
|
||||||
|
"SIGABA"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -230,6 +235,7 @@
|
||||||
"From Case Insensitive Regex",
|
"From Case Insensitive Regex",
|
||||||
"Add line numbers",
|
"Add line numbers",
|
||||||
"Remove line numbers",
|
"Remove line numbers",
|
||||||
|
"Get All Casings",
|
||||||
"To Table",
|
"To Table",
|
||||||
"Reverse",
|
"Reverse",
|
||||||
"Sort",
|
"Sort",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import OperationError from "./OperationError.mjs";
|
import OperationError from "./OperationError.mjs";
|
||||||
import DishError from "./DishError.mjs";
|
import DishError from "./DishError.mjs";
|
||||||
import ExcludedOperationError from "./ExcludedOperationError";
|
import ExcludedOperationError from "./ExcludedOperationError.mjs";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
OperationError,
|
OperationError,
|
||||||
|
|
27
src/core/lib/Base45.mjs
Normal file
27
src/core/lib/Base45.mjs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* Base45 resources.
|
||||||
|
*
|
||||||
|
* @author Thomas Weißschuh [thomas@t-8ch.de]
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlight to Base45
|
||||||
|
*/
|
||||||
|
export function highlightToBase45(pos, args) {
|
||||||
|
pos[0].start = Math.floor(pos[0].start / 2) * 3;
|
||||||
|
pos[0].end = Math.ceil(pos[0].end / 2) * 3;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlight from Base45
|
||||||
|
*/
|
||||||
|
export function highlightFromBase45(pos, args) {
|
||||||
|
pos[0].start = Math.floor(pos[0].start / 3) * 2;
|
||||||
|
pos[0].end = Math.ceil(pos[0].end / 3) * 2;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ALPHABET = "0-9A-Z $%*+\\-./:";
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constant
|
* @constant
|
||||||
|
@ -128,7 +129,7 @@ export function getScatterValuesWithColour(input, recordDelimiter, fieldDelimite
|
||||||
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
|
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
|
||||||
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
|
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
|
||||||
|
|
||||||
return [x, y, colour];
|
return [x, y, Utils.escapeHtml(colour)];
|
||||||
});
|
});
|
||||||
|
|
||||||
return { headings, values };
|
return { headings, values };
|
||||||
|
|
|
@ -12,15 +12,15 @@
|
||||||
*
|
*
|
||||||
* @param {string} input
|
* @param {string} input
|
||||||
* @param {RegExp} searchRegex
|
* @param {RegExp} searchRegex
|
||||||
* @param {RegExp} removeRegex - A regular expression defining results to remove from the
|
* @param {RegExp} [removeRegex=null] - A regular expression defining results to remove from the
|
||||||
* final list
|
* final list
|
||||||
* @param {boolean} includeTotal - Whether or not to include the total number of results
|
* @param {Function} [sortBy=null] - The sorting comparison function to apply
|
||||||
|
* @param {boolean} [unique=false] - Whether to unique the results
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function search (input, searchRegex, removeRegex, includeTotal) {
|
export function search(input, searchRegex, removeRegex=null, sortBy=null, unique=false) {
|
||||||
let output = "",
|
let results = [];
|
||||||
total = 0,
|
let match;
|
||||||
match;
|
|
||||||
|
|
||||||
while ((match = searchRegex.exec(input))) {
|
while ((match = searchRegex.exec(input))) {
|
||||||
// Moves pointer when an empty string is matched (prevents infinite loop)
|
// Moves pointer when an empty string is matched (prevents infinite loop)
|
||||||
|
@ -30,14 +30,19 @@ export function search (input, searchRegex, removeRegex, includeTotal) {
|
||||||
|
|
||||||
if (removeRegex && removeRegex.test(match[0]))
|
if (removeRegex && removeRegex.test(match[0]))
|
||||||
continue;
|
continue;
|
||||||
total++;
|
|
||||||
output += match[0] + "\n";
|
results.push(match[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeTotal)
|
if (sortBy) {
|
||||||
output = "Total found: " + total + "\n\n" + output;
|
results = results.sort(sortBy);
|
||||||
|
}
|
||||||
|
|
||||||
return output;
|
if (unique) {
|
||||||
|
results = results.unique();
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import OperationConfig from "../config/OperationConfig.json";
|
import OperationConfig from "../config/OperationConfig.json" assert {type: "json"};
|
||||||
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
|
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import Recipe from "../Recipe.mjs";
|
import Recipe from "../Recipe.mjs";
|
||||||
import Dish from "../Dish.mjs";
|
import Dish from "../Dish.mjs";
|
||||||
|
|
502
src/core/lib/SIGABA.mjs
Normal file
502
src/core/lib/SIGABA.mjs
Normal file
|
@ -0,0 +1,502 @@
|
||||||
|
/**
|
||||||
|
* Emulation of the SIGABA machine
|
||||||
|
*
|
||||||
|
* @author hettysymes
|
||||||
|
* @copyright hettysymes 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of randomised example SIGABA cipher/control rotors (these rotors are interchangeable). Cipher and control rotors can be referred to as C and R rotors respectively.
|
||||||
|
*/
|
||||||
|
export const CR_ROTORS = [
|
||||||
|
{name: "Example 1", value: "SRGWANHPJZFXVIDQCEUKBYOLMT"},
|
||||||
|
{name: "Example 2", value: "THQEFSAZVKJYULBODCPXNIMWRG"},
|
||||||
|
{name: "Example 3", value: "XDTUYLEVFNQZBPOGIRCSMHWKAJ"},
|
||||||
|
{name: "Example 4", value: "LOHDMCWUPSTNGVXYFJREQIKBZA"},
|
||||||
|
{name: "Example 5", value: "ERXWNZQIJYLVOFUMSGHTCKPBDA"},
|
||||||
|
{name: "Example 6", value: "FQECYHJIOUMDZVPSLKRTGWXBAN"},
|
||||||
|
{name: "Example 7", value: "TBYIUMKZDJSOPEWXVANHLCFQGR"},
|
||||||
|
{name: "Example 8", value: "QZUPDTFNYIAOMLEBWJXCGHKRSV"},
|
||||||
|
{name: "Example 9", value: "CZWNHEMPOVXLKRSIDGJFYBTQAU"},
|
||||||
|
{name: "Example 10", value: "ENPXJVKYQBFZTICAGMOHWRLDUS"}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of randomised example SIGABA index rotors (may be referred to as I rotors).
|
||||||
|
*/
|
||||||
|
export const I_ROTORS = [
|
||||||
|
{name: "Example 1", value: "6201348957"},
|
||||||
|
{name: "Example 2", value: "6147253089"},
|
||||||
|
{name: "Example 3", value: "8239647510"},
|
||||||
|
{name: "Example 4", value: "7194835260"},
|
||||||
|
{name: "Example 5", value: "4873205916"}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const NUMBERS = "0123456789".split("");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a letter to uppercase (if it already isn't)
|
||||||
|
*
|
||||||
|
* @param {char} letter - letter to convert to uppercase
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
export function convToUpperCase(letter) {
|
||||||
|
const charCode = letter.charCodeAt();
|
||||||
|
if (97<=charCode && charCode<=122) {
|
||||||
|
return String.fromCharCode(charCode-32);
|
||||||
|
}
|
||||||
|
return letter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SIGABA machine consisting of the 3 rotor banks: cipher, control and index banks.
|
||||||
|
*/
|
||||||
|
export class SigabaMachine {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SigabaMachine constructor
|
||||||
|
*
|
||||||
|
* @param {Object[]} cipherRotors - list of CRRotors
|
||||||
|
* @param {Object[]} controlRotors - list of CRRotors
|
||||||
|
* @param {object[]} indexRotors - list of IRotors
|
||||||
|
*/
|
||||||
|
constructor(cipherRotors, controlRotors, indexRotors) {
|
||||||
|
this.cipherBank = new CipherBank(cipherRotors);
|
||||||
|
this.controlBank = new ControlBank(controlRotors);
|
||||||
|
this.indexBank = new IndexBank(indexRotors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steps all the correct rotors in the machine.
|
||||||
|
*/
|
||||||
|
step() {
|
||||||
|
const controlOut = this.controlBank.goThroughControl();
|
||||||
|
const indexOut = this.indexBank.goThroughIndex(controlOut);
|
||||||
|
this.cipherBank.step(indexOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a letter. A space is converted to a "Z" before encryption, and a "Z" is converted to an "X". This allows spaces to be encrypted.
|
||||||
|
*
|
||||||
|
* @param {char} letter - letter to encrypt
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
encryptLetter(letter) {
|
||||||
|
letter = convToUpperCase(letter);
|
||||||
|
if (letter === " ") {
|
||||||
|
letter = "Z";
|
||||||
|
} else if (letter === "Z") {
|
||||||
|
letter = "X";
|
||||||
|
}
|
||||||
|
const encryptedLetter = this.cipherBank.encrypt(letter);
|
||||||
|
this.step();
|
||||||
|
return encryptedLetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a letter. A letter decrypted as a "Z" is converted to a space before it is output, since spaces are converted to "Z"s before encryption.
|
||||||
|
*
|
||||||
|
* @param {char} letter - letter to decrypt
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
decryptLetter(letter) {
|
||||||
|
letter = convToUpperCase(letter);
|
||||||
|
let decryptedLetter = this.cipherBank.decrypt(letter);
|
||||||
|
if (decryptedLetter === "Z") {
|
||||||
|
decryptedLetter = " ";
|
||||||
|
}
|
||||||
|
this.step();
|
||||||
|
return decryptedLetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a message of one or more letters
|
||||||
|
*
|
||||||
|
* @param {string} msg - message to encrypt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
encrypt(msg) {
|
||||||
|
let ciphertext = "";
|
||||||
|
for (const letter of msg) {
|
||||||
|
ciphertext = ciphertext.concat(this.encryptLetter(letter));
|
||||||
|
}
|
||||||
|
return ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a message of one or more letters
|
||||||
|
*
|
||||||
|
* @param {string} msg - message to decrypt
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
decrypt(msg) {
|
||||||
|
let plaintext = "";
|
||||||
|
for (const letter of msg) {
|
||||||
|
plaintext = plaintext.concat(this.decryptLetter(letter));
|
||||||
|
}
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cipher rotor bank consists of 5 cipher rotors in either a forward or reversed orientation.
|
||||||
|
*/
|
||||||
|
export class CipherBank {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CipherBank constructor
|
||||||
|
*
|
||||||
|
* @param {Object[]} rotors - list of CRRotors
|
||||||
|
*/
|
||||||
|
constructor(rotors) {
|
||||||
|
this.rotors = rotors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a letter through the cipher rotors (signal goes from left-to-right)
|
||||||
|
*
|
||||||
|
* @param {char} inputPos - the input position of the signal (letter to be encrypted)
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
encrypt(inputPos) {
|
||||||
|
for (const rotor of this.rotors) {
|
||||||
|
inputPos = rotor.crypt(inputPos, "leftToRight");
|
||||||
|
}
|
||||||
|
return inputPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a letter through the cipher rotors (signal goes from right-to-left)
|
||||||
|
*
|
||||||
|
* @param {char} inputPos - the input position of the signal (letter to be decrypted)
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
decrypt(inputPos) {
|
||||||
|
const revOrderedRotors = [...this.rotors].reverse();
|
||||||
|
for (const rotor of revOrderedRotors) {
|
||||||
|
inputPos = rotor.crypt(inputPos, "rightToLeft");
|
||||||
|
}
|
||||||
|
return inputPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Step the cipher rotors forward according to the inputs from the index rotors
|
||||||
|
*
|
||||||
|
* @param {number[]} indexInputs - the inputs from the index rotors
|
||||||
|
*/
|
||||||
|
step(indexInputs) {
|
||||||
|
const logicDict = {0: [0, 9], 1: [7, 8], 2: [5, 6], 3: [3, 4], 4: [1, 2]};
|
||||||
|
const rotorsToMove = [];
|
||||||
|
for (const key in logicDict) {
|
||||||
|
const item = logicDict[key];
|
||||||
|
for (const i of indexInputs) {
|
||||||
|
if (item.includes(i)) {
|
||||||
|
rotorsToMove.push(this.rotors[key]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const rotor of rotorsToMove) {
|
||||||
|
rotor.step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The control rotor bank consists of 5 control rotors in either a forward or reversed orientation. Signals to the control rotor bank always go from right-to-left.
|
||||||
|
*/
|
||||||
|
export class ControlBank {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ControlBank constructor. The rotors have been reversed as signals go from right-to-left through the control rotors.
|
||||||
|
*
|
||||||
|
* @param {Object[]} rotors - list of CRRotors
|
||||||
|
*/
|
||||||
|
constructor(rotors) {
|
||||||
|
this.rotors = [...rotors].reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a letter.
|
||||||
|
*
|
||||||
|
* @param {char} inputPos - the input position of the signal
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
crypt(inputPos) {
|
||||||
|
for (const rotor of this.rotors) {
|
||||||
|
inputPos = rotor.crypt(inputPos, "rightToLeft");
|
||||||
|
}
|
||||||
|
return inputPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the outputs of the control rotors. The inputs to the control rotors are always "F", "G", "H" and "I".
|
||||||
|
*
|
||||||
|
* @returns {number[]}
|
||||||
|
*/
|
||||||
|
getOutputs() {
|
||||||
|
const outputs = [this.crypt("F"), this.crypt("G"), this.crypt("H"), this.crypt("I")];
|
||||||
|
const logicDict = {1: "B", 2: "C", 3: "DE", 4: "FGH", 5: "IJK", 6: "LMNO", 7: "PQRST", 8: "UVWXYZ", 9: "A"};
|
||||||
|
const numberOutputs = [];
|
||||||
|
for (const key in logicDict) {
|
||||||
|
const item = logicDict[key];
|
||||||
|
for (const output of outputs) {
|
||||||
|
if (item.includes(output)) {
|
||||||
|
numberOutputs.push(key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numberOutputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steps the control rotors. Only 3 of the control rotors step: one after every encryption, one after every 26, and one after every 26 squared.
|
||||||
|
*/
|
||||||
|
step() {
|
||||||
|
const MRotor = this.rotors[1], FRotor = this.rotors[2], SRotor = this.rotors[3];
|
||||||
|
// 14 is the offset of "O" from "A" - the next rotor steps once the previous rotor reaches "O"
|
||||||
|
if (FRotor.state === 14) {
|
||||||
|
if (MRotor.state === 14) {
|
||||||
|
SRotor.step();
|
||||||
|
}
|
||||||
|
MRotor.step();
|
||||||
|
}
|
||||||
|
FRotor.step();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The goThroughControl function combines getting the outputs from the control rotor bank and then stepping them.
|
||||||
|
*
|
||||||
|
* @returns {number[]}
|
||||||
|
*/
|
||||||
|
goThroughControl() {
|
||||||
|
const outputs = this.getOutputs();
|
||||||
|
this.step();
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index rotor bank consists of 5 index rotors all placed in the forwards orientation.
|
||||||
|
*/
|
||||||
|
export class IndexBank {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IndexBank constructor
|
||||||
|
*
|
||||||
|
* @param {Object[]} rotors - list of IRotors
|
||||||
|
*/
|
||||||
|
constructor(rotors) {
|
||||||
|
this.rotors = rotors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a number.
|
||||||
|
*
|
||||||
|
* @param {number} inputPos - the input position of the signal
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
crypt(inputPos) {
|
||||||
|
for (const rotor of this.rotors) {
|
||||||
|
inputPos = rotor.crypt(inputPos);
|
||||||
|
}
|
||||||
|
return inputPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The goThroughIndex function takes the inputs from the control rotor bank and returns the list of outputs after encryption through the index rotors.
|
||||||
|
*
|
||||||
|
* @param {number[]} controlInputs - inputs from the control rotors
|
||||||
|
* @returns {number[]}
|
||||||
|
*/
|
||||||
|
goThroughIndex(controlInputs) {
|
||||||
|
const outputs = [];
|
||||||
|
for (const inp of controlInputs) {
|
||||||
|
outputs.push(this.crypt(inp));
|
||||||
|
}
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotor class
|
||||||
|
*/
|
||||||
|
export class Rotor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotor constructor
|
||||||
|
*
|
||||||
|
* @param {number[]} wireSetting - the wirings within the rotor: mapping from left-to-right, the index of the number in the list maps onto the number at that index
|
||||||
|
* @param {bool} rev - true if the rotor is reversed, false if it isn't
|
||||||
|
* @param {number} key - the starting position or state of the rotor
|
||||||
|
*/
|
||||||
|
constructor(wireSetting, key, rev) {
|
||||||
|
this.state = key;
|
||||||
|
this.numMapping = this.getNumMapping(wireSetting, rev);
|
||||||
|
this.posMapping = this.getPosMapping(rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number mapping from the wireSetting (only different from wireSetting if rotor is reversed)
|
||||||
|
*
|
||||||
|
* @param {number[]} wireSetting - the wirings within the rotors
|
||||||
|
* @param {bool} rev - true if reversed, false if not
|
||||||
|
* @returns {number[]}
|
||||||
|
*/
|
||||||
|
getNumMapping(wireSetting, rev) {
|
||||||
|
if (rev===false) {
|
||||||
|
return wireSetting;
|
||||||
|
} else {
|
||||||
|
const length = wireSetting.length;
|
||||||
|
const tempMapping = new Array(length);
|
||||||
|
for (let i=0; i<length; i++) {
|
||||||
|
tempMapping[wireSetting[i]] = i;
|
||||||
|
}
|
||||||
|
return tempMapping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position mapping (how the position numbers map onto the numbers of the rotor)
|
||||||
|
*
|
||||||
|
* @param {bool} rev - true if reversed, false if not
|
||||||
|
* @returns {number[]}
|
||||||
|
*/
|
||||||
|
getPosMapping(rev) {
|
||||||
|
const length = this.numMapping.length;
|
||||||
|
const posMapping = [];
|
||||||
|
if (rev===false) {
|
||||||
|
for (let i = this.state; i < this.state+length; i++) {
|
||||||
|
let res = i%length;
|
||||||
|
if (res<0) {
|
||||||
|
res += length;
|
||||||
|
}
|
||||||
|
posMapping.push(res);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = this.state; i > this.state-length; i--) {
|
||||||
|
let res = i%length;
|
||||||
|
if (res<0) {
|
||||||
|
res += length;
|
||||||
|
}
|
||||||
|
posMapping.push(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return posMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt/decrypt data. This process is identical to the rotors of cipher machines such as Enigma or Typex.
|
||||||
|
*
|
||||||
|
* @param {number} inputPos - the input position of the signal (the data to encrypt/decrypt)
|
||||||
|
* @param {string} direction - one of "leftToRight" and "rightToLeft", states the direction in which the signal passes through the rotor
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
cryptNum(inputPos, direction) {
|
||||||
|
const inpNum = this.posMapping[inputPos];
|
||||||
|
let outNum;
|
||||||
|
if (direction === "leftToRight") {
|
||||||
|
outNum = this.numMapping[inpNum];
|
||||||
|
} else if (direction === "rightToLeft") {
|
||||||
|
outNum = this.numMapping.indexOf(inpNum);
|
||||||
|
}
|
||||||
|
const outPos = this.posMapping.indexOf(outNum);
|
||||||
|
return outPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Steps the rotor. The number at position 0 will be moved to position 1 etc.
|
||||||
|
*/
|
||||||
|
step() {
|
||||||
|
const lastNum = this.posMapping.pop();
|
||||||
|
this.posMapping.splice(0, 0, lastNum);
|
||||||
|
this.state = this.posMapping[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CRRotor is a cipher (C) or control (R) rotor. These rotors are identical and interchangeable. A C or R rotor consists of 26 contacts, one for each letter, and may be put into either a forwards of reversed orientation.
|
||||||
|
*/
|
||||||
|
export class CRRotor extends Rotor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRRotor constructor
|
||||||
|
*
|
||||||
|
* @param {string} wireSetting - the rotor wirings (string of letters)
|
||||||
|
* @param {char} key - initial state of rotor
|
||||||
|
* @param {bool} rev - true if reversed, false if not
|
||||||
|
*/
|
||||||
|
constructor(wireSetting, key, rev=false) {
|
||||||
|
wireSetting = wireSetting.split("").map(CRRotor.letterToNum);
|
||||||
|
super(wireSetting, CRRotor.letterToNum(key), rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static function which converts a letter into its number i.e. its offset from the letter "A"
|
||||||
|
*
|
||||||
|
* @param {char} letter - letter to convert to number
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
static letterToNum(letter) {
|
||||||
|
return letter.charCodeAt()-65;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static function which converts a number (a letter's offset from "A") into its letter
|
||||||
|
*
|
||||||
|
* @param {number} num - number to convert to letter
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
static numToLetter(num) {
|
||||||
|
return String.fromCharCode(num+65);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts/decrypts a letter.
|
||||||
|
*
|
||||||
|
* @param {char} inputPos - the input position of the signal ("A" refers to position 0 etc.)
|
||||||
|
* @param {string} direction - one of "leftToRight" and "rightToLeft"
|
||||||
|
* @returns {char}
|
||||||
|
*/
|
||||||
|
crypt(inputPos, direction) {
|
||||||
|
inputPos = CRRotor.letterToNum(inputPos);
|
||||||
|
const outPos = this.cryptNum(inputPos, direction);
|
||||||
|
return CRRotor.numToLetter(outPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An IRotor is an index rotor, which consists of 10 contacts each numbered from 0 to 9. Unlike C and R rotors, they cannot be put in the reversed orientation. The index rotors do not step at any point during encryption or decryption.
|
||||||
|
*/
|
||||||
|
export class IRotor extends Rotor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IRotor constructor
|
||||||
|
*
|
||||||
|
* @param {string} wireSetting - the rotor wirings (string of numbers)
|
||||||
|
* @param {char} key - initial state of rotor
|
||||||
|
*/
|
||||||
|
constructor(wireSetting, key) {
|
||||||
|
wireSetting = wireSetting.split("").map(Number);
|
||||||
|
super(wireSetting, Number(key), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts a number
|
||||||
|
*
|
||||||
|
* @param {number} inputPos - the input position of the signal
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
crypt(inputPos) {
|
||||||
|
return this.cryptNum(inputPos, "leftToRight");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
331
src/core/lib/SM4.mjs
Normal file
331
src/core/lib/SM4.mjs
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
/**
|
||||||
|
* Complete implementation of SM4 cipher encryption/decryption with
|
||||||
|
* ECB, CBC, CFB, OFB, CTR block modes.
|
||||||
|
* These modes are specified in IETF draft-ribose-cfrg-sm4-09, see:
|
||||||
|
* https://tools.ietf.org/id/draft-ribose-cfrg-sm4-09.html
|
||||||
|
* for details.
|
||||||
|
*
|
||||||
|
* Follows spec from Cryptography Standardization Technical Comittee:
|
||||||
|
* http://www.gmbz.org.cn/upload/2018-04-04/1522788048733065051.pdf
|
||||||
|
*
|
||||||
|
* @author swesven
|
||||||
|
* @copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/** Number of rounds */
|
||||||
|
const NROUNDS = 32;
|
||||||
|
|
||||||
|
/** block size in bytes */
|
||||||
|
const BLOCKSIZE = 16;
|
||||||
|
|
||||||
|
/** The S box, 256 8-bit values */
|
||||||
|
const Sbox = [
|
||||||
|
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
|
||||||
|
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
|
||||||
|
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
|
||||||
|
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
|
||||||
|
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
|
||||||
|
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
|
||||||
|
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
|
||||||
|
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
|
||||||
|
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
|
||||||
|
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
|
||||||
|
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
|
||||||
|
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
|
||||||
|
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
|
||||||
|
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
|
||||||
|
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
|
||||||
|
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
|
||||||
|
];
|
||||||
|
|
||||||
|
/** "Fixed parameter CK" used in key expansion */
|
||||||
|
const CK = [
|
||||||
|
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
|
||||||
|
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
|
||||||
|
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
|
||||||
|
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
|
||||||
|
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
|
||||||
|
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
|
||||||
|
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
|
||||||
|
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
|
||||||
|
];
|
||||||
|
|
||||||
|
/** "System parameter FK" */
|
||||||
|
const FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotating 32-bit shift left
|
||||||
|
*
|
||||||
|
* (Note that although JS integers are stored in doubles and thus have 53 bits,
|
||||||
|
* the JS bitwise operations are 32-bit)
|
||||||
|
*/
|
||||||
|
function ROL(i, n) {
|
||||||
|
return (i << n) | (i >>> (32 - n));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linear transformation L
|
||||||
|
*
|
||||||
|
* @param {integer} b - a 32 bit integer
|
||||||
|
*/
|
||||||
|
function transformL(b) {
|
||||||
|
/* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
|
||||||
|
b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
|
||||||
|
(Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
|
||||||
|
/* circular rotate and xor */
|
||||||
|
return b ^ ROL(b, 2) ^ ROL(b, 10) ^ ROL(b, 18) ^ ROL(b, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linear transformation L'
|
||||||
|
*
|
||||||
|
* @param {integer} b - a 32 bit integer
|
||||||
|
*/
|
||||||
|
function transformLprime(b) {
|
||||||
|
/* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
|
||||||
|
b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
|
||||||
|
(Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
|
||||||
|
return b ^ ROL(b, 13) ^ ROL(b, 23); /* circular rotate and XOR */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the round key
|
||||||
|
*/
|
||||||
|
function initSM4RoundKey(rawkey) {
|
||||||
|
const K = rawkey.map((a, i) => a ^ FK[i]); /* K = rawkey ^ FK */
|
||||||
|
const roundKey = [];
|
||||||
|
for (let i = 0; i < 32; i++)
|
||||||
|
roundKey[i] = K[i + 4] = K[i] ^ transformLprime(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]);
|
||||||
|
return roundKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts/decrypts a single block X (4 32-bit values) with a prepared round key.
|
||||||
|
*
|
||||||
|
* @param {intArray} X - A cleartext block.
|
||||||
|
* @param {intArray} roundKey - The round key from initSMRoundKey for encrypting (reversed for decrypting).
|
||||||
|
* @returns {byteArray} - The cipher text.
|
||||||
|
*/
|
||||||
|
function encryptBlockSM4(X, roundKey) {
|
||||||
|
for (let i = 0; i < NROUNDS; i++)
|
||||||
|
X[i + 4] = X[i] ^ transformL(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ roundKey[i]);
|
||||||
|
return [X[35], X[34], X[33], X[32]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes 16 bytes from an offset in an array and returns an array of 4 32-bit Big-Endian values.
|
||||||
|
* (DataView won't work portably here as we need Big-Endian)
|
||||||
|
*
|
||||||
|
* @param {byteArray} bArray - the array of bytes
|
||||||
|
* @param {integer} offset - starting offset in the array; 15 bytes must follow it.
|
||||||
|
*/
|
||||||
|
function bytesToInts(bArray, offs=0) {
|
||||||
|
let offset = offs;
|
||||||
|
const A = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
|
||||||
|
offset += 4;
|
||||||
|
const B = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
|
||||||
|
offset += 4;
|
||||||
|
const C = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
|
||||||
|
offset += 4;
|
||||||
|
const D = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
|
||||||
|
return [A, B, C, D];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inverse of bytesToInts above; takes an array of 32-bit integers and turns it into an array of bytes.
|
||||||
|
* Again, Big-Endian order.
|
||||||
|
*/
|
||||||
|
function intsToBytes(ints) {
|
||||||
|
const bArr = [];
|
||||||
|
for (let i = 0; i < ints.length; i++) {
|
||||||
|
bArr.push((ints[i] >> 24) & 0xFF);
|
||||||
|
bArr.push((ints[i] >> 16) & 0xFF);
|
||||||
|
bArr.push((ints[i] >> 8) & 0xFF);
|
||||||
|
bArr.push(ints[i] & 0xFF);
|
||||||
|
}
|
||||||
|
return bArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt using SM4 using a given block cipher mode.
|
||||||
|
*
|
||||||
|
* @param {byteArray} message - The clear text message; any length under 32 Gb or so.
|
||||||
|
* @param {byteArray} key - The cipher key, 16 bytes.
|
||||||
|
* @param {byteArray} iv - The IV or nonce, 16 bytes (not used with ECB mode)
|
||||||
|
* @param {string} mode - The block cipher mode "CBC", "ECB", "CFB", "OFB", "CTR".
|
||||||
|
* @param {boolean} noPadding - Don't add PKCS#7 padding if set.
|
||||||
|
* @returns {byteArray} - The cipher text.
|
||||||
|
*/
|
||||||
|
export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
|
||||||
|
const messageLength = message.length;
|
||||||
|
if (messageLength === 0)
|
||||||
|
return [];
|
||||||
|
const roundKey = initSM4RoundKey(bytesToInts(key, 0));
|
||||||
|
|
||||||
|
/* Pad with PKCS#7 if requested for ECB/CBC else add zeroes (which are sliced off at the end) */
|
||||||
|
let padByte = 0;
|
||||||
|
let nPadding = 16 - (message.length & 0xF);
|
||||||
|
if (mode === "ECB" || mode === "CBC") {
|
||||||
|
if (noPadding) {
|
||||||
|
if (nPadding !== 16)
|
||||||
|
throw new OperationError(`No padding requested in ${mode} mode but input is not a 16-byte multiple.`);
|
||||||
|
nPadding = 0;
|
||||||
|
} else
|
||||||
|
padByte = nPadding;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < nPadding; i++)
|
||||||
|
message.push(padByte);
|
||||||
|
|
||||||
|
const cipherText = [];
|
||||||
|
switch (mode) {
|
||||||
|
case "ECB":
|
||||||
|
for (let i = 0; i < message.length; i += BLOCKSIZE)
|
||||||
|
Array.prototype.push.apply(cipherText, intsToBytes(encryptBlockSM4(bytesToInts(message, i), roundKey)));
|
||||||
|
break;
|
||||||
|
case "CBC":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < message.length; i += BLOCKSIZE) {
|
||||||
|
const block = bytesToInts(message, i);
|
||||||
|
block[0] ^= iv[0]; block[1] ^= iv[1];
|
||||||
|
block[2] ^= iv[2]; block[3] ^= iv[3];
|
||||||
|
iv = encryptBlockSM4(block, roundKey);
|
||||||
|
Array.prototype.push.apply(cipherText, intsToBytes(iv));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "CFB":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < message.length; i += BLOCKSIZE) {
|
||||||
|
iv = encryptBlockSM4(iv, roundKey);
|
||||||
|
const block = bytesToInts(message, i);
|
||||||
|
block[0] ^= iv[0]; block[1] ^= iv[1];
|
||||||
|
block[2] ^= iv[2]; block[3] ^= iv[3];
|
||||||
|
Array.prototype.push.apply(cipherText, intsToBytes(block));
|
||||||
|
iv = block;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "OFB":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < message.length; i += BLOCKSIZE) {
|
||||||
|
iv = encryptBlockSM4(iv, roundKey);
|
||||||
|
const block = bytesToInts(message, i);
|
||||||
|
block[0] ^= iv[0]; block[1] ^= iv[1];
|
||||||
|
block[2] ^= iv[2]; block[3] ^= iv[3];
|
||||||
|
Array.prototype.push.apply(cipherText, intsToBytes(block));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "CTR":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < message.length; i += BLOCKSIZE) {
|
||||||
|
let iv2 = [...iv]; /* containing the IV + counter */
|
||||||
|
iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
|
||||||
|
iv2 = encryptBlockSM4(iv2, roundKey);
|
||||||
|
const block = bytesToInts(message, i);
|
||||||
|
block[0] ^= iv2[0]; block[1] ^= iv2[1];
|
||||||
|
block[2] ^= iv2[2]; block[3] ^= iv2[3];
|
||||||
|
Array.prototype.push.apply(cipherText, intsToBytes(block));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError("Invalid block cipher mode: "+mode);
|
||||||
|
}
|
||||||
|
if (mode !== "ECB" && mode !== "CBC")
|
||||||
|
return cipherText.slice(0, messageLength);
|
||||||
|
return cipherText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt using SM4 using a given block cipher mode.
|
||||||
|
*
|
||||||
|
* @param {byteArray} cipherText - The ciphertext
|
||||||
|
* @param {byteArray} key - The cipher key, 16 bytes.
|
||||||
|
* @param {byteArray} iv - The IV or nonce, 16 bytes (not used with ECB mode)
|
||||||
|
* @param {string} mode - The block cipher mode "CBC", "ECB", "CFB", "OFB", "CTR"
|
||||||
|
* @param {boolean] ignorePadding - If true, ignore padding issues in ECB/CBC mode.
|
||||||
|
* @returns {byteArray} - The cipher text.
|
||||||
|
*/
|
||||||
|
export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false) {
|
||||||
|
const originalLength = cipherText.length;
|
||||||
|
if (originalLength === 0)
|
||||||
|
return [];
|
||||||
|
let roundKey = initSM4RoundKey(bytesToInts(key, 0));
|
||||||
|
|
||||||
|
if (mode === "ECB" || mode === "CBC") {
|
||||||
|
/* Init decryption key */
|
||||||
|
roundKey = roundKey.reverse();
|
||||||
|
if ((originalLength & 0xF) !== 0 && !ignorePadding)
|
||||||
|
throw new OperationError(`With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${cipherText.length & 0xF} bytes extra)`);
|
||||||
|
} else { /* Pad dummy bytes for other modes, chop them off at the end */
|
||||||
|
while ((cipherText.length & 0xF) !== 0)
|
||||||
|
cipherText.push(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearText = [];
|
||||||
|
switch (mode) {
|
||||||
|
case "ECB":
|
||||||
|
for (let i = 0; i < cipherText.length; i += BLOCKSIZE)
|
||||||
|
Array.prototype.push.apply(clearText, intsToBytes(encryptBlockSM4(bytesToInts(cipherText, i), roundKey)));
|
||||||
|
break;
|
||||||
|
case "CBC":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
|
||||||
|
const block = encryptBlockSM4(bytesToInts(cipherText, i), roundKey);
|
||||||
|
block[0] ^= iv[0]; block[1] ^= iv[1];
|
||||||
|
block[2] ^= iv[2]; block[3] ^= iv[3];
|
||||||
|
Array.prototype.push.apply(clearText, intsToBytes(block));
|
||||||
|
iv = bytesToInts(cipherText, i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "CFB":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
|
||||||
|
iv = encryptBlockSM4(iv, roundKey);
|
||||||
|
const block = bytesToInts(cipherText, i);
|
||||||
|
block[0] ^= iv[0]; block[1] ^= iv[1];
|
||||||
|
block[2] ^= iv[2]; block[3] ^= iv[3];
|
||||||
|
Array.prototype.push.apply(clearText, intsToBytes(block));
|
||||||
|
iv = bytesToInts(cipherText, i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "OFB":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
|
||||||
|
iv = encryptBlockSM4(iv, roundKey);
|
||||||
|
const block = bytesToInts(cipherText, i);
|
||||||
|
block[0] ^= iv[0]; block[1] ^= iv[1];
|
||||||
|
block[2] ^= iv[2]; block[3] ^= iv[3];
|
||||||
|
Array.prototype.push.apply(clearText, intsToBytes(block));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "CTR":
|
||||||
|
iv = bytesToInts(iv, 0);
|
||||||
|
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
|
||||||
|
let iv2 = [...iv]; /* containing the IV + counter */
|
||||||
|
iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
|
||||||
|
iv2 = encryptBlockSM4(iv2, roundKey);
|
||||||
|
const block = bytesToInts(cipherText, i);
|
||||||
|
block[0] ^= iv2[0]; block[1] ^= iv2[1];
|
||||||
|
block[2] ^= iv2[2]; block[3] ^= iv2[3];
|
||||||
|
Array.prototype.push.apply(clearText, intsToBytes(block));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Invalid block cipher mode: ${mode}`);
|
||||||
|
}
|
||||||
|
/* Check PKCS#7 padding */
|
||||||
|
if (mode === "ECB" || mode === "CBC") {
|
||||||
|
if (ignorePadding)
|
||||||
|
return clearText;
|
||||||
|
const padByte = clearText[clearText.length - 1];
|
||||||
|
if (padByte > 16)
|
||||||
|
throw new OperationError("Invalid PKCS#7 padding.");
|
||||||
|
for (let i = 0; i < padByte; i++)
|
||||||
|
if (clearText[clearText.length -i - 1] !== padByte)
|
||||||
|
throw new OperationError("Invalid PKCS#7 padding.");
|
||||||
|
return clearText.slice(0, clearText.length - padByte);
|
||||||
|
}
|
||||||
|
return clearText.slice(0, originalLength);
|
||||||
|
}
|
||||||
|
|
105
src/core/lib/Sort.mjs
Normal file
105
src/core/lib/Sort.mjs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
* Sorting functions
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2022
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison operation for sorting of strings ignoring case.
|
||||||
|
*
|
||||||
|
* @param {string} a
|
||||||
|
* @param {string} b
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
export function caseInsensitiveSort(a, b) {
|
||||||
|
return a.toLowerCase().localeCompare(b.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison operation for sorting of IPv4 addresses.
|
||||||
|
*
|
||||||
|
* @param {string} a
|
||||||
|
* @param {string} b
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
export function ipSort(a, b) {
|
||||||
|
let a_ = a.split("."),
|
||||||
|
b_ = b.split(".");
|
||||||
|
|
||||||
|
a_ = a_[0] * 0x1000000 + a_[1] * 0x10000 + a_[2] * 0x100 + a_[3] * 1;
|
||||||
|
b_ = b_[0] * 0x1000000 + b_[1] * 0x10000 + b_[2] * 0x100 + b_[3] * 1;
|
||||||
|
|
||||||
|
if (isNaN(a_) && !isNaN(b_)) return 1;
|
||||||
|
if (!isNaN(a_) && isNaN(b_)) return -1;
|
||||||
|
if (isNaN(a_) && isNaN(b_)) return a.localeCompare(b);
|
||||||
|
|
||||||
|
return a_ - b_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison operation for sorting of numeric values.
|
||||||
|
*
|
||||||
|
* @author Chris van Marle
|
||||||
|
* @param {string} a
|
||||||
|
* @param {string} b
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
export function numericSort(a, b) {
|
||||||
|
const a_ = a.split(/([^\d]+)/),
|
||||||
|
b_ = b.split(/([^\d]+)/);
|
||||||
|
|
||||||
|
for (let i = 0; i < a_.length && i < b.length; ++i) {
|
||||||
|
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
|
||||||
|
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
|
||||||
|
if (isNaN(a_[i]) && isNaN(b_[i])) {
|
||||||
|
const ret = a_[i].localeCompare(b_[i]); // Compare strings
|
||||||
|
if (ret !== 0) return ret;
|
||||||
|
}
|
||||||
|
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
|
||||||
|
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.localeCompare(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison operation for sorting of hexadecimal values.
|
||||||
|
*
|
||||||
|
* @author Chris van Marle
|
||||||
|
* @param {string} a
|
||||||
|
* @param {string} b
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
export function hexadecimalSort(a, b) {
|
||||||
|
let a_ = a.split(/([^\da-f]+)/i),
|
||||||
|
b_ = b.split(/([^\da-f]+)/i);
|
||||||
|
|
||||||
|
a_ = a_.map(v => {
|
||||||
|
const t = parseInt(v, 16);
|
||||||
|
return isNaN(t) ? v : t;
|
||||||
|
});
|
||||||
|
|
||||||
|
b_ = b_.map(v => {
|
||||||
|
const t = parseInt(v, 16);
|
||||||
|
return isNaN(t) ? v : t;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < a_.length && i < b.length; ++i) {
|
||||||
|
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
|
||||||
|
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
|
||||||
|
if (isNaN(a_[i]) && isNaN(b_[i])) {
|
||||||
|
const ret = a_[i].localeCompare(b_[i]); // Compare strings
|
||||||
|
if (ret !== 0) return ret;
|
||||||
|
}
|
||||||
|
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
|
||||||
|
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.localeCompare(b);
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ class AESDecrypt extends Operation {
|
||||||
|
|
||||||
this.name = "AES Decrypt";
|
this.name = "AES Decrypt";
|
||||||
this.module = "Ciphers";
|
this.module = "Ciphers";
|
||||||
this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul><br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.";
|
this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul><br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Advanced_Encryption_Standard";
|
this.infoURL = "https://wikipedia.org/wiki/Advanced_Encryption_Standard";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -66,6 +66,14 @@ class AESDecrypt extends Operation {
|
||||||
{
|
{
|
||||||
name: "ECB",
|
name: "ECB",
|
||||||
off: [5, 6]
|
off: [5, 6]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CBC/NoPadding",
|
||||||
|
off: [5, 6]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECB/NoPadding",
|
||||||
|
off: [5, 6]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -104,7 +112,8 @@ class AESDecrypt extends Operation {
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
||||||
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
||||||
mode = args[2],
|
mode = args[2].substring(0, 3),
|
||||||
|
noPadding = args[2].endsWith("NoPadding"),
|
||||||
inputType = args[3],
|
inputType = args[3],
|
||||||
outputType = args[4],
|
outputType = args[4],
|
||||||
gcmTag = Utils.convertToByteString(args[5].string, args[5].option),
|
gcmTag = Utils.convertToByteString(args[5].string, args[5].option),
|
||||||
|
@ -122,6 +131,14 @@ The following algorithms will be used based on the size of the key:
|
||||||
input = Utils.convertToByteString(input, inputType);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
|
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
|
||||||
|
|
||||||
|
/* Allow for a "no padding" mode */
|
||||||
|
if (noPadding) {
|
||||||
|
decipher.mode.unpad = function(output, options) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
decipher.start({
|
decipher.start({
|
||||||
iv: iv.length === 0 ? "" : iv,
|
iv: iv.length === 0 ? "" : iv,
|
||||||
tag: mode === "GCM" ? gcmTag : undefined,
|
tag: mode === "GCM" ? gcmTag : undefined,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Emulation of the Bombe machine.
|
* Emulation of the Bombe machine.
|
||||||
*
|
*
|
||||||
|
* Tested against the Bombe Rebuild at Bletchley Park's TNMOC
|
||||||
|
* using a variety of inputs and settings to confirm correctness.
|
||||||
|
*
|
||||||
* @author s2224834
|
* @author s2224834
|
||||||
* @copyright Crown Copyright 2019
|
* @copyright Crown Copyright 2019
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Emulation of Colossus.
|
* Emulation of Colossus.
|
||||||
*
|
*
|
||||||
|
* Tested against the Colossus Rebuild at Bletchley Park's TNMOC
|
||||||
|
* using a variety of inputs and settings to confirm correctness.
|
||||||
|
*
|
||||||
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||||
* @copyright Crown Copyright 2019
|
* @copyright Crown Copyright 2019
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
|
|
|
@ -22,7 +22,7 @@ class DESDecrypt extends Operation {
|
||||||
|
|
||||||
this.name = "DES Decrypt";
|
this.name = "DES Decrypt";
|
||||||
this.module = "Ciphers";
|
this.module = "Ciphers";
|
||||||
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -42,7 +42,7 @@ class DESDecrypt extends Operation {
|
||||||
{
|
{
|
||||||
"name": "Mode",
|
"name": "Mode",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
|
"value": ["CBC", "CFB", "OFB", "CTR", "ECB", "CBC/NoPadding", "ECB/NoPadding"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Input",
|
"name": "Input",
|
||||||
|
@ -65,7 +65,9 @@ class DESDecrypt extends Operation {
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
||||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||||
[,, mode, inputType, outputType] = args;
|
mode = args[2].substring(0, 3),
|
||||||
|
noPadding = args[2].endsWith("NoPadding"),
|
||||||
|
[,,, inputType, outputType] = args;
|
||||||
|
|
||||||
if (key.length !== 8) {
|
if (key.length !== 8) {
|
||||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
|
@ -83,6 +85,14 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||||
input = Utils.convertToByteString(input, inputType);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
const decipher = forge.cipher.createDecipher("DES-" + mode, key);
|
const decipher = forge.cipher.createDecipher("DES-" + mode, key);
|
||||||
|
|
||||||
|
/* Allow for a "no padding" mode */
|
||||||
|
if (noPadding) {
|
||||||
|
decipher.mode.unpad = function(output, options) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
decipher.start({iv: iv});
|
decipher.start({iv: iv});
|
||||||
decipher.update(forge.util.createBuffer(input));
|
decipher.update(forge.util.createBuffer(input));
|
||||||
const result = decipher.finish();
|
const result = decipher.finish();
|
||||||
|
|
|
@ -67,7 +67,7 @@ class DeriveEVPKey extends Operation {
|
||||||
iterations = args[2],
|
iterations = args[2],
|
||||||
hasher = args[3],
|
hasher = args[3],
|
||||||
salt = Utils.convertToByteString(args[4].string, args[4].option),
|
salt = Utils.convertToByteString(args[4].string, args[4].option),
|
||||||
key = CryptoJS.EvpKDF(passphrase, salt, {
|
key = CryptoJS.EvpKDF(passphrase, salt, { // lgtm [js/insufficient-password-hash]
|
||||||
keySize: keySize,
|
keySize: keySize,
|
||||||
hasher: CryptoJS.algo[hasher],
|
hasher: CryptoJS.algo[hasher],
|
||||||
iterations: iterations,
|
iterations: iterations,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Emulation of the Enigma machine.
|
* Emulation of the Enigma machine.
|
||||||
*
|
*
|
||||||
|
* Tested against various genuine Enigma machines using a variety of inputs
|
||||||
|
* and settings to confirm correctness.
|
||||||
|
*
|
||||||
* @author s2224834
|
* @author s2224834
|
||||||
* @copyright Crown Copyright 2019
|
* @copyright Crown Copyright 2019
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
|
|
|
@ -44,7 +44,13 @@ class ExtractDates extends Operation {
|
||||||
date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
|
date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
|
||||||
regex = new RegExp(date1 + "|" + date2 + "|" + date3, "ig");
|
regex = new RegExp(date1 + "|" + date2 + "|" + date3, "ig");
|
||||||
|
|
||||||
return search(input, regex, null, displayTotal);
|
const results = search(input, regex);
|
||||||
|
|
||||||
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
|
} else {
|
||||||
|
return results.join("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
|
import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
|
||||||
|
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract domains operation
|
* Extract domains operation
|
||||||
|
@ -25,9 +26,19 @@ class ExtractDomains extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Display total",
|
name: "Display total",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": true
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sort",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unique",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -38,8 +49,21 @@ class ExtractDomains extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const displayTotal = args[0];
|
const [displayTotal, sort, unique] = args;
|
||||||
return search(input, DOMAIN_REGEX, null, displayTotal);
|
|
||||||
|
const results = search(
|
||||||
|
input,
|
||||||
|
DOMAIN_REGEX,
|
||||||
|
null,
|
||||||
|
sort ? caseInsensitiveSort : null,
|
||||||
|
unique
|
||||||
|
);
|
||||||
|
|
||||||
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
|
} else {
|
||||||
|
return results.join("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { search } from "../lib/Extract.mjs";
|
import { search } from "../lib/Extract.mjs";
|
||||||
|
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract email addresses operation
|
* Extract email addresses operation
|
||||||
|
@ -25,9 +26,19 @@ class ExtractEmailAddresses extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Display total",
|
name: "Display total",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sort",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unique",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -38,10 +49,23 @@ class ExtractEmailAddresses extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const displayTotal = args[0],
|
const [displayTotal, sort, unique] = args,
|
||||||
// email regex from: https://www.regextester.com/98066
|
// email regex from: https://www.regextester.com/98066
|
||||||
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig;
|
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig;
|
||||||
return search(input, regex, null, displayTotal);
|
|
||||||
|
const results = search(
|
||||||
|
input,
|
||||||
|
regex,
|
||||||
|
null,
|
||||||
|
sort ? caseInsensitiveSort : null,
|
||||||
|
unique
|
||||||
|
);
|
||||||
|
|
||||||
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
|
} else {
|
||||||
|
return results.join("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { search } from "../lib/Extract.mjs";
|
import { search } from "../lib/Extract.mjs";
|
||||||
|
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract file paths operation
|
* Extract file paths operation
|
||||||
|
@ -25,19 +26,29 @@ class ExtractFilePaths extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Windows",
|
name: "Windows",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": true
|
value: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "UNIX",
|
name: "UNIX",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": true
|
value: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Display total",
|
name: "Display total",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sort",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unique",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -48,7 +59,7 @@ class ExtractFilePaths extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const [includeWinPath, includeUnixPath, displayTotal] = args,
|
const [includeWinPath, includeUnixPath, displayTotal, sort, unique] = args,
|
||||||
winDrive = "[A-Z]:\\\\",
|
winDrive = "[A-Z]:\\\\",
|
||||||
winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)~]{0,61}",
|
winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)~]{0,61}",
|
||||||
winExt = "[A-Z\\d]{1,6}",
|
winExt = "[A-Z\\d]{1,6}",
|
||||||
|
@ -65,12 +76,25 @@ class ExtractFilePaths extends Operation {
|
||||||
filePaths = unixPath;
|
filePaths = unixPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filePaths) {
|
if (!filePaths) {
|
||||||
const regex = new RegExp(filePaths, "ig");
|
|
||||||
return search(input, regex, null, displayTotal);
|
|
||||||
} else {
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const regex = new RegExp(filePaths, "ig");
|
||||||
|
const results = search(
|
||||||
|
input,
|
||||||
|
regex,
|
||||||
|
null,
|
||||||
|
sort ? caseInsensitiveSort : null,
|
||||||
|
unique
|
||||||
|
);
|
||||||
|
|
||||||
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
|
} else {
|
||||||
|
return results.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { search } from "../lib/Extract.mjs";
|
import { search } from "../lib/Extract.mjs";
|
||||||
|
import { ipSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract IP addresses operation
|
* Extract IP addresses operation
|
||||||
|
@ -25,24 +26,34 @@ class ExtractIPAddresses extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "IPv4",
|
name: "IPv4",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": true
|
value: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "IPv6",
|
name: "IPv6",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Remove local IPv4 addresses",
|
name: "Remove local IPv4 addresses",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Display total",
|
name: "Display total",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sort",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unique",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -53,7 +64,7 @@ class ExtractIPAddresses extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const [includeIpv4, includeIpv6, removeLocal, displayTotal] = 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})?",
|
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}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})";
|
||||||
let ips = "";
|
let ips = "";
|
||||||
|
@ -66,23 +77,29 @@ class ExtractIPAddresses extends Operation {
|
||||||
ips = ipv6;
|
ips = ipv6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ips) {
|
if (!ips) return "";
|
||||||
const regex = new RegExp(ips, "ig");
|
|
||||||
|
|
||||||
if (removeLocal) {
|
const regex = new RegExp(ips, "ig");
|
||||||
const ten = "10\\..+",
|
|
||||||
oneninetwo = "192\\.168\\..+",
|
|
||||||
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
|
|
||||||
onetwoseven = "127\\..+",
|
|
||||||
removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
|
|
||||||
"|" + oneseventwo + "|" + onetwoseven + ")");
|
|
||||||
|
|
||||||
return search(input, regex, removeRegex, displayTotal);
|
const ten = "10\\..+",
|
||||||
} else {
|
oneninetwo = "192\\.168\\..+",
|
||||||
return search(input, regex, null, displayTotal);
|
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
|
||||||
}
|
onetwoseven = "127\\..+",
|
||||||
|
removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
|
||||||
|
"|" + oneseventwo + "|" + onetwoseven + ")");
|
||||||
|
|
||||||
|
const results = search(
|
||||||
|
input,
|
||||||
|
regex,
|
||||||
|
removeLocal ? removeRegex : null,
|
||||||
|
sort ? ipSort : null,
|
||||||
|
unique
|
||||||
|
);
|
||||||
|
|
||||||
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return results.join("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { search } from "../lib/Extract.mjs";
|
import { search } from "../lib/Extract.mjs";
|
||||||
|
import { hexadecimalSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract MAC addresses operation
|
* Extract MAC addresses operation
|
||||||
|
@ -25,9 +26,19 @@ class ExtractMACAddresses extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Display total",
|
name: "Display total",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sort",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unique",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -38,10 +49,21 @@ class ExtractMACAddresses extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const displayTotal = args[0],
|
const [displayTotal, sort, unique] = args,
|
||||||
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig;
|
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig,
|
||||||
|
results = search(
|
||||||
|
input,
|
||||||
|
regex,
|
||||||
|
null,
|
||||||
|
sort ? hexadecimalSort : null,
|
||||||
|
unique
|
||||||
|
);
|
||||||
|
|
||||||
return search(input, regex, null, displayTotal);
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
|
} else {
|
||||||
|
return results.join("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { search, URL_REGEX } from "../lib/Extract.mjs";
|
import { search, URL_REGEX } from "../lib/Extract.mjs";
|
||||||
|
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract URLs operation
|
* Extract URLs operation
|
||||||
|
@ -25,9 +26,19 @@ class ExtractURLs extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Display total",
|
name: "Display total",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sort",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unique",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -38,8 +49,20 @@ class ExtractURLs extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const displayTotal = args[0];
|
const [displayTotal, sort, unique] = args;
|
||||||
return search(input, URL_REGEX, null, displayTotal);
|
const results = search(
|
||||||
|
input,
|
||||||
|
URL_REGEX,
|
||||||
|
null,
|
||||||
|
sort ? caseInsensitiveSort : null,
|
||||||
|
unique
|
||||||
|
);
|
||||||
|
|
||||||
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
|
} else {
|
||||||
|
return results.join("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
89
src/core/operations/FromBase45.mjs
Normal file
89
src/core/operations/FromBase45.mjs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/**
|
||||||
|
* @author Thomas Weißschuh [thomas@t-8ch.de]
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {ALPHABET, highlightToBase45, highlightFromBase45} from "../lib/Base45.mjs";
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From Base45 operation
|
||||||
|
*/
|
||||||
|
class FromBase45 extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FromBase45 constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "From Base45";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Base45 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers. The high number base results in shorter strings than with the decimal or hexadecimal system. Base45 is optimized for usage with QR codes.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "byteArray";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Alphabet",
|
||||||
|
type: "string",
|
||||||
|
value: ALPHABET
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
this.highlight = highlightFromBase45;
|
||||||
|
this.highlightReverse = highlightToBase45;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {byteArray}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (!input) return [];
|
||||||
|
const alphabet = Utils.expandAlphRange(args[0]);
|
||||||
|
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (const triple of Utils.chunked(input, 3)) {
|
||||||
|
triple.reverse();
|
||||||
|
let b = 0;
|
||||||
|
for (const c of triple) {
|
||||||
|
const idx = alphabet.indexOf(c);
|
||||||
|
if (idx === -1) {
|
||||||
|
throw new OperationError(`Character not in alphabet: '${c}'`);
|
||||||
|
}
|
||||||
|
b *= 45;
|
||||||
|
b += idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b > 65535) {
|
||||||
|
throw new OperationError(`Triplet too large: '${triple.join("")}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triple.length > 2) {
|
||||||
|
/**
|
||||||
|
* The last triple may only have 2 bytes so we push the MSB when we got 3 bytes
|
||||||
|
* Pushing MSB
|
||||||
|
*/
|
||||||
|
res.push(b >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushing LSB
|
||||||
|
*/
|
||||||
|
res.push(b & 0xff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FromBase45;
|
53
src/core/operations/GetAllCasings.mjs
Normal file
53
src/core/operations/GetAllCasings.mjs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permutate String operation
|
||||||
|
*/
|
||||||
|
class GetAllCasings extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetAllCasings constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Get All Casings";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Outputs all possible casing variations of a string.";
|
||||||
|
this.infoURL = "";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const length = input.length;
|
||||||
|
const max = 1 << length;
|
||||||
|
input = input.toLowerCase();
|
||||||
|
let result = "";
|
||||||
|
|
||||||
|
for (let i = 0; i < max; i++) {
|
||||||
|
const temp = input.split("");
|
||||||
|
for (let j = 0; j < length; j++) {
|
||||||
|
if (((i >> j) & 1) === 1) {
|
||||||
|
temp[j] = temp[j].toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += temp.join("") + "\n";
|
||||||
|
}
|
||||||
|
return result.slice(0, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GetAllCasings;
|
|
@ -1,6 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Emulation of the Lorenz SZ40/42a/42b cipher attachment.
|
* Emulation of the Lorenz SZ40/42a/42b cipher attachment.
|
||||||
*
|
*
|
||||||
|
* Tested against the Colossus Rebuild at Bletchley Park's TNMOC
|
||||||
|
* using a variety of inputs and settings to confirm correctness.
|
||||||
|
*
|
||||||
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||||
* @copyright Crown Copyright 2019
|
* @copyright Crown Copyright 2019
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
|
|
|
@ -43,9 +43,9 @@ class RC4Drop extends Operation {
|
||||||
"value": ["Latin1", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Hex", "Base64"]
|
"value": ["Latin1", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Hex", "Base64"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Number of bytes to drop",
|
"name": "Number of dwords to drop",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"value": 768
|
"value": 192
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
287
src/core/operations/SIGABA.mjs
Normal file
287
src/core/operations/SIGABA.mjs
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
/**
|
||||||
|
* Emulation of the SIGABA machine.
|
||||||
|
*
|
||||||
|
* @author hettysymes
|
||||||
|
* @copyright hettysymes 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import {LETTERS} from "../lib/Enigma.mjs";
|
||||||
|
import {NUMBERS, CR_ROTORS, I_ROTORS, SigabaMachine, CRRotor, IRotor} from "../lib/SIGABA.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sigaba operation
|
||||||
|
*/
|
||||||
|
class Sigaba extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sigaba constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "SIGABA";
|
||||||
|
this.module = "Bletchley";
|
||||||
|
this.description = "Encipher/decipher with the WW2 SIGABA machine. <br><br>SIGABA, otherwise known as ECM Mark II, was used by the United States for message encryption during WW2 up to the 1950s. It was developed in the 1930s by the US Army and Navy, and has up to this day never been broken. Consisting of 15 rotors: 5 cipher rotors and 10 rotors (5 control rotors and 5 index rotors) controlling the stepping of the cipher rotors, the rotor stepping for SIGABA is much more complex than other rotor machines of its time, such as Enigma. All example rotor wirings are random example sets.<br><br>To configure rotor wirings, for the cipher and control rotors enter a string of letters which map from A to Z, and for the index rotors enter a sequence of numbers which map from 0 to 9. Note that encryption is not the same as decryption, so first choose the desired mode. <br><br> Note: Whilst this has been tested against other software emulators, it has not been tested against hardware.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/SIGABA";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "1st (left-hand) cipher rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1st cipher rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1st cipher rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd cipher rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd cipher rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd cipher rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd (middle) cipher rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd cipher rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd cipher rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th cipher rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th cipher rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th cipher rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th (right-hand) cipher rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th cipher rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th cipher rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1st (left-hand) control rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1st control rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1st control rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd control rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd control rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd control rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd (middle) control rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd control rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd control rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th control rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th control rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th control rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th (right-hand) control rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: CR_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th control rotor reversed",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th control rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: LETTERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1st (left-hand) index rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: I_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "1st index rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: NUMBERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd index rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: I_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2nd index rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: NUMBERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd (middle) index rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: I_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3rd index rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: NUMBERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th index rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: I_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4th index rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: NUMBERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th (right-hand) index rotor",
|
||||||
|
type: "editableOption",
|
||||||
|
value: I_ROTORS,
|
||||||
|
defaultIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "5th index rotor intial value",
|
||||||
|
type: "option",
|
||||||
|
value: NUMBERS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SIGABA mode",
|
||||||
|
type: "option",
|
||||||
|
value: ["Encrypt", "Decrypt"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const sigabaSwitch = args[40];
|
||||||
|
const cipherRotors = [];
|
||||||
|
const controlRotors = [];
|
||||||
|
const indexRotors = [];
|
||||||
|
for (let i=0; i<5; i++) {
|
||||||
|
const rotorWiring = args[i*3];
|
||||||
|
cipherRotors.push(new CRRotor(rotorWiring, args[i*3+2], args[i*3+1]));
|
||||||
|
}
|
||||||
|
for (let i=5; i<10; i++) {
|
||||||
|
const rotorWiring = args[i*3];
|
||||||
|
controlRotors.push(new CRRotor(rotorWiring, args[i*3+2], args[i*3+1]));
|
||||||
|
}
|
||||||
|
for (let i=15; i<20; i++) {
|
||||||
|
const rotorWiring = args[i*2];
|
||||||
|
indexRotors.push(new IRotor(rotorWiring, args[i*2+1]));
|
||||||
|
}
|
||||||
|
const sigaba = new SigabaMachine(cipherRotors, controlRotors, indexRotors);
|
||||||
|
let result;
|
||||||
|
if (sigabaSwitch === "Encrypt") {
|
||||||
|
result = sigaba.encrypt(input);
|
||||||
|
} else if (sigabaSwitch === "Decrypt") {
|
||||||
|
result = sigaba.decrypt(input);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export default Sigaba;
|
88
src/core/operations/SM4Decrypt.mjs
Normal file
88
src/core/operations/SM4Decrypt.mjs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* @author swesven
|
||||||
|
* @copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { toHex } from "../lib/Hex.mjs";
|
||||||
|
import { decryptSM4 } from "../lib/SM4.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SM4 Decrypt operation
|
||||||
|
*/
|
||||||
|
class SM4Decrypt extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SM4Encrypt constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "SM4 Decrypt";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "SM4 is a 128-bit block cipher, currently established as a national standard (GB/T 32907-2016) of China.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/SM4_(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": "Mode",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["CBC", "CFB", "OFB", "CTR", "ECB", "CBC/NoPadding", "ECB/NoPadding"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Input",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Raw", "Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Hex", "Raw"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||||
|
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||||
|
[,, mode, inputType, outputType] = args;
|
||||||
|
|
||||||
|
if (key.length !== 16)
|
||||||
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
|
|
||||||
|
SM4 uses a key length of 16 bytes (128 bits).`);
|
||||||
|
if (iv.length !== 16 && !mode.startsWith("ECB"))
|
||||||
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||||
|
|
||||||
|
SM4 uses an IV length of 16 bytes (128 bits).
|
||||||
|
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||||
|
|
||||||
|
input = Utils.convertToByteArray(input, inputType);
|
||||||
|
const output = decryptSM4(input, key, iv, mode.substring(0, 3), mode.endsWith("NoPadding"));
|
||||||
|
return outputType === "Hex" ? toHex(output) : Utils.byteArrayToUtf8(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SM4Decrypt;
|
88
src/core/operations/SM4Encrypt.mjs
Normal file
88
src/core/operations/SM4Encrypt.mjs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* @author swesven
|
||||||
|
* @copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { toHex } from "../lib/Hex.mjs";
|
||||||
|
import { encryptSM4 } from "../lib/SM4.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SM4 Encrypt operation
|
||||||
|
*/
|
||||||
|
class SM4Encrypt extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SM4Encrypt constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "SM4 Encrypt";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "SM4 is a 128-bit block cipher, currently established as a national standard (GB/T 32907-2016) of China. Multiple block cipher modes are supported. When using CBC or ECB mode, the PKCS#7 padding scheme is used.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/SM4_(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": "Mode",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Input",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Raw", "Hex"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Hex", "Raw"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||||
|
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||||
|
[,, mode, inputType, outputType] = args;
|
||||||
|
|
||||||
|
if (key.length !== 16)
|
||||||
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
|
|
||||||
|
SM4 uses a key length of 16 bytes (128 bits).`);
|
||||||
|
if (iv.length !== 16 && !mode.startsWith("ECB"))
|
||||||
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||||
|
|
||||||
|
SM4 uses an IV length of 16 bytes (128 bits).
|
||||||
|
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||||
|
|
||||||
|
input = Utils.convertToByteArray(input, inputType);
|
||||||
|
const output = encryptSM4(input, key, iv, mode.substring(0, 3), mode.endsWith("NoPadding"));
|
||||||
|
return outputType === "Hex" ? toHex(output) : Utils.byteArrayToUtf8(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SM4Encrypt;
|
|
@ -87,7 +87,7 @@ class ScatterChart extends Operation {
|
||||||
const recordDelimiter = Utils.charRep(args[0]),
|
const recordDelimiter = Utils.charRep(args[0]),
|
||||||
fieldDelimiter = Utils.charRep(args[1]),
|
fieldDelimiter = Utils.charRep(args[1]),
|
||||||
columnHeadingsAreIncluded = args[2],
|
columnHeadingsAreIncluded = args[2],
|
||||||
fillColour = args[5],
|
fillColour = Utils.escapeHtml(args[5]),
|
||||||
radius = args[6],
|
radius = args[6],
|
||||||
colourInInput = args[7],
|
colourInInput = args[7],
|
||||||
dimension = 500;
|
dimension = 500;
|
||||||
|
|
|
@ -72,7 +72,10 @@ class SeriesChart extends Operation {
|
||||||
fieldDelimiter = Utils.charRep(args[1]),
|
fieldDelimiter = Utils.charRep(args[1]),
|
||||||
xLabel = args[2],
|
xLabel = args[2],
|
||||||
pipRadius = args[3],
|
pipRadius = args[3],
|
||||||
seriesColours = args[4].split(","),
|
// Escape HTML from all colours to prevent reflected XSS. See https://github.com/gchq/CyberChef/issues/1265
|
||||||
|
seriesColours = args[4].split(",").map((colour) => {
|
||||||
|
return Utils.escapeHtml(colour);
|
||||||
|
}),
|
||||||
svgWidth = 500,
|
svgWidth = 500,
|
||||||
interSeriesPadding = 20,
|
interSeriesPadding = 20,
|
||||||
xAxisHeight = 50,
|
xAxisHeight = 50,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||||
|
import {caseInsensitiveSort, ipSort, numericSort, hexadecimalSort} from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort operation
|
* Sort operation
|
||||||
|
@ -57,120 +58,19 @@ class Sort extends Operation {
|
||||||
if (order === "Alphabetical (case sensitive)") {
|
if (order === "Alphabetical (case sensitive)") {
|
||||||
sorted = sorted.sort();
|
sorted = sorted.sort();
|
||||||
} else if (order === "Alphabetical (case insensitive)") {
|
} else if (order === "Alphabetical (case insensitive)") {
|
||||||
sorted = sorted.sort(Sort._caseInsensitiveSort);
|
sorted = sorted.sort(caseInsensitiveSort);
|
||||||
} else if (order === "IP address") {
|
} else if (order === "IP address") {
|
||||||
sorted = sorted.sort(Sort._ipSort);
|
sorted = sorted.sort(ipSort);
|
||||||
} else if (order === "Numeric") {
|
} else if (order === "Numeric") {
|
||||||
sorted = sorted.sort(Sort._numericSort);
|
sorted = sorted.sort(numericSort);
|
||||||
} else if (order === "Numeric (hexadecimal)") {
|
} else if (order === "Numeric (hexadecimal)") {
|
||||||
sorted = sorted.sort(Sort._hexadecimalSort);
|
sorted = sorted.sort(hexadecimalSort);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortReverse) sorted.reverse();
|
if (sortReverse) sorted.reverse();
|
||||||
return sorted.join(delim);
|
return sorted.join(delim);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Comparison operation for sorting of strings ignoring case.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {string} a
|
|
||||||
* @param {string} b
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
static _caseInsensitiveSort(a, b) {
|
|
||||||
return a.toLowerCase().localeCompare(b.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comparison operation for sorting of IPv4 addresses.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {string} a
|
|
||||||
* @param {string} b
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
static _ipSort(a, b) {
|
|
||||||
let a_ = a.split("."),
|
|
||||||
b_ = b.split(".");
|
|
||||||
|
|
||||||
a_ = a_[0] * 0x1000000 + a_[1] * 0x10000 + a_[2] * 0x100 + a_[3] * 1;
|
|
||||||
b_ = b_[0] * 0x1000000 + b_[1] * 0x10000 + b_[2] * 0x100 + b_[3] * 1;
|
|
||||||
|
|
||||||
if (isNaN(a_) && !isNaN(b_)) return 1;
|
|
||||||
if (!isNaN(a_) && isNaN(b_)) return -1;
|
|
||||||
if (isNaN(a_) && isNaN(b_)) return a.localeCompare(b);
|
|
||||||
|
|
||||||
return a_ - b_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comparison operation for sorting of numeric values.
|
|
||||||
*
|
|
||||||
* @author Chris van Marle
|
|
||||||
* @private
|
|
||||||
* @param {string} a
|
|
||||||
* @param {string} b
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
static _numericSort(a, b) {
|
|
||||||
const a_ = a.split(/([^\d]+)/),
|
|
||||||
b_ = b.split(/([^\d]+)/);
|
|
||||||
|
|
||||||
for (let i = 0; i < a_.length && i < b.length; ++i) {
|
|
||||||
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
|
|
||||||
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
|
|
||||||
if (isNaN(a_[i]) && isNaN(b_[i])) {
|
|
||||||
const ret = a_[i].localeCompare(b_[i]); // Compare strings
|
|
||||||
if (ret !== 0) return ret;
|
|
||||||
}
|
|
||||||
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
|
|
||||||
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.localeCompare(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comparison operation for sorting of hexadecimal values.
|
|
||||||
*
|
|
||||||
* @author Chris van Marle
|
|
||||||
* @private
|
|
||||||
* @param {string} a
|
|
||||||
* @param {string} b
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
static _hexadecimalSort(a, b) {
|
|
||||||
let a_ = a.split(/([^\da-f]+)/i),
|
|
||||||
b_ = b.split(/([^\da-f]+)/i);
|
|
||||||
|
|
||||||
a_ = a_.map(v => {
|
|
||||||
const t = parseInt(v, 16);
|
|
||||||
return isNaN(t) ? v : t;
|
|
||||||
});
|
|
||||||
|
|
||||||
b_ = b_.map(v => {
|
|
||||||
const t = parseInt(v, 16);
|
|
||||||
return isNaN(t) ? v : t;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let i = 0; i < a_.length && i < b.length; ++i) {
|
|
||||||
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
|
|
||||||
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
|
|
||||||
if (isNaN(a_[i]) && isNaN(b_[i])) {
|
|
||||||
const ret = a_[i].localeCompare(b_[i]); // Compare strings
|
|
||||||
if (ret !== 0) return ret;
|
|
||||||
}
|
|
||||||
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
|
|
||||||
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.localeCompare(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Sort;
|
export default Sort;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import XRegExp from "xregexp";
|
import XRegExp from "xregexp";
|
||||||
import { search } from "../lib/Extract.mjs";
|
import { search } from "../lib/Extract.mjs";
|
||||||
|
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strings operation
|
* Strings operation
|
||||||
|
@ -27,27 +28,37 @@ class Strings extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Encoding",
|
name: "Encoding",
|
||||||
"type": "option",
|
type: "option",
|
||||||
"value": ["Single byte", "16-bit littleendian", "16-bit bigendian", "All"]
|
value: ["Single byte", "16-bit littleendian", "16-bit bigendian", "All"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Minimum length",
|
name: "Minimum length",
|
||||||
"type": "number",
|
type: "number",
|
||||||
"value": 4
|
value: 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Match",
|
name: "Match",
|
||||||
"type": "option",
|
type: "option",
|
||||||
"value": [
|
value: [
|
||||||
"[ASCII]", "Alphanumeric + punctuation (A)", "All printable chars (A)", "Null-terminated strings (A)",
|
"[ASCII]", "Alphanumeric + punctuation (A)", "All printable chars (A)", "Null-terminated strings (A)",
|
||||||
"[Unicode]", "Alphanumeric + punctuation (U)", "All printable chars (U)", "Null-terminated strings (U)"
|
"[Unicode]", "Alphanumeric + punctuation (U)", "All printable chars (U)", "Null-terminated strings (U)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Display total",
|
name: "Display total",
|
||||||
"type": "boolean",
|
type: "boolean",
|
||||||
"value": false
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sort",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unique",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -58,7 +69,7 @@ class Strings extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const [encoding, minLen, matchType, displayTotal] = args,
|
const [encoding, minLen, matchType, displayTotal, sort, unique] = args,
|
||||||
alphanumeric = "A-Z\\d",
|
alphanumeric = "A-Z\\d",
|
||||||
punctuation = "/\\-:.,_$%'\"()<>= !\\[\\]{}@",
|
punctuation = "/\\-:.,_$%'\"()<>= !\\[\\]{}@",
|
||||||
printable = "\x20-\x7e",
|
printable = "\x20-\x7e",
|
||||||
|
@ -108,8 +119,19 @@ class Strings extends Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
const regex = new XRegExp(strings, "ig");
|
const regex = new XRegExp(strings, "ig");
|
||||||
|
const results = search(
|
||||||
|
input,
|
||||||
|
regex,
|
||||||
|
null,
|
||||||
|
sort ? caseInsensitiveSort : null,
|
||||||
|
unique
|
||||||
|
);
|
||||||
|
|
||||||
return search(input, regex, null, displayTotal);
|
if (displayTotal) {
|
||||||
|
return `Total found: ${results.length}\n\n${results.join("\n")}`;
|
||||||
|
} else {
|
||||||
|
return results.join("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
78
src/core/operations/ToBase45.mjs
Normal file
78
src/core/operations/ToBase45.mjs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
* @author Thomas Weißschuh [thomas@t-8ch.de]
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {ALPHABET, highlightToBase45, highlightFromBase45} from "../lib/Base45.mjs";
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Base45 operation
|
||||||
|
*/
|
||||||
|
class ToBase45 extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToBase45 constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "To Base45";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Base45 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers. The high number base results in shorter strings than with the decimal or hexadecimal system. Base45 is optimized for usage with QR codes.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Alphabet",
|
||||||
|
type: "string",
|
||||||
|
value: ALPHABET
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
this.highlight = highlightToBase45;
|
||||||
|
this.highlightReverse = highlightFromBase45;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (!input) return "";
|
||||||
|
input = new Uint8Array(input);
|
||||||
|
const alphabet = Utils.expandAlphRange(args[0]);
|
||||||
|
|
||||||
|
const res = [];
|
||||||
|
|
||||||
|
for (const pair of Utils.chunked(input, 2)) {
|
||||||
|
let b = 0;
|
||||||
|
for (const e of pair) {
|
||||||
|
b *= 256;
|
||||||
|
b += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chars = 0;
|
||||||
|
do {
|
||||||
|
res.push(alphabet[b % 45]);
|
||||||
|
chars++;
|
||||||
|
b = Math.floor(b / 45);
|
||||||
|
} while (b > 0);
|
||||||
|
|
||||||
|
if (chars < 2) {
|
||||||
|
res.push("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return res.join("");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToBase45;
|
|
@ -22,7 +22,7 @@ class TripleDESDecrypt extends Operation {
|
||||||
|
|
||||||
this.name = "Triple DES Decrypt";
|
this.name = "Triple DES Decrypt";
|
||||||
this.module = "Ciphers";
|
this.module = "Ciphers";
|
||||||
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -42,7 +42,7 @@ class TripleDESDecrypt extends Operation {
|
||||||
{
|
{
|
||||||
"name": "Mode",
|
"name": "Mode",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
|
"value": ["CBC", "CFB", "OFB", "CTR", "ECB", "CBC/NoPadding", "ECB/NoPadding"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Input",
|
"name": "Input",
|
||||||
|
@ -65,7 +65,8 @@ class TripleDESDecrypt extends Operation {
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
||||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||||
mode = args[2],
|
mode = args[2].substring(0, 3),
|
||||||
|
noPadding = args[2].endsWith("NoPadding"),
|
||||||
inputType = args[3],
|
inputType = args[3],
|
||||||
outputType = args[4];
|
outputType = args[4];
|
||||||
|
|
||||||
|
@ -85,6 +86,14 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||||
input = Utils.convertToByteString(input, inputType);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
const decipher = forge.cipher.createDecipher("3DES-" + mode, key);
|
const decipher = forge.cipher.createDecipher("3DES-" + mode, key);
|
||||||
|
|
||||||
|
/* Allow for a "no padding" mode */
|
||||||
|
if (noPadding) {
|
||||||
|
decipher.mode.unpad = function(output, options) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
decipher.start({iv: iv});
|
decipher.start({iv: iv});
|
||||||
decipher.update(forge.util.createBuffer(input));
|
decipher.update(forge.util.createBuffer(input));
|
||||||
const result = decipher.finish();
|
const result = decipher.finish();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Emulation of the Typex machine.
|
* Emulation of the Typex machine.
|
||||||
*
|
*
|
||||||
|
* Tested against a genuine Typex machine using a variety of inputs
|
||||||
|
* and settings to confirm correctness.
|
||||||
|
*
|
||||||
* @author s2224834
|
* @author s2224834
|
||||||
* @copyright Crown Copyright 2019
|
* @copyright Crown Copyright 2019
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
|
|
|
@ -26,9 +26,14 @@ class Unique extends Operation {
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Delimiter",
|
name: "Delimiter",
|
||||||
"type": "option",
|
type: "option",
|
||||||
"value": INPUT_DELIM_OPTIONS
|
value: INPUT_DELIM_OPTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Display count",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -39,8 +44,23 @@ class Unique extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const delim = Utils.charRep(args[0]);
|
const delim = Utils.charRep(args[0]),
|
||||||
return input.split(delim).unique().join(delim);
|
count = args[1];
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
const valMap = input.split(delim).reduce((acc, curr) => {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(acc, curr)) {
|
||||||
|
acc[curr]++;
|
||||||
|
} else {
|
||||||
|
acc[curr] = 1;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return Object.keys(valMap).map(val => `${valMap[val]} ${val}`).join(delim);
|
||||||
|
} else {
|
||||||
|
return input.split(delim).unique().join(delim);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
import NodeDish from "./NodeDish.mjs";
|
import NodeDish from "./NodeDish.mjs";
|
||||||
import NodeRecipe from "./NodeRecipe.mjs";
|
import NodeRecipe from "./NodeRecipe.mjs";
|
||||||
import OperationConfig from "../core/config/OperationConfig.json";
|
import OperationConfig from "../core/config/OperationConfig.json" assert {type: "json"};
|
||||||
import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils.mjs";
|
import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils.mjs";
|
||||||
import ExcludedOperationError from "../core/errors/ExcludedOperationError.mjs";
|
import ExcludedOperationError from "../core/errors/ExcludedOperationError.mjs";
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
/**
|
|
||||||
* Export the main ESM module as CommonJS
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author d98762656 [d98762625@gmail.com]
|
|
||||||
* @copyright Crown Copyright 2019
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* eslint no-global-assign: ["off"] */
|
|
||||||
require = require("esm")(module);
|
|
||||||
module.exports = require("./index.mjs");
|
|
||||||
module.exports.File = require("./File.mjs");
|
|
|
@ -41,7 +41,7 @@ let code = `/**
|
||||||
import NodeDish from "./NodeDish.mjs";
|
import NodeDish from "./NodeDish.mjs";
|
||||||
import { _wrap, help, bake, _explainExcludedFunction } from "./api.mjs";
|
import { _wrap, help, bake, _explainExcludedFunction } from "./api.mjs";
|
||||||
import File from "./File.mjs";
|
import File from "./File.mjs";
|
||||||
import { OperationError, DishError, ExcludedOperationError } from "../core/errors/index";
|
import { OperationError, DishError, ExcludedOperationError } from "../core/errors/index.mjs";
|
||||||
import {
|
import {
|
||||||
// import as core_ to avoid name clashes after wrap.
|
// import as core_ to avoid name clashes after wrap.
|
||||||
`;
|
`;
|
||||||
|
@ -52,7 +52,7 @@ includedOperations.forEach((op) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
code +=`
|
code +=`
|
||||||
} from "../core/operations/index";
|
} from "../core/operations/index.mjs";
|
||||||
|
|
||||||
global.File = File;
|
global.File = File;
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const chef = require("./cjs.js");
|
import chef from "./index.mjs";
|
||||||
const repl = require("repl");
|
import repl from "repl";
|
||||||
|
|
||||||
|
|
||||||
/* eslint no-console: ["off"] */
|
/* eslint no-console: ["off"] */
|
11
src/node/wrapper.js
Normal file
11
src/node/wrapper.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/**
|
||||||
|
* Export the main ESM module as CommonJS
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author d98762656 [d98762625@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = (async () => await import("./index.mjs"))();
|
||||||
|
module.exports.File = (async () => await import("./File.mjs"))();
|
|
@ -29,7 +29,7 @@
|
||||||
<meta name="description" content="The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis" />
|
<meta name="description" content="The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis" />
|
||||||
<meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip, md5, sha1, aes, des, blowfish, xor" />
|
<meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip, md5, sha1, aes, des, blowfish, xor" />
|
||||||
|
|
||||||
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico').default %>" />
|
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
"use strict";
|
"use strict";
|
||||||
|
@ -197,7 +197,7 @@
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="mx-2 btn btn-lg btn-success btn-raised btn-block" id="bake">
|
<button type="button" class="mx-2 btn btn-lg btn-success btn-raised btn-block" id="bake">
|
||||||
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png').default %>" alt="Chef Icon"/>
|
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png') %>" alt="Chef Icon"/>
|
||||||
<span>Bake!</span>
|
<span>Bake!</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@
|
||||||
<div class="file-overlay" id="file-overlay"></div>
|
<div class="file-overlay" id="file-overlay"></div>
|
||||||
<div style="position: relative; height: 100%;">
|
<div style="position: relative; height: 100%;">
|
||||||
<div class="io-card card">
|
<div class="io-card card">
|
||||||
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png').default %>" alt="File icon" id="input-file-thumbnail"/>
|
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon" id="input-file-thumbnail"/>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<button type="button" class="close" id="input-file-close">×</button>
|
<button type="button" class="close" id="input-file-close">×</button>
|
||||||
Name: <span id="input-file-name"></span><br>
|
Name: <span id="input-file-name"></span><br>
|
||||||
|
@ -346,12 +346,12 @@
|
||||||
<div id="output-highlighter" class="no-select"></div>
|
<div id="output-highlighter" class="no-select"></div>
|
||||||
<div id="output-html"></div>
|
<div id="output-html"></div>
|
||||||
<textarea id="output-text" readonly="readonly" spellcheck="false"></textarea>
|
<textarea id="output-text" readonly="readonly" spellcheck="false"></textarea>
|
||||||
<img id="show-file-overlay" aria-hidden="true" src="<%- require('../static/images/file-32x32.png').default %>" alt="Show file overlay" title="Show file overlay"/>
|
<img id="show-file-overlay" aria-hidden="true" src="<%- require('../static/images/file-32x32.png') %>" alt="Show file overlay" title="Show file overlay"/>
|
||||||
<div id="output-file">
|
<div id="output-file">
|
||||||
<div class="file-overlay"></div>
|
<div class="file-overlay"></div>
|
||||||
<div style="position: relative; height: 100%;">
|
<div style="position: relative; height: 100%;">
|
||||||
<div class="io-card card">
|
<div class="io-card card">
|
||||||
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png').default %>" alt="File icon"/>
|
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon"/>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
Size: <span id="output-file-size"></span><br>
|
Size: <span id="output-file-size"></span><br>
|
||||||
<button id="output-file-download" type="button" class="btn btn-primary btn-outline">Download</button>
|
<button id="output-file-download" type="button" class="btn btn-primary btn-outline">Download</button>
|
||||||
|
@ -626,7 +626,7 @@
|
||||||
<h5 class="modal-title">CyberChef - The Cyber Swiss Army Knife</h5>
|
<h5 class="modal-title">CyberChef - The Cyber Swiss Army Knife</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png').default %>" alt="CyberChef Logo"/>
|
<img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png') %>" alt="CyberChef Logo"/>
|
||||||
<p class="subtext">
|
<p class="subtext">
|
||||||
Version <%= htmlWebpackPlugin.options.version %><br>
|
Version <%= htmlWebpackPlugin.options.version %><br>
|
||||||
Compile time: <%= htmlWebpackPlugin.options.compileTime %>
|
Compile time: <%= htmlWebpackPlugin.options.compileTime %>
|
||||||
|
@ -749,7 +749,7 @@
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
</div>
|
</div>
|
||||||
<a href="https://github.com/gchq/CyberChef">
|
<a href="https://github.com/gchq/CyberChef">
|
||||||
<img aria-hidden="true" style="position: absolute; top: 0; right: 0; border: 0;" src="<%- require('../static/images/fork_me.png').default %>" alt="Fork me on GitHub">
|
<img aria-hidden="true" style="position: absolute; top: 0; right: 0; border: 0;" src="<%- require('../static/images/fork_me.png') %>" alt="Fork me on GitHub">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -17,8 +17,8 @@ import * as CanvasComponents from "../core/lib/CanvasComponents.mjs";
|
||||||
|
|
||||||
// CyberChef
|
// CyberChef
|
||||||
import App from "./App.mjs";
|
import App from "./App.mjs";
|
||||||
import Categories from "../core/config/Categories.json";
|
import Categories from "../core/config/Categories.json" assert {type: "json"};
|
||||||
import OperationConfig from "../core/config/OperationConfig.json";
|
import OperationConfig from "../core/config/OperationConfig.json" assert {type: "json"};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import sm from "sitemap";
|
import sm from "sitemap";
|
||||||
import OperationConfig from "../../core/config/OperationConfig.json";
|
import OperationConfig from "../../core/config/OperationConfig.json" assert {type: "json"};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -303,7 +303,7 @@
|
||||||
|
|
||||||
#stale-indicator {
|
#stale-indicator {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visibile;
|
visibility: visible;
|
||||||
transition: margin 0s, opacity 0.3s;
|
transition: margin 0s, opacity 0.3s;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
cursor: help;
|
cursor: help;
|
||||||
|
@ -316,7 +316,7 @@
|
||||||
|
|
||||||
#magic {
|
#magic {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visibile;
|
visibility: visible;
|
||||||
transition: margin 0s 0.3s, opacity 0.3s 0.3s, visibility 0.3s 0.3s;
|
transition: margin 0s 0.3s, opacity 0.3s 0.3s, visibility 0.3s 0.3s;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
|
|
@ -71,7 +71,7 @@ module.exports = {
|
||||||
.moveToElement(toHex, 10, 10)
|
.moveToElement(toHex, 10, 10)
|
||||||
.useCss()
|
.useCss()
|
||||||
.waitForElementVisible(".popover-body", 1000)
|
.waitForElementVisible(".popover-body", 1000)
|
||||||
.doubleClick();
|
.doubleClick("xpath", toHex);
|
||||||
|
|
||||||
// Confirm that it has been added to the recipe
|
// Confirm that it has been added to the recipe
|
||||||
browser
|
browser
|
||||||
|
@ -90,7 +90,7 @@ module.exports = {
|
||||||
browser
|
browser
|
||||||
.useCss()
|
.useCss()
|
||||||
.waitForElementNotVisible("#stale-indicator", 1000)
|
.waitForElementNotVisible("#stale-indicator", 1000)
|
||||||
.expect.element("#output-text").to.have.value.that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e");
|
.expect.element("#output-text").to.have.property("value").that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e");
|
||||||
|
|
||||||
// Clear recipe
|
// Clear recipe
|
||||||
browser
|
browser
|
||||||
|
@ -202,11 +202,11 @@ module.exports = {
|
||||||
browser
|
browser
|
||||||
.getLocationInView(genUUID)
|
.getLocationInView(genUUID)
|
||||||
.moveToElement(genUUID, 10, 10)
|
.moveToElement(genUUID, 10, 10)
|
||||||
.doubleClick()
|
.doubleClick("xpath", genUUID)
|
||||||
.useCss()
|
.useCss()
|
||||||
.waitForElementVisible(".operation .op-title", 1000)
|
.waitForElementVisible(".operation .op-title", 1000)
|
||||||
.waitForElementNotVisible("#stale-indicator", 1000)
|
.waitForElementNotVisible("#stale-indicator", 1000)
|
||||||
.expect.element("#output-text").to.have.value.which.matches(/[\da-f-]{36}/);
|
.expect.element("#output-text").to.have.property("value").which.matches(/[\da-f-]{36}/);
|
||||||
|
|
||||||
browser.click("#clr-recipe");
|
browser.click("#clr-recipe");
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,8 @@ module.exports = {
|
||||||
.click("#auto-bake-label");
|
.click("#auto-bake-label");
|
||||||
},
|
},
|
||||||
|
|
||||||
"Sanity check operations": browser => {
|
"Sanity check operations": async browser => {
|
||||||
|
const Images = await import("../samples/Images.mjs");
|
||||||
testOp(browser, "A1Z26 Cipher Decode", "20 5 19 20 15 21 20 16 21 20", "testoutput");
|
testOp(browser, "A1Z26 Cipher Decode", "20 5 19 20 15 21 20 16 21 20", "testoutput");
|
||||||
testOp(browser, "A1Z26 Cipher Encode", "test input", "20 5 19 20 9 14 16 21 20");
|
testOp(browser, "A1Z26 Cipher Encode", "test input", "20 5 19 20 9 14 16 21 20");
|
||||||
testOp(browser, "ADD", "test input", "Ê»ÉÊv¿ÄÆËÊ", [{ "option": "Hex", "string": "56" }]);
|
testOp(browser, "ADD", "test input", "Ê»ÉÊv¿ÄÆËÊ", [{ "option": "Hex", "string": "56" }]);
|
||||||
|
@ -24,7 +25,7 @@ module.exports = {
|
||||||
testOp(browser, "AES Encrypt", "test input", "e42eb8fbfb7a98fff061cd2c1a794d92", [{"option": "Hex", "string": "00112233445566778899aabbccddeeff"}, {"option": "Hex", "string": "00000000000000000000000000000000"}, "CBC", "Raw", "Hex"]);
|
testOp(browser, "AES Encrypt", "test input", "e42eb8fbfb7a98fff061cd2c1a794d92", [{"option": "Hex", "string": "00112233445566778899aabbccddeeff"}, {"option": "Hex", "string": "00000000000000000000000000000000"}, "CBC", "Raw", "Hex"]);
|
||||||
testOp(browser, "AND", "test input", "4$04 $044", [{ "option": "Hex", "string": "34" }]);
|
testOp(browser, "AND", "test input", "4$04 $044", [{ "option": "Hex", "string": "34" }]);
|
||||||
testOp(browser, "Add line numbers", "test input", "1 test input");
|
testOp(browser, "Add line numbers", "test input", "1 test input");
|
||||||
// testOp(browser, "Add Text To Image", "test input", "test_output");
|
testOp(browser, ["From Hex", "Add Text To Image", "To Base64"], Images.PNG_HEX, Images.PNG_CHEF_B64, [[], ["Chef", "Center", "Middle", 0, 0, 16], []]);
|
||||||
testOp(browser, "Adler-32 Checksum", "test input", "16160411");
|
testOp(browser, "Adler-32 Checksum", "test input", "16160411");
|
||||||
testOp(browser, "Affine Cipher Decode", "test input", "rcqr glnsr", [1, 2]);
|
testOp(browser, "Affine Cipher Decode", "test input", "rcqr glnsr", [1, 2]);
|
||||||
testOp(browser, "Affine Cipher Encode", "test input", "njln rbfpn", [2, 1]);
|
testOp(browser, "Affine Cipher Encode", "test input", "njln rbfpn", [2, 1]);
|
||||||
|
@ -44,12 +45,12 @@ module.exports = {
|
||||||
// testOp(browser, "Bifid Cipher Encode", "test input", "test_output");
|
// testOp(browser, "Bifid Cipher Encode", "test input", "test_output");
|
||||||
// testOp(browser, "Bit shift left", "test input", "test_output");
|
// testOp(browser, "Bit shift left", "test input", "test_output");
|
||||||
// testOp(browser, "Bit shift right", "test input", "test_output");
|
// testOp(browser, "Bit shift right", "test input", "test_output");
|
||||||
// testOp(browser, "Blowfish Decrypt", "test input", "test_output");
|
testOp(browser, "Blowfish Decrypt", "10884e15427dd84ec35204e9c8e921ae", "test_output", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Hex", "Raw"]);
|
||||||
// testOp(browser, "Blowfish Encrypt", "test input", "test_output");
|
testOp(browser, "Blowfish Encrypt", "test input", "f0fadbd1d90d774f714248cf26b96410", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Raw", "Hex"]);
|
||||||
// testOp(browser, "Blur Image", "test input", "test_output");
|
testOp(browser, ["From Hex", "Blur Image", "To Base64"], Images.PNG_HEX, Images.PNG_BLUR_B64);
|
||||||
// testOp(browser, "Bombe", "test input", "test_output");
|
// testOp(browser, "Bombe", "test input", "test_output");
|
||||||
// testOp(browser, "Bzip2 Compress", "test input", "test_output");
|
testOp(browser, ["Bzip2 Compress", "To Hex"], "test input", "42 5a 68 39 31 41 59 26 53 59 cf 96 82 1d 00 00 03 91 80 40 00 02 21 4e 00 20 00 21 90 c2 10 c0 88 33 92 8e df 17 72 45 38 50 90 cf 96 82 1d");
|
||||||
// testOp(browser, "Bzip2 Decompress", "test input", "test_output");
|
testOp(browser, ["From Hex", "Bzip2 Decompress"], "425a68393141592653597b0884b7000003038000008200ce00200021a647a4218013709517c5dc914e14241ec2212dc0", "test_output", [[], [true]]);
|
||||||
// testOp(browser, "CRC-16 Checksum", "test input", "test_output");
|
// testOp(browser, "CRC-16 Checksum", "test input", "test_output");
|
||||||
// testOp(browser, "CRC-32 Checksum", "test input", "test_output");
|
// testOp(browser, "CRC-32 Checksum", "test input", "test_output");
|
||||||
// testOp(browser, "CRC-8 Checksum", "test input", "test_output");
|
// testOp(browser, "CRC-8 Checksum", "test input", "test_output");
|
||||||
|
@ -69,10 +70,10 @@ module.exports = {
|
||||||
// testOp(browser, "Comment", "test input", "test_output");
|
// testOp(browser, "Comment", "test input", "test_output");
|
||||||
// testOp(browser, "Compare CTPH hashes", "test input", "test_output");
|
// testOp(browser, "Compare CTPH hashes", "test input", "test_output");
|
||||||
// testOp(browser, "Compare SSDEEP hashes", "test input", "test_output");
|
// testOp(browser, "Compare SSDEEP hashes", "test input", "test_output");
|
||||||
// testOp(browser, "Conditional Jump", "test input", "test_output");
|
// /testOp(browser, "Conditional Jump", "test input", "test_output");
|
||||||
// testOp(browser, "Contain Image", "test input", "test_output");
|
// testOp(browser, "Contain Image", "test input", "test_output");
|
||||||
// testOp(browser, "Convert area", "test input", "test_output");
|
// testOp(browser, "Convert area", "test input", "test_output");
|
||||||
// testOp(browser, "Convert co-ordinate format", "test input", "test_output");
|
// /testOp(browser, "Convert co-ordinate format", "test input", "test_output");
|
||||||
// testOp(browser, "Convert data units", "test input", "test_output");
|
// testOp(browser, "Convert data units", "test input", "test_output");
|
||||||
// testOp(browser, "Convert distance", "test input", "test_output");
|
// testOp(browser, "Convert distance", "test input", "test_output");
|
||||||
// testOp(browser, "Convert Image Format", "test input", "test_output");
|
// testOp(browser, "Convert Image Format", "test input", "test_output");
|
||||||
|
@ -197,10 +198,12 @@ module.exports = {
|
||||||
// testOp(browser, "MD4", "test input", "test_output");
|
// testOp(browser, "MD4", "test input", "test_output");
|
||||||
// testOp(browser, "MD5", "test input", "test_output");
|
// testOp(browser, "MD5", "test input", "test_output");
|
||||||
// testOp(browser, "MD6", "test input", "test_output");
|
// testOp(browser, "MD6", "test input", "test_output");
|
||||||
// testOp(browser, "Magic", "test input", "test_output");
|
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(1) th:nth-of-type(2)", "Result snippet");
|
||||||
|
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(2) td:nth-of-type(2)", "test_output");
|
||||||
|
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(2) td:nth-of-type(1)", /Base64/);
|
||||||
// testOp(browser, "Mean", "test input", "test_output");
|
// testOp(browser, "Mean", "test input", "test_output");
|
||||||
// testOp(browser, "Median", "test input", "test_output");
|
// testOp(browser, "Median", "test input", "test_output");`
|
||||||
// testOp(browser, "Merge", "test input", "test_output");
|
// testOp(browser, "Merge", "test input", "test_output");`
|
||||||
// testOp(browser, "Microsoft Script Decoder", "test input", "test_output");
|
// testOp(browser, "Microsoft Script Decoder", "test input", "test_output");
|
||||||
// testOp(browser, "Multiple Bombe", "test input", "test_output");
|
// testOp(browser, "Multiple Bombe", "test input", "test_output");
|
||||||
// testOp(browser, "Multiply", "test input", "test_output");
|
// testOp(browser, "Multiply", "test input", "test_output");
|
||||||
|
@ -372,34 +375,50 @@ module.exports = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/** @function
|
||||||
* Clears the current recipe and tests a new operation.
|
* Clears the current recipe and bakes a new operation.
|
||||||
*
|
*
|
||||||
* @param {string} opName
|
* @param {Browser} browser - Nightwatch client
|
||||||
* @param {Browser} browser
|
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
||||||
|
* @param {string} input - input text for test
|
||||||
|
* @param {Array<string>|Array<Array<string>>} args - aarguments, nested if multiple ops
|
||||||
*/
|
*/
|
||||||
function testOp(browser, opName, input, output, args=[]) {
|
function bakeOp(browser, opName, input, args=[]) {
|
||||||
|
let recipeConfig;
|
||||||
|
|
||||||
const recipeConfig = JSON.stringify([{
|
if (typeof(opName) === "string") {
|
||||||
"op": opName,
|
recipeConfig = JSON.stringify([{
|
||||||
"args": args
|
"op": opName,
|
||||||
}]);
|
"args": args
|
||||||
|
}]);
|
||||||
|
} else if (opName instanceof Array) {
|
||||||
|
recipeConfig = JSON.stringify(
|
||||||
|
opName.map((op, i) => {
|
||||||
|
return {
|
||||||
|
op: op,
|
||||||
|
args: args.length ? args[i] : []
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid operation type. Must be string or array of strings. Received: " + typeof(opName));
|
||||||
|
}
|
||||||
|
|
||||||
browser
|
browser
|
||||||
.perform(function() {
|
|
||||||
console.log(opName);
|
|
||||||
})
|
|
||||||
.useCss()
|
.useCss()
|
||||||
.click("#clr-recipe")
|
.click("#clr-recipe")
|
||||||
.click("#clr-io")
|
.click("#clr-io")
|
||||||
.waitForElementNotPresent("#rec-list li.operation")
|
.waitForElementNotPresent("#rec-list li.operation")
|
||||||
.expect.element("#input-text").to.have.value.that.equals("");
|
.expect.element("#input-text").to.have.property("value").that.equals("");
|
||||||
|
|
||||||
browser
|
browser
|
||||||
|
.perform(function() {
|
||||||
|
console.log(`Current test: ${opName}`);
|
||||||
|
})
|
||||||
.urlHash("recipe=" + recipeConfig)
|
.urlHash("recipe=" + recipeConfig)
|
||||||
.setValue("#input-text", input)
|
.setValue("#input-text", input)
|
||||||
.waitForElementPresent("#rec-list li.operation")
|
.waitForElementPresent("#rec-list li.operation")
|
||||||
.expect.element("#input-text").to.have.value.that.equals(input);
|
.expect.element("#input-text").to.have.property("value").that.equals(input);
|
||||||
|
|
||||||
browser
|
browser
|
||||||
.waitForElementVisible("#stale-indicator", 5000)
|
.waitForElementVisible("#stale-indicator", 5000)
|
||||||
|
@ -408,10 +427,44 @@ function testOp(browser, opName, input, output, args=[]) {
|
||||||
.pause(100)
|
.pause(100)
|
||||||
.waitForElementPresent("#stale-indicator.hidden", 5000)
|
.waitForElementPresent("#stale-indicator.hidden", 5000)
|
||||||
.waitForElementNotVisible("#output-loader", 5000);
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @function
|
||||||
|
* Clears the current recipe and tests a new operation.
|
||||||
|
*
|
||||||
|
* @param {Browser} browser - Nightwatch client
|
||||||
|
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
||||||
|
* @param {string} input - input text
|
||||||
|
* @param {string} output - expected output
|
||||||
|
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
||||||
|
*/
|
||||||
|
function testOp(browser, opName, input, output, args=[]) {
|
||||||
|
|
||||||
|
bakeOp(browser, opName, input, args);
|
||||||
|
|
||||||
if (typeof output === "string") {
|
if (typeof output === "string") {
|
||||||
browser.expect.element("#output-text").to.have.value.that.equals(output);
|
browser.expect.element("#output-text").to.have.property("value").that.equals(output);
|
||||||
} else if (output instanceof RegExp) {
|
} else if (output instanceof RegExp) {
|
||||||
browser.expect.element("#output-text").to.have.value.that.matches(output);
|
browser.expect.element("#output-text").to.have.property("value").that.matches(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @function
|
||||||
|
* Clears the current recipe and tests a new operation.
|
||||||
|
*
|
||||||
|
* @param {Browser} browser - Nightwatch client
|
||||||
|
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
|
||||||
|
* @param {string} input - input text
|
||||||
|
* @param {string} cssSelector - CSS selector for HTML output
|
||||||
|
* @param {string} output - expected output
|
||||||
|
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
||||||
|
*/
|
||||||
|
function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
|
||||||
|
bakeOp(browser, opName, input, args);
|
||||||
|
|
||||||
|
if (typeof output === "string") {
|
||||||
|
browser.expect.element("#output-html " + cssSelector).text.that.equals(output);
|
||||||
|
} else if (output instanceof RegExp) {
|
||||||
|
browser.expect.element("#output-html " + cssSelector).text.that.matches(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,24 +6,27 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const chef = require("cyberchef");
|
|
||||||
const assert = require("assert");
|
const assert = require("assert");
|
||||||
|
|
||||||
const d = chef.bake("Testing, 1 2 3", [
|
require("cyberchef").then(chef => {
|
||||||
chef.toHex,
|
|
||||||
chef.reverse,
|
|
||||||
{
|
|
||||||
op: chef.unique,
|
|
||||||
args: {
|
|
||||||
delimiter: "Space",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
op: chef.multiply,
|
|
||||||
args: {
|
|
||||||
delimiter: "Space",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert.equal(d.value, "630957449041920");
|
const d = chef.bake("Testing, 1 2 3", [
|
||||||
|
chef.toHex,
|
||||||
|
chef.reverse,
|
||||||
|
{
|
||||||
|
op: chef.unique,
|
||||||
|
args: {
|
||||||
|
delimiter: "Space",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: chef.multiply,
|
||||||
|
args: {
|
||||||
|
delimiter: "Space",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.equal(d.value, "630957449041920");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
|
@ -7,8 +7,28 @@
|
||||||
*/
|
*/
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import chef from "cyberchef";
|
import chef from "cyberchef";
|
||||||
|
import { bake, toHex, reverse, unique, multiply } from "cyberchef";
|
||||||
|
|
||||||
const d = chef.bake("Testing, 1 2 3", [
|
const a = bake("Testing, 1 2 3", [
|
||||||
|
toHex,
|
||||||
|
reverse,
|
||||||
|
{
|
||||||
|
op: unique,
|
||||||
|
args: {
|
||||||
|
delimiter: "Space",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: multiply,
|
||||||
|
args: {
|
||||||
|
delimiter: "Space",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.equal(a.value, "630957449041920");
|
||||||
|
|
||||||
|
const b = chef.bake("Testing, 1 2 3", [
|
||||||
chef.toHex,
|
chef.toHex,
|
||||||
chef.reverse,
|
chef.reverse,
|
||||||
{
|
{
|
||||||
|
@ -25,4 +45,4 @@ const d = chef.bake("Testing, 1 2 3", [
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert.equal(d.value, "630957449041920");
|
assert.equal(b.value, "630957449041920");
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
/**
|
|
||||||
* Tests to ensure that a consuming app can use named imports from deep import patch
|
|
||||||
*
|
|
||||||
* @author d98762625 [d98762625@gmail.com]
|
|
||||||
* @copyright Crown Copyright 2019
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
import assert from "assert";
|
|
||||||
import { bake, toHex, reverse, unique, multiply } from "cyberchef/src/node/index.mjs";
|
|
||||||
|
|
||||||
const d = bake("Testing, 1 2 3", [
|
|
||||||
toHex,
|
|
||||||
reverse,
|
|
||||||
{
|
|
||||||
op: unique,
|
|
||||||
args: {
|
|
||||||
delimiter: "Space",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
op: multiply,
|
|
||||||
args: {
|
|
||||||
delimiter: "Space",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert.equal(d.value, "630957449041920");
|
|
|
@ -1,6 +1,6 @@
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import Categories from "../../../src/core/config/Categories.json";
|
import Categories from "../../../src/core/config/Categories.json" assert {type: "json"};
|
||||||
import OperationConfig from "../../../src/core/config/OperationConfig.json";
|
import OperationConfig from "../../../src/core/config/OperationConfig.json" assert {type: "json"};
|
||||||
import it from "../assertionHandler.mjs";
|
import it from "../assertionHandler.mjs";
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ TestRegister.addApiTests([
|
||||||
assert.strictEqual(result[0].module, "Ciphers");
|
assert.strictEqual(result[0].module, "Ciphers");
|
||||||
assert.strictEqual(result[0].inputType, "string");
|
assert.strictEqual(result[0].inputType, "string");
|
||||||
assert.strictEqual(result[0].outputType, "string");
|
assert.strictEqual(result[0].outputType, "string");
|
||||||
assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.");
|
assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.");
|
||||||
assert.strictEqual(result[0].args.length, 5);
|
assert.strictEqual(result[0].args.length, 5);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ import {
|
||||||
CSSMinify,
|
CSSMinify,
|
||||||
toBase64,
|
toBase64,
|
||||||
toHex
|
toHex
|
||||||
} from "../../../src/node/index";
|
} from "../../../src/node/index.mjs";
|
||||||
import chef from "../../../src/node/index.mjs";
|
import chef from "../../../src/node/index.mjs";
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import File from "../../../src/node/File.mjs";
|
import File from "../../../src/node/File.mjs";
|
||||||
|
@ -471,7 +471,7 @@ color: white;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("Extract dates", () => {
|
it("Extract dates", () => {
|
||||||
assert.strictEqual(chef.extractDates("Don't Look a Gift Horse In The Mouth 01/02/1992").toString(), "01/02/1992\n");
|
assert.strictEqual(chef.extractDates("Don't Look a Gift Horse In The Mouth 01/02/1992").toString(), "01/02/1992");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("Filter", () => {
|
it("Filter", () => {
|
||||||
|
@ -685,8 +685,8 @@ Arguments:
|
||||||
it("Parse user agent", () => {
|
it("Parse user agent", () => {
|
||||||
const result = chef.parseUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 ");
|
const result = chef.parseUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 ");
|
||||||
const expected = `Browser
|
const expected = `Browser
|
||||||
Name: Mozilla
|
Name: Firefox
|
||||||
Version: 5.0
|
Version: 47.0
|
||||||
Device
|
Device
|
||||||
Model: unknown
|
Model: unknown
|
||||||
Type: unknown
|
Type: unknown
|
||||||
|
@ -816,7 +816,7 @@ pCGTErs=
|
||||||
it("RC4 Drop", () => {
|
it("RC4 Drop", () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
chef.RC4Drop("Go Out On a Limb", {passphrase: {string: "Under Your Nose", option: "UTF8"}, inputFormat: "UTF8", outputFormat: "Hex"}).toString(),
|
chef.RC4Drop("Go Out On a Limb", {passphrase: {string: "Under Your Nose", option: "UTF8"}, inputFormat: "UTF8", outputFormat: "Hex"}).toString(),
|
||||||
"8fa5f2751d34476a0c857439f43816cf");
|
"b85cb1c4ed6bed8f260ab92829bba942");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("Regular Expression", () => {
|
it("Regular Expression", () => {
|
||||||
|
@ -879,8 +879,7 @@ FROM STATS;`;
|
||||||
const result = chef.strings("smothering ampersand abreast", {displayTotal: true});
|
const result = chef.strings("smothering ampersand abreast", {displayTotal: true});
|
||||||
const expected = `Total found: 1
|
const expected = `Total found: 1
|
||||||
|
|
||||||
smothering ampersand abreast
|
smothering ampersand abreast`;
|
||||||
`;
|
|
||||||
assert.strictEqual(result.toString(), expected);
|
assert.strictEqual(result.toString(), expected);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import TestRegister from "../lib/TestRegister.mjs";
|
||||||
import "./tests/BCD.mjs";
|
import "./tests/BCD.mjs";
|
||||||
import "./tests/BSON.mjs";
|
import "./tests/BSON.mjs";
|
||||||
import "./tests/BaconCipher.mjs";
|
import "./tests/BaconCipher.mjs";
|
||||||
|
import "./tests/Base45.mjs";
|
||||||
import "./tests/Base58.mjs";
|
import "./tests/Base58.mjs";
|
||||||
import "./tests/Base64.mjs";
|
import "./tests/Base64.mjs";
|
||||||
import "./tests/Base62.mjs";
|
import "./tests/Base62.mjs";
|
||||||
|
@ -74,6 +75,7 @@ import "./tests/SeqUtils.mjs";
|
||||||
import "./tests/SetDifference.mjs";
|
import "./tests/SetDifference.mjs";
|
||||||
import "./tests/SetIntersection.mjs";
|
import "./tests/SetIntersection.mjs";
|
||||||
import "./tests/SetUnion.mjs";
|
import "./tests/SetUnion.mjs";
|
||||||
|
import "./tests/SM4.mjs";
|
||||||
import "./tests/StrUtils.mjs";
|
import "./tests/StrUtils.mjs";
|
||||||
import "./tests/SymmetricDifference.mjs";
|
import "./tests/SymmetricDifference.mjs";
|
||||||
import "./tests/TextEncodingBruteForce.mjs";
|
import "./tests/TextEncodingBruteForce.mjs";
|
||||||
|
@ -107,6 +109,8 @@ import "./tests/CBORDecode.mjs";
|
||||||
import "./tests/JA3Fingerprint.mjs";
|
import "./tests/JA3Fingerprint.mjs";
|
||||||
import "./tests/JA3SFingerprint.mjs";
|
import "./tests/JA3SFingerprint.mjs";
|
||||||
import "./tests/HASSH.mjs";
|
import "./tests/HASSH.mjs";
|
||||||
|
import "./tests/GetAllCasings.mjs";
|
||||||
|
import "./tests/SIGABA.mjs";
|
||||||
|
|
||||||
|
|
||||||
// Cannot test operations that use the File type yet
|
// Cannot test operations that use the File type yet
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import TestRegister from "../../lib/TestRegister";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* @copyright Karsten Silkenbäumer 2019
|
* @copyright Karsten Silkenbäumer 2019
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../lib/TestRegister";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import { BACON_ALPHABETS, BACON_TRANSLATIONS } from "../../../src/core/lib/Bacon";
|
import { BACON_ALPHABETS, BACON_TRANSLATIONS } from "../../../src/core/lib/Bacon.mjs";
|
||||||
|
|
||||||
const alphabets = Object.keys(BACON_ALPHABETS);
|
const alphabets = Object.keys(BACON_ALPHABETS);
|
||||||
const translations = BACON_TRANSLATIONS;
|
const translations = BACON_TRANSLATIONS;
|
||||||
|
|
103
tests/operations/tests/Base45.mjs
Normal file
103
tests/operations/tests/Base45.mjs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/**
|
||||||
|
* Base45 tests.
|
||||||
|
*
|
||||||
|
* @author Thomas Weißschuh [thomas@t-8ch.de]
|
||||||
|
*
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
const defaultB45Alph = "0-9A-Z $%*+\\-./:";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "To Base45: nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Base45: Spec encoding example 1",
|
||||||
|
input: "AB",
|
||||||
|
expectedOutput: "BB8",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Base45: Spec encoding example 2",
|
||||||
|
input: "Hello!!",
|
||||||
|
expectedOutput: "%69 VD92EX0",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Base45: Spec encoding example 3",
|
||||||
|
input: "base-45",
|
||||||
|
expectedOutput: "UJCLQE7W581",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Base45: nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Base45: Spec decoding example 1",
|
||||||
|
input: "QED8WEX0",
|
||||||
|
expectedOutput: "ietf!",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Base45: Invalid character",
|
||||||
|
input: "!",
|
||||||
|
expectedOutput: "Character not in alphabet: '!'",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Base45: Invalid triplet value",
|
||||||
|
input: "ZZZ",
|
||||||
|
expectedOutput: "Triplet too large: 'ZZZ'",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Base45",
|
||||||
|
args: [defaultB45Alph],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
|
@ -11,7 +11,7 @@ TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Extract email address",
|
name: "Extract email address",
|
||||||
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
|
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
|
||||||
expectedOutput: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com\n",
|
expectedOutput: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
"op": "Extract email addresses",
|
||||||
|
@ -22,7 +22,7 @@ TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Extract email address - Display total",
|
name: "Extract email address - Display total",
|
||||||
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
|
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
|
||||||
expectedOutput: "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com\n",
|
expectedOutput: "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
"op": "Extract email addresses",
|
||||||
|
@ -33,7 +33,7 @@ TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Extract email address (Internationalized)",
|
name: "Extract email address (Internationalized)",
|
||||||
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
||||||
expectedOutput: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com\n",
|
expectedOutput: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
"op": "Extract email addresses",
|
||||||
|
@ -44,7 +44,7 @@ TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Extract email address - Display total (Internationalized)",
|
name: "Extract email address - Display total (Internationalized)",
|
||||||
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
||||||
expectedOutput: "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com\n",
|
expectedOutput: "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Extract email addresses",
|
"op": "Extract email addresses",
|
||||||
|
|
44
tests/operations/tests/GetAllCasings.mjs
Normal file
44
tests/operations/tests/GetAllCasings.mjs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* GetAllCasings tests.
|
||||||
|
*
|
||||||
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "All casings of test",
|
||||||
|
input: "test",
|
||||||
|
expectedOutput: "test\nTest\ntEst\nTEst\nteSt\nTeSt\ntESt\nTESt\ntesT\nTesT\ntEsT\nTEsT\nteST\nTeST\ntEST\nTEST",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Get All Casings",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "All casings of t",
|
||||||
|
input: "t",
|
||||||
|
expectedOutput: "t\nT",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Get All Casings",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "All casings of null",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Get All Casings",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
|
@ -9,7 +9,7 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import { GIF_ANIMATED_HEX, PNG_HEX, JPG_B64, EXIF_JPG_HEX, NO_EXIF_JPG_HEX } from "../samples/Images.mjs";
|
import { GIF_ANIMATED_HEX, PNG_HEX, JPG_B64, EXIF_JPG_HEX, NO_EXIF_JPG_HEX } from "../../samples/Images.mjs";
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import { JPG_RAW } from "../samples/Images.mjs";
|
import { JPG_RAW } from "../../samples/Images.mjs";
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../samples/Ciphers.mjs";
|
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../../samples/Ciphers.mjs";
|
||||||
|
|
||||||
// RSA-1024
|
// RSA-1024
|
||||||
const ALICE_PRIVATE = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
const ALICE_PRIVATE = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../samples/Ciphers.mjs";
|
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../../samples/Ciphers.mjs";
|
||||||
|
|
||||||
const PEM_PRIV_2048 = `-----BEGIN RSA PRIVATE KEY-----
|
const PEM_PRIV_2048 = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIEpAIBAAKCAQEAwfaUOpUEutKyU3wkCv6kYunz4MqxzSuTSckRz1IxwZtwIiqq
|
MIIEpAIBAAKCAQEAwfaUOpUEutKyU3wkCv6kYunz4MqxzSuTSckRz1IxwZtwIiqq
|
||||||
|
|
91
tests/operations/tests/SIGABA.mjs
Normal file
91
tests/operations/tests/SIGABA.mjs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* SIGABA machine tests
|
||||||
|
*
|
||||||
|
* @author hettysymes
|
||||||
|
* @copyright hettysymes 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "SIGABA: encrypt test 1",
|
||||||
|
input: "HELLO WORLD TESTING THE SIGABA MACHINE",
|
||||||
|
expectedOutput: "ULBECJCZJBJFVUDWAVRGRBMPSQHOTTNVQEESKN",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SIGABA",
|
||||||
|
"args": [
|
||||||
|
"BHKWECJDOVAYLFMITUGXRNSPZQ", true, "G",
|
||||||
|
"CDTAKGQOZXLVJYHSWMIBPRUNEF", false, "L",
|
||||||
|
"WAXHJZMBVDPOLTUYRCQFNSGKEI", false, "I",
|
||||||
|
"HUSCWIMJQXDALVGBFTOYZKRPNE", false, "T",
|
||||||
|
"RTLSMNKXFVWQUZGCHEJBYDAIPO", false, "B",
|
||||||
|
"GHAQBRJWDMNZTSKLOUXYPFIECV", false, "N",
|
||||||
|
"VFLGEMTCXZIQDYAKRPBONHWSUJ", true, "Q",
|
||||||
|
"ZQCAYHRJNXPFLKIOTBUSVWMGDE", false, "B",
|
||||||
|
"EZVSWPCTULGAOFDJNBIYMXKQHR", false, "J",
|
||||||
|
"ELKSGDXMVYJUZNCAROQBPWHITF", false, "R",
|
||||||
|
"3891625740", "3",
|
||||||
|
"6297135408", "1",
|
||||||
|
"2389715064", "8",
|
||||||
|
"9264351708", "6",
|
||||||
|
"9573086142", "6",
|
||||||
|
"Encrypt"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SIGABA: encrypt test 2",
|
||||||
|
input: "PCRPJZWSPNOHMWANBFBEIVZOXDQESPYDEFBNTHXLSICIRPKUATJVDUQFLZOKGHHHDUDIBRKUHVCGAGLBWVGFFXNDHKPFSPSCIIPCXUFRRHNYWIJFEJWQSGMSNJHWSLPKVXHUQUWIURHDIHIUTWGQFIYLTKEZAUESWYEKIWXUSSXWXBEHCXCUDQWKCISVPKXJVPOIJZWTUGKAORBMKBAQUZOPTSUSYZRROWQUYKNCLHVIHEGWCCONGVHEKCEXVYIPNILIXTXDELNGLJGMEQKKQJWZLPNXPOGIOSVAEAJYKWYJXXGKKPLVYAZGDCMNHMPLCYWDQSRBEMVVVZVFYJMRYGHJOTDOEQVRQOVXOGOVYGTXETFHAYELRYVDGWOFVGAOWPMHQYRZMNXVTAHWSKZLJDFVQPZGMHZWFNOBHSZHEDAEXIFCEEJYZDOEFOQWCXTKPJRUEITKHVCITCLKBUFNAFBYXELAYPBRGGGOCCAGLXXJXTSWCJHMHQPVUIBAGBDKAGEEEPKRGGICJQXSYHBNNAKGYODRAUWAEYHWCKHEQIBAONWQJYQCIFKDTOCTJMBJULWKMSNNMPXINHZQWUMJQLQKIPVZVRGYPCJJZMENWTFTUSPCSPRXHMZPCHCNQTUDCOUJHRKYQIUWWVEVVRYFDIYRQISNGPMQLNMCNMVBEWHNCUODHAGEVEUMKVZLEIKYAMPGVVSBYNRJMFCATDXTQCYXIBCXXKYEYHHYERQGQWZTWCEJBFQLRFFCIVVSZUKGLOTLNGLQNTIKTBBWVFMONUFKRLCJASEKUEEDDQDIVQMFRSJRNHYZJODFHSCJSDAIRUXOSDNFUFUFMNZYQIEGRUXKUPCHENUEZHRKYHDRJYSHLZNYRBWVXORMJMJRIRNSAJQRUMPCXUDFYRGKEAXQXJHPEWNIYIDURDGWIFEMSOFYYCFRZGMZXJNTLTJBBSZIULQSOMEVGCTCVXUHTIEHSPOPQYCJLPAJAPQPAQXE",
|
||||||
|
expectedOutput: "GMEXPPCMFGKUVGXZHVTCKXRSTJUYWNOKFVELWAHHSJBXGOEXCMLOVSIMCDMGEYMWWTFDUMCDUJEZITNPVVBGQDJEVHJXSKJAAUZWBELMSPUTXCUYPDTJCQXEBGWPWRSQLSNFMASCTJZDSFNKDDTAXLRGUPKCBNXMZPADJSFGGNYKRPYBNTYPTGVPACBEINILNACWFVKMJPGCEZFROEYYKTGYSQYMFSGVDOJJONNYEYSCCIXWLKUSJZDRVAQSNUWHMDJVDNNMPGOYRGQRSBGSPQKGCTFZQWSOXBWSQZDCRQJQAWZDPQEILGMMABIMCDPNSKAFCLPQGIRJCMGQREBEUHBYREXFABFMVZTZBDUMASVNUMHIYRSZLGNZFMVAIABLCUZLJLKKZPWEXDHYZFVSNRLCLNDRKLKSWRHQVQJRTHCNFZXDEXSLAXXOGMFVSGCJGAWOLGDMTLWSFNTCUVCCEACINRZAZZOGLEHHXLPHVKILBBJDPOOCILQKKGODSXOBDPZZDXHJLLBOBVFCHJVMUBUZZIKGCWGCYGXVEHHIJGPEQERWEZLILQNHPHALFKFMGADNELGBKILKIUETGDCBQUEOECWVFNOXTJKUYPWBNEKYSIKMVSAMBZGLIKDAOELRSTKFASEKABTUCPSFEGXXQGDFPSPVOLBHGLZSLLWCABSRKZDQQRKVCKXDGTIHPDNMPDZEXYFYKXZTPJPLYOFNLWAGKJEOHOYLMZELXIDWWNXPKEPUCKNNNHJLFYHPQNHMMCGMUPHSUSYYIVWTIMFKKKTFPGFTLTWWSQBRBMGBTZXPVULKNZIIKVTYLJFISGPTLZFTCLGNZOMVKZOIMUDGXRDDSVFRHRYWBEWHYLCUISYMRWAZZAQPJYXZQQKZLILOSHXUTQJFPTXQSREKSUDZTLGUDLUGOJMQHJRJHXCHQTKJULTWWQOXIRFRQEYBPJPEKXFIRMNATWNFBADOSIJVZYRYDBHDAEDJUVDHLDAU",
|
||||||
|
recipeConfig: [
|
||||||
|
{ "op": "SIGABA",
|
||||||
|
"args": [
|
||||||
|
"YCHLQSUGBDIXNZKERPVJTAWFOM", true, "A",
|
||||||
|
"INPXBWETGUYSAOCHVLDMQKZJFR", false, "B",
|
||||||
|
"WNDRIOZPTAXHFJYQBMSVEKUCGL", false, "C",
|
||||||
|
"TZGHOBKRVUXLQDMPNFWCJYEIAS", false, "D",
|
||||||
|
"YWTAHRQJVLCEXUNGBIPZMSDFOK", true, "E",
|
||||||
|
"QSLRBTEKOGAICFWYVMHJNXZUDP", false, "F",
|
||||||
|
"CHJDQIGNBSAKVTUOXFWLEPRMZY", false, "G",
|
||||||
|
"CDFAJXTIMNBEQHSUGRYLWZKVPO", true, "H",
|
||||||
|
"XHFESZDNRBCGKQIJLTVMUOYAPW", false, "I",
|
||||||
|
"EZJQXMOGYTCSFRIUPVNADLHWBK", false, "J",
|
||||||
|
"7591482630", "0",
|
||||||
|
"3810592764", "1",
|
||||||
|
"4086153297", "2",
|
||||||
|
"3980526174", "3",
|
||||||
|
"6497135280", "4",
|
||||||
|
"Encrypt"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SIGABA: decrypt test",
|
||||||
|
input: "AKDHFWAYSLHJDKXEVMJJHGKFTQBZPJPJILOVHMBYOAGBZVLLTQUOIKXFPUFNILBDPCAELMAPSXTLMUEGSDTNUDWGZDADBFELWWHKVPRZNDATDPYEHIDMTGAGPDEZYXFSASVKSBMXVOJQXRMHDBWUNZDTIIIVKHJYPIEUHAJCNBXNLGVFADEWIKXDJZBUTGOQBCQZWYKRVEENWRWWRYDNOAPGMODTPTUJZCLUCRDILJABNTBTWUEIJSJRQBUVCOUJJDWFMNNUHXBDFYXLGUMXQEAWSVHBXQGEOOGPYRVOAJLAIYIOHHEXACDTAWWCBGQRNPERSIKHTXPXKBUNACZLFZTRBMBBDDGKNBIQMFHZROCZZBGNZSJKDRRWPEQHLCFADNPWPWSLPIFNKBWQPMARUERGWUUODXSCOJQECGHIZRFRNRSXWSFWKISHHTUFRVXLHCQWGBMRDHCYDSVNIDDRSTODCGJSSBLUYOBGEWFOVKOZBJTYCAKMZECUGLJGTSZJNBOLTMUZRRSIGGRQHLRPMGLINASSMZOBNACKUMSFNIZAUFCPFXXOOTJQWWLZOFLGZLHJCWZJCRJKVOUDLNMKQATGVTOFHACAEKFLRWRTTMVRXHYGOTYPNBMUSKDAKXFCICUOVSWXGPQOYUUWTWRPQMEQCSDJMMJKELIHGEDYKWOVHVPUAIBFGAODXODXVFIIZIGWRZSBTIGXVHFABMMOPGVMLGHQQXNOEJRDLOBGUOWSELBHERZFSBLUODMOGIBNVGVGQYDBTKLOPNKZZNGLTTGZYYXIBAHZJDCILZXKNSJDHXWTYQLFHTUINTYSBPIXOPLOQHSAHGQPYUWYNPKMRBBBYIICCBBJRKWVLBIDBBEKJCXHLPUBMIGBUFYDPOCSRUNZOKMKJHMYFJZWFNHQZOGGRTNNUVLMRLDSAJIECTYCJKBYVNAXGCMGNVFJEDSATZQDQTYRBPLZKHAXMOVJZEDKINXKBUVWXXHTYUFO",
|
||||||
|
expectedOutput: "KTSOYDGMLPMVXEAJIATXCNQFXHBNCBXIJOCQGCQBRQSBYFOOEVPVXACBMIUIRNVMJHREKRHBSXJFSMWCKTTCYXJOFSJCQECXXCHTEGPEYSMYDHCSMODUAVBNLILYUIBBIXJCXXNQPCERRSMJTPQLMOXSKTRPWOFUSWXOYRJLBIJGIOYTEAEJEGGYAGSXNHNQTETANPWEGATHSBFLHCVHVIJUAKDVGQCWUSIFFFVAJYPJAFUYDXSLGPGESOUAYXBQIIOXWTXNOXLNCGWSUKVIBMOUGNHORYLSNVNNJLKKFDUAEISOLBLCXYHMDGVBVVVIKDLTMTDVWWJBXWXROVTJBXXKXLEWTTISKIUMYSACVUGGNANMCGUMFNQUXDLTHJNYTFIQEPKQQQSSROYJOILJYQXICXACWGOHCSHENXJILOMIIFCIOUDXDCINIVKIRJCVHWXSFQXMNRBJJWTPXNJADEOPEJBLKHKXNTORIRVRLXUXXAMKMODBXNLQCVJXVOTBRHXBBVJHPFEQFCRXYRRXHXPTXXSUESUTHUGOWQYQPQFPXQPVGEIRPQNKXXMBHIPECRUWFEWJUTYIKSMJSRQIQAIAMXTGDXSJIABHIGKUPJBCHWMVYTMQNQYGDHCNMBSVTPXNFRELFXXQYIOLCDEXDXDVSINICOXRMNSPICPQMOBIDJCNBJKXFAVMUXOXHERJIBIXLMXXULDXKXXHAQDXEXIWXOEEUGKSUGCMRWJDPYCYKXTPCOXMURAJCPRXKFJAJALERWRHVMFHOGMFHXGSXQDPJCJNXRQFGHKRCYTEBJDHPCMYFEAPWSVVMMBVUJJMCAAYURHUPVQVJYDCSNMQEMNIFEXYXIIXBVRVILXAUCBDXRJHGPKPYXHPPPNVSBBCDRLVVIYPKAKYIXTJVYDGVPHXULWMADBEICNIFKWUOOHEFNANDKOXMCVBVORLQYNXLULOEGVGWNKNMOHYVRSYSOVYGAKCGAWKGAIAQNQR",
|
||||||
|
recipeConfig: [
|
||||||
|
{ "op": "SIGABA",
|
||||||
|
"args": [
|
||||||
|
"YCHLQSUGBDIXNZKERPVJTAWFOM", true, "A",
|
||||||
|
"INPXBWETGUYSAOCHVLDMQKZJFR", false, "B",
|
||||||
|
"WNDRIOZPTAXHFJYQBMSVEKUCGL", false, "C",
|
||||||
|
"TZGHOBKRVUXLQDMPNFWCJYEIAS", false, "D",
|
||||||
|
"YWTAHRQJVLCEXUNGBIPZMSDFOK", true, "E",
|
||||||
|
"QSLRBTEKOGAICFWYVMHJNXZUDP", false, "F",
|
||||||
|
"CHJDQIGNBSAKVTUOXFWLEPRMZY", false, "G",
|
||||||
|
"CDFAJXTIMNBEQHSUGRYLWZKVPO", true, "H",
|
||||||
|
"XHFESZDNRBCGKQIJLTVMUOYAPW", false, "I",
|
||||||
|
"EZJQXMOGYTCSFRIUPVNADLHWBK", false, "J",
|
||||||
|
"7591482630", "0",
|
||||||
|
"3810592764", "1",
|
||||||
|
"4086153297", "2",
|
||||||
|
"3980526174", "3",
|
||||||
|
"6497135280", "4",
|
||||||
|
"Decrypt"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
279
tests/operations/tests/SM4.mjs
Normal file
279
tests/operations/tests/SM4.mjs
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
/**
|
||||||
|
* SM4 crypto tests.
|
||||||
|
*
|
||||||
|
* Test data used from IETF draft-ribose-cfrg-sm4-09, see:
|
||||||
|
* https://tools.ietf.org/id/draft-ribose-cfrg-sm4-09.html
|
||||||
|
*
|
||||||
|
* @author swesven
|
||||||
|
* @copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
/* Cleartexts */
|
||||||
|
const TWO_BLOCK_PLAIN = "aa aa aa aa bb bb bb bb cc cc cc cc dd dd dd dd ee ee ee ee ff ff ff ff aa aa aa aa bb bb bb bb";
|
||||||
|
const FOUR_BLOCK_PLAIN = "aa aa aa aa aa aa aa aa bb bb bb bb bb bb bb bb cc cc cc cc cc cc cc cc dd dd dd dd dd dd dd dd ee ee ee ee ee ee ee ee ff ff ff ff ff ff ff ff aa aa aa aa aa aa aa aa bb bb bb bb bb bb bb bb";
|
||||||
|
/* Keys */
|
||||||
|
const KEY_1 = "01 23 45 67 89 ab cd ef fe dc ba 98 76 54 32 10";
|
||||||
|
const KEY_2 = "fe dc ba 98 76 54 32 10 01 23 45 67 89 ab cd ef";
|
||||||
|
/* IV */
|
||||||
|
const IV = "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f";
|
||||||
|
/* Ciphertexts */
|
||||||
|
const ECB_1 = "5e c8 14 3d e5 09 cf f7 b5 17 9f 8f 47 4b 86 19 2f 1d 30 5a 7f b1 7d f9 85 f8 1c 84 82 19 23 04";
|
||||||
|
const ECB_2 = "c5 87 68 97 e4 a5 9b bb a7 2a 10 c8 38 72 24 5b 12 dd 90 bc 2d 20 06 92 b5 29 a4 15 5a c9 e6 00";
|
||||||
|
/* With PKCS#7 padding */
|
||||||
|
const ECB_1P ="5e c8 14 3d e5 09 cf f7 b5 17 9f 8f 47 4b 86 19 2f 1d 30 5a 7f b1 7d f9 85 f8 1c 84 82 19 23 04 00 2a 8a 4e fa 86 3c ca d0 24 ac 03 00 bb 40 d2";
|
||||||
|
const ECB_2P= "c5 87 68 97 e4 a5 9b bb a7 2a 10 c8 38 72 24 5b 12 dd 90 bc 2d 20 06 92 b5 29 a4 15 5a c9 e6 00 a2 51 49 20 93 f8 f6 42 89 b7 8d 6e 8a 28 b1 c6";
|
||||||
|
const CBC_1 = "78 eb b1 1c c4 0b 0a 48 31 2a ae b2 04 02 44 cb 4c b7 01 69 51 90 92 26 97 9b 0d 15 dc 6a 8f 6d";
|
||||||
|
const CBC_2 = "0d 3a 6d dc 2d 21 c6 98 85 72 15 58 7b 7b b5 9a 91 f2 c1 47 91 1a 41 44 66 5e 1f a1 d4 0b ae 38";
|
||||||
|
const OFB_1 = "ac 32 36 cb 86 1d d3 16 e6 41 3b 4e 3c 75 24 b7 1d 01 ac a2 48 7c a5 82 cb f5 46 3e 66 98 53 9b";
|
||||||
|
const OFB_2 = "5d cc cd 25 a8 4b a1 65 60 d7 f2 65 88 70 68 49 33 fa 16 bd 5c d9 c8 56 ca ca a1 e1 01 89 7a 97";
|
||||||
|
const CFB_1 = "ac 32 36 cb 86 1d d3 16 e6 41 3b 4e 3c 75 24 b7 69 d4 c5 4e d4 33 b9 a0 34 60 09 be b3 7b 2b 3f";
|
||||||
|
const CFB_2 = "5d cc cd 25 a8 4b a1 65 60 d7 f2 65 88 70 68 49 0d 9b 86 ff 20 c3 bf e1 15 ff a0 2c a6 19 2c c5";
|
||||||
|
const CTR_1 = "ac 32 36 cb 97 0c c2 07 91 36 4c 39 5a 13 42 d1 a3 cb c1 87 8c 6f 30 cd 07 4c ce 38 5c dd 70 c7 f2 34 bc 0e 24 c1 19 80 fd 12 86 31 0c e3 7b 92 6e 02 fc d0 fa a0 ba f3 8b 29 33 85 1d 82 45 14";
|
||||||
|
const CTR_2 = "5d cc cd 25 b9 5a b0 74 17 a0 85 12 ee 16 0e 2f 8f 66 15 21 cb ba b4 4c c8 71 38 44 5b c2 9e 5c 0a e0 29 72 05 d6 27 04 17 3b 21 23 9b 88 7f 6c 8c b5 b8 00 91 7a 24 88 28 4b de 9e 16 ea 29 06";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: ECB 1, No padding",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: ECB_1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: ECB 2, No padding",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: ECB_2,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: ECB 1, With padding",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: ECB_1P,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: "", option: "Hex"}, "ECB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: ECB 2, With padding",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: ECB_2P,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: "", option: "Hex"}, "ECB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: CBC 1",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: CBC_1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: CBC 2",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: CBC_2,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: OFB1",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: OFB_1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: OFB2",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: OFB_2,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: CFB1",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: CFB_1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: CFB2",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: CFB_2,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: CTR1",
|
||||||
|
input: FOUR_BLOCK_PLAIN,
|
||||||
|
expectedOutput: CTR_1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Encrypt: CTR1",
|
||||||
|
input: FOUR_BLOCK_PLAIN,
|
||||||
|
expectedOutput: CTR_2,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Encrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: ECB 1",
|
||||||
|
input: ECB_1,
|
||||||
|
expectedOutput: TWO_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: ECB 2",
|
||||||
|
input: ECB_2,
|
||||||
|
expectedOutput: TWO_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: "", option: "Hex"}, "ECB/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: CBC 1",
|
||||||
|
input: CBC_1,
|
||||||
|
expectedOutput: TWO_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: CBC 2",
|
||||||
|
input: CBC_2,
|
||||||
|
expectedOutput: TWO_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CBC/NoPadding", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: OFB1",
|
||||||
|
input: TWO_BLOCK_PLAIN,
|
||||||
|
expectedOutput: OFB_1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: OFB2",
|
||||||
|
input: OFB_2,
|
||||||
|
expectedOutput: TWO_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "OFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: CFB1",
|
||||||
|
input: CFB_1,
|
||||||
|
expectedOutput: TWO_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: CFB2",
|
||||||
|
input: CFB_2,
|
||||||
|
expectedOutput: TWO_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CFB", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: CTR1",
|
||||||
|
input: CTR_1,
|
||||||
|
expectedOutput: FOUR_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_1, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SM4 Decrypt: CTR1",
|
||||||
|
input: CTR_2,
|
||||||
|
expectedOutput: FOUR_BLOCK_PLAIN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "SM4 Decrypt",
|
||||||
|
"args": [{string: KEY_2, option: "Hex"}, {string: IV, option: "Hex"}, "CTR", "Hex", "Hex"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]);
|
|
@ -18,6 +18,18 @@ export const GIF_ANIMATED_HEX = "4749463839610f000f00b30b00424242ffe700ffef00ffc
|
||||||
*/
|
*/
|
||||||
export const PNG_HEX = "89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af400000006624b474400ff00ff00ffa0bda793000000097048597300000dd700000dd70142289b78000005184944415458c3c5575d6c145514feeeccecccacdbddb6e096a5dbcdb6d06d80d06090466d6953454ab52ad0a65589840ac1d02a313c989af062820fa66210130d9a68b0363c34610135690b188b7183c13f44506c8115ba535ab6ddd2617f667f66ae0fb41596ddee2eadf13c4de69e7bcf77cff9cecf25b83f613b3b3b975b2c96f25028c47a3c9e1f5a5a5a7e05a0016000d0c9ef9442d23448a60edeb973a769c78e1d077272721a65594620106000505996bf1a1f1f3f67369bebc2e1f0ef6bd7aedd0a409d2d00e2743a1f2929296915046199a66901007aa3d1580600131313da24000000a594124288aaaab72a2b2bed1d1d1d8f8ba2386fc3860d9f25f3c84c0088cbe56a2d2c2cdc4708d12552880770a7288a3228088215003c1ecfd68d1b377e9e488f4b66dde974aeb2dbed498da71251146d538ed1b4e4746092dddee170b4300ca3c32c251c0edfd8bc79f3d164de4e0680110461794a02119292c482202c387efcf86f3d3d3d7b13814816024a2955e62a8b4451b4abaafad8e485d5743ca005028153699c4dd30c83140a857e4c9409c900a0bbbbfbc368343a34a3754a693a1c58b76eddf2dadada5d89002705b07bf7eee13367ce3cab284aff6c482808425e6767e70bc9ea0033d3e6c6c6c65fd6ac5953a1695a3453c3a150c84d295529a59aa669914cd3705adc6eb7926eaca74455d5605555d5c3030303f59224bd525f5f7f30992e87ff40344d5328a5caa64d9bbe4ca5cbe07f1666ae522dae40a5dd8ed30941c8e5727d63341a9f8a5f181a1ac2f0f07022029e02109d2b00bae2e26207cbb2f72cf03c8f9c9c9c441c580c804dc70b330258b6c020beb87ac9abecb59f8b087377b4f4f30a68b6de482549a29224ddb5168bc51cd5d5d54ff6f5f575cfa69633edeb971c78e2d195db055e77cfb6a2eaadb816e5b59ffafb19a7d3095555e3ab64341a8d96f6f6f6fe755f247c69d542abd9c0bd3c70f90a628c30fd5f56542c5c550fc3837600406e6e2eca9e2e433837fcefc0c8b2e079fe7b9fcfe7aba9a9296613c52f55084acc864a027013b28c828a2d30e805bcbe670fac4b5740f5a9285b18c6a0db4da8c180fdc6fdb035d850c555a174a4148410b85cae7293c97442a7d395363434347775757d91b6075a2a6c45d66ce18369258685de644659d96af45ff80345f9f908c932821313c4eff7639b6d1b06838358242c82d96c86288abe582ce6e6797e052184701c9797910796e61976b10c991fff7f7b5313b6373541d5340426d36f747414e5c67294679503a1e90634e6f57adbac56ebb14020f0e9a14387decf84038c8e232b53b45888dc6dec63636389d290c9caca5a3d09a6a2a6a6a628130054d33092a2c52272bbe4515996113f16288ab2c86432bd01001cc72db5582caf651202eaf5473e7e80d7af270409d9cb320c0c66331ca5a5602c1624180d492412392bcbf2db46a3f1394992f665c481b77a2f9f78e719476b5e16ff2e00d31dae8524cb30e8f560390ee72e5e243d7d7d34168bc16030a87575752ccbb20400a2d1e8b7478e1c390ce0f0fd5442fae6d7039f343d643956345f5fcbf1fafd00b219868145afc78d4b97101a1b833a32426d361bcdcfcf87cd6663a7a6649ee70725497a6faede86e4c2c993cf171716eee5753aeb9d0b7f5ebfae5df67a99b86164e8e6cd9badcdcdcdc7d27ae5a6a3f45147c7794dd30e2e59bcf896c0f3851ccbe602c0a8df4fc783413269d8130c06f79d3e7d7a4b5b5bdbd9b45b77c60304c3f0df75752db31714acf8dbe7cbbee2f5fafd7efff9f6f6f6b357af5e8d647ade3fa1780bad734c65970000000049454e44ae426082";
|
export const PNG_HEX = "89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af400000006624b474400ff00ff00ffa0bda793000000097048597300000dd700000dd70142289b78000005184944415458c3c5575d6c145514feeeccecccacdbddb6e096a5dbcdb6d06d80d06090466d6953454ab52ad0a65589840ac1d02a313c989af062820fa66210130d9a68b0363c34610135690b188b7183c13f44506c8115ba535ab6ddd2617f667f66ae0fb41596ddee2eadf13c4de69e7bcf77cff9cecf25b83f613b3b3b975b2c96f25028c47a3c9e1f5a5a5a7e05a0016000d0c9ef9442d23448a60edeb973a769c78e1d077272721a65594620106000505996bf1a1f1f3f67369bebc2e1f0ef6bd7aedd0a409d2d00e2743a1f2929296915046199a66901007aa3d1580600131313da24000000a594124288aaaab72a2b2bed1d1d1d8f8ba2386fc3860d9f25f3c84c0088cbe56a2d2c2cdc4708d12552880770a7288a3228088215003c1ecfd68d1b377e9e488f4b66dde974aeb2dbed498da71251146d538ed1b4e4746092dddee170b4300ca3c32c251c0edfd8bc79f3d164de4e0680110461794a02119292c482202c387efcf86f3d3d3d7b13814816024a2955e62a8b4451b4abaafad8e485d5743ca005028153699c4dd30c83140a857e4c9409c900a0bbbbfbc368343a34a3754a693a1c58b76eddf2dadada5d89002705b07bf7eee13367ce3cab284aff6c482808425e6767e70bc9ea0033d3e6c6c6c65fd6ac5953a1695a3453c3a150c84d295529a59aa669914cd3705adc6eb7926eaca74455d5605555d5c3030303f59224bd525f5f7f30992e87ff40344d5328a5caa64d9bbe4ca5cbe07f1666ae522dae40a5dd8ed30941c8e5727d63341a9f8a5f181a1ac2f0f07022029e02109d2b00bae2e26207cbb2f72cf03c8f9c9c9c441c580c804dc70b330258b6c020beb87ac9abecb59f8b087377b4f4f30a68b6de482549a29224ddb5168bc51cd5d5d54ff6f5f575cfa69633edeb971c78e2d195db055e77cfb6a2eaadb816e5b59ffafb19a7d3095555e3ab64341a8d96f6f6f6fe755f247c69d542abd9c0bd3c70f90a628c30fd5f56542c5c550fc3837600406e6e2eca9e2e433837fcefc0c8b2e079fe7b9fcfe7aba9a9296613c52f55084acc864a027013b28c828a2d30e805bcbe670fac4b5740f5a9285b18c6a0db4da8c180fdc6fdb035d850c555a174a4148410b85cae7293c97442a7d395363434347775757d91b6075a2a6c45d66ce18369258685de644659d96af45ff80345f9f908c932821313c4eff7639b6d1b06838358242c82d96c86288abe582ce6e6797e052184701c9797910796e61976b10c991fff7f7b5313b6373541d5340426d36f747414e5c67294679503a1e90634e6f57adbac56ebb14020f0e9a14387decf84038c8e232b53b45888dc6dec63636389d290c9caca5a3d09a6a2a6a6a628130054d33092a2c52272bbe4515996113f16288ab2c86432bd01001cc72db5582caf651202eaf5473e7e80d7af270409d9cb320c0c66331ca5a5602c1624180d492412392bcbf2db46a3f1394992f665c481b77a2f9f78e719476b5e16ff2e00d31dae8524cb30e8f560390ee72e5e243d7d7d34168bc16030a87575752ccbb20400a2d1e8b7478e1c390ce0f0fd5442fae6d7039f343d643956345f5fcbf1fafd00b219868145afc78d4b97101a1b833a32426d361bcdcfcf87cd6663a7a6649ee70725497a6faede86e4c2c993cf171716eee5753aeb9d0b7f5ebfae5df67a99b86164e8e6cd9badcdcdcdc7d27ae5a6a3f45147c7794dd30e2e59bcf896c0f3851ccbe602c0a8df4fc783413269d8130c06f79d3e7d7a4b5b5bdbd9b45b77c60304c3f0df75752db31714acf8dbe7cbbee2f5fafd7efff9f6f6f6b357af5e8d647ade3fa1780bad734c65970000000049454e44ae426082";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CyberChef logo with 'chef'
|
||||||
|
* 32x32
|
||||||
|
*/
|
||||||
|
export const PNG_CHEF_B64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAH40lEQVR4AaXBfVAU5wEH4N/77t7ufXAnHlwE5MuK1uApVo1ppNBxgpJKKyijaewYJzRj0eokjBpbp3HQ0VpN1fqHndCxNkW4UWf8KHZaa0yR1hPH04QGGwm9Ata7KN/c5m5v9+52t8tIp1QPJOnzEHw5TF1dnTMlJWVxOBxmfD7fjY0bN34EQAVAAWgAVEwAwcQQABSAtmXLFltlZeW7iYmJqwVBQCgUogA0QRAuDg4OfuxwOEpkWW5dunRpBQAFT8FifOTcuXPPz5w5cxPP87mqqoYAmKxW63N4RMUjxGazrbBard8hOp7ncziOe7O2tnaJ0Wi0l5WVnQCgIg6CsRG3270pOzv7CCHEgDgCgYAaCoUo4pAk6T7P81Oh8/l8FStXrvwt4mAxhnPnzi3Myso6Qggx4EswGo0ZeERTVRVjoYiPzJgxYyOl1ID/kyzLPevWrbsAgCAOBvExVVVVOzmOm4pxRCIRRCIRgnGwLJvwim7NmjUZdXV17+MxLOLTdBKejmACjEZjlqIoLwCgABSMQhGfGgqFmvB0GiZAlmV/OBz2AFDxGAZjyMzMvOt0OtcyDGPFiEgkAkVRwDAMhkmSpEWjUYJxyLLcU1xcnHvixIkGABpGEEIM6enpLxCMkpOT82JpaenLHMc9IwiCv6CgoG3RokWbjUbjTOh4nofX60VGRgaGBQIBNRQKUTyFz+fbWFZW9i5GmM3m9IaGhsb8/PxsihHbtm071traeikpKYnz+/2fLFiwILu8vPwXBw4cOK+qahQ6RVGgaRomIhwOd2qapmiapuoiGKWiomJbZmbm5OTk5K+y0BUUFHx33759P8jLy1vW1tb2Z+hqa2vR3Ny87/Dhwzs7OjrgcDgwUYqiiIWFhQvq6+sLzGazY9WqVe9hlPLy8rzTp097QqFQBwPd3r17a65evfo3l8u1H6O0tbW17t69e3t7ezvsdjsopRgcHITZbEYoFMLQ0BCRJAkcx2E0SZKI3+9/0NXVNd3j8fR1dna2K4oSYxjGuH79+h8WFxcXWSwWo8Fg4BldQk1NzaHjx4//+s6dOzcwSjQaFevr6z+orKys4DgOlFLwPA+bzQZVVWGz2TB37lx4vV5wHIdhQ0NDcDqddP78+Xmpqal07dq1r5WUlKw6pSOEsOvWrdvtdDqn2e1229DQUCLL83xCcnKy2e/3P0QcXq/3I5PJFAHAQWe329HV1YXk5GQEAgH19u3b1OFwQBRFaJoGq9WKvr4+LF68+NlYLCZYrdYUj8fTunz58sqGhoZ3qqqqlsybN6/x8uXLgf3795dRAAQ6RVFUxBd2u90ftLS0QBAEeDwe+Hw+tLS0wO12w+PxIC0tDZcuXcLFixexcOFCnDp1CoqiRAkhfDAYHLxy5cq1/Pz8ZRiFUkqgY1VVVaBLSkqyIj5DTk7ODIZhYDQaYTAYkJSUhGEcx6Gvrw8Mw2DWrFkQRRGUUlRXV6O6ulrEKC6X60PEwcqyPHD37t3eaTo8JneKxfjW1jdD/X9vplMmGQHL10Gkz0EG22Gyp2uTTFbtQTQKTdPQ3t6uASDQ7dq1C263u+rmzZt/xIhYLCYjDqppWuzChQt/WLFixcuUUh7/Rb//0iLP+u17qfbwLqj3ryChASAcAPVeQ5rZTCwMQ6BTVRXNzc3k+vXriMVi0DQNZrP5YH5+PoLB4KeiKHZIktSFOCh0R48e/emcOXNSt27desxoNCZC99o3Zy158fUfO1uuN8LORPAfiqohdeEqWJKzMMxkMoFSCnmyDEIIampqsGHDBjgcDjqgW758+WKXy3WpqKhoC+Jgoevu7m4vLCz81smTJ3+zZ8+eXlEUowkWs+nTm024VrMTqzcfgsXE48N+AYMw45MBBc+lyrjf2UlgMCBGYugv70chWwj+Mx49PT2oqalhJEnq4TgObrcbN27ceBVxEIxCCGHT09Odq/JSv+ZMZk8YIgKkmIrVb52A3ZGK42fP4tqtW9j7xhuwMAyabt2CYDKhK7MLxx4ew9uOt5EdzkYwGBxobGy0chxngG5gYGCby+U6hBFTpkyZJkmSEggE/sXgf6mCIDz83mxrhZlGn4cupmqYnV8Kk8WK+bm5KCsqgsVsRkwQ0NndjR5RRK4lF6VcKRJjiRhGCPE1NTW9brFYXhEE4bjL5foJAA0jQqHQkCzLAegonkQNLJmPcciyDCPLYlh/fz8ep6oqTUhI+AZ0PM/nL1u2bBrGQPEkTVXRjXHwPI8IdIRogiBA0zSMJknSV2w223boWJZ9NiUlZTPGwOJJWm8wUmPmTKWEgEEcDKWwOByYMWcOaEoKCCF4DIlEIi2CIOy1Wq0r/H7/EYyBRRzVf/rn+z/79oxNzyRw7wCwYYSqqvALAiwmExiWxcdtbeTS1ataLBaDxWJRSkpKGB2BLhqNNp4/f/4sgLMYB4v4tB/9/h+/WjMv5XfTkkwvsZzpKIBJlFKkmEzo8XoR7u+H0t2tZWRkaGlpacjIyGCIDjqO4+77/f5DmAAW4zjT8rAbQO2rPb1yjtnyc85gmGrgeUydPRvDog8eaIm9vRSjKIrymSiKW5qamvyYAAYT8Mva2juqqr43a/r0z3mOy2YZZjJ0fcGgNiiKBDpFUXyiKB5pbm5ev2PHjhZMEMEXRCnl/nLmTG5Wenpe18DApI7e3qDuzsGDB1vu3bsXwRf0bxUQXc2aUJWHAAAAAElFTkSuQmCC";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CyberChef logo with blur
|
||||||
|
* 32x32
|
||||||
|
*/
|
||||||
|
export const PNG_BLUR_B64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAANT0lEQVR4AS3BC5CV1X0A8P8553s/7mMvyz5gWUFApEKpEtloSQdLDDDoREXMDK1Zx8dg4xjHqdWpQwgI29QoFrE6gyFJ6YhmoDNMapIBYhzHqgg1ZAvRdIVld5Vl9+597N17v+8779NNJ78fklL6GzdutJ955hnnrbfect98803vxIkTwccffxwdOnQoGhoaihuNRiilDKvValCr1XzGmNtqtdz29naru7sburq6dG9vr1i6dClbtWoV7evryzZv3pw8/PDDSX9/f+vIkSPN/fv3t86cOZMYY7KBgQFarVY5AAjr4MGD6KOPPsK1Wg0bY4ht25Y9q1gs2h0dHW6apm5PT4/HGPMrlYpv23aQJIk3y8nn85bneYgQopVSglJq1et1Mjk5iS5fvqzPnz+vzp49K44fP85uueUW++jRozalVDz77LOkUCjg/v5+hI8dO4YajQZSSuE0TYnW2rJneZ7nlEolt7293SuVSn5nZ6ff1tYWtrW1hcViMczn81EYhpHjOBFCKNJah5TSsNVqBZVKJRgdHQ0uXLjgnzt3znv77bfdo0ePOkeOHLEPHTpkHThwgKxbt46sWLECk4sXL3ozMzPWmTNnnEaj4QwPD3vbt2/3a7VaeOXKlVBKGRFCIsdxIilluGPHjnDXrl0BQsh3Xdf3PM8dGBiwXNe1fN/Hvu8jz/MgjmP98ssvq3379qkoiuTrr78ub731VvHhhx+qbdu2qf7+frV69WqNq9UqmpycxK7rYtu2ied5VhAEdj6ftwuFglssFr1SqeTncrkgn88HuVwuCMMwCsMw8jwvtCwrJISExpiQcx6maRq0Wi2/Uqn4X375pTcyMuIODg46586ds9977z373LlzZHx8HJ8+fRoXCgVEDh486D755JN2uVx2xsfH3eHhYf+JJ57wa7VaVC6XIyFERAiJACBijEWMscgYE+zcuTPYs2ePZ9u2Y9u25TgOdl0XeZ4HnufpKIpUHMfqtddeEwMDA2LZsmX85MmTYnx8XGit5djYmHznnXcUNsagKIqQbdvYsixSKBRIGIZWGIZ2oVBwCoWCm8vlvCiK/GBWGIbBrDAIgtBxnJAQEgJAqJQKpZQB59xPksRvNptuvV53JiYmnMuXL9vDw8PW+Pg4GRoaIrVaDc+dOxeVSiWE169fD3PnzkVdXV2oVCqhfD6P4zgm+Xye5PN5K45jO5fLObNcjLFHCPEAwEMIeUopXwjhc869LMu8VqvlzszMOI1Gw6nX6061WrUbjYY1PT1Nrl69SkZGRvDZs2fxBx98gF599VX0/vvvg3XvvffCyMgILFiwADzPQ/l8HsVBgKMowgBAQGsiGLNZltmcMZtS6lBKXZplLmXMUlIiTDC2bQdmScdx7DiOSZqmmDGG0zTFjDEkhEBSSlQqlaC3txd6e3vhtttuA7xo/U3w1W+uN/kFeQgLIfixBcR3QAFHQDQSWmHGKU7ThCRJy8rS1Mqy1KKUWlma2hmlVpZRizFGKKWEMYYZpVgIgYQQIIQwWmswsxhjptFomMnJSTMxMWFGR0cN/un3vmX65gLc3NtrlnTnTGQBBJYCDzT4WANIhjRniGUJZlmGGU0Jp5QwmhEhOBaMYc4Z5oxhKTkSgiMuBCiljBDCKKU0xlgbY7SUUgshtBBC53I5PTg4aPC2mwEe2txjruuYhqXzjJmf12ZOwE3B48ZDythGGC0YSEpB8AxxRpHgDEkhkOQcCcmRFAIJKUBKZaSURv8JIUTZtq3iOFBxHKv29nbl+77u7OzU9XrdvPTSSxofe+4ec20nwI2LPFOEFnQEyrR5yoRYGFdnAJKB4RQES0EyCkowkIKDksJIJY1S0mgltdZSKyW11koBAomQkRiDJDaRYZyTxWJRBkGg2tvblW3buqurS1+6dMngB5ZWIPnlHLN9QwPuukmba4t1mAMzUCDceIoZWzEDghkpqJGcghLCKMGNUsJoKYxWSisttVZaaa2UBiOVlkoDSESIAAAZBZG0bVs5gaOKxaJatmyZWrBggR4YGND4ujv/F368+HO4zxuBlfAFdMsyBGwSSFIFyJogswaIrAkqS0FxaiSnoJUwWnKjlDBKCaOU0lJJrZTUUkqt1Syp/h8QkEEcSMdxlOu6KteeU8YY3dHRoc+cOWPw/i9+jrak/42+VZiG7mQUdcsy5NIKqOkJBHQadNYEmTaBpy0ksxRpRkEwiiQXoIQwUgijpDBKcCOl1FJyLaVUUnOllFCUUi200MY1iraoHjo/ZJIk0fPnz9eHDx/W+HH/12gd/gA5w+/iztZFBONDmE2N4GxyDNPaBGb1Ck4bVcyTJhI0QYJlSHEKklOkBAfJOXDOQChhhOBGcGY4Zyaj1LSyluFZpgFAN5tNM1GdMIwxff78efPuu++aU6dOgfVt979QbvBXeKU8iMbGz2OYvIhVdQyLX43jrDpJ0ukqyWamMU9nMM+qmNMUS8aQ5BQJqZAEZLAhIAgBJhhwLkxKU6BZZrI0MzNJYrjgZmZmxkxVpsyJ/zwBr7zyCnz66adw3333GXz29ZfwzewjhC++jxuffkySkQskHf2cVL8Ytmh9ktDpCskadUJbM0RkCRY0xZJnWAqOpOBIco6E5CAEA8E4MMaAMgpZlkCz2YR6ow6N6QZUK1UYGx2Der1uyq2y4ZybO+64A/BN079GldO/wJfOvEPY+CCuj1wg5dE/WDMTo2RmatLKGjXCZupEZgmWNMWKUywZw5JzrKRASnKkhEBCCCQlBy4yxBmFJElQo9lA1WoVVWtlNDE5AZ999hkc/tlh9MjfPIKGhobQ7t27AV/+xXEMnw3i4MolTEcvEqt2FaNqGbNKhdBalfCZBmFZiwhKsRQcGyGRURIZJUEribRWoLQGrRVorUAqDZxzxIWAjGbQSmZQlmZQmaqgNE2h2WxCpVKBsbExGB8fB3wDrqP6l5/hrDqC82wa6Zk6pq0Gps0ZTFtNLFmGNOfIaIlAKQBjAAEYBAaQAYMAGYSMQQjMHwFoAwBGSA5SStAKIOMcwaxas4bK5TKCP7nzzjuR1YMFKhhAJZCo2qKYMIkMk0hQgUBrwNoAwdhYCBvHsnSVSG0RrW3LKI0MQoCUsSxlWZayLEtb2NKEEI3nYYPAzJJGKWVaSQsajQZUKhX4zUe/QfPa5qGTJ08CXpJJdG9vAW4qRtDrW9DmAoQA4CNsbGwZxyLGd2zl25byHVsFriN9x5G+6wrf9YTneSJwPRF4vgh8XwS+LwPPU0HgKdfxtesF2nd843u+ieLItOfazZL5S8ymTZsMzMLJvwHA+wA9dd8sJLF2pWdsJ9DY97Tju8oLA+n5vgziiHthyP0wYn4UMtcPeRCGLA5DFoUxi4KQ5+KYx1Ek4lxO5OKcbCsU5JxiUXV1zVVd87r00oVLdU9PjwmCAP7o2LFjhry3d2N4+O57rHXXbrceXFN12r7ZdNY8IJwNZeVeyoxzRex2ptCAXdu5x2ruskn6nIWetmwQjqvBcRXxfGEHAQtzuSzOFdK2A6WkY25H0tXdnSy8ZnFy3fLl6e8G/yfp+0pftmHDBlq+WmYHDhzg99xzj5yamlLk0Z9sCcJ3P7YW5bZbz94urTm/Z/aND0rnzjo4f5va9rhy7Wnjkgb+J9zAe3HzuQFI93haOp4CJxA4iJgd5TK/WMj2zfnXpK2jM5nX29vqXXRta8Wfr2itX7eudfHzS+mWLVvSx7/7OH3hn19gfX19or+/X65evVpZA3/do89vvVHNt1dKtuoTma4SYskKwntO+WxOo0Bj08hcXHeQk1nIaWLldxk6l0tFhUW0QTYQ5bou87u6szn5Qlrq6Uk7FvRmi66/Plu+chW7Zc0tfNfePeL2zbfLPd/fo3bs2KFaqKURQnrFihXGemP9Tfr03YPq9xNfqN1fvUGOfh+LNZditvgvYtZZLdO8PZ15uGwTr0mM30Ki0TKMSoEYt4hQiBBL2a7L/TkhzRXb0tKSpen8xQuzJStW0r6vraUbH3iQbd26lX9y7hOx43s7JG1QFcexPn78uFm7dq0h8Vs/cb+9Zht56FSAH97yPH7hoX3kuvJu646nI3L3EzEZsfJ4nNl4yg3RlBPCd93I1N1QGz9SVhALLy6yuNROCws6s+6enuSalSuT6//shuTmvjXJ3Z/8Lnnq0UfS3c/tyfYO7KXLFy9nzWaT7927V7744oty06ZNmtzK1zul+/4R/3uvwVu3tuOd93vkmseeJxv4D8iG7+wn255rw2MU4yt2iCZIgL7j5syUH2vsx8rLFbmfL/GX2jtp+7Xzsnm916SLb1ydrl79leT2D7+e3L/l3nTgqX/Ifvyjn2Zv/OwN+tsLv+Wff/q5LJfLIgxDjTHWZN8f9ts3tp5HT/3gGXz6/g789GNz8DWPReSvdkTk1OUfki279uPhp3bii8jDV6wAHvYiMxHntRXmlBvlZVTsYP/S3sU6li3IehYuypavXZv+5dfeSU5//RvZ3//do+nCMMiOHv0PeuKXJ9iVkSvirv67xOGfH5aPP/i4unr1qv4/bGwpHb1ZNmYAAAAASUVORK5CYII=";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sunglasses smiley
|
* Sunglasses smiley
|
||||||
* 32x32
|
* 32x32
|
|
@ -36,7 +36,8 @@ const banner = `/**
|
||||||
module.exports = {
|
module.exports = {
|
||||||
output: {
|
output: {
|
||||||
publicPath: "",
|
publicPath: "",
|
||||||
globalObject: "this"
|
globalObject: "this",
|
||||||
|
assetModuleFilename: "assets/[hash][ext][query]"
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
|
@ -122,7 +123,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /prime.worker.min.js$/,
|
test: /prime.worker.min.js$/,
|
||||||
use: "raw-loader"
|
type: "asset/source"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /bootstrap-material-design/,
|
test: /bootstrap-material-design/,
|
||||||
|
@ -165,53 +166,33 @@ module.exports = {
|
||||||
"sass-loader",
|
"sass-loader",
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* The limit for these files has been increased to 60,000 (60KB)
|
|
||||||
* to ensure the material icons font is inlined.
|
|
||||||
*
|
|
||||||
* See: https://github.com/gchq/CyberChef/issues/612
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
test: /\.(ico|eot|ttf|woff|woff2)$/,
|
test: /\.(ico|eot|ttf|woff|woff2)$/,
|
||||||
loader: "url-loader",
|
type: "asset/resource",
|
||||||
options: {
|
|
||||||
limit: 60000,
|
|
||||||
name: "[hash].[ext]",
|
|
||||||
outputPath: "assets"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.svg$/,
|
||||||
loader: "svg-url-loader",
|
type: "asset/inline",
|
||||||
options: {
|
|
||||||
encoding: "base64"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{ // Store font .fnt and .png files in a separate fonts folder
|
{ // Store font .fnt and .png files in a separate fonts folder
|
||||||
test: /(\.fnt$|bmfonts\/.+\.png$)/,
|
test: /(\.fnt$|bmfonts\/.+\.png$)/,
|
||||||
loader: "file-loader",
|
type: "asset/resource",
|
||||||
options: {
|
generator: {
|
||||||
name: "[name].[ext]",
|
filename: "assets/fonts/[name][ext]"
|
||||||
outputPath: "assets/fonts"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ // First party images are saved as files to be cached
|
{ // First party images are saved as files to be cached
|
||||||
test: /\.(png|jpg|gif)$/,
|
test: /\.(png|jpg|gif)$/,
|
||||||
exclude: /(node_modules|bmfonts)/,
|
exclude: /(node_modules|bmfonts)/,
|
||||||
loader: "file-loader",
|
type: "asset/resource",
|
||||||
options: {
|
generator: {
|
||||||
name: "images/[name].[ext]"
|
filename: "images/[name][ext]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ // Third party images are inlined
|
{ // Third party images are inlined
|
||||||
test: /\.(png|jpg|gif)$/,
|
test: /\.(png|jpg|gif)$/,
|
||||||
exclude: /web\/static/,
|
exclude: /web\/static/,
|
||||||
loader: "url-loader",
|
type: "asset/inline",
|
||||||
options: {
|
|
||||||
limit: 10000,
|
|
||||||
name: "[hash].[ext]",
|
|
||||||
outputPath: "assets"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -219,14 +200,15 @@ module.exports = {
|
||||||
children: false,
|
children: false,
|
||||||
chunks: false,
|
chunks: false,
|
||||||
modules: false,
|
modules: false,
|
||||||
entrypoints: false,
|
entrypoints: false
|
||||||
warningsFilter: [
|
|
||||||
/source-map/,
|
|
||||||
/dependency is an expression/,
|
|
||||||
/export 'default'/,
|
|
||||||
/Can't resolve 'sodium'/
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
ignoreWarnings: [
|
||||||
|
/source-map/,
|
||||||
|
/source map/,
|
||||||
|
/dependency is an expression/,
|
||||||
|
/export 'default'/,
|
||||||
|
/Can't resolve 'sodium'/
|
||||||
|
],
|
||||||
performance: {
|
performance: {
|
||||||
hints: false
|
hints: false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue