mirror of
https://github.com/gchq/CyberChef.git
synced 2024-11-02 14:11:02 +01:00
Merge branch 'master' into features/rsa
This commit is contained in:
commit
73864e0809
@ -1,2 +1 @@
|
||||
src/core/vendor/**
|
||||
src/web/static/clippy_assets/**
|
@ -47,6 +47,7 @@
|
||||
"block-spacing": "error",
|
||||
"array-bracket-spacing": "error",
|
||||
"comma-spacing": "error",
|
||||
"spaced-comment": ["error", "always", { "exceptions": ["/"] } ],
|
||||
"comma-style": "error",
|
||||
"computed-property-spacing": "error",
|
||||
"no-trailing-spaces": "warn",
|
||||
|
4
.github/ISSUE_TEMPLATE/bug-report.md
vendored
4
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -26,8 +26,8 @@ If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (if relevant, please complete the following information):**
|
||||
- OS: [e.g. Windows]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
- Browser: [e.g. chrome 72, firefox 60]
|
||||
- CyberChef version: [e.g. 9.7.14]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: 'Bug report: <Insert title here>'
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Prefix the title above with 'Bug report:' -->
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior or a link to the recipe / input used to cause the bug:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (if relevant, please complete the following information):**
|
||||
- OS: [e.g. Windows]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,7 +4,6 @@ travis.log
|
||||
build
|
||||
.vscode
|
||||
.*.swp
|
||||
.DS_Store
|
||||
src/core/config/modules/*
|
||||
src/core/config/OperationConfig.json
|
||||
src/core/operations/index.mjs
|
||||
|
17
.travis.yml
17
.travis.yml
@ -1,7 +1,8 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- lts/*
|
||||
- lts/dubnium
|
||||
cache: npm
|
||||
os: linux
|
||||
addons:
|
||||
chrome: stable
|
||||
install: npm install
|
||||
@ -10,7 +11,7 @@ before_script:
|
||||
- export NODE_OPTIONS=--max_old_space_size=2048
|
||||
script:
|
||||
- grunt lint
|
||||
- grunt test
|
||||
- npm test
|
||||
- grunt testnodeconsumer
|
||||
- grunt prod --msg="$COMPILE_MSG"
|
||||
- xvfb-run --server-args="-screen 0 1200x800x24" grunt testui
|
||||
@ -19,16 +20,16 @@ before_deploy:
|
||||
- grunt copy:ghPages
|
||||
deploy:
|
||||
- provider: pages
|
||||
skip_cleanup: true
|
||||
github_token: $GITHUB_TOKEN
|
||||
edge: true
|
||||
token: $GITHUB_TOKEN
|
||||
local_dir: build/prod/
|
||||
target_branch: gh-pages
|
||||
on:
|
||||
repo: gchq/CyberChef
|
||||
branch: master
|
||||
- provider: releases
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
edge: true
|
||||
token:
|
||||
secure: "HV1WSKv4l/0Y2bKKs1iBJocBcmLj08PCRUeEM/jTwA4jqJ8EiLHWiXtER/D5sEg2iibRVKd2OQjfrmS6bo4AiwdeVgAKmv0FtS2Jw+391N8Nd5AkEANHa5Om/IpHLTL2YRAjpJTsDpY72bMUTJIwjQA3TFJkgrpOw6KYfohOcgbxLpZ4XuNJRU3VL4Hsxdv5V9aOVmfFOmMOVPQlakXy7NgtW5POp1f2WJwgcZxylkR1CjwaqMyXmSoVl46pyH3tr5+dptsQoKSGdi6sIHGA60oDotFPcm+0ifa47wZw+vapuuDi4tdNxhrHGaDMG8xiE0WFDHwQUDlk2/+W7j9SEX0H3Em7us371JXRp56EDwEcDa34VpVkC6i8HGcHK55hnxVbMZXGf3qhOFD8wY7qMbjMRvIpucrMHBi86OfkDfv0vDj2LyvIl5APj/AX50BrE0tfH1MZbH26Jkx4NdlkcxQ14GumarmUqfmVvbX/fsoA6oUuAAE9ZgRRi3KHO4wci6KUcRfdm+XOeUkaBFsL86G3EEYIvrtBTuaypdz+Cx7nd1iPZyWMx5Y1gXnVzha4nBdV4+7l9JIsFggD8QVpw2uHXQiS1KXFjOeqA3DBD8tjMB7q26Fl2fD3jkOo4BTbQ2NrRIZUu/iL+fOmMPsyMt2qulB0yaSBCfkbEq8xrUA="
|
||||
file_glob: true
|
||||
file:
|
||||
@ -38,9 +39,9 @@ deploy:
|
||||
repo: gchq/CyberChef
|
||||
tags: true
|
||||
- provider: npm
|
||||
skip_cleanup: true
|
||||
edge: true
|
||||
email: "n1474335@gmail.com"
|
||||
api_key:
|
||||
api_token:
|
||||
secure: "UnDQL3Kh+GK2toL0TK3FObO0ujVssU3Eg4BBuYdjwLB81GhiGE5/DTh7THdZPOpbLo6wQeOwfZDuMeKC1OU+0Uf4NsdYFu1aq6xMO20qBQ4qUfgsyiK4Qgywj9gk0p1+OFZdGAZ/j1CNRAaF71XQIY6iV84c+SO4WoizXYrNT0Jh4sr2DA4/97G2xmJtPi0qOzYrJ09R56ZUozmqeik5G0pMRIuJRbpjS/7bZXV+N7WV0ombZc9RkUaetbabEVOLQ+Xx5YAIVq+VuEeMe9VBSnxY/FfCLmy1wJsjGzpLCyBI9nbrG4nw8Wgc2m8NfK9rcpIvBTGner9r2j60NVDkZ8kLZPrqXhq6AZMwa+oz6K5UQCqRo2RRQzSGwXxg67HY5Tcq+oNmjd+DqpPg4LZ3eGlluyP5XfG+hpSr9Ya4d8q8SrUWLxkoLHI6ZKMtoKFbTCSSQPiluW5hsZxjz3yDkkjsJw64M/EM8UyJrgaXqDklQu+7rBGKLfsK6os7RDiqjBWpQ7gwpo8HvY0O8yqEAabPz+QGkanpjcCOZCXFbSkzWxYy37RMAPu88iINVZVlZE4l+WJenCpZY95ueyy0mG9cyMSzVRPyX6A+/n4H6VMFPFjpGDLTD588ACEjY1lmHfS/eXwXJcgqPPD2gW0XdRdUheU/ssqlfCfGWQMTDXs="
|
||||
on:
|
||||
tags: true
|
||||
|
73
CHANGELOG.md
73
CHANGELOG.md
@ -2,6 +2,45 @@
|
||||
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
||||
|
||||
|
||||
### [9.20.0] - 2020-03-27
|
||||
- 'Parse ObjectID Timestamp' operation added [@dmfj] | [#987]
|
||||
|
||||
### [9.19.0] - 2020-03-24
|
||||
- Improvements to the 'Magic' operation, allowing it to recognise more data formats and provide more accurate results [@n1073645] [@n1474335] | [#966] [b765534b](https://github.com/gchq/CyberChef/commit/b765534b8b2a0454a5132a0a52d1d8844bcbdaaa)
|
||||
|
||||
### [9.18.0] - 2020-03-13
|
||||
- 'Convert to NATO alphabet' operation added [@MarvinJWendt] | [#674]
|
||||
|
||||
### [9.17.0] - 2020-03-13
|
||||
- 'Generate Image' operation added [@pointhi] | [#683]
|
||||
|
||||
### [9.16.0] - 2020-03-06
|
||||
- 'Colossus' operation added [@VirtualColossus] | [#917]
|
||||
|
||||
### [9.15.0] - 2020-03-05
|
||||
- 'CipherSaber2 Encrypt' and 'CipherSaber2 Decrypt' operations added [@n1073645] | [#952]
|
||||
|
||||
### [9.14.0] - 2020-03-05
|
||||
- 'Luhn Checksum' operation added [@n1073645] | [#965]
|
||||
|
||||
### [9.13.0] - 2020-02-13
|
||||
- 'Rail Fence Cipher Encode' and 'Rail Fence Cipher Decode' operations added [@Flavsditz] | [#948]
|
||||
|
||||
### [9.12.0] - 2019-12-20
|
||||
- 'Normalise Unicode' operation added [@matthieuxyz] | [#912]
|
||||
|
||||
### [9.11.0] - 2019-11-06
|
||||
- Implemented CFB, OFB, and CTR modes for Blowfish operations [@cbeuw] | [#653]
|
||||
|
||||
### [9.10.0] - 2019-11-06
|
||||
- 'Lorenz' operation added [@VirtualColossus] | [#528]
|
||||
|
||||
### [9.9.0] - 2019-11-01
|
||||
- Added support for 109 more character encodings [@n1474335]
|
||||
|
||||
### [9.8.0] - 2019-10-31
|
||||
- 'Avro to JSON' operation added [@jarrodconnolly] | [#865]
|
||||
|
||||
### [9.7.0] - 2019-09-13
|
||||
- 'Optical Character Recognition' operation added [@MShwed] [@n1474335] | [#632]
|
||||
|
||||
@ -185,6 +224,19 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
|
||||
|
||||
[9.20.0]: https://github.com/gchq/CyberChef/releases/tag/v9.20.0
|
||||
[9.19.0]: https://github.com/gchq/CyberChef/releases/tag/v9.19.0
|
||||
[9.18.0]: https://github.com/gchq/CyberChef/releases/tag/v9.18.0
|
||||
[9.17.0]: https://github.com/gchq/CyberChef/releases/tag/v9.17.0
|
||||
[9.16.0]: https://github.com/gchq/CyberChef/releases/tag/v9.16.0
|
||||
[9.15.0]: https://github.com/gchq/CyberChef/releases/tag/v9.15.0
|
||||
[9.14.0]: https://github.com/gchq/CyberChef/releases/tag/v9.14.0
|
||||
[9.13.0]: https://github.com/gchq/CyberChef/releases/tag/v9.13.0
|
||||
[9.12.0]: https://github.com/gchq/CyberChef/releases/tag/v9.12.0
|
||||
[9.11.0]: https://github.com/gchq/CyberChef/releases/tag/v9.11.0
|
||||
[9.10.0]: https://github.com/gchq/CyberChef/releases/tag/v9.10.0
|
||||
[9.9.0]: https://github.com/gchq/CyberChef/releases/tag/v9.9.0
|
||||
[9.8.0]: https://github.com/gchq/CyberChef/releases/tag/v9.8.0
|
||||
[9.7.0]: https://github.com/gchq/CyberChef/releases/tag/v9.7.0
|
||||
[9.6.0]: https://github.com/gchq/CyberChef/releases/tag/v9.6.0
|
||||
[9.5.0]: https://github.com/gchq/CyberChef/releases/tag/v9.5.0
|
||||
@ -241,6 +293,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[@n1474335]: https://github.com/n1474335
|
||||
[@d98762625]: https://github.com/d98762625
|
||||
[@j433866]: https://github.com/j433866
|
||||
[@n1073645]: https://github.com/n1073645
|
||||
[@GCHQ77703]: https://github.com/GCHQ77703
|
||||
[@h345983745]: https://github.com/h345983745
|
||||
[@s2224834]: https://github.com/s2224834
|
||||
@ -262,6 +315,14 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[@Ge0rg3]: https://github.com/Ge0rg3
|
||||
[@MShwed]: https://github.com/MShwed
|
||||
[@kassi]: https://github.com/kassi
|
||||
[@jarrodconnolly]: https://github.com/jarrodconnolly
|
||||
[@VirtualColossus]: https://github.com/VirtualColossus
|
||||
[@cbeuw]: https://github.com/cbeuw
|
||||
[@matthieuxyz]: https://github.com/matthieuxyz
|
||||
[@Flavsditz]: https://github.com/Flavsditz
|
||||
[@pointhi]: https://github.com/pointhi
|
||||
[@MarvinJWendt]: https://github.com/MarvinJWendt
|
||||
[@dmfj]: https://github.com/dmfj
|
||||
|
||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||
@ -308,6 +369,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[#515]: https://github.com/gchq/CyberChef/pull/515
|
||||
[#516]: https://github.com/gchq/CyberChef/pull/516
|
||||
[#525]: https://github.com/gchq/CyberChef/pull/525
|
||||
[#528]: https://github.com/gchq/CyberChef/pull/528
|
||||
[#530]: https://github.com/gchq/CyberChef/pull/530
|
||||
[#531]: https://github.com/gchq/CyberChef/pull/531
|
||||
[#533]: https://github.com/gchq/CyberChef/pull/533
|
||||
@ -322,3 +384,14 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[#625]: https://github.com/gchq/CyberChef/pull/625
|
||||
[#627]: https://github.com/gchq/CyberChef/pull/627
|
||||
[#632]: https://github.com/gchq/CyberChef/pull/632
|
||||
[#653]: https://github.com/gchq/CyberChef/pull/653
|
||||
[#674]: https://github.com/gchq/CyberChef/pull/674
|
||||
[#683]: https://github.com/gchq/CyberChef/pull/683
|
||||
[#865]: https://github.com/gchq/CyberChef/pull/865
|
||||
[#912]: https://github.com/gchq/CyberChef/pull/912
|
||||
[#917]: https://github.com/gchq/CyberChef/pull/917
|
||||
[#948]: https://github.com/gchq/CyberChef/pull/948
|
||||
[#952]: https://github.com/gchq/CyberChef/pull/952
|
||||
[#965]: https://github.com/gchq/CyberChef/pull/965
|
||||
[#966]: https://github.com/gchq/CyberChef/pull/966
|
||||
[#987]: https://github.com/gchq/CyberChef/pull/987
|
||||
|
198
Gruntfile.js
198
Gruntfile.js
@ -14,7 +14,6 @@ const path = require("path");
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.file.defaultEncoding = "utf8";
|
||||
grunt.file.preserveBOM = false;
|
||||
@ -27,7 +26,7 @@ module.exports = function (grunt) {
|
||||
grunt.registerTask("prod",
|
||||
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
||||
[
|
||||
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "webpack:web",
|
||||
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "findModules", "webpack:web",
|
||||
"copy:standalone", "zip:standalone", "clean:standalone", "chmod"
|
||||
]);
|
||||
|
||||
@ -37,11 +36,10 @@ module.exports = function (grunt) {
|
||||
"clean:node", "clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
|
||||
]);
|
||||
|
||||
grunt.registerTask("test",
|
||||
"A task which runs all the operation tests in the tests directory.",
|
||||
grunt.registerTask("configTests",
|
||||
"A task which configures config files in preparation for tests to be run. Use `npm test` to run tests.",
|
||||
[
|
||||
"clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex",
|
||||
"exec:nodeTests", "exec:opTests"
|
||||
"clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
|
||||
]);
|
||||
|
||||
grunt.registerTask("testui",
|
||||
@ -56,9 +54,21 @@ module.exports = function (grunt) {
|
||||
"Lints the code base",
|
||||
["eslint", "exec:repoSize"]);
|
||||
|
||||
grunt.registerTask("tests", "test");
|
||||
grunt.registerTask("lint", "eslint");
|
||||
|
||||
grunt.registerTask("findModules",
|
||||
"Finds all generated modules and updates the entry point list for Webpack",
|
||||
function(arg1, arg2) {
|
||||
const moduleEntryPoints = listEntryModules();
|
||||
|
||||
grunt.log.writeln(`Found ${Object.keys(moduleEntryPoints).length} modules.`);
|
||||
|
||||
grunt.config.set("webpack.web.entry",
|
||||
Object.assign({
|
||||
main: "./src/web/index.js"
|
||||
}, moduleEntryPoints));
|
||||
});
|
||||
|
||||
|
||||
// Load tasks provided by each plugin
|
||||
grunt.loadNpmTasks("grunt-eslint");
|
||||
@ -84,58 +94,12 @@ module.exports = function (grunt) {
|
||||
PKG_VERSION: JSON.stringify(pkg.version),
|
||||
},
|
||||
moduleEntryPoints = listEntryModules(),
|
||||
nodeConsumerTestPath = "~/tmp-cyberchef";
|
||||
|
||||
|
||||
nodeConsumerTestPath = "~/tmp-cyberchef",
|
||||
/**
|
||||
* Generates an entry list for all the modules.
|
||||
* Configuration for Webpack production build. Defined as a function so that it
|
||||
* can be recalculated when new modules are generated.
|
||||
*/
|
||||
function listEntryModules() {
|
||||
const entryModules = {};
|
||||
|
||||
glob.sync("./src/core/config/modules/*.mjs").forEach(file => {
|
||||
const basename = path.basename(file);
|
||||
if (basename !== "Default.mjs" && basename !== "OpModules.mjs")
|
||||
entryModules["modules/" + basename.split(".mjs")[0]] = path.resolve(file);
|
||||
});
|
||||
|
||||
return entryModules;
|
||||
}
|
||||
|
||||
grunt.initConfig({
|
||||
clean: {
|
||||
dev: ["build/dev/*"],
|
||||
prod: ["build/prod/*"],
|
||||
node: ["build/node/*"],
|
||||
config: ["src/core/config/OperationConfig.json", "src/core/config/modules/*", "src/code/operations/index.mjs"],
|
||||
nodeConfig: ["src/node/index.mjs", "src/node/config/OperationConfig.json"],
|
||||
standalone: ["build/prod/CyberChef*.html"]
|
||||
},
|
||||
eslint: {
|
||||
options: {
|
||||
configFile: "./.eslintrc.json"
|
||||
},
|
||||
configs: ["*.{js,mjs}"],
|
||||
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
|
||||
web: ["src/web/**/*.{js,mjs}", "!src/web/static/**/*"],
|
||||
node: ["src/node/**/*.{js,mjs}"],
|
||||
tests: ["tests/**/*.{js,mjs}"],
|
||||
},
|
||||
accessibility: {
|
||||
options: {
|
||||
accessibilityLevel: "WCAG2A",
|
||||
verbose: false,
|
||||
ignore: [
|
||||
"WCAG2A.Principle1.Guideline1_3.1_3_1.H42.2"
|
||||
]
|
||||
},
|
||||
test: {
|
||||
src: ["build/**/*.html"]
|
||||
}
|
||||
},
|
||||
webpack: {
|
||||
options: webpackConfig,
|
||||
web: () => {
|
||||
webpackProdConf = () => {
|
||||
return {
|
||||
mode: "production",
|
||||
target: "web",
|
||||
@ -176,12 +140,84 @@ module.exports = function (grunt) {
|
||||
}),
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generates an entry list for all the modules.
|
||||
*/
|
||||
function listEntryModules() {
|
||||
const entryModules = {};
|
||||
|
||||
glob.sync("./src/core/config/modules/*.mjs").forEach(file => {
|
||||
const basename = path.basename(file);
|
||||
if (basename !== "Default.mjs" && basename !== "OpModules.mjs")
|
||||
entryModules["modules/" + basename.split(".mjs")[0]] = path.resolve(file);
|
||||
});
|
||||
|
||||
return entryModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the correct delimiter to use to chain shell commands together
|
||||
* based on the current OS.
|
||||
*
|
||||
* @param {string[]} cmds
|
||||
* @returns {string}
|
||||
*/
|
||||
function chainCommands(cmds) {
|
||||
const win = process.platform === "win32";
|
||||
if (!win) {
|
||||
return cmds.join(";");
|
||||
}
|
||||
return cmds
|
||||
// && means that subsequent commands will not be executed if the
|
||||
// previous one fails. & would coninue on a fail
|
||||
.join("&&")
|
||||
// Windows does not support \n properly
|
||||
.replace("\n", "\\n");
|
||||
}
|
||||
|
||||
grunt.initConfig({
|
||||
clean: {
|
||||
dev: ["build/dev/*"],
|
||||
prod: ["build/prod/*"],
|
||||
node: ["build/node/*"],
|
||||
config: ["src/core/config/OperationConfig.json", "src/core/config/modules/*", "src/code/operations/index.mjs"],
|
||||
nodeConfig: ["src/node/index.mjs", "src/node/config/OperationConfig.json"],
|
||||
standalone: ["build/prod/CyberChef*.html"]
|
||||
},
|
||||
eslint: {
|
||||
options: {
|
||||
configFile: "./.eslintrc.json"
|
||||
},
|
||||
configs: ["*.{js,mjs}"],
|
||||
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
|
||||
web: ["src/web/**/*.{js,mjs}", "!src/web/static/**/*"],
|
||||
node: ["src/node/**/*.{js,mjs}"],
|
||||
tests: ["tests/**/*.{js,mjs}"],
|
||||
},
|
||||
accessibility: {
|
||||
options: {
|
||||
accessibilityLevel: "WCAG2A",
|
||||
verbose: false,
|
||||
ignore: [
|
||||
"WCAG2A.Principle1.Guideline1_3.1_3_1.H42.2"
|
||||
]
|
||||
},
|
||||
test: {
|
||||
src: ["build/**/*.html"]
|
||||
}
|
||||
},
|
||||
webpack: {
|
||||
options: webpackConfig,
|
||||
web: webpackProdConf(),
|
||||
},
|
||||
"webpack-dev-server": {
|
||||
options: {
|
||||
webpack: webpackConfig,
|
||||
host: "0.0.0.0",
|
||||
port: grunt.option("port") || 8080,
|
||||
disableHostCheck: true,
|
||||
overlay: true,
|
||||
inline: false,
|
||||
@ -238,7 +274,7 @@ module.exports = function (grunt) {
|
||||
connect: {
|
||||
prod: {
|
||||
options: {
|
||||
port: 8000,
|
||||
port: grunt.option("port") || 8000,
|
||||
base: "build/prod/"
|
||||
}
|
||||
}
|
||||
@ -316,78 +352,76 @@ module.exports = function (grunt) {
|
||||
},
|
||||
exec: {
|
||||
repoSize: {
|
||||
command: [
|
||||
command: chainCommands([
|
||||
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
|
||||
"du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
|
||||
].join(";"),
|
||||
]),
|
||||
stderr: false
|
||||
},
|
||||
cleanGit: {
|
||||
command: "git gc --prune=now --aggressive"
|
||||
},
|
||||
sitemap: {
|
||||
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml"
|
||||
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml",
|
||||
sync: true
|
||||
},
|
||||
generateConfig: {
|
||||
command: [
|
||||
command: chainCommands([
|
||||
"echo '\n--- Regenerating config files. ---'",
|
||||
"echo [] > src/core/config/OperationConfig.json",
|
||||
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
|
||||
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
|
||||
"echo '--- Config scripts finished. ---\n'"
|
||||
].join(";")
|
||||
]),
|
||||
sync: true
|
||||
},
|
||||
generateNodeIndex: {
|
||||
command: [
|
||||
command: chainCommands([
|
||||
"echo '\n--- Regenerating node index ---'",
|
||||
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
|
||||
"echo '--- Node index generated. ---\n'"
|
||||
].join(";"),
|
||||
},
|
||||
opTests: {
|
||||
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
|
||||
]),
|
||||
sync: true
|
||||
},
|
||||
browserTests: {
|
||||
command: "./node_modules/.bin/nightwatch --env prod"
|
||||
},
|
||||
nodeTests: {
|
||||
command: "node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs"
|
||||
},
|
||||
setupNodeConsumers: {
|
||||
command: [
|
||||
"echo '\n--- Testing node conumers ---'",
|
||||
command: chainCommands([
|
||||
"echo '\n--- Testing node consumers ---'",
|
||||
"npm link",
|
||||
`mkdir ${nodeConsumerTestPath}`,
|
||||
`cp tests/node/consumers/* ${nodeConsumerTestPath}`,
|
||||
`cd ${nodeConsumerTestPath}`,
|
||||
"npm link cyberchef"
|
||||
].join(";"),
|
||||
]),
|
||||
sync: true
|
||||
},
|
||||
teardownNodeConsumers: {
|
||||
command: [
|
||||
command: chainCommands([
|
||||
`rm -rf ${nodeConsumerTestPath}`,
|
||||
"echo '\n--- Node consumer tests complete ---'"
|
||||
].join(";"),
|
||||
]),
|
||||
},
|
||||
testCJSNodeConsumer: {
|
||||
command: [
|
||||
command: chainCommands([
|
||||
`cd ${nodeConsumerTestPath}`,
|
||||
"node --no-warnings cjs-consumer.js",
|
||||
].join(";"),
|
||||
]),
|
||||
stdout: false,
|
||||
},
|
||||
testESMNodeConsumer: {
|
||||
command: [
|
||||
command: chainCommands([
|
||||
`cd ${nodeConsumerTestPath}`,
|
||||
"node --no-warnings --experimental-modules esm-consumer.mjs",
|
||||
].join(";"),
|
||||
]),
|
||||
stdout: false,
|
||||
},
|
||||
testESMDeepImportNodeConsumer: {
|
||||
command: [
|
||||
command: chainCommands([
|
||||
`cd ${nodeConsumerTestPath}`,
|
||||
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
|
||||
].join(";"),
|
||||
]),
|
||||
stdout: false,
|
||||
},
|
||||
},
|
||||
|
10
README.md
10
README.md
@ -69,7 +69,15 @@ You can use as many operations as you like in simple or complex ways. Some examp
|
||||
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field. Files up to around 2GB are supported (depending on your browser), however some operations may take a very long time to run over this much data.
|
||||
- CyberChef is entirely client-side
|
||||
- It should be noted that none of your recipe configuration or input (either text or files) is ever sent to the CyberChef web server - all processing is carried out within your browser, on your own computer.
|
||||
- Due to this feature, CyberChef can be compiled into a single HTML file. You can download this file and drop it into a virtual machine, share it with other people, or use it independently on your local machine.
|
||||
- Due to this feature, CyberChef can be downloaded and run locally. You can use the link in the top left corner of the app to download a full copy of CyberChef and drop it into a virtual machine, share it with other people, or host it in a closed network.
|
||||
|
||||
|
||||
## Deep linking
|
||||
|
||||
By manipulation of CyberChef's URL hash, you can change the initial settings with which the page opens.
|
||||
The format is `https://gchq.github.io/CyberChef/#recipe=Operation()&input=...`
|
||||
|
||||
Supported arguments are `recipe`, `input` (encoded in Base64), and `theme`.
|
||||
|
||||
|
||||
## Browser support
|
||||
|
7467
package-lock.json
generated
7467
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
113
package.json
113
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "9.7.2",
|
||||
"version": "9.20.3",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@ -36,26 +36,27 @@
|
||||
"node >= 10"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/plugin-transform-runtime": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"autoprefixer": "^9.6.1",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"@babel/core": "^7.8.7",
|
||||
"@babel/plugin-transform-runtime": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.7",
|
||||
"autoprefixer": "^9.7.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.0",
|
||||
"chromedriver": "^76.0.1",
|
||||
"colors": "^1.3.3",
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"css-loader": "^3.2.0",
|
||||
"eslint": "^6.2.2",
|
||||
"chromedriver": "^80.0.1",
|
||||
"cli-progress": "^3.6.0",
|
||||
"colors": "^1.4.0",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^3.4.2",
|
||||
"eslint": "^6.8.0",
|
||||
"exports-loader": "^0.7.0",
|
||||
"file-loader": "^4.2.0",
|
||||
"grunt": "^1.0.4",
|
||||
"file-loader": "^6.0.0",
|
||||
"grunt": "^1.1.0",
|
||||
"grunt-accessibility": "~6.0.0",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-concurrent": "^3.0.0",
|
||||
"grunt-contrib-clean": "~2.0.0",
|
||||
"grunt-contrib-connect": "^2.0.0",
|
||||
"grunt-contrib-connect": "^2.1.0",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"grunt-eslint": "^22.0.0",
|
||||
@ -64,55 +65,56 @@
|
||||
"grunt-zip": "^0.18.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"imports-loader": "^0.8.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"nightwatch": "^1.2.1",
|
||||
"node-sass": "^4.12.0",
|
||||
"postcss-css-variables": "^0.13.0",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"nightwatch": "^1.3.4",
|
||||
"node-sass": "^4.13.1",
|
||||
"postcss-css-variables": "^0.14.0",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"prompt": "^1.0.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"sitemap": "^4.1.1",
|
||||
"style-loader": "^1.0.0",
|
||||
"svg-url-loader": "^3.0.1",
|
||||
"url-loader": "^2.1.0",
|
||||
"webpack": "^4.39.3",
|
||||
"webpack-bundle-analyzer": "^3.4.1",
|
||||
"webpack-dev-server": "^3.8.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
"sitemap": "^6.1.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"svg-url-loader": "^5.0.0",
|
||||
"url-loader": "^4.0.0",
|
||||
"webpack": "^4.42.0",
|
||||
"webpack-bundle-analyzer": "^3.6.1",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"webpack-node-externals": "^1.7.2",
|
||||
"worker-loader": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.4.4",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@babel/polyfill": "^7.8.7",
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"arrive": "^2.4.1",
|
||||
"avsc": "^5.4.19",
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"blakejs": "^1.1.0",
|
||||
"bootstrap": "4.3.1",
|
||||
"bootstrap-colorpicker": "^3.1.2",
|
||||
"bootstrap": "4.4.1",
|
||||
"bootstrap-colorpicker": "^3.2.0",
|
||||
"bootstrap-material-design": "^4.1.2",
|
||||
"bson": "^4.0.2",
|
||||
"bson": "^4.0.3",
|
||||
"chi-squared": "^1.1.0",
|
||||
"clippyjs": "0.0.3",
|
||||
"core-js": "^3.2.1",
|
||||
"codepage": "^1.14.0",
|
||||
"core-js": "^3.6.4",
|
||||
"crypto-api": "^0.8.5",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"crypto-js": "^4.0.0",
|
||||
"ctph.js": "0.0.5",
|
||||
"d3": "^5.11.0",
|
||||
"d3": "^5.15.0",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"diff": "^4.0.1",
|
||||
"es6-promisify": "^6.0.2",
|
||||
"escodegen": "^1.12.0",
|
||||
"diff": "^4.0.2",
|
||||
"es6-promisify": "^6.1.0",
|
||||
"escodegen": "^1.14.1",
|
||||
"esm": "^3.2.25",
|
||||
"esmangle": "^1.0.1",
|
||||
"esprima": "^4.0.1",
|
||||
"exif-parser": "^0.1.12",
|
||||
"file-saver": "^2.0.2",
|
||||
"geodesy": "^1.1.3",
|
||||
"highlight.js": "^9.15.10",
|
||||
"jimp": "^0.6.4",
|
||||
"highlight.js": "^9.18.1",
|
||||
"jimp": "^0.9.5",
|
||||
"jquery": "3.4.1",
|
||||
"js-crc": "^0.2.0",
|
||||
"js-sha3": "^0.8.0",
|
||||
@ -121,43 +123,44 @@
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jsqr": "^1.2.0",
|
||||
"jsrsasign": "8.0.12",
|
||||
"kbpgp": "2.1.3",
|
||||
"kbpgp": "2.1.13",
|
||||
"libbzip2-wasm": "0.0.4",
|
||||
"libyara-wasm": "0.0.12",
|
||||
"libyara-wasm": "^1.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
"loglevel": "^1.6.3",
|
||||
"loglevel": "^1.6.7",
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"markdown-it": "^9.1.0",
|
||||
"markdown-it": "^10.0.0",
|
||||
"moment": "^2.24.0",
|
||||
"moment-timezone": "^0.5.26",
|
||||
"moment-timezone": "^0.5.28",
|
||||
"ngeohash": "^0.6.3",
|
||||
"node-forge": "^0.8.5",
|
||||
"node-forge": "^0.9.1",
|
||||
"node-md6": "^0.1.0",
|
||||
"nodom": "^2.2.0",
|
||||
"notepack.io": "^2.2.0",
|
||||
"nodom": "^2.4.0",
|
||||
"notepack.io": "^2.3.0",
|
||||
"nwmatcher": "^1.4.4",
|
||||
"otp": "^0.1.3",
|
||||
"popper.js": "^1.15.0",
|
||||
"popper.js": "^1.16.1",
|
||||
"qr-image": "^3.2.0",
|
||||
"scryptsy": "^2.1.0",
|
||||
"snackbarjs": "^1.1.0",
|
||||
"sortablejs": "^1.9.0",
|
||||
"sortablejs": "^1.10.2",
|
||||
"split.js": "^1.5.11",
|
||||
"ssdeep.js": "0.0.2",
|
||||
"tesseract.js": "^2.0.0-alpha.15",
|
||||
"ua-parser-js": "^0.7.20",
|
||||
"tesseract.js": "^2.0.2",
|
||||
"ua-parser-js": "^0.7.21",
|
||||
"unorm": "^1.6.0",
|
||||
"utf8": "^3.0.0",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"xmldom": "^0.1.27",
|
||||
"xmldom": "^0.3.0",
|
||||
"xpath": "0.0.27",
|
||||
"xregexp": "^4.2.4",
|
||||
"xregexp": "^4.3.0",
|
||||
"zlibjs": "^0.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "grunt dev",
|
||||
"build": "grunt prod",
|
||||
"repl": "node src/node/repl.js",
|
||||
"test": "grunt test",
|
||||
"test": "grunt configTests && node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs",
|
||||
"test-node-consumer": "grunt testnodeconsumer",
|
||||
"testui": "grunt testui",
|
||||
"testuidev": "npx nightwatch --env=dev",
|
||||
|
@ -39,7 +39,7 @@ class Chef {
|
||||
*/
|
||||
async bake(input, recipeConfig, options) {
|
||||
log.debug("Chef baking");
|
||||
const startTime = new Date().getTime(),
|
||||
const startTime = Date.now(),
|
||||
recipe = new Recipe(recipeConfig),
|
||||
containsFc = recipe.containsFlowControl(),
|
||||
notUTF8 = options && "treatAsUtf8" in options && !options.treatAsUtf8;
|
||||
@ -73,10 +73,10 @@ class Chef {
|
||||
// The threshold is specified in KiB.
|
||||
const threshold = (options.ioDisplayThreshold || 1024) * 1024;
|
||||
const returnType =
|
||||
this.dish.size > threshold ?
|
||||
Dish.ARRAY_BUFFER :
|
||||
this.dish.type === Dish.HTML ?
|
||||
Dish.HTML :
|
||||
this.dish.size > threshold ?
|
||||
Dish.ARRAY_BUFFER :
|
||||
Dish.STRING;
|
||||
|
||||
return {
|
||||
@ -84,7 +84,7 @@ class Chef {
|
||||
result: await this.dish.get(returnType, notUTF8),
|
||||
type: Dish.enumLookup(this.dish.type),
|
||||
progress: progress,
|
||||
duration: new Date().getTime() - startTime,
|
||||
duration: Date.now() - startTime,
|
||||
error: error
|
||||
};
|
||||
}
|
||||
@ -110,7 +110,7 @@ class Chef {
|
||||
silentBake(recipeConfig) {
|
||||
log.debug("Running silent bake");
|
||||
|
||||
const startTime = new Date().getTime(),
|
||||
const startTime = Date.now(),
|
||||
recipe = new Recipe(recipeConfig),
|
||||
dish = new Dish();
|
||||
|
||||
@ -119,7 +119,7 @@ class Chef {
|
||||
} catch (err) {
|
||||
// Suppress all errors
|
||||
}
|
||||
return new Date().getTime() - startTime;
|
||||
return Date.now() - startTime;
|
||||
}
|
||||
|
||||
|
||||
@ -146,7 +146,12 @@ class Chef {
|
||||
const func = direction === "forward" ? highlights[i].f : highlights[i].b;
|
||||
|
||||
if (typeof func == "function") {
|
||||
try {
|
||||
pos = func(pos, highlights[i].args);
|
||||
} catch (err) {
|
||||
// Throw away highlighting errors
|
||||
pos = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ class Dish {
|
||||
*
|
||||
* @param {number} type - The data type of value, see Dish enums.
|
||||
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
|
||||
* @returns {* | Promise} - (Broswer) A promise | (Node) value of dish in given type
|
||||
* @returns {* | Promise} - (Browser) A promise | (Node) value of dish in given type
|
||||
*/
|
||||
get(type, notUTF8=false) {
|
||||
if (typeof type === "string") {
|
||||
@ -191,7 +191,7 @@ class Dish {
|
||||
*
|
||||
* @param {number} type - The data type of value, see Dish enums.
|
||||
* @param {boolean} [notUTF8=false] - Do not treat strings as UTF8.
|
||||
* @returns {Dish | Promise} - (Broswer) A promise | (Node) value of dish in given type
|
||||
* @returns {Dish | Promise} - (Browser) A promise | (Node) value of dish in given type
|
||||
*/
|
||||
presentAs(type, notUTF8=false) {
|
||||
const clone = this.clone();
|
||||
|
@ -113,6 +113,7 @@ class Ingredient {
|
||||
return data;
|
||||
}
|
||||
case "number":
|
||||
if (data === null) return data;
|
||||
number = parseFloat(data);
|
||||
if (isNaN(number)) {
|
||||
const sample = Utils.truncate(data.toString(), 10);
|
||||
|
@ -201,9 +201,8 @@ class Utils {
|
||||
* Utils.parseEscapedChars("\\n");
|
||||
*/
|
||||
static parseEscapedChars(str) {
|
||||
return str.replace(/(\\)?\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a, b) {
|
||||
if (a === "\\") return "\\"+b;
|
||||
switch (b[0]) {
|
||||
return str.replace(/\\([bfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a) {
|
||||
switch (a[0]) {
|
||||
case "\\":
|
||||
return "\\";
|
||||
case "0":
|
||||
@ -214,7 +213,7 @@ class Utils {
|
||||
case "5":
|
||||
case "6":
|
||||
case "7":
|
||||
return String.fromCharCode(parseInt(b, 8));
|
||||
return String.fromCharCode(parseInt(a, 8));
|
||||
case "b":
|
||||
return "\b";
|
||||
case "t":
|
||||
@ -232,12 +231,12 @@ class Utils {
|
||||
case "'":
|
||||
return "'";
|
||||
case "x":
|
||||
return String.fromCharCode(parseInt(b.substr(1), 16));
|
||||
return String.fromCharCode(parseInt(a.substr(1), 16));
|
||||
case "u":
|
||||
if (b[1] === "{")
|
||||
return String.fromCodePoint(parseInt(b.slice(2, -1), 16));
|
||||
if (a[1] === "{")
|
||||
return String.fromCodePoint(parseInt(a.slice(2, -1), 16));
|
||||
else
|
||||
return String.fromCharCode(parseInt(b.substr(1), 16));
|
||||
return String.fromCharCode(parseInt(a.substr(1), 16));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -592,6 +591,44 @@ class Utils {
|
||||
return utf8 ? Utils.byteArrayToUtf8(arr) : Utils.byteArrayToChars(arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the Shannon entropy for a given set of data.
|
||||
*
|
||||
* @param {Uint8Array|ArrayBuffer} input
|
||||
* @returns {number}
|
||||
*/
|
||||
static calculateShannonEntropy(data) {
|
||||
if (data instanceof ArrayBuffer) {
|
||||
data = new Uint8Array(data);
|
||||
}
|
||||
const prob = [],
|
||||
occurrences = new Array(256).fill(0);
|
||||
|
||||
// Count occurrences of each byte in the input
|
||||
let i;
|
||||
for (i = 0; i < data.length; i++) {
|
||||
occurrences[data[i]]++;
|
||||
}
|
||||
|
||||
// Store probability list
|
||||
for (i = 0; i < occurrences.length; i++) {
|
||||
if (occurrences[i] > 0) {
|
||||
prob.push(occurrences[i] / data.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Shannon entropy
|
||||
let entropy = 0,
|
||||
p;
|
||||
|
||||
for (i = 0; i < prob.length; i++) {
|
||||
p = prob[i];
|
||||
entropy += p * Math.log(p) / Math.log(2);
|
||||
}
|
||||
|
||||
return -entropy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses CSV data and returns it as a two dimensional array or strings.
|
||||
@ -759,15 +796,15 @@ class Utils {
|
||||
"%7E": "~",
|
||||
"%21": "!",
|
||||
"%24": "$",
|
||||
//"%26": "&",
|
||||
// "%26": "&",
|
||||
"%27": "'",
|
||||
"%28": "(",
|
||||
"%29": ")",
|
||||
"%2A": "*",
|
||||
//"%2B": "+",
|
||||
// "%2B": "+",
|
||||
"%2C": ",",
|
||||
"%3B": ";",
|
||||
//"%3D": "=",
|
||||
// "%3D": "=",
|
||||
"%3A": ":",
|
||||
"%40": "@",
|
||||
"%2F": "/",
|
||||
@ -1145,6 +1182,7 @@ class Utils {
|
||||
"CRLF": /\r\n/g,
|
||||
"Forward slash": /\//g,
|
||||
"Backslash": /\\/g,
|
||||
"0x with comma": /,?0x/g,
|
||||
"0x": /0x/g,
|
||||
"\\x": /\\x/g,
|
||||
"None": /\s+/g // Included here to remove whitespace when there shouldn't be any
|
||||
@ -1298,7 +1336,7 @@ export function sendStatusMessage(msg) {
|
||||
self.sendStatusMessage(msg);
|
||||
else if (isWebEnvironment())
|
||||
app.alert(msg, 10000);
|
||||
else if (isNodeEnvironment())
|
||||
else if (isNodeEnvironment() && !global.TESTING)
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug(msg);
|
||||
}
|
||||
@ -1336,14 +1374,14 @@ export function debounce(func, wait, id, scope, args) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
|
||||
if (!String.prototype.padStart) {
|
||||
String.prototype.padStart = function padStart(targetLength, padString) {
|
||||
targetLength = targetLength>>0; //floor if number or convert non-number to 0;
|
||||
targetLength = targetLength>>0; // floor if number or convert non-number to 0;
|
||||
padString = String((typeof padString !== "undefined" ? padString : " "));
|
||||
if (this.length > targetLength) {
|
||||
return String(this);
|
||||
} else {
|
||||
targetLength = targetLength-this.length;
|
||||
if (targetLength > padString.length) {
|
||||
padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
|
||||
padString += padString.repeat(targetLength/padString.length); // append to original to ensure we are longer than needed
|
||||
}
|
||||
return padString.slice(0, targetLength) + String(this);
|
||||
}
|
||||
@ -1355,14 +1393,14 @@ if (!String.prototype.padStart) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
|
||||
if (!String.prototype.padEnd) {
|
||||
String.prototype.padEnd = function padEnd(targetLength, padString) {
|
||||
targetLength = targetLength>>0; //floor if number or convert non-number to 0;
|
||||
targetLength = targetLength>>0; // floor if number or convert non-number to 0;
|
||||
padString = String((typeof padString !== "undefined" ? padString : " "));
|
||||
if (this.length > targetLength) {
|
||||
return String(this);
|
||||
} else {
|
||||
targetLength = targetLength-this.length;
|
||||
if (targetLength > padString.length) {
|
||||
padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
|
||||
padString += padString.repeat(targetLength/padString.length); // append to original to ensure we are longer than needed
|
||||
}
|
||||
return String(this) + padString.slice(0, targetLength);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
"URL Decode",
|
||||
"Escape Unicode Characters",
|
||||
"Unescape Unicode Characters",
|
||||
"Normalise Unicode",
|
||||
"To Quoted Printable",
|
||||
"From Quoted Printable",
|
||||
"To Punycode",
|
||||
@ -59,7 +60,8 @@
|
||||
"From Braille",
|
||||
"Parse TLV",
|
||||
"CSV to JSON",
|
||||
"JSON to CSV"
|
||||
"JSON to CSV",
|
||||
"Avro to JSON"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -93,7 +95,11 @@
|
||||
"Affine Cipher Decode",
|
||||
"A1Z26 Cipher Encode",
|
||||
"A1Z26 Cipher Decode",
|
||||
"Rail Fence Cipher Encode",
|
||||
"Rail Fence Cipher Decode",
|
||||
"Atbash Cipher",
|
||||
"CipherSaber2 Encrypt",
|
||||
"CipherSaber2 Decrypt",
|
||||
"Substitute",
|
||||
"Derive PBKDF2 key",
|
||||
"Derive EVP key",
|
||||
@ -110,7 +116,9 @@
|
||||
"Enigma",
|
||||
"Bombe",
|
||||
"Multiple Bombe",
|
||||
"Typex"
|
||||
"Typex",
|
||||
"Lorenz",
|
||||
"Colossus"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -125,6 +133,7 @@
|
||||
"Generate PGP Key Pair",
|
||||
"PGP Encrypt",
|
||||
"PGP Decrypt",
|
||||
"PGP Verify",
|
||||
"PGP Encrypt and Sign",
|
||||
"PGP Decrypt and Verify",
|
||||
"Parse SSH Host Key"
|
||||
@ -194,7 +203,8 @@
|
||||
"Encode text",
|
||||
"Decode text",
|
||||
"Remove Diacritics",
|
||||
"Unescape Unicode Characters"
|
||||
"Unescape Unicode Characters",
|
||||
"Convert to NATO alphabet"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -234,6 +244,7 @@
|
||||
"Convert co-ordinate format",
|
||||
"Show on map",
|
||||
"Parse UNIX file permissions",
|
||||
"Parse ObjectID timestamp",
|
||||
"Swap endianness",
|
||||
"Parse colour code",
|
||||
"Escape string",
|
||||
@ -286,6 +297,7 @@
|
||||
"Zip",
|
||||
"Unzip",
|
||||
"Bzip2 Decompress",
|
||||
"Bzip2 Compress",
|
||||
"Tar",
|
||||
"Untar"
|
||||
]
|
||||
@ -327,6 +339,7 @@
|
||||
"Fletcher-32 Checksum",
|
||||
"Fletcher-64 Checksum",
|
||||
"Adler-32 Checksum",
|
||||
"Luhn Checksum",
|
||||
"CRC-8 Checksum",
|
||||
"CRC-16 Checksum",
|
||||
"CRC-32 Checksum",
|
||||
@ -372,6 +385,7 @@
|
||||
"Detect File Type",
|
||||
"Scan for Embedded Files",
|
||||
"Extract Files",
|
||||
"YARA Rules",
|
||||
"Remove EXIF",
|
||||
"Extract EXIF",
|
||||
"Extract RGBA",
|
||||
@ -385,6 +399,7 @@
|
||||
"ops": [
|
||||
"Render Image",
|
||||
"Play Media",
|
||||
"Generate Image",
|
||||
"Optical Character Recognition",
|
||||
"Remove EXIF",
|
||||
"Extract EXIF",
|
||||
@ -403,6 +418,7 @@
|
||||
"Cover Image",
|
||||
"Image Hue/Saturation/Lightness",
|
||||
"Sharpen Image",
|
||||
"Normalise Image",
|
||||
"Convert Image Format",
|
||||
"Add Text To Image",
|
||||
"Hex Density chart",
|
||||
|
@ -9,7 +9,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/*eslint no-console: ["off"] */
|
||||
/* eslint no-console: ["off"] */
|
||||
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
@ -42,13 +42,10 @@ for (const opObj in Ops) {
|
||||
outputType: op.presentType,
|
||||
flowControl: op.flowControl,
|
||||
manualBake: op.manualBake,
|
||||
args: op.args
|
||||
args: op.args,
|
||||
checks: op.checks
|
||||
};
|
||||
|
||||
if ("patterns" in op) {
|
||||
operationConfig[op.name].patterns = op.patterns;
|
||||
}
|
||||
|
||||
if (!(op.module in modules))
|
||||
modules[op.module] = {};
|
||||
modules[op.module][op.name] = opObj;
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/*eslint no-console: ["off"] */
|
||||
/* eslint no-console: ["off"] */
|
||||
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
@ -6,7 +6,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/*eslint no-console: ["off"] */
|
||||
/* eslint no-console: ["off"] */
|
||||
|
||||
import prompt from "prompt";
|
||||
import colors from "colors";
|
||||
@ -208,7 +208,7 @@ ${result.highlight ? `
|
||||
export default ${moduleName};
|
||||
`;
|
||||
|
||||
//console.log(template);
|
||||
// console.log(template);
|
||||
|
||||
const filename = path.join(dir, `./${moduleName}.mjs`);
|
||||
if (fs.existsSync(filename)) {
|
||||
|
@ -17,7 +17,7 @@ class DishJSON extends DishType {
|
||||
*/
|
||||
static toArrayBuffer() {
|
||||
DishJSON.checkForValue(this.value);
|
||||
this.value = this.value ? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4)) : new ArrayBuffer;
|
||||
this.value = this.value !== undefined ? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4)) : new ArrayBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import DishType from "./DishType.mjs";
|
||||
import { isNodeEnvironment } from "../Utils.mjs";
|
||||
import Utils, { isNodeEnvironment } from "../Utils.mjs";
|
||||
|
||||
|
||||
/**
|
||||
@ -16,13 +16,14 @@ class DishListFile extends DishType {
|
||||
/**
|
||||
* convert the given value to a ArrayBuffer
|
||||
*/
|
||||
static toArrayBuffer() {
|
||||
static async toArrayBuffer() {
|
||||
DishListFile.checkForValue(this.value);
|
||||
|
||||
if (isNodeEnvironment()) {
|
||||
this.value = this.value.map(file => Uint8Array.from(file.data));
|
||||
} else {
|
||||
this.value = await DishListFile.concatenateTypedArraysWithTypedElements(...this.value);
|
||||
}
|
||||
this.value = DishListFile.concatenateTypedArrays(...this.value).buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33,6 +34,27 @@ class DishListFile extends DishType {
|
||||
this.value = [new File(this.value, "unknown")];
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates a list of typed elements together.
|
||||
*
|
||||
* @param {Uint8Array[]} arrays
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
static async concatenateTypedArraysWithTypedElements(...arrays) {
|
||||
let totalLength = 0;
|
||||
for (const arr of arrays) {
|
||||
totalLength += arr.size;
|
||||
}
|
||||
const myArray = new Uint8Array(totalLength);
|
||||
|
||||
let offset = 0;
|
||||
for (const arr of arrays) {
|
||||
const data = await Utils.readFile(arr);
|
||||
myArray.set(data, offset);
|
||||
offset += data.length;
|
||||
}
|
||||
return myArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates a list of Uint8Arrays together
|
||||
|
9
src/core/errors/index.mjs
Normal file
9
src/core/errors/index.mjs
Normal file
@ -0,0 +1,9 @@
|
||||
import OperationError from "./OperationError.mjs";
|
||||
import DishError from "./DishError.mjs";
|
||||
import ExcludedOperationError from "./ExcludedOperationError";
|
||||
|
||||
export {
|
||||
OperationError,
|
||||
DishError,
|
||||
ExcludedOperationError,
|
||||
};
|
@ -22,7 +22,7 @@ export const ENCODING_SCHEME = [
|
||||
/**
|
||||
* Lookup table for the binary value of each digit representation.
|
||||
*
|
||||
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
|
||||
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programmatically,
|
||||
* but unfortunately it's much easier (if less elegant) to use lookup tables
|
||||
* when supporting multiple encoding schemes.
|
||||
*
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Base64's the input byte array using the given alphabet, returning a string.
|
||||
@ -33,6 +33,9 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
|
||||
}
|
||||
|
||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
|
||||
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
|
||||
}
|
||||
|
||||
let output = "",
|
||||
chr1, chr2, chr3,
|
||||
@ -86,6 +89,9 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
|
||||
|
||||
alphabet = alphabet || "A-Za-z0-9+/=";
|
||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
|
||||
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
|
||||
}
|
||||
|
||||
const output = [];
|
||||
let chr1, chr2, chr3,
|
||||
|
@ -20,7 +20,7 @@ export const ALPHABET_OPTIONS = [
|
||||
},
|
||||
{
|
||||
name: "IPv6",
|
||||
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|~}",
|
||||
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~",
|
||||
}
|
||||
];
|
||||
|
||||
|
436
src/core/lib/Blowfish.mjs
Normal file
436
src/core/lib/Blowfish.mjs
Normal file
@ -0,0 +1,436 @@
|
||||
/**
|
||||
Blowfish.js from Dojo Toolkit 1.8.1 (https://github.com/dojo/dojox/tree/1.8/encoding)
|
||||
Extracted by Sladex (xslade@gmail.com)
|
||||
Shoehorned into working with mjs for CyberChef by Matt C (matt@artemisbot.uk)
|
||||
Refactored and implemented modes support by cbeuw (cbeuw.andy@gmail.com)
|
||||
|
||||
@license BSD
|
||||
========================================================================
|
||||
The "New" BSD License:
|
||||
**********************
|
||||
|
||||
Copyright (c) 2005-2016, The Dojo Foundation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the Dojo Foundation nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const crypto = {};
|
||||
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
|
||||
|
||||
/* dojo-release-1.8.1/dojo/_base/lang.js.uncompressed.js */
|
||||
|
||||
const lang = {};
|
||||
lang.isString = function(it) {
|
||||
// summary:
|
||||
// Return true if it is a String
|
||||
// it: anything
|
||||
// Item to test.
|
||||
return (typeof it == "string" || it instanceof String); // Boolean
|
||||
};
|
||||
|
||||
|
||||
/* dojo-release-1.8.1/dojo/_base/array.js.uncompressed.js */
|
||||
|
||||
const arrayUtil = {};
|
||||
arrayUtil.map = function(arr, callback, thisObject, Ctr) {
|
||||
// summary:
|
||||
// applies callback to each element of arr and returns
|
||||
// an Array with the results
|
||||
// arr: Array|String
|
||||
// the array to iterate on. If a string, operates on
|
||||
// individual characters.
|
||||
// callback: Function
|
||||
// a function is invoked with three arguments, (item, index,
|
||||
// array), and returns a value
|
||||
// thisObject: Object?
|
||||
// may be used to scope the call to callback
|
||||
// returns: Array
|
||||
// description:
|
||||
// This function corresponds to the JavaScript 1.6 Array.map() method, with one difference: when
|
||||
// run over sparse arrays, this implementation passes the "holes" in the sparse array to
|
||||
// the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array.
|
||||
// For more details, see:
|
||||
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
|
||||
// example:
|
||||
// | // returns [2, 3, 4, 5]
|
||||
// | array.map([1, 2, 3, 4], function(item){ return item+1 });
|
||||
|
||||
// TODO: why do we have a non-standard signature here? do we need "Ctr"?
|
||||
let i = 0;
|
||||
const l = arr && arr.length || 0, out = new (Ctr || Array)(l);
|
||||
if (l && typeof arr == "string") arr = arr.split("");
|
||||
if (thisObject) {
|
||||
for (; i < l; ++i) {
|
||||
out[i] = callback.call(thisObject, arr[i], i, arr);
|
||||
}
|
||||
} else {
|
||||
for (; i < l; ++i) {
|
||||
out[i] = callback(arr[i], i, arr);
|
||||
}
|
||||
}
|
||||
return out; // Array
|
||||
};
|
||||
|
||||
/* dojo-release-1.8.1/dojox/encoding/crypto/Blowfish.js.uncompressed.js */
|
||||
|
||||
/* Blowfish
|
||||
* Created based on the C# implementation by Marcus Hahn (http://www.hotpixel.net/)
|
||||
* Unsigned math based on Paul Johnstone and Peter Wood patches.
|
||||
* 2005-12-08
|
||||
*/
|
||||
const boxes={
|
||||
p: [
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
0x9216d5d9, 0x8979fb1b
|
||||
],
|
||||
s0: [
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
|
||||
],
|
||||
s1: [
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
|
||||
],
|
||||
s2: [
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
|
||||
],
|
||||
s3: [
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// fixes based on patch submitted by Peter Wood (#5791)
|
||||
const xor = function(x, y) {
|
||||
return (((x>>0x10)^(y>>0x10))<<0x10)|(((x&0xffff)^(y&0xffff))&0xffff);
|
||||
};
|
||||
|
||||
|
||||
const f = function(v, box) {
|
||||
const d=box.s3[v&0xff]; v>>=8;
|
||||
const c=box.s2[v&0xff]; v>>=8;
|
||||
const b=box.s1[v&0xff]; v>>=8;
|
||||
const a=box.s0[v&0xff];
|
||||
|
||||
let r = (((a>>0x10)+(b>>0x10)+(((a&0xffff)+(b&0xffff))>>0x10))<<0x10)|(((a&0xffff)+(b&0xffff))&0xffff);
|
||||
r = (((r>>0x10)^(c>>0x10))<<0x10)|(((r&0xffff)^(c&0xffff))&0xffff);
|
||||
return (((r>>0x10)+(d>>0x10)+(((r&0xffff)+(d&0xffff))>>0x10))<<0x10)|(((r&0xffff)+(d&0xffff))&0xffff);
|
||||
};
|
||||
|
||||
|
||||
const eb = function(o, box) {
|
||||
// TODO: see if this can't be made more efficient
|
||||
let l=o.left;
|
||||
let r=o.right;
|
||||
l=xor(l, box.p[0]);
|
||||
r=xor(r, xor(f(l, box), box.p[1]));
|
||||
l=xor(l, xor(f(r, box), box.p[2]));
|
||||
r=xor(r, xor(f(l, box), box.p[3]));
|
||||
l=xor(l, xor(f(r, box), box.p[4]));
|
||||
r=xor(r, xor(f(l, box), box.p[5]));
|
||||
l=xor(l, xor(f(r, box), box.p[6]));
|
||||
r=xor(r, xor(f(l, box), box.p[7]));
|
||||
l=xor(l, xor(f(r, box), box.p[8]));
|
||||
r=xor(r, xor(f(l, box), box.p[9]));
|
||||
l=xor(l, xor(f(r, box), box.p[10]));
|
||||
r=xor(r, xor(f(l, box), box.p[11]));
|
||||
l=xor(l, xor(f(r, box), box.p[12]));
|
||||
r=xor(r, xor(f(l, box), box.p[13]));
|
||||
l=xor(l, xor(f(r, box), box.p[14]));
|
||||
r=xor(r, xor(f(l, box), box.p[15]));
|
||||
l=xor(l, xor(f(r, box), box.p[16]));
|
||||
o.right=l;
|
||||
o.left=xor(r, box.p[17]);
|
||||
};
|
||||
|
||||
const db = function(o, box) {
|
||||
let l=o.left;
|
||||
let r=o.right;
|
||||
l=xor(l, box.p[17]);
|
||||
r=xor(r, xor(f(l, box), box.p[16]));
|
||||
l=xor(l, xor(f(r, box), box.p[15]));
|
||||
r=xor(r, xor(f(l, box), box.p[14]));
|
||||
l=xor(l, xor(f(r, box), box.p[13]));
|
||||
r=xor(r, xor(f(l, box), box.p[12]));
|
||||
l=xor(l, xor(f(r, box), box.p[11]));
|
||||
r=xor(r, xor(f(l, box), box.p[10]));
|
||||
l=xor(l, xor(f(r, box), box.p[9]));
|
||||
r=xor(r, xor(f(l, box), box.p[8]));
|
||||
l=xor(l, xor(f(r, box), box.p[7]));
|
||||
r=xor(r, xor(f(l, box), box.p[6]));
|
||||
l=xor(l, xor(f(r, box), box.p[5]));
|
||||
r=xor(r, xor(f(l, box), box.p[4]));
|
||||
l=xor(l, xor(f(r, box), box.p[3]));
|
||||
r=xor(r, xor(f(l, box), box.p[2]));
|
||||
l=xor(l, xor(f(r, box), box.p[1]));
|
||||
o.right=l;
|
||||
o.left=xor(r, box.p[0]);
|
||||
};
|
||||
|
||||
const encryptBlock=function(inblock, outblock, box) {
|
||||
const o = {};
|
||||
o.left=inblock[0];
|
||||
o.right=inblock[1];
|
||||
eb(o, box);
|
||||
outblock[0] = o.left;
|
||||
outblock[1] = o.right;
|
||||
};
|
||||
|
||||
const decryptBlock=function(inblock, outblock, box) {
|
||||
const o= {};
|
||||
o.left=inblock[0];
|
||||
o.right=inblock[1];
|
||||
db(o, box);
|
||||
outblock[0] = o.left;
|
||||
outblock[1] = o.right;
|
||||
};
|
||||
|
||||
crypto.Blowfish = new function() {
|
||||
this.createCipher=function(key, modeName) {
|
||||
return new forge.cipher.BlockCipher({
|
||||
algorithm: new Blowfish.Algorithm(key, modeName),
|
||||
key: key,
|
||||
decrypt: false
|
||||
});
|
||||
};
|
||||
|
||||
this.createDecipher=function(key, modeName) {
|
||||
return new forge.cipher.BlockCipher({
|
||||
algorithm: new Blowfish.Algorithm(key, modeName),
|
||||
key: key,
|
||||
decrypt: true
|
||||
});
|
||||
};
|
||||
}();
|
||||
|
||||
|
||||
crypto.Blowfish.Algorithm=function(key, modeName) {
|
||||
this.initialize({key: key});
|
||||
const _box = this.box;
|
||||
const modeOption = {
|
||||
blockSize: 8,
|
||||
cipher: {
|
||||
encrypt: function(inblock, outblock) {
|
||||
encryptBlock(inblock, outblock, _box);
|
||||
},
|
||||
decrypt: function(inblock, outblock) {
|
||||
decryptBlock(inblock, outblock, _box);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
switch (modeName.toLowerCase()) {
|
||||
case "ecb":
|
||||
this.mode=new forge.cipher.modes.ecb(modeOption);
|
||||
break;
|
||||
case "cbc":
|
||||
this.mode=new forge.cipher.modes.cbc(modeOption);
|
||||
break;
|
||||
case "cfb":
|
||||
this.mode=new forge.cipher.modes.cfb(modeOption);
|
||||
break;
|
||||
case "ofb":
|
||||
this.mode=new forge.cipher.modes.ofb(modeOption);
|
||||
break;
|
||||
case "ctr":
|
||||
this.mode=new forge.cipher.modes.ctr(modeOption);
|
||||
break;
|
||||
default:
|
||||
this.mode=new forge.cipher.modes.ecb(modeOption);
|
||||
break;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
crypto.Blowfish.Algorithm.prototype.initialize=function(options) {
|
||||
const POW8=Math.pow(2, 8);
|
||||
|
||||
let k=options.key;
|
||||
if (lang.isString(k)) {
|
||||
k = arrayUtil.map(k.split(""), function(item) {
|
||||
return item.charCodeAt(0) & 0xff;
|
||||
});
|
||||
}
|
||||
|
||||
// init the boxes
|
||||
let pos=0, data=0;
|
||||
const res={ left: 0, right: 0 };
|
||||
const box = {
|
||||
p: arrayUtil.map(boxes.p.slice(0), function(item) {
|
||||
const l=k.length;
|
||||
for (let j=0; j<4; j++) {
|
||||
data=(data*POW8)|k[pos++ % l];
|
||||
}
|
||||
return (((item>>0x10)^(data>>0x10))<<0x10)|(((item&0xffff)^(data&0xffff))&0xffff);
|
||||
}),
|
||||
s0: boxes.s0.slice(0),
|
||||
s1: boxes.s1.slice(0),
|
||||
s2: boxes.s2.slice(0),
|
||||
s3: boxes.s3.slice(0)
|
||||
};
|
||||
|
||||
// encrypt p and the s boxes
|
||||
for (let i=0, l=box.p.length; i<l;) {
|
||||
eb(res, box);
|
||||
box.p[i++]=res.left;
|
||||
box.p[i++]=res.right;
|
||||
}
|
||||
for (let i=0; i<4; i++) {
|
||||
for (let j=0, l=box["s"+i].length; j<l;) {
|
||||
eb(res, box);
|
||||
box["s"+i][j++]=res.left;
|
||||
box["s"+i][j++]=res.right;
|
||||
}
|
||||
}
|
||||
this.box = box;
|
||||
};
|
||||
|
||||
export const Blowfish = crypto.Blowfish;
|
@ -12,16 +12,65 @@
|
||||
export const IO_FORMAT = {
|
||||
"UTF-8 (65001)": 65001,
|
||||
"UTF-7 (65000)": 65000,
|
||||
"UTF16LE (1200)": 1200,
|
||||
"UTF16BE (1201)": 1201,
|
||||
"UTF16 (1201)": 1201,
|
||||
"UTF-16LE (1200)": 1200,
|
||||
"UTF-16BE (1201)": 1201,
|
||||
"UTF-32LE (12000)": 12000,
|
||||
"UTF-32BE (12001)": 12001,
|
||||
"IBM EBCDIC International (500)": 500,
|
||||
"IBM EBCDIC US-Canada (37)": 37,
|
||||
"IBM EBCDIC Multilingual/ROECE (Latin 2) (870)": 870,
|
||||
"IBM EBCDIC Greek Modern (875)": 875,
|
||||
"IBM EBCDIC French (1010)": 1010,
|
||||
"IBM EBCDIC Turkish (Latin 5) (1026)": 1026,
|
||||
"IBM EBCDIC Latin 1/Open System (1047)": 1047,
|
||||
"IBM EBCDIC Lao (1132/1133/1341)": 1132,
|
||||
"IBM EBCDIC US-Canada (037 + Euro symbol) (1140)": 1140,
|
||||
"IBM EBCDIC Germany (20273 + Euro symbol) (1141)": 1141,
|
||||
"IBM EBCDIC Denmark-Norway (20277 + Euro symbol) (1142)": 1142,
|
||||
"IBM EBCDIC Finland-Sweden (20278 + Euro symbol) (1143)": 1143,
|
||||
"IBM EBCDIC Italy (20280 + Euro symbol) (1144)": 1144,
|
||||
"IBM EBCDIC Latin America-Spain (20284 + Euro symbol) (1145)": 1145,
|
||||
"IBM EBCDIC United Kingdom (20285 + Euro symbol) (1146)": 1146,
|
||||
"IBM EBCDIC France (20297 + Euro symbol) (1147)": 1147,
|
||||
"IBM EBCDIC International (500 + Euro symbol) (1148)": 1148,
|
||||
"IBM EBCDIC Icelandic (20871 + Euro symbol) (1149)": 1149,
|
||||
"IBM EBCDIC Germany (20273)": 20273,
|
||||
"IBM EBCDIC Denmark-Norway (20277)": 20277,
|
||||
"IBM EBCDIC Finland-Sweden (20278)": 20278,
|
||||
"IBM EBCDIC Italy (20280)": 20280,
|
||||
"IBM EBCDIC Latin America-Spain (20284)": 20284,
|
||||
"IBM EBCDIC United Kingdom (20285)": 20285,
|
||||
"IBM EBCDIC Japanese Katakana Extended (20290)": 20290,
|
||||
"IBM EBCDIC France (20297)": 20297,
|
||||
"IBM EBCDIC Arabic (20420)": 20420,
|
||||
"IBM EBCDIC Greek (20423)": 20423,
|
||||
"IBM EBCDIC Hebrew (20424)": 20424,
|
||||
"IBM EBCDIC Korean Extended (20833)": 20833,
|
||||
"IBM EBCDIC Thai (20838)": 20838,
|
||||
"IBM EBCDIC Icelandic (20871)": 20871,
|
||||
"IBM EBCDIC Cyrillic Russian (20880)": 20880,
|
||||
"IBM EBCDIC Turkish (20905)": 20905,
|
||||
"IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) (20924)": 20924,
|
||||
"IBM EBCDIC Cyrillic Serbian-Bulgarian (21025)": 21025,
|
||||
"OEM United States (437)": 437,
|
||||
"OEM Greek (formerly 437G); Greek (DOS) (737)": 737,
|
||||
"OEM Baltic; Baltic (DOS) (775)": 775,
|
||||
"OEM Russian; Cyrillic + Euro symbol (808)": 808,
|
||||
"OEM Multilingual Latin 1; Western European (DOS) (850)": 850,
|
||||
"OEM Latin 2; Central European (DOS) (852)": 852,
|
||||
"OEM Cyrillic (primarily Russian) (855)": 855,
|
||||
"OEM Turkish; Turkish (DOS) (857)": 857,
|
||||
"OEM Multilingual Latin 1 + Euro symbol (858)": 858,
|
||||
"OEM Portuguese; Portuguese (DOS) (860)": 860,
|
||||
"OEM Icelandic; Icelandic (DOS) (861)": 861,
|
||||
"OEM Hebrew; Hebrew (DOS) (862)": 862,
|
||||
"OEM French Canadian; French Canadian (DOS) (863)": 863,
|
||||
"OEM Arabic; Arabic (864) (864)": 864,
|
||||
"OEM Nordic; Nordic (DOS) (865)": 865,
|
||||
"OEM Russian; Cyrillic (DOS) (866)": 866,
|
||||
"OEM Modern Greek; Greek, Modern (DOS) (869)": 869,
|
||||
"OEM Cyrillic (primarily Russian) + Euro Symbol (872)": 872,
|
||||
"Windows-874 Thai (874)": 874,
|
||||
"Japanese Shift-JIS (932)": 932,
|
||||
"Simplified Chinese GBK (936)": 936,
|
||||
"Korean (949)": 949,
|
||||
"Traditional Chinese Big5 (950)": 950,
|
||||
"Windows-1250 Central European (1250)": 1250,
|
||||
"Windows-1251 Cyrillic (1251)": 1251,
|
||||
"Windows-1252 Latin (1252)": 1252,
|
||||
@ -31,10 +80,6 @@ export const IO_FORMAT = {
|
||||
"Windows-1256 Arabic (1256)": 1256,
|
||||
"Windows-1257 Baltic (1257)": 1257,
|
||||
"Windows-1258 Vietnam (1258)": 1258,
|
||||
"US-ASCII (20127)": 20127,
|
||||
"Simplified Chinese GB2312 (20936)": 20936,
|
||||
"KOI8-R Russian Cyrillic (20866)": 20866,
|
||||
"KOI8-U Ukrainian Cyrillic (21866)": 21866,
|
||||
"ISO-8859-1 Latin 1 Western European (28591)": 28591,
|
||||
"ISO-8859-2 Latin 2 Central European (28592)": 28592,
|
||||
"ISO-8859-3 Latin 3 South European (28593)": 28593,
|
||||
@ -43,6 +88,7 @@ export const IO_FORMAT = {
|
||||
"ISO-8859-6 Latin/Arabic (28596)": 28596,
|
||||
"ISO-8859-7 Latin/Greek (28597)": 28597,
|
||||
"ISO-8859-8 Latin/Hebrew (28598)": 28598,
|
||||
"ISO 8859-8 Hebrew (ISO-Logical) (38598)": 38598,
|
||||
"ISO-8859-9 Latin 5 Turkish (28599)": 28599,
|
||||
"ISO-8859-10 Latin 6 Nordic (28600)": 28600,
|
||||
"ISO-8859-11 Latin/Thai (28601)": 28601,
|
||||
@ -50,9 +96,83 @@ export const IO_FORMAT = {
|
||||
"ISO-8859-14 Latin 8 Celtic (28604)": 28604,
|
||||
"ISO-8859-15 Latin 9 (28605)": 28605,
|
||||
"ISO-8859-16 Latin 10 (28606)": 28606,
|
||||
"ISO-2022 JIS Japanese (50222)": 50222,
|
||||
"ISO 2022 JIS Japanese with no halfwidth Katakana (50220)": 50220,
|
||||
"ISO 2022 JIS Japanese with halfwidth Katakana (50221)": 50221,
|
||||
"ISO 2022 Japanese JIS X 0201-1989 (1 byte Kana-SO/SI) (50222)": 50222,
|
||||
"ISO 2022 Korean (50225)": 50225,
|
||||
"ISO 2022 Simplified Chinese (50227)": 50227,
|
||||
"ISO 6937 Non-Spacing Accent (20269)": 20269,
|
||||
"EUC Japanese (51932)": 51932,
|
||||
"EUC Simplified Chinese (51936)": 51936,
|
||||
"EUC Korean (51949)": 51949,
|
||||
"ISCII Devanagari (57002)": 57002,
|
||||
"ISCII Bengali (57003)": 57003,
|
||||
"ISCII Tamil (57004)": 57004,
|
||||
"ISCII Telugu (57005)": 57005,
|
||||
"ISCII Assamese (57006)": 57006,
|
||||
"ISCII Oriya (57007)": 57007,
|
||||
"ISCII Kannada (57008)": 57008,
|
||||
"ISCII Malayalam (57009)": 57009,
|
||||
"ISCII Gujarati (57010)": 57010,
|
||||
"ISCII Punjabi (57011)": 57011,
|
||||
"Japanese Shift-JIS (932)": 932,
|
||||
"Simplified Chinese GBK (936)": 936,
|
||||
"Korean (949)": 949,
|
||||
"Traditional Chinese Big5 (950)": 950,
|
||||
"US-ASCII (7-bit) (20127)": 20127,
|
||||
"Simplified Chinese GB2312 (20936)": 20936,
|
||||
"KOI8-R Russian Cyrillic (20866)": 20866,
|
||||
"KOI8-U Ukrainian Cyrillic (21866)": 21866,
|
||||
"Mazovia (Polish) MS-DOS (620)": 620,
|
||||
"Arabic (ASMO 708) (708)": 708,
|
||||
"Arabic (Transparent ASMO); Arabic (DOS) (720)": 720,
|
||||
"Kamenický (Czech) MS-DOS (895)": 895,
|
||||
"Korean (Johab) (1361)": 1361,
|
||||
"MAC Roman (10000)": 10000,
|
||||
"Japanese (Mac) (10001)": 10001,
|
||||
"MAC Traditional Chinese (Big5) (10002)": 10002,
|
||||
"Korean (Mac) (10003)": 10003,
|
||||
"Arabic (Mac) (10004)": 10004,
|
||||
"Hebrew (Mac) (10005)": 10005,
|
||||
"Greek (Mac) (10006)": 10006,
|
||||
"Cyrillic (Mac) (10007)": 10007,
|
||||
"MAC Simplified Chinese (GB 2312) (10008)": 10008,
|
||||
"Romanian (Mac) (10010)": 10010,
|
||||
"Ukrainian (Mac) (10017)": 10017,
|
||||
"Thai (Mac) (10021)": 10021,
|
||||
"MAC Latin 2 (Central European) (10029)": 10029,
|
||||
"Icelandic (Mac) (10079)": 10079,
|
||||
"Turkish (Mac) (10081)": 10081,
|
||||
"Croatian (Mac) (10082)": 10082,
|
||||
"CNS Taiwan (Chinese Traditional) (20000)": 20000,
|
||||
"TCA Taiwan (20001)": 20001,
|
||||
"ETEN Taiwan (Chinese Traditional) (20002)": 20002,
|
||||
"IBM5550 Taiwan (20003)": 20003,
|
||||
"TeleText Taiwan (20004)": 20004,
|
||||
"Wang Taiwan (20005)": 20005,
|
||||
"Western European IA5 (IRV International Alphabet 5) (20105)": 20105,
|
||||
"IA5 German (7-bit) (20106)": 20106,
|
||||
"IA5 Swedish (7-bit) (20107)": 20107,
|
||||
"IA5 Norwegian (7-bit) (20108)": 20108,
|
||||
"T.61 (20261)": 20261,
|
||||
"Japanese (JIS 0208-1990 and 0212-1990) (20932)": 20932,
|
||||
"Korean Wansung (20949)": 20949,
|
||||
"Extended/Ext Alpha Lowercase (21027)": 21027,
|
||||
"Europa 3 (29001)": 29001,
|
||||
"Atari ST/TT (47451)": 47451,
|
||||
"HZ-GB2312 Simplified Chinese (52936)": 52936,
|
||||
"Simplified Chinese GB18030 (54936)": 54936,
|
||||
};
|
||||
|
||||
/**
|
||||
* Unicode Normalisation Forms
|
||||
*
|
||||
* @author Matthieu [m@tthieu.xyz]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Character encoding format mappings.
|
||||
*/
|
||||
export const UNICODE_NORMALISATION_FORMS = ["NFD", "NFC", "NFKD", "NFKC"];
|
||||
|
34
src/core/lib/CipherSaber2.mjs
Normal file
34
src/core/lib/CipherSaber2.mjs
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
export function encode(tempIVP, key, rounds, input) {
|
||||
const ivp = new Uint8Array(key.concat(tempIVP));
|
||||
const state = new Array(256).fill(0);
|
||||
let j = 0, i = 0;
|
||||
const result = [];
|
||||
|
||||
// Mixing states based off of IV.
|
||||
for (let i = 0; i < 256; i++)
|
||||
state[i] = i;
|
||||
const ivpLength = ivp.length;
|
||||
for (let r = 0; r < rounds; r ++) {
|
||||
for (let k = 0; k < 256; k++) {
|
||||
j = (j + state[k] + ivp[k % ivpLength]) % 256;
|
||||
[state[k], state[j]] = [state[j], state[k]];
|
||||
}
|
||||
}
|
||||
j = 0;
|
||||
i = 0;
|
||||
|
||||
// XOR cipher with key.
|
||||
for (let x = 0; x < input.length; x++) {
|
||||
i = (++i) % 256;
|
||||
j = (j + state[i]) % 256;
|
||||
[state[i], state[j]] = [state[j], state[i]];
|
||||
const n = (state[i] + state[j]) % 256;
|
||||
result.push(state[n] ^ input[x]);
|
||||
}
|
||||
return result;
|
||||
}
|
417
src/core/lib/Colossus.mjs
Normal file
417
src/core/lib/Colossus.mjs
Normal file
@ -0,0 +1,417 @@
|
||||
/**
|
||||
* Colossus - an emulation of the world's first electronic computer
|
||||
*
|
||||
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import {INIT_PATTERNS, ITA2_TABLE, ROTOR_SIZES} from "../lib/Lorenz.mjs";
|
||||
|
||||
/**
|
||||
* Colossus simulator class.
|
||||
*/
|
||||
export class ColossusComputer {
|
||||
/**
|
||||
* Construct a Colossus.
|
||||
*
|
||||
* @param {string} ciphertext
|
||||
* @param {string} pattern - named pattern of Chi, Mu and Psi wheels
|
||||
* @param {Object} qbusin - which data inputs are being sent to q bus - each can be null, plain or delta
|
||||
* @param {Object[]} qbusswitches - Q bus calculation switches, multiple rows
|
||||
* @param {Object} control - control switches which specify stepping modes
|
||||
* @param {Object} starts - rotor start positions
|
||||
*/
|
||||
constructor(ciphertext, pattern, qbusin, qbusswitches, control, starts, settotal, limit) {
|
||||
this.ITAlookup = ITA2_TABLE;
|
||||
this.ReverseITAlookup = {};
|
||||
for (const letter in this.ITAlookup) {
|
||||
const code = this.ITAlookup[letter];
|
||||
this.ReverseITAlookup[code] = letter;
|
||||
}
|
||||
|
||||
this.initThyratrons(pattern);
|
||||
|
||||
this.ciphertext = ciphertext;
|
||||
this.qbusin = qbusin;
|
||||
this.qbusswitches = qbusswitches;
|
||||
this.control = control;
|
||||
this.starts = starts;
|
||||
this.settotal = settotal;
|
||||
this.limitations = limit;
|
||||
|
||||
|
||||
this.allCounters = [0, 0, 0, 0, 0];
|
||||
|
||||
this.Zbits = [0, 0, 0, 0, 0]; // Z input is the cipher tape
|
||||
this.ZbitsOneBack = [0, 0, 0, 0, 0]; // for delta
|
||||
this.Qbits = [0, 0, 0, 0, 0]; // input generated for placing onto the Q-bus (the logic processor)
|
||||
|
||||
this.Xbits = [0, 0, 0, 0, 0]; // X is the Chi wheel bits
|
||||
this.Xptr = [0, 0, 0, 0, 0]; // pointers to the current X bits (Chi wheels)
|
||||
this.XbitsOneBack = [0, 0, 0, 0, 0]; // the X bits one back (for delta)
|
||||
|
||||
this.Sbits = [0, 0, 0, 0, 0]; // S is the Psi wheel bits
|
||||
this.Sptr = [0, 0, 0, 0, 0]; // pointers to the current S bits (Psi wheels)
|
||||
this.SbitsOneBack = [0, 0, 0, 0, 0]; // the S bits one back (for delta)
|
||||
|
||||
this.Mptr = [0, 0];
|
||||
|
||||
this.rotorPtrs = {};
|
||||
|
||||
this.totalmotor = 0;
|
||||
this.P5Zbit = [0, 0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a run
|
||||
*
|
||||
* @returns {object}
|
||||
*/
|
||||
run() {
|
||||
const result = {
|
||||
printout: ""
|
||||
};
|
||||
|
||||
// loop until our start positions are back to the beginning
|
||||
this.rotorPtrs = {X1: this.starts.X1, X2: this.starts.X2, X3: this.starts.X3, X4: this.starts.X4, X5: this.starts.X5, M61: this.starts.M61, M37: this.starts.M37, S1: this.starts.S1, S2: this.starts.S2, S3: this.starts.S3, S4: this.starts.S4, S5: this.starts.S5};
|
||||
// this.rotorPtrs = this.starts;
|
||||
let runcount = 1;
|
||||
|
||||
const fast = this.control.fast;
|
||||
const slow = this.control.slow;
|
||||
|
||||
// Print Headers
|
||||
result.printout += fast + " " + slow + "\n";
|
||||
|
||||
do {
|
||||
this.allCounters = [0, 0, 0, 0, 0];
|
||||
this.ZbitsOneBack = [0, 0, 0, 0, 0];
|
||||
this.XbitsOneBack = [0, 0, 0, 0, 0];
|
||||
|
||||
// Run full tape loop and process counters
|
||||
this.runTape();
|
||||
|
||||
// Only print result if larger than set total
|
||||
let fastRef = "00";
|
||||
let slowRef = "00";
|
||||
if (fast !== "") fastRef = this.rotorPtrs[fast].toString().padStart(2, "0");
|
||||
if (slow !== "") slowRef = this.rotorPtrs[slow].toString().padStart(2, "0");
|
||||
let printline = "";
|
||||
for (let c=0;c<5;c++) {
|
||||
if (this.allCounters[c] > this.settotal) {
|
||||
printline += String.fromCharCode(c+97) + this.allCounters[c]+" ";
|
||||
}
|
||||
}
|
||||
if (printline !== "") {
|
||||
result.printout += fastRef + " " + slowRef + " : ";
|
||||
result.printout += printline;
|
||||
result.printout += "\n";
|
||||
}
|
||||
|
||||
// Step fast rotor if required
|
||||
if (fast !== "") {
|
||||
this.rotorPtrs[fast]++;
|
||||
if (this.rotorPtrs[fast] > ROTOR_SIZES[fast]) this.rotorPtrs[fast] = 1;
|
||||
}
|
||||
|
||||
// Step slow rotor if fast rotor has returned to initial start position
|
||||
if (slow !== "" && this.rotorPtrs[fast] === this.starts[fast]) {
|
||||
this.rotorPtrs[slow]++;
|
||||
if (this.rotorPtrs[slow] > ROTOR_SIZES[slow]) this.rotorPtrs[slow] = 1;
|
||||
}
|
||||
|
||||
runcount++;
|
||||
} while (JSON.stringify(this.rotorPtrs) !== JSON.stringify(this.starts));
|
||||
|
||||
result.counters = this.allCounters;
|
||||
result.runcount = runcount;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run tape loop
|
||||
*/
|
||||
runTape() {
|
||||
let charZin = "";
|
||||
|
||||
this.Xptr = [this.rotorPtrs.X1, this.rotorPtrs.X2, this.rotorPtrs.X3, this.rotorPtrs.X4, this.rotorPtrs.X5];
|
||||
this.Mptr = [this.rotorPtrs.M37, this.rotorPtrs.M61];
|
||||
this.Sptr = [this.rotorPtrs.S1, this.rotorPtrs.S2, this.rotorPtrs.S3, this.rotorPtrs.S4, this.rotorPtrs.S5];
|
||||
|
||||
// Run full loop of all character on the input tape (Z)
|
||||
for (let i=0; i<this.ciphertext.length; i++) {
|
||||
charZin = this.ciphertext.charAt(i);
|
||||
|
||||
// Firstly, we check what inputs are specified on the Q-bus input switches
|
||||
this.getQbusInputs(charZin);
|
||||
|
||||
/*
|
||||
* Pattern conditions on individual impulses. Matching patterns of bits on the Q bus.
|
||||
* This is the top section on Colussus K rack - the Q bus programming switches
|
||||
*/
|
||||
const tmpcnt = this.runQbusProcessingConditional();
|
||||
|
||||
/*
|
||||
* Addition of impulses.
|
||||
* This is the bottom section of Colossus K rack.
|
||||
*/
|
||||
this.runQbusProcessingAddition(tmpcnt);
|
||||
|
||||
// Store Z bit impulse 5 two back required for P5 limitation
|
||||
this.P5Zbit[1] = this.P5Zbit[0];
|
||||
this.P5Zbit[0] = this.ITAlookup[charZin].split("")[4];
|
||||
|
||||
// Step rotors
|
||||
this.stepThyratrons();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Step thyratron rings to simulate movement of Lorenz rotors
|
||||
* Chi rotors all step one per character
|
||||
* Motor M61 rotor steps one per character, M37 steps dependant on M61 setting
|
||||
* Psi rotors only step dependant on M37 setting + limitation
|
||||
*/
|
||||
stepThyratrons() {
|
||||
let X2bPtr = this.Xptr[1]-1;
|
||||
if (X2bPtr===0) X2bPtr = ROTOR_SIZES.X2;
|
||||
let S1bPtr = this.Sptr[0]-1;
|
||||
if (S1bPtr===0) S1bPtr = ROTOR_SIZES.S1;
|
||||
|
||||
// Get Chi rotor 5 two back to calculate plaintext (Z+Chi+Psi=Plain)
|
||||
let X5bPtr=this.Xptr[4]-1;
|
||||
if (X5bPtr===0) X5bPtr=ROTOR_SIZES.X5;
|
||||
X5bPtr=X5bPtr-1;
|
||||
if (X5bPtr===0) X5bPtr=ROTOR_SIZES.X5;
|
||||
// Get Psi rotor 5 two back to calculate plaintext (Z+Chi+Psi=Plain)
|
||||
let S5bPtr=this.Sptr[4]-1;
|
||||
if (S5bPtr===0) S5bPtr=ROTOR_SIZES.S5;
|
||||
S5bPtr=S5bPtr-1;
|
||||
if (S5bPtr===0) S5bPtr=ROTOR_SIZES.S5;
|
||||
|
||||
const x2sw = this.limitations.X2;
|
||||
const s1sw = this.limitations.S1;
|
||||
const p5sw = this.limitations.P5;
|
||||
|
||||
// Limitation calculations
|
||||
let lim=1;
|
||||
if (x2sw) lim = this.rings.X[2][X2bPtr-1];
|
||||
if (s1sw) lim = lim ^ this.rings.S[1][S1bPtr-1];
|
||||
|
||||
// P5
|
||||
if (p5sw) {
|
||||
let p5lim = this.P5Zbit[1];
|
||||
p5lim = p5lim ^ this.rings.X[5][X5bPtr-1];
|
||||
p5lim = p5lim ^ this.rings.S[5][S5bPtr-1];
|
||||
lim = lim ^ p5lim;
|
||||
}
|
||||
|
||||
const basicmotor = this.rings.M[2][this.Mptr[0]-1];
|
||||
this.totalmotor = basicmotor;
|
||||
|
||||
if (x2sw || s1sw) {
|
||||
if (basicmotor===0 && lim===1) {
|
||||
this.totalmotor = 0;
|
||||
} else {
|
||||
this.totalmotor = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Step Chi rotors
|
||||
for (let r=0; r<5; r++) {
|
||||
this.Xptr[r]++;
|
||||
if (this.Xptr[r] > ROTOR_SIZES["X"+(r+1)]) this.Xptr[r] = 1;
|
||||
}
|
||||
|
||||
if (this.totalmotor) {
|
||||
// Step Psi rotors
|
||||
for (let r=0; r<5; r++) {
|
||||
this.Sptr[r]++;
|
||||
if (this.Sptr[r] > ROTOR_SIZES["S"+(r+1)]) this.Sptr[r] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Move M37 rotor if M61 set
|
||||
if (this.rings.M[1][this.Mptr[1]-1]===1) this.Mptr[0]++;
|
||||
if (this.Mptr[0] > ROTOR_SIZES.M37) this.Mptr[0]=1;
|
||||
|
||||
// Always move M61 rotor
|
||||
this.Mptr[1]++;
|
||||
if (this.Mptr[1] > ROTOR_SIZES.M61) this.Mptr[1]=1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Q bus inputs
|
||||
*/
|
||||
getQbusInputs(charZin) {
|
||||
// Zbits - the bits from the current character from the cipher tape.
|
||||
this.Zbits = this.ITAlookup[charZin].split("");
|
||||
if (this.qbusin.Z === "Z") {
|
||||
// direct Z
|
||||
this.Qbits = this.Zbits;
|
||||
} else if (this.qbusin.Z === "ΔZ") {
|
||||
// delta Z, the Bitwise XOR of this character Zbits + last character Zbits
|
||||
for (let b=0;b<5;b++) {
|
||||
this.Qbits[b] = this.Zbits[b] ^ this.ZbitsOneBack[b];
|
||||
}
|
||||
}
|
||||
this.ZbitsOneBack = this.Zbits.slice(); // copy value of object, not reference
|
||||
|
||||
// Xbits - the current Chi wheel bits
|
||||
for (let b=0;b<5;b++) {
|
||||
this.Xbits[b] = this.rings.X[b+1][this.Xptr[b]-1];
|
||||
}
|
||||
if (this.qbusin.Chi !== "") {
|
||||
if (this.qbusin.Chi === "Χ") {
|
||||
// direct X added to Qbits
|
||||
for (let b=0;b<5;b++) {
|
||||
this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
|
||||
}
|
||||
} else if (this.qbusin.Chi === "ΔΧ") {
|
||||
// delta X
|
||||
for (let b=0;b<5;b++) {
|
||||
this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
|
||||
this.Qbits[b] = this.Qbits[b] ^ this.XbitsOneBack[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
this.XbitsOneBack = this.Xbits.slice();
|
||||
|
||||
// Sbits - the current Psi wheel bits
|
||||
for (let b=0;b<5;b++) {
|
||||
this.Sbits[b] = this.rings.S[b+1][this.Sptr[b]-1];
|
||||
}
|
||||
if (this.qbusin.Psi !== "") {
|
||||
if (this.qbusin.Psi === "Ψ") {
|
||||
// direct S added to Qbits
|
||||
for (let b=0;b<5;b++) {
|
||||
this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
|
||||
}
|
||||
} else if (this.qbusin.Psi === "ΔΨ") {
|
||||
// delta S
|
||||
for (let b=0;b<5;b++) {
|
||||
this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
|
||||
this.Qbits[b] = this.Qbits[b] ^ this.SbitsOneBack[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
this.SbitsOneBack = this.Sbits.slice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditional impulse Q bus section
|
||||
*/
|
||||
runQbusProcessingConditional() {
|
||||
const cnt = [-1, -1, -1, -1, -1];
|
||||
const numrows = this.qbusswitches.condition.length;
|
||||
|
||||
for (let r=0;r<numrows;r++) {
|
||||
const row = this.qbusswitches.condition[r];
|
||||
if (row.Counter !== "") {
|
||||
let result = true;
|
||||
const cPnt = row.Counter-1;
|
||||
const Qswitch = this.readBusSwitches(row.Qswitches);
|
||||
// Match switches to bit pattern
|
||||
for (let s=0;s<5;s++) {
|
||||
if (Qswitch[s] >= 0 && Qswitch[s] !== parseInt(this.Qbits[s], 10)) result = false;
|
||||
}
|
||||
// Check for NOT switch
|
||||
if (row.Negate) result = !result;
|
||||
|
||||
// AND each row to get final result
|
||||
if (cnt[cPnt] === -1) {
|
||||
cnt[cPnt] = result;
|
||||
} else if (!result) {
|
||||
cnt[cPnt] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negate the whole column, this allows A OR B by doing NOT(NOT A AND NOT B)
|
||||
for (let c=0;c<5;c++) {
|
||||
if (this.qbusswitches.condNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition of impulses Q bus section
|
||||
*/
|
||||
runQbusProcessingAddition(cnt) {
|
||||
const row = this.qbusswitches.addition[0];
|
||||
const Qswitch = row.Qswitches.slice();
|
||||
|
||||
// To save making the arguments of this operation any larger, limiting addition counter to first one only
|
||||
// Colossus could actually add into any of the five counters.
|
||||
if (row.C1) {
|
||||
let addition = 0;
|
||||
for (let s=0;s<5;s++) {
|
||||
// XOR addition
|
||||
if (Qswitch[s]) {
|
||||
addition = addition ^ this.Qbits[s];
|
||||
}
|
||||
}
|
||||
const equals = (row.Equals===""?-1:(row.Equals==="."?0:1));
|
||||
if (addition === equals) {
|
||||
// AND with conditional rows to get final result
|
||||
if (cnt[0] === -1) cnt[0] = true;
|
||||
} else {
|
||||
cnt[0] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Final check, check for addition section negate
|
||||
// then, if any column set, from top to bottom of rack, add to counter.
|
||||
for (let c=0;c<5;c++) {
|
||||
if (this.qbusswitches.addNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
|
||||
|
||||
if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor === 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor === 1)) {
|
||||
if (cnt[c] === true) this.allCounters[c]++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise thyratron rings
|
||||
* These hold the pattern of 1s & 0s for each rotor on banks of thyraton GT1C valves which act as a one-bit store.
|
||||
*/
|
||||
initThyratrons(pattern) {
|
||||
this.rings = {
|
||||
X: {
|
||||
1: INIT_PATTERNS[pattern].X[1].slice().reverse(),
|
||||
2: INIT_PATTERNS[pattern].X[2].slice().reverse(),
|
||||
3: INIT_PATTERNS[pattern].X[3].slice().reverse(),
|
||||
4: INIT_PATTERNS[pattern].X[4].slice().reverse(),
|
||||
5: INIT_PATTERNS[pattern].X[5].slice().reverse()
|
||||
},
|
||||
M: {
|
||||
1: INIT_PATTERNS[pattern].M[1].slice().reverse(),
|
||||
2: INIT_PATTERNS[pattern].M[2].slice().reverse(),
|
||||
},
|
||||
S: {
|
||||
1: INIT_PATTERNS[pattern].S[1].slice().reverse(),
|
||||
2: INIT_PATTERNS[pattern].S[2].slice().reverse(),
|
||||
3: INIT_PATTERNS[pattern].S[3].slice().reverse(),
|
||||
4: INIT_PATTERNS[pattern].S[4].slice().reverse(),
|
||||
5: INIT_PATTERNS[pattern].S[5].slice().reverse()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Read argument bus switches X & . and convert to 1 & 0
|
||||
*/
|
||||
readBusSwitches(row) {
|
||||
const output = [-1, -1, -1, -1, -1];
|
||||
for (let c=0;c<5;c++) {
|
||||
if (row[c]===".") output[c] = 0;
|
||||
if (row[c]==="x") output[c] = 1;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,7 @@ export const WORD_DELIM_OPTIONS = ["Line feed", "CRLF", "Forward slash", "Backsl
|
||||
export const INPUT_DELIM_OPTIONS = ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"];
|
||||
|
||||
/**
|
||||
* Armithmetic sequence delimiters
|
||||
* Arithmetic sequence delimiters
|
||||
*/
|
||||
export const ARITHMETIC_DELIM_OPTIONS = ["Line feed", "Space", "Comma", "Semi-colon", "Colon", "CRLF"];
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -178,7 +178,7 @@ export function scanForFileTypes(buf, categories=Object.keys(FILE_SIGNATURES)) {
|
||||
* @param {Uint8Array} buf - The buffer to search
|
||||
* @param {Object} sig - A single signature object (Not an array of signatures)
|
||||
* @param {number} offset - Where to start search from
|
||||
* @returs {number} The position of the match or -1 if one cannot be found.
|
||||
* @returns {number} The position of the match or -1 if one cannot be found.
|
||||
*/
|
||||
function locatePotentialSig(buf, sig, offset) {
|
||||
// Find values for first key and value in sig
|
||||
|
@ -23,25 +23,39 @@ import Utils from "../Utils.mjs";
|
||||
*
|
||||
* // returns "0a:14:1e"
|
||||
* toHex([10,20,30], ":");
|
||||
*
|
||||
* // returns "0x0a,0x14,0x1e"
|
||||
* toHex([10,20,30], "0x", 2, ",")
|
||||
*/
|
||||
export function toHex(data, delim=" ", padding=2) {
|
||||
export function toHex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
|
||||
if (!data) return "";
|
||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||
|
||||
let output = "";
|
||||
const prepend = (delim === "0x" || delim === "\\x");
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
output += data[i].toString(16).padStart(padding, "0") + delim;
|
||||
const hex = data[i].toString(16).padStart(padding, "0");
|
||||
output += prepend ? delim + hex : hex + delim;
|
||||
|
||||
if (extraDelim) {
|
||||
output += extraDelim;
|
||||
}
|
||||
// Add LF after each lineSize amount of bytes but not at the end
|
||||
if ((i !== data.length - 1) && ((i + 1) % lineSize === 0)) {
|
||||
output += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Add \x or 0x to beginning
|
||||
if (delim === "0x") output = "0x" + output;
|
||||
if (delim === "\\x") output = "\\x" + output;
|
||||
|
||||
if (delim.length)
|
||||
return output.slice(0, -delim.length);
|
||||
else
|
||||
// Remove the extraDelim at the end (if there is one)
|
||||
// and remove the delim at the end, but if it's prepended there's nothing to remove
|
||||
const rTruncLen = extraDelim.length + (prepend ? 0 : delim.length);
|
||||
if (rTruncLen) {
|
||||
// If rTruncLen === 0 then output.slice(0,0) will be returned, which is nothing
|
||||
return output.slice(0, -rTruncLen);
|
||||
} else {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -87,7 +101,7 @@ export function toHexFast(data) {
|
||||
*/
|
||||
export function fromHex(data, delim="Auto", byteLen=2) {
|
||||
if (delim !== "None") {
|
||||
const delimRegex = delim === "Auto" ? /[^a-f\d]/gi : Utils.regexRep(delim);
|
||||
const delimRegex = delim === "Auto" ? /[^a-f\d]|(0x)/gi : Utils.regexRep(delim);
|
||||
data = data.replace(delimRegex, "");
|
||||
}
|
||||
|
||||
@ -102,7 +116,7 @@ export function fromHex(data, delim="Auto", byteLen=2) {
|
||||
/**
|
||||
* To Hexadecimal delimiters.
|
||||
*/
|
||||
export const TO_HEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"];
|
||||
export const TO_HEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "0x with comma", "\\x", "None"];
|
||||
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,7 @@ export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allo
|
||||
let output = "";
|
||||
|
||||
if (cidrRange < 0 || cidrRange > 31) {
|
||||
return "IPv4 CIDR must be less than 32";
|
||||
throw new OperationError("IPv4 CIDR must be less than 32");
|
||||
}
|
||||
|
||||
const mask = ~(0xFFFFFFFF >>> cidrRange),
|
||||
@ -64,7 +64,7 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
|
||||
cidrRange = parseInt(cidr[cidr.length-1], 10);
|
||||
|
||||
if (cidrRange < 0 || cidrRange > 127) {
|
||||
return "IPv6 CIDR must be less than 128";
|
||||
throw new OperationError("IPv6 CIDR must be less than 128");
|
||||
}
|
||||
|
||||
const ip1 = new Array(8),
|
||||
@ -211,7 +211,7 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
|
||||
const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
|
||||
const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
|
||||
if (cidrRange < 0 || cidrRange > 31) {
|
||||
return "IPv4 CIDR must be less than 32";
|
||||
throw new OperationError("IPv4 CIDR must be less than 32");
|
||||
}
|
||||
const mask = ~(0xFFFFFFFF >>> cidrRange),
|
||||
cidrIp1 = network & mask,
|
||||
@ -254,7 +254,7 @@ export function ipv6ListedRange(match, includeNetworkInfo) {
|
||||
const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
|
||||
|
||||
if (cidrRange < 0 || cidrRange > 127) {
|
||||
return "IPv6 CIDR must be less than 128";
|
||||
throw new OperationError("IPv6 CIDR must be less than 128");
|
||||
}
|
||||
|
||||
const cidrIp1 = new Array(8),
|
||||
|
156
src/core/lib/Lorenz.mjs
Normal file
156
src/core/lib/Lorenz.mjs
Normal file
@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Resources required by the Lorenz SZ40/42 and Colossus
|
||||
*
|
||||
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
export const SWITCHES = [
|
||||
{name: "Up (.)", value: "."},
|
||||
{name: "Centre", value: ""},
|
||||
{name: "Down (x)", value: "x"}
|
||||
];
|
||||
|
||||
export const VALID_ITA2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ34589+-./";
|
||||
|
||||
export const ITA2_TABLE = {
|
||||
"A": "11000",
|
||||
"B": "10011",
|
||||
"C": "01110",
|
||||
"D": "10010",
|
||||
"E": "10000",
|
||||
"F": "10110",
|
||||
"G": "01011",
|
||||
"H": "00101",
|
||||
"I": "01100",
|
||||
"J": "11010",
|
||||
"K": "11110",
|
||||
"L": "01001",
|
||||
"M": "00111",
|
||||
"N": "00110",
|
||||
"O": "00011",
|
||||
"P": "01101",
|
||||
"Q": "11101",
|
||||
"R": "01010",
|
||||
"S": "10100",
|
||||
"T": "00001",
|
||||
"U": "11100",
|
||||
"V": "01111",
|
||||
"W": "11001",
|
||||
"X": "10111",
|
||||
"Y": "10101",
|
||||
"Z": "10001",
|
||||
"3": "00010",
|
||||
"4": "01000",
|
||||
"9": "00100",
|
||||
"/": "00000",
|
||||
" ": "00100",
|
||||
".": "00100",
|
||||
"8": "11111",
|
||||
"5": "11011",
|
||||
"-": "11111",
|
||||
"+": "11011"
|
||||
};
|
||||
|
||||
export const ROTOR_SIZES = {
|
||||
S1: 43,
|
||||
S2: 47,
|
||||
S3: 51,
|
||||
S4: 53,
|
||||
S5: 59,
|
||||
M37: 37,
|
||||
M61: 61,
|
||||
X1: 41,
|
||||
X2: 31,
|
||||
X3: 29,
|
||||
X4: 26,
|
||||
X5: 23
|
||||
};
|
||||
|
||||
/**
|
||||
* Initial rotor patterns
|
||||
*/
|
||||
export const INIT_PATTERNS = {
|
||||
"No Pattern": {
|
||||
"X": {
|
||||
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
},
|
||||
"S": {
|
||||
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
}
|
||||
|
||||
},
|
||||
"KH Pattern": {
|
||||
"X": {
|
||||
1: [0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
|
||||
2: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0],
|
||||
3: [0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0],
|
||||
4: [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||
5: [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0]
|
||||
},
|
||||
"S": {
|
||||
1: [0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1],
|
||||
2: [0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
|
||||
3: [0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
|
||||
4: [0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
|
||||
5: [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||
2: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
|
||||
}
|
||||
},
|
||||
"ZMUG Pattern": {
|
||||
"X": {
|
||||
1: [0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
|
||||
2: [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0],
|
||||
3: [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0],
|
||||
4: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1],
|
||||
5: [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1]
|
||||
},
|
||||
"S": {
|
||||
1: [1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||
2: [0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1],
|
||||
3: [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1],
|
||||
4: [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1],
|
||||
5: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
|
||||
2: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"BREAM Pattern": {
|
||||
"X": {
|
||||
1: [0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||
2: [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
|
||||
3: [1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0],
|
||||
4: [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0],
|
||||
5: [0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0]
|
||||
},
|
||||
"S": {
|
||||
1: [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
|
||||
2: [1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
|
||||
3: [1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||
4: [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1],
|
||||
5: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1],
|
||||
2: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1]
|
||||
}
|
||||
}
|
||||
};
|
@ -2,7 +2,7 @@ import OperationConfig from "../config/OperationConfig.json";
|
||||
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import Recipe from "../Recipe.mjs";
|
||||
import Dish from "../Dish.mjs";
|
||||
import {detectFileType} from "./FileType.mjs";
|
||||
import {detectFileType, isType} from "./FileType.mjs";
|
||||
import chiSquared from "chi-squared";
|
||||
|
||||
/**
|
||||
@ -19,31 +19,38 @@ class Magic {
|
||||
* Magic constructor.
|
||||
*
|
||||
* @param {ArrayBuffer} buf
|
||||
* @param {Object[]} [opPatterns]
|
||||
* @param {Object[]} [opCriteria]
|
||||
* @param {Object} [prevOp]
|
||||
*/
|
||||
constructor(buf, opPatterns) {
|
||||
constructor(buf, opCriteria=Magic._generateOpCriteria(), prevOp=null) {
|
||||
this.inputBuffer = new Uint8Array(buf);
|
||||
this.inputStr = Utils.arrayBufferToStr(buf);
|
||||
this.opPatterns = opPatterns || Magic._generateOpPatterns();
|
||||
this.opCriteria = opCriteria;
|
||||
this.prevOp = prevOp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds operations that claim to be able to decode the input based on regular
|
||||
* expression matches.
|
||||
* Finds operations that claim to be able to decode the input based on various criteria.
|
||||
*
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
findMatchingOps() {
|
||||
const matches = [];
|
||||
findMatchingInputOps() {
|
||||
const matches = [],
|
||||
inputEntropy = this.calcEntropy();
|
||||
|
||||
for (let i = 0; i < this.opPatterns.length; i++) {
|
||||
const pattern = this.opPatterns[i],
|
||||
regex = new RegExp(pattern.match, pattern.flags);
|
||||
this.opCriteria.forEach(check => {
|
||||
// If the input doesn't lie in the required entropy range, move on
|
||||
if (check.entropyRange &&
|
||||
(inputEntropy < check.entropyRange[0] ||
|
||||
inputEntropy > check.entropyRange[1]))
|
||||
return;
|
||||
// If the input doesn't match the pattern, move on
|
||||
if (check.pattern &&
|
||||
!check.pattern.test(this.inputStr))
|
||||
return;
|
||||
|
||||
if (regex.test(this.inputStr)) {
|
||||
matches.push(pattern);
|
||||
}
|
||||
}
|
||||
matches.push(check);
|
||||
});
|
||||
|
||||
return matches;
|
||||
}
|
||||
@ -97,6 +104,7 @@ class Magic {
|
||||
|
||||
if (!fileType.length) return null;
|
||||
return {
|
||||
name: fileType[0].name,
|
||||
ext: fileType[0].extension,
|
||||
mime: fileType[0].mime,
|
||||
desc: fileType[0].description
|
||||
@ -184,8 +192,10 @@ class Magic {
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
calcEntropy() {
|
||||
const prob = this._freqDist();
|
||||
calcEntropy(data=this.inputBuffer, standalone=false) {
|
||||
if (!standalone && this.inputEntropy) return this.inputEntropy;
|
||||
|
||||
const prob = this._freqDist(data, standalone);
|
||||
let entropy = 0,
|
||||
p;
|
||||
|
||||
@ -194,6 +204,8 @@ class Magic {
|
||||
if (p === 0) continue;
|
||||
entropy += p * Math.log(p) / Math.log(2);
|
||||
}
|
||||
|
||||
if (!standalone) this.inputEntropy = -entropy;
|
||||
return -entropy;
|
||||
}
|
||||
|
||||
@ -263,6 +275,32 @@ class Magic {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the data passes output criteria for an operation check
|
||||
*
|
||||
* @param {ArrayBuffer} data
|
||||
* @param {Object} criteria
|
||||
* @returns {boolean}
|
||||
*/
|
||||
outputCheckPasses(data, criteria) {
|
||||
if (criteria.pattern) {
|
||||
const dataStr = Utils.arrayBufferToStr(data),
|
||||
regex = new RegExp(criteria.pattern, criteria.flags);
|
||||
if (!regex.test(dataStr))
|
||||
return false;
|
||||
}
|
||||
if (criteria.entropyRange) {
|
||||
const dataEntropy = this.calcEntropy(data, true);
|
||||
if (dataEntropy < criteria.entropyRange[0] || dataEntropy > criteria.entropyRange[1])
|
||||
return false;
|
||||
}
|
||||
if (criteria.mime &&
|
||||
!isType(criteria.mime, data))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Speculatively executes matching operations, recording metadata of each result.
|
||||
*
|
||||
@ -273,15 +311,23 @@ class Magic {
|
||||
* performance)
|
||||
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
|
||||
* @param {boolean} [useful=false] - Whether the current recipe should be scored highly
|
||||
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation output
|
||||
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation
|
||||
* output
|
||||
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
|
||||
*/
|
||||
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null) {
|
||||
async speculativeExecution(
|
||||
depth=0,
|
||||
extLang=false,
|
||||
intensive=false,
|
||||
recipeConfig=[],
|
||||
useful=false,
|
||||
crib=null) {
|
||||
|
||||
// If we have reached the recursion depth, return
|
||||
if (depth < 0) return [];
|
||||
|
||||
// Find any operations that can be run on this data
|
||||
const matchingOps = this.findMatchingOps();
|
||||
|
||||
const matchingOps = this.findMatchingInputOps();
|
||||
let results = [];
|
||||
|
||||
// Record the properties of the current data
|
||||
@ -307,17 +353,21 @@ class Magic {
|
||||
},
|
||||
output = await this._runRecipe([opConfig]);
|
||||
|
||||
// If the recipe is repeating and returning the same data, do not continue
|
||||
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the recipe returned an empty buffer, do not continue
|
||||
if (_buffersEqual(output, new ArrayBuffer())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const magic = new Magic(output, this.opPatterns),
|
||||
// If the recipe is repeating and returning the same data, do not continue
|
||||
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the output criteria for this op doesn't match the output, do not continue
|
||||
if (op.output && !this.outputCheckPasses(output, op.output))
|
||||
return;
|
||||
|
||||
const magic = new Magic(output, this.opCriteria, OperationConfig[op.op]),
|
||||
speculativeResults = await magic.speculativeExecution(
|
||||
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
|
||||
|
||||
@ -329,7 +379,7 @@ class Magic {
|
||||
const bfEncodings = await this.bruteForce();
|
||||
|
||||
await Promise.all(bfEncodings.map(async enc => {
|
||||
const magic = new Magic(enc.data, this.opPatterns),
|
||||
const magic = new Magic(enc.data, this.opCriteria, undefined),
|
||||
bfResults = await magic.speculativeExecution(
|
||||
depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
|
||||
|
||||
@ -344,7 +394,8 @@ class Magic {
|
||||
r.languageScores[0].probability > 0 || // Some kind of language was found
|
||||
r.fileType || // A file was found
|
||||
r.isUTF8 || // UTF-8 was found
|
||||
r.matchingOps.length // A matching op was found
|
||||
r.matchingOps.length || // A matching op was found
|
||||
r.matchesCrib // The crib matches
|
||||
)
|
||||
);
|
||||
|
||||
@ -354,17 +405,17 @@ class Magic {
|
||||
let aScore = a.languageScores[0].score,
|
||||
bScore = b.languageScores[0].score;
|
||||
|
||||
// If a recipe results in a file being detected, it receives a relatively good score
|
||||
if (a.fileType) aScore = 500;
|
||||
if (b.fileType) bScore = 500;
|
||||
|
||||
// If the result is valid UTF8, its score gets boosted (lower being better)
|
||||
if (a.isUTF8) aScore -= 100;
|
||||
if (b.isUTF8) bScore -= 100;
|
||||
|
||||
// If a recipe results in a file being detected, it receives a relatively good score
|
||||
if (a.fileType && aScore > 500) aScore = 500;
|
||||
if (b.fileType && bScore > 500) bScore = 500;
|
||||
|
||||
// If the option is marked useful, give it a good score
|
||||
if (a.useful) aScore = 100;
|
||||
if (b.useful) bScore = 100;
|
||||
if (a.useful && aScore > 100) aScore = 100;
|
||||
if (b.useful && bScore > 100) bScore = 100;
|
||||
|
||||
// Shorter recipes are better, so we add the length of the recipe to the score
|
||||
aScore += a.recipe.length;
|
||||
@ -375,9 +426,10 @@ class Magic {
|
||||
bScore += b.entropy;
|
||||
|
||||
// A result with no recipe but matching ops suggests there are better options
|
||||
if ((!a.recipe.length && a.matchingOps.length) &&
|
||||
b.recipe.length)
|
||||
if ((!a.recipe.length && a.matchingOps.length) && b.recipe.length)
|
||||
return 1;
|
||||
if ((!b.recipe.length && b.matchingOps.length) && a.recipe.length)
|
||||
return -1;
|
||||
|
||||
return aScore - bScore;
|
||||
});
|
||||
@ -402,7 +454,7 @@ class Magic {
|
||||
await recipe.execute(dish);
|
||||
// Return an empty buffer if the recipe did not run to completion
|
||||
if (recipe.lastRunOp === recipe.opList[recipe.opList.length - 1]) {
|
||||
return dish.get(Dish.ARRAY_BUFFER);
|
||||
return await dish.get(Dish.ARRAY_BUFFER);
|
||||
} else {
|
||||
return new ArrayBuffer();
|
||||
}
|
||||
@ -416,14 +468,16 @@ class Magic {
|
||||
* Calculates the number of times each byte appears in the input as a percentage
|
||||
*
|
||||
* @private
|
||||
* @param {ArrayBuffer} [data]
|
||||
* @param {boolean} [standalone]
|
||||
* @returns {number[]}
|
||||
*/
|
||||
_freqDist() {
|
||||
if (this.freqDist) return this.freqDist;
|
||||
_freqDist(data=this.inputBuffer, standalone=false) {
|
||||
if (!standalone && this.freqDist) return this.freqDist;
|
||||
|
||||
const len = this.inputBuffer.length;
|
||||
const len = data.length,
|
||||
counts = new Array(256).fill(0);
|
||||
let i = len;
|
||||
const counts = new Array(256).fill(0);
|
||||
|
||||
if (!len) {
|
||||
this.freqDist = counts;
|
||||
@ -431,13 +485,15 @@ class Magic {
|
||||
}
|
||||
|
||||
while (i--) {
|
||||
counts[this.inputBuffer[i]]++;
|
||||
counts[data[i]]++;
|
||||
}
|
||||
|
||||
this.freqDist = counts.map(c => {
|
||||
const result = counts.map(c => {
|
||||
return c / len * 100;
|
||||
});
|
||||
return this.freqDist;
|
||||
|
||||
if (!standalone) this.freqDist = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -446,24 +502,29 @@ class Magic {
|
||||
* @private
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
static _generateOpPatterns() {
|
||||
const opPatterns = [];
|
||||
static _generateOpCriteria() {
|
||||
const opCriteria = [];
|
||||
|
||||
for (const op in OperationConfig) {
|
||||
if (!("patterns" in OperationConfig[op])) continue;
|
||||
if (!("checks" in OperationConfig[op]))
|
||||
continue;
|
||||
|
||||
OperationConfig[op].patterns.forEach(pattern => {
|
||||
opPatterns.push({
|
||||
OperationConfig[op].checks.forEach(check => {
|
||||
// Add to the opCriteria list.
|
||||
// Compile the regex here and cache the compiled version so we
|
||||
// don't have to keep calculating it.
|
||||
opCriteria.push({
|
||||
op: op,
|
||||
match: pattern.match,
|
||||
flags: pattern.flags,
|
||||
args: pattern.args,
|
||||
useful: pattern.useful || false
|
||||
pattern: check.pattern ? new RegExp(check.pattern, check.flags) : null,
|
||||
args: check.args,
|
||||
useful: check.useful,
|
||||
entropyRange: check.entropyRange,
|
||||
output: check.output
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return opPatterns;
|
||||
return opCriteria;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -497,7 +558,7 @@ class Magic {
|
||||
* Taken from http://wikistats.wmflabs.org/display.php?t=wp
|
||||
*
|
||||
* @param {string} code - ISO 639 code
|
||||
* @returns {string} The full name of the languge
|
||||
* @returns {string} The full name of the language
|
||||
*/
|
||||
static codeToLanguage(code) {
|
||||
return {
|
||||
|
@ -37,7 +37,7 @@ export async function parseQrCode(input, normalise) {
|
||||
image = await jimp.read(image);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error normalising iamge. (${err})`);
|
||||
throw new OperationError(`Error normalising image. (${err})`);
|
||||
}
|
||||
|
||||
const qrData = jsQR(image.bitmap.data, image.getWidth(), image.getHeight());
|
||||
|
@ -155,17 +155,67 @@ export default class Stream {
|
||||
}
|
||||
|
||||
// val is an array
|
||||
let found = false;
|
||||
while (!found && this.position < this.length) {
|
||||
while (++this.position < this.length && this.bytes[this.position] !== val[0]) {
|
||||
continue;
|
||||
|
||||
/**
|
||||
* Builds the skip forward table from the value to be searched.
|
||||
*
|
||||
* @param {Uint8Array} val
|
||||
* @param {Number} len
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
function preprocess(val, len) {
|
||||
const skiptable = new Array();
|
||||
val.forEach((element, index) => {
|
||||
skiptable[element] = len - index;
|
||||
});
|
||||
return skiptable;
|
||||
}
|
||||
|
||||
const length = val.length;
|
||||
const initial = val[length-1];
|
||||
this.position = length;
|
||||
|
||||
// Get the skip table.
|
||||
const skiptable = preprocess(val, length);
|
||||
let found = true;
|
||||
|
||||
while (this.position < this.length) {
|
||||
// Until we hit the final element of val in the stream.
|
||||
while ((this.position < this.length) && (this.bytes[this.position++] !== initial));
|
||||
|
||||
found = true;
|
||||
for (let i = 1; i < val.length; i++) {
|
||||
if (this.position + i > this.length || this.bytes[this.position + i] !== val[i])
|
||||
|
||||
// Loop through the elements comparing them to val.
|
||||
for (let x = length-1; x >= 0; x--) {
|
||||
if (this.bytes[this.position - length + x] !== val[x]) {
|
||||
found = false;
|
||||
|
||||
// If element is not equal to val's element then jump forward by the correct amount.
|
||||
this.position += skiptable[val[x]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
this.position -= length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consume bytes if they match the supplied value.
|
||||
*
|
||||
* @param {Number} val
|
||||
*/
|
||||
consumeWhile(val) {
|
||||
while (this.position < this.length) {
|
||||
if (this.bytes[this.position] !== val) {
|
||||
break;
|
||||
}
|
||||
this.position++;
|
||||
}
|
||||
this.bitPos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,11 +303,13 @@ export default class Stream {
|
||||
/**
|
||||
* Returns a slice of the stream up to the current position.
|
||||
*
|
||||
* @param {number} [start=0]
|
||||
* @param {number} [finish=this.position]
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
carve() {
|
||||
if (this.bitPos > 0) this.position++;
|
||||
return this.bytes.slice(0, this.position);
|
||||
carve(start=0, finish=this.position) {
|
||||
if (this.bitPos > 0) finish++;
|
||||
return this.bytes.slice(start, finish);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,38 @@ class A1Z26CipherDecode extends Operation {
|
||||
value: DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^\\s*([12]?[0-9] )+[12]?[0-9]\\s*$",
|
||||
flags: "",
|
||||
args: ["Space"]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([12]?[0-9],)+[12]?[0-9]\\s*$",
|
||||
flags: "",
|
||||
args: ["Comma"]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([12]?[0-9];)+[12]?[0-9]\\s*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon"]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([12]?[0-9]:)+[12]?[0-9]\\s*$",
|
||||
flags: "",
|
||||
args: ["Colon"]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([12]?[0-9]\\n)+[12]?[0-9]\\s*$",
|
||||
flags: "",
|
||||
args: ["Line feed"]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([12]?[0-9]\\r\\n)+[12]?[0-9]\\s*$",
|
||||
flags: "",
|
||||
args: ["CRLF"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
76
src/core/operations/AvroToJSON.mjs
Normal file
76
src/core/operations/AvroToJSON.mjs
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @author jarrodconnolly [jarrod@nestedquotes.ca]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import avro from "avsc";
|
||||
|
||||
/**
|
||||
* Avro to JSON operation
|
||||
*/
|
||||
class AvroToJSON extends Operation {
|
||||
|
||||
/**
|
||||
* AvroToJSON constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Avro to JSON";
|
||||
this.module = "Serialise";
|
||||
this.description = "Converts Avro encoded data into JSON.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Apache_Avro";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Force Valid JSON",
|
||||
type: "boolean",
|
||||
value: true
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (input.byteLength <= 0) {
|
||||
throw new OperationError("Please provide an input.");
|
||||
}
|
||||
|
||||
const forceJSON = args[0];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const result = [];
|
||||
const inpArray = new Uint8Array(input);
|
||||
const decoder = new avro.streams.BlockDecoder();
|
||||
|
||||
decoder
|
||||
.on("data", function (obj) {
|
||||
result.push(obj);
|
||||
})
|
||||
.on("error", function () {
|
||||
reject(new OperationError("Error parsing Avro file."));
|
||||
})
|
||||
.on("end", function () {
|
||||
if (forceJSON) {
|
||||
resolve(result.length === 1 ? JSON.stringify(result[0], null, 4) : JSON.stringify(result, null, 4));
|
||||
} else {
|
||||
const data = result.reduce((result, current) => result + JSON.stringify(current) + "\n", "");
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
|
||||
decoder.write(inpArray);
|
||||
decoder.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AvroToJSON;
|
@ -50,7 +50,7 @@ class BLAKE2b extends Operation {
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string} The input having been hashed with BLAKE2b in the encoding format speicifed.
|
||||
* @returns {string} The input having been hashed with BLAKE2b in the encoding format specified.
|
||||
*/
|
||||
run(input, args) {
|
||||
const [outSize, outFormat] = args;
|
||||
|
@ -51,7 +51,7 @@ class BLAKE2s extends Operation {
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string} The input having been hashed with BLAKE2s in the encoding format speicifed.
|
||||
* @returns {string} The input having been hashed with BLAKE2s in the encoding format specified.
|
||||
*/
|
||||
run(input, args) {
|
||||
const [outSize, outFormat] = args;
|
||||
|
@ -20,7 +20,7 @@ class BSONDeserialise extends Operation {
|
||||
super();
|
||||
|
||||
this.name = "BSON deserialise";
|
||||
this.module = "BSON";
|
||||
this.module = "Serialise";
|
||||
this.description = "BSON is a computer data interchange format used mainly as a data storage and network transfer format in the MongoDB database. It is a binary form for representing simple data structures, associative arrays (called objects or documents in MongoDB), and various data types of specific interest to MongoDB. The name 'BSON' is based on the term JSON and stands for 'Binary JSON'.<br><br>Input data should be in a raw bytes format.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/BSON";
|
||||
this.inputType = "ArrayBuffer";
|
||||
|
@ -20,7 +20,7 @@ class BSONSerialise extends Operation {
|
||||
super();
|
||||
|
||||
this.name = "BSON serialise";
|
||||
this.module = "BSON";
|
||||
this.module = "Serialise";
|
||||
this.description = "BSON is a computer data interchange format used mainly as a data storage and network transfer format in the MongoDB database. It is a binary form for representing simple data structures, associative arrays (called objects or documents in MongoDB), and various data types of specific interest to MongoDB. The name 'BSON' is based on the term JSON and stands for 'Binary JSON'.<br><br>Input data should be valid JSON.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/BSON";
|
||||
this.inputType = "string";
|
||||
|
@ -4,12 +4,12 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import {
|
||||
BACON_ALPHABETS,
|
||||
BACON_TRANSLATION_CASE, BACON_TRANSLATION_AMNZ, BACON_TRANSLATIONS, BACON_CLEARER_MAP, BACON_NORMALIZE_MAP,
|
||||
swapZeroAndOne
|
||||
} from "../lib/Bacon";
|
||||
} from "../lib/Bacon.mjs";
|
||||
|
||||
/**
|
||||
* Bacon Cipher Decode operation
|
||||
@ -44,6 +44,48 @@ class BaconCipherDecode extends Operation {
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Standard (I=J and U=V)", "0/1", false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Standard (I=J and U=V)", "0/1", true]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Standard (I=J and U=V)", "A/B", false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Standard (I=J and U=V)", "A/B", true]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Complete", "0/1", false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Complete", "0/1", true]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Complete", "A/B", false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||
flags: "",
|
||||
args: ["Complete", "A/B", true]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,12 +4,12 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import {
|
||||
BACON_ALPHABETS,
|
||||
BACON_TRANSLATIONS_FOR_ENCODING, BACON_TRANSLATION_AB,
|
||||
swapZeroAndOne
|
||||
} from "../lib/Bacon";
|
||||
} from "../lib/Bacon.mjs";
|
||||
|
||||
/**
|
||||
* Bacon Cipher Encode operation
|
||||
|
@ -6,23 +6,9 @@
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { Blowfish } from "../vendor/Blowfish.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
|
||||
/**
|
||||
* Lookup table for Blowfish output types.
|
||||
*/
|
||||
const BLOWFISH_OUTPUT_TYPE_LOOKUP = {
|
||||
Base64: 0, Hex: 1, String: 2, Raw: 3
|
||||
};
|
||||
/**
|
||||
* Lookup table for Blowfish modes.
|
||||
*/
|
||||
const BLOWFISH_MODE_LOOKUP = {
|
||||
ECB: 0, CBC: 1, PCBC: 2, CFB: 3, OFB: 4, CTR: 5
|
||||
};
|
||||
import { Blowfish } from "../lib/Blowfish.mjs";
|
||||
|
||||
/**
|
||||
* Blowfish Decrypt operation
|
||||
@ -57,12 +43,12 @@ class BlowfishDecrypt extends Operation {
|
||||
{
|
||||
"name": "Mode",
|
||||
"type": "option",
|
||||
"value": ["CBC", "PCBC", "CFB", "OFB", "CTR", "ECB"]
|
||||
"value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
|
||||
},
|
||||
{
|
||||
"name": "Input",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Base64", "Raw"]
|
||||
"value": ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
"name": "Output",
|
||||
@ -79,21 +65,29 @@ class BlowfishDecrypt extends Operation {
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
[,, mode, inputType, outputType] = args;
|
||||
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
||||
mode = args[2],
|
||||
inputType = args[3],
|
||||
outputType = args[4];
|
||||
|
||||
if (key.length === 0) throw new OperationError("Enter a key");
|
||||
if (key.length !== 8) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
input = inputType === "Raw" ? Utils.strToByteArray(input) : input;
|
||||
Blowfish uses a key length of 8 bytes (64 bits).`);
|
||||
}
|
||||
|
||||
Blowfish.setIV(toBase64(iv), 0);
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
const result = Blowfish.decrypt(input, key, {
|
||||
outputType: BLOWFISH_OUTPUT_TYPE_LOOKUP[inputType], // This actually means inputType. The library is weird.
|
||||
cipherMode: BLOWFISH_MODE_LOOKUP[mode]
|
||||
});
|
||||
const decipher = Blowfish.createDecipher(key, mode);
|
||||
decipher.start({iv: iv});
|
||||
decipher.update(forge.util.createBuffer(input));
|
||||
const result = decipher.finish();
|
||||
|
||||
return outputType === "Hex" ? toHexFast(Utils.strToByteArray(result)) : result;
|
||||
if (result) {
|
||||
return outputType === "Hex" ? decipher.output.toHex() : decipher.output.getBytes();
|
||||
} else {
|
||||
throw new OperationError("Unable to decrypt input with these parameters.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,24 +6,9 @@
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { Blowfish } from "../vendor/Blowfish.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
|
||||
/**
|
||||
* Lookup table for Blowfish output types.
|
||||
*/
|
||||
const BLOWFISH_OUTPUT_TYPE_LOOKUP = {
|
||||
Base64: 0, Hex: 1, String: 2, Raw: 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup table for Blowfish modes.
|
||||
*/
|
||||
const BLOWFISH_MODE_LOOKUP = {
|
||||
ECB: 0, CBC: 1, PCBC: 2, CFB: 3, OFB: 4, CTR: 5
|
||||
};
|
||||
|
||||
import { Blowfish } from "../lib/Blowfish.mjs";
|
||||
|
||||
/**
|
||||
* Blowfish Encrypt operation
|
||||
@ -58,7 +43,7 @@ class BlowfishEncrypt extends Operation {
|
||||
{
|
||||
"name": "Mode",
|
||||
"type": "option",
|
||||
"value": ["CBC", "PCBC", "CFB", "OFB", "CTR", "ECB"]
|
||||
"value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
|
||||
},
|
||||
{
|
||||
"name": "Input",
|
||||
@ -68,7 +53,7 @@ class BlowfishEncrypt extends Operation {
|
||||
{
|
||||
"name": "Output",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Base64", "Raw"]
|
||||
"value": ["Hex", "Raw"]
|
||||
}
|
||||
];
|
||||
}
|
||||
@ -80,21 +65,29 @@ class BlowfishEncrypt extends Operation {
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
[,, mode, inputType, outputType] = args;
|
||||
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
||||
mode = args[2],
|
||||
inputType = args[3],
|
||||
outputType = args[4];
|
||||
|
||||
if (key.length === 0) throw new OperationError("Enter a key");
|
||||
if (key.length !== 8) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
Blowfish uses a key length of 8 bytes (64 bits).`);
|
||||
}
|
||||
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
Blowfish.setIV(toBase64(iv), 0);
|
||||
const cipher = Blowfish.createCipher(key, mode);
|
||||
cipher.start({iv: iv});
|
||||
cipher.update(forge.util.createBuffer(input));
|
||||
cipher.finish();
|
||||
|
||||
const enc = Blowfish.encrypt(input, key, {
|
||||
outputType: BLOWFISH_OUTPUT_TYPE_LOOKUP[outputType],
|
||||
cipherMode: BLOWFISH_MODE_LOOKUP[mode]
|
||||
});
|
||||
|
||||
return outputType === "Raw" ? Utils.byteArrayToChars(enc) : enc;
|
||||
if (outputType === "Hex") {
|
||||
return cipher.output.toHex();
|
||||
} else {
|
||||
return cipher.output.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class Bombe extends Operation {
|
||||
super();
|
||||
|
||||
this.name = "Bombe";
|
||||
this.module = "Default";
|
||||
this.module = "Bletchley";
|
||||
this.description = "Emulation of the Bombe machine used at Bletchley Park to attack Enigma, based on work by Polish and British cryptanalysts.<br><br>To run this you need to have a 'crib', which is some known plaintext for a chunk of the target ciphertext, and know the rotors used. (See the 'Bombe (multiple runs)' operation if you don't know the rotors.) The machine will suggest possible configurations of the Enigma. Each suggestion has the rotor start positions (left to right) and known plugboard pairs.<br><br>Choosing a crib: First, note that Enigma cannot encrypt a letter to itself, which allows you to rule out some positions for possible cribs. Secondly, the Bombe does not simulate the Enigma's middle rotor stepping. The longer your crib, the more likely a step happened within it, which will prevent the attack working. However, other than that, longer cribs are generally better. The attack produces a 'menu' which maps ciphertext letters to plaintext, and the goal is to produce 'loops': for example, with ciphertext ABC and crib CAB, we have the mappings A<->C, B<->A, and C<->B, which produces a loop A-B-C-A. The more loops, the better the crib. The operation will output this: if your menu has too few loops or is too short, a large number of incorrect outputs will usually be produced. Try a different crib. If the menu seems good but the right answer isn't produced, your crib may be wrong, or you may have overlapped the middle rotor stepping - try a different crib.<br><br>Output is not sufficient to fully decrypt the data. You will have to recover the rest of the plugboard settings by inspection. And the ring position is not taken into account: this affects when the middle rotor steps. If your output is correct for a bit, and then goes wrong, adjust the ring and start position on the right-hand rotor together until the output improves. If necessary, repeat for the middle rotor.<br><br>By default this operation runs the checking machine, a manual process to verify the quality of Bombe stops, on each stop, discarding stops which fail. If you want to see how many times the hardware actually stops for a given input, disable the checking machine.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bombe";
|
||||
this.inputType = "string";
|
||||
|
@ -33,9 +33,9 @@ class Bzip2Decompress extends Operation {
|
||||
value: false
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
"match": "^\\x42\\x5a\\x68",
|
||||
"pattern": "^\\x42\\x5a\\x68",
|
||||
"flags": "",
|
||||
"args": []
|
||||
}
|
||||
@ -47,7 +47,7 @@ class Bzip2Decompress extends Operation {
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
async run(input, args) {
|
||||
const [small] = args;
|
||||
if (input.byteLength <= 0) {
|
||||
throw new OperationError("Please provide an input.");
|
||||
|
61
src/core/operations/CipherSaber2Decrypt.mjs
Normal file
61
src/core/operations/CipherSaber2Decrypt.mjs
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { encode } from "../lib/CipherSaber2.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* CipherSaber2 Decrypt operation
|
||||
*/
|
||||
class CipherSaber2Decrypt extends Operation {
|
||||
|
||||
/**
|
||||
* CipherSaber2Decrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CipherSaber2 Decrypt";
|
||||
this.module = "Crypto";
|
||||
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Rounds",
|
||||
type: "number",
|
||||
value: 20
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = new Uint8Array(input);
|
||||
const result = [],
|
||||
key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
rounds = args[1];
|
||||
|
||||
const tempIVP = input.slice(0, 10);
|
||||
input = input.slice(10);
|
||||
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CipherSaber2Decrypt;
|
65
src/core/operations/CipherSaber2Encrypt.mjs
Normal file
65
src/core/operations/CipherSaber2Encrypt.mjs
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import crypto from "crypto";
|
||||
import { encode } from "../lib/CipherSaber2.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* CipherSaber2 Encrypt operation
|
||||
*/
|
||||
class CipherSaber2Encrypt extends Operation {
|
||||
|
||||
/**
|
||||
* CipherSaber2Encrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CipherSaber2 Encrypt";
|
||||
this.module = "Crypto";
|
||||
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Rounds",
|
||||
type: "number",
|
||||
value: 20
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = new Uint8Array(input);
|
||||
const result = [],
|
||||
key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
rounds = args[1];
|
||||
|
||||
// Assign into initialisation vector based on cipher mode.
|
||||
const tempIVP = crypto.randomBytes(10);
|
||||
for (let m = 0; m < 10; m++)
|
||||
result.push(tempIVP[m]);
|
||||
|
||||
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CipherSaber2Encrypt;
|
@ -6,7 +6,7 @@
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import cptable from "codepage";
|
||||
|
||||
/**
|
||||
* Citrix CTX1 Decode operation
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import cptable from "codepage";
|
||||
|
||||
/**
|
||||
* Citrix CTX1 Encode operation
|
||||
|
572
src/core/operations/Colossus.mjs
Normal file
572
src/core/operations/Colossus.mjs
Normal file
@ -0,0 +1,572 @@
|
||||
/**
|
||||
* Emulation of Colossus.
|
||||
*
|
||||
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { ColossusComputer } from "../lib/Colossus.mjs";
|
||||
import { SWITCHES, VALID_ITA2 } from "../lib/Lorenz.mjs";
|
||||
|
||||
/**
|
||||
* Colossus operation
|
||||
*/
|
||||
class Colossus extends Operation {
|
||||
|
||||
/**
|
||||
* Colossus constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
this.name = "Colossus";
|
||||
this.module = "Bletchley";
|
||||
this.description = "Colossus is the name of the world's first electronic computer. Ten Colossi were designed by Tommy Flowers and built at the Post Office Research Labs at Dollis Hill in 1943 during World War 2. They assisted with the breaking of the German Lorenz cipher attachment, a machine created to encipher communications between Hitler and his generals on the front lines.<br><br>To learn more, Virtual Colossus, an online, browser based simulation of a Colossus computer is available at <a href='https://virtualcolossus.co.uk' target='_blank'>virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Colossus' target='_blank'>here</a>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Colossus_computer";
|
||||
this.inputType = "string";
|
||||
this.outputType = "JSON";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
name: "Input",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "Pattern",
|
||||
type: "option",
|
||||
value: ["KH Pattern", "ZMUG Pattern", "BREAM Pattern"]
|
||||
},
|
||||
{
|
||||
name: "QBusZ",
|
||||
type: "option",
|
||||
value: ["", "Z", "ΔZ"]
|
||||
},
|
||||
{
|
||||
name: "QBusΧ",
|
||||
type: "option",
|
||||
value: ["", "Χ", "ΔΧ"]
|
||||
},
|
||||
{
|
||||
name: "QBusΨ",
|
||||
type: "option",
|
||||
value: ["", "Ψ", "ΔΨ"]
|
||||
},
|
||||
{
|
||||
name: "Limitation",
|
||||
type: "option",
|
||||
value: ["None", "Χ2", "Χ2 + P5", "X2 + Ψ1", "X2 + Ψ1 + P5"]
|
||||
},
|
||||
{
|
||||
name: "K Rack Option",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "Select Program",
|
||||
on: [7],
|
||||
off: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||
},
|
||||
{
|
||||
name: "Top Section - Conditional",
|
||||
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
||||
off: [7, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||
},
|
||||
{
|
||||
name: "Bottom Section - Addition",
|
||||
on: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||
off: [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||
},
|
||||
{
|
||||
name: "Advanced",
|
||||
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||
off: [7]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Program to run",
|
||||
type: "option",
|
||||
value: ["", "Letter Count", "1+2=. (1+2 Break In, Find X1,X2)", "4=5=/1=2 (Given X1,X2 find X4,X5)", "/,5,U (Count chars to find X3)"]
|
||||
},
|
||||
{
|
||||
name: "K Rack: Conditional",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "R1-Q1",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q2",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q3",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q4",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q5",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Negate",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "R1-Counter",
|
||||
type: "option",
|
||||
value: ["", "1", "2", "3", "4", "5"]
|
||||
},
|
||||
{
|
||||
name: "R2-Q1",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q2",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q3",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q4",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q5",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Negate",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "R2-Counter",
|
||||
type: "option",
|
||||
value: ["", "1", "2", "3", "4", "5"]
|
||||
},
|
||||
{
|
||||
name: "R3-Q1",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q2",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q3",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q4",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q5",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Negate",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "R3-Counter",
|
||||
type: "option",
|
||||
value: ["", "1", "2", "3", "4", "5"]
|
||||
},
|
||||
{
|
||||
name: "Negate All",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "K Rack: Addition",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "Add-Q1",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q2",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q3",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q4",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q5",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Equals",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "Add-Counter1",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add Negate All",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Total Motor",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "Master Control Panel",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "Set Total",
|
||||
type: "number",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "Fast Step",
|
||||
type: "option",
|
||||
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||
},
|
||||
{
|
||||
name: "Slow Step",
|
||||
type: "option",
|
||||
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||
},
|
||||
{
|
||||
name: "Start Χ1",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ2",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ3",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ4",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ5",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start M61",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start M37",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ1",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ2",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ3",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ4",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ5",
|
||||
type: "number",
|
||||
value: 1
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {Object}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = input.toUpperCase();
|
||||
for (const character of input) {
|
||||
if (VALID_ITA2.indexOf(character) === -1) {
|
||||
let errltr = character;
|
||||
if (errltr === "\n") errltr = "Carriage Return";
|
||||
if (errltr === " ") errltr = "Space";
|
||||
throw new OperationError("Invalid ITA2 character : " + errltr);
|
||||
}
|
||||
}
|
||||
|
||||
const pattern = args[1];
|
||||
const qbusin = {
|
||||
"Z": args[2],
|
||||
"Chi": args[3],
|
||||
"Psi": args[4],
|
||||
};
|
||||
|
||||
const limitation = args[5];
|
||||
const lm = [false, false, false];
|
||||
if (limitation.includes("Χ2")) lm[0] = true;
|
||||
if (limitation.includes("Ψ1")) lm[1] = true;
|
||||
if (limitation.includes("P5")) lm[2] = true;
|
||||
const limit = {
|
||||
X2: lm[0], S1: lm[1], P5: lm[2]
|
||||
};
|
||||
|
||||
const KRackOpt = args[6];
|
||||
const setProgram = args[7];
|
||||
|
||||
if (KRackOpt === "Select Program" && setProgram !== "") {
|
||||
args = this.selectProgram(setProgram, args);
|
||||
}
|
||||
|
||||
const re = new RegExp("^$|^[.x]$");
|
||||
for (let qr=0;qr<3;qr++) {
|
||||
for (let a=0;a<5;a++) {
|
||||
if (!re.test(args[((qr*7)+(a+9))]))
|
||||
throw new OperationError("Switch R"+(qr+1)+"-Q"+(a+1)+" can only be set to blank, . or x");
|
||||
}
|
||||
}
|
||||
|
||||
if (!re.test(args[37])) throw new OperationError("Switch Add-Equals can only be set to blank, . or x");
|
||||
if (!re.test(args[40])) throw new OperationError("Switch Total Motor can only be set to blank, . or x");
|
||||
|
||||
// Q1,Q2,Q3,Q4,Q5,negate,counter1
|
||||
const qbusswitches = {
|
||||
condition: [
|
||||
{Qswitches: [args[9], args[10], args[11], args[12], args[13]], Negate: args[14], Counter: args[15]},
|
||||
{Qswitches: [args[16], args[17], args[18], args[19], args[20]], Negate: args[21], Counter: args[22]},
|
||||
{Qswitches: [args[23], args[24], args[25], args[26], args[27]], Negate: args[28], Counter: args[29]}
|
||||
],
|
||||
condNegateAll: args[30],
|
||||
addition: [
|
||||
{Qswitches: [args[32], args[33], args[34], args[35], args[36]], Equals: args[37], C1: args[38]}
|
||||
],
|
||||
addNegateAll: args[39],
|
||||
totalMotor: args[40]
|
||||
};
|
||||
|
||||
const settotal = parseInt(args[42], 10);
|
||||
if (settotal < 0 || settotal > 9999)
|
||||
throw new OperationError("Set Total must be between 0000 and 9999");
|
||||
|
||||
// null|fast|slow for each of S1-5,M1-2,X1-5
|
||||
const control = {
|
||||
fast: args[43],
|
||||
slow: args[44]
|
||||
};
|
||||
|
||||
// Start positions
|
||||
if (args[52]<1 || args[52]>43) throw new OperationError("Ψ1 start must be between 1 and 43");
|
||||
if (args[53]<1 || args[53]>47) throw new OperationError("Ψ2 start must be between 1 and 47");
|
||||
if (args[54]<1 || args[54]>51) throw new OperationError("Ψ3 start must be between 1 and 51");
|
||||
if (args[55]<1 || args[55]>53) throw new OperationError("Ψ4 start must be between 1 and 53");
|
||||
if (args[56]<1 || args[57]>59) throw new OperationError("Ψ5 start must be between 1 and 59");
|
||||
if (args[51]<1 || args[51]>37) throw new OperationError("Μ37 start must be between 1 and 37");
|
||||
if (args[50]<1 || args[50]>61) throw new OperationError("Μ61 start must be between 1 and 61");
|
||||
if (args[45]<1 || args[45]>41) throw new OperationError("Χ1 start must be between 1 and 41");
|
||||
if (args[46]<1 || args[46]>31) throw new OperationError("Χ2 start must be between 1 and 31");
|
||||
if (args[47]<1 || args[47]>29) throw new OperationError("Χ3 start must be between 1 and 29");
|
||||
if (args[48]<1 || args[48]>26) throw new OperationError("Χ4 start must be between 1 and 26");
|
||||
if (args[49]<1 || args[49]>23) throw new OperationError("Χ5 start must be between 1 and 23");
|
||||
|
||||
const starts = {
|
||||
X1: args[45], X2: args[46], X3: args[47], X4: args[48], X5: args[49],
|
||||
M61: args[50], M37: args[51],
|
||||
S1: args[52], S2: args[53], S3: args[54], S4: args[55], S5: args[56]
|
||||
};
|
||||
|
||||
const colossus = new ColossusComputer(input, pattern, qbusin, qbusswitches, control, starts, settotal, limit);
|
||||
const result = colossus.run();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select Program
|
||||
*
|
||||
* @param {string} progname
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
selectProgram(progname, args) {
|
||||
|
||||
// Basic Letter Count
|
||||
if (progname === "Letter Count") {
|
||||
// Set Conditional R1 : count every character into counter 1
|
||||
args[9] = "";
|
||||
args[10] = "";
|
||||
args[11] = "";
|
||||
args[12] = "";
|
||||
args[13] = "";
|
||||
args[14] = false;
|
||||
args[15] = "1";
|
||||
// clear Conditional R2 & R3
|
||||
args[22] = "";
|
||||
args[29] = "";
|
||||
// Clear Negate result
|
||||
args[30] = false;
|
||||
// Clear Addition row counter
|
||||
args[38] = false;
|
||||
}
|
||||
|
||||
// Bill Tutte's 1+2 Break In
|
||||
if (progname === "1+2=. (1+2 Break In, Find X1,X2)") {
|
||||
// Clear any other counters
|
||||
args[15] = ""; // Conditional R1
|
||||
args[22] = ""; // Conditional R2
|
||||
args[29] = ""; // Conditional R3
|
||||
// Set Add Q1+Q2=. into Counter 1
|
||||
args[32] = true;
|
||||
args[33] = true;
|
||||
args[34] = false;
|
||||
args[35] = false;
|
||||
args[36] = false;
|
||||
args[37] = ".";
|
||||
args[38] = true;
|
||||
}
|
||||
|
||||
// 4=3=/1=2 : Find X4 & X5 where X1 & X2 are known
|
||||
if (progname === "4=5=/1=2 (Given X1,X2 find X4,X5)") {
|
||||
// Set Conditional R1 : Match NOT ..?.. into counter 1
|
||||
args[9] = ".";
|
||||
args[10] = ".";
|
||||
args[11] = "";
|
||||
args[12] = ".";
|
||||
args[13] = ".";
|
||||
args[14] = true;
|
||||
args[15] = "1";
|
||||
// Set Conditional R2 : AND Match NOT xx?xx into counter 1
|
||||
args[16] = "x";
|
||||
args[17] = "x";
|
||||
args[18] = "";
|
||||
args[19] = "x";
|
||||
args[20] = "x";
|
||||
args[21] = true;
|
||||
args[22] = "1";
|
||||
// clear Conditional R3
|
||||
args[29] = "";
|
||||
// Negate result, giving NOT(NOT Q1 AND NOT Q2) which is equivalent to Q1 OR Q2
|
||||
args[30] = true;
|
||||
// Clear Addition row counter
|
||||
args[38] = false;
|
||||
}
|
||||
|
||||
// /,5,U : Count number of matches of /, 5 & U to find X3
|
||||
if (progname === "/,5,U (Count chars to find X3)") {
|
||||
// Set Conditional R1 : Match / char, ITA2 = ..... into counter 1
|
||||
args[9] = ".";
|
||||
args[10] = ".";
|
||||
args[11] = ".";
|
||||
args[12] = ".";
|
||||
args[13] = ".";
|
||||
args[14] = false;
|
||||
args[15] = "1";
|
||||
// Set Conditional R2 : Match 5 char, ITA2 = xx.xx into counter 2
|
||||
args[16] = "x";
|
||||
args[17] = "x";
|
||||
args[18] = ".";
|
||||
args[19] = "x";
|
||||
args[20] = "x";
|
||||
args[21] = false;
|
||||
args[22] = "2";
|
||||
// Set Conditional R3 : Match U char, ITA2 = xxx.. into counter 3
|
||||
args[23] = "x";
|
||||
args[24] = "x";
|
||||
args[25] = "x";
|
||||
args[26] = ".";
|
||||
args[27] = ".";
|
||||
args[28] = false;
|
||||
args[29] = "3";
|
||||
// Clear Negate result
|
||||
args[30] = false;
|
||||
// Clear Addition row counter
|
||||
args[38] = false;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays Colossus results in an HTML table
|
||||
*
|
||||
* @param {Object} output
|
||||
* @param {Object[]} output.counters
|
||||
* @returns {html}
|
||||
*/
|
||||
present(output) {
|
||||
let html = "Colossus Printer\n\n";
|
||||
html += output.printout + "\n\n";
|
||||
html += "Colossus Counters\n\n";
|
||||
html += "<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>C1</th> <th>C2</th> <th>C3</th> <th>C4</th> <th>C5</th></tr>\n";
|
||||
html += "<tr>";
|
||||
for (const ct of output.counters) {
|
||||
html += `<td>${ct}</td>\n`;
|
||||
}
|
||||
html += "</tr>";
|
||||
html += "</table>";
|
||||
return html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Colossus;
|
82
src/core/operations/ConvertToNATOAlphabet.mjs
Normal file
82
src/core/operations/ConvertToNATOAlphabet.mjs
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @author MarvinJWendt [git@marvinjwendt.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Convert to NATO alphabet operation
|
||||
*/
|
||||
class ConvertToNATOAlphabet extends Operation {
|
||||
/**
|
||||
* ConvertToNATOAlphabet constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert to NATO alphabet";
|
||||
this.module = "Default";
|
||||
this.description = "Converts characters to their representation in the NATO phonetic alphabet.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/NATO_phonetic_alphabet";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return input.replace(/[a-z0-9,/.]/ig, letter => {
|
||||
return lookup[letter.toUpperCase()];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const lookup = {
|
||||
"A": "Alfa ",
|
||||
"B": "Bravo ",
|
||||
"C": "Charlie ",
|
||||
"D": "Delta ",
|
||||
"E": "Echo ",
|
||||
"F": "Foxtrot ",
|
||||
"G": "Golf ",
|
||||
"H": "Hotel ",
|
||||
"I": "India ",
|
||||
"J": "Juliett ",
|
||||
"K": "Kilo ",
|
||||
"L": "Lima ",
|
||||
"M": "Mike ",
|
||||
"N": "November ",
|
||||
"O": "Oscar ",
|
||||
"P": "Papa ",
|
||||
"Q": "Quebec ",
|
||||
"R": "Romeo ",
|
||||
"S": "Sierra ",
|
||||
"T": "Tango ",
|
||||
"U": "Uniform ",
|
||||
"V": "Victor ",
|
||||
"W": "Whiskey ",
|
||||
"X": "X-ray ",
|
||||
"Y": "Yankee ",
|
||||
"Z": "Zulu ",
|
||||
"0": "Zero ",
|
||||
"1": "One ",
|
||||
"2": "Two ",
|
||||
"3": "Three ",
|
||||
"4": "Four ",
|
||||
"5": "Five ",
|
||||
"6": "Six ",
|
||||
"7": "Seven ",
|
||||
"8": "Eight ",
|
||||
"9": "Nine ",
|
||||
",": "Comma ",
|
||||
"/": "Fraction bar ",
|
||||
".": "Full stop ",
|
||||
};
|
||||
|
||||
export default ConvertToNATOAlphabet;
|
@ -73,6 +73,12 @@ class DESDecrypt extends Operation {
|
||||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
||||
DES uses an IV length of 8 bytes (64 bits).
|
||||
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||
}
|
||||
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
|
@ -73,6 +73,12 @@ class DESEncrypt extends Operation {
|
||||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
||||
DES uses an IV length of 8 bytes (64 bits).
|
||||
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||
}
|
||||
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
|
@ -63,9 +63,9 @@ class DNSOverHTTPS extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "Validate DNSSEC",
|
||||
name: "Disable DNSSEC validation",
|
||||
type: "boolean",
|
||||
value: true
|
||||
value: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -24,6 +24,13 @@ class DechunkHTTPResponse extends Operation {
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^[0-9A-F]+\r\n",
|
||||
flags: "i",
|
||||
args: []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,6 +30,13 @@ class DecodeNetBIOSName extends Operation {
|
||||
"value": 65
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^\\s*\\S{32}$",
|
||||
flags: "",
|
||||
args: [65]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import cptable from "codepage";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc.mjs";
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
|
||||
/**
|
||||
@ -25,7 +25,17 @@ class DefangIPAddresses extends Operation {
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^\\s*(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-f]{4}:){7}[0-9a-f]{4})\\s*$",
|
||||
flags: "i",
|
||||
args: [],
|
||||
output: {
|
||||
pattern: "^\\s*(([0-9]{1,3}\\[\\.\\]){3}[0-9]{1,3}|([0-9a-f]{4}\\[\\:\\]){7}[0-9a-f]{4})\\s*$",
|
||||
flags: "i"
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,13 @@ import Operation from "../Operation.mjs";
|
||||
import {detectFileType} from "../lib/FileType.mjs";
|
||||
import {FILE_SIGNATURES} from "../lib/FileSignatures.mjs";
|
||||
|
||||
// Concat all supported extensions into a single flat list
|
||||
const exts = [].concat.apply([], Object.keys(FILE_SIGNATURES).map(cat =>
|
||||
[].concat.apply([], FILE_SIGNATURES[cat].map(sig =>
|
||||
sig.extension.split(",")
|
||||
))
|
||||
)).unique().sort().join(", ");
|
||||
|
||||
/**
|
||||
* Detect File Type operation
|
||||
*/
|
||||
@ -22,11 +29,7 @@ class DetectFileType extends Operation {
|
||||
this.name = "Detect File Type";
|
||||
this.module = "Default";
|
||||
this.description = "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.<br><br>Currently supports the following file types: " +
|
||||
Object.keys(FILE_SIGNATURES).map(cat =>
|
||||
FILE_SIGNATURES[cat].map(sig =>
|
||||
sig.extension.split(",")[0]
|
||||
).join(", ")
|
||||
).join(", ") + ".";
|
||||
exts + ".";
|
||||
this.infoURL = "https://wikipedia.org/wiki/List_of_file_signatures";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
|
@ -47,6 +47,11 @@ class Diff extends Operation {
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Show subtraction",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Ignore whitespace",
|
||||
"type": "boolean",
|
||||
@ -67,6 +72,7 @@ class Diff extends Operation {
|
||||
diffBy,
|
||||
showAdded,
|
||||
showRemoved,
|
||||
showSubtraction,
|
||||
ignoreWhitespace
|
||||
] = args,
|
||||
samples = input.split(sampleDelim);
|
||||
@ -116,7 +122,7 @@ class Diff extends Operation {
|
||||
if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else if (diff[i].removed) {
|
||||
if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else {
|
||||
} else if (!showSubtraction) {
|
||||
output += Utils.escapeHtml(diff[i].value);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import cptable from "codepage";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc.mjs";
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,7 @@ class Enigma extends Operation {
|
||||
super();
|
||||
|
||||
this.name = "Enigma";
|
||||
this.module = "Default";
|
||||
this.module = "Bletchley";
|
||||
this.description = "Encipher/decipher with the WW2 Enigma machine.<br><br>Enigma was used by the German military, among others, around the WW2 era as a portable cipher machine to protect sensitive military, diplomatic and commercial communications.<br><br>The standard set of German military rotors and reflectors are provided. To configure the plugboard, enter a string of connected pairs of letters, e.g. <code>AB CD EF</code> connects A to B, C to D, and E to F. This is also used to create your own reflectors. To create your own rotor, enter the letters that the rotor maps A to Z to, in order, optionally followed by <code><</code> then a list of stepping points.<br>This is deliberately fairly permissive with rotor placements etc compared to a real Enigma (on which, for example, a four-rotor Enigma uses only the thin reflectors and the beta or gamma rotor in the 4th slot).<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Enigma_machine";
|
||||
this.inputType = "string";
|
||||
|
@ -44,22 +44,22 @@ class EscapeUnicodeCharacters extends Operation {
|
||||
"value": true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "\\\\u(?:[\\da-f]{4,6})",
|
||||
pattern: "\\\\u(?:[\\da-f]{4,6})",
|
||||
flags: "i",
|
||||
args: ["\\u"]
|
||||
},
|
||||
{
|
||||
match: "%u(?:[\\da-f]{4,6})",
|
||||
pattern: "%u(?:[\\da-f]{4,6})",
|
||||
flags: "i",
|
||||
args: ["%u"]
|
||||
},
|
||||
{
|
||||
match: "U\\+(?:[\\da-f]{4,6})",
|
||||
pattern: "U\\+(?:[\\da-f]{4,6})",
|
||||
flags: "i",
|
||||
args: ["U+"]
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,8 @@ class Fork extends Operation {
|
||||
}
|
||||
|
||||
const recipe = new Recipe();
|
||||
let output = "",
|
||||
progress = 0;
|
||||
const outputs = [];
|
||||
let progress = 0;
|
||||
|
||||
state.forkOffset += state.progress + 1;
|
||||
|
||||
@ -104,10 +104,10 @@ class Fork extends Operation {
|
||||
}
|
||||
progress = err.progress + 1;
|
||||
}
|
||||
output += await dish.get(outputType) + mergeDelim;
|
||||
outputs.push(await dish.get(outputType));
|
||||
}
|
||||
|
||||
state.dish.set(output, outputType);
|
||||
state.dish.set(outputs.join(mergeDelim), outputType);
|
||||
state.progress += progress;
|
||||
return state;
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ class FromBCD extends Operation {
|
||||
"value": FORMAT
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^(?:\\d{4} ){3,}\\d{4}$",
|
||||
pattern: "^(?:\\d{4} ){3,}\\d{4}$",
|
||||
flags: "",
|
||||
args: ["8 4 2 1", true, false, "Nibbles"]
|
||||
},
|
||||
|
@ -36,12 +36,12 @@ class FromBase32 extends Operation {
|
||||
value: true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
|
||||
pattern: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
|
||||
flags: "",
|
||||
args: ["A-Z2-7=", false]
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -38,14 +38,14 @@ class FromBase58 extends Operation {
|
||||
"value": true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||
pattern: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||
flags: "",
|
||||
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", false]
|
||||
},
|
||||
{
|
||||
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||
pattern: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||
flags: "",
|
||||
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", false]
|
||||
},
|
||||
|
@ -42,15 +42,22 @@ class FromBase62 extends Operation {
|
||||
*/
|
||||
run(input, args) {
|
||||
if (input.length < 1) return [];
|
||||
const ALPHABET = Utils.expandAlphRange(args[0]).join("");
|
||||
const BN = BigNumber.clone({ ALPHABET });
|
||||
const alphabet = Utils.expandAlphRange(args[0]).join("");
|
||||
const BN62 = BigNumber.clone({ ALPHABET: alphabet });
|
||||
|
||||
const re = new RegExp("[^" + ALPHABET.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||
input = input.replace(re, "");
|
||||
|
||||
const number = new BN(input, 62);
|
||||
// Read number in using Base62 alphabet
|
||||
const number = new BN62(input, 62);
|
||||
// Copy to new BigNumber object that uses the default alphabet
|
||||
const normalized = new BigNumber(number);
|
||||
|
||||
return Utils.convertToByteArray(number.toString(16), "Hex");
|
||||
// Convert to hex and add leading 0 if required
|
||||
let hex = normalized.toString(16);
|
||||
if (hex.length % 2 !== 0) hex = "0" + hex;
|
||||
|
||||
return Utils.convertToByteArray(hex, "Hex");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,69 +36,69 @@ class FromBase64 extends Operation {
|
||||
value: true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
pattern: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
|
||||
pattern: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9-_", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
|
||||
pattern: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+\\-=", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
|
||||
pattern: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z=", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*[A-Z\\d_.]{20,}\\s*$",
|
||||
pattern: "^\\s*[A-Z\\d_.]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9_.", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
|
||||
pattern: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9._-", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["0-9a-zA-Z+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["0-9A-Za-z+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
||||
pattern: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
||||
flags: "",
|
||||
args: [" -_", false]
|
||||
},
|
||||
{
|
||||
match: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
|
||||
pattern: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["+\\-0-9A-Za-z", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
|
||||
pattern: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
|
||||
flags: "",
|
||||
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
|
||||
pattern: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["N-ZA-Mn-za-m0-9+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^\\s*[A-Z\\d./]{20,}\\s*$",
|
||||
pattern: "^\\s*[A-Z\\d./]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z", true]
|
||||
},
|
||||
|
@ -33,39 +33,39 @@ class FromBinary extends Operation {
|
||||
"value": BIN_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^(?:[01]{8})+$",
|
||||
pattern: "^(?:[01]{8})+$",
|
||||
flags: "",
|
||||
args: ["None"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?: [01]{8})*$",
|
||||
pattern: "^(?:[01]{8})(?: [01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Space"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:,[01]{8})*$",
|
||||
pattern: "^(?:[01]{8})(?:,[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Comma"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:;[01]{8})*$",
|
||||
pattern: "^(?:[01]{8})(?:;[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?::[01]{8})*$",
|
||||
pattern: "^(?:[01]{8})(?::[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:\\n[01]{8})*$",
|
||||
pattern: "^(?:[01]{8})(?:\\n[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Line feed"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
|
||||
pattern: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["CRLF"]
|
||||
},
|
||||
|
@ -36,37 +36,37 @@ class FromDecimal extends Operation {
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Space", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Comma", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Colon", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Line feed", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["CRLF", false]
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,12 @@ class FromHTMLEntity extends Operation {
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
|
||||
pattern: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
|
||||
flags: "i",
|
||||
args: []
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -32,49 +32,54 @@ class FromHex extends Operation {
|
||||
value: FROM_HEX_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^(?:[\\dA-F]{2})+$",
|
||||
pattern: "^(?:[\\dA-F]{2})+$",
|
||||
flags: "i",
|
||||
args: ["None"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
|
||||
pattern: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Space"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
|
||||
pattern: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Comma"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
|
||||
pattern: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Semi-colon"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
|
||||
pattern: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Colon"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
|
||||
pattern: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
|
||||
flags: "i",
|
||||
args: ["Line feed"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
|
||||
pattern: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
|
||||
flags: "i",
|
||||
args: ["CRLF"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?:0x[\\dA-F]{2})*$",
|
||||
pattern: "^(?:0x[\\dA-F]{2})+$",
|
||||
flags: "i",
|
||||
args: ["0x"]
|
||||
},
|
||||
{
|
||||
match: "^[\\dA-F]{2}(?:\\\\x[\\dA-F]{2})*$",
|
||||
pattern: "^0x[\\dA-F]{2}(?:,0x[\\dA-F]{2})*$",
|
||||
flags: "i",
|
||||
args: ["0x with comma"]
|
||||
},
|
||||
{
|
||||
pattern: "^(?:\\\\x[\\dA-F]{2})+$",
|
||||
flags: "i",
|
||||
args: ["\\x"]
|
||||
}
|
||||
|
@ -26,6 +26,13 @@ class FromHexContent extends Operation {
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "\\|([\\da-f]{2} ?)+\\|",
|
||||
flags: "i",
|
||||
args: []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,9 +27,9 @@ class FromHexdump extends Operation {
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
|
||||
pattern: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
|
||||
flags: "i",
|
||||
args: []
|
||||
},
|
||||
|
@ -37,12 +37,12 @@ class FromMorseCode extends Operation {
|
||||
"value": WORD_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
|
||||
pattern: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
|
||||
flags: "i",
|
||||
args: ["Space", "Line feed"]
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ class FromMorseCode extends Operation {
|
||||
const letterDelim = Utils.charRep(args[0]);
|
||||
const wordDelim = Utils.charRep(args[1]);
|
||||
|
||||
input = input.replace(/-|‐|−|_|–|—|dash/ig, "<dash>"); //hyphen-minus|hyphen|minus-sign|undersore|en-dash|em-dash
|
||||
input = input.replace(/-|‐|−|_|–|—|dash/ig, "<dash>"); // hyphen-minus|hyphen|minus-sign|undersore|en-dash|em-dash
|
||||
input = input.replace(/\.|·|dot/ig, "<dot>");
|
||||
|
||||
let words = input.split(wordDelim);
|
||||
@ -147,7 +147,8 @@ const MORSE_TABLE = {
|
||||
"=": "<dash><dot><dot><dot><dash>",
|
||||
"&": "<dot><dash><dot><dot><dot>",
|
||||
"_": "<dot><dot><dash><dash><dot><dash>",
|
||||
"$": "<dot><dot><dot><dash><dot><dot><dash>"
|
||||
"$": "<dot><dot><dot><dash><dot><dot><dash>",
|
||||
" ": "<dot><dot><dot><dot><dot><dot><dot>"
|
||||
};
|
||||
|
||||
export default FromMorseCode;
|
||||
|
@ -32,37 +32,37 @@ class FromOctal extends Operation {
|
||||
"value": DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
flags: "",
|
||||
args: ["Space"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
flags: "",
|
||||
args: ["Comma"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
flags: "",
|
||||
args: ["Colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
flags: "",
|
||||
args: ["Line feed"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||
flags: "",
|
||||
args: ["CRLF"]
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -28,9 +28,9 @@ class FromQuotedPrintable extends Operation {
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
|
||||
pattern: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
|
||||
flags: "i",
|
||||
args: []
|
||||
},
|
||||
|
@ -33,27 +33,27 @@ class FromUNIXTimestamp extends Operation {
|
||||
"value": UNITS
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^1?\\d{9}$",
|
||||
pattern: "^1?\\d{9}$",
|
||||
flags: "",
|
||||
args: ["Seconds (s)"]
|
||||
},
|
||||
{
|
||||
match: "^1?\\d{12}$",
|
||||
pattern: "^1?\\d{12}$",
|
||||
flags: "",
|
||||
args: ["Milliseconds (ms)"]
|
||||
},
|
||||
{
|
||||
match: "^1?\\d{15}$",
|
||||
pattern: "^1?\\d{15}$",
|
||||
flags: "",
|
||||
args: ["Microseconds (μs)"]
|
||||
},
|
||||
{
|
||||
match: "^1?\\d{18}$",
|
||||
pattern: "^1?\\d{18}$",
|
||||
flags: "",
|
||||
args: ["Nanoseconds (ns)"]
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
|
184
src/core/operations/GenerateImage.mjs
Normal file
184
src/core/operations/GenerateImage.mjs
Normal file
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* @author pointhi [thomas.pointhuber@gmx.at]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {isImage} from "../lib/FileType";
|
||||
import {toBase64} from "../lib/Base64";
|
||||
import jimp from "jimp";
|
||||
import {isWorkerEnvironment} from "../Utils";
|
||||
|
||||
/**
|
||||
* Generate Image operation
|
||||
*/
|
||||
class GenerateImage extends Operation {
|
||||
|
||||
/**
|
||||
* GenerateImage constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Generate Image";
|
||||
this.module = "Image";
|
||||
this.description = "Generates an image using the input as pixel values.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Mode",
|
||||
"type": "option",
|
||||
"value": ["Greyscale", "RG", "RGB", "RGBA", "Bits"]
|
||||
},
|
||||
{
|
||||
"name": "Pixel Scale Factor",
|
||||
"type": "number",
|
||||
"value": 8,
|
||||
},
|
||||
{
|
||||
"name": "Pixels per row",
|
||||
"type": "number",
|
||||
"value": 64,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [mode, scale, width] = args;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
if (scale <= 0) {
|
||||
throw new OperationError("Pixel Scale Factor needs to be > 0");
|
||||
}
|
||||
|
||||
if (width <= 0) {
|
||||
throw new OperationError("Pixels per Row needs to be > 0");
|
||||
}
|
||||
|
||||
const bytePerPixelMap = {
|
||||
"Greyscale": 1,
|
||||
"RG": 2,
|
||||
"RGB": 3,
|
||||
"RGBA": 4,
|
||||
"Bits": 1/8,
|
||||
};
|
||||
|
||||
const bytesPerPixel = bytePerPixelMap[mode];
|
||||
|
||||
if (bytesPerPixel > 0 && input.length % bytesPerPixel !== 0) {
|
||||
throw new OperationError(`Number of bytes is not a divisor of ${bytesPerPixel}`);
|
||||
}
|
||||
|
||||
const height = Math.ceil(input.length / bytesPerPixel / width);
|
||||
const image = await new jimp(width, height, (err, image) => {});
|
||||
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Generating image from data...");
|
||||
|
||||
if (mode === "Bits") {
|
||||
let index = 0;
|
||||
for (let j = 0; j < input.length; j++) {
|
||||
const curByte = Utils.bin(input[j]);
|
||||
for (let k = 0; k < 8; k++, index++) {
|
||||
const x = index % width;
|
||||
const y = Math.floor(index / width);
|
||||
|
||||
const value = curByte[k] === "0" ? 0xFF : 0x00;
|
||||
const pixel = jimp.rgbaToInt(value, value, value, 0xFF);
|
||||
image.setPixelColor(pixel, x, y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let i = 0;
|
||||
while (i < input.length) {
|
||||
const index = i / bytesPerPixel;
|
||||
const x = index % width;
|
||||
const y = Math.floor(index / width);
|
||||
|
||||
let red = 0x00;
|
||||
let green = 0x00;
|
||||
let blue = 0x00;
|
||||
let alpha = 0xFF;
|
||||
|
||||
switch (mode) {
|
||||
case "Greyscale":
|
||||
red = green = blue = input[i++];
|
||||
break;
|
||||
|
||||
case "RG":
|
||||
red = input[i++];
|
||||
green = input[i++];
|
||||
break;
|
||||
|
||||
case "RGB":
|
||||
red = input[i++];
|
||||
green = input[i++];
|
||||
blue = input[i++];
|
||||
break;
|
||||
|
||||
case "RGBA":
|
||||
red = input[i++];
|
||||
green = input[i++];
|
||||
blue = input[i++];
|
||||
alpha = input[i++];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new OperationError(`Unsupported Mode: (${mode})`);
|
||||
}
|
||||
|
||||
try {
|
||||
const pixel = jimp.rgbaToInt(red, green, blue, alpha);
|
||||
image.setPixelColor(pixel, x, y);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error while generating image from pixel values. (${err})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scale !== 1) {
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Scaling image...");
|
||||
|
||||
image.scaleToFit(width*scale, height*scale, jimp.RESIZE_NEAREST_NEIGHBOR);
|
||||
}
|
||||
|
||||
try {
|
||||
const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error generating image. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the generated image using HTML for web apps
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GenerateImage;
|
@ -58,7 +58,7 @@ class GeneratePGPKeyPair extends Operation {
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
async run(input, args) {
|
||||
const [keyType, keySize] = args[0].split("-"),
|
||||
password = args[1],
|
||||
name = args[2],
|
||||
|
@ -117,7 +117,7 @@ class GroupIPAddresses extends Operation {
|
||||
|
||||
// Sort IPv6 network dictionaries and print
|
||||
for (networkStr in ipv6Networks) {
|
||||
//ipv6Networks[networkStr] = ipv6Networks[networkStr].sort(); TODO
|
||||
// ipv6Networks[networkStr] = ipv6Networks[networkStr].sort(); TODO
|
||||
|
||||
output += networkStr + "/" + cidr + "\n";
|
||||
|
||||
|
@ -5,9 +5,9 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import zlibAndGzip from "zlibjs/bin/zlib_and_gzip.min.js";
|
||||
import gunzip from "zlibjs/bin/gunzip.min.js";
|
||||
|
||||
const Zlib = zlibAndGzip.Zlib;
|
||||
const Zlib = gunzip.Zlib;
|
||||
|
||||
/**
|
||||
* Gunzip operation
|
||||
@ -27,12 +27,12 @@ class Gunzip extends Operation {
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
match: "^\\x1f\\x8b\\x08",
|
||||
pattern: "^\\x1f\\x8b\\x08",
|
||||
flags: "",
|
||||
args: []
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@ -42,8 +42,8 @@ class Gunzip extends Operation {
|
||||
* @returns {File}
|
||||
*/
|
||||
run(input, args) {
|
||||
const gunzip = new Zlib.Gunzip(new Uint8Array(input));
|
||||
return new Uint8Array(gunzip.decompress()).buffer;
|
||||
const gzipObj = new Zlib.Gunzip(new Uint8Array(input));
|
||||
return new Uint8Array(gzipObj.decompress()).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import {COMPRESSION_TYPE, ZLIB_COMPRESSION_TYPE_LOOKUP} from "../lib/Zlib.mjs";
|
||||
import zlibAndGzip from "zlibjs/bin/zlib_and_gzip.min.js";
|
||||
import gzip from "zlibjs/bin/gzip.min.js";
|
||||
|
||||
const Zlib = zlibAndGzip.Zlib;
|
||||
const Zlib = gzip.Zlib;
|
||||
|
||||
/**
|
||||
* Gzip operation
|
||||
@ -73,12 +73,15 @@ class Gzip extends Operation {
|
||||
options.filename = filename;
|
||||
}
|
||||
if (comment.length) {
|
||||
options.flags.fcommenct = true;
|
||||
options.flags.comment = true;
|
||||
options.comment = comment;
|
||||
}
|
||||
|
||||
const gzip = new Zlib.Gzip(new Uint8Array(input), options);
|
||||
return new Uint8Array(gzip.compress()).buffer;
|
||||
const gzipObj = new Zlib.Gzip(new Uint8Array(input), options);
|
||||
const compressed = new Uint8Array(gzipObj.compress());
|
||||
if (options.flags.comment && !(compressed[3] & 0x10)) {
|
||||
compressed[3] |= 0x10;
|
||||
}
|
||||
return compressed.buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class HammingDistance extends Operation {
|
||||
samples = input.split(delim);
|
||||
|
||||
if (samples.length !== 2) {
|
||||
throw new OperationError("Error: You can only calculae the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.");
|
||||
throw new OperationError("Error: You can only calculate the edit distance between 2 strings. Please ensure exactly two inputs are provided, separated by the specified delimiter.");
|
||||
}
|
||||
|
||||
if (samples[0].length !== samples[1].length) {
|
||||
|
759
src/core/operations/Lorenz.mjs
Normal file
759
src/core/operations/Lorenz.mjs
Normal file
@ -0,0 +1,759 @@
|
||||
/**
|
||||
* Emulation of the Lorenz SZ40/42a/42b cipher attachment.
|
||||
*
|
||||
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Lorenz operation
|
||||
*/
|
||||
class Lorenz extends Operation {
|
||||
|
||||
/**
|
||||
* Lorenz constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Lorenz";
|
||||
this.module = "Bletchley";
|
||||
this.description = "The Lorenz SZ40/42 cipher attachment was a WW2 German rotor cipher machine with twelve rotors which attached in-line between remote teleprinters.<br><br>It used the Vernam cipher with two groups of five rotors (named the psi(ψ) wheels and chi(χ) wheels at Bletchley Park) to create two pseudorandom streams of five bits, encoded in ITA2, which were XOR added to the plaintext. Two other rotors, dubbed the mu(μ) or motor wheels, could hold up the stepping of the psi wheels meaning they stepped intermittently.<br><br>Each rotor has a different number of cams/lugs around their circumference which could be set active or inactive changing the key stream.<br><br>Three models of the Lorenz are emulated, SZ40, SZ42a and SZ42b and three example wheel patterns (the lug settings) are included (KH, ZMUG & BREAM) with the option to set a custom set using the letter 'x' for active or '.' for an inactive lug.<br><br>The input can either be plaintext or ITA2 when sending and ITA2 when receiving.<br><br>To learn more, Virtual Lorenz, an online, browser based simulation of the Lorenz SZ40/42 is available at <a href='https://lorenz.virtualcolossus.co.uk' target='_blank'>lorenz.virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Lorenz-SZ' target='_blank'>here</a>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Lorenz_cipher";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Model",
|
||||
type: "option",
|
||||
value: ["SZ40", "SZ42a", "SZ42b"]
|
||||
},
|
||||
{
|
||||
name: "Wheel Pattern",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "KH Pattern",
|
||||
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||
},
|
||||
{
|
||||
name: "ZMUG Pattern",
|
||||
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||
},
|
||||
{
|
||||
name: "BREAM Pattern",
|
||||
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||
},
|
||||
{
|
||||
name: "No Pattern",
|
||||
off: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||
},
|
||||
{
|
||||
name: "Custom",
|
||||
on: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "KT-Schalter",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Mode",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "Send",
|
||||
on: [4],
|
||||
off: [5]
|
||||
},
|
||||
{
|
||||
name: "Receive",
|
||||
off: [4],
|
||||
on: [5]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Input Type",
|
||||
type: "option",
|
||||
value: ["Plaintext", "ITA2"]
|
||||
},
|
||||
{
|
||||
name: "Output Type",
|
||||
type: "option",
|
||||
value: ["Plaintext", "ITA2"]
|
||||
},
|
||||
{
|
||||
name: "ITA2 Format",
|
||||
type: "option",
|
||||
value: ["5/8/9", "+/-/."]
|
||||
},
|
||||
{
|
||||
name: "Ψ1 start (1-43)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Ψ2 start (1-47)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Ψ3 start (1-51)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Ψ4 start (1-53)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Ψ5 start (1-59)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Μ37 start (1-37)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Μ61 start (1-61)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Χ1 start (1-41)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Χ2 start (1-31)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Χ3 start (1-29)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Χ4 start (1-26)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Χ5 start (1-23)",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Ψ1 lugs (43)",
|
||||
type: "string",
|
||||
value: ".x...xx.x.x..xxx.x.x.xxxx.x.x.x.x.x..x.xx.x"
|
||||
},
|
||||
{
|
||||
name: "Ψ2 lugs (47)",
|
||||
type: "string",
|
||||
value: ".xx.x.xxx..x.x.x..x.xx.x.xxx.x....x.xx.x.x.x..x"
|
||||
},
|
||||
{
|
||||
name: "Ψ3 lugs (51)",
|
||||
type: "string",
|
||||
value: ".x.x.x..xxx....x.x.xx.x.x.x..xxx.x.x..x.x.xx..x.x.x"
|
||||
},
|
||||
{
|
||||
name: "Ψ4 lugs (53)",
|
||||
type: "string",
|
||||
value: ".xx...xxxxx.x.x.xx...x.xx.x.x..x.x.xx.x..x.x.x.x.x.x."
|
||||
},
|
||||
{
|
||||
name: "Ψ5 lugs (59)",
|
||||
type: "string",
|
||||
value: "xx...xx.x..x.xx.x...x.x.x.x.x.x.x.x.xx..xxxx.x.x...xx.x..x."
|
||||
},
|
||||
{
|
||||
name: "Μ37 lugs (37)",
|
||||
type: "string",
|
||||
value: "x.x.x.x.x.x...x.x.x...x.x.x...x.x...."
|
||||
},
|
||||
{
|
||||
name: "Μ61 lugs (61)",
|
||||
type: "string",
|
||||
value: ".xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx..."
|
||||
},
|
||||
{
|
||||
name: "Χ1 lugs (41)",
|
||||
type: "string",
|
||||
value: ".x...xxx.x.xxxx.x...x.x..xxx....xx.xxxx.."
|
||||
},
|
||||
{
|
||||
name: "Χ2 lugs (31)",
|
||||
type: "string",
|
||||
value: "x..xxx...x.xxxx..xx..x..xx.xx.."
|
||||
},
|
||||
{
|
||||
name: "Χ3 lugs (29)",
|
||||
type: "string",
|
||||
value: "..xx..x.xxx...xx...xx..xx.xx."
|
||||
},
|
||||
{
|
||||
name: "Χ4 lugs (26)",
|
||||
type: "string",
|
||||
value: "xx..x..xxxx..xx.xxx....x.."
|
||||
},
|
||||
{
|
||||
name: "Χ5 lugs (23)",
|
||||
type: "string",
|
||||
value: "xx..xx....xxxx.x..x.x.."
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
|
||||
const model = args[0],
|
||||
pattern = args[1],
|
||||
kt = args[2],
|
||||
mode = args[3],
|
||||
intype = args[4],
|
||||
outtype = args[5],
|
||||
format = args[6],
|
||||
lugs1 = args[19],
|
||||
lugs2 = args[20],
|
||||
lugs3 = args[21],
|
||||
lugs4 = args[22],
|
||||
lugs5 = args[23],
|
||||
lugm37 = args[24],
|
||||
lugm61 = args[25],
|
||||
lugx1 = args[26],
|
||||
lugx2 = args[27],
|
||||
lugx3 = args[28],
|
||||
lugx4 = args[29],
|
||||
lugx5 = args[30];
|
||||
|
||||
let s1 = args[7],
|
||||
s2 = args[8],
|
||||
s3 = args[9],
|
||||
s4 = args[10],
|
||||
s5 = args[11],
|
||||
m37 = args[12],
|
||||
m61 = args[13],
|
||||
x1 = args[14],
|
||||
x2 = args[15],
|
||||
x3 = args[16],
|
||||
x4 = args[17],
|
||||
x5 = args[18];
|
||||
|
||||
this.reverseTable();
|
||||
|
||||
if (s1<1 || s1>43) throw new OperationError("Ψ1 start must be between 1 and 43");
|
||||
if (s2<1 || s2>47) throw new OperationError("Ψ2 start must be between 1 and 47");
|
||||
if (s3<1 || s3>51) throw new OperationError("Ψ3 start must be between 1 and 51");
|
||||
if (s4<1 || s4>53) throw new OperationError("Ψ4 start must be between 1 and 53");
|
||||
if (s5<1 || s5>59) throw new OperationError("Ψ5 start must be between 1 and 59");
|
||||
if (m37<1 || m37>37) throw new OperationError("Μ37 start must be between 1 and 37");
|
||||
if (m61<1 || m61>61) throw new OperationError("Μ61 start must be between 1 and 61");
|
||||
if (x1<1 || x1>41) throw new OperationError("Χ1 start must be between 1 and 41");
|
||||
if (x2<1 || x2>31) throw new OperationError("Χ2 start must be between 1 and 31");
|
||||
if (x3<1 || x3>29) throw new OperationError("Χ3 start must be between 1 and 29");
|
||||
if (x4<1 || x4>26) throw new OperationError("Χ4 start must be between 1 and 26");
|
||||
if (x5<1 || x5>23) throw new OperationError("Χ5 start must be between 1 and 23");
|
||||
|
||||
// Initialise chosen wheel pattern
|
||||
let chosenSetting = "";
|
||||
if (pattern === "Custom") {
|
||||
const re = new RegExp("^[.xX]*$");
|
||||
if (lugs1.length !== 43 || !re.test(lugs1)) throw new OperationError("Ψ1 custom lugs must be 43 long and can only include . or x ");
|
||||
if (lugs2.length !== 47 || !re.test(lugs2)) throw new OperationError("Ψ2 custom lugs must be 47 long and can only include . or x");
|
||||
if (lugs3.length !== 51 || !re.test(lugs3)) throw new OperationError("Ψ3 custom lugs must be 51 long and can only include . or x");
|
||||
if (lugs4.length !== 53 || !re.test(lugs4)) throw new OperationError("Ψ4 custom lugs must be 53 long and can only include . or x");
|
||||
if (lugs5.length !== 59 || !re.test(lugs5)) throw new OperationError("Ψ5 custom lugs must be 59 long and can only include . or x");
|
||||
if (lugm37.length !== 37 || !re.test(lugm37)) throw new OperationError("M37 custom lugs must be 37 long and can only include . or x");
|
||||
if (lugm61.length !== 61 || !re.test(lugm61)) throw new OperationError("M61 custom lugs must be 61 long and can only include . or x");
|
||||
if (lugx1.length !== 41 || !re.test(lugx1)) throw new OperationError("Χ1 custom lugs must be 41 long and can only include . or x");
|
||||
if (lugx2.length !== 31 || !re.test(lugx2)) throw new OperationError("Χ2 custom lugs must be 31 long and can only include . or x");
|
||||
if (lugx3.length !== 29 || !re.test(lugx3)) throw new OperationError("Χ3 custom lugs must be 29 long and can only include . or x");
|
||||
if (lugx4.length !== 26 || !re.test(lugx4)) throw new OperationError("Χ4 custom lugs must be 26 long and can only include . or x");
|
||||
if (lugx5.length !== 23 || !re.test(lugx5)) throw new OperationError("Χ5 custom lugs must be 23 long and can only include . or x");
|
||||
chosenSetting = INIT_PATTERNS["No Pattern"];
|
||||
chosenSetting.S[1] = this.readLugs(lugs1);
|
||||
chosenSetting.S[2] = this.readLugs(lugs2);
|
||||
chosenSetting.S[3] = this.readLugs(lugs3);
|
||||
chosenSetting.S[4] = this.readLugs(lugs4);
|
||||
chosenSetting.S[5] = this.readLugs(lugs5);
|
||||
chosenSetting.M[1] = this.readLugs(lugm61);
|
||||
chosenSetting.M[2] = this.readLugs(lugm37);
|
||||
chosenSetting.X[1] = this.readLugs(lugx1);
|
||||
chosenSetting.X[2] = this.readLugs(lugx2);
|
||||
chosenSetting.X[3] = this.readLugs(lugx3);
|
||||
chosenSetting.X[4] = this.readLugs(lugx4);
|
||||
chosenSetting.X[5] = this.readLugs(lugx5);
|
||||
} else {
|
||||
chosenSetting = INIT_PATTERNS[pattern];
|
||||
}
|
||||
const chiSettings = chosenSetting.X; // Pin settings for Chi links (X)
|
||||
const psiSettings = chosenSetting.S; // Pin settings for Psi links (S)
|
||||
const muSettings = chosenSetting.M; // Pin settings for Motor links (M)
|
||||
|
||||
// Convert input text to ITA2 (including figure/letter shifts)
|
||||
const ita2Input = this.convertToITA2(input, intype, mode);
|
||||
|
||||
let thisPsi = [];
|
||||
let thisChi = [];
|
||||
let m61lug = muSettings[1][m61-1];
|
||||
let m37lug = muSettings[2][m37-1];
|
||||
const p5 = [0, 0, 0];
|
||||
|
||||
const self = this;
|
||||
const letters = Array.prototype.map.call(ita2Input, function(character) {
|
||||
const letter = character.toUpperCase();
|
||||
|
||||
// Store lugs used in limitations, need these later
|
||||
let x2bptr = x2+1;
|
||||
if (x2bptr===32) x2bptr=1;
|
||||
let s1bptr = s1+1;
|
||||
if (s1bptr===44) s1bptr=1;
|
||||
|
||||
thisChi = [
|
||||
chiSettings[1][x1-1],
|
||||
chiSettings[2][x2-1],
|
||||
chiSettings[3][x3-1],
|
||||
chiSettings[4][x4-1],
|
||||
chiSettings[5][x5-1]
|
||||
];
|
||||
|
||||
thisPsi = [
|
||||
psiSettings[1][s1-1],
|
||||
psiSettings[2][s2-1],
|
||||
psiSettings[3][s3-1],
|
||||
psiSettings[4][s4-1],
|
||||
psiSettings[5][s5-1]
|
||||
];
|
||||
|
||||
if (typeof ITA2_TABLE[letter] == "undefined") {
|
||||
return "";
|
||||
}
|
||||
|
||||
// The encipher calculation
|
||||
|
||||
// We calculate Bitwise XOR for each of the 5 bits across our input ( K XOR Psi XOR Chi )
|
||||
const xorSum = [];
|
||||
for (let i=0;i<=4;i++) {
|
||||
xorSum[i] = ITA2_TABLE[letter][i] ^ thisPsi[i] ^ thisChi[i];
|
||||
}
|
||||
const resultStr = xorSum.join("");
|
||||
|
||||
// Wheel movement
|
||||
|
||||
// Chi wheels always move one back after each letter
|
||||
if (--x1 < 1) x1 = 41;
|
||||
if (--x2 < 1) x2 = 31;
|
||||
if (--x3 < 1) x3 = 29;
|
||||
if (--x4 < 1) x4 = 26;
|
||||
if (--x5 < 1) x5 = 23;
|
||||
|
||||
// Motor wheel (61 pin) also moves one each letter
|
||||
if (--m61 < 1) m61 = 61;
|
||||
|
||||
// If M61 is set, we also move M37
|
||||
if (m61lug === 1) {
|
||||
if (--m37 < 1) m37 = 37;
|
||||
}
|
||||
|
||||
// Psi wheels only move sometimes, dependent on M37 current setting and limitations
|
||||
|
||||
const basicmotor = m37lug;
|
||||
let totalmotor = basicmotor;
|
||||
let lim = 0;
|
||||
|
||||
p5[2] = p5[1];
|
||||
p5[1] = p5[0];
|
||||
if (mode==="Send") {
|
||||
p5[0] = parseInt(ITA2_TABLE[letter][4], 10);
|
||||
} else {
|
||||
p5[0] = parseInt(xorSum[4], 10);
|
||||
}
|
||||
|
||||
// Limitations here
|
||||
if (model==="SZ42a") {
|
||||
// Chi 2 one back lim - The active character of Chi 2 (2nd Chi wheel) in the previous position
|
||||
lim = parseInt(chiSettings[2][x2bptr-1], 10);
|
||||
if (kt) {
|
||||
// p5 back 2
|
||||
if (lim===p5[2]) {
|
||||
lim = 0;
|
||||
} else {
|
||||
lim=1;
|
||||
}
|
||||
}
|
||||
|
||||
// If basic motor = 0 and limitation = 1, Total motor = 0 [no move], otherwise, total motor = 1 [move]
|
||||
if (basicmotor===0 && lim===1) {
|
||||
totalmotor = 0;
|
||||
} else {
|
||||
totalmotor = 1;
|
||||
}
|
||||
|
||||
} else if (model==="SZ42b") {
|
||||
// Chi 2 one back + Psi 1 one back.
|
||||
const x2b1lug = parseInt(chiSettings[2][x2bptr-1], 10);
|
||||
const s1b1lug = parseInt(psiSettings[1][s1bptr-1], 10);
|
||||
lim = 1;
|
||||
if (x2b1lug===s1b1lug) lim=0;
|
||||
if (kt) {
|
||||
// p5 back 2
|
||||
if (lim===p5[2]) {
|
||||
lim=0;
|
||||
} else {
|
||||
lim=1;
|
||||
}
|
||||
}
|
||||
// If basic motor = 0 and limitation = 1, Total motor = 0 [no move], otherwise, total motor = 1 [move]
|
||||
if (basicmotor===0 && lim===1) {
|
||||
totalmotor = 0;
|
||||
} else {
|
||||
totalmotor = 1;
|
||||
}
|
||||
|
||||
} else if (model==="SZ40") {
|
||||
// SZ40 - just move based on the M37 motor wheel
|
||||
totalmotor = basicmotor;
|
||||
} else {
|
||||
throw new OperationError("Lorenz model type not recognised");
|
||||
}
|
||||
|
||||
// Move the Psi wheels when current totalmotor active
|
||||
if (totalmotor === 1) {
|
||||
if (--s1 < 1) s1 = 43;
|
||||
if (--s2 < 1) s2 = 47;
|
||||
if (--s3 < 1) s3 = 51;
|
||||
if (--s4 < 1) s4 = 53;
|
||||
if (--s5 < 1) s5 = 59;
|
||||
}
|
||||
|
||||
m61lug = muSettings[1][m61-1];
|
||||
m37lug = muSettings[2][m37-1];
|
||||
|
||||
let rtnstr = self.REVERSE_ITA2_TABLE[resultStr];
|
||||
if (format==="5/8/9") {
|
||||
if (rtnstr==="+") rtnstr="5"; // + or 5 used to represent figure shift
|
||||
if (rtnstr==="-") rtnstr="8"; // - or 8 used to represent letter shift
|
||||
if (rtnstr===".") rtnstr="9"; // . or 9 used to represent space
|
||||
}
|
||||
return rtnstr;
|
||||
});
|
||||
|
||||
const ita2output = letters.join("");
|
||||
|
||||
return this.convertFromITA2(ita2output, outtype, mode);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the ITA2 Code lookup table
|
||||
*/
|
||||
reverseTable() {
|
||||
this.REVERSE_ITA2_TABLE = {};
|
||||
this.REVERSE_FIGSHIFT_TABLE = {};
|
||||
|
||||
for (const letter in ITA2_TABLE) {
|
||||
const code = ITA2_TABLE[letter];
|
||||
this.REVERSE_ITA2_TABLE[code] = letter;
|
||||
}
|
||||
for (const letter in figShiftArr) {
|
||||
const ltr = figShiftArr[letter];
|
||||
this.REVERSE_FIGSHIFT_TABLE[ltr] = letter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read lugs settings - convert to 0|1
|
||||
*/
|
||||
readLugs(lugstr) {
|
||||
const arr = Array.prototype.map.call(lugstr, function(lug) {
|
||||
if (lug===".") {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert input plaintext to ITA2
|
||||
*/
|
||||
convertToITA2(input, intype, mode) {
|
||||
let result = "";
|
||||
let figShifted = false;
|
||||
|
||||
for (const character of input) {
|
||||
const letter = character.toUpperCase();
|
||||
|
||||
// Convert input text to ITA2 (including figure/letter shifts)
|
||||
if (intype === "ITA2" || mode === "Receive") {
|
||||
if (validITA2.indexOf(letter) === -1) {
|
||||
let errltr = letter;
|
||||
if (errltr==="\n") errltr = "Carriage Return";
|
||||
if (errltr===" ") errltr = "Space";
|
||||
throw new OperationError("Invalid ITA2 character : "+errltr);
|
||||
}
|
||||
result += letter;
|
||||
} else {
|
||||
if (validChars.indexOf(letter) === -1) throw new OperationError("Invalid Plaintext character : "+letter);
|
||||
|
||||
if (!figShifted && figShiftedChars.indexOf(letter) !== -1) {
|
||||
// in letters mode and next char needs to be figure shifted
|
||||
figShifted = true;
|
||||
result += "55" + figShiftArr[letter];
|
||||
} else if (figShifted) {
|
||||
// in figures mode and next char needs to be letter shifted
|
||||
if (letter==="\n") {
|
||||
result += "34";
|
||||
} else if (letter==="\r") {
|
||||
result += "4";
|
||||
} else if (figShiftedChars.indexOf(letter) === -1) {
|
||||
figShifted = false;
|
||||
result += "88" + letter;
|
||||
} else {
|
||||
result += figShiftArr[letter];
|
||||
}
|
||||
|
||||
} else {
|
||||
if (letter==="\n") {
|
||||
result += "34";
|
||||
} else if (letter==="\r") {
|
||||
result += "4";
|
||||
} else {
|
||||
result += letter;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert final result ITA2 to plaintext
|
||||
*/
|
||||
convertFromITA2(input, outtype, mode) {
|
||||
let result = "";
|
||||
let figShifted = false;
|
||||
for (const letter of input) {
|
||||
if (mode === "Receive") {
|
||||
|
||||
// Convert output ITA2 to plaintext (including figure/letter shifts)
|
||||
if (outtype === "Plaintext") {
|
||||
|
||||
if (letter === "5" || letter === "+") {
|
||||
figShifted = true;
|
||||
} else if (letter === "8" || letter === "-") {
|
||||
figShifted = false;
|
||||
} else if (letter === "9") {
|
||||
result += " ";
|
||||
} else if (letter === "3") {
|
||||
result += "\n";
|
||||
} else if (letter === "4") {
|
||||
result += "";
|
||||
} else if (letter === "/") {
|
||||
result += "/";
|
||||
} else {
|
||||
|
||||
if (figShifted) {
|
||||
result += this.REVERSE_FIGSHIFT_TABLE[letter];
|
||||
} else {
|
||||
result += letter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
result += letter;
|
||||
}
|
||||
|
||||
} else {
|
||||
result += letter;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const ITA2_TABLE = {
|
||||
"A": "11000",
|
||||
"B": "10011",
|
||||
"C": "01110",
|
||||
"D": "10010",
|
||||
"E": "10000",
|
||||
"F": "10110",
|
||||
"G": "01011",
|
||||
"H": "00101",
|
||||
"I": "01100",
|
||||
"J": "11010",
|
||||
"K": "11110",
|
||||
"L": "01001",
|
||||
"M": "00111",
|
||||
"N": "00110",
|
||||
"O": "00011",
|
||||
"P": "01101",
|
||||
"Q": "11101",
|
||||
"R": "01010",
|
||||
"S": "10100",
|
||||
"T": "00001",
|
||||
"U": "11100",
|
||||
"V": "01111",
|
||||
"W": "11001",
|
||||
"X": "10111",
|
||||
"Y": "10101",
|
||||
"Z": "10001",
|
||||
"3": "00010",
|
||||
"4": "01000",
|
||||
"9": "00100",
|
||||
"/": "00000",
|
||||
" ": "00100",
|
||||
".": "00100",
|
||||
"8": "11111",
|
||||
"5": "11011",
|
||||
"-": "11111",
|
||||
"+": "11011"
|
||||
};
|
||||
|
||||
const validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+-'()/:=?,. \n\r";
|
||||
const validITA2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ34589+-./";
|
||||
const figShiftedChars = "1234567890+-'()/:=?,.";
|
||||
|
||||
const figShiftArr = {
|
||||
"1": "Q",
|
||||
"2": "W",
|
||||
"3": "E",
|
||||
"4": "R",
|
||||
"5": "T",
|
||||
"6": "Y",
|
||||
"7": "U",
|
||||
"8": "I",
|
||||
"9": "O",
|
||||
"0": "P",
|
||||
" ": "9",
|
||||
"-": "A",
|
||||
"?": "B",
|
||||
":": "C",
|
||||
"#": "D",
|
||||
"%": "F",
|
||||
"@": "G",
|
||||
"£": "H",
|
||||
"": "J",
|
||||
"(": "K",
|
||||
")": "L",
|
||||
".": "M",
|
||||
",": "N",
|
||||
"'": "S",
|
||||
"=": "V",
|
||||
"/": "X",
|
||||
"+": "Z",
|
||||
"\n": "3",
|
||||
"\r": "4"
|
||||
};
|
||||
|
||||
const INIT_PATTERNS = {
|
||||
"No Pattern": {
|
||||
"X": {
|
||||
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
},
|
||||
"S": {
|
||||
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
}
|
||||
|
||||
},
|
||||
"KH Pattern": {
|
||||
"X": {
|
||||
1: [0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
|
||||
2: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0],
|
||||
3: [0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0],
|
||||
4: [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||
5: [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0]
|
||||
},
|
||||
"S": {
|
||||
1: [0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1],
|
||||
2: [0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
|
||||
3: [0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
|
||||
4: [0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
|
||||
5: [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||
2: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
|
||||
}
|
||||
},
|
||||
"ZMUG Pattern": {
|
||||
"X": {
|
||||
1: [0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
|
||||
2: [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0],
|
||||
3: [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0],
|
||||
4: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1],
|
||||
5: [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1]
|
||||
},
|
||||
"S": {
|
||||
1: [1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||
2: [0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1],
|
||||
3: [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1],
|
||||
4: [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1],
|
||||
5: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
|
||||
2: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"BREAM Pattern": {
|
||||
"X": {
|
||||
1: [0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||
2: [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
|
||||
3: [1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0],
|
||||
4: [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0],
|
||||
5: [0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0]
|
||||
},
|
||||
"S": {
|
||||
1: [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
|
||||
2: [1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
|
||||
3: [1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||
4: [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1],
|
||||
5: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
|
||||
},
|
||||
"M": {
|
||||
1: [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1],
|
||||
2: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default Lorenz;
|
77
src/core/operations/LuhnChecksum.mjs
Normal file
77
src/core/operations/LuhnChecksum.mjs
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Luhn Checksum operation
|
||||
*/
|
||||
class LuhnChecksum extends Operation {
|
||||
|
||||
/**
|
||||
* LuhnChecksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Luhn Checksum";
|
||||
this.module = "Default";
|
||||
this.description = "The Luhn algorithm, also known as the modulus 10 or mod 10 algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers and Canadian Social Insurance Numbers.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Luhn_algorithm";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Luhn Checksum from the input.
|
||||
*
|
||||
* @param {string} inputStr
|
||||
* @returns {number}
|
||||
*/
|
||||
checksum(inputStr) {
|
||||
let even = false;
|
||||
return inputStr.split("").reverse().reduce((acc, elem) => {
|
||||
// Convert element to integer.
|
||||
let temp = parseInt(elem, 10);
|
||||
|
||||
// If element is not an integer.
|
||||
if (isNaN(temp))
|
||||
throw new OperationError("Character: " + elem + " is not a digit.");
|
||||
|
||||
// If element is in an even position
|
||||
if (even) {
|
||||
// Double the element and add the quotient and remainder together.
|
||||
temp = 2 * elem;
|
||||
temp = Math.floor(temp/10) + (temp % 10);
|
||||
}
|
||||
|
||||
even = !even;
|
||||
return acc + temp;
|
||||
}, 0) % 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input) return "";
|
||||
|
||||
const checkSum = this.checksum(input);
|
||||
let checkDigit = this.checksum(input + "0");
|
||||
checkDigit = checkDigit === 0 ? 0 : (10-checkDigit);
|
||||
|
||||
return `Checksum: ${checkSum}
|
||||
Checkdigit: ${checkDigit}
|
||||
Luhn Validated String: ${input + "" + checkDigit}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default LuhnChecksum;
|
@ -54,7 +54,7 @@ class MultipleBombe extends Operation {
|
||||
super();
|
||||
|
||||
this.name = "Multiple Bombe";
|
||||
this.module = "Default";
|
||||
this.module = "Bletchley";
|
||||
this.description = "Emulation of the Bombe machine used to attack Enigma. This version carries out multiple Bombe runs to handle unknown rotor configurations.<br><br>You should test your menu on the single Bombe operation before running it here. See the description of the Bombe operation for instructions on choosing a crib.<br><br>More detailed descriptions of the Enigma, Typex and Bombe operations <a href='https://github.com/gchq/CyberChef/wiki/Enigma,-the-Bombe,-and-Typex'>can be found here</a>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bombe";
|
||||
this.inputType = "string";
|
||||
@ -144,7 +144,7 @@ class MultipleBombe extends Operation {
|
||||
* @param {number} progress - Progress (as a float in the range 0..1)
|
||||
*/
|
||||
updateStatus(nLoops, nStops, progress, start) {
|
||||
const elapsed = new Date().getTime() - start;
|
||||
const elapsed = Date.now() - start;
|
||||
const remaining = (elapsed / progress) * (1 - progress) / 1000;
|
||||
const hours = Math.floor(remaining / 3600);
|
||||
const minutes = `0${Math.floor((remaining % 3600) / 60)}`.slice(-2);
|
||||
@ -237,7 +237,7 @@ class MultipleBombe extends Operation {
|
||||
const totalRuns = choose(rotors.length, 3) * 6 * fourthRotors.length * reflectors.length;
|
||||
let nRuns = 0;
|
||||
let nStops = 0;
|
||||
const start = new Date().getTime();
|
||||
const start = Date.now();
|
||||
for (const rotor1 of rotors) {
|
||||
for (const rotor2 of rotors) {
|
||||
if (rotor2 === rotor1) {
|
||||
|
62
src/core/operations/NormaliseUnicode.mjs
Normal file
62
src/core/operations/NormaliseUnicode.mjs
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @author Matthieu [m@tthieu.xyz]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import {UNICODE_NORMALISATION_FORMS} from "../lib/ChrEnc.mjs";
|
||||
import unorm from "unorm";
|
||||
|
||||
/**
|
||||
* Normalise Unicode operation
|
||||
*/
|
||||
class NormaliseUnicode extends Operation {
|
||||
|
||||
/**
|
||||
* NormaliseUnicode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Normalise Unicode";
|
||||
this.module = "Encodings";
|
||||
this.description = "Transform Unicode characters to one of the Normalisation Forms";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Unicode_equivalence#Normal_forms";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Normal Form",
|
||||
type: "option",
|
||||
value: UNICODE_NORMALISATION_FORMS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [normalForm] = args;
|
||||
|
||||
switch (normalForm) {
|
||||
case "NFD":
|
||||
return unorm.nfd(input);
|
||||
case "NFC":
|
||||
return unorm.nfc(input);
|
||||
case "NFKD":
|
||||
return unorm.nfkd(input);
|
||||
case "NFKC":
|
||||
return unorm.nfc(input);
|
||||
default:
|
||||
throw new OperationError("Unknown Normalisation Form");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default NormaliseUnicode;
|
@ -128,8 +128,7 @@ class PHPDeserialize extends Operation {
|
||||
switch (kind) {
|
||||
case "n":
|
||||
expect(";");
|
||||
return "";
|
||||
|
||||
return "null";
|
||||
case "i":
|
||||
case "d":
|
||||
case "b": {
|
||||
|
47
src/core/operations/ParseObjectIDTimestamp.mjs
Normal file
47
src/core/operations/ParseObjectIDTimestamp.mjs
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @author dmfj [dominic@dmfj.io]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import BSON from "bson";
|
||||
|
||||
/**
|
||||
* Parse ObjectID timestamp operation
|
||||
*/
|
||||
class ParseObjectIDTimestamp extends Operation {
|
||||
|
||||
/**
|
||||
* ParseObjectIDTimestamp constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Parse ObjectID timestamp";
|
||||
this.module = "Serialise";
|
||||
this.description = "Parse timestamp from MongoDB/BSON ObjectID hex string.";
|
||||
this.infoURL = "https://docs.mongodb.com/manual/reference/method/ObjectId.getTimestamp/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
try {
|
||||
const objectId = new BSON.ObjectID(input);
|
||||
return objectId.getTimestamp().toISOString();
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ParseObjectIDTimestamp;
|
@ -33,9 +33,9 @@ class ParseQRCode extends Operation {
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
this.checks = [
|
||||
{
|
||||
"match": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)",
|
||||
"pattern": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)",
|
||||
"flags": "",
|
||||
"args": [false],
|
||||
"useful": true
|
||||
|
@ -4,11 +4,11 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
import { fromBase64 } from "../lib/Base64";
|
||||
import { fromHex, toHexFast } from "../lib/Hex";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { fromBase64 } from "../lib/Base64.mjs";
|
||||
import { fromHex, toHexFast } from "../lib/Hex.mjs";
|
||||
|
||||
/**
|
||||
* Parse SSH Host Key operation
|
||||
@ -38,6 +38,13 @@ class ParseSSHHostKey extends Operation {
|
||||
]
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^\\s*([A-F\\d]{2}[,;:]){15,}[A-F\\d]{2}\\s*$",
|
||||
flags: "i",
|
||||
args: ["Hex"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,6 +25,13 @@ class ParseUNIXFilePermissions extends Operation {
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^\\s*d[rxw-]{9}\\s*$",
|
||||
flags: "",
|
||||
args: []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user