mirror of
https://github.com/gchq/CyberChef
synced 2025-01-26 03:05:06 +00:00
Merge branch 'gchq:master' into word_count
This commit is contained in:
commit
5a58e7f821
92 changed files with 7293 additions and 2524 deletions
|
@ -1 +0,0 @@
|
||||||
src/core/vendor/**
|
|
116
.eslintrc.json
116
.eslintrc.json
|
@ -1,116 +0,0 @@
|
||||||
{
|
|
||||||
"parser": "@babel/eslint-parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2022,
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"impliedStrict": true
|
|
||||||
},
|
|
||||||
"sourceType": "module",
|
|
||||||
"allowImportExportEverywhere": true
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es6": true,
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"extends": "eslint:recommended",
|
|
||||||
"rules": {
|
|
||||||
// enable additional rules
|
|
||||||
"no-eval": "error",
|
|
||||||
"no-implied-eval": "error",
|
|
||||||
"dot-notation": "error",
|
|
||||||
"eqeqeq": ["error", "smart"],
|
|
||||||
"no-caller": "error",
|
|
||||||
"no-extra-bind": "error",
|
|
||||||
"no-unused-expressions": "error",
|
|
||||||
"no-useless-call": "error",
|
|
||||||
"no-useless-return": "error",
|
|
||||||
"radix": "warn",
|
|
||||||
|
|
||||||
// modify rules from base configurations
|
|
||||||
"no-unused-vars": ["error", {
|
|
||||||
"args": "none",
|
|
||||||
"vars": "all"
|
|
||||||
}],
|
|
||||||
"no-empty": ["error", {
|
|
||||||
"allowEmptyCatch": true
|
|
||||||
}],
|
|
||||||
|
|
||||||
// disable rules from base configurations
|
|
||||||
"no-control-regex": "off",
|
|
||||||
"require-atomic-updates": "off",
|
|
||||||
"no-async-promise-executor": "off",
|
|
||||||
|
|
||||||
// stylistic conventions
|
|
||||||
"brace-style": ["error", "1tbs"],
|
|
||||||
"space-before-blocks": ["error", "always"],
|
|
||||||
"block-spacing": "error",
|
|
||||||
"array-bracket-spacing": "error",
|
|
||||||
"comma-spacing": "error",
|
|
||||||
"spaced-comment": ["error", "always", { "exceptions": ["/"] } ],
|
|
||||||
"comma-style": "error",
|
|
||||||
"computed-property-spacing": "error",
|
|
||||||
"no-trailing-spaces": "warn",
|
|
||||||
"eol-last": "error",
|
|
||||||
"func-call-spacing": "error",
|
|
||||||
"key-spacing": ["warn", {
|
|
||||||
"mode": "minimum"
|
|
||||||
}],
|
|
||||||
"indent": ["error", 4, {
|
|
||||||
"ignoreComments": true,
|
|
||||||
"ArrayExpression": "first",
|
|
||||||
"SwitchCase": 1
|
|
||||||
}],
|
|
||||||
"linebreak-style": ["error", "unix"],
|
|
||||||
"quotes": ["error", "double", {
|
|
||||||
"avoidEscape": true,
|
|
||||||
"allowTemplateLiterals": true
|
|
||||||
}],
|
|
||||||
"camelcase": ["error", {
|
|
||||||
"properties": "always"
|
|
||||||
}],
|
|
||||||
"semi": ["error", "always"],
|
|
||||||
"unicode-bom": "error",
|
|
||||||
"require-jsdoc": ["error", {
|
|
||||||
"require": {
|
|
||||||
"FunctionDeclaration": true,
|
|
||||||
"MethodDefinition": true,
|
|
||||||
"ClassDeclaration": true,
|
|
||||||
"ArrowFunctionExpression": true
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"keyword-spacing": ["error", {
|
|
||||||
"before": true,
|
|
||||||
"after": true
|
|
||||||
}],
|
|
||||||
"no-multiple-empty-lines": ["warn", {
|
|
||||||
"max": 2,
|
|
||||||
"maxEOF": 1,
|
|
||||||
"maxBOF": 0
|
|
||||||
}],
|
|
||||||
"no-whitespace-before-property": "error",
|
|
||||||
"operator-linebreak": ["error", "after"],
|
|
||||||
"space-in-parens": "error",
|
|
||||||
"no-var": "error",
|
|
||||||
"prefer-const": "error"
|
|
||||||
},
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": "tests/**/*",
|
|
||||||
"rules": {
|
|
||||||
"no-unused-expressions": "off",
|
|
||||||
"no-console": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"globals": {
|
|
||||||
"$": false,
|
|
||||||
"jQuery": false,
|
|
||||||
"log": false,
|
|
||||||
"app": false,
|
|
||||||
|
|
||||||
"COMPILE_TIME": false,
|
|
||||||
"COMPILE_MSG": false,
|
|
||||||
"PKG_VERSION": false
|
|
||||||
}
|
|
||||||
}
|
|
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -13,6 +13,28 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
|
### [10.19.0] - 2024-06-21
|
||||||
|
- Add support for ECDSA and DSA in 'Parse CSR' [@robinsandhu] | [#1828]
|
||||||
|
- Fix typos in SIGABA.mjs [@eltociear] | [#1834]
|
||||||
|
|
||||||
|
### [10.18.0] - 2024-04-24
|
||||||
|
- Added 'XXTEA Encrypt' and 'XXTEA Decrypt' operations [@n1474335] | [0a353ee]
|
||||||
|
|
||||||
|
### [10.17.0] - 2024-04-13
|
||||||
|
- Fix unit test 'expectOutput' implementation [@zb3] | [#1783]
|
||||||
|
- Add accessibility labels for icons [@e218736] | [#1743]
|
||||||
|
- Add focus styling for keyboard navigation [@e218736] | [#1739]
|
||||||
|
- Add support for operation option hiding [@TheZ3ro] | [#541]
|
||||||
|
- Improve efficiency of RAKE implementation [@sw5678] | [#1751]
|
||||||
|
- Require (a, 26) to be coprime in 'Affine Encode' [@EvieHarv] | [#1788]
|
||||||
|
- Added 'JWK to PEM' operation [@cplussharp] | [#1277]
|
||||||
|
- Added 'PEM to JWK' operation [@cplussharp] | [#1277]
|
||||||
|
- Added 'Public Key from Certificate' operation [@cplussharp] | [#1642]
|
||||||
|
- Added 'Public Key from Private Key' operation [@cplussharp] | [#1642]
|
||||||
|
|
||||||
|
### [10.16.0] - 2024-04-12
|
||||||
|
- Added 'JA4Server Fingerprint' operation [@n1474335] | [#1789]
|
||||||
|
|
||||||
### [10.15.0] - 2024-04-02
|
### [10.15.0] - 2024-04-02
|
||||||
- Fix Ciphersaber2 key concatenation [@zb3] | [#1765]
|
- Fix Ciphersaber2 key concatenation [@zb3] | [#1765]
|
||||||
- Fix DeriveEVPKey's array parsing [@zb3] | [#1767]
|
- Fix DeriveEVPKey's array parsing [@zb3] | [#1767]
|
||||||
|
@ -418,6 +440,10 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
## [4.0.0] - 2016-11-28
|
## [4.0.0] - 2016-11-28
|
||||||
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
||||||
|
|
||||||
|
[10.19.0]: https://github.com/gchq/CyberChef/releases/tag/v10.19.0
|
||||||
|
[10.18.0]: https://github.com/gchq/CyberChef/releases/tag/v10.18.0
|
||||||
|
[10.17.0]: https://github.com/gchq/CyberChef/releases/tag/v10.17.0
|
||||||
|
[10.16.0]: https://github.com/gchq/CyberChef/releases/tag/v10.16.0
|
||||||
[10.15.0]: https://github.com/gchq/CyberChef/releases/tag/v10.15.0
|
[10.15.0]: https://github.com/gchq/CyberChef/releases/tag/v10.15.0
|
||||||
[10.14.0]: https://github.com/gchq/CyberChef/releases/tag/v10.14.0
|
[10.14.0]: https://github.com/gchq/CyberChef/releases/tag/v10.14.0
|
||||||
[10.13.0]: https://github.com/gchq/CyberChef/releases/tag/v10.13.0
|
[10.13.0]: https://github.com/gchq/CyberChef/releases/tag/v10.13.0
|
||||||
|
@ -598,6 +624,12 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
[@zb3]: https://github.com/zb3
|
[@zb3]: https://github.com/zb3
|
||||||
[@jkataja]: https://github.com/jkataja
|
[@jkataja]: https://github.com/jkataja
|
||||||
[@tomgond]: https://github.com/tomgond
|
[@tomgond]: https://github.com/tomgond
|
||||||
|
[@e218736]: https://github.com/e218736
|
||||||
|
[@TheZ3ro]: https://github.com/TheZ3ro
|
||||||
|
[@EvieHarv]: https://github.com/EvieHarv
|
||||||
|
[@cplussharp]: https://github.com/cplussharp
|
||||||
|
[@robinsandhu]: https://github.com/robinsandhu
|
||||||
|
[@eltociear]: https://github.com/eltociear
|
||||||
|
|
||||||
|
|
||||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||||
|
@ -609,6 +641,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
[31a7f83]: https://github.com/gchq/CyberChef/commit/31a7f83b82e78927f89689f323fcb9185144d6ff
|
[31a7f83]: https://github.com/gchq/CyberChef/commit/31a7f83b82e78927f89689f323fcb9185144d6ff
|
||||||
[760eff4]: https://github.com/gchq/CyberChef/commit/760eff49b5307aaa3104c5e5b437ffe62299acd1
|
[760eff4]: https://github.com/gchq/CyberChef/commit/760eff49b5307aaa3104c5e5b437ffe62299acd1
|
||||||
[65ffd8d]: https://github.com/gchq/CyberChef/commit/65ffd8d65d88eb369f6f61a5d1d0f807179bffb7
|
[65ffd8d]: https://github.com/gchq/CyberChef/commit/65ffd8d65d88eb369f6f61a5d1d0f807179bffb7
|
||||||
|
[0a353ee]: https://github.com/gchq/CyberChef/commit/0a353eeb378b9ca5d49e23c7dfc175ae07107b08
|
||||||
|
|
||||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||||
|
@ -744,3 +777,5 @@ All major and minor version changes will be documented in this file. Details of
|
||||||
[#1504]: https://github.com/gchq/CyberChef/issues/1504
|
[#1504]: https://github.com/gchq/CyberChef/issues/1504
|
||||||
[#512]: https://github.com/gchq/CyberChef/issues/512
|
[#512]: https://github.com/gchq/CyberChef/issues/512
|
||||||
[#1732]: https://github.com/gchq/CyberChef/issues/1732
|
[#1732]: https://github.com/gchq/CyberChef/issues/1732
|
||||||
|
[#1789]: https://github.com/gchq/CyberChef/issues/1789
|
||||||
|
|
||||||
|
|
12
Gruntfile.js
12
Gruntfile.js
|
@ -431,6 +431,18 @@ module.exports = function (grunt) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
stdout: false
|
stdout: false
|
||||||
|
},
|
||||||
|
fixJimpModule: {
|
||||||
|
command: function () {
|
||||||
|
switch (process.platform) {
|
||||||
|
case "darwin":
|
||||||
|
// Space added before comma to prevent multiple modifications
|
||||||
|
return `sed -i '' 's/"es\\/index.js",/"es\\/index.js" ,\\n "type": "module",/' ./node_modules/jimp/package.json`;
|
||||||
|
default:
|
||||||
|
return `sed -i 's/"es\\/index.js",/"es\\/index.js" ,\\n "type": "module",/' ./node_modules/jimp/package.json`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stdout: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
129
eslint.config.mjs
Executable file
129
eslint.config.mjs
Executable file
|
@ -0,0 +1,129 @@
|
||||||
|
import babelParser from "@babel/eslint-parser";
|
||||||
|
import jsdoc from "eslint-plugin-jsdoc";
|
||||||
|
import js from "@eslint/js";
|
||||||
|
import globals from "globals";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
js.configs.recommended,
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2022,
|
||||||
|
parser: babelParser,
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2022,
|
||||||
|
ecmaFeatures: {
|
||||||
|
impliedStrict: true
|
||||||
|
},
|
||||||
|
sourceType: "module",
|
||||||
|
allowImportExportEverywhere: true
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
...globals.node,
|
||||||
|
...globals.es6,
|
||||||
|
"$": false,
|
||||||
|
"jQuery": false,
|
||||||
|
"log": false,
|
||||||
|
"app": false,
|
||||||
|
|
||||||
|
"COMPILE_TIME": false,
|
||||||
|
"COMPILE_MSG": false,
|
||||||
|
"PKG_VERSION": false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ignores: ["src/core/vendor/**"],
|
||||||
|
plugins: {
|
||||||
|
jsdoc
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// enable additional rules
|
||||||
|
"no-eval": "error",
|
||||||
|
"no-implied-eval": "error",
|
||||||
|
"dot-notation": "error",
|
||||||
|
"eqeqeq": ["error", "smart"],
|
||||||
|
"no-caller": "error",
|
||||||
|
"no-extra-bind": "error",
|
||||||
|
"no-unused-expressions": "error",
|
||||||
|
"no-useless-call": "error",
|
||||||
|
"no-useless-return": "error",
|
||||||
|
"radix": "warn",
|
||||||
|
|
||||||
|
// modify rules from base configurations
|
||||||
|
"no-unused-vars": ["error", {
|
||||||
|
"args": "none",
|
||||||
|
"vars": "all",
|
||||||
|
"caughtErrors": "none"
|
||||||
|
}],
|
||||||
|
"no-empty": ["error", {
|
||||||
|
"allowEmptyCatch": true
|
||||||
|
}],
|
||||||
|
|
||||||
|
// disable rules from base configurations
|
||||||
|
"no-control-regex": "off",
|
||||||
|
"require-atomic-updates": "off",
|
||||||
|
"no-async-promise-executor": "off",
|
||||||
|
|
||||||
|
// stylistic conventions
|
||||||
|
"brace-style": ["error", "1tbs"],
|
||||||
|
"space-before-blocks": ["error", "always"],
|
||||||
|
"block-spacing": "error",
|
||||||
|
"array-bracket-spacing": "error",
|
||||||
|
"comma-spacing": "error",
|
||||||
|
"spaced-comment": ["error", "always", { "exceptions": ["/"] }],
|
||||||
|
"comma-style": "error",
|
||||||
|
"computed-property-spacing": "error",
|
||||||
|
"no-trailing-spaces": "warn",
|
||||||
|
"eol-last": "error",
|
||||||
|
"func-call-spacing": "error",
|
||||||
|
"key-spacing": ["warn", {
|
||||||
|
"mode": "minimum"
|
||||||
|
}],
|
||||||
|
"indent": ["error", 4, {
|
||||||
|
"ignoreComments": true,
|
||||||
|
"ArrayExpression": "first",
|
||||||
|
"SwitchCase": 1
|
||||||
|
}],
|
||||||
|
"linebreak-style": ["error", "unix"],
|
||||||
|
"quotes": ["error", "double", {
|
||||||
|
"avoidEscape": true,
|
||||||
|
"allowTemplateLiterals": true
|
||||||
|
}],
|
||||||
|
"camelcase": ["error", {
|
||||||
|
"properties": "always"
|
||||||
|
}],
|
||||||
|
"semi": ["error", "always"],
|
||||||
|
"unicode-bom": "error",
|
||||||
|
"jsdoc/require-jsdoc": ["error", {
|
||||||
|
"require": {
|
||||||
|
"FunctionDeclaration": true,
|
||||||
|
"MethodDefinition": true,
|
||||||
|
"ClassDeclaration": true,
|
||||||
|
"ArrowFunctionExpression": false
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"keyword-spacing": ["error", {
|
||||||
|
"before": true,
|
||||||
|
"after": true
|
||||||
|
}],
|
||||||
|
"no-multiple-empty-lines": ["warn", {
|
||||||
|
"max": 2,
|
||||||
|
"maxEOF": 1,
|
||||||
|
"maxBOF": 0
|
||||||
|
}],
|
||||||
|
"no-whitespace-before-property": "error",
|
||||||
|
"operator-linebreak": ["error", "after"],
|
||||||
|
"space-in-parens": "error",
|
||||||
|
"no-var": "error",
|
||||||
|
"prefer-const": "error",
|
||||||
|
"no-console": "error"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// File-pattern specific overrides
|
||||||
|
{
|
||||||
|
files: ["tests/**/*"],
|
||||||
|
rules: {
|
||||||
|
"no-unused-expressions": "off",
|
||||||
|
"no-console": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
4224
package-lock.json
generated
4224
package-lock.json
generated
File diff suppressed because it is too large
Load diff
88
package.json
88
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "10.15.1",
|
"version": "10.19.0",
|
||||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||||
"author": "n1474335 <n1474335@gmail.com>",
|
"author": "n1474335 <n1474335@gmail.com>",
|
||||||
"homepage": "https://gchq.github.io/CyberChef",
|
"homepage": "https://gchq.github.io/CyberChef",
|
||||||
|
@ -39,29 +39,31 @@
|
||||||
"node >= 16"
|
"node >= 16"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.23.9",
|
"@babel/core": "^7.24.7",
|
||||||
"@babel/eslint-parser": "^7.23.10",
|
"@babel/eslint-parser": "^7.24.7",
|
||||||
"@babel/plugin-syntax-import-assertions": "^7.23.3",
|
"@babel/plugin-syntax-import-assertions": "^7.24.7",
|
||||||
"@babel/plugin-transform-runtime": "^7.23.9",
|
"@babel/plugin-transform-runtime": "^7.24.7",
|
||||||
"@babel/preset-env": "^7.23.9",
|
"@babel/preset-env": "^7.24.7",
|
||||||
"@babel/runtime": "^7.23.9",
|
"@babel/runtime": "^7.24.7",
|
||||||
"@codemirror/commands": "^6.3.3",
|
"@codemirror/commands": "^6.6.0",
|
||||||
"@codemirror/language": "^6.10.1",
|
"@codemirror/language": "^6.10.2",
|
||||||
"@codemirror/search": "^6.5.5",
|
"@codemirror/search": "^6.5.6",
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.1",
|
||||||
"@codemirror/view": "^6.23.1",
|
"@codemirror/view": "^6.28.0",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.19",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||||
"base64-loader": "^1.0.0",
|
"base64-loader": "^1.0.0",
|
||||||
"chromedriver": "^122.0.0",
|
"chromedriver": "^125.0.3",
|
||||||
"cli-progress": "^3.12.0",
|
"cli-progress": "^3.12.0",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"copy-webpack-plugin": "^12.0.2",
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
"core-js": "^3.35.1",
|
"core-js": "^3.37.1",
|
||||||
"css-loader": "6.10.0",
|
"css-loader": "7.1.2",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^9.4.0",
|
||||||
|
"eslint-plugin-jsdoc": "^48.2.9",
|
||||||
|
"globals": "^15.4.0",
|
||||||
"grunt": "^1.6.1",
|
"grunt": "^1.6.1",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
"grunt-concurrent": "^3.0.0",
|
"grunt-concurrent": "^3.0.0",
|
||||||
|
@ -69,25 +71,25 @@
|
||||||
"grunt-contrib-connect": "^4.0.0",
|
"grunt-contrib-connect": "^4.0.0",
|
||||||
"grunt-contrib-copy": "~1.0.0",
|
"grunt-contrib-copy": "~1.0.0",
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
"grunt-eslint": "^24.3.0",
|
"grunt-eslint": "^25.0.0",
|
||||||
"grunt-exec": "~3.0.0",
|
"grunt-exec": "~3.0.0",
|
||||||
"grunt-webpack": "^6.0.0",
|
"grunt-webpack": "^6.0.0",
|
||||||
"grunt-zip": "^1.0.0",
|
"grunt-zip": "^1.0.0",
|
||||||
"html-webpack-plugin": "^5.6.0",
|
"html-webpack-plugin": "^5.6.0",
|
||||||
"imports-loader": "^5.0.0",
|
"imports-loader": "^5.0.0",
|
||||||
"mini-css-extract-plugin": "2.8.0",
|
"mini-css-extract-plugin": "2.9.0",
|
||||||
"modify-source-webpack-plugin": "^3.0.0",
|
"modify-source-webpack-plugin": "^4.1.0",
|
||||||
"nightwatch": "^3.4.0",
|
"nightwatch": "^3.6.3",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.4.38",
|
||||||
"postcss-css-variables": "^0.19.0",
|
"postcss-css-variables": "^0.19.0",
|
||||||
"postcss-import": "^16.0.0",
|
"postcss-import": "^16.1.0",
|
||||||
"postcss-loader": "^8.1.0",
|
"postcss-loader": "^8.1.1",
|
||||||
"prompt": "^1.3.0",
|
"prompt": "^1.3.0",
|
||||||
"sitemap": "^7.1.1",
|
"sitemap": "^8.0.0",
|
||||||
"terser": "^5.27.0",
|
"terser": "^5.31.1",
|
||||||
"webpack": "^5.90.1",
|
"webpack": "^5.91.0",
|
||||||
"webpack-bundle-analyzer": "^4.10.1",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
"webpack-dev-server": "4.15.1",
|
"webpack-dev-server": "5.0.4",
|
||||||
"webpack-node-externals": "^3.0.0",
|
"webpack-node-externals": "^3.0.0",
|
||||||
"worker-loader": "^3.0.8"
|
"worker-loader": "^3.0.8"
|
||||||
},
|
},
|
||||||
|
@ -96,6 +98,7 @@
|
||||||
"@babel/polyfill": "^7.12.1",
|
"@babel/polyfill": "^7.12.1",
|
||||||
"@blu3r4y/lzma": "^2.3.3",
|
"@blu3r4y/lzma": "^2.3.3",
|
||||||
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
||||||
|
"@xmldom/xmldom": "^0.8.10",
|
||||||
"argon2-browser": "^1.18.0",
|
"argon2-browser": "^1.18.0",
|
||||||
"arrive": "^2.4.1",
|
"arrive": "^2.4.1",
|
||||||
"avsc": "^5.7.7",
|
"avsc": "^5.7.7",
|
||||||
|
@ -115,26 +118,26 @@
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"ctph.js": "0.0.5",
|
"ctph.js": "0.0.5",
|
||||||
"d3": "7.8.5",
|
"d3": "7.9.0",
|
||||||
"d3-hexbin": "^0.2.2",
|
"d3-hexbin": "^0.2.2",
|
||||||
"diff": "^5.1.0",
|
"diff": "^5.2.0",
|
||||||
"es6-promisify": "^7.0.0",
|
"es6-promisify": "^7.0.0",
|
||||||
"escodegen": "^2.1.0",
|
"escodegen": "^2.1.0",
|
||||||
"esprima": "^4.0.1",
|
"esprima": "^4.0.1",
|
||||||
"exif-parser": "^0.1.12",
|
"exif-parser": "^0.1.12",
|
||||||
"ieee754": "^1.1.13",
|
"fernet": "^0.4.0",
|
||||||
"fernet": "^0.3.2",
|
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"flat": "^6.0.1",
|
"flat": "^6.0.1",
|
||||||
"geodesy": "1.1.3",
|
"geodesy": "1.1.3",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
"jimp": "^0.16.13",
|
"ieee754": "^1.2.1",
|
||||||
|
"jimp": "^0.22.12",
|
||||||
"jquery": "3.7.1",
|
"jquery": "3.7.1",
|
||||||
"js-crc": "^0.2.0",
|
"js-crc": "^0.2.0",
|
||||||
"js-sha3": "^0.9.3",
|
"js-sha3": "^0.9.3",
|
||||||
"jsesc": "^3.0.2",
|
"jsesc": "^3.0.2",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"jsonpath-plus": "^8.0.0",
|
"jsonpath-plus": "^9.0.0",
|
||||||
"jsonwebtoken": "8.5.1",
|
"jsonwebtoken": "8.5.1",
|
||||||
"jsqr": "^1.4.0",
|
"jsqr": "^1.4.0",
|
||||||
"jsrsasign": "^11.1.0",
|
"jsrsasign": "^11.1.0",
|
||||||
|
@ -146,9 +149,9 @@
|
||||||
"loglevel-message-prefix": "^3.0.0",
|
"loglevel-message-prefix": "^3.0.0",
|
||||||
"lz-string": "^1.5.0",
|
"lz-string": "^1.5.0",
|
||||||
"lz4js": "^0.2.0",
|
"lz4js": "^0.2.0",
|
||||||
"markdown-it": "^14.0.0",
|
"markdown-it": "^14.1.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"moment-timezone": "^0.5.44",
|
"moment-timezone": "^0.5.45",
|
||||||
"ngeohash": "^0.6.3",
|
"ngeohash": "^0.6.3",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
"node-md6": "^0.1.0",
|
"node-md6": "^0.1.0",
|
||||||
|
@ -160,9 +163,9 @@
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"protobufjs": "^7.2.6",
|
"protobufjs": "^7.3.1",
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"reflect-metadata": "^0.2.1",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rison": "^0.1.1",
|
"rison": "^0.1.1",
|
||||||
"scryptsy": "^2.1.0",
|
"scryptsy": "^2.1.0",
|
||||||
"snackbarjs": "^1.1.0",
|
"snackbarjs": "^1.1.0",
|
||||||
|
@ -170,12 +173,11 @@
|
||||||
"split.js": "^1.6.5",
|
"split.js": "^1.6.5",
|
||||||
"ssdeep.js": "0.0.3",
|
"ssdeep.js": "0.0.3",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"tesseract.js": "5.0.4",
|
"tesseract.js": "5.1.0",
|
||||||
"ua-parser-js": "^1.0.37",
|
"ua-parser-js": "^1.0.38",
|
||||||
"unorm": "^1.6.0",
|
"unorm": "^1.6.0",
|
||||||
"utf8": "^3.0.0",
|
"utf8": "^3.0.0",
|
||||||
"vkbeautify": "^0.99.3",
|
"vkbeautify": "^0.99.3",
|
||||||
"@xmldom/xmldom": "^0.8.0",
|
|
||||||
"xpath": "0.0.34",
|
"xpath": "0.0.34",
|
||||||
"xregexp": "^5.1.1",
|
"xregexp": "^5.1.1",
|
||||||
"zlibjs": "^0.3.1"
|
"zlibjs": "^0.3.1"
|
||||||
|
@ -190,7 +192,7 @@
|
||||||
"testui": "npx grunt testui",
|
"testui": "npx grunt testui",
|
||||||
"testuidev": "npx nightwatch --env=dev",
|
"testuidev": "npx nightwatch --env=dev",
|
||||||
"lint": "npx grunt lint",
|
"lint": "npx grunt lint",
|
||||||
"postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup",
|
"postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup && npx grunt exec:fixJimpModule",
|
||||||
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
|
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
|
||||||
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",
|
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",
|
||||||
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
|
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
|
||||||
|
|
|
@ -117,6 +117,8 @@
|
||||||
"XOR Brute Force",
|
"XOR Brute Force",
|
||||||
"Vigenère Encode",
|
"Vigenère Encode",
|
||||||
"Vigenère Decode",
|
"Vigenère Decode",
|
||||||
|
"XXTEA Encrypt",
|
||||||
|
"XXTEA Decrypt",
|
||||||
"To Morse Code",
|
"To Morse Code",
|
||||||
"From Morse Code",
|
"From Morse Code",
|
||||||
"Bacon Cipher Encode",
|
"Bacon Cipher Encode",
|
||||||
|
@ -155,8 +157,7 @@
|
||||||
"Typex",
|
"Typex",
|
||||||
"Lorenz",
|
"Lorenz",
|
||||||
"Colossus",
|
"Colossus",
|
||||||
"SIGABA",
|
"SIGABA"
|
||||||
"XXTEA"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -168,6 +169,8 @@
|
||||||
"Hex to PEM",
|
"Hex to PEM",
|
||||||
"Hex to Object Identifier",
|
"Hex to Object Identifier",
|
||||||
"Object Identifier to Hex",
|
"Object Identifier to Hex",
|
||||||
|
"PEM to JWK",
|
||||||
|
"JWK to PEM",
|
||||||
"Generate PGP Key Pair",
|
"Generate PGP Key Pair",
|
||||||
"PGP Encrypt",
|
"PGP Encrypt",
|
||||||
"PGP Decrypt",
|
"PGP Decrypt",
|
||||||
|
@ -179,8 +182,14 @@
|
||||||
"RSA Verify",
|
"RSA Verify",
|
||||||
"RSA Encrypt",
|
"RSA Encrypt",
|
||||||
"RSA Decrypt",
|
"RSA Decrypt",
|
||||||
|
"Generate ECDSA Key Pair",
|
||||||
|
"ECDSA Signature Conversion",
|
||||||
|
"ECDSA Sign",
|
||||||
|
"ECDSA Verify",
|
||||||
"Parse SSH Host Key",
|
"Parse SSH Host Key",
|
||||||
"Parse CSR"
|
"Parse CSR",
|
||||||
|
"Public Key from Certificate",
|
||||||
|
"Public Key from Private Key"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -238,6 +247,7 @@
|
||||||
"JA3 Fingerprint",
|
"JA3 Fingerprint",
|
||||||
"JA3S Fingerprint",
|
"JA3S Fingerprint",
|
||||||
"JA4 Fingerprint",
|
"JA4 Fingerprint",
|
||||||
|
"JA4Server Fingerprint",
|
||||||
"HASSH Client Fingerprint",
|
"HASSH Client Fingerprint",
|
||||||
"HASSH Server Fingerprint",
|
"HASSH Server Fingerprint",
|
||||||
"Format MAC addresses",
|
"Format MAC addresses",
|
||||||
|
|
|
@ -30,12 +30,12 @@ fs.readdirSync(path.join(dir, "../operations")).forEach(file => {
|
||||||
|
|
||||||
// Construct index file
|
// Construct index file
|
||||||
let code = `/**
|
let code = `/**
|
||||||
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
|
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
|
||||||
*
|
*
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
|
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
`;
|
`;
|
||||||
|
|
||||||
opObjs.forEach(obj => {
|
opObjs.forEach(obj => {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
*
|
*
|
||||||
* @author Matt C [matt@artemisbot.uk]
|
* @author Matt C [matt@artemisbot.uk]
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @author Evie H [evie@evie.sh]
|
||||||
*
|
*
|
||||||
* @copyright Crown Copyright 2018
|
* @copyright Crown Copyright 2018
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
|
@ -10,6 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
import CryptoJS from "crypto-js";
|
import CryptoJS from "crypto-js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +32,10 @@ export function affineEncode(input, args) {
|
||||||
throw new OperationError("The values of a and b can only be integers.");
|
throw new OperationError("The values of a and b can only be integers.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Utils.gcd(a, 26) !== 1) {
|
||||||
|
throw new OperationError("The value of `a` must be coprime to 26.");
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < input.length; i++) {
|
for (let i = 0; i < input.length; i++) {
|
||||||
if (alphabet.indexOf(input[i]) >= 0) {
|
if (alphabet.indexOf(input[i]) >= 0) {
|
||||||
// Uses the affine function ax+b % m = y (where m is length of the alphabet)
|
// Uses the affine function ax+b % m = y (where m is length of the alphabet)
|
||||||
|
|
|
@ -25,6 +25,9 @@ export function toJA4(bytes) {
|
||||||
let tlsr = {};
|
let tlsr = {};
|
||||||
try {
|
try {
|
||||||
tlsr = parseTLSRecord(bytes);
|
tlsr = parseTLSRecord(bytes);
|
||||||
|
if (tlsr.handshake.value.handshakeType.value !== 0x01) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError("Data is not a valid TLS Client Hello. QUIC is not yet supported.\n" + err);
|
throw new OperationError("Data is not a valid TLS Client Hello. QUIC is not yet supported.\n" + err);
|
||||||
}
|
}
|
||||||
|
@ -48,16 +51,7 @@ export function toJA4(bytes) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (version) {
|
version = tlsVersionMapper(version);
|
||||||
case 0x0304: version = "13"; break; // TLS 1.3
|
|
||||||
case 0x0303: version = "12"; break; // TLS 1.2
|
|
||||||
case 0x0302: version = "11"; break; // TLS 1.1
|
|
||||||
case 0x0301: version = "10"; break; // TLS 1.0
|
|
||||||
case 0x0300: version = "s3"; break; // SSL 3.0
|
|
||||||
case 0x0200: version = "s2"; break; // SSL 2.0
|
|
||||||
case 0x0100: version = "s1"; break; // SSL 1.0
|
|
||||||
default: version = "00"; // Unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SNI
|
/* SNI
|
||||||
If the SNI extension (0x0000) exists, then the destination of the connection is a domain, or “d” in the fingerprint.
|
If the SNI extension (0x0000) exists, then the destination of the connection is a domain, or “d” in the fingerprint.
|
||||||
|
@ -99,6 +93,7 @@ export function toJA4(bytes) {
|
||||||
if (ext.type.value === "application_layer_protocol_negotiation") {
|
if (ext.type.value === "application_layer_protocol_negotiation") {
|
||||||
alpn = parseFirstALPNValue(ext.value.data);
|
alpn = parseFirstALPNValue(ext.value.data);
|
||||||
alpn = alpn.charAt(0) + alpn.charAt(alpn.length - 1);
|
alpn = alpn.charAt(0) + alpn.charAt(alpn.length - 1);
|
||||||
|
if (alpn.charCodeAt(0) > 127) alpn = "99";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,3 +159,106 @@ export function toJA4(bytes) {
|
||||||
"JA4_ro": `${ptype}${version}${sni}${cipherLen}${extLen}${alpn}_${originalCiphersRaw}_${originalExtensionsRaw}`,
|
"JA4_ro": `${ptype}${version}${sni}${cipherLen}${extLen}${alpn}_${originalCiphersRaw}_${originalExtensionsRaw}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the JA4Server from a given TLS Server Hello Stream
|
||||||
|
* @param {Uint8Array} bytes
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function toJA4S(bytes) {
|
||||||
|
let tlsr = {};
|
||||||
|
try {
|
||||||
|
tlsr = parseTLSRecord(bytes);
|
||||||
|
if (tlsr.handshake.value.handshakeType.value !== 0x02) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError("Data is not a valid TLS Server Hello. QUIC is not yet supported.\n" + err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* QUIC
|
||||||
|
“q” or “t”, which denotes whether the hello packet is for QUIC or TCP.
|
||||||
|
TODO: Implement QUIC
|
||||||
|
*/
|
||||||
|
const ptype = "t";
|
||||||
|
|
||||||
|
/* TLS Version
|
||||||
|
TLS version is shown in 3 different places. If extension 0x002b exists (supported_versions), then the version
|
||||||
|
is the highest value in the extension. Remember to ignore GREASE values. If the extension doesn’t exist, then
|
||||||
|
the TLS version is the value of the Protocol Version. Handshake version (located at the top of the packet)
|
||||||
|
should be ignored.
|
||||||
|
*/
|
||||||
|
let version = tlsr.version.value;
|
||||||
|
for (const ext of tlsr.handshake.value.extensions.value) {
|
||||||
|
if (ext.type.value === "supported_versions") {
|
||||||
|
version = parseHighestSupportedVersion(ext.value.data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
version = tlsVersionMapper(version);
|
||||||
|
|
||||||
|
/* Number of Extensions
|
||||||
|
2 character number of cipher suites, so if there’s 6 cipher suites in the hello packet, then the value should be “06”.
|
||||||
|
If there’s > 99, which there should never be, then output “99”.
|
||||||
|
*/
|
||||||
|
let extLen = tlsr.handshake.value.extensions.value.length;
|
||||||
|
extLen = extLen > 99 ? "99" : extLen.toString().padStart(2, "0");
|
||||||
|
|
||||||
|
/* ALPN Extension Chosen Value
|
||||||
|
The first and last characters of the ALPN (Application-Layer Protocol Negotiation) first value.
|
||||||
|
If there are no ALPN values or no ALPN extension then we print “00” as the value in the fingerprint.
|
||||||
|
*/
|
||||||
|
let alpn = "00";
|
||||||
|
for (const ext of tlsr.handshake.value.extensions.value) {
|
||||||
|
if (ext.type.value === "application_layer_protocol_negotiation") {
|
||||||
|
alpn = parseFirstALPNValue(ext.value.data);
|
||||||
|
alpn = alpn.charAt(0) + alpn.charAt(alpn.length - 1);
|
||||||
|
if (alpn.charCodeAt(0) > 127) alpn = "99";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chosen Cipher
|
||||||
|
The hex value of the chosen cipher suite
|
||||||
|
*/
|
||||||
|
const cipher = toHexFast(tlsr.handshake.value.cipherSuite.data);
|
||||||
|
|
||||||
|
/* Extension hash
|
||||||
|
A 12 character truncated sha256 hash of the list of extensions.
|
||||||
|
The extension list is created using the 4 character hex values of the extensions, lower case, comma delimited.
|
||||||
|
*/
|
||||||
|
const extensionsList = [];
|
||||||
|
for (const ext of tlsr.handshake.value.extensions.value) {
|
||||||
|
extensionsList.push(toHexFast(ext.type.data));
|
||||||
|
}
|
||||||
|
const extensionsRaw = extensionsList.join(",");
|
||||||
|
const extensionsHash = runHash(
|
||||||
|
"sha256",
|
||||||
|
Utils.strToArrayBuffer(extensionsRaw)
|
||||||
|
).substring(0, 12);
|
||||||
|
|
||||||
|
return {
|
||||||
|
"JA4S": `${ptype}${version}${extLen}${alpn}_${cipher}_${extensionsHash}`,
|
||||||
|
"JA4S_r": `${ptype}${version}${extLen}${alpn}_${cipher}_${extensionsRaw}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a TLS version value and returns a JA4 TLS version string
|
||||||
|
* @param {Uint8Array} version - Two byte array of version number
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function tlsVersionMapper(version) {
|
||||||
|
switch (version) {
|
||||||
|
case 0x0304: return "13"; // TLS 1.3
|
||||||
|
case 0x0303: return "12"; // TLS 1.2
|
||||||
|
case 0x0302: return "11"; // TLS 1.1
|
||||||
|
case 0x0301: return "10"; // TLS 1.0
|
||||||
|
case 0x0300: return "s3"; // SSL 3.0
|
||||||
|
case 0x0200: return "s2"; // SSL 2.0
|
||||||
|
case 0x0100: return "s1"; // SSL 1.0
|
||||||
|
default: return "00"; // Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import jsQR from "jsqr";
|
import jsQR from "jsqr";
|
||||||
import qr from "qr-image";
|
import qr from "qr-image";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a QR code image from an image
|
* Parses a QR code image from an image
|
||||||
|
@ -22,7 +22,7 @@ import jimp from "jimp";
|
||||||
export async function parseQrCode(input, normalise) {
|
export async function parseQrCode(input, normalise) {
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error opening image. (${err})`);
|
throw new OperationError(`Error opening image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,8 @@ export async function parseQrCode(input, normalise) {
|
||||||
image.background(0xFFFFFFFF);
|
image.background(0xFFFFFFFF);
|
||||||
image.normalize();
|
image.normalize();
|
||||||
image.greyscale();
|
image.greyscale();
|
||||||
image = await image.getBufferAsync(jimp.MIME_JPEG);
|
image = await image.getBufferAsync(Jimp.MIME_JPEG);
|
||||||
image = await jimp.read(image);
|
image = await Jimp.read(image);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error normalising image. (${err})`);
|
throw new OperationError(`Error normalising image. (${err})`);
|
||||||
|
|
|
@ -70,13 +70,11 @@ function parseHandshake(bytes) {
|
||||||
|
|
||||||
// Handshake type
|
// Handshake type
|
||||||
h.handshakeType = {
|
h.handshakeType = {
|
||||||
description: "Client Hello",
|
description: "Handshake Type",
|
||||||
length: 1,
|
length: 1,
|
||||||
data: b.getBytes(1),
|
data: b.getBytes(1),
|
||||||
value: s.readInt(1)
|
value: s.readInt(1)
|
||||||
};
|
};
|
||||||
if (h.handshakeType.value !== 0x01)
|
|
||||||
throw new OperationError("Not a Client Hello.");
|
|
||||||
|
|
||||||
// Handshake length
|
// Handshake length
|
||||||
h.handshakeLength = {
|
h.handshakeLength = {
|
||||||
|
@ -86,8 +84,33 @@ function parseHandshake(bytes) {
|
||||||
value: s.readInt(3)
|
value: s.readInt(3)
|
||||||
};
|
};
|
||||||
if (s.length !== h.handshakeLength.value + 4)
|
if (s.length !== h.handshakeLength.value + 4)
|
||||||
throw new OperationError("Not enough data in Client Hello.");
|
throw new OperationError("Not enough data in Handshake message.");
|
||||||
|
|
||||||
|
|
||||||
|
switch (h.handshakeType.value) {
|
||||||
|
case 0x01:
|
||||||
|
h.handshakeType.description = "Client Hello";
|
||||||
|
parseClientHello(s, b, h);
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
h.handshakeType.description = "Server Hello";
|
||||||
|
parseServerHello(s, b, h);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError("Not a known handshake message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a TLS Client Hello
|
||||||
|
* @param {Stream} s
|
||||||
|
* @param {Stream} b
|
||||||
|
* @param {Object} h
|
||||||
|
* @returns {JSON}
|
||||||
|
*/
|
||||||
|
function parseClientHello(s, b, h) {
|
||||||
// Hello version
|
// Hello version
|
||||||
h.helloVersion = {
|
h.helloVersion = {
|
||||||
description: "Client Hello Version",
|
description: "Client Hello Version",
|
||||||
|
@ -171,6 +194,79 @@ function parseHandshake(bytes) {
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a TLS Server Hello
|
||||||
|
* @param {Stream} s
|
||||||
|
* @param {Stream} b
|
||||||
|
* @param {Object} h
|
||||||
|
* @returns {JSON}
|
||||||
|
*/
|
||||||
|
function parseServerHello(s, b, h) {
|
||||||
|
// Hello version
|
||||||
|
h.helloVersion = {
|
||||||
|
description: "Server Hello Version",
|
||||||
|
length: 2,
|
||||||
|
data: b.getBytes(2),
|
||||||
|
value: s.readInt(2)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Random
|
||||||
|
h.random = {
|
||||||
|
description: "Server Random",
|
||||||
|
length: 32,
|
||||||
|
data: b.getBytes(32),
|
||||||
|
value: s.getBytes(32)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Session ID Length
|
||||||
|
h.sessionIDLength = {
|
||||||
|
description: "Session ID Length",
|
||||||
|
length: 1,
|
||||||
|
data: b.getBytes(1),
|
||||||
|
value: s.readInt(1)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Session ID
|
||||||
|
h.sessionID = {
|
||||||
|
description: "Session ID",
|
||||||
|
length: h.sessionIDLength.value,
|
||||||
|
data: b.getBytes(h.sessionIDLength.value),
|
||||||
|
value: s.getBytes(h.sessionIDLength.value)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cipher Suite
|
||||||
|
h.cipherSuite = {
|
||||||
|
description: "Selected Cipher Suite",
|
||||||
|
length: 2,
|
||||||
|
data: b.getBytes(2),
|
||||||
|
value: CIPHER_SUITES_LOOKUP[s.readInt(2)] || "Unknown"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compression Method
|
||||||
|
h.compressionMethod = {
|
||||||
|
description: "Selected Compression Method",
|
||||||
|
length: 1,
|
||||||
|
data: b.getBytes(1),
|
||||||
|
value: s.readInt(1) // TODO: Compression method name here
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extensions Length
|
||||||
|
h.extensionsLength = {
|
||||||
|
description: "Extensions Length",
|
||||||
|
length: 2,
|
||||||
|
data: b.getBytes(2),
|
||||||
|
value: s.readInt(2)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extensions
|
||||||
|
h.extensions = {
|
||||||
|
description: "Extensions",
|
||||||
|
length: h.extensionsLength.value,
|
||||||
|
data: b.getBytes(h.extensionsLength.value),
|
||||||
|
value: parseExtensions(s.getBytes(h.extensionsLength.value))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse Cipher Suites
|
* Parse Cipher Suites
|
||||||
* @param {Uint8Array} bytes
|
* @param {Uint8Array} bytes
|
||||||
|
@ -748,6 +844,11 @@ export const GREASE_VALUES = [
|
||||||
export function parseHighestSupportedVersion(bytes) {
|
export function parseHighestSupportedVersion(bytes) {
|
||||||
const s = new Stream(bytes);
|
const s = new Stream(bytes);
|
||||||
|
|
||||||
|
// The Server Hello supported_versions extension simply contains the chosen version
|
||||||
|
if (s.length === 2) {
|
||||||
|
return s.readInt(2);
|
||||||
|
}
|
||||||
|
|
||||||
// Length
|
// Length
|
||||||
let i = s.readInt(1);
|
let i = s.readInt(1);
|
||||||
|
|
||||||
|
|
174
src/core/lib/XXTEA.mjs
Normal file
174
src/core/lib/XXTEA.mjs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/**
|
||||||
|
* XXTEA library
|
||||||
|
*
|
||||||
|
* Encryption Algorithm Authors:
|
||||||
|
* David J. Wheeler
|
||||||
|
* Roger M. Needham
|
||||||
|
*
|
||||||
|
* @author Ma Bingyao [mabingyao@gmail.com]
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
const DELTA = 0x9E3779B9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a buffer to a Uint8Array
|
||||||
|
* @param {Uint32Array} v
|
||||||
|
* @param {boolean} includeLength
|
||||||
|
* @returns {Uint8Array}
|
||||||
|
*/
|
||||||
|
function toUint8Array(v, includeLength) {
|
||||||
|
const length = v.length;
|
||||||
|
let n = length << 2;
|
||||||
|
if (includeLength) {
|
||||||
|
const m = v[length - 1];
|
||||||
|
n -= 4;
|
||||||
|
if ((m < n - 3) || (m > n)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
n = m;
|
||||||
|
}
|
||||||
|
const bytes = new Uint8Array(n);
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
bytes[i] = v[i >> 2] >> ((i & 3) << 3);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a buffer to a Uint32Array
|
||||||
|
* @param {TypedArray} bs
|
||||||
|
* @param {boolean} includeLength
|
||||||
|
* @returns {Uint32Array}
|
||||||
|
*/
|
||||||
|
function toUint32Array(bs, includeLength) {
|
||||||
|
const length = bs.length;
|
||||||
|
let n = length >> 2;
|
||||||
|
if ((length & 3) !== 0) {
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
let v;
|
||||||
|
if (includeLength) {
|
||||||
|
v = new Uint32Array(n + 1);
|
||||||
|
v[n] = length;
|
||||||
|
} else {
|
||||||
|
v = new Uint32Array(n);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < length; ++i) {
|
||||||
|
v[i >> 2] |= bs[i] << ((i & 3) << 3);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask an int to 32 bits
|
||||||
|
* @param {number} i
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function int32(i) {
|
||||||
|
return i & 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MX function for data randomisation
|
||||||
|
* @param {number} sum
|
||||||
|
* @param {number} y
|
||||||
|
* @param {number} z
|
||||||
|
* @param {number} p
|
||||||
|
* @param {number} e
|
||||||
|
* @param {number} k
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function mx(sum, y, z, p, e, k) {
|
||||||
|
return ((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure an array is a multiple of 16 bits
|
||||||
|
* @param {TypedArray} k
|
||||||
|
* @returns {TypedArray}
|
||||||
|
*/
|
||||||
|
function fixk(k) {
|
||||||
|
if (k.length < 16) {
|
||||||
|
const key = new Uint8Array(16);
|
||||||
|
key.set(k);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs XXTEA encryption on a Uint32Array
|
||||||
|
* @param {Uint32Array} v
|
||||||
|
* @param {Uint32Array} k
|
||||||
|
* @returns {Uint32Array}
|
||||||
|
*/
|
||||||
|
function encryptUint32Array(v, k) {
|
||||||
|
const length = v.length;
|
||||||
|
const n = length - 1;
|
||||||
|
let y, z, sum, e, p, q;
|
||||||
|
z = v[n];
|
||||||
|
sum = 0;
|
||||||
|
for (q = Math.floor(6 + 52 / length) | 0; q > 0; --q) {
|
||||||
|
sum = int32(sum + DELTA);
|
||||||
|
e = sum >>> 2 & 3;
|
||||||
|
for (p = 0; p < n; ++p) {
|
||||||
|
y = v[p + 1];
|
||||||
|
z = v[p] = int32(v[p] + mx(sum, y, z, p, e, k));
|
||||||
|
}
|
||||||
|
y = v[0];
|
||||||
|
z = v[n] = int32(v[n] + mx(sum, y, z, n, e, k));
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs XXTEA decryption on a Uint32Array
|
||||||
|
* @param {Uint32Array} v
|
||||||
|
* @param {Uint32Array} k
|
||||||
|
* @returns {Uint32Array}
|
||||||
|
*/
|
||||||
|
function decryptUint32Array(v, k) {
|
||||||
|
const length = v.length;
|
||||||
|
const n = length - 1;
|
||||||
|
let y, z, sum, e, p;
|
||||||
|
y = v[0];
|
||||||
|
const q = Math.floor(6 + 52 / length);
|
||||||
|
for (sum = int32(q * DELTA); sum !== 0; sum = int32(sum - DELTA)) {
|
||||||
|
e = sum >>> 2 & 3;
|
||||||
|
for (p = n; p > 0; --p) {
|
||||||
|
z = v[p - 1];
|
||||||
|
y = v[p] = int32(v[p] - mx(sum, y, z, p, e, k));
|
||||||
|
}
|
||||||
|
z = v[n];
|
||||||
|
y = v[0] = int32(v[0] - mx(sum, y, z, 0, e, k));
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt function
|
||||||
|
* @param {TypedArray} data
|
||||||
|
* @param {TypedArray} key
|
||||||
|
* @returns {Uint8Array}
|
||||||
|
*/
|
||||||
|
export function encrypt(data, key) {
|
||||||
|
if (data === undefined || data === null || data.length === 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return toUint8Array(encryptUint32Array(toUint32Array(data, true), toUint32Array(fixk(key), false)), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt function
|
||||||
|
* @param {TypedArray} data
|
||||||
|
* @param {TypedArray} key
|
||||||
|
* @returns {Uint8Array}
|
||||||
|
*/
|
||||||
|
export function decrypt(data, key) {
|
||||||
|
if (data === undefined || data === null || data.length === 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return toUint8Array(decryptUint32Array(toUint32Array(data, false), toUint32Array(fixk(key), false)), true);
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Text To Image operation
|
* Add Text To Image operation
|
||||||
|
@ -127,7 +127,7 @@ class AddTextToImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ class AddTextToImage extends Operation {
|
||||||
const font = fontsMap[fontFace];
|
const font = fontsMap[fontFace];
|
||||||
|
|
||||||
// LoadFont needs an absolute url, so append the font name to self.docURL
|
// LoadFont needs an absolute url, so append the font name to self.docURL
|
||||||
const jimpFont = await jimp.loadFont(self.docURL + "/" + font.default);
|
const jimpFont = await Jimp.loadFont(self.docURL + "/" + font.default);
|
||||||
|
|
||||||
jimpFont.pages.forEach(function(page) {
|
jimpFont.pages.forEach(function(page) {
|
||||||
if (page.bitmap) {
|
if (page.bitmap) {
|
||||||
|
@ -190,7 +190,7 @@ class AddTextToImage extends Operation {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a temporary image to hold the rendered text
|
// Create a temporary image to hold the rendered text
|
||||||
const textImage = new jimp(jimp.measureText(jimpFont, text), jimp.measureTextHeight(jimpFont, text));
|
const textImage = new Jimp(Jimp.measureText(jimpFont, text), Jimp.measureTextHeight(jimpFont, text));
|
||||||
textImage.print(jimpFont, 0, 0, text);
|
textImage.print(jimpFont, 0, 0, text);
|
||||||
|
|
||||||
// Scale the rendered text image to the correct size
|
// Scale the rendered text image to the correct size
|
||||||
|
@ -198,9 +198,9 @@ class AddTextToImage extends Operation {
|
||||||
if (size !== 1) {
|
if (size !== 1) {
|
||||||
// Use bicubic for decreasing size
|
// Use bicubic for decreasing size
|
||||||
if (size > 1) {
|
if (size > 1) {
|
||||||
textImage.scale(scaleFactor, jimp.RESIZE_BICUBIC);
|
textImage.scale(scaleFactor, Jimp.RESIZE_BICUBIC);
|
||||||
} else {
|
} else {
|
||||||
textImage.scale(scaleFactor, jimp.RESIZE_BILINEAR);
|
textImage.scale(scaleFactor, Jimp.RESIZE_BILINEAR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,9 +234,9 @@ class AddTextToImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blur Image operation
|
* Blur Image operation
|
||||||
|
@ -59,7 +59,7 @@ class BlurImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -79,9 +79,9 @@ class BlurImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contain Image operation
|
* Contain Image operation
|
||||||
|
@ -91,20 +91,20 @@ class ContainImage extends Operation {
|
||||||
const [width, height, hAlign, vAlign, alg, opaqueBg] = args;
|
const [width, height, hAlign, vAlign, alg, opaqueBg] = args;
|
||||||
|
|
||||||
const resizeMap = {
|
const resizeMap = {
|
||||||
"Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR,
|
"Nearest Neighbour": Jimp.RESIZE_NEAREST_NEIGHBOR,
|
||||||
"Bilinear": jimp.RESIZE_BILINEAR,
|
"Bilinear": Jimp.RESIZE_BILINEAR,
|
||||||
"Bicubic": jimp.RESIZE_BICUBIC,
|
"Bicubic": Jimp.RESIZE_BICUBIC,
|
||||||
"Hermite": jimp.RESIZE_HERMITE,
|
"Hermite": Jimp.RESIZE_HERMITE,
|
||||||
"Bezier": jimp.RESIZE_BEZIER
|
"Bezier": Jimp.RESIZE_BEZIER
|
||||||
};
|
};
|
||||||
|
|
||||||
const alignMap = {
|
const alignMap = {
|
||||||
"Left": jimp.HORIZONTAL_ALIGN_LEFT,
|
"Left": Jimp.HORIZONTAL_ALIGN_LEFT,
|
||||||
"Center": jimp.HORIZONTAL_ALIGN_CENTER,
|
"Center": Jimp.HORIZONTAL_ALIGN_CENTER,
|
||||||
"Right": jimp.HORIZONTAL_ALIGN_RIGHT,
|
"Right": Jimp.HORIZONTAL_ALIGN_RIGHT,
|
||||||
"Top": jimp.VERTICAL_ALIGN_TOP,
|
"Top": Jimp.VERTICAL_ALIGN_TOP,
|
||||||
"Middle": jimp.VERTICAL_ALIGN_MIDDLE,
|
"Middle": Jimp.VERTICAL_ALIGN_MIDDLE,
|
||||||
"Bottom": jimp.VERTICAL_ALIGN_BOTTOM
|
"Bottom": Jimp.VERTICAL_ALIGN_BOTTOM
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isImage(input)) {
|
if (!isImage(input)) {
|
||||||
|
@ -113,7 +113,7 @@ class ContainImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -123,16 +123,16 @@ class ContainImage extends Operation {
|
||||||
image.contain(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]);
|
image.contain(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]);
|
||||||
|
|
||||||
if (opaqueBg) {
|
if (opaqueBg) {
|
||||||
const newImage = await jimp.read(width, height, 0x000000FF);
|
const newImage = await Jimp.read(width, height, 0x000000FF);
|
||||||
newImage.blit(image, 0, 0);
|
newImage.blit(image, 0, 0);
|
||||||
image = newImage;
|
image = newImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Image Format operation
|
* Convert Image Format operation
|
||||||
|
@ -76,19 +76,19 @@ class ConvertImageFormat extends Operation {
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args;
|
const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args;
|
||||||
const formatMap = {
|
const formatMap = {
|
||||||
"JPEG": jimp.MIME_JPEG,
|
"JPEG": Jimp.MIME_JPEG,
|
||||||
"PNG": jimp.MIME_PNG,
|
"PNG": Jimp.MIME_PNG,
|
||||||
"BMP": jimp.MIME_BMP,
|
"BMP": Jimp.MIME_BMP,
|
||||||
"TIFF": jimp.MIME_TIFF
|
"TIFF": Jimp.MIME_TIFF
|
||||||
};
|
};
|
||||||
|
|
||||||
const pngFilterMap = {
|
const pngFilterMap = {
|
||||||
"Auto": jimp.PNG_FILTER_AUTO,
|
"Auto": Jimp.PNG_FILTER_AUTO,
|
||||||
"None": jimp.PNG_FILTER_NONE,
|
"None": Jimp.PNG_FILTER_NONE,
|
||||||
"Sub": jimp.PNG_FILTER_SUB,
|
"Sub": Jimp.PNG_FILTER_SUB,
|
||||||
"Up": jimp.PNG_FILTER_UP,
|
"Up": Jimp.PNG_FILTER_UP,
|
||||||
"Average": jimp.PNG_FILTER_AVERAGE,
|
"Average": Jimp.PNG_FILTER_AVERAGE,
|
||||||
"Paeth": jimp.PNG_FILTER_PATH
|
"Paeth": Jimp.PNG_FILTER_PATH
|
||||||
};
|
};
|
||||||
|
|
||||||
const mime = formatMap[format];
|
const mime = formatMap[format];
|
||||||
|
@ -98,7 +98,7 @@ class ConvertImageFormat extends Operation {
|
||||||
}
|
}
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error opening image file. (${err})`);
|
throw new OperationError(`Error opening image file. (${err})`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cover Image operation
|
* Cover Image operation
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crop Image operation
|
* Crop Image operation
|
||||||
|
@ -99,7 +99,7 @@ class CropImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -119,9 +119,9 @@ class CropImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image Dither operation
|
* Image Dither operation
|
||||||
|
@ -44,7 +44,7 @@ class DitherImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,9 @@ class DitherImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
107
src/core/operations/ECDSASign.mjs
Normal file
107
src/core/operations/ECDSASign.mjs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { fromHex } from "../lib/Hex.mjs";
|
||||||
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
|
import r from "jsrsasign";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ECDSA Sign operation
|
||||||
|
*/
|
||||||
|
class ECDSASign extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ECDSASign constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "ECDSA Sign";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "Sign a plaintext message with a PEM encoded EC key.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "ECDSA Private Key (PEM)",
|
||||||
|
type: "text",
|
||||||
|
value: "-----BEGIN EC PRIVATE KEY-----"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Message Digest Algorithm",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"SHA-256",
|
||||||
|
"SHA-384",
|
||||||
|
"SHA-512",
|
||||||
|
"SHA-1",
|
||||||
|
"MD5"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Output Format",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"ASN.1 HEX",
|
||||||
|
"P1363 HEX",
|
||||||
|
"JSON Web Signature",
|
||||||
|
"Raw JSON"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [keyPem, mdAlgo, outputFormat] = args;
|
||||||
|
|
||||||
|
if (keyPem.replace("-----BEGIN EC PRIVATE KEY-----", "").length === 0) {
|
||||||
|
throw new OperationError("Please enter a private key.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const internalAlgorithmName = mdAlgo.replace("-", "") + "withECDSA";
|
||||||
|
const sig = new r.KJUR.crypto.Signature({ alg: internalAlgorithmName });
|
||||||
|
const key = r.KEYUTIL.getKey(keyPem);
|
||||||
|
if (key.type !== "EC") {
|
||||||
|
throw new OperationError("Provided key is not an EC key.");
|
||||||
|
}
|
||||||
|
if (!key.isPrivate) {
|
||||||
|
throw new OperationError("Provided key is not a private key.");
|
||||||
|
}
|
||||||
|
sig.init(key);
|
||||||
|
const signatureASN1Hex = sig.signString(input);
|
||||||
|
|
||||||
|
let result;
|
||||||
|
switch (outputFormat) {
|
||||||
|
case "ASN.1 HEX":
|
||||||
|
result = signatureASN1Hex;
|
||||||
|
break;
|
||||||
|
case "P1363 HEX":
|
||||||
|
result = r.KJUR.crypto.ECDSA.asn1SigToConcatSig(signatureASN1Hex);
|
||||||
|
break;
|
||||||
|
case "JSON Web Signature":
|
||||||
|
result = r.KJUR.crypto.ECDSA.asn1SigToConcatSig(signatureASN1Hex);
|
||||||
|
result = toBase64(fromHex(result), "A-Za-z0-9-_"); // base64url
|
||||||
|
break;
|
||||||
|
case "Raw JSON": {
|
||||||
|
const signatureRS = r.KJUR.crypto.ECDSA.parseSigHexInHexRS(signatureASN1Hex);
|
||||||
|
result = JSON.stringify(signatureRS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ECDSASign;
|
146
src/core/operations/ECDSASignatureConversion.mjs
Normal file
146
src/core/operations/ECDSASignatureConversion.mjs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { fromBase64, toBase64 } from "../lib/Base64.mjs";
|
||||||
|
import { fromHex, toHexFast } from "../lib/Hex.mjs";
|
||||||
|
import r from "jsrsasign";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ECDSA Sign operation
|
||||||
|
*/
|
||||||
|
class ECDSASignatureConversion extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ECDSASignatureConversion constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "ECDSA Signature Conversion";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "Convert an ECDSA signature between hex, asn1 and json.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Input Format",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"Auto",
|
||||||
|
"ASN.1 HEX",
|
||||||
|
"P1363 HEX",
|
||||||
|
"JSON Web Signature",
|
||||||
|
"Raw JSON"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Output Format",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"ASN.1 HEX",
|
||||||
|
"P1363 HEX",
|
||||||
|
"JSON Web Signature",
|
||||||
|
"Raw JSON"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
let inputFormat = args[0];
|
||||||
|
const outputFormat = args[1];
|
||||||
|
|
||||||
|
// detect input format
|
||||||
|
let inputJson;
|
||||||
|
if (inputFormat === "Auto") {
|
||||||
|
try {
|
||||||
|
inputJson = JSON.parse(input);
|
||||||
|
if (typeof(inputJson) === "object") {
|
||||||
|
inputFormat = "Raw JSON";
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputFormat === "Auto") {
|
||||||
|
const hexRegex = /^[a-f\d]{2,}$/gi;
|
||||||
|
if (hexRegex.test(input)) {
|
||||||
|
if (input.substring(0, 2) === "30" && r.ASN1HEX.isASN1HEX(input)) {
|
||||||
|
inputFormat = "ASN.1 HEX";
|
||||||
|
} else {
|
||||||
|
inputFormat = "P1363 HEX";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputBase64;
|
||||||
|
if (inputFormat === "Auto") {
|
||||||
|
try {
|
||||||
|
inputBase64 = fromBase64(input, "A-Za-z0-9-_", false);
|
||||||
|
inputFormat = "JSON Web Signature";
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert input to ASN.1 hex
|
||||||
|
let signatureASN1Hex;
|
||||||
|
switch (inputFormat) {
|
||||||
|
case "Auto":
|
||||||
|
throw new OperationError("Signature format could not be detected");
|
||||||
|
case "ASN.1 HEX":
|
||||||
|
signatureASN1Hex = input;
|
||||||
|
break;
|
||||||
|
case "P1363 HEX":
|
||||||
|
signatureASN1Hex = r.KJUR.crypto.ECDSA.concatSigToASN1Sig(input);
|
||||||
|
break;
|
||||||
|
case "JSON Web Signature":
|
||||||
|
if (!inputBase64) inputBase64 = fromBase64(input, "A-Za-z0-9-_");
|
||||||
|
signatureASN1Hex = r.KJUR.crypto.ECDSA.concatSigToASN1Sig(toHexFast(inputBase64));
|
||||||
|
break;
|
||||||
|
case "Raw JSON": {
|
||||||
|
if (!inputJson) inputJson = JSON.parse(input);
|
||||||
|
if (!inputJson.r) {
|
||||||
|
throw new OperationError('No "r" value in the signature JSON');
|
||||||
|
}
|
||||||
|
if (!inputJson.s) {
|
||||||
|
throw new OperationError('No "s" value in the signature JSON');
|
||||||
|
}
|
||||||
|
signatureASN1Hex = r.KJUR.crypto.ECDSA.hexRSSigToASN1Sig(inputJson.r, inputJson.s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert ASN.1 hex to output format
|
||||||
|
let result;
|
||||||
|
switch (outputFormat) {
|
||||||
|
case "ASN.1 HEX":
|
||||||
|
result = signatureASN1Hex;
|
||||||
|
break;
|
||||||
|
case "P1363 HEX":
|
||||||
|
result = r.KJUR.crypto.ECDSA.asn1SigToConcatSig(signatureASN1Hex);
|
||||||
|
break;
|
||||||
|
case "JSON Web Signature":
|
||||||
|
result = r.KJUR.crypto.ECDSA.asn1SigToConcatSig(signatureASN1Hex);
|
||||||
|
result = toBase64(fromHex(result), "A-Za-z0-9-_"); // base64url
|
||||||
|
break;
|
||||||
|
case "Raw JSON": {
|
||||||
|
const signatureRS = r.KJUR.crypto.ECDSA.parseSigHexInHexRS(signatureASN1Hex);
|
||||||
|
result = JSON.stringify(signatureRS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ECDSASignatureConversion;
|
154
src/core/operations/ECDSAVerify.mjs
Normal file
154
src/core/operations/ECDSAVerify.mjs
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { fromBase64 } from "../lib/Base64.mjs";
|
||||||
|
import { toHexFast } from "../lib/Hex.mjs";
|
||||||
|
import r from "jsrsasign";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ECDSA Verify operation
|
||||||
|
*/
|
||||||
|
class ECDSAVerify extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ECDSAVerify constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "ECDSA Verify";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "Verify a message against a signature and a public PEM encoded EC key.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Input Format",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"Auto",
|
||||||
|
"ASN.1 HEX",
|
||||||
|
"P1363 HEX",
|
||||||
|
"JSON Web Signature",
|
||||||
|
"Raw JSON"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Message Digest Algorithm",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"SHA-256",
|
||||||
|
"SHA-384",
|
||||||
|
"SHA-512",
|
||||||
|
"SHA-1",
|
||||||
|
"MD5"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Public Key (PEM)",
|
||||||
|
type: "text",
|
||||||
|
value: "-----BEGIN PUBLIC KEY-----"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Message",
|
||||||
|
type: "text",
|
||||||
|
value: ""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
let inputFormat = args[0];
|
||||||
|
const [, mdAlgo, keyPem, msg] = args;
|
||||||
|
|
||||||
|
if (keyPem.replace("-----BEGIN PUBLIC KEY-----", "").length === 0) {
|
||||||
|
throw new OperationError("Please enter a public key.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect input format
|
||||||
|
let inputJson;
|
||||||
|
if (inputFormat === "Auto") {
|
||||||
|
try {
|
||||||
|
inputJson = JSON.parse(input);
|
||||||
|
if (typeof(inputJson) === "object") {
|
||||||
|
inputFormat = "Raw JSON";
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputFormat === "Auto") {
|
||||||
|
const hexRegex = /^[a-f\d]{2,}$/gi;
|
||||||
|
if (hexRegex.test(input)) {
|
||||||
|
if (input.substring(0, 2) === "30" && r.ASN1HEX.isASN1HEX(input)) {
|
||||||
|
inputFormat = "ASN.1 HEX";
|
||||||
|
} else {
|
||||||
|
inputFormat = "P1363 HEX";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputBase64;
|
||||||
|
if (inputFormat === "Auto") {
|
||||||
|
try {
|
||||||
|
inputBase64 = fromBase64(input, "A-Za-z0-9-_", false);
|
||||||
|
inputFormat = "JSON Web Signature";
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to ASN.1 signature
|
||||||
|
let signatureASN1Hex;
|
||||||
|
switch (inputFormat) {
|
||||||
|
case "Auto":
|
||||||
|
throw new OperationError("Signature format could not be detected");
|
||||||
|
case "ASN.1 HEX":
|
||||||
|
signatureASN1Hex = input;
|
||||||
|
break;
|
||||||
|
case "P1363 HEX":
|
||||||
|
signatureASN1Hex = r.KJUR.crypto.ECDSA.concatSigToASN1Sig(input);
|
||||||
|
break;
|
||||||
|
case "JSON Web Signature":
|
||||||
|
if (!inputBase64) inputBase64 = fromBase64(input, "A-Za-z0-9-_");
|
||||||
|
signatureASN1Hex = r.KJUR.crypto.ECDSA.concatSigToASN1Sig(toHexFast(inputBase64));
|
||||||
|
break;
|
||||||
|
case "Raw JSON": {
|
||||||
|
if (!inputJson) inputJson = JSON.parse(input);
|
||||||
|
if (!inputJson.r) {
|
||||||
|
throw new OperationError('No "r" value in the signature JSON');
|
||||||
|
}
|
||||||
|
if (!inputJson.s) {
|
||||||
|
throw new OperationError('No "s" value in the signature JSON');
|
||||||
|
}
|
||||||
|
signatureASN1Hex = r.KJUR.crypto.ECDSA.hexRSSigToASN1Sig(inputJson.r, inputJson.s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify signature
|
||||||
|
const internalAlgorithmName = mdAlgo.replace("-", "") + "withECDSA";
|
||||||
|
const sig = new r.KJUR.crypto.Signature({ alg: internalAlgorithmName });
|
||||||
|
const key = r.KEYUTIL.getKey(keyPem);
|
||||||
|
if (key.type !== "EC") {
|
||||||
|
throw new OperationError("Provided key is not an EC key.");
|
||||||
|
}
|
||||||
|
if (!key.isPublic) {
|
||||||
|
throw new OperationError("Provided key is not a public key.");
|
||||||
|
}
|
||||||
|
sig.init(key);
|
||||||
|
sig.updateString(msg);
|
||||||
|
const result = sig.verify(signatureASN1Hex);
|
||||||
|
return result ? "Verified OK" : "Verification Failure";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ECDSAVerify;
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import { fromBinary } from "../lib/Binary.mjs";
|
import { fromBinary } from "../lib/Binary.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract LSB operation
|
* Extract LSB operation
|
||||||
|
@ -73,7 +73,7 @@ class ExtractLSB extends Operation {
|
||||||
const bit = 7 - args.pop(),
|
const bit = 7 - args.pop(),
|
||||||
pixelOrder = args.pop(),
|
pixelOrder = args.pop(),
|
||||||
colours = args.filter(option => option !== "").map(option => COLOUR_OPTIONS.indexOf(option)),
|
colours = args.filter(option => option !== "").map(option => COLOUR_OPTIONS.indexOf(option)),
|
||||||
parsedImage = await jimp.read(input),
|
parsedImage = await Jimp.read(input),
|
||||||
width = parsedImage.bitmap.width,
|
width = parsedImage.bitmap.width,
|
||||||
height = parsedImage.bitmap.height,
|
height = parsedImage.bitmap.height,
|
||||||
rgba = parsedImage.bitmap.data;
|
rgba = parsedImage.bitmap.data;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
import {RGBA_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
import {RGBA_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ class ExtractRGBA extends Operation {
|
||||||
|
|
||||||
const delimiter = args[0],
|
const delimiter = args[0],
|
||||||
includeAlpha = args[1],
|
includeAlpha = args[1],
|
||||||
parsedImage = await jimp.read(input);
|
parsedImage = await Jimp.read(input);
|
||||||
|
|
||||||
let bitmap = parsedImage.bitmap.data;
|
let bitmap = parsedImage.bitmap.data;
|
||||||
bitmap = includeAlpha ? bitmap : bitmap.filter((val, idx) => idx % 4 !== 3);
|
bitmap = includeAlpha ? bitmap : bitmap.filter((val, idx) => idx % 4 !== 3);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flip Image operation
|
* Flip Image operation
|
||||||
|
@ -51,7 +51,7 @@ class FlipImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,9 @@ class FlipImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -55,22 +55,19 @@ class GOSTDecrypt extends Operation {
|
||||||
type: "argSelector",
|
type: "argSelector",
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
name: "GOST 28147 (Magma, 1989)",
|
name: "GOST 28147 (1989)",
|
||||||
off: [5],
|
on: [5]
|
||||||
on: [6]
|
},
|
||||||
|
{
|
||||||
|
name: "GOST R 34.12 (Magma, 2015)",
|
||||||
|
off: [5]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
on: [5],
|
off: [5]
|
||||||
off: [6]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Block length",
|
|
||||||
type: "option",
|
|
||||||
value: ["64", "128"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "sBox",
|
name: "sBox",
|
||||||
type: "option",
|
type: "option",
|
||||||
|
@ -100,14 +97,30 @@ class GOSTDecrypt extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [keyObj, ivObj, inputType, outputType, version, length, sBox, blockMode, keyMeshing, padding] = args;
|
const [keyObj, ivObj, inputType, outputType, version, sBox, blockMode, keyMeshing, padding] = args;
|
||||||
|
|
||||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||||
|
|
||||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
let blockLength, versionNum;
|
||||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
switch (version) {
|
||||||
|
case "GOST 28147 (1989)":
|
||||||
|
versionNum = 1989;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Magma, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Kuznyechik, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown algorithm version: ${version}`);
|
||||||
|
}
|
||||||
|
|
||||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||||
|
|
||||||
const algorithm = {
|
const algorithm = {
|
||||||
|
|
|
@ -55,22 +55,19 @@ class GOSTEncrypt extends Operation {
|
||||||
type: "argSelector",
|
type: "argSelector",
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
name: "GOST 28147 (Magma, 1989)",
|
name: "GOST 28147 (1989)",
|
||||||
off: [5],
|
on: [5]
|
||||||
on: [6]
|
},
|
||||||
|
{
|
||||||
|
name: "GOST R 34.12 (Magma, 2015)",
|
||||||
|
off: [5]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
on: [5],
|
off: [5]
|
||||||
off: [6]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Block length",
|
|
||||||
type: "option",
|
|
||||||
value: ["64", "128"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "sBox",
|
name: "sBox",
|
||||||
type: "option",
|
type: "option",
|
||||||
|
@ -100,14 +97,30 @@ class GOSTEncrypt extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [keyObj, ivObj, inputType, outputType, version, length, sBox, blockMode, keyMeshing, padding] = args;
|
const [keyObj, ivObj, inputType, outputType, version, sBox, blockMode, keyMeshing, padding] = args;
|
||||||
|
|
||||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||||
|
|
||||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
let blockLength, versionNum;
|
||||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
switch (version) {
|
||||||
|
case "GOST 28147 (1989)":
|
||||||
|
versionNum = 1989;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Magma, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Kuznyechik, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown algorithm version: ${version}`);
|
||||||
|
}
|
||||||
|
|
||||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||||
|
|
||||||
const algorithm = {
|
const algorithm = {
|
||||||
|
|
|
@ -55,22 +55,19 @@ class GOSTKeyUnwrap extends Operation {
|
||||||
type: "argSelector",
|
type: "argSelector",
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
name: "GOST 28147 (Magma, 1989)",
|
name: "GOST 28147 (1989)",
|
||||||
off: [5],
|
on: [5]
|
||||||
on: [6]
|
},
|
||||||
|
{
|
||||||
|
name: "GOST R 34.12 (Magma, 2015)",
|
||||||
|
off: [5]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
on: [5],
|
off: [5]
|
||||||
off: [6]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Block length",
|
|
||||||
type: "option",
|
|
||||||
value: ["64", "128"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "sBox",
|
name: "sBox",
|
||||||
type: "option",
|
type: "option",
|
||||||
|
@ -90,14 +87,30 @@ class GOSTKeyUnwrap extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [keyObj, ukmObj, inputType, outputType, version, length, sBox, keyWrapping] = args;
|
const [keyObj, ukmObj, inputType, outputType, version, sBox, keyWrapping] = args;
|
||||||
|
|
||||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||||
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
||||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||||
|
|
||||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
let blockLength, versionNum;
|
||||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
switch (version) {
|
||||||
|
case "GOST 28147 (1989)":
|
||||||
|
versionNum = 1989;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Magma, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Kuznyechik, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown algorithm version: ${version}`);
|
||||||
|
}
|
||||||
|
|
||||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||||
|
|
||||||
const algorithm = {
|
const algorithm = {
|
||||||
|
|
|
@ -55,22 +55,19 @@ class GOSTKeyWrap extends Operation {
|
||||||
type: "argSelector",
|
type: "argSelector",
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
name: "GOST 28147 (Magma, 1989)",
|
name: "GOST 28147 (1989)",
|
||||||
off: [5],
|
on: [5]
|
||||||
on: [6]
|
},
|
||||||
|
{
|
||||||
|
name: "GOST R 34.12 (Magma, 2015)",
|
||||||
|
off: [5]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
on: [5],
|
off: [5]
|
||||||
off: [6]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Block length",
|
|
||||||
type: "option",
|
|
||||||
value: ["64", "128"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "sBox",
|
name: "sBox",
|
||||||
type: "option",
|
type: "option",
|
||||||
|
@ -90,14 +87,30 @@ class GOSTKeyWrap extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [keyObj, ukmObj, inputType, outputType, version, length, sBox, keyWrapping] = args;
|
const [keyObj, ukmObj, inputType, outputType, version, sBox, keyWrapping] = args;
|
||||||
|
|
||||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||||
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
||||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||||
|
|
||||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
let blockLength, versionNum;
|
||||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
switch (version) {
|
||||||
|
case "GOST 28147 (1989)":
|
||||||
|
versionNum = 1989;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Magma, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Kuznyechik, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown algorithm version: ${version}`);
|
||||||
|
}
|
||||||
|
|
||||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||||
|
|
||||||
const algorithm = {
|
const algorithm = {
|
||||||
|
|
|
@ -55,22 +55,19 @@ class GOSTSign extends Operation {
|
||||||
type: "argSelector",
|
type: "argSelector",
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
name: "GOST 28147 (Magma, 1989)",
|
name: "GOST 28147 (1989)",
|
||||||
off: [5],
|
on: [5]
|
||||||
on: [6]
|
},
|
||||||
|
{
|
||||||
|
name: "GOST R 34.12 (Magma, 2015)",
|
||||||
|
off: [5]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
on: [5],
|
off: [5]
|
||||||
off: [6]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Block length",
|
|
||||||
type: "option",
|
|
||||||
value: ["64", "128"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "sBox",
|
name: "sBox",
|
||||||
type: "option",
|
type: "option",
|
||||||
|
@ -93,14 +90,30 @@ class GOSTSign extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [keyObj, ivObj, inputType, outputType, version, length, sBox, macLength] = args;
|
const [keyObj, ivObj, inputType, outputType, version, sBox, macLength] = args;
|
||||||
|
|
||||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||||
|
|
||||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
let blockLength, versionNum;
|
||||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
switch (version) {
|
||||||
|
case "GOST 28147 (1989)":
|
||||||
|
versionNum = 1989;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Magma, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Kuznyechik, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown algorithm version: ${version}`);
|
||||||
|
}
|
||||||
|
|
||||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||||
|
|
||||||
const algorithm = {
|
const algorithm = {
|
||||||
|
|
|
@ -56,22 +56,19 @@ class GOSTVerify extends Operation {
|
||||||
type: "argSelector",
|
type: "argSelector",
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
name: "GOST 28147 (Magma, 1989)",
|
name: "GOST 28147 (1989)",
|
||||||
off: [5],
|
on: [5]
|
||||||
on: [6]
|
},
|
||||||
|
{
|
||||||
|
name: "GOST R 34.12 (Magma, 2015)",
|
||||||
|
off: [5]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
on: [5],
|
off: [5]
|
||||||
off: [6]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Block length",
|
|
||||||
type: "option",
|
|
||||||
value: ["64", "128"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "sBox",
|
name: "sBox",
|
||||||
type: "option",
|
type: "option",
|
||||||
|
@ -86,15 +83,31 @@ class GOSTVerify extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [keyObj, ivObj, macObj, inputType, version, length, sBox] = args;
|
const [keyObj, ivObj, macObj, inputType, version, sBox] = args;
|
||||||
|
|
||||||
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
|
||||||
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||||
const mac = toHexFast(Utils.convertToByteArray(macObj.string, macObj.option));
|
const mac = toHexFast(Utils.convertToByteArray(macObj.string, macObj.option));
|
||||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||||
|
|
||||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
let blockLength, versionNum;
|
||||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
switch (version) {
|
||||||
|
case "GOST 28147 (1989)":
|
||||||
|
versionNum = 1989;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Magma, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 64;
|
||||||
|
break;
|
||||||
|
case "GOST R 34.12 (Kuznyechik, 2015)":
|
||||||
|
versionNum = 2015;
|
||||||
|
blockLength = 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown algorithm version: ${version}`);
|
||||||
|
}
|
||||||
|
|
||||||
const sBoxVal = versionNum === 1989 ? sBox : null;
|
const sBoxVal = versionNum === 1989 ? sBox : null;
|
||||||
|
|
||||||
const algorithm = {
|
const algorithm = {
|
||||||
|
|
102
src/core/operations/GenerateECDSAKeyPair.mjs
Normal file
102
src/core/operations/GenerateECDSAKeyPair.mjs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import { cryptNotice } from "../lib/Crypt.mjs";
|
||||||
|
import r from "jsrsasign";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate ECDSA Key Pair operation
|
||||||
|
*/
|
||||||
|
class GenerateECDSAKeyPair extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GenerateECDSAKeyPair constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Generate ECDSA Key Pair";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = `Generate an ECDSA key pair with a given Curve.<br><br>${cryptNotice}`;
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Elliptic Curve",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"P-256",
|
||||||
|
"P-384",
|
||||||
|
"P-521"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Output Format",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"PEM",
|
||||||
|
"DER",
|
||||||
|
"JWK"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async run(input, args) {
|
||||||
|
const [curveName, outputFormat] = args;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let internalCurveName;
|
||||||
|
switch (curveName) {
|
||||||
|
case "P-256":
|
||||||
|
internalCurveName = "secp256r1";
|
||||||
|
break;
|
||||||
|
case "P-384":
|
||||||
|
internalCurveName = "secp384r1";
|
||||||
|
break;
|
||||||
|
case "P-521":
|
||||||
|
internalCurveName = "secp521r1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const keyPair = r.KEYUTIL.generateKeypair("EC", internalCurveName);
|
||||||
|
|
||||||
|
let pubKey;
|
||||||
|
let privKey;
|
||||||
|
let result;
|
||||||
|
switch (outputFormat) {
|
||||||
|
case "PEM":
|
||||||
|
pubKey = r.KEYUTIL.getPEM(keyPair.pubKeyObj).replace(/\r/g, "");
|
||||||
|
privKey = r.KEYUTIL.getPEM(keyPair.prvKeyObj, "PKCS8PRV").replace(/\r/g, "");
|
||||||
|
result = pubKey + "\n" + privKey;
|
||||||
|
break;
|
||||||
|
case "DER":
|
||||||
|
result = keyPair.prvKeyObj.prvKeyHex;
|
||||||
|
break;
|
||||||
|
case "JWK":
|
||||||
|
pubKey = r.KEYUTIL.getJWKFromKey(keyPair.pubKeyObj);
|
||||||
|
pubKey.key_ops = ["verify"]; // eslint-disable-line camelcase
|
||||||
|
pubKey.kid = "PublicKey";
|
||||||
|
privKey = r.KEYUTIL.getJWKFromKey(keyPair.prvKeyObj);
|
||||||
|
privKey.key_ops = ["sign"]; // eslint-disable-line camelcase
|
||||||
|
privKey.kid = "PrivateKey";
|
||||||
|
result = JSON.stringify({keys: [privKey, pubKey]}, null, 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GenerateECDSAKeyPair;
|
|
@ -10,7 +10,7 @@ import Utils from "../Utils.mjs";
|
||||||
import {isImage} from "../lib/FileType.mjs";
|
import {isImage} from "../lib/FileType.mjs";
|
||||||
import {toBase64} from "../lib/Base64.mjs";
|
import {toBase64} from "../lib/Base64.mjs";
|
||||||
import {isWorkerEnvironment} from "../Utils.mjs";
|
import {isWorkerEnvironment} from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate Image operation
|
* Generate Image operation
|
||||||
|
@ -81,7 +81,7 @@ class GenerateImage extends Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
const height = Math.ceil(input.length / bytesPerPixel / width);
|
const height = Math.ceil(input.length / bytesPerPixel / width);
|
||||||
const image = await new jimp(width, height, (err, image) => {});
|
const image = await new Jimp(width, height, (err, image) => {});
|
||||||
|
|
||||||
if (isWorkerEnvironment())
|
if (isWorkerEnvironment())
|
||||||
self.sendStatusMessage("Generating image from data...");
|
self.sendStatusMessage("Generating image from data...");
|
||||||
|
@ -95,7 +95,7 @@ class GenerateImage extends Operation {
|
||||||
const y = Math.floor(index / width);
|
const y = Math.floor(index / width);
|
||||||
|
|
||||||
const value = curByte[k] === "0" ? 0xFF : 0x00;
|
const value = curByte[k] === "0" ? 0xFF : 0x00;
|
||||||
const pixel = jimp.rgbaToInt(value, value, value, 0xFF);
|
const pixel = Jimp.rgbaToInt(value, value, value, 0xFF);
|
||||||
image.setPixelColor(pixel, x, y);
|
image.setPixelColor(pixel, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ class GenerateImage extends Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pixel = jimp.rgbaToInt(red, green, blue, alpha);
|
const pixel = Jimp.rgbaToInt(red, green, blue, alpha);
|
||||||
image.setPixelColor(pixel, x, y);
|
image.setPixelColor(pixel, x, y);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error while generating image from pixel values. (${err})`);
|
throw new OperationError(`Error while generating image from pixel values. (${err})`);
|
||||||
|
@ -151,11 +151,11 @@ class GenerateImage extends Operation {
|
||||||
if (isWorkerEnvironment())
|
if (isWorkerEnvironment())
|
||||||
self.sendStatusMessage("Scaling image...");
|
self.sendStatusMessage("Scaling image...");
|
||||||
|
|
||||||
image.scaleToFit(width*scale, height*scale, jimp.RESIZE_NEAREST_NEIGHBOR);
|
image.scaleToFit(width*scale, height*scale, Jimp.RESIZE_NEAREST_NEIGHBOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
const imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error generating image. (${err})`);
|
throw new OperationError(`Error generating image. (${err})`);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image Brightness / Contrast operation
|
* Image Brightness / Contrast operation
|
||||||
|
@ -60,7 +60,7 @@ class ImageBrightnessContrast extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -78,9 +78,9 @@ class ImageBrightnessContrast extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image Filter operation
|
* Image Filter operation
|
||||||
|
@ -54,7 +54,7 @@ class ImageFilter extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,9 @@ class ImageFilter extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image Hue/Saturation/Lightness operation
|
* Image Hue/Saturation/Lightness operation
|
||||||
|
@ -68,7 +68,7 @@ class ImageHueSaturationLightness extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -106,9 +106,9 @@ class ImageHueSaturationLightness extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image Opacity operation
|
* Image Opacity operation
|
||||||
|
@ -53,7 +53,7 @@ class ImageOpacity extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,9 @@ class ImageOpacity extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invert Image operation
|
* Invert Image operation
|
||||||
|
@ -44,7 +44,7 @@ class InvertImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,9 @@ class InvertImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
66
src/core/operations/JA4ServerFingerprint.mjs
Normal file
66
src/core/operations/JA4ServerFingerprint.mjs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import {toJA4S} from "../lib/JA4.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JA4Server Fingerprint operation
|
||||||
|
*/
|
||||||
|
class JA4ServerFingerprint extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JA4ServerFingerprint constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "JA4Server Fingerprint";
|
||||||
|
this.module = "Crypto";
|
||||||
|
this.description = "Generates a JA4Server Fingerprint (JA4S) to help identify TLS servers or sessions based on hashing together values from the Server Hello.<br><br>Input: A hex stream of the TLS or QUIC Server Hello packet application layer.";
|
||||||
|
this.infoURL = "https://medium.com/foxio/ja4-network-fingerprinting-9376fe9ca637";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Input format",
|
||||||
|
type: "option",
|
||||||
|
value: ["Hex", "Base64", "Raw"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Output format",
|
||||||
|
type: "option",
|
||||||
|
value: ["JA4S", "JA4S Raw", "Both"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [inputFormat, outputFormat] = args;
|
||||||
|
input = Utils.convertToByteArray(input, inputFormat);
|
||||||
|
const ja4s = toJA4S(new Uint8Array(input));
|
||||||
|
|
||||||
|
// Output
|
||||||
|
switch (outputFormat) {
|
||||||
|
case "JA4S":
|
||||||
|
return ja4s.JA4S;
|
||||||
|
case "JA4S Raw":
|
||||||
|
return ja4s.JA4S_r;
|
||||||
|
case "Both":
|
||||||
|
default:
|
||||||
|
return `JA4S: ${ja4s.JA4S}\nJA4S_r: ${ja4s.JA4S_r}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JA4ServerFingerprint;
|
|
@ -35,12 +35,6 @@ class JPathExpression extends Operation {
|
||||||
name: "Result delimiter",
|
name: "Result delimiter",
|
||||||
type: "binaryShortString",
|
type: "binaryShortString",
|
||||||
value: "\\n"
|
value: "\\n"
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Prevent eval",
|
|
||||||
type: "boolean",
|
|
||||||
value: true,
|
|
||||||
description: "Evaluated expressions are disabled by default for security reasons"
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -51,7 +45,7 @@ class JPathExpression extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const [query, delimiter, preventEval] = args;
|
const [query, delimiter] = args;
|
||||||
let results, jsonObj;
|
let results, jsonObj;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -63,8 +57,7 @@ class JPathExpression extends Operation {
|
||||||
try {
|
try {
|
||||||
results = JSONPath({
|
results = JSONPath({
|
||||||
path: query,
|
path: query,
|
||||||
json: jsonObj,
|
json: jsonObj
|
||||||
preventEval: preventEval
|
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Invalid JPath expression: ${err.message}`);
|
throw new OperationError(`Invalid JPath expression: ${err.message}`);
|
||||||
|
|
80
src/core/operations/JWKToPem.mjs
Normal file
80
src/core/operations/JWKToPem.mjs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEM to JWK operation
|
||||||
|
*/
|
||||||
|
class PEMToJWK extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEMToJWK constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "JWK to PEM";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Converts Keys in JSON Web Key format to PEM format (PKCS#8).";
|
||||||
|
this.infoURL = "https://datatracker.ietf.org/doc/html/rfc7517";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
"pattern": "\"kty\":\\s*\"(EC|RSA)\"",
|
||||||
|
"flags": "gm",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const inputJson = JSON.parse(input);
|
||||||
|
|
||||||
|
let keys = [];
|
||||||
|
if (Array.isArray(inputJson)) {
|
||||||
|
// list of keys => transform all keys
|
||||||
|
keys = inputJson;
|
||||||
|
} else if (Array.isArray(inputJson.keys)) {
|
||||||
|
// JSON Web Key Set => transform all keys
|
||||||
|
keys = inputJson.keys;
|
||||||
|
} else if (typeof inputJson === "object") {
|
||||||
|
// single key
|
||||||
|
keys.push(inputJson);
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Input is not a JSON Web Key");
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = "";
|
||||||
|
for (let i=0; i<keys.length; i++) {
|
||||||
|
const jwk = keys[i];
|
||||||
|
if (typeof jwk.kty !== "string") {
|
||||||
|
throw new OperationError("Invalid JWK format");
|
||||||
|
} else if ("|RSA|EC|".indexOf(jwk.kty) === -1) {
|
||||||
|
throw new OperationError(`Unsupported JWK key type '${inputJson.kty}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = r.KEYUTIL.getKey(jwk);
|
||||||
|
const pem = key.isPrivate ? r.KEYUTIL.getPEM(key, "PKCS8PRV") : r.KEYUTIL.getPEM(key);
|
||||||
|
|
||||||
|
// PEM ends with '\n', so a new key always starts on a new line
|
||||||
|
output += pem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PEMToJWK;
|
|
@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalise Image operation
|
* Normalise Image operation
|
||||||
|
@ -43,7 +43,7 @@ class NormaliseImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error opening image file. (${err})`);
|
throw new OperationError(`Error opening image file. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,9 @@ class NormaliseImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -12,9 +12,10 @@ import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
|
|
||||||
import process from "process";
|
|
||||||
import { createWorker } from "tesseract.js";
|
import { createWorker } from "tesseract.js";
|
||||||
|
|
||||||
|
const OEM_MODES = ["Tesseract only", "LSTM only", "Tesseract/LSTM Combined"];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optical Character Recognition operation
|
* Optical Character Recognition operation
|
||||||
*/
|
*/
|
||||||
|
@ -37,6 +38,12 @@ class OpticalCharacterRecognition extends Operation {
|
||||||
name: "Show confidence",
|
name: "Show confidence",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: true
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OCR Engine Mode",
|
||||||
|
type: "option",
|
||||||
|
value: OEM_MODES,
|
||||||
|
defaultIndex: 1
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -47,7 +54,7 @@ class OpticalCharacterRecognition extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [showConfidence] = args;
|
const [showConfidence, oemChoice] = args;
|
||||||
|
|
||||||
if (!isWorkerEnvironment()) throw new OperationError("This operation only works in a browser");
|
if (!isWorkerEnvironment()) throw new OperationError("This operation only works in a browser");
|
||||||
|
|
||||||
|
@ -56,12 +63,13 @@ class OpticalCharacterRecognition extends Operation {
|
||||||
throw new OperationError("Unsupported file type (supported: jpg,png,pbm,bmp) or no file provided");
|
throw new OperationError("Unsupported file type (supported: jpg,png,pbm,bmp) or no file provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
const assetDir = isWorkerEnvironment() ? `${self.docURL}/assets/` : `${process.cwd()}/src/core/vendor/`;
|
const assetDir = `${self.docURL}/assets/`;
|
||||||
|
const oem = OEM_MODES.indexOf(oemChoice);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self.sendStatusMessage("Spinning up Tesseract worker...");
|
self.sendStatusMessage("Spinning up Tesseract worker...");
|
||||||
const image = `data:${type};base64,${toBase64(input)}`;
|
const image = `data:${type};base64,${toBase64(input)}`;
|
||||||
const worker = createWorker({
|
const worker = await createWorker("eng", oem, {
|
||||||
workerPath: `${assetDir}tesseract/worker.min.js`,
|
workerPath: `${assetDir}tesseract/worker.min.js`,
|
||||||
langPath: `${assetDir}tesseract/lang-data`,
|
langPath: `${assetDir}tesseract/lang-data`,
|
||||||
corePath: `${assetDir}tesseract/tesseract-core.wasm.js`,
|
corePath: `${assetDir}tesseract/tesseract-core.wasm.js`,
|
||||||
|
@ -71,11 +79,6 @@ class OpticalCharacterRecognition extends Operation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await worker.load();
|
|
||||||
self.sendStatusMessage(`Loading English language pack...`);
|
|
||||||
await worker.loadLanguage("eng");
|
|
||||||
self.sendStatusMessage("Intialising Tesseract API...");
|
|
||||||
await worker.initialize("eng");
|
|
||||||
self.sendStatusMessage("Finding text...");
|
self.sendStatusMessage("Finding text...");
|
||||||
const result = await worker.recognize(image);
|
const result = await worker.recognize(image);
|
||||||
|
|
||||||
|
|
88
src/core/operations/PEMToJWK.mjs
Normal file
88
src/core/operations/PEMToJWK.mjs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEM to JWK operation
|
||||||
|
*/
|
||||||
|
class PEMToJWK extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEMToJWK constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "PEM to JWK";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Converts Keys in PEM format to a JSON Web Key format.";
|
||||||
|
this.infoURL = "https://datatracker.ietf.org/doc/html/rfc7517";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
"pattern": "-----BEGIN ((RSA |EC )?(PRIVATE|PUBLIC) KEY|CERTIFICATE)-----",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
let output = "";
|
||||||
|
let match;
|
||||||
|
const regex = /-----BEGIN ([A-Z][A-Z ]+[A-Z])-----/g;
|
||||||
|
while ((match = regex.exec(input)) !== null) {
|
||||||
|
// find corresponding end tag
|
||||||
|
const indexBase64 = match.index + match[0].length;
|
||||||
|
const header = input.substring(match.index, indexBase64);
|
||||||
|
const footer = `-----END ${match[1]}-----`;
|
||||||
|
const indexFooter = input.indexOf(footer, indexBase64);
|
||||||
|
if (indexFooter === -1) {
|
||||||
|
throw new OperationError(`PEM footer '${footer}' not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pem = input.substring(match.index, indexFooter + footer.length);
|
||||||
|
if (match[1].indexOf("KEY") !== -1) {
|
||||||
|
if (header === "-----BEGIN RSA PUBLIC KEY-----") {
|
||||||
|
throw new OperationError("Unsupported RSA public key format. Only PKCS#8 is supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = r.KEYUTIL.getKey(pem);
|
||||||
|
if (key.type === "DSA") {
|
||||||
|
throw new OperationError("DSA keys are not supported for JWK");
|
||||||
|
}
|
||||||
|
const jwk = r.KEYUTIL.getJWKFromKey(key);
|
||||||
|
if (output.length > 0) {
|
||||||
|
output += "\n";
|
||||||
|
}
|
||||||
|
output += JSON.stringify(jwk);
|
||||||
|
} else if (match[1] === "CERTIFICATE") {
|
||||||
|
const cert = new r.X509();
|
||||||
|
cert.readCertPEM(pem);
|
||||||
|
const key = cert.getPublicKey();
|
||||||
|
const jwk = r.KEYUTIL.getJWKFromKey(key);
|
||||||
|
if (output.length > 0) {
|
||||||
|
output += "\n";
|
||||||
|
}
|
||||||
|
output += JSON.stringify(jwk);
|
||||||
|
} else {
|
||||||
|
throw new OperationError(`Unsupported PEM type '${match[1]}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PEMToJWK;
|
|
@ -4,8 +4,9 @@
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import forge from "node-forge";
|
import { formatDnObj } from "../lib/PublicKey.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,16 +31,6 @@ class ParseCSR extends Operation {
|
||||||
"name": "Input format",
|
"name": "Input format",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": ["PEM"]
|
"value": ["PEM"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Key type",
|
|
||||||
"type": "option",
|
|
||||||
"value": ["RSA"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Strict ASN.1 value lengths",
|
|
||||||
"type": "boolean",
|
|
||||||
"value": true
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.checks = [
|
this.checks = [
|
||||||
|
@ -61,73 +52,71 @@ class ParseCSR extends Operation {
|
||||||
return "No input";
|
return "No input";
|
||||||
}
|
}
|
||||||
|
|
||||||
const csr = forge.pki.certificationRequestFromPem(input, args[1]);
|
// Parse the CSR into JSON parameters
|
||||||
|
const csrParam = new r.KJUR.asn1.csr.CSRUtil.getParam(input);
|
||||||
|
|
||||||
// RSA algorithm is the only one supported for CSR in node-forge as of 1.3.1
|
return `Subject\n${formatDnObj(csrParam.subject, 2)}
|
||||||
return `Version: ${1 + csr.version} (0x${Utils.hex(csr.version)})
|
Public Key${formatSubjectPublicKey(csrParam.sbjpubkey)}
|
||||||
Subject${formatSubject(csr.subject)}
|
Signature${formatSignature(csrParam.sigalg, csrParam.sighex)}
|
||||||
Subject Alternative Names${formatSubjectAlternativeNames(csr)}
|
Requested Extensions${formatRequestedExtensions(csrParam)}`;
|
||||||
Public Key
|
|
||||||
Algorithm: RSA
|
|
||||||
Length: ${csr.publicKey.n.bitLength()} bits
|
|
||||||
Modulus: ${formatMultiLine(chop(csr.publicKey.n.toString(16).replace(/(..)/g, "$&:")))}
|
|
||||||
Exponent: ${csr.publicKey.e} (0x${Utils.hex(csr.publicKey.e)})
|
|
||||||
Signature
|
|
||||||
Algorithm: ${forge.pki.oids[csr.signatureOid]}
|
|
||||||
Signature: ${formatMultiLine(Utils.strToByteArray(csr.signature).map(b => Utils.hex(b)).join(":"))}
|
|
||||||
Extensions${formatExtensions(csr)}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format Subject of the request as a multi-line string
|
* Format signature of a CSR
|
||||||
* @param {*} subject CSR Subject
|
* @param {*} sigAlg string
|
||||||
* @returns Multi-line string describing Subject
|
* @param {*} sigHex string
|
||||||
|
* @returns Multi-line string describing CSR Signature
|
||||||
*/
|
*/
|
||||||
function formatSubject(subject) {
|
function formatSignature(sigAlg, sigHex) {
|
||||||
let out = "\n";
|
let out = `\n`;
|
||||||
|
|
||||||
for (const attribute of subject.attributes) {
|
out += ` Algorithm: ${sigAlg}\n`;
|
||||||
out += ` ${attribute.shortName} = ${attribute.value}\n`;
|
|
||||||
|
if (new RegExp("withdsa", "i").test(sigAlg)) {
|
||||||
|
const d = new r.KJUR.crypto.DSA();
|
||||||
|
const sigParam = d.parseASN1Signature(sigHex);
|
||||||
|
out += ` Signature:
|
||||||
|
R: ${formatHexOntoMultiLine(absBigIntToHex(sigParam[0]))}
|
||||||
|
S: ${formatHexOntoMultiLine(absBigIntToHex(sigParam[1]))}\n`;
|
||||||
|
} else if (new RegExp("withrsa", "i").test(sigAlg)) {
|
||||||
|
out += ` Signature: ${formatHexOntoMultiLine(sigHex)}\n`;
|
||||||
|
} else {
|
||||||
|
out += ` Signature: ${formatHexOntoMultiLine(ensureHexIsPositiveInTwosComplement(sigHex))}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return chop(out);
|
return chop(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format Subject Alternative Names from the name `subjectAltName` extension
|
* Format Subject Public Key from PEM encoded public key string
|
||||||
* @param {*} extension CSR object
|
* @param {*} publicKeyPEM string
|
||||||
* @returns Multi-line string describing Subject Alternative Names
|
* @returns Multi-line string describing Subject Public Key Info
|
||||||
*/
|
*/
|
||||||
function formatSubjectAlternativeNames(csr) {
|
function formatSubjectPublicKey(publicKeyPEM) {
|
||||||
let out = "\n";
|
let out = "\n";
|
||||||
|
|
||||||
for (const attribute of csr.attributes) {
|
const publicKey = r.KEYUTIL.getKey(publicKeyPEM);
|
||||||
for (const extension of attribute.extensions) {
|
if (publicKey instanceof r.RSAKey) {
|
||||||
if (extension.name === "subjectAltName") {
|
out += ` Algorithm: RSA
|
||||||
const names = [];
|
Length: ${publicKey.n.bitLength()} bits
|
||||||
for (const altName of extension.altNames) {
|
Modulus: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.n))}
|
||||||
switch (altName.type) {
|
Exponent: ${publicKey.e} (0x${Utils.hex(publicKey.e)})\n`;
|
||||||
case 1:
|
} else if (publicKey instanceof r.KJUR.crypto.ECDSA) {
|
||||||
names.push(`EMAIL: ${altName.value}`);
|
out += ` Algorithm: ECDSA
|
||||||
break;
|
Length: ${publicKey.ecparams.keylen} bits
|
||||||
case 2:
|
Pub: ${formatHexOntoMultiLine(publicKey.pubKeyHex)}
|
||||||
names.push(`DNS: ${altName.value}`);
|
ASN1 OID: ${r.KJUR.crypto.ECDSA.getName(publicKey.getShortNISTPCurveName())}
|
||||||
break;
|
NIST CURVE: ${publicKey.getShortNISTPCurveName()}\n`;
|
||||||
case 6:
|
} else if (publicKey instanceof r.KJUR.crypto.DSA) {
|
||||||
names.push(`URI: ${altName.value}`);
|
out += ` Algorithm: DSA
|
||||||
break;
|
Length: ${publicKey.p.toString(16).length * 4} bits
|
||||||
case 7:
|
Pub: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.y))}
|
||||||
names.push(`IP: ${altName.ip}`);
|
P: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.p))}
|
||||||
break;
|
Q: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.q))}
|
||||||
default:
|
G: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.g))}\n`;
|
||||||
names.push(`(unable to format type ${altName.type} name)\n`);
|
} else {
|
||||||
}
|
out += `unsupported public key algorithm\n`;
|
||||||
}
|
|
||||||
out += indent(2, names);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return chop(out);
|
return chop(out);
|
||||||
|
@ -135,45 +124,105 @@ function formatSubjectAlternativeNames(csr) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format known extensions of a CSR
|
* Format known extensions of a CSR
|
||||||
* @param {*} csr CSR object
|
* @param {*} csrParam object
|
||||||
* @returns Multi-line string describing attributes
|
* @returns Multi-line string describing CSR Requested Extensions
|
||||||
*/
|
*/
|
||||||
function formatExtensions(csr) {
|
function formatRequestedExtensions(csrParam) {
|
||||||
let out = "\n";
|
const formattedExtensions = new Array(4).fill("");
|
||||||
|
|
||||||
for (const attribute of csr.attributes) {
|
if (Object.hasOwn(csrParam, "extreq")) {
|
||||||
for (const extension of attribute.extensions) {
|
for (const extension of csrParam.extreq) {
|
||||||
// formatted separately
|
|
||||||
if (extension.name === "subjectAltName") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
out += ` ${extension.name}${(extension.critical ? " CRITICAL" : "")}:\n`;
|
|
||||||
let parts = [];
|
let parts = [];
|
||||||
switch (extension.name) {
|
switch (extension.extname) {
|
||||||
case "basicConstraints" :
|
case "basicConstraints" :
|
||||||
parts = describeBasicConstraints(extension);
|
parts = describeBasicConstraints(extension);
|
||||||
|
formattedExtensions[0] = ` Basic Constraints:${formatExtensionCriticalTag(extension)}\n${indent(4, parts)}`;
|
||||||
break;
|
break;
|
||||||
case "keyUsage" :
|
case "keyUsage" :
|
||||||
parts = describeKeyUsage(extension);
|
parts = describeKeyUsage(extension);
|
||||||
|
formattedExtensions[1] = ` Key Usage:${formatExtensionCriticalTag(extension)}\n${indent(4, parts)}`;
|
||||||
break;
|
break;
|
||||||
case "extKeyUsage" :
|
case "extKeyUsage" :
|
||||||
parts = describeExtendedKeyUsage(extension);
|
parts = describeExtendedKeyUsage(extension);
|
||||||
|
formattedExtensions[2] = ` Extended Key Usage:${formatExtensionCriticalTag(extension)}\n${indent(4, parts)}`;
|
||||||
|
break;
|
||||||
|
case "subjectAltName" :
|
||||||
|
parts = describeSubjectAlternativeName(extension);
|
||||||
|
formattedExtensions[3] = ` Subject Alternative Name:${formatExtensionCriticalTag(extension)}\n${indent(4, parts)}`;
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
parts = ["(unable to format extension)"];
|
parts = ["(unsuported extension)"];
|
||||||
|
formattedExtensions.push(` ${extension.extname}:${formatExtensionCriticalTag(extension)}\n${indent(4, parts)}`);
|
||||||
}
|
}
|
||||||
out += indent(4, parts);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let out = "\n";
|
||||||
|
|
||||||
|
formattedExtensions.forEach((formattedExtension) => {
|
||||||
|
if (formattedExtension !== undefined && formattedExtension !== null && formattedExtension.length !== 0) {
|
||||||
|
out += formattedExtension;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return chop(out);
|
return chop(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format extension critical tag
|
||||||
|
* @param {*} extension Object
|
||||||
|
* @returns String describing whether the extension is critical or not
|
||||||
|
*/
|
||||||
|
function formatExtensionCriticalTag(extension) {
|
||||||
|
return Object.hasOwn(extension, "critical") && extension.critical ? " critical" : "";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format hex string onto multiple lines
|
* Format string input as a comma separated hex string on multiple lines
|
||||||
|
* @param {*} hex String
|
||||||
|
* @returns Multi-line string describing the Hex input
|
||||||
|
*/
|
||||||
|
function formatHexOntoMultiLine(hex) {
|
||||||
|
if (hex.length % 2 !== 0) {
|
||||||
|
hex = "0" + hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatMultiLine(chop(hex.replace(/(..)/g, "$&:")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert BigInt to abs value in Hex
|
||||||
|
* @param {*} int BigInt
|
||||||
|
* @returns String representing absolute value in Hex
|
||||||
|
*/
|
||||||
|
function absBigIntToHex(int) {
|
||||||
|
int = int < 0n ? -int : int;
|
||||||
|
|
||||||
|
return ensureHexIsPositiveInTwosComplement(int.toString(16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure Hex String remains positive in 2's complement
|
||||||
|
* @param {*} hex String
|
||||||
|
* @returns Hex String ensuring value remains positive in 2's complement
|
||||||
|
*/
|
||||||
|
function ensureHexIsPositiveInTwosComplement(hex) {
|
||||||
|
if (hex.length % 2 !== 0) {
|
||||||
|
return "0" + hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepend 00 if most significant bit is 1 (sign bit)
|
||||||
|
if (hex.length >=2 && (parseInt(hex.substring(0, 2), 16) & 128)) {
|
||||||
|
hex = "00" + hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format string onto multiple lines
|
||||||
* @param {*} longStr
|
* @param {*} longStr
|
||||||
* @returns Hex string as a multi-line hex string
|
* @returns String as a multi-line string
|
||||||
*/
|
*/
|
||||||
function formatMultiLine(longStr) {
|
function formatMultiLine(longStr) {
|
||||||
const lines = [];
|
const lines = [];
|
||||||
|
@ -194,8 +243,8 @@ function formatMultiLine(longStr) {
|
||||||
function describeBasicConstraints(extension) {
|
function describeBasicConstraints(extension) {
|
||||||
const constraints = [];
|
const constraints = [];
|
||||||
|
|
||||||
constraints.push(`CA = ${extension.cA}`);
|
constraints.push(`CA = ${Object.hasOwn(extension, "cA") && extension.cA ? "true" : "false"}`);
|
||||||
if (extension.pathLenConstraint !== undefined) constraints.push(`PathLenConstraint = ${extension.pathLenConstraint}`);
|
if (Object.hasOwn(extension, "pathLen")) constraints.push(`PathLenConstraint = ${extension.pathLen}`);
|
||||||
|
|
||||||
return constraints;
|
return constraints;
|
||||||
}
|
}
|
||||||
|
@ -209,15 +258,27 @@ function describeBasicConstraints(extension) {
|
||||||
function describeKeyUsage(extension) {
|
function describeKeyUsage(extension) {
|
||||||
const usage = [];
|
const usage = [];
|
||||||
|
|
||||||
if (extension.digitalSignature) usage.push("Digital signature");
|
const kuIdentifierToName = {
|
||||||
if (extension.nonRepudiation) usage.push("Non-repudiation");
|
digitalSignature: "Digital Signature",
|
||||||
if (extension.keyEncipherment) usage.push("Key encipherment");
|
nonRepudiation: "Non-repudiation",
|
||||||
if (extension.dataEncipherment) usage.push("Data encipherment");
|
keyEncipherment: "Key encipherment",
|
||||||
if (extension.keyAgreement) usage.push("Key agreement");
|
dataEncipherment: "Data encipherment",
|
||||||
if (extension.keyCertSign) usage.push("Key certificate signing");
|
keyAgreement: "Key agreement",
|
||||||
if (extension.cRLSign) usage.push("CRL signing");
|
keyCertSign: "Key certificate signing",
|
||||||
if (extension.encipherOnly) usage.push("Encipher only");
|
cRLSign: "CRL signing",
|
||||||
if (extension.decipherOnly) usage.push("Decipher only");
|
encipherOnly: "Encipher Only",
|
||||||
|
decipherOnly: "Decipher Only",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Object.hasOwn(extension, "names")) {
|
||||||
|
extension.names.forEach((ku) => {
|
||||||
|
if (Object.hasOwn(kuIdentifierToName, ku)) {
|
||||||
|
usage.push(kuIdentifierToName[ku]);
|
||||||
|
} else {
|
||||||
|
usage.push(`unknown key usage (${ku})`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (usage.length === 0) usage.push("(none)");
|
if (usage.length === 0) usage.push("(none)");
|
||||||
|
|
||||||
|
@ -233,23 +294,79 @@ function describeKeyUsage(extension) {
|
||||||
function describeExtendedKeyUsage(extension) {
|
function describeExtendedKeyUsage(extension) {
|
||||||
const usage = [];
|
const usage = [];
|
||||||
|
|
||||||
if (extension.serverAuth) usage.push("TLS Web Server Authentication");
|
const ekuIdentifierToName = {
|
||||||
if (extension.clientAuth) usage.push("TLS Web Client Authentication");
|
"serverAuth": "TLS Web Server Authentication",
|
||||||
if (extension.codeSigning) usage.push("Code signing");
|
"clientAuth": "TLS Web Client Authentication",
|
||||||
if (extension.emailProtection) usage.push("E-mail Protection (S/MIME)");
|
"codeSigning": "Code signing",
|
||||||
if (extension.timeStamping) usage.push("Trusted Timestamping");
|
"emailProtection": "E-mail Protection (S/MIME)",
|
||||||
if (extension.msCodeInd) usage.push("Microsoft Individual Code Signing");
|
"timeStamping": "Trusted Timestamping",
|
||||||
if (extension.msCodeCom) usage.push("Microsoft Commercial Code Signing");
|
"1.3.6.1.4.1.311.2.1.21": "Microsoft Individual Code Signing", // msCodeInd
|
||||||
if (extension.msCTLSign) usage.push("Microsoft Trust List Signing");
|
"1.3.6.1.4.1.311.2.1.22": "Microsoft Commercial Code Signing", // msCodeCom
|
||||||
if (extension.msSGC) usage.push("Microsoft Server Gated Crypto");
|
"1.3.6.1.4.1.311.10.3.1": "Microsoft Trust List Signing", // msCTLSign
|
||||||
if (extension.msEFS) usage.push("Microsoft Encrypted File System");
|
"1.3.6.1.4.1.311.10.3.3": "Microsoft Server Gated Crypto", // msSGC
|
||||||
if (extension.nsSGC) usage.push("Netscape Server Gated Crypto");
|
"1.3.6.1.4.1.311.10.3.4": "Microsoft Encrypted File System", // msEFS
|
||||||
|
"1.3.6.1.4.1.311.20.2.2": "Microsoft Smartcard Login", // msSmartcardLogin
|
||||||
|
"2.16.840.1.113730.4.1": "Netscape Server Gated Crypto", // nsSGC
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Object.hasOwn(extension, "array")) {
|
||||||
|
extension.array.forEach((eku) => {
|
||||||
|
if (Object.hasOwn(ekuIdentifierToName, eku)) {
|
||||||
|
usage.push(ekuIdentifierToName[eku]);
|
||||||
|
} else {
|
||||||
|
usage.push(eku);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (usage.length === 0) usage.push("(none)");
|
if (usage.length === 0) usage.push("(none)");
|
||||||
|
|
||||||
return usage;
|
return usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format Subject Alternative Names from the name `subjectAltName` extension
|
||||||
|
* @see RFC 5280 4.2.1.6. Subject Alternative Name https://www.ietf.org/rfc/rfc5280.txt
|
||||||
|
* @param {*} extension object
|
||||||
|
* @returns Array of strings describing Subject Alternative Name extension
|
||||||
|
*/
|
||||||
|
function describeSubjectAlternativeName(extension) {
|
||||||
|
const names = [];
|
||||||
|
|
||||||
|
if (Object.hasOwn(extension, "extname") && extension.extname === "subjectAltName") {
|
||||||
|
if (Object.hasOwn(extension, "array")) {
|
||||||
|
for (const altName of extension.array) {
|
||||||
|
Object.keys(altName).forEach((key) => {
|
||||||
|
switch (key) {
|
||||||
|
case "rfc822":
|
||||||
|
names.push(`EMAIL: ${altName[key]}`);
|
||||||
|
break;
|
||||||
|
case "dns":
|
||||||
|
names.push(`DNS: ${altName[key]}`);
|
||||||
|
break;
|
||||||
|
case "uri":
|
||||||
|
names.push(`URI: ${altName[key]}`);
|
||||||
|
break;
|
||||||
|
case "ip":
|
||||||
|
names.push(`IP: ${altName[key]}`);
|
||||||
|
break;
|
||||||
|
case "dn":
|
||||||
|
names.push(`DIR: ${altName[key].str}`);
|
||||||
|
break;
|
||||||
|
case "other" :
|
||||||
|
names.push(`Other: ${altName[key].oid}::${altName[key].value.utf8str.str}`);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
names.push(`(unable to format SAN '${key}':${altName[key]})\n`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join an array of strings and add leading spaces to each line.
|
* Join an array of strings and add leading spaces to each line.
|
||||||
* @param {*} n How many leading spaces
|
* @param {*} n How many leading spaces
|
||||||
|
|
68
src/core/operations/PubKeyFromCert.mjs
Normal file
68
src/core/operations/PubKeyFromCert.mjs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2023
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public Key from Certificate operation
|
||||||
|
*/
|
||||||
|
class PubKeyFromCert extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PubKeyFromCert constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Public Key from Certificate";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Extracts the Public Key from a Certificate.";
|
||||||
|
this.infoURL = "https://en.wikipedia.org/wiki/X.509";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
this.checks = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
let output = "";
|
||||||
|
let match;
|
||||||
|
const regex = /-----BEGIN CERTIFICATE-----/g;
|
||||||
|
while ((match = regex.exec(input)) !== null) {
|
||||||
|
// find corresponding end tag
|
||||||
|
const indexBase64 = match.index + match[0].length;
|
||||||
|
const footer = "-----END CERTIFICATE-----";
|
||||||
|
const indexFooter = input.indexOf(footer, indexBase64);
|
||||||
|
if (indexFooter === -1) {
|
||||||
|
throw new OperationError(`PEM footer '${footer}' not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const certPem = input.substring(match.index, indexFooter + footer.length);
|
||||||
|
const cert = new r.X509();
|
||||||
|
cert.readCertPEM(certPem);
|
||||||
|
let pubKey;
|
||||||
|
try {
|
||||||
|
pubKey = cert.getPublicKey();
|
||||||
|
} catch {
|
||||||
|
throw new OperationError("Unsupported public key type");
|
||||||
|
}
|
||||||
|
const pubKeyPem = r.KEYUTIL.getPEM(pubKey);
|
||||||
|
|
||||||
|
// PEM ends with '\n', so a new key always starts on a new line
|
||||||
|
output += pubKeyPem;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PubKeyFromCert;
|
82
src/core/operations/PubKeyFromPrivKey.mjs
Normal file
82
src/core/operations/PubKeyFromPrivKey.mjs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/**
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2023
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import r from "jsrsasign";
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public Key from Private Key operation
|
||||||
|
*/
|
||||||
|
class PubKeyFromPrivKey extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PubKeyFromPrivKey constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Public Key from Private Key";
|
||||||
|
this.module = "PublicKey";
|
||||||
|
this.description = "Extracts the Public Key from a Private Key.";
|
||||||
|
this.infoURL = "https://en.wikipedia.org/wiki/PKCS_8";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
this.checks = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
let output = "";
|
||||||
|
let match;
|
||||||
|
const regex = /-----BEGIN ((RSA |EC |DSA )?PRIVATE KEY)-----/g;
|
||||||
|
while ((match = regex.exec(input)) !== null) {
|
||||||
|
// find corresponding end tag
|
||||||
|
const indexBase64 = match.index + match[0].length;
|
||||||
|
const footer = `-----END ${match[1]}-----`;
|
||||||
|
const indexFooter = input.indexOf(footer, indexBase64);
|
||||||
|
if (indexFooter === -1) {
|
||||||
|
throw new OperationError(`PEM footer '${footer}' not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const privKeyPem = input.substring(match.index, indexFooter + footer.length);
|
||||||
|
let privKey;
|
||||||
|
try {
|
||||||
|
privKey = r.KEYUTIL.getKey(privKeyPem);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Unsupported key type: ${err}`);
|
||||||
|
}
|
||||||
|
let pubKey;
|
||||||
|
if (privKey.type && privKey.type === "EC") {
|
||||||
|
pubKey = new r.KJUR.crypto.ECDSA({ curve: privKey.curve });
|
||||||
|
pubKey.setPublicKeyHex(privKey.generatePublicKeyHex());
|
||||||
|
} else if (privKey.type && privKey.type === "DSA") {
|
||||||
|
if (!privKey.y) {
|
||||||
|
throw new OperationError(`DSA Private Key in PKCS#8 is not supported`);
|
||||||
|
}
|
||||||
|
pubKey = new r.KJUR.crypto.DSA();
|
||||||
|
pubKey.setPublic(privKey.p, privKey.q, privKey.g, privKey.y);
|
||||||
|
} else if (privKey.n && privKey.e) {
|
||||||
|
pubKey = new r.RSAKey();
|
||||||
|
pubKey.setPublic(privKey.n, privKey.e);
|
||||||
|
} else {
|
||||||
|
throw new OperationError(`Unsupported key type`);
|
||||||
|
}
|
||||||
|
const pubKeyPem = r.KEYUTIL.getPEM(pubKey);
|
||||||
|
|
||||||
|
// PEM ends with '\n', so a new key always starts on a new line
|
||||||
|
output += pubKeyPem;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PubKeyFromPrivKey;
|
|
@ -101,22 +101,17 @@ class RAKE extends Operation {
|
||||||
phrases = phrases.filter(subArray => subArray.length > 0);
|
phrases = phrases.filter(subArray => subArray.length > 0);
|
||||||
|
|
||||||
// Remove duplicate phrases
|
// Remove duplicate phrases
|
||||||
const uniquePhrases = [...new Set(phrases.map(function (phrase) {
|
phrases = phrases.unique();
|
||||||
return phrase.join(" ");
|
|
||||||
}))];
|
|
||||||
phrases = uniquePhrases.map(function (phrase) {
|
|
||||||
return phrase.split(" ");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate word_degree_matrix and populate
|
// Generate word_degree_matrix and populate
|
||||||
const wordDegreeMatrix = Array.from(Array(tokens.length), _ => Array(tokens.length).fill(0));
|
const wordDegreeMatrix = Array(tokens.length).fill().map(() => Array(tokens.length).fill(0));
|
||||||
phrases.forEach(function (phrase) {
|
for (const phrase of phrases) {
|
||||||
phrase.forEach(function (word1) {
|
for (const word1 of phrase) {
|
||||||
phrase.forEach(function (word2) {
|
for (const word2 of phrase) {
|
||||||
wordDegreeMatrix[tokens.indexOf(word1)][tokens.indexOf(word2)]++;
|
wordDegreeMatrix[tokens.indexOf(word1)][tokens.indexOf(word2)]++;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// Calculate degree score for each token
|
// Calculate degree score for each token
|
||||||
const degreeScores = Array(tokens.length).fill(0);
|
const degreeScores = Array(tokens.length).fill(0);
|
||||||
|
|
|
@ -10,7 +10,7 @@ import Utils from "../Utils.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { runHash } from "../lib/Hash.mjs";
|
import { runHash } from "../lib/Hash.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Randomize Colour Palette operation
|
* Randomize Colour Palette operation
|
||||||
|
@ -48,7 +48,7 @@ class RandomizeColourPalette extends Operation {
|
||||||
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
||||||
|
|
||||||
const seed = args[0] || (Math.random().toString().substr(2)),
|
const seed = args[0] || (Math.random().toString().substr(2)),
|
||||||
parsedImage = await jimp.read(input),
|
parsedImage = await Jimp.read(input),
|
||||||
width = parsedImage.bitmap.width,
|
width = parsedImage.bitmap.width,
|
||||||
height = parsedImage.bitmap.height;
|
height = parsedImage.bitmap.height;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class RandomizeColourPalette extends Operation {
|
||||||
parsedImage.setPixelColor(parseInt(rgbHex, 16), x, y);
|
parsedImage.setPixelColor(parseInt(rgbHex, 16), x, y);
|
||||||
});
|
});
|
||||||
|
|
||||||
const imageBuffer = await parsedImage.getBufferAsync(jimp.AUTO);
|
const imageBuffer = await parsedImage.getBufferAsync(Jimp.AUTO);
|
||||||
|
|
||||||
return new Uint8Array(imageBuffer).buffer;
|
return new Uint8Array(imageBuffer).buffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize Image operation
|
* Resize Image operation
|
||||||
|
@ -80,11 +80,11 @@ class ResizeImage extends Operation {
|
||||||
resizeAlg = args[4];
|
resizeAlg = args[4];
|
||||||
|
|
||||||
const resizeMap = {
|
const resizeMap = {
|
||||||
"Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR,
|
"Nearest Neighbour": Jimp.RESIZE_NEAREST_NEIGHBOR,
|
||||||
"Bilinear": jimp.RESIZE_BILINEAR,
|
"Bilinear": Jimp.RESIZE_BILINEAR,
|
||||||
"Bicubic": jimp.RESIZE_BICUBIC,
|
"Bicubic": Jimp.RESIZE_BICUBIC,
|
||||||
"Hermite": jimp.RESIZE_HERMITE,
|
"Hermite": Jimp.RESIZE_HERMITE,
|
||||||
"Bezier": jimp.RESIZE_BEZIER
|
"Bezier": Jimp.RESIZE_BEZIER
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isImage(input)) {
|
if (!isImage(input)) {
|
||||||
|
@ -93,7 +93,7 @@ class ResizeImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -113,9 +113,9 @@ class ResizeImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotate Image operation
|
* Rotate Image operation
|
||||||
|
@ -52,7 +52,7 @@ class RotateImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,9 @@ class RotateImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -40,7 +40,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "1st cipher rotor intial value",
|
name: "1st cipher rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -56,7 +56,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "2nd cipher rotor intial value",
|
name: "2nd cipher rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -72,7 +72,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "3rd cipher rotor intial value",
|
name: "3rd cipher rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -88,7 +88,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "4th cipher rotor intial value",
|
name: "4th cipher rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -104,7 +104,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "5th cipher rotor intial value",
|
name: "5th cipher rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -120,7 +120,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "1st control rotor intial value",
|
name: "1st control rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -136,7 +136,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "2nd control rotor intial value",
|
name: "2nd control rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -152,7 +152,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "3rd control rotor intial value",
|
name: "3rd control rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -168,7 +168,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "4th control rotor intial value",
|
name: "4th control rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -184,7 +184,7 @@ class Sigaba extends Operation {
|
||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "5th control rotor intial value",
|
name: "5th control rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: LETTERS
|
value: LETTERS
|
||||||
},
|
},
|
||||||
|
@ -195,7 +195,7 @@ class Sigaba extends Operation {
|
||||||
defaultIndex: 0
|
defaultIndex: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "1st index rotor intial value",
|
name: "1st index rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: NUMBERS
|
value: NUMBERS
|
||||||
},
|
},
|
||||||
|
@ -206,7 +206,7 @@ class Sigaba extends Operation {
|
||||||
defaultIndex: 0
|
defaultIndex: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "2nd index rotor intial value",
|
name: "2nd index rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: NUMBERS
|
value: NUMBERS
|
||||||
},
|
},
|
||||||
|
@ -217,7 +217,7 @@ class Sigaba extends Operation {
|
||||||
defaultIndex: 0
|
defaultIndex: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "3rd index rotor intial value",
|
name: "3rd index rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: NUMBERS
|
value: NUMBERS
|
||||||
},
|
},
|
||||||
|
@ -228,7 +228,7 @@ class Sigaba extends Operation {
|
||||||
defaultIndex: 0
|
defaultIndex: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "4th index rotor intial value",
|
name: "4th index rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: NUMBERS
|
value: NUMBERS
|
||||||
},
|
},
|
||||||
|
@ -239,7 +239,7 @@ class Sigaba extends Operation {
|
||||||
defaultIndex: 0
|
defaultIndex: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "5th index rotor intial value",
|
name: "5th index rotor initial value",
|
||||||
type: "option",
|
type: "option",
|
||||||
value: NUMBERS
|
value: NUMBERS
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sharpen Image operation
|
* Sharpen Image operation
|
||||||
|
@ -68,7 +68,7 @@ class SharpenImage extends Operation {
|
||||||
|
|
||||||
let image;
|
let image;
|
||||||
try {
|
try {
|
||||||
image = await jimp.read(input);
|
image = await Jimp.read(input);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Error loading image. (${err})`);
|
throw new OperationError(`Error loading image. (${err})`);
|
||||||
}
|
}
|
||||||
|
@ -137,9 +137,9 @@ class SharpenImage extends Operation {
|
||||||
|
|
||||||
let imageBuffer;
|
let imageBuffer;
|
||||||
if (image.getMIME() === "image/gif") {
|
if (image.getMIME() === "image/gif") {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||||
} else {
|
} else {
|
||||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||||
}
|
}
|
||||||
return imageBuffer.buffer;
|
return imageBuffer.buffer;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import {isImage} from "../lib/FileType.mjs";
|
import {isImage} from "../lib/FileType.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split Colour Channels operation
|
* Split Colour Channels operation
|
||||||
|
@ -41,7 +41,7 @@ class SplitColourChannels extends Operation {
|
||||||
// Make sure that the input is an image
|
// Make sure that the input is an image
|
||||||
if (!isImage(input)) throw new OperationError("Invalid file type.");
|
if (!isImage(input)) throw new OperationError("Invalid file type.");
|
||||||
|
|
||||||
const parsedImage = await jimp.read(Buffer.from(input));
|
const parsedImage = await Jimp.read(Buffer.from(input));
|
||||||
|
|
||||||
const red = new Promise(async (resolve, reject) => {
|
const red = new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
|
@ -51,7 +51,7 @@ class SplitColourChannels extends Operation {
|
||||||
{apply: "blue", params: [-255]},
|
{apply: "blue", params: [-255]},
|
||||||
{apply: "green", params: [-255]}
|
{apply: "green", params: [-255]}
|
||||||
])
|
])
|
||||||
.getBufferAsync(jimp.MIME_PNG);
|
.getBufferAsync(Jimp.MIME_PNG);
|
||||||
resolve(new File([new Uint8Array((await split).values())], "red.png", {type: "image/png"}));
|
resolve(new File([new Uint8Array((await split).values())], "red.png", {type: "image/png"}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(new OperationError(`Could not split red channel: ${err}`));
|
reject(new OperationError(`Could not split red channel: ${err}`));
|
||||||
|
@ -64,7 +64,7 @@ class SplitColourChannels extends Operation {
|
||||||
.color([
|
.color([
|
||||||
{apply: "red", params: [-255]},
|
{apply: "red", params: [-255]},
|
||||||
{apply: "blue", params: [-255]},
|
{apply: "blue", params: [-255]},
|
||||||
]).getBufferAsync(jimp.MIME_PNG);
|
]).getBufferAsync(Jimp.MIME_PNG);
|
||||||
resolve(new File([new Uint8Array((await split).values())], "green.png", {type: "image/png"}));
|
resolve(new File([new Uint8Array((await split).values())], "green.png", {type: "image/png"}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(new OperationError(`Could not split green channel: ${err}`));
|
reject(new OperationError(`Could not split green channel: ${err}`));
|
||||||
|
@ -77,7 +77,7 @@ class SplitColourChannels extends Operation {
|
||||||
.color([
|
.color([
|
||||||
{apply: "red", params: [-255]},
|
{apply: "red", params: [-255]},
|
||||||
{apply: "green", params: [-255]},
|
{apply: "green", params: [-255]},
|
||||||
]).getBufferAsync(jimp.MIME_PNG);
|
]).getBufferAsync(Jimp.MIME_PNG);
|
||||||
resolve(new File([new Uint8Array((await split).values())], "blue.png", {type: "image/png"}));
|
resolve(new File([new Uint8Array((await split).values())], "blue.png", {type: "image/png"}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(new OperationError(`Could not split blue channel: ${err}`));
|
reject(new OperationError(`Could not split blue channel: ${err}`));
|
||||||
|
|
|
@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import jimp from "jimp";
|
import Jimp from "jimp/es/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View Bit Plane operation
|
* View Bit Plane operation
|
||||||
|
@ -52,7 +52,7 @@ class ViewBitPlane extends Operation {
|
||||||
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
||||||
|
|
||||||
const [colour, bit] = args,
|
const [colour, bit] = args,
|
||||||
parsedImage = await jimp.read(input),
|
parsedImage = await Jimp.read(input),
|
||||||
width = parsedImage.bitmap.width,
|
width = parsedImage.bitmap.width,
|
||||||
height = parsedImage.bitmap.height,
|
height = parsedImage.bitmap.height,
|
||||||
colourIndex = COLOUR_OPTIONS.indexOf(colour),
|
colourIndex = COLOUR_OPTIONS.indexOf(colour),
|
||||||
|
@ -78,7 +78,7 @@ class ViewBitPlane extends Operation {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const imageBuffer = await parsedImage.getBufferAsync(jimp.AUTO);
|
const imageBuffer = await parsedImage.getBufferAsync(Jimp.AUTO);
|
||||||
|
|
||||||
return new Uint8Array(imageBuffer).buffer;
|
return new Uint8Array(imageBuffer).buffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,12 +52,6 @@ class XPathExpression extends Operation {
|
||||||
try {
|
try {
|
||||||
doc = new xmldom.DOMParser({
|
doc = new xmldom.DOMParser({
|
||||||
errorHandler: {
|
errorHandler: {
|
||||||
warning(w) {
|
|
||||||
throw w;
|
|
||||||
},
|
|
||||||
error(e) {
|
|
||||||
throw e;
|
|
||||||
},
|
|
||||||
fatalError(e) {
|
fatalError(e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,182 +0,0 @@
|
||||||
/**
|
|
||||||
* @author devcydo [devcydo@gmail.com]
|
|
||||||
* @author Ma Bingyao [mabingyao@gmail.com]
|
|
||||||
* @copyright Crown Copyright 2022
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
|
||||||
import {toBase64} from "../lib/Base64.mjs";
|
|
||||||
import Utils from "../Utils.mjs";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XXTEA Encrypt operation
|
|
||||||
*/
|
|
||||||
class XXTEAEncrypt extends Operation {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XXTEAEncrypt constructor
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.name = "XXTEA";
|
|
||||||
this.module = "Default";
|
|
||||||
this.description = "Corrected Block TEA (often referred to as XXTEA) is a block cipher designed to correct weaknesses in the original Block TEA. XXTEA operates on variable-length blocks that are some arbitrary multiple of 32 bits in size (minimum 64 bits). The number of full cycles depends on the block size, but there are at least six (rising to 32 for small block sizes). The original Block TEA applies the XTEA round function to each word in the block and combines it additively with its leftmost neighbour. Slow diffusion rate of the decryption process was immediately exploited to break the cipher. Corrected Block TEA uses a more involved round function which makes use of both immediate neighbours in processing each word in the block.";
|
|
||||||
this.infoURL = "https://wikipedia.org/wiki/XXTEA";
|
|
||||||
this.inputType = "string";
|
|
||||||
this.outputType = "string";
|
|
||||||
this.args = [
|
|
||||||
{
|
|
||||||
"name": "Key",
|
|
||||||
"type": "string",
|
|
||||||
"value": "",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
run(input, args) {
|
|
||||||
let key = args[0];
|
|
||||||
|
|
||||||
if (input === undefined || input === null || input.length === 0) {
|
|
||||||
throw new OperationError("Invalid input length (0)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === undefined || key === null || key.length === 0) {
|
|
||||||
throw new OperationError("Invalid key length (0)");
|
|
||||||
}
|
|
||||||
|
|
||||||
input = Utils.convertToByteString(input, "utf8");
|
|
||||||
key = Utils.convertToByteString(key, "utf8");
|
|
||||||
|
|
||||||
input = this.convertToUint32Array(input, true);
|
|
||||||
key = this.fixLength(this.convertToUint32Array(key, false));
|
|
||||||
|
|
||||||
let encrypted = this.encryptUint32Array(input, key);
|
|
||||||
|
|
||||||
encrypted = toBase64(this.toBinaryString(encrypted, false));
|
|
||||||
|
|
||||||
return encrypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert Uint32Array to binary string
|
|
||||||
*
|
|
||||||
* @param {Uint32Array} v
|
|
||||||
* @param {Boolean} includeLength
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
toBinaryString(v, includeLENGTH) {
|
|
||||||
const LENGTH = v.length;
|
|
||||||
let n = LENGTH << 2;
|
|
||||||
if (includeLENGTH) {
|
|
||||||
const M = v[LENGTH - 1];
|
|
||||||
n -= 4;
|
|
||||||
if ((M < n - 3) || (M > n)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
n = M;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < LENGTH; i++) {
|
|
||||||
v[i] = String.fromCharCode(
|
|
||||||
v[i] & 0xFF,
|
|
||||||
v[i] >>> 8 & 0xFF,
|
|
||||||
v[i] >>> 16 & 0xFF,
|
|
||||||
v[i] >>> 24 & 0xFF
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const RESULT = v.join("");
|
|
||||||
if (includeLENGTH) {
|
|
||||||
return RESULT.substring(0, n);
|
|
||||||
}
|
|
||||||
return RESULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} sum
|
|
||||||
* @param {number} y
|
|
||||||
* @param {number} z
|
|
||||||
* @param {number} p
|
|
||||||
* @param {number} e
|
|
||||||
* @param {number} k
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
mx(sum, y, z, p, e, k) {
|
|
||||||
return ((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypt Uint32Array
|
|
||||||
*
|
|
||||||
* @param {Uint32Array} v
|
|
||||||
* @param {number} k
|
|
||||||
* @returns {Uint32Array}
|
|
||||||
*/
|
|
||||||
encryptUint32Array(v, k) {
|
|
||||||
const LENGTH = v.length;
|
|
||||||
const N = LENGTH - 1;
|
|
||||||
let y, z, sum, e, p, q;
|
|
||||||
z = v[N];
|
|
||||||
sum = 0;
|
|
||||||
for (q = Math.floor(6 + 52 / LENGTH) | 0; q > 0; --q) {
|
|
||||||
sum = (sum + 0x9E3779B9) & 0xFFFFFFFF;
|
|
||||||
e = sum >>> 2 & 3;
|
|
||||||
for (p = 0; p < N; ++p) {
|
|
||||||
y = v[p + 1];
|
|
||||||
z = v[p] = (v[p] + this.mx(sum, y, z, p, e, k)) & 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
y = v[0];
|
|
||||||
z = v[N] = (v[N] + this.mx(sum, y, z, N, e, k)) & 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fixes the Uint32Array lenght to 4
|
|
||||||
*
|
|
||||||
* @param {Uint32Array} k
|
|
||||||
* @returns {Uint32Array}
|
|
||||||
*/
|
|
||||||
fixLength(k) {
|
|
||||||
if (k.length < 4) {
|
|
||||||
k.length = 4;
|
|
||||||
}
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert string to Uint32Array
|
|
||||||
*
|
|
||||||
* @param {string} bs
|
|
||||||
* @param {Boolean} includeLength
|
|
||||||
* @returns {Uint32Array}
|
|
||||||
*/
|
|
||||||
convertToUint32Array(bs, includeLength) {
|
|
||||||
const LENGTH = bs.length;
|
|
||||||
let n = LENGTH >> 2;
|
|
||||||
if ((LENGTH & 3) !== 0) {
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
let v;
|
|
||||||
if (includeLength) {
|
|
||||||
v = new Array(n + 1);
|
|
||||||
v[n] = LENGTH;
|
|
||||||
} else {
|
|
||||||
v = new Array(n);
|
|
||||||
}
|
|
||||||
for (let i = 0; i < LENGTH; ++i) {
|
|
||||||
v[i >> 2] |= bs.charCodeAt(i) << ((i & 3) << 3);
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default XXTEAEncrypt;
|
|
57
src/core/operations/XXTEADecrypt.mjs
Normal file
57
src/core/operations/XXTEADecrypt.mjs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* @author devcydo [devcydo@gmail.com]
|
||||||
|
* @author Ma Bingyao [mabingyao@gmail.com]
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import {decrypt} from "../lib/XXTEA.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XXTEA Decrypt operation
|
||||||
|
*/
|
||||||
|
class XXTEADecrypt extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XXTEADecrypt constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "XXTEA Decrypt";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "Corrected Block TEA (often referred to as XXTEA) is a block cipher designed to correct weaknesses in the original Block TEA. XXTEA operates on variable-length blocks that are some arbitrary multiple of 32 bits in size (minimum 64 bits). The number of full cycles depends on the block size, but there are at least six (rising to 32 for small block sizes). The original Block TEA applies the XTEA round function to each word in the block and combines it additively with its leftmost neighbour. Slow diffusion rate of the decryption process was immediately exploited to break the cipher. Corrected Block TEA uses a more involved round function which makes use of both immediate neighbours in processing each word in the block.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/XXTEA";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Key",
|
||||||
|
"type": "toggleString",
|
||||||
|
"value": "",
|
||||||
|
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const key = new Uint8Array(Utils.convertToByteArray(args[0].string, args[0].option));
|
||||||
|
try {
|
||||||
|
return decrypt(new Uint8Array(input), key).buffer;
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError("Unable to decrypt using this key");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default XXTEADecrypt;
|
52
src/core/operations/XXTEAEncrypt.mjs
Normal file
52
src/core/operations/XXTEAEncrypt.mjs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* @author devcydo [devcydo@gmail.com]
|
||||||
|
* @author Ma Bingyao [mabingyao@gmail.com]
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import {encrypt} from "../lib/XXTEA.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XXTEA Encrypt operation
|
||||||
|
*/
|
||||||
|
class XXTEAEncrypt extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XXTEAEncrypt constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "XXTEA Encrypt";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = "Corrected Block TEA (often referred to as XXTEA) is a block cipher designed to correct weaknesses in the original Block TEA. XXTEA operates on variable-length blocks that are some arbitrary multiple of 32 bits in size (minimum 64 bits). The number of full cycles depends on the block size, but there are at least six (rising to 32 for small block sizes). The original Block TEA applies the XTEA round function to each word in the block and combines it additively with its leftmost neighbour. Slow diffusion rate of the decryption process was immediately exploited to break the cipher. Corrected Block TEA uses a more involved round function which makes use of both immediate neighbours in processing each word in the block.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/XXTEA";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Key",
|
||||||
|
"type": "toggleString",
|
||||||
|
"value": "",
|
||||||
|
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const key = new Uint8Array(Utils.convertToByteArray(args[0].string, args[0].option));
|
||||||
|
return encrypt(new Uint8Array(input), key).buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default XXTEAEncrypt;
|
4
src/core/vendor/DisassembleX86-64.mjs
vendored
4
src/core/vendor/DisassembleX86-64.mjs
vendored
|
@ -3199,7 +3199,7 @@ const REG = [
|
||||||
REG index 10 Intel MM qword technology MMX vector instructions.
|
REG index 10 Intel MM qword technology MMX vector instructions.
|
||||||
---------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
These can not be used with Vector length adjustment used in vector extensions. The MM register are the ST registers aliased
|
These can not be used with Vector length adjustment used in vector extensions. The MM register are the ST registers aliased
|
||||||
to MM register. Instructions that use these registers use the the SIMD vector unit registers (MM), these are called the old
|
to MM register. Instructions that use these registers use the SIMD vector unit registers (MM), these are called the old
|
||||||
MMX vector instructions. When Intel added the SSE instructions to the SIMD math vector unit the new 128 bit XMM registers,
|
MMX vector instructions. When Intel added the SSE instructions to the SIMD math vector unit the new 128 bit XMM registers,
|
||||||
are added into the SIMD unit then they ware made longer in size 256, then 512 across in length, with 1024 (?MM Reserved)
|
are added into the SIMD unit then they ware made longer in size 256, then 512 across in length, with 1024 (?MM Reserved)
|
||||||
In which the vector length setting was added to control there size though vector setting adjustment codes. Instruction
|
In which the vector length setting was added to control there size though vector setting adjustment codes. Instruction
|
||||||
|
@ -3784,7 +3784,7 @@ function GotoPosition( Address )
|
||||||
/*-------------------------------------------------------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------------------------------------------------------
|
||||||
Finds bit positions to the Size attribute indexes in REG array, and the Pointer Array. For the Size Attribute variations.
|
Finds bit positions to the Size attribute indexes in REG array, and the Pointer Array. For the Size Attribute variations.
|
||||||
---------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------------
|
||||||
The SizeAttribute settings is 8 digits big consisting of 1, or 0 to specify the the extended size that an operand can be made.
|
The SizeAttribute settings is 8 digits big consisting of 1, or 0 to specify the extended size that an operand can be made.
|
||||||
In which an value of 01100100 is decoded as "0 = 1024, 1 = 512, 1 = 256, 0 = 128, 0 = 64, 1 = 32, 0 = 16, 0 = 8".
|
In which an value of 01100100 is decoded as "0 = 1024, 1 = 512, 1 = 256, 0 = 128, 0 = 64, 1 = 32, 0 = 16, 0 = 8".
|
||||||
In which the largest bit position is 512, and is the 6th number "0 = 7, 1 = 6, 1 = 5, 0 = 4, 0 = 3, 1 = 2, 0 = 1, 0 = 0".
|
In which the largest bit position is 512, and is the 6th number "0 = 7, 1 = 6, 1 = 5, 0 = 4, 0 = 3, 1 = 2, 0 = 1, 0 = 0".
|
||||||
In which 6 is the bit position for 512 as the returned Size . Each size is in order from 0 to 7, thus the size given back
|
In which 6 is the bit position for 512 as the returned Size . Each size is in order from 0 to 7, thus the size given back
|
||||||
|
|
|
@ -39,7 +39,6 @@ class App {
|
||||||
|
|
||||||
this.baking = false;
|
this.baking = false;
|
||||||
this.autoBake_ = false;
|
this.autoBake_ = false;
|
||||||
this.autoBakePause = false;
|
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
this.ingId = 0;
|
this.ingId = 0;
|
||||||
|
|
||||||
|
@ -155,12 +154,12 @@ class App {
|
||||||
* Runs Auto Bake if it is set.
|
* Runs Auto Bake if it is set.
|
||||||
*/
|
*/
|
||||||
autoBake() {
|
autoBake() {
|
||||||
// If autoBakePause is set, we are loading a full recipe (and potentially input), so there is no
|
if (this.baking) {
|
||||||
// need to set the staleness indicator. Just exit and wait until auto bake is called after loading
|
this.manager.worker.cancelBakeForAutoBake();
|
||||||
// has completed.
|
this.baking = false;
|
||||||
if (this.autoBakePause) return false;
|
}
|
||||||
|
|
||||||
if (this.autoBake_ && !this.baking) {
|
if (this.autoBake_) {
|
||||||
log.debug("Auto-baking");
|
log.debug("Auto-baking");
|
||||||
this.manager.worker.bakeInputs({
|
this.manager.worker.bakeInputs({
|
||||||
nums: [this.manager.tabs.getActiveTab("input")],
|
nums: [this.manager.tabs.getActiveTab("input")],
|
||||||
|
@ -473,7 +472,6 @@ class App {
|
||||||
* @fires Manager#statechange
|
* @fires Manager#statechange
|
||||||
*/
|
*/
|
||||||
loadURIParams(params=this.getURIParams()) {
|
loadURIParams(params=this.getURIParams()) {
|
||||||
this.autoBakePause = true;
|
|
||||||
this.uriParams = params;
|
this.uriParams = params;
|
||||||
|
|
||||||
// Read in recipe from URI params
|
// Read in recipe from URI params
|
||||||
|
@ -502,7 +500,7 @@ class App {
|
||||||
// Input Character Encoding
|
// Input Character Encoding
|
||||||
// Must be set before the input is loaded
|
// Must be set before the input is loaded
|
||||||
if (this.uriParams.ienc) {
|
if (this.uriParams.ienc) {
|
||||||
this.manager.input.chrEncChange(parseInt(this.uriParams.ienc, 10), true);
|
this.manager.input.chrEncChange(parseInt(this.uriParams.ienc, 10), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output Character Encoding
|
// Output Character Encoding
|
||||||
|
@ -540,7 +538,6 @@ class App {
|
||||||
this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme));
|
this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.autoBakePause = false;
|
|
||||||
window.dispatchEvent(this.manager.statechange);
|
window.dispatchEvent(this.manager.statechange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,10 +571,6 @@ class App {
|
||||||
setRecipeConfig(recipeConfig) {
|
setRecipeConfig(recipeConfig) {
|
||||||
document.getElementById("rec-list").innerHTML = null;
|
document.getElementById("rec-list").innerHTML = null;
|
||||||
|
|
||||||
// Pause auto-bake while loading but don't modify `this.autoBake_`
|
|
||||||
// otherwise `manualBake` cannot trigger.
|
|
||||||
this.autoBakePause = true;
|
|
||||||
|
|
||||||
for (let i = 0; i < recipeConfig.length; i++) {
|
for (let i = 0; i < recipeConfig.length; i++) {
|
||||||
const item = this.manager.recipe.addOperation(recipeConfig[i].op);
|
const item = this.manager.recipe.addOperation(recipeConfig[i].op);
|
||||||
|
|
||||||
|
@ -612,9 +605,6 @@ class App {
|
||||||
|
|
||||||
this.progress = 0;
|
this.progress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpause auto bake
|
|
||||||
this.autoBakePause = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ class HTMLCategory {
|
||||||
let html = `<div class="panel category">
|
let html = `<div class="panel category">
|
||||||
<a class="category-title" data-toggle="collapse" data-target="#${catName}">
|
<a class="category-title" data-toggle="collapse" data-target="#${catName}">
|
||||||
${this.name}
|
${this.name}
|
||||||
|
<span class="op-count hidden">
|
||||||
|
${this.opList.length}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div id="${catName}" class="panel-collapse collapse ${(this.selected ? " show" : "")}" data-parent="#categories">
|
<div id="${catName}" class="panel-collapse collapse ${(this.selected ? " show" : "")}" data-parent="#categories">
|
||||||
<ul class="op-list">`;
|
<ul class="op-list">`;
|
||||||
|
|
|
@ -85,6 +85,7 @@ class HTMLOperation {
|
||||||
<div class="recip-icons">
|
<div class="recip-icons">
|
||||||
<i class="material-icons breakpoint" title="Set breakpoint" break="false" data-help-title="Setting breakpoints" data-help="Setting a breakpoint on an operation will cause execution of the Recipe to pause when it reaches that operation.">pause</i>
|
<i class="material-icons breakpoint" title="Set breakpoint" break="false" data-help-title="Setting breakpoints" data-help="Setting a breakpoint on an operation will cause execution of the Recipe to pause when it reaches that operation.">pause</i>
|
||||||
<i class="material-icons disable-icon" title="Disable operation" disabled="false" data-help-title="Disabling operations" data-help="Disabling an operation will prevent it from being executed when the Recipe is baked. Execution will skip over the disabled operation and continue with subsequent operations.">not_interested</i>
|
<i class="material-icons disable-icon" title="Disable operation" disabled="false" data-help-title="Disabling operations" data-help="Disabling an operation will prevent it from being executed when the Recipe is baked. Execution will skip over the disabled operation and continue with subsequent operations.">not_interested</i>
|
||||||
|
<i class="material-icons hide-args-icon" title="Hide operation's arguments" hide-args="false" data-help-title="Hide operation's arguments" data-help="Hiding an operation's argument will save space in the Recipe window. Execution will still take place with the selected argument options.">keyboard_arrow_up</i>
|
||||||
</div>
|
</div>
|
||||||
<div class="clearfix"> </div>`;
|
<div class="clearfix"> </div>`;
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,7 @@ class Manager {
|
||||||
document.getElementById("load-delete-button").addEventListener("click", this.controls.loadDeleteClick.bind(this.controls));
|
document.getElementById("load-delete-button").addEventListener("click", this.controls.loadDeleteClick.bind(this.controls));
|
||||||
document.getElementById("load-name").addEventListener("change", this.controls.loadNameChange.bind(this.controls));
|
document.getElementById("load-name").addEventListener("change", this.controls.loadNameChange.bind(this.controls));
|
||||||
document.getElementById("load-button").addEventListener("click", this.controls.loadButtonClick.bind(this.controls));
|
document.getElementById("load-button").addEventListener("click", this.controls.loadButtonClick.bind(this.controls));
|
||||||
|
document.getElementById("hide-icon").addEventListener("click", this.controls.hideRecipeArgsClick.bind(this.recipe));
|
||||||
document.getElementById("support").addEventListener("click", this.controls.supportButtonClick.bind(this.controls));
|
document.getElementById("support").addEventListener("click", this.controls.supportButtonClick.bind(this.controls));
|
||||||
this.addMultiEventListeners("#save-texts textarea", "keyup paste", this.controls.saveTextChange, this.controls);
|
this.addMultiEventListeners("#save-texts textarea", "keyup paste", this.controls.saveTextChange, this.controls);
|
||||||
|
|
||||||
|
@ -154,6 +155,7 @@ class Manager {
|
||||||
// Recipe
|
// Recipe
|
||||||
this.addDynamicListener(".arg:not(select)", "input", this.recipe.ingChange, this.recipe);
|
this.addDynamicListener(".arg:not(select)", "input", this.recipe.ingChange, this.recipe);
|
||||||
this.addDynamicListener(".arg[type=checkbox], .arg[type=radio], select.arg", "change", this.recipe.ingChange, this.recipe);
|
this.addDynamicListener(".arg[type=checkbox], .arg[type=radio], select.arg", "change", this.recipe.ingChange, this.recipe);
|
||||||
|
this.addDynamicListener(".hide-args-icon", "click", this.recipe.hideArgsClick, this.recipe);
|
||||||
this.addDynamicListener(".disable-icon", "click", this.recipe.disableClick, this.recipe);
|
this.addDynamicListener(".disable-icon", "click", this.recipe.disableClick, this.recipe);
|
||||||
this.addDynamicListener(".breakpoint", "click", this.recipe.breakpointClick, this.recipe);
|
this.addDynamicListener(".breakpoint", "click", this.recipe.breakpointClick, this.recipe);
|
||||||
this.addDynamicListener("#rec-list li.operation", "dblclick", this.recipe.operationDblclick, this.recipe);
|
this.addDynamicListener("#rec-list li.operation", "dblclick", this.recipe.operationDblclick, this.recipe);
|
||||||
|
@ -227,6 +229,7 @@ class Manager {
|
||||||
this.addDynamicListener(".option-item input[type=checkbox]", "change", this.options.switchChange, this.options);
|
this.addDynamicListener(".option-item input[type=checkbox]", "change", this.options.switchChange, this.options);
|
||||||
this.addDynamicListener(".option-item input[type=checkbox]#wordWrap", "change", this.options.setWordWrap, this.options);
|
this.addDynamicListener(".option-item input[type=checkbox]#wordWrap", "change", this.options.setWordWrap, this.options);
|
||||||
this.addDynamicListener(".option-item input[type=checkbox]#useMetaKey", "change", this.bindings.updateKeybList, this.bindings);
|
this.addDynamicListener(".option-item input[type=checkbox]#useMetaKey", "change", this.bindings.updateKeybList, this.bindings);
|
||||||
|
this.addDynamicListener(".option-item input[type=checkbox]#showCatCount", "change", this.ops.setCatCount, this.ops);
|
||||||
this.addDynamicListener(".option-item input[type=number]", "keyup", this.options.numberChange, this.options);
|
this.addDynamicListener(".option-item input[type=number]", "keyup", this.options.numberChange, this.options);
|
||||||
this.addDynamicListener(".option-item input[type=number]", "change", this.options.numberChange, this.options);
|
this.addDynamicListener(".option-item input[type=number]", "change", this.options.numberChange, this.options);
|
||||||
this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
|
this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
|
||||||
|
@ -268,7 +271,7 @@ class Manager {
|
||||||
* @param {Object} [scope=this] - The object to bind to the callback function
|
* @param {Object} [scope=this] - The object to bind to the callback function
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Calls the search function whenever the the keyup, paste or search events are triggered on the
|
* // Calls the search function whenever the keyup, paste or search events are triggered on the
|
||||||
* // search element
|
* // search element
|
||||||
* this.addMultiEventListener("search", "keyup paste search", this.search, this);
|
* this.addMultiEventListener("search", "keyup paste search", this.search, this);
|
||||||
*/
|
*/
|
||||||
|
@ -289,7 +292,7 @@ class Manager {
|
||||||
* @param {Object} [scope=this] - The object to bind to the callback function
|
* @param {Object} [scope=this] - The object to bind to the callback function
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Calls the save function whenever the the keyup or paste events are triggered on any element
|
* // Calls the save function whenever the keyup or paste events are triggered on any element
|
||||||
* // with the .saveable class
|
* // with the .saveable class
|
||||||
* this.addMultiEventListener(".saveable", "keyup paste", this.save, this);
|
* this.addMultiEventListener(".saveable", "keyup paste", this.save, this);
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
<div id="operations" class="split split-horizontal no-select">
|
<div id="operations" class="split split-horizontal no-select">
|
||||||
<div class="title no-select" data-help-title="Operations list" data-help="<p>The Operations list contains all the operations in CyberChef arranged into categories. Some operations may be present in multiple categories. You can search for operations using the search box.</p><p>To use an operation, either double click it, or drag it into the Recipe pane. You will then be able to configure its arguments (or 'Ingredients' in CyberChef terminology).</p>">
|
<div class="title no-select" data-help-title="Operations list" data-help="<p>The Operations list contains all the operations in CyberChef arranged into categories. Some operations may be present in multiple categories. You can search for operations using the search box.</p><p>To use an operation, either double click it, or drag it into the Recipe pane. You will then be able to configure its arguments (or 'Ingredients' in CyberChef terminology).</p>">
|
||||||
Operations
|
Operations
|
||||||
|
<span class="op-count"></span>
|
||||||
</div>
|
</div>
|
||||||
<input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="2" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>">
|
<input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="2" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>">
|
||||||
<ul id="search-results" class="op-list"></ul>
|
<ul id="search-results" class="op-list"></ul>
|
||||||
|
@ -181,10 +182,13 @@
|
||||||
<div class="title no-select">
|
<div class="title no-select">
|
||||||
Recipe
|
Recipe
|
||||||
<span class="pane-controls hide-on-maximised-output">
|
<span class="pane-controls hide-on-maximised-output">
|
||||||
<button type="button" aria-label="Save recipe" class="btn btn-primary bmd-btn-icon" id="save" data-toggle="tooltip" title="Save recipe" data-help-title="Saving a recipe" data-help="<p>Recipes can be represented in a few different formats and saved for use at a later date. You can either copy the Recipe configuration and save it somewhere offline for later use, or use your browser's local storage.</p><ul><li><b>Deep link:</b> The easiest way to share a CyberChef Recipe is to copy the deep link, either from the address bar (which is updated as the Recipe or Input changes), or from the 'Save recipe' pane. When you visit this link, the Recipe and Input should be populated from where you left off.</li><li><b>Chef format:</b> This custom format is designed to be compact and easily readable. It is the format used in CyberChef's URL, so it largely uses characters that do not have to be escaped in URL encoding, making it a little easier to understand what a CyberChef URL contains.</li><li><b>Clean JSON:</b> This JSON format uses whitespace and indentation in a way that makes the Recipe easy to read.</li><li><b>Compact JSON:</b> This is the most compact way that the Recipe can be represented in JSON.</li><li><b>Local storage:</b> Alternatively, you can enter a name into the 'Recipe name' field and save to your browser's local storage. The Recipe will then be available to load from the 'Load Recipe' pane as long as you are using the same browser profile. Be aware that if your browser profile is cleaned, you may lose this data.</li></ul>">
|
<button type="button" aria-label="Hide arguments" class="btn btn-primary bmd-btn-icon" id="hide-icon" data-toggle="tooltip" title="Hide arguments" hide-args="false" data-help-title="Hiding every Operation's argument view in a Recipe" data-help="Clicking 'Hide arguments' will hide all the argument views for every Operation in the Recipe, to save space when you have too many Operation in your Recipe">
|
||||||
|
<i class="material-icons">keyboard_arrow_up</i>
|
||||||
|
</button>
|
||||||
|
<button type="button" aria-label="Save recipe" class="btn btn-primary bmd-btn-icon" id="save" data-toggle="tooltip" title="Save recipe" data-help-title="Saving a recipe" data-help="<p>Recipes can be represented in a few different formats and saved for use at a later date. You can either copy the Recipe configuration and save it somewhere offline for later use, or use your browser's local storage.</p><ul><li><b>Deep link:</b> The easiest way to share a CyberChef Recipe is to copy the deep link, either from the address bar (which is updated as the Recipe or Input changes), or from the 'Save recipe' pane. When you visit this link, the Recipe and Input will be populated from where you left off.</li><li><b>Chef format:</b> This custom format is designed to be compact and easily readable. It is the format used in CyberChef's URL, so it largely uses characters that do not have to be escaped in URL encoding, making it a little easier to understand what a CyberChef URL contains.</li><li><b>Clean JSON:</b> This JSON format uses whitespace and indentation in a way that makes the Recipe easy to read.</li><li><b>Compact JSON:</b> This is the most compact way that the Recipe can be represented in JSON.</li><li><b>Local storage:</b> Alternatively, you can enter a name into the 'Recipe name' field and save to your browser's local storage. The Recipe will then be available to load from the 'Load Recipe' pane as long as you are using the same browser profile. Be aware that if your browser profile is cleaned, you may lose this data.</li></ul>">
|
||||||
<i class="material-icons" aria-hidden="true">save</i>
|
<i class="material-icons" aria-hidden="true">save</i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" aria-label="Load recipe" class="btn btn-primary bmd-btn-icon" id="load" data-toggle="tooltip" title="Load recipe" data-help-title="Loading a recipe" data-help="<p>Saved recipes can be loaded using one of the following methods:</p><ul><li>If you have a CyberChef deep link, simply visit that link and the Recipe and Input should be populated automatically.</li><li>If you have a Recipe string in any of the accepted formats, paste it into the 'Load recipe' pane textbox and click 'Load'.</li><li>If you have saved a Recipe to your browser's local storage, it should be available in the dropdown menu in the 'Load recipe' pane. If it is not there, you may not be using the same browser profile, or your profile may have been cleared.</li></ul>">
|
<button type="button" aria-label="Load recipe" class="btn btn-primary bmd-btn-icon" id="load" data-toggle="tooltip" title="Load recipe" data-help-title="Loading a recipe" data-help="<p>Saved recipes can be loaded using one of the following methods:</p><ul><li>If you have a CyberChef deep link, simply visit that link and the Recipe and Input will be populated automatically.</li><li>If you have a Recipe string in any of the accepted formats, paste it into the 'Load recipe' pane textbox and click 'Load'.</li><li>If you have saved a Recipe to your browser's local storage, it should be available in the dropdown menu in the 'Load recipe' pane. If it is not there, you may not be using the same browser profile, or your profile may have been cleared.</li></ul>">
|
||||||
<i class="material-icons" aria-hidden="true">folder</i>
|
<i class="material-icons" aria-hidden="true">folder</i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" aria-label="Clear recipe" class="btn btn-primary bmd-btn-icon" id="clr-recipe" data-toggle="tooltip" title="Clear recipe" data-help-title="Clearing a recipe" data-help="Clicking the 'Clear recipe' button will remove all operations from the Recipe. It will not clear the Input, but it will trigger a Bake if Auto-bake is turned on, which will change the value of the Output.">
|
<button type="button" aria-label="Clear recipe" class="btn btn-primary bmd-btn-icon" id="clr-recipe" data-toggle="tooltip" title="Clear recipe" data-help-title="Clearing a recipe" data-help="Clicking the 'Clear recipe' button will remove all operations from the Recipe. It will not clear the Input, but it will trigger a Bake if Auto-bake is turned on, which will change the value of the Output.">
|
||||||
|
@ -272,7 +276,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="output" class="split" data-help-title="Output pane" data-help="<p>This pane displays the results of the Recipe after it has processed your Input.</p><p>CyberChef does its best to represent data as accurately as possible to ensure you know exactly what you are working with. Non-printable characters are represented using control character pictures, for example a null byte (0x00) is displayed like this: <span title='Control character null' aria-label='Control character null' class='cm-specialChar'>␀</span>.</p><p>When copying these characters from the Output, the original byte value should be copied into your clipboard, rather than the control character picture itself.</p>">
|
<div id="output" class="split" data-help-title="Output pane" data-help="<p>This pane displays the results of the Recipe after it has processed your Input.</p><p>CyberChef does its best to represent data as accurately as possible to ensure you know exactly what you are working with. Non-printable characters are represented using control character pictures, for example a null byte (0x00) is displayed like this: <span title='Control character null' aria-label='Control character null' class='cm-specialChar'>␀</span>.</p><p>When copying these characters from the Output, the original byte value will be copied into your clipboard, rather than the control character picture itself.</p>">
|
||||||
<div class="title no-select">
|
<div class="title no-select">
|
||||||
<label for="output-text">Output</label>
|
<label for="output-text">Output</label>
|
||||||
<span class="pane-controls">
|
<span class="pane-controls">
|
||||||
|
@ -283,7 +287,7 @@
|
||||||
<button type="button" aria-label="save" class="btn btn-primary bmd-btn-icon" id="save-to-file" data-toggle="tooltip" title="Save output to file" data-help-title="Saving output to a file" data-help="The currently active Output can be saved to a file. You will be asked to specify a filename. CyberChef will attempt to guess the correct file extension based on the data. If a file type cannot be detected, the extension defaults to '.dat' but can be changed manually.">
|
<button type="button" aria-label="save" class="btn btn-primary bmd-btn-icon" id="save-to-file" data-toggle="tooltip" title="Save output to file" data-help-title="Saving output to a file" data-help="The currently active Output can be saved to a file. You will be asked to specify a filename. CyberChef will attempt to guess the correct file extension based on the data. If a file type cannot be detected, the extension defaults to '.dat' but can be changed manually.">
|
||||||
<i class="material-icons" aria-hidden="true">save</i>
|
<i class="material-icons" aria-hidden="true">save</i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" aria-label="copy content" class="btn btn-primary bmd-btn-icon" id="copy-output" data-toggle="tooltip" title="Copy raw output to the clipboard" data-help-title="Copying raw output to the clipboard" data-help="<p>Data can be copied from the Output in the normal way by selecting text and copying it. This button provides a quick way of copying the entire output to the clipboard without having to select it. It directly copies the raw data rather than selecting text in the Output editor. Each method should have the same result, but the button may be more efficient for large Outputs as it does not require any DOM interaction.</p>">
|
<button type="button" aria-label="copy content" class="btn btn-primary bmd-btn-icon" id="copy-output" data-toggle="tooltip" title="Copy raw output to the clipboard" data-help-title="Copying raw output to the clipboard" data-help="<p>Data can be copied from the Output in the normal way by selecting text and copying it. This button provides a quick way of copying the entire output to the clipboard without having to select it. It directly copies the raw data rather than selecting text in the Output editor. Each method will have the same result, but the button may be more efficient for large Outputs as it does not require any DOM interaction.</p>">
|
||||||
<i class="material-icons" aria-hidden="true">content_copy</i>
|
<i class="material-icons" aria-hidden="true">content_copy</i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" aria-label="replace input with output" class="btn btn-primary bmd-btn-icon" id="switch" data-toggle="tooltip" title="Replace input with output" data-help-title="Replacing input with output" data-help="<p>This button moves the currently active Output data into the currently active Input tab, overwriting whatever data was already there.</p><p>The Input character encoding and EOL sequence will be changed to match the current Output values, so that the data is interpreted correctly.</p>">
|
<button type="button" aria-label="replace input with output" class="btn btn-primary bmd-btn-icon" id="switch" data-toggle="tooltip" title="Replace input with output" data-help-title="Replacing input with output" data-help="<p>This button moves the currently active Output data into the currently active Input tab, overwriting whatever data was already there.</p><p>The Input character encoding and EOL sequence will be changed to match the current Output values, so that the data is interpreted correctly.</p>">
|
||||||
|
@ -518,6 +522,13 @@
|
||||||
Keep the current tab in sync between the input and output
|
Keep the current tab in sync between the input and output
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="checkbox option-item">
|
||||||
|
<label for="showCatCount">
|
||||||
|
<input type="checkbox" option="showCatCount" id="showCatCount">
|
||||||
|
Show the number of operations in each category
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" id="reset-options">Reset options to default</button>
|
<button type="button" class="btn btn-secondary" id="reset-options">Reset options to default</button>
|
||||||
|
@ -608,7 +619,7 @@
|
||||||
What sort of things can I do with CyberChef?
|
What sort of things can I do with CyberChef?
|
||||||
</a>
|
</a>
|
||||||
<div class="collapse" id="faq-examples">
|
<div class="collapse" id="faq-examples">
|
||||||
<p>There are around 300 operations in CyberChef allowing you to carry out simple and complex tasks easily. Here are some examples:</p>
|
<p>There are <span class="num-ops">hundreds of</span> operations in CyberChef allowing you to carry out simple and complex tasks easily. Here are some examples:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1">Decode a Base64-encoded string</a></li>
|
<li><a href="#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1">Decode a Base64-encoded string</a></li>
|
||||||
<li><a href="#recipe=Translate_DateTime_Format('Standard%20date%20and%20time','DD/MM/YYYY%20HH:mm:ss','UTC','dddd%20Do%20MMMM%20YYYY%20HH:mm:ss%20Z%20z','Australia/Queensland')&input=MTUvMDYvMjAxNSAyMDo0NTowMA">Convert a date and time to a different time zone</a></li>
|
<li><a href="#recipe=Translate_DateTime_Format('Standard%20date%20and%20time','DD/MM/YYYY%20HH:mm:ss','UTC','dddd%20Do%20MMMM%20YYYY%20HH:mm:ss%20Z%20z','Australia/Queensland')&input=MTUvMDYvMjAxNSAyMDo0NTowMA">Convert a date and time to a different time zone</a></li>
|
||||||
|
@ -679,7 +690,7 @@
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<p>There are around 200 useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.</p>
|
<p>There are <span class="num-ops">hundreds of</span> useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.</p>
|
||||||
<p>It’s the Cyber Swiss Army Knife.</p>
|
<p>It’s the Cyber Swiss Army Knife.</p>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="keybindings" style="padding: 20px;">
|
<div role="tabpanel" class="tab-pane" id="keybindings" style="padding: 20px;">
|
||||||
|
@ -860,7 +871,7 @@
|
||||||
<h6>CyberChef v<%= htmlWebpackPlugin.options.version %></h6>
|
<h6>CyberChef v<%= htmlWebpackPlugin.options.version %></h6>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Build time: <%= htmlWebpackPlugin.options.compileTime %></li>
|
<li>Build time: <%= htmlWebpackPlugin.options.compileTime %></li>
|
||||||
<li>The changelog for this version can be viewed <a href="https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md">here</a></li>
|
<li>The changelog for this version can be viewed <a href="https://github.com/gchq/CyberChef/blob/v<%= htmlWebpackPlugin.options.version %>/CHANGELOG.md">here</a></li>
|
||||||
<li>© Crown Copyright 2016-<%= htmlWebpackPlugin.options.compileYear %></li>
|
<li>© Crown Copyright 2016-<%= htmlWebpackPlugin.options.compileYear %></li>
|
||||||
<li>Released under the Apache Licence, Version 2.0</li>
|
<li>Released under the Apache Licence, Version 2.0</li>
|
||||||
<li>SHA256 hash: DOWNLOAD_HASH_PLACEHOLDER</li>
|
<li>SHA256 hash: DOWNLOAD_HASH_PLACEHOLDER</li>
|
||||||
|
|
|
@ -51,7 +51,8 @@ function main() {
|
||||||
logLevel: "info",
|
logLevel: "info",
|
||||||
autoMagic: true,
|
autoMagic: true,
|
||||||
imagePreview: true,
|
imagePreview: true,
|
||||||
syncTabs: true
|
syncTabs: true,
|
||||||
|
showCatCount: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
document.removeEventListener("DOMContentLoaded", main, false);
|
document.removeEventListener("DOMContentLoaded", main, false);
|
||||||
|
|
|
@ -40,4 +40,13 @@
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.op-count {
|
||||||
|
float: right;
|
||||||
|
color: var(--subtext-font-colour);
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: xx-small;
|
||||||
|
opacity: 0.5;
|
||||||
|
padding-left: .5em;
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,10 @@ body {
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.blur {
|
.blur {
|
||||||
color: transparent !important;
|
color: transparent !important;
|
||||||
text-shadow: rgba(0, 0, 0, 0.95) 0 0 10px !important;
|
text-shadow: rgba(0, 0, 0, 0.95) 0 0 10px !important;
|
||||||
|
|
|
@ -36,6 +36,11 @@ class ControlsWaiter {
|
||||||
boundary: "viewport",
|
boundary: "viewport",
|
||||||
trigger: "hover"
|
trigger: "hover"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set number of operations in various places in the DOM
|
||||||
|
document.querySelectorAll(".num-ops").forEach(el => {
|
||||||
|
el.innerHTML = Object.keys(this.app.operations).length;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -345,6 +350,36 @@ class ControlsWaiter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides the arguments for all the operations in the current recipe.
|
||||||
|
*/
|
||||||
|
hideRecipeArgsClick() {
|
||||||
|
const icon = document.getElementById("hide-icon");
|
||||||
|
|
||||||
|
if (icon.getAttribute("hide-args") === "false") {
|
||||||
|
icon.setAttribute("hide-args", "true");
|
||||||
|
icon.setAttribute("data-original-title", "Show arguments");
|
||||||
|
icon.children[0].innerText = "keyboard_arrow_down";
|
||||||
|
Array.from(document.getElementsByClassName("hide-args-icon")).forEach(function(item) {
|
||||||
|
item.setAttribute("hide-args", "true");
|
||||||
|
item.innerText = "keyboard_arrow_down";
|
||||||
|
item.classList.add("hide-args-selected");
|
||||||
|
item.parentNode.previousElementSibling.style.display = "none";
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
icon.setAttribute("hide-args", "false");
|
||||||
|
icon.setAttribute("data-original-title", "Hide arguments");
|
||||||
|
icon.children[0].innerText = "keyboard_arrow_up";
|
||||||
|
Array.from(document.getElementsByClassName("hide-args-icon")).forEach(function(item) {
|
||||||
|
item.setAttribute("hide-args", "false");
|
||||||
|
item.innerText = "keyboard_arrow_up";
|
||||||
|
item.classList.remove("hide-args-selected");
|
||||||
|
item.parentNode.previousElementSibling.style.display = "grid";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates the bug report information box with useful technical info.
|
* Populates the bug report information box with useful technical info.
|
||||||
*
|
*
|
||||||
|
|
|
@ -215,13 +215,16 @@ class InputWaiter {
|
||||||
* Handler for Chr Enc change events
|
* Handler for Chr Enc change events
|
||||||
* Sets the input character encoding
|
* Sets the input character encoding
|
||||||
* @param {number} chrEncVal
|
* @param {number} chrEncVal
|
||||||
* @param {boolean} [manual=false]
|
* @param {boolean} [manual=false] - Flag to indicate the encoding was set by the user
|
||||||
|
* @param {boolean} [internal=false] - Flag to indicate this was set internally, i.e. by loading from URI
|
||||||
*/
|
*/
|
||||||
chrEncChange(chrEncVal, manual=false) {
|
chrEncChange(chrEncVal, manual=false, internal=false) {
|
||||||
if (typeof chrEncVal !== "number") return;
|
if (typeof chrEncVal !== "number") return;
|
||||||
this.inputChrEnc = chrEncVal;
|
this.inputChrEnc = chrEncVal;
|
||||||
this.encodingState = manual ? 2 : this.encodingState;
|
this.encodingState = manual ? 2 : this.encodingState;
|
||||||
this.inputChange();
|
if (!internal) {
|
||||||
|
this.inputChange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -639,10 +642,6 @@ class InputWaiter {
|
||||||
const inputStr = toBase64(inputVal, "A-Za-z0-9+/");
|
const inputStr = toBase64(inputVal, "A-Za-z0-9+/");
|
||||||
this.app.updateURL(true, inputStr);
|
this.app.updateURL(true, inputStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger a state change
|
|
||||||
if (!silent) window.dispatchEvent(this.manager.statechange);
|
|
||||||
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,10 @@ class OperationsWaiter {
|
||||||
*/
|
*/
|
||||||
opListCreate(e) {
|
opListCreate(e) {
|
||||||
this.manager.recipe.createSortableSeedList(e.target);
|
this.manager.recipe.createSortableSeedList(e.target);
|
||||||
|
|
||||||
|
// Populate ops total
|
||||||
|
document.querySelector("#operations .title .op-count").innerText = Object.keys(this.app.operations).length;
|
||||||
|
|
||||||
this.enableOpsListPopovers(e.target);
|
this.enableOpsListPopovers(e.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,6 +297,18 @@ class OperationsWaiter {
|
||||||
this.app.resetFavourites();
|
this.app.resetFavourites();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether operation counts are displayed next to a category title
|
||||||
|
*/
|
||||||
|
setCatCount() {
|
||||||
|
if (this.app.options.showCatCount) {
|
||||||
|
document.querySelectorAll(".category-title .op-count").forEach(el => el.classList.remove("hidden"));
|
||||||
|
} else {
|
||||||
|
document.querySelectorAll(".category-title .op-count").forEach(el => el.classList.add("hidden"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default OperationsWaiter;
|
export default OperationsWaiter;
|
||||||
|
|
|
@ -50,6 +50,7 @@ class OptionsWaiter {
|
||||||
|
|
||||||
// Initialise options
|
// Initialise options
|
||||||
this.setWordWrap();
|
this.setWordWrap();
|
||||||
|
this.manager.ops.setCatCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,45 @@ class RecipeWaiter {
|
||||||
window.dispatchEvent(this.manager.statechange);
|
window.dispatchEvent(this.manager.statechange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for hide-args click events.
|
||||||
|
* Updates the icon status.
|
||||||
|
*
|
||||||
|
* @fires Manager#statechange
|
||||||
|
* @param {event} e
|
||||||
|
*/
|
||||||
|
hideArgsClick(e) {
|
||||||
|
const icon = e.target;
|
||||||
|
|
||||||
|
if (icon.getAttribute("hide-args") === "false") {
|
||||||
|
icon.setAttribute("hide-args", "true");
|
||||||
|
icon.innerText = "keyboard_arrow_down";
|
||||||
|
icon.classList.add("hide-args-selected");
|
||||||
|
icon.parentNode.previousElementSibling.style.display = "none";
|
||||||
|
} else {
|
||||||
|
icon.setAttribute("hide-args", "false");
|
||||||
|
icon.innerText = "keyboard_arrow_up";
|
||||||
|
icon.classList.remove("hide-args-selected");
|
||||||
|
icon.parentNode.previousElementSibling.style.display = "grid";
|
||||||
|
}
|
||||||
|
|
||||||
|
const icons = Array.from(document.getElementsByClassName("hide-args-icon"));
|
||||||
|
if (icons.length > 1) {
|
||||||
|
// Check if ALL the icons are hidden/shown
|
||||||
|
const uniqueIcons = icons.map(function(item) {
|
||||||
|
return item.getAttribute("hide-args");
|
||||||
|
}).unique();
|
||||||
|
|
||||||
|
const controlsIconStatus = document.getElementById("hide-icon").getAttribute("hide-args");
|
||||||
|
|
||||||
|
// If all icons are in the same state and the global icon isn't, fix it
|
||||||
|
if (uniqueIcons.length === 1 && icon.getAttribute("hide-args") !== controlsIconStatus) {
|
||||||
|
this.manager.controls.hideRecipeArgsClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.dispatchEvent(this.manager.statechange);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for disable click events.
|
* Handler for disable click events.
|
||||||
|
|
|
@ -322,6 +322,28 @@ class WorkerWaiter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the current bake making it possible to autobake again
|
||||||
|
*/
|
||||||
|
cancelBakeForAutoBake() {
|
||||||
|
if (this.totalOutputs > 1) {
|
||||||
|
this.cancelBake();
|
||||||
|
} else {
|
||||||
|
// In this case the UI changes can be skipped
|
||||||
|
|
||||||
|
for (let i = this.chefWorkers.length - 1; i >= 0; i--) {
|
||||||
|
if (this.chefWorkers[i].active) {
|
||||||
|
this.removeChefWorker(this.chefWorkers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inputs = [];
|
||||||
|
this.inputNums = [];
|
||||||
|
this.totalOutputs = 0;
|
||||||
|
this.loadingOutputs = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels the current bake by terminating and removing all ChefWorkers
|
* Cancels the current bake by terminating and removing all ChefWorkers
|
||||||
*
|
*
|
||||||
|
|
|
@ -167,6 +167,37 @@ module.exports = {
|
||||||
browser.expect.element("#output-text .cm-status-bar .eol-value").text.to.equal("LF");
|
browser.expect.element("#output-text .cm-status-bar .eol-value").text.to.equal("LF");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"Autobaking the latest input": browser => {
|
||||||
|
// Use the sleep recipe to simulate a long running task
|
||||||
|
utils.loadRecipe(browser, "Sleep", "input", [2000]);
|
||||||
|
|
||||||
|
browser.waitForElementVisible("#stale-indicator");
|
||||||
|
|
||||||
|
// Enable previously disabled autobake
|
||||||
|
browser.expect.element("#auto-bake").to.not.be.selected;
|
||||||
|
browser.click("#auto-bake-label");
|
||||||
|
browser.expect.element("#auto-bake").to.be.selected.before(1000);
|
||||||
|
|
||||||
|
// Add content to the input
|
||||||
|
browser.pause(100);
|
||||||
|
browser.sendKeys("#input-text .cm-content", "1");
|
||||||
|
browser.waitForElementVisible("#output-loader");
|
||||||
|
browser.pause(500);
|
||||||
|
|
||||||
|
// Make another change while the previous input is being baked
|
||||||
|
browser
|
||||||
|
.sendKeys("#input-text .cm-content", "2")
|
||||||
|
.waitForElementNotVisible("#stale-indicator")
|
||||||
|
.waitForElementNotVisible("#output-loader");
|
||||||
|
|
||||||
|
// Ensure we got the latest input baked
|
||||||
|
utils.expectOutput(browser, "input12");
|
||||||
|
|
||||||
|
// Turn autobake off again
|
||||||
|
browser.click("#auto-bake-label");
|
||||||
|
browser.expect.element("#auto-bake").to.not.be.selected.before(1000);
|
||||||
|
},
|
||||||
|
|
||||||
"Special content": browser => {
|
"Special content": browser => {
|
||||||
/* Special characters are rendered correctly */
|
/* Special characters are rendered correctly */
|
||||||
utils.setInput(browser, SPECIAL_CHARS, false);
|
utils.setInput(browser, SPECIAL_CHARS, false);
|
||||||
|
@ -645,6 +676,20 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"Loading from URL": browser => {
|
"Loading from URL": browser => {
|
||||||
|
utils.clear(browser);
|
||||||
|
|
||||||
|
/* Side panel displays correct info */
|
||||||
|
utils.uploadFile(browser, "files/TowelDay.jpeg");
|
||||||
|
|
||||||
|
browser
|
||||||
|
.waitForElementVisible("#input-text .cm-file-details")
|
||||||
|
.waitForElementVisible("#input-text .cm-file-details .file-details-toggle-shown")
|
||||||
|
.waitForElementVisible("#input-text .cm-file-details .file-details-thumbnail")
|
||||||
|
.waitForElementVisible("#input-text .cm-file-details .file-details-name")
|
||||||
|
.waitForElementVisible("#input-text .cm-file-details .file-details-size")
|
||||||
|
.waitForElementVisible("#input-text .cm-file-details .file-details-type")
|
||||||
|
.waitForElementVisible("#input-text .cm-file-details .file-details-loaded");
|
||||||
|
|
||||||
/* Complex deep link populates the input correctly (encoding, eol, input) */
|
/* Complex deep link populates the input correctly (encoding, eol, input) */
|
||||||
browser
|
browser
|
||||||
.urlHash("recipe=To_Base64('A-Za-z0-9%2B/%3D')&input=VGhlIHNoaXBzIGh1bmcgaW4gdGhlIHNreSBpbiBtdWNoIHRoZSBzYW1lIHdheSB0aGF0IGJyaWNrcyBkb24ndC4M&ienc=21866&oenc=1201&ieol=FF&oeol=PS")
|
.urlHash("recipe=To_Base64('A-Za-z0-9%2B/%3D')&input=VGhlIHNoaXBzIGh1bmcgaW4gdGhlIHNreSBpbiBtdWNoIHRoZSBzYW1lIHdheSB0aGF0IGJyaWNrcyBkb24ndC4M&ienc=21866&oenc=1201&ieol=FF&oeol=PS")
|
||||||
|
|
|
@ -37,7 +37,7 @@ module.exports = {
|
||||||
testOp(browser, ["From Hex", "Add Text To Image", "To Base64"], Images.PNG_HEX, Images.PNG_CHEF_B64, [[], ["Chef", "Center", "Middle", 0, 0, 16], []]);
|
testOp(browser, ["From Hex", "Add Text To Image", "To Base64"], Images.PNG_HEX, Images.PNG_CHEF_B64, [[], ["Chef", "Center", "Middle", 0, 0, 16], []]);
|
||||||
testOp(browser, "Adler-32 Checksum", "test input", "16160411");
|
testOp(browser, "Adler-32 Checksum", "test input", "16160411");
|
||||||
testOp(browser, "Affine Cipher Decode", "test input", "rcqr glnsr", [1, 2]);
|
testOp(browser, "Affine Cipher Decode", "test input", "rcqr glnsr", [1, 2]);
|
||||||
testOp(browser, "Affine Cipher Encode", "test input", "njln rbfpn", [2, 1]);
|
testOp(browser, "Affine Cipher Encode", "test input", "gndg zoujg", [3, 1]);
|
||||||
testOp(browser, "AMF Decode", "\u000A\u0013\u0001\u0003a\u0006\u0009test", /"\$value": "test"/);
|
testOp(browser, "AMF Decode", "\u000A\u0013\u0001\u0003a\u0006\u0009test", /"\$value": "test"/);
|
||||||
testOp(browser, "AMF Encode", '{"a": "test"}', "\u000A\u0013\u0001\u0003a\u0006\u0009test");
|
testOp(browser, "AMF Encode", '{"a": "test"}', "\u000A\u0013\u0001\u0003a\u0006\u0009test");
|
||||||
testOp(browser, "Analyse hash", "0123456789abcdef", /CRC-64/);
|
testOp(browser, "Analyse hash", "0123456789abcdef", /CRC-64/);
|
||||||
|
@ -236,7 +236,7 @@ module.exports = {
|
||||||
// testOp(browser, "OR", "test input", "test_output");
|
// testOp(browser, "OR", "test input", "test_output");
|
||||||
// testOp(browser, "Object Identifier to Hex", "test input", "test_output");
|
// testOp(browser, "Object Identifier to Hex", "test input", "test_output");
|
||||||
testOpHtml(browser, "Offset checker", "test input\n\nbest input", ".hl5", "est input");
|
testOpHtml(browser, "Offset checker", "test input\n\nbest input", ".hl5", "est input");
|
||||||
// testOp(browser, "Optical Character Recognition", "test input", "test_output");
|
testOpFile(browser, "Optical Character Recognition", "files/testocr.png", false, /This is a lot of 12 point text to test the/, [], 10000);
|
||||||
// testOp(browser, "PEM to Hex", "test input", "test_output");
|
// testOp(browser, "PEM to Hex", "test input", "test_output");
|
||||||
// testOp(browser, "PGP Decrypt", "test input", "test_output");
|
// testOp(browser, "PGP Decrypt", "test input", "test_output");
|
||||||
// testOp(browser, "PGP Decrypt and Verify", "test input", "test_output");
|
// testOp(browser, "PGP Decrypt and Verify", "test input", "test_output");
|
||||||
|
@ -408,7 +408,7 @@ module.exports = {
|
||||||
* @param {Browser} browser - Nightwatch client
|
* @param {Browser} browser - Nightwatch client
|
||||||
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
||||||
* @param {string} input - input text for test
|
* @param {string} input - input text for test
|
||||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||||
*/
|
*/
|
||||||
function bakeOp(browser, opName, input, args=[]) {
|
function bakeOp(browser, opName, input, args=[]) {
|
||||||
browser.perform(function() {
|
browser.perform(function() {
|
||||||
|
@ -425,12 +425,12 @@ function bakeOp(browser, opName, input, args=[]) {
|
||||||
* @param {Browser} browser - Nightwatch client
|
* @param {Browser} browser - Nightwatch client
|
||||||
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
||||||
* @param {string} input - input text
|
* @param {string} input - input text
|
||||||
* @param {string} output - expected output
|
* @param {string|RegExp} output - expected output
|
||||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||||
*/
|
*/
|
||||||
function testOp(browser, opName, input, output, args=[]) {
|
function testOp(browser, opName, input, output, args=[]) {
|
||||||
bakeOp(browser, opName, input, args);
|
bakeOp(browser, opName, input, args);
|
||||||
utils.expectOutput(browser, output);
|
utils.expectOutput(browser, output, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @function
|
/** @function
|
||||||
|
@ -440,8 +440,8 @@ function testOp(browser, opName, input, output, args=[]) {
|
||||||
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
|
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
|
||||||
* @param {string} input - input text
|
* @param {string} input - input text
|
||||||
* @param {string} cssSelector - CSS selector for HTML output
|
* @param {string} cssSelector - CSS selector for HTML output
|
||||||
* @param {string} output - expected output
|
* @param {string|RegExp} output - expected output
|
||||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||||
*/
|
*/
|
||||||
function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
|
function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
|
||||||
bakeOp(browser, opName, input, args);
|
bakeOp(browser, opName, input, args);
|
||||||
|
@ -459,9 +459,9 @@ function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
|
||||||
* @param {Browser} browser - Nightwatch client
|
* @param {Browser} browser - Nightwatch client
|
||||||
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
|
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
|
||||||
* @param {string} filename - filename of image file from samples directory
|
* @param {string} filename - filename of image file from samples directory
|
||||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||||
*/
|
*/
|
||||||
function testOpImage(browser, opName, filename, args) {
|
function testOpImage(browser, opName, filename, args=[]) {
|
||||||
browser.perform(function() {
|
browser.perform(function() {
|
||||||
console.log(`Current test: ${opName}`);
|
console.log(`Current test: ${opName}`);
|
||||||
});
|
});
|
||||||
|
@ -481,11 +481,12 @@ function testOpImage(browser, opName, filename, args) {
|
||||||
* @param {Browser} browser - Nightwatch client
|
* @param {Browser} browser - Nightwatch client
|
||||||
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
|
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
|
||||||
* @param {string} filename - filename of file from samples directory
|
* @param {string} filename - filename of file from samples directory
|
||||||
* @param {string} cssSelector - CSS selector for HTML output
|
* @param {string|boolean} cssSelector - CSS selector for HTML output or false for normal text output
|
||||||
* @param {string} output - expected output
|
* @param {string|RegExp} output - expected output
|
||||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||||
|
* @param {number} [waitWindow=1000] - The number of milliseconds to wait for the output to be correct
|
||||||
*/
|
*/
|
||||||
function testOpFile(browser, opName, filename, cssSelector, output, args) {
|
function testOpFile(browser, opName, filename, cssSelector, output, args=[], waitWindow=1000) {
|
||||||
browser.perform(function() {
|
browser.perform(function() {
|
||||||
console.log(`Current test: ${opName}`);
|
console.log(`Current test: ${opName}`);
|
||||||
});
|
});
|
||||||
|
@ -494,9 +495,14 @@ function testOpFile(browser, opName, filename, cssSelector, output, args) {
|
||||||
browser.pause(100).waitForElementVisible("#stale-indicator", 5000);
|
browser.pause(100).waitForElementVisible("#stale-indicator", 5000);
|
||||||
utils.bake(browser);
|
utils.bake(browser);
|
||||||
|
|
||||||
if (typeof output === "string") {
|
if (!cssSelector) {
|
||||||
|
// Text output
|
||||||
|
utils.expectOutput(browser, output, true, waitWindow);
|
||||||
|
} else if (typeof output === "string") {
|
||||||
|
// HTML output - string match
|
||||||
browser.expect.element("#output-html " + cssSelector).text.that.equals(output);
|
browser.expect.element("#output-html " + cssSelector).text.that.equals(output);
|
||||||
} else if (output instanceof RegExp) {
|
} else if (output instanceof RegExp) {
|
||||||
|
// HTML output - RegEx match
|
||||||
browser.expect.element("#output-html " + cssSelector).text.that.matches(output);
|
browser.expect.element("#output-html " + cssSelector).text.that.matches(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,9 @@ function setInput(browser, input, type=true) {
|
||||||
browser.execute(text => {
|
browser.execute(text => {
|
||||||
window.app.setInput(text);
|
window.app.setInput(text);
|
||||||
}, [input]);
|
}, [input]);
|
||||||
|
browser.pause(100);
|
||||||
}
|
}
|
||||||
|
expectInput(browser, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @function
|
/** @function
|
||||||
|
@ -48,6 +50,11 @@ function setInput(browser, input, type=true) {
|
||||||
* @param {Browser} browser - Nightwatch client
|
* @param {Browser} browser - Nightwatch client
|
||||||
*/
|
*/
|
||||||
function bake(browser) {
|
function bake(browser) {
|
||||||
|
browser
|
||||||
|
// Ensure we're not currently busy
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000)
|
||||||
|
.expect.element("#bake span").text.to.equal("BAKE!");
|
||||||
|
|
||||||
browser
|
browser
|
||||||
.click("#bake")
|
.click("#bake")
|
||||||
.waitForElementNotVisible("#stale-indicator", 5000)
|
.waitForElementNotVisible("#stale-indicator", 5000)
|
||||||
|
@ -161,7 +168,6 @@ function loadRecipe(browser, opName, input, args) {
|
||||||
throw new Error("Invalid operation type. Must be string or array of strings. Received: " + typeof(opName));
|
throw new Error("Invalid operation type. Must be string or array of strings. Received: " + typeof(opName));
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(browser);
|
|
||||||
setInput(browser, input, false);
|
setInput(browser, input, false);
|
||||||
browser
|
browser
|
||||||
.urlHash("recipe=" + recipeConfig)
|
.urlHash("recipe=" + recipeConfig)
|
||||||
|
@ -173,8 +179,19 @@ function loadRecipe(browser, opName, input, args) {
|
||||||
*
|
*
|
||||||
* @param {Browser} browser - Nightwatch client
|
* @param {Browser} browser - Nightwatch client
|
||||||
* @param {string|RegExp} expected - The expected output value
|
* @param {string|RegExp} expected - The expected output value
|
||||||
|
* @param {boolean} [waitNotNull=false] - Wait for the output to not be empty before testing the value
|
||||||
|
* @param {number} [waitWindow=1000] - The number of milliseconds to wait for the output to be correct
|
||||||
*/
|
*/
|
||||||
function expectOutput(browser, expected) {
|
function expectOutput(browser, expected, waitNotNull=false, waitWindow=1000) {
|
||||||
|
if (waitNotNull && expected !== "") {
|
||||||
|
browser.waitUntil(async function() {
|
||||||
|
const output = await this.execute(function() {
|
||||||
|
return window.app.manager.output.outputEditorView.state.doc.toString();
|
||||||
|
});
|
||||||
|
return output.length;
|
||||||
|
}, waitWindow);
|
||||||
|
}
|
||||||
|
|
||||||
browser.execute(expected => {
|
browser.execute(expected => {
|
||||||
return window.app.manager.output.outputEditorView.state.doc.toString();
|
return window.app.manager.output.outputEditorView.state.doc.toString();
|
||||||
}, [expected], function({value}) {
|
}, [expected], function({value}) {
|
||||||
|
@ -186,6 +203,24 @@ function expectOutput(browser, expected) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @function
|
||||||
|
* Tests whether the input matches a given value
|
||||||
|
*
|
||||||
|
* @param {Browser} browser - Nightwatch client
|
||||||
|
* @param {string|RegExp} expected - The expected input value
|
||||||
|
*/
|
||||||
|
function expectInput(browser, expected) {
|
||||||
|
browser.execute(expected => {
|
||||||
|
return window.app.manager.input.inputEditorView.state.doc.toString();
|
||||||
|
}, [expected], function({value}) {
|
||||||
|
if (expected instanceof RegExp) {
|
||||||
|
browser.expect(value).match(expected);
|
||||||
|
} else {
|
||||||
|
browser.expect(value).to.be.equal(expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** @function
|
/** @function
|
||||||
* Uploads a file using the #open-file input
|
* Uploads a file using the #open-file input
|
||||||
*
|
*
|
||||||
|
@ -245,6 +280,7 @@ module.exports = {
|
||||||
paste: paste,
|
paste: paste,
|
||||||
loadRecipe: loadRecipe,
|
loadRecipe: loadRecipe,
|
||||||
expectOutput: expectOutput,
|
expectOutput: expectOutput,
|
||||||
|
expectInput: expectInput,
|
||||||
uploadFile: uploadFile,
|
uploadFile: uploadFile,
|
||||||
uploadFolder: uploadFolder
|
uploadFolder: uploadFolder
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,6 +59,7 @@ import "./tests/Crypt.mjs";
|
||||||
import "./tests/CSV.mjs";
|
import "./tests/CSV.mjs";
|
||||||
import "./tests/DateTime.mjs";
|
import "./tests/DateTime.mjs";
|
||||||
import "./tests/DefangIP.mjs";
|
import "./tests/DefangIP.mjs";
|
||||||
|
import "./tests/ECDSA.mjs";
|
||||||
import "./tests/ELFInfo.mjs";
|
import "./tests/ELFInfo.mjs";
|
||||||
import "./tests/Enigma.mjs";
|
import "./tests/Enigma.mjs";
|
||||||
import "./tests/ExtractEmailAddresses.mjs";
|
import "./tests/ExtractEmailAddresses.mjs";
|
||||||
|
@ -83,12 +84,13 @@ import "./tests/HKDF.mjs";
|
||||||
import "./tests/Image.mjs";
|
import "./tests/Image.mjs";
|
||||||
import "./tests/IndexOfCoincidence.mjs";
|
import "./tests/IndexOfCoincidence.mjs";
|
||||||
import "./tests/JA3Fingerprint.mjs";
|
import "./tests/JA3Fingerprint.mjs";
|
||||||
import "./tests/JA4Fingerprint.mjs";
|
import "./tests/JA4.mjs";
|
||||||
import "./tests/JA3SFingerprint.mjs";
|
import "./tests/JA3SFingerprint.mjs";
|
||||||
import "./tests/JSONBeautify.mjs";
|
import "./tests/JSONBeautify.mjs";
|
||||||
import "./tests/JSONMinify.mjs";
|
import "./tests/JSONMinify.mjs";
|
||||||
import "./tests/JSONtoCSV.mjs";
|
import "./tests/JSONtoCSV.mjs";
|
||||||
import "./tests/Jump.mjs";
|
import "./tests/Jump.mjs";
|
||||||
|
import "./tests/JWK.mjs";
|
||||||
import "./tests/JWTDecode.mjs";
|
import "./tests/JWTDecode.mjs";
|
||||||
import "./tests/JWTSign.mjs";
|
import "./tests/JWTSign.mjs";
|
||||||
import "./tests/JWTVerify.mjs";
|
import "./tests/JWTVerify.mjs";
|
||||||
|
@ -120,6 +122,8 @@ import "./tests/PGP.mjs";
|
||||||
import "./tests/PHP.mjs";
|
import "./tests/PHP.mjs";
|
||||||
import "./tests/PowerSet.mjs";
|
import "./tests/PowerSet.mjs";
|
||||||
import "./tests/Protobuf.mjs";
|
import "./tests/Protobuf.mjs";
|
||||||
|
import "./tests/PubKeyFromCert.mjs";
|
||||||
|
import "./tests/PubKeyFromPrivKey.mjs";
|
||||||
import "./tests/Rabbit.mjs";
|
import "./tests/Rabbit.mjs";
|
||||||
import "./tests/RAKE.mjs";
|
import "./tests/RAKE.mjs";
|
||||||
import "./tests/Regex.mjs";
|
import "./tests/Regex.mjs";
|
||||||
|
@ -150,6 +154,7 @@ import "./tests/Unicode.mjs";
|
||||||
import "./tests/WordCount.mjs";
|
import "./tests/WordCount.mjs";
|
||||||
import "./tests/YARA.mjs";
|
import "./tests/YARA.mjs";
|
||||||
import "./tests/ParseCSR.mjs";
|
import "./tests/ParseCSR.mjs";
|
||||||
|
import "./tests/XXTEA.mjs";
|
||||||
|
|
||||||
const testStatus = {
|
const testStatus = {
|
||||||
allTestsPassing: true,
|
allTestsPassing: true,
|
||||||
|
|
|
@ -189,7 +189,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["", "\n", true]
|
"args": ["", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -205,7 +205,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$.store.book[*].author", "\n", true]
|
"args": ["$.store.book[*].author", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -223,7 +223,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$..title", "\n", true]
|
"args": ["$..title", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -238,7 +238,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$.store.*", "\n", true]
|
"args": ["$.store.*", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -249,7 +249,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$..book[-1:]", "\n", true]
|
"args": ["$..book[-1:]", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -263,7 +263,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$..book[:2]", "\n", true]
|
"args": ["$..book[:2]", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -277,7 +277,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$..book[?(@.isbn)]", "\n", false]
|
"args": ["$..book[?(@.isbn)]", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -292,7 +292,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$..book[?(@.price<30 && @.category==\"fiction\")]", "\n", false]
|
"args": ["$..book[?(@.price<30 && @.category==\"fiction\")]", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -306,7 +306,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": ["$..book[?(@.price<10)]", "\n", false]
|
"args": ["$..book[?(@.price<10)]", "\n"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -318,12 +318,11 @@ TestRegister.addTests([
|
||||||
"op": "JPath expression",
|
"op": "JPath expression",
|
||||||
"args": [
|
"args": [
|
||||||
"$..[?(({__proto__:[].constructor}).constructor(\"self.postMessage({action:'bakeComplete',data:{bakeId:1,dish:{type:1,value:''},duration:1,error:false,id:undefined,inputNum:2,progress:1,result:'<iframe/onload=debugger>',type: 'html'}});\")();)]",
|
"$..[?(({__proto__:[].constructor}).constructor(\"self.postMessage({action:'bakeComplete',data:{bakeId:1,dish:{type:1,value:''},duration:1,error:false,id:undefined,inputNum:2,progress:1,result:'<iframe/onload=debugger>',type: 'html'}});\")();)]",
|
||||||
"\n",
|
"\n"
|
||||||
true
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
expectedOutput: "Invalid JPath expression: Eval [?(expr)] prevented in JSONPath expression."
|
expectedMatch: /^Invalid JPath expression: jsonPath: self is not defined:/
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CSS selector",
|
name: "CSS selector",
|
||||||
|
|
464
tests/operations/tests/ECDSA.mjs
Normal file
464
tests/operations/tests/ECDSA.mjs
Normal file
|
@ -0,0 +1,464 @@
|
||||||
|
/**
|
||||||
|
* ECDSA tests.
|
||||||
|
*
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
import { ASCII_TEXT } from "../../samples/Ciphers.mjs";
|
||||||
|
|
||||||
|
const P256 = {
|
||||||
|
// openssl ecparam -name prime256v1 -genkey -noout -out p256.priv.key
|
||||||
|
privateKeyPkcs1: `-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEINtTjwUkgfAiSwqgcGAXWyE0ueIW6n2k395dmQZ3vGr4oAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEDUc8A0EDNKoCYIPWMHz1yUzqE5mJgusgcAE8H6810fkJ8ZmTNiCC
|
||||||
|
a6sLgR2vD1VNh2diirWgKPH4PVMKav5e6Q==
|
||||||
|
-----END EC PRIVATE KEY-----`,
|
||||||
|
privateKeyPkcs8: `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg21OPBSSB8CJLCqBw
|
||||||
|
YBdbITS54hbqfaTf3l2ZBne8avihRANCAAQNRzwDQQM0qgJgg9YwfPXJTOoTmYmC
|
||||||
|
6yBwATwfrzXR+QnxmZM2IIJrqwuBHa8PVU2HZ2KKtaAo8fg9Uwpq/l7p
|
||||||
|
-----END PRIVATE KEY-----`,
|
||||||
|
|
||||||
|
// openssl ec -in p256.priv.key -pubout -out p256.pub.key
|
||||||
|
publicKey: `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDUc8A0EDNKoCYIPWMHz1yUzqE5mJ
|
||||||
|
gusgcAE8H6810fkJ8ZmTNiCCa6sLgR2vD1VNh2diirWgKPH4PVMKav5e6Q==
|
||||||
|
-----END PUBLIC KEY-----`,
|
||||||
|
|
||||||
|
signature: {
|
||||||
|
sha256: {
|
||||||
|
asn1: "3046022100e06905608a2fa7dbda9e284c2a7959dfb68fb527a5f003b2d7975ff135145127022100b6baa253793334f8b93ea1dd622bc600124d8090babd807efe3f77b8b324388d",
|
||||||
|
p1363: "e06905608a2fa7dbda9e284c2a7959dfb68fb527a5f003b2d7975ff135145127b6baa253793334f8b93ea1dd622bc600124d8090babd807efe3f77b8b324388d",
|
||||||
|
jws: "4GkFYIovp9vanihMKnlZ37aPtSel8AOy15df8TUUUSe2uqJTeTM0-Lk-od1iK8YAEk2AkLq9gH7-P3e4syQ4jQ",
|
||||||
|
json: `{"r":"00e06905608a2fa7dbda9e284c2a7959dfb68fb527a5f003b2d7975ff135145127","s":"00b6baa253793334f8b93ea1dd622bc600124d8090babd807efe3f77b8b324388d"}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// openssl pkcs8 -topk8 -in p256.priv.key -out p256.enc-priv.key -v2 des3 -v2prf hmacWithSHA1 -passout pass:Test1234
|
||||||
|
/* const PEM_PRIV_P256_ENCRYPTED_PASS = "Test1234";
|
||||||
|
const PEM_PRIV_P256_ENCRYPTED = `-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAg+4ckqI9Q9ZAICCAAw
|
||||||
|
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEOnMUW15Hn/ub0OcCCj9lksEgZCk
|
||||||
|
kxaK4d430lZHovcA4ZeKTt94QcfjnIHRk65aZt93l17l52pv6n/srs3aRo/n5RV+
|
||||||
|
wZ5sTLF0925ZQWJB5cIhzc8KQIvguGCX1znLQJJaRHyYOUXIN77AKEfALKAinBit
|
||||||
|
25paDnbXAqGn1CR3UwFWUZZW+c3UEhWhmpghQpS1tIl0KI6IAvnrGIdw2kKIouo=
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----`;*/
|
||||||
|
|
||||||
|
const P384 = {
|
||||||
|
privateKeyPkcs8: `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAYo22xn2kZjN8MInom
|
||||||
|
NDsgD/zhpUwnCYch634jUgO59fN9m2lR5ekaI1XABHz39rihZANiAAQwXoCsPOLv
|
||||||
|
Nn2STUs/hpL41CQveSL3WUmJ4QdtD7UFCl1mBO6ME0xSUgIQTUNkHt5k9CpOq3x9
|
||||||
|
r+LG5+GcisoLn7R54R+bRoGp/p1ZBeuBXoCgthvs+RFoT3OewUmA8oQ=
|
||||||
|
-----END PRIVATE KEY-----`,
|
||||||
|
publicKey: `-----BEGIN PUBLIC KEY-----
|
||||||
|
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEMF6ArDzi7zZ9kk1LP4aS+NQkL3ki91lJ
|
||||||
|
ieEHbQ+1BQpdZgTujBNMUlICEE1DZB7eZPQqTqt8fa/ixufhnIrKC5+0eeEfm0aB
|
||||||
|
qf6dWQXrgV6AoLYb7PkRaE9znsFJgPKE
|
||||||
|
-----END PUBLIC KEY-----`
|
||||||
|
};
|
||||||
|
|
||||||
|
const P521 = {
|
||||||
|
privateKeyPkcs8: `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAifBaJDqNwOtKgThc
|
||||||
|
FU34GzPQ73ubOQg9dnighpVGwA3b/KwCifimCNKDmKnXJaE04mEcxg8yzcFKausF
|
||||||
|
5I8o206hgYkDgYYABAGwpkwrBBlZOdx4u9mxqYxJvtzAHaFFAzl21WQVbAjyrqXe
|
||||||
|
nFPMkhbFpEEWr1ualPYKQkHe14AX33iU3fQ9MlBkgAAripsPbiKggAaog74cUERo
|
||||||
|
qbrUFZwMbptGgovpE6pU93h7A1wb3Vtw9DZQCgiNbwzMbdsft+p2RJ8iSxWEC6Gd
|
||||||
|
mw==
|
||||||
|
-----END PRIVATE KEY-----`,
|
||||||
|
publicKey: `-----BEGIN PUBLIC KEY-----
|
||||||
|
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBsKZMKwQZWTnceLvZsamMSb7cwB2h
|
||||||
|
RQM5dtVkFWwI8q6l3pxTzJIWxaRBFq9bmpT2CkJB3teAF994lN30PTJQZIAAK4qb
|
||||||
|
D24ioIAGqIO+HFBEaKm61BWcDG6bRoKL6ROqVPd4ewNcG91bcPQ2UAoIjW8MzG3b
|
||||||
|
H7fqdkSfIksVhAuhnZs=
|
||||||
|
-----END PUBLIC KEY-----`
|
||||||
|
};
|
||||||
|
|
||||||
|
const PEM_PPRIV_RSA512 = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOQIBAAJBAPKr0Dp6YdItzOfk6a7ma7L4BF4LnelMYKtboGLrk6ihtqFPZFRL
|
||||||
|
NcJi68Hvnt8stMrP50t6jqwWQ2EjMdkj6fsCAwEAAQJAOJUpM0lv36MAQR3WAwsF
|
||||||
|
F7DOy+LnigteCvaNWiNVxZ6jByB5Qb7sall/Qlu9sFI0ZwrlVcKS0kldee7JTYlL
|
||||||
|
WQIhAP3UKEfOtpTgT1tYmdhaqjxqMfxBom0Ri+rt9ajlzs6vAiEA9L85B8/Gnb7p
|
||||||
|
6Af7/wpmafL277OV4X4xBfzMR+TUzHUCIBq+VLQkInaTH6lXL3ZtLwyIf9W9MJjf
|
||||||
|
RWeuRLjT5bM/AiBF7Kw6kx5Hy1fAtydEApCoDIaIjWJw/kC7WTJ0B+jUUQIgV6dw
|
||||||
|
NSyj0feakeD890gmId+lvl/w/3oUXiczqvl/N9o=
|
||||||
|
-----END RSA PRIVATE KEY-----`;
|
||||||
|
const PEM_PUB_RSA512 = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKr0Dp6YdItzOfk6a7ma7L4BF4LnelM
|
||||||
|
YKtboGLrk6ihtqFPZFRLNcJi68Hvnt8stMrP50t6jqwWQ2EjMdkj6fsCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify: P-256 with MD5",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P256.privateKeyPkcs1, "MD5", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "MD5", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify: P-256 with SHA1",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P256.privateKeyPkcs1, "SHA-1", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-1", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify: P-256 with SHA256",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P256.privateKeyPkcs1, "SHA-256", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify: P-256 with SHA384",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P256.privateKeyPkcs1, "SHA-384", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-384", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify: P-256 with SHA512",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P256.privateKeyPkcs1, "SHA-512", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-512", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify:: Using a private key in PKCS#8 format works",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P256.privateKeyPkcs8, "SHA-256", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify: P-384 with SHA384",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P384.privateKeyPkcs8, "SHA-384", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-384", P384.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign/Verify: P-521 with SHA512",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P521.privateKeyPkcs8, "SHA-512", "ASN.1 HEX"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-512", P521.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ECDSA Sign
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign: Using public key fails",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Provided key is not a private key.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [P256.publicKey, "SHA-256", "ASN.1 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Sign: Using an RSA key fails",
|
||||||
|
input: ASCII_TEXT,
|
||||||
|
expectedOutput: "Provided key is not an EC key.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Sign",
|
||||||
|
"args": [PEM_PPRIV_RSA512, "SHA-256", "ASN.1 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ECDSA Verify
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: P-256 with SHA256 (ASN.1 signature)",
|
||||||
|
input: P256.signature.sha256.asn1,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["Auto", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: P-256 with SHA256 (P1363 signature)",
|
||||||
|
input: P256.signature.sha256.p1363,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["Auto", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: P-256 with SHA256 (JWS signature)",
|
||||||
|
input: P256.signature.sha256.jws,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["Auto", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: P-256 with SHA256 (JSON signature)",
|
||||||
|
input: P256.signature.sha256.json,
|
||||||
|
expectedOutput: "Verified OK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["Auto", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: JSON signature missing r",
|
||||||
|
input: JSON.stringify({s: JSON.parse(P256.signature.sha256.json).s}),
|
||||||
|
expectedOutput: 'No "r" value in the signature JSON',
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["Auto", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: JSON signature missing s",
|
||||||
|
input: JSON.stringify({r: JSON.parse(P256.signature.sha256.json).r}),
|
||||||
|
expectedOutput: 'No "s" value in the signature JSON',
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["Auto", "SHA-256", P256.publicKey, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: Using private key fails",
|
||||||
|
input: P256.signature.sha256.asn1,
|
||||||
|
expectedOutput: "Provided key is not a public key.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-256", P256.privateKeyPkcs1, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Verify: Using an RSA key fails",
|
||||||
|
input: P256.signature.sha256.asn1,
|
||||||
|
expectedOutput: "Provided key is not an EC key.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Verify",
|
||||||
|
"args": ["ASN.1 HEX", "SHA-256", PEM_PUB_RSA512, ASCII_TEXT]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// ECDSA Signatur Conversion
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: ASN.1 To ASN.1",
|
||||||
|
input: P256.signature.sha256.asn1,
|
||||||
|
expectedOutput: P256.signature.sha256.asn1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "ASN.1 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: ASN.1 To P1363",
|
||||||
|
input: P256.signature.sha256.asn1,
|
||||||
|
expectedOutput: P256.signature.sha256.p1363,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "P1363 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: ASN.1 To JWS",
|
||||||
|
input: P256.signature.sha256.asn1,
|
||||||
|
expectedOutput: P256.signature.sha256.jws,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "JSON Web Signature"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: ASN.1 To JSON",
|
||||||
|
input: P256.signature.sha256.asn1,
|
||||||
|
expectedOutput: P256.signature.sha256.json,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "Raw JSON"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: P1363 To ASN.1",
|
||||||
|
input: P256.signature.sha256.p1363,
|
||||||
|
expectedOutput: P256.signature.sha256.asn1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "ASN.1 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: P1363 To P1363",
|
||||||
|
input: P256.signature.sha256.p1363,
|
||||||
|
expectedOutput: P256.signature.sha256.p1363,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "P1363 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: P1363 To JWS",
|
||||||
|
input: P256.signature.sha256.p1363,
|
||||||
|
expectedOutput: P256.signature.sha256.jws,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "JSON Web Signature"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: P1363 To JSON",
|
||||||
|
input: P256.signature.sha256.p1363,
|
||||||
|
expectedOutput: P256.signature.sha256.json,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "Raw JSON"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: JSON To ASN.1",
|
||||||
|
input: P256.signature.sha256.json,
|
||||||
|
expectedOutput: P256.signature.sha256.asn1,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "ASN.1 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: JSON To P1363",
|
||||||
|
input: P256.signature.sha256.json,
|
||||||
|
expectedOutput: P256.signature.sha256.p1363,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "P1363 HEX"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: JSON To JWS",
|
||||||
|
input: P256.signature.sha256.json,
|
||||||
|
expectedOutput: P256.signature.sha256.jws,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "JSON Web Signature"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECDSA Signature Conversion: JSON To JSON",
|
||||||
|
input: P256.signature.sha256.json,
|
||||||
|
expectedOutput: P256.signature.sha256.json,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "ECDSA Signature Conversion",
|
||||||
|
"args": ["Auto", "Raw JSON"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
|
@ -14,7 +14,7 @@ import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "GOST Encrypt: Magma",
|
name: "GOST Encrypt: 1989",
|
||||||
input: "Hello, World!",
|
input: "Hello, World!",
|
||||||
expectedOutput: "f124ac5c0853870906dbaf9b56",
|
expectedOutput: "f124ac5c0853870906dbaf9b56",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
|
@ -25,8 +25,7 @@ TestRegister.addTests([
|
||||||
{ "option": "Hex", "string": "0011223344556677" },
|
{ "option": "Hex", "string": "0011223344556677" },
|
||||||
"Raw",
|
"Raw",
|
||||||
"Hex",
|
"Hex",
|
||||||
"GOST 28147 (Magma, 1989)",
|
"GOST 28147 (1989)",
|
||||||
"64",
|
|
||||||
"E-SC",
|
"E-SC",
|
||||||
"OFB",
|
"OFB",
|
||||||
"CP",
|
"CP",
|
||||||
|
@ -48,7 +47,6 @@ TestRegister.addTests([
|
||||||
"Raw",
|
"Raw",
|
||||||
"Hex",
|
"Hex",
|
||||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
"128",
|
|
||||||
"E-SC",
|
"E-SC",
|
||||||
"CBC",
|
"CBC",
|
||||||
"CP",
|
"CP",
|
||||||
|
@ -58,7 +56,7 @@ TestRegister.addTests([
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GOST Decrypt: Magma",
|
name: "GOST Decrypt: 1989",
|
||||||
input: "f124ac5c0853870906dbaf9b56",
|
input: "f124ac5c0853870906dbaf9b56",
|
||||||
expectedOutput: "Hello, World!",
|
expectedOutput: "Hello, World!",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
|
@ -69,8 +67,7 @@ TestRegister.addTests([
|
||||||
{ "option": "Hex", "string": "0011223344556677" },
|
{ "option": "Hex", "string": "0011223344556677" },
|
||||||
"Hex",
|
"Hex",
|
||||||
"Raw",
|
"Raw",
|
||||||
"GOST 28147 (Magma, 1989)",
|
"GOST 28147 (1989)",
|
||||||
"128",
|
|
||||||
"E-SC",
|
"E-SC",
|
||||||
"OFB",
|
"OFB",
|
||||||
"CP",
|
"CP",
|
||||||
|
@ -92,7 +89,6 @@ TestRegister.addTests([
|
||||||
"Hex",
|
"Hex",
|
||||||
"Raw",
|
"Raw",
|
||||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
"128",
|
|
||||||
"E-TEST",
|
"E-TEST",
|
||||||
"CBC",
|
"CBC",
|
||||||
"CP",
|
"CP",
|
||||||
|
@ -113,8 +109,7 @@ TestRegister.addTests([
|
||||||
{ "option": "Hex", "string": "0011223344556677" },
|
{ "option": "Hex", "string": "0011223344556677" },
|
||||||
"Raw",
|
"Raw",
|
||||||
"Hex",
|
"Hex",
|
||||||
"GOST 28147 (Magma, 1989)",
|
"GOST 28147 (1989)",
|
||||||
"64",
|
|
||||||
"E-C",
|
"E-C",
|
||||||
48
|
48
|
||||||
]
|
]
|
||||||
|
@ -134,7 +129,6 @@ TestRegister.addTests([
|
||||||
{ "option": "Hex", "string": "42b77fb3d6f6bf04" },
|
{ "option": "Hex", "string": "42b77fb3d6f6bf04" },
|
||||||
"Raw",
|
"Raw",
|
||||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||||
"128",
|
|
||||||
"E-TEST"
|
"E-TEST"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -152,8 +146,7 @@ TestRegister.addTests([
|
||||||
{ "option": "Hex", "string": "0011223344556677" },
|
{ "option": "Hex", "string": "0011223344556677" },
|
||||||
"Raw",
|
"Raw",
|
||||||
"Hex",
|
"Hex",
|
||||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
"GOST R 34.12 (Magma, 2015)",
|
||||||
"64",
|
|
||||||
"E-TEST",
|
"E-TEST",
|
||||||
"CP"
|
"CP"
|
||||||
]
|
]
|
||||||
|
@ -172,8 +165,7 @@ TestRegister.addTests([
|
||||||
{ "option": "Latin1", "string": "00112233" },
|
{ "option": "Latin1", "string": "00112233" },
|
||||||
"Hex",
|
"Hex",
|
||||||
"Raw",
|
"Raw",
|
||||||
"GOST 28147 (Magma, 1989)",
|
"GOST 28147 (1989)",
|
||||||
"64",
|
|
||||||
"E-Z",
|
"E-Z",
|
||||||
"CP"
|
"CP"
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* JA4Fingerprint tests.
|
* JA4 tests.
|
||||||
*
|
*
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
* @copyright Crown Copyright 2024
|
* @copyright Crown Copyright 2024
|
||||||
|
@ -52,4 +52,70 @@ TestRegister.addTests([
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "JA4Server Fingerprint: TLS 1.2 h2 ALPN",
|
||||||
|
input: "16030300640200006003035f0236c07f47bfb12dc2da706ecb3fe7f9eeac9968cc2ddf444f574e4752440120b89ff1ab695278c69b8a73f76242ef755e0b13dc6d459aaaa784fec9c2dfce34cca900001800000000ff01000100000b00020100001000050003026832",
|
||||||
|
expectedOutput: "t1204h2_cca9_1428ce7b4018",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4Server Fingerprint",
|
||||||
|
"args": ["Hex", "JA4S"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JA4Server Fingerprint: TLS 1.2 h2 ALPN Raw",
|
||||||
|
input: "16030300640200006003035f0236c07f47bfb12dc2da706ecb3fe7f9eeac9968cc2ddf444f574e4752440120b89ff1ab695278c69b8a73f76242ef755e0b13dc6d459aaaa784fec9c2dfce34cca900001800000000ff01000100000b00020100001000050003026832",
|
||||||
|
expectedOutput: "t1204h2_cca9_0000,ff01,000b,0010",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4Server Fingerprint",
|
||||||
|
"args": ["Hex", "JA4S Raw"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JA4Server Fingerprint: TLS 1.3",
|
||||||
|
input: "160303007a020000760303236d214556452c55a0754487e64b1a8b0262c50ba23004c9d504166a6de3439920d0b0099243c9296a0c84153ea4ada7d87ad017f4211c2ea1350b0b3cc5514d5f130100002e00330024001d002099e3cc43a2c9941ae75af1b2c7a629bee3ee7031973cad85c82f2f23677fb244002b00020304",
|
||||||
|
expectedOutput: "t130200_1301_234ea6891581",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4Server Fingerprint",
|
||||||
|
"args": ["Hex", "JA4S"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JA4Server Fingerprint: TLS 1.3 Raw",
|
||||||
|
input: "160303007a020000760303236d214556452c55a0754487e64b1a8b0262c50ba23004c9d504166a6de3439920d0b0099243c9296a0c84153ea4ada7d87ad017f4211c2ea1350b0b3cc5514d5f130100002e00330024001d002099e3cc43a2c9941ae75af1b2c7a629bee3ee7031973cad85c82f2f23677fb244002b00020304",
|
||||||
|
expectedOutput: "t130200_1301_0033,002b",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4Server Fingerprint",
|
||||||
|
"args": ["Hex", "JA4S Raw"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JA4Server Fingerprint: TLS 1.3 non-ascii ALPN",
|
||||||
|
input: "160303007a020000760303897c232e3ee313314f2b662307ff4f7e2cf1caeec1b27711bca77f469519168520bc58b92f865e6b9aa4a6371cadcb0afe1da1c0f705209a11d52357f56d5dd962130100002e00330024001d002076b8b7ed0f96b63a773d85ab6f3a87a151c130529785b41a4defb53184055957002b00020304",
|
||||||
|
expectedOutput: "t130200_1301_234ea6891581",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4Server Fingerprint",
|
||||||
|
"args": ["Hex", "JA4S"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JA4Server Fingerprint: TLS 1.3 non-ascii ALPN Raw",
|
||||||
|
input: "160303007a020000760303897c232e3ee313314f2b662307ff4f7e2cf1caeec1b27711bca77f469519168520bc58b92f865e6b9aa4a6371cadcb0afe1da1c0f705209a11d52357f56d5dd962130100002e00330024001d002076b8b7ed0f96b63a773d85ab6f3a87a151c130529785b41a4defb53184055957002b00020304",
|
||||||
|
expectedOutput: "t130200_1301_0033,002b",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "JA4Server Fingerprint",
|
||||||
|
"args": ["Hex", "JA4S Raw"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
]);
|
]);
|
359
tests/operations/tests/JWK.mjs
Normal file
359
tests/operations/tests/JWK.mjs
Normal file
|
@ -0,0 +1,359 @@
|
||||||
|
/**
|
||||||
|
* JWK conversion
|
||||||
|
*
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
// test data for RSA key pair
|
||||||
|
const RSA_512 = {
|
||||||
|
private: {
|
||||||
|
pem1: `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOQIBAAJBAPKr0Dp6YdItzOfk6a7ma7L4BF4LnelMYKtboGLrk6ihtqFPZFRL
|
||||||
|
NcJi68Hvnt8stMrP50t6jqwWQ2EjMdkj6fsCAwEAAQJAOJUpM0lv36MAQR3WAwsF
|
||||||
|
F7DOy+LnigteCvaNWiNVxZ6jByB5Qb7sall/Qlu9sFI0ZwrlVcKS0kldee7JTYlL
|
||||||
|
WQIhAP3UKEfOtpTgT1tYmdhaqjxqMfxBom0Ri+rt9ajlzs6vAiEA9L85B8/Gnb7p
|
||||||
|
6Af7/wpmafL277OV4X4xBfzMR+TUzHUCIBq+VLQkInaTH6lXL3ZtLwyIf9W9MJjf
|
||||||
|
RWeuRLjT5bM/AiBF7Kw6kx5Hy1fAtydEApCoDIaIjWJw/kC7WTJ0B+jUUQIgV6dw
|
||||||
|
NSyj0feakeD890gmId+lvl/w/3oUXiczqvl/N9o=
|
||||||
|
-----END RSA PRIVATE KEY-----`,
|
||||||
|
pem8: `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA8qvQOnph0i3M5+Tp
|
||||||
|
ruZrsvgEXgud6Uxgq1ugYuuTqKG2oU9kVEs1wmLrwe+e3yy0ys/nS3qOrBZDYSMx
|
||||||
|
2SPp+wIDAQABAkA4lSkzSW/fowBBHdYDCwUXsM7L4ueKC14K9o1aI1XFnqMHIHlB
|
||||||
|
vuxqWX9CW72wUjRnCuVVwpLSSV157slNiUtZAiEA/dQoR862lOBPW1iZ2FqqPGox
|
||||||
|
/EGibRGL6u31qOXOzq8CIQD0vzkHz8advunoB/v/CmZp8vbvs5XhfjEF/MxH5NTM
|
||||||
|
dQIgGr5UtCQidpMfqVcvdm0vDIh/1b0wmN9FZ65EuNPlsz8CIEXsrDqTHkfLV8C3
|
||||||
|
J0QCkKgMhoiNYnD+QLtZMnQH6NRRAiBXp3A1LKPR95qR4Pz3SCYh36W+X/D/ehRe
|
||||||
|
JzOq+X832g==
|
||||||
|
-----END PRIVATE KEY-----`,
|
||||||
|
jwk: {
|
||||||
|
"kty": "RSA",
|
||||||
|
"n": "8qvQOnph0i3M5-TpruZrsvgEXgud6Uxgq1ugYuuTqKG2oU9kVEs1wmLrwe-e3yy0ys_nS3qOrBZDYSMx2SPp-w",
|
||||||
|
"e": "AQAB",
|
||||||
|
"d": "OJUpM0lv36MAQR3WAwsFF7DOy-LnigteCvaNWiNVxZ6jByB5Qb7sall_Qlu9sFI0ZwrlVcKS0kldee7JTYlLWQ",
|
||||||
|
"p": "_dQoR862lOBPW1iZ2FqqPGox_EGibRGL6u31qOXOzq8",
|
||||||
|
"q": "9L85B8_Gnb7p6Af7_wpmafL277OV4X4xBfzMR-TUzHU",
|
||||||
|
"dp": "Gr5UtCQidpMfqVcvdm0vDIh_1b0wmN9FZ65EuNPlsz8",
|
||||||
|
"dq": "ReysOpMeR8tXwLcnRAKQqAyGiI1icP5Au1kydAfo1FE",
|
||||||
|
"qi": "V6dwNSyj0feakeD890gmId-lvl_w_3oUXiczqvl_N9o"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
public: {
|
||||||
|
pem1: `-----BEGIN RSA PUBLIC KEY-----
|
||||||
|
MEgCQQDyq9A6emHSLczn5Omu5muy+AReC53pTGCrW6Bi65OoobahT2RUSzXCYuvB
|
||||||
|
757fLLTKz+dLeo6sFkNhIzHZI+n7AgMBAAE=
|
||||||
|
-----END RSA PUBLIC KEY-----`,
|
||||||
|
pem8: `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKr0Dp6YdItzOfk6a7ma7L4BF4LnelM
|
||||||
|
YKtboGLrk6ihtqFPZFRLNcJi68Hvnt8stMrP50t6jqwWQ2EjMdkj6fsCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----`,
|
||||||
|
cert: `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBfTCCASegAwIBAgIUeisK5Nwss2DGg5PCs4uSxxXyyNkwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwEzERMA8GA1UEAwwIUlNBIHRlc3QwHhcNMjExMTE5MTcyMDI2WhcNMzExMTE3
|
||||||
|
MTcyMDI2WjATMREwDwYDVQQDDAhSU0EgdGVzdDBcMA0GCSqGSIb3DQEBAQUAA0sA
|
||||||
|
MEgCQQDyq9A6emHSLczn5Omu5muy+AReC53pTGCrW6Bi65OoobahT2RUSzXCYuvB
|
||||||
|
757fLLTKz+dLeo6sFkNhIzHZI+n7AgMBAAGjUzBRMB0GA1UdDgQWBBRO+jvkqq5p
|
||||||
|
pnQgwMMnRoun6e7eiTAfBgNVHSMEGDAWgBRO+jvkqq5ppnQgwMMnRoun6e7eiTAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAR/5HAZM5qBhU/ezDUIFx
|
||||||
|
gmUGoFbIb5kJD41YCnaSdrgWglh4He4melSs42G/oxBBjuCJ0bUpqWnLl+lJkv1z
|
||||||
|
IA==
|
||||||
|
-----END CERTIFICATE-----`,
|
||||||
|
jwk: {
|
||||||
|
"kty": "RSA",
|
||||||
|
"n": "8qvQOnph0i3M5-TpruZrsvgEXgud6Uxgq1ugYuuTqKG2oU9kVEs1wmLrwe-e3yy0ys_nS3qOrBZDYSMx2SPp-w",
|
||||||
|
"e": "AQAB"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// test data for EC key pair
|
||||||
|
const EC_P256 = {
|
||||||
|
private: {
|
||||||
|
pem1: `-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEINtTjwUkgfAiSwqgcGAXWyE0ueIW6n2k395dmQZ3vGr4oAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEDUc8A0EDNKoCYIPWMHz1yUzqE5mJgusgcAE8H6810fkJ8ZmTNiCC
|
||||||
|
a6sLgR2vD1VNh2diirWgKPH4PVMKav5e6Q==
|
||||||
|
-----END EC PRIVATE KEY-----`,
|
||||||
|
pem8: `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg21OPBSSB8CJLCqBw
|
||||||
|
YBdbITS54hbqfaTf3l2ZBne8avihRANCAAQNRzwDQQM0qgJgg9YwfPXJTOoTmYmC
|
||||||
|
6yBwATwfrzXR+QnxmZM2IIJrqwuBHa8PVU2HZ2KKtaAo8fg9Uwpq/l7p
|
||||||
|
-----END PRIVATE KEY-----`,
|
||||||
|
jwk: {
|
||||||
|
"kty": "EC",
|
||||||
|
"crv": "P-256",
|
||||||
|
"x": "DUc8A0EDNKoCYIPWMHz1yUzqE5mJgusgcAE8H6810fk",
|
||||||
|
"y": "CfGZkzYggmurC4Edrw9VTYdnYoq1oCjx-D1TCmr-Xuk",
|
||||||
|
"d": "21OPBSSB8CJLCqBwYBdbITS54hbqfaTf3l2ZBne8avg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
public: {
|
||||||
|
pem8: `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDUc8A0EDNKoCYIPWMHz1yUzqE5mJ
|
||||||
|
gusgcAE8H6810fkJ8ZmTNiCCa6sLgR2vD1VNh2diirWgKPH4PVMKav5e6Q==
|
||||||
|
-----END PUBLIC KEY-----`,
|
||||||
|
cert: `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBfzCCASWgAwIBAgIUK4H8J3Hr7NpRLPrACj8Pje4JJJ0wCgYIKoZIzj0EAwIw
|
||||||
|
FTETMBEGA1UEAwwKUC0yNTYgdGVzdDAeFw0yMTExMTkxNzE5NDVaFw0zMTExMTcx
|
||||||
|
NzE5NDVaMBUxEzARBgNVBAMMClAtMjU2IHRlc3QwWTATBgcqhkjOPQIBBggqhkjO
|
||||||
|
PQMBBwNCAAQNRzwDQQM0qgJgg9YwfPXJTOoTmYmC6yBwATwfrzXR+QnxmZM2IIJr
|
||||||
|
qwuBHa8PVU2HZ2KKtaAo8fg9Uwpq/l7po1MwUTAdBgNVHQ4EFgQU/SxodXrpkybM
|
||||||
|
gcIgkxnRKd7HMzowHwYDVR0jBBgwFoAU/SxodXrpkybMgcIgkxnRKd7HMzowDwYD
|
||||||
|
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiBU9PrOa/kXCpTTBInRf/sN
|
||||||
|
ac2iDHmbdpWzcXI+xLKNYAIhAIRR1LRSHVwOTLQ/iBXd+8LCkm5aTB27RW46LN80
|
||||||
|
ylxt
|
||||||
|
-----END CERTIFICATE-----`,
|
||||||
|
jwk: {
|
||||||
|
"kty": "EC",
|
||||||
|
"crv": "P-256",
|
||||||
|
"x": "DUc8A0EDNKoCYIPWMHz1yUzqE5mJgusgcAE8H6810fk",
|
||||||
|
"y": "CfGZkzYggmurC4Edrw9VTYdnYoq1oCjx-D1TCmr-Xuk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const PEM_PRIV_DSA1024 = `-----BEGIN DSA PRIVATE KEY-----
|
||||||
|
MIIBuwIBAAKBgQCkFEttBrPHEJRgcvaT8HbZs9h1pVQLHhn2F452izusRox1czMM
|
||||||
|
IC8Z7YQiM1pt6bgEmf0h8ldx6UFT0YL9JWSbyBy1U5pHKfnz/xjeg7ZMReL4F0/T
|
||||||
|
Gwmu4ercqfM//TmEg9nL3nDxb4WmF2al/SmHN3qlzYmYaIDEFfEuu8vWbwIVAMOq
|
||||||
|
7pqQiMGUu6uJY/nQTWW0c3IfAoGARWryStp2AElj538qN9tWRuyobRA93Q1ujrdM
|
||||||
|
EqsqVpMZd1a8qtRyMaZVVdB7N3EweNUuFOoSAp10s/SQEH9qhVo6NwvzhB7lEtm4
|
||||||
|
5FjWW9+9WCuuFOGZpTy8PSFAvQcfUqunP/DeaDliNmgKci+n0nfIBakuQn10Zmqk
|
||||||
|
vGu8NZICgYBUsoQeXSJ19e6XZenk6G8wVI3yXFqnRAwb6s7sAVoPwfDCsOXTxC7W
|
||||||
|
Mlfz0HcYMiifFKEd28NnuAZ2e0ngyPHsb9s5phzTgRfO3GFzOjsjwgx3DmQI2Ck2
|
||||||
|
yOWHSAtaNhH4DoBZEyNsb1akiB50vx9b09EHN4weqbgAu743NMDHRQIVAIG5uiiO
|
||||||
|
OnWUYieHAiVIPkBCrYUd
|
||||||
|
-----END DSA PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc8037#appendix-A.2
|
||||||
|
const JWK_PUB_ED25591 = {
|
||||||
|
"kty": "OKP",
|
||||||
|
"crv": "Ed25519",
|
||||||
|
"x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
|
||||||
|
};
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: Missing footer",
|
||||||
|
input: RSA_512.private.pem1.substring(0, RSA_512.private.pem1.length / 2),
|
||||||
|
expectedOutput: "PEM footer '-----END RSA PRIVATE KEY-----' not found",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: DSA not supported",
|
||||||
|
input: PEM_PRIV_DSA1024,
|
||||||
|
expectedOutput: "DSA keys are not supported for JWK",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test RSA key convertion
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: RSA Private Key PKCS1",
|
||||||
|
input: RSA_512.private.pem1,
|
||||||
|
expectedOutput: JSON.stringify(RSA_512.private.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: RSA Private Key PKCS8",
|
||||||
|
input: RSA_512.private.pem8,
|
||||||
|
expectedOutput: JSON.stringify(RSA_512.private.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: RSA Public Key PKCS1",
|
||||||
|
input: RSA_512.public.pem1,
|
||||||
|
expectedOutput: "Unsupported RSA public key format. Only PKCS#8 is supported.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: RSA Public Key PKCS8",
|
||||||
|
input: RSA_512.public.pem8,
|
||||||
|
expectedOutput: JSON.stringify(RSA_512.public.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: Certificate with RSA Public Key",
|
||||||
|
input: RSA_512.public.cert,
|
||||||
|
expectedOutput: JSON.stringify(RSA_512.public.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test EC key conversion
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: EC Private Key PKCS1",
|
||||||
|
input: EC_P256.private.pem1,
|
||||||
|
expectedOutput: JSON.stringify(EC_P256.private.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: EC Private Key PKCS8",
|
||||||
|
input: EC_P256.private.pem8,
|
||||||
|
expectedOutput: JSON.stringify(EC_P256.private.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: EC Public Key",
|
||||||
|
input: EC_P256.public.pem8,
|
||||||
|
expectedOutput: JSON.stringify(EC_P256.public.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PEM to JWK: Certificate with EC Public Key",
|
||||||
|
input: EC_P256.public.cert,
|
||||||
|
expectedOutput: JSON.stringify(EC_P256.public.jwk),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "PEM to JWK",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: not a JWK",
|
||||||
|
input: "\"foobar\"",
|
||||||
|
expectedOutput: "Input is not a JSON Web Key",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: unsupported key type",
|
||||||
|
input: JSON.stringify(JWK_PUB_ED25591),
|
||||||
|
expectedOutput: "Unsupported JWK key type 'OKP'",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test RSA key conversion
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: RSA Private Key",
|
||||||
|
input: JSON.stringify(RSA_512.private.jwk),
|
||||||
|
expectedOutput: RSA_512.private.pem8.replace(/\r/g, "").replace(/\n/g, "\r\n")+"\r\n",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: RSA Public Key",
|
||||||
|
input: JSON.stringify(RSA_512.public.jwk),
|
||||||
|
expectedOutput: RSA_512.public.pem8.replace(/\r/g, "").replace(/\n/g, "\r\n")+"\r\n",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test EC key conversion
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: EC Private Key",
|
||||||
|
input: JSON.stringify(EC_P256.private.jwk),
|
||||||
|
expectedOutput: EC_P256.private.pem8.replace(/\r/g, "").replace(/\n/g, "\r\n")+"\r\n",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: EC Public Key",
|
||||||
|
input: JSON.stringify(EC_P256.public.jwk),
|
||||||
|
expectedOutput: EC_P256.public.pem8.replace(/\r/g, "").replace(/\n/g, "\r\n")+"\r\n",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: Array of keys",
|
||||||
|
input: JSON.stringify([RSA_512.public.jwk, EC_P256.public.jwk]),
|
||||||
|
expectedOutput: (RSA_512.public.pem8 + "\n" + EC_P256.public.pem8 + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JWK to PEM: JSON Web Key Set",
|
||||||
|
input: JSON.stringify({"keys": [RSA_512.public.jwk, EC_P256.public.jwk]}),
|
||||||
|
expectedOutput: (RSA_512.public.pem8 + "\n" + EC_P256.public.pem8 + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "JWK to PEM",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]);
|
|
@ -29,31 +29,28 @@ NFgFNIvSXhbqMYoHAAApMHJOxiWpBFdYKp3tESnlgh2lUh7lQtmOjD4a1dzfU8PU
|
||||||
oViyp+UJGasN2WRd+4VtaPw64w==
|
oViyp+UJGasN2WRd+4VtaPw64w==
|
||||||
-----END CERTIFICATE REQUEST-----`;
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
const OUT_EXAMPLE_COM_RSA_1024 = `Version: 1 (0x00)
|
const OUT_EXAMPLE_COM_RSA_1024 = `Subject
|
||||||
Subject
|
C = CH
|
||||||
C = CH
|
|
||||||
ST = Zurich
|
ST = Zurich
|
||||||
L = Zurich
|
L = Zurich
|
||||||
O = Example RE
|
O = Example RE
|
||||||
OU = IT Department
|
OU = IT Department
|
||||||
CN = example.com
|
CN = example.com
|
||||||
Subject Alternative Names
|
|
||||||
DNS: example.com
|
|
||||||
DNS: www.example.com
|
|
||||||
Public Key
|
Public Key
|
||||||
Algorithm: RSA
|
Algorithm: RSA
|
||||||
Length: 1024 bits
|
Length: 1024 bits
|
||||||
Modulus: ae:b4:eb:2c:8e:85:93:38:d7:f0:56:5f:72:5b:76:a3:
|
Modulus: 00:ae:b4:eb:2c:8e:85:93:38:d7:f0:56:5f:72:5b:76:
|
||||||
1d:43:cf:b2:91:c2:de:5f:e9:f7:d9:89:ce:ed:c0:b0:
|
a3:1d:43:cf:b2:91:c2:de:5f:e9:f7:d9:89:ce:ed:c0:
|
||||||
0a:27:86:a8:fc:7d:c0:3e:3c:28:15:55:17:1a:38:8d:
|
b0:0a:27:86:a8:fc:7d:c0:3e:3c:28:15:55:17:1a:38:
|
||||||
8f:f5:c5:d9:19:48:77:85:31:07:56:fa:0a:05:a3:ba:
|
8d:8f:f5:c5:d9:19:48:77:85:31:07:56:fa:0a:05:a3:
|
||||||
30:5b:f5:6e:75:ad:37:6f:7d:62:f2:00:7b:2b:2d:ca:
|
ba:30:5b:f5:6e:75:ad:37:6f:7d:62:f2:00:7b:2b:2d:
|
||||||
6d:a5:5c:fe:57:d6:3c:5f:d9:04:14:24:46:18:3c:86:
|
ca:6d:a5:5c:fe:57:d6:3c:5f:d9:04:14:24:46:18:3c:
|
||||||
e7:e5:fe:36:ee:82:3b:34:e9:50:f0:e3:e1:b2:08:5f:
|
86:e7:e5:fe:36:ee:82:3b:34:e9:50:f0:e3:e1:b2:08:
|
||||||
fb:8f:93:77:c3:60:31:2a:2c:29:55:cb:cf:d5:4b:8f
|
5f:fb:8f:93:77:c3:60:31:2a:2c:29:55:cb:cf:d5:4b:
|
||||||
|
8f
|
||||||
Exponent: 65537 (0x10001)
|
Exponent: 65537 (0x10001)
|
||||||
Signature
|
Signature
|
||||||
Algorithm: sha256WithRSAEncryption
|
Algorithm: SHA256withRSA
|
||||||
Signature: 74:99:49:4f:82:de:a9:b7:f9:23:0f:4a:73:39:43:64:
|
Signature: 74:99:49:4f:82:de:a9:b7:f9:23:0f:4a:73:39:43:64:
|
||||||
e5:ef:67:04:54:18:40:6b:86:20:71:98:6c:f5:f7:9a:
|
e5:ef:67:04:54:18:40:6b:86:20:71:98:6c:f5:f7:9a:
|
||||||
2e:16:77:db:d4:09:d3:e2:c6:d3:d2:4e:e9:c7:5a:cd:
|
2e:16:77:db:d4:09:d3:e2:c6:d3:d2:4e:e9:c7:5a:cd:
|
||||||
|
@ -62,14 +59,17 @@ Signature
|
||||||
25:a9:04:57:58:2a:9d:ed:11:29:e5:82:1d:a5:52:1e:
|
25:a9:04:57:58:2a:9d:ed:11:29:e5:82:1d:a5:52:1e:
|
||||||
e5:42:d9:8e:8c:3e:1a:d5:dc:df:53:c3:d4:a1:58:b2:
|
e5:42:d9:8e:8c:3e:1a:d5:dc:df:53:c3:d4:a1:58:b2:
|
||||||
a7:e5:09:19:ab:0d:d9:64:5d:fb:85:6d:68:fc:3a:e3
|
a7:e5:09:19:ab:0d:d9:64:5d:fb:85:6d:68:fc:3a:e3
|
||||||
Extensions
|
Requested Extensions
|
||||||
basicConstraints CRITICAL:
|
Basic Constraints: critical
|
||||||
CA = false
|
CA = false
|
||||||
keyUsage CRITICAL:
|
Key Usage: critical
|
||||||
Digital signature
|
Digital Signature
|
||||||
Key encipherment
|
Key encipherment
|
||||||
extKeyUsage:
|
Extended Key Usage:
|
||||||
TLS Web Server Authentication`;
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
// openssl req -newkey rsa:2048 -keyout test-rsa-2048.key -out test-rsa-2048.csr \
|
// openssl req -newkey rsa:2048 -keyout test-rsa-2048.key -out test-rsa-2048.csr \
|
||||||
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||||
|
@ -97,39 +97,36 @@ m9cpVxuxGLtONBnohzohnFECytSXWEXPIj8L9SpYK97G02nJYYCAcb5BF11Alfux
|
||||||
sNxtsr6zgPaLRrvOBT11WxJVKerbhfezAJ3naem1eM3VLxCGWwMwxg==
|
sNxtsr6zgPaLRrvOBT11WxJVKerbhfezAJ3naem1eM3VLxCGWwMwxg==
|
||||||
-----END CERTIFICATE REQUEST-----`;
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
const OUT_EXAMPLE_COM_RSA_2048 = `Version: 1 (0x00)
|
const OUT_EXAMPLE_COM_RSA_2048 = `Subject
|
||||||
Subject
|
C = CH
|
||||||
C = CH
|
|
||||||
ST = Zurich
|
ST = Zurich
|
||||||
L = Zurich
|
L = Zurich
|
||||||
O = Example RE
|
O = Example RE
|
||||||
OU = IT Department
|
OU = IT Department
|
||||||
CN = example.com
|
CN = example.com
|
||||||
Subject Alternative Names
|
|
||||||
DNS: example.com
|
|
||||||
DNS: www.example.com
|
|
||||||
Public Key
|
Public Key
|
||||||
Algorithm: RSA
|
Algorithm: RSA
|
||||||
Length: 2048 bits
|
Length: 2048 bits
|
||||||
Modulus: a3:e8:80:b9:96:3e:e2:bf:20:67:5c:b7:6b:ff:dc:c1:
|
Modulus: 00:a3:e8:80:b9:96:3e:e2:bf:20:67:5c:b7:6b:ff:dc:
|
||||||
4a:55:a5:5e:2a:9d:87:97:96:ad:ff:30:c5:2c:20:1e:
|
c1:4a:55:a5:5e:2a:9d:87:97:96:ad:ff:30:c5:2c:20:
|
||||||
e7:56:f0:87:b0:6a:35:52:44:72:2e:00:a7:09:57:03:
|
1e:e7:56:f0:87:b0:6a:35:52:44:72:2e:00:a7:09:57:
|
||||||
55:95:99:03:c1:14:12:65:63:04:19:56:3c:f9:50:03:
|
03:55:95:99:03:c1:14:12:65:63:04:19:56:3c:f9:50:
|
||||||
76:0a:63:47:c6:e7:79:9d:5d:37:62:66:76:fc:89:a5:
|
03:76:0a:63:47:c6:e7:79:9d:5d:37:62:66:76:fc:89:
|
||||||
47:3a:4a:71:93:0f:a9:4f:a5:88:90:82:d3:82:fe:5c:
|
a5:47:3a:4a:71:93:0f:a9:4f:a5:88:90:82:d3:82:fe:
|
||||||
86:ce:77:1f:95:cf:9d:9d:17:ef:82:73:e1:6e:48:5a:
|
5c:86:ce:77:1f:95:cf:9d:9d:17:ef:82:73:e1:6e:48:
|
||||||
bc:d3:7c:96:fa:a7:9f:2b:c2:6c:24:d3:bd:2a:e3:f1:
|
5a:bc:d3:7c:96:fa:a7:9f:2b:c2:6c:24:d3:bd:2a:e3:
|
||||||
44:b6:0a:48:00:03:6b:d3:08:26:2b:2b:bb:53:f3:70:
|
f1:44:b6:0a:48:00:03:6b:d3:08:26:2b:2b:bb:53:f3:
|
||||||
10:0e:72:29:8e:98:d9:c5:5a:ea:3e:2c:ab:1d:e2:55:
|
70:10:0e:72:29:8e:98:d9:c5:5a:ea:3e:2c:ab:1d:e2:
|
||||||
37:d0:e1:31:0d:d2:87:c2:dc:ad:eb:63:23:d5:cd:e8:
|
55:37:d0:e1:31:0d:d2:87:c2:dc:ad:eb:63:23:d5:cd:
|
||||||
94:ed:49:8e:f9:23:b5:65:a3:c0:72:3e:d0:48:13:8e:
|
e8:94:ed:49:8e:f9:23:b5:65:a3:c0:72:3e:d0:48:13:
|
||||||
f9:1e:5e:57:14:61:9b:ef:2e:5c:ac:74:a1:11:31:1a:
|
8e:f9:1e:5e:57:14:61:9b:ef:2e:5c:ac:74:a1:11:31:
|
||||||
33:bc:c4:c6:aa:aa:07:58:28:16:97:e4:6a:f5:9e:8f:
|
1a:33:bc:c4:c6:aa:aa:07:58:28:16:97:e4:6a:f5:9e:
|
||||||
4e:03:6c:44:ee:02:2a:e8:35:67:09:a1:f3:2e:9a:71:
|
8f:4e:03:6c:44:ee:02:2a:e8:35:67:09:a1:f3:2e:9a:
|
||||||
9e:ec:61:bf:dd:6a:bf:07:39:ea:89:9d:cd:29:0a:ff
|
71:9e:ec:61:bf:dd:6a:bf:07:39:ea:89:9d:cd:29:0a:
|
||||||
|
ff
|
||||||
Exponent: 65537 (0x10001)
|
Exponent: 65537 (0x10001)
|
||||||
Signature
|
Signature
|
||||||
Algorithm: sha256WithRSAEncryption
|
Algorithm: SHA256withRSA
|
||||||
Signature: 1b:47:23:7d:10:58:d6:90:73:bb:e8:df:ef:23:10:ac:
|
Signature: 1b:47:23:7d:10:58:d6:90:73:bb:e8:df:ef:23:10:ac:
|
||||||
ae:66:42:b8:7b:d9:a8:ab:56:e5:c7:9a:87:21:9b:25:
|
ae:66:42:b8:7b:d9:a8:ab:56:e5:c7:9a:87:21:9b:25:
|
||||||
31:ca:dd:06:ee:8b:e7:36:12:84:af:e5:fd:b2:74:a1:
|
31:ca:dd:06:ee:8b:e7:36:12:84:af:e5:fd:b2:74:a1:
|
||||||
|
@ -146,14 +143,17 @@ Signature
|
||||||
be:41:17:5d:40:95:fb:b1:b0:dc:6d:b2:be:b3:80:f6:
|
be:41:17:5d:40:95:fb:b1:b0:dc:6d:b2:be:b3:80:f6:
|
||||||
8b:46:bb:ce:05:3d:75:5b:12:55:29:ea:db:85:f7:b3:
|
8b:46:bb:ce:05:3d:75:5b:12:55:29:ea:db:85:f7:b3:
|
||||||
00:9d:e7:69:e9:b5:78:cd:d5:2f:10:86:5b:03:30:c6
|
00:9d:e7:69:e9:b5:78:cd:d5:2f:10:86:5b:03:30:c6
|
||||||
Extensions
|
Requested Extensions
|
||||||
basicConstraints CRITICAL:
|
Basic Constraints: critical
|
||||||
CA = false
|
CA = false
|
||||||
keyUsage CRITICAL:
|
Key Usage: critical
|
||||||
Digital signature
|
Digital Signature
|
||||||
Key encipherment
|
Key encipherment
|
||||||
extKeyUsage:
|
Extended Key Usage:
|
||||||
TLS Web Server Authentication`;
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
// openssl genpkey -genparam -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out test-ec-param.pem
|
// openssl genpkey -genparam -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -out test-ec-param.pem
|
||||||
// openssl req -newkey ec:test-ec-param.pem -keyout test-ec.key -out test-ec.csr \
|
// openssl req -newkey ec:test-ec-param.pem -keyout test-ec.key -out test-ec.csr \
|
||||||
|
@ -162,7 +162,7 @@ Extensions
|
||||||
// -addext "basicConstraints = critical,CA:FALSE" \
|
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||||
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||||
// -addext "extendedKeyUsage = serverAuth"
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
const IN_EXAMPLE_COM_EC = `-----BEGIN CERTIFICATE REQUEST-----
|
const IN_EXAMPLE_COM_EC_P256 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
MIIBmzCCAUECAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
MIIBmzCCAUECAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqG
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqG
|
||||||
|
@ -174,7 +174,690 @@ zj0EAwIDSAAwRQIgQkum/qaLzE3QZ3WD00uLpalUn113FObd7rM5Mr3HQwQCIQCr
|
||||||
7OjzYI9v7qIJp/E9N16XfJN87G2ZVIZ4FuPXVjokCQ==
|
7OjzYI9v7qIJp/E9N16XfJN87G2ZVIZ4FuPXVjokCQ==
|
||||||
-----END CERTIFICATE REQUEST-----`;
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
const OUT_EXAMPLE_COM_EC = `Parse CSR - Cannot read public key. OID is not RSA.`;
|
const OUT_EXAMPLE_COM_EC_P256 = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: ECDSA
|
||||||
|
Length: 256 bits
|
||||||
|
Pub: 04:09:a9:61:73:61:f8:bf:44:d1:0d:ec:2e:1a:ce:f8:
|
||||||
|
c1:75:5e:02:82:7e:a2:67:b6:b3:b2:22:4a:c6:c2:88:
|
||||||
|
90:7e:d1:db:25:64:c0:e9:db:b1:42:15:3f:dd:df:41:
|
||||||
|
f9:23:7f:89:b7:8a:63:ec:5e:88:d0:6b:b3:67:93:61:
|
||||||
|
9e
|
||||||
|
ASN1 OID: secp256r1
|
||||||
|
NIST CURVE: P-256
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withECDSA
|
||||||
|
Signature: 30:45:02:20:42:4b:a6:fe:a6:8b:cc:4d:d0:67:75:83:
|
||||||
|
d3:4b:8b:a5:a9:54:9f:5d:77:14:e6:dd:ee:b3:39:32:
|
||||||
|
bd:c7:43:04:02:21:00:ab:ec:e8:f3:60:8f:6f:ee:a2:
|
||||||
|
09:a7:f1:3d:37:5e:97:7c:93:7c:ec:6d:99:54:86:78:
|
||||||
|
16:e3:d7:56:3a:24:09
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Key encipherment
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
|
// openssl ecparam -name secp384r1 -genkey -noout -out test-ec-key.pem
|
||||||
|
// openssl req -new -key test-ec-key.pem -out test-ec.csr
|
||||||
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com"
|
||||||
|
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com"
|
||||||
|
// -addext "basicConstraints = critical,CA:FALSE"
|
||||||
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment"
|
||||||
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
|
const IN_EXAMPLE_COM_EC_P384 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIB2TCCAV4CAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTB2MBAGByqGSM49AgEGBSuB
|
||||||
|
BAAiA2IABE3rpRO164NtXx2kYMP1zlN7YgHEincO4YgwoyAYyJm3LwcbR+XyKg6A
|
||||||
|
/i+DUaGWa2FQ+f8w8VmEUFAgLozVxwnntPOCSODrXAQwJFPLCqs7m3o8OuzU3t07
|
||||||
|
POGhPtj7f6BtMGsGCSqGSIb3DQEJDjFeMFwwJwYDVR0RBCAwHoILZXhhbXBsZS5j
|
||||||
|
b22CD3d3dy5leGFtcGxlLmNvbTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF
|
||||||
|
oDATBgNVHSUEDDAKBggrBgEFBQcDATAKBggqhkjOPQQDAgNpADBmAjEAlq7RaEXU
|
||||||
|
aNHEC+qfuIitonWHOatm+qiiaNSh80QjLw5P1rszg9yQQigHd8cD7I4DAjEAzmo1
|
||||||
|
DLpcESwZCBrh3sPflDA38TZjoedRNeWcVxdn1QmwDWMeprD/zgPAey8GOmyj
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const OUT_EXAMPLE_COM_EC_P384 = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: ECDSA
|
||||||
|
Length: 384 bits
|
||||||
|
Pub: 04:4d:eb:a5:13:b5:eb:83:6d:5f:1d:a4:60:c3:f5:ce:
|
||||||
|
53:7b:62:01:c4:8a:77:0e:e1:88:30:a3:20:18:c8:99:
|
||||||
|
b7:2f:07:1b:47:e5:f2:2a:0e:80:fe:2f:83:51:a1:96:
|
||||||
|
6b:61:50:f9:ff:30:f1:59:84:50:50:20:2e:8c:d5:c7:
|
||||||
|
09:e7:b4:f3:82:48:e0:eb:5c:04:30:24:53:cb:0a:ab:
|
||||||
|
3b:9b:7a:3c:3a:ec:d4:de:dd:3b:3c:e1:a1:3e:d8:fb:
|
||||||
|
7f
|
||||||
|
ASN1 OID: secp384r1
|
||||||
|
NIST CURVE: P-384
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withECDSA
|
||||||
|
Signature: 30:66:02:31:00:96:ae:d1:68:45:d4:68:d1:c4:0b:ea:
|
||||||
|
9f:b8:88:ad:a2:75:87:39:ab:66:fa:a8:a2:68:d4:a1:
|
||||||
|
f3:44:23:2f:0e:4f:d6:bb:33:83:dc:90:42:28:07:77:
|
||||||
|
c7:03:ec:8e:03:02:31:00:ce:6a:35:0c:ba:5c:11:2c:
|
||||||
|
19:08:1a:e1:de:c3:df:94:30:37:f1:36:63:a1:e7:51:
|
||||||
|
35:e5:9c:57:17:67:d5:09:b0:0d:63:1e:a6:b0:ff:ce:
|
||||||
|
03:c0:7b:2f:06:3a:6c:a3
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Key encipherment
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
|
// openssl ecparam -name secp521r1 -genkey -noout -out test-ec-key.pem
|
||||||
|
// openssl req -new -key test-ec-key.pem -out test-ec.csr
|
||||||
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com"
|
||||||
|
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com"
|
||||||
|
// -addext "basicConstraints = critical,CA:FALSE"
|
||||||
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment"
|
||||||
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
|
const IN_EXAMPLE_COM_EC_P521 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIICIjCCAYQCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCBmzAQBgcqhkjOPQIBBgUr
|
||||||
|
gQQAIwOBhgAEAKf5BRB57svfglRz5dM0bnJAnieMFjNjOFca5/pJ2bOpORkp9Uol
|
||||||
|
x//mHY5WOMYYC/xvM5lJRcmUnL791zQ6rf6pAD/CrEpDF2svae6e5nA/fN2XsB98
|
||||||
|
xjmkTpYZVC5nFT83Ceo9J0kHbvliYlAMsEOO60qGghyWV7myiDgORfE+POU3oG0w
|
||||||
|
awYJKoZIhvcNAQkOMV4wXDAnBgNVHREEIDAeggtleGFtcGxlLmNvbYIPd3d3LmV4
|
||||||
|
YW1wbGUuY29tMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQM
|
||||||
|
MAoGCCsGAQUFBwMBMAoGCCqGSM49BAMCA4GLADCBhwJBDeIpSuvIT+kiE0ZnJwPS
|
||||||
|
DVik93CLqjFm5Ieq02d81GwusSgAA82WlZZVZRsTEjkZXtk96zMBnh5/uxk+wN+j
|
||||||
|
+PoCQgEDmXREwi0BPkHj6QlktE+7SLELVkrd75D9mfw/SV6ZJiLiLIT9yeoA0Zon
|
||||||
|
uhcl2rK/DLQutuJF6JIBe5s7lieKfQ==
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const OUT_EXAMPLE_COM_EC_P521 = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: ECDSA
|
||||||
|
Length: 521 bits
|
||||||
|
Pub: 04:00:a7:f9:05:10:79:ee:cb:df:82:54:73:e5:d3:34:
|
||||||
|
6e:72:40:9e:27:8c:16:33:63:38:57:1a:e7:fa:49:d9:
|
||||||
|
b3:a9:39:19:29:f5:4a:25:c7:ff:e6:1d:8e:56:38:c6:
|
||||||
|
18:0b:fc:6f:33:99:49:45:c9:94:9c:be:fd:d7:34:3a:
|
||||||
|
ad:fe:a9:00:3f:c2:ac:4a:43:17:6b:2f:69:ee:9e:e6:
|
||||||
|
70:3f:7c:dd:97:b0:1f:7c:c6:39:a4:4e:96:19:54:2e:
|
||||||
|
67:15:3f:37:09:ea:3d:27:49:07:6e:f9:62:62:50:0c:
|
||||||
|
b0:43:8e:eb:4a:86:82:1c:96:57:b9:b2:88:38:0e:45:
|
||||||
|
f1:3e:3c:e5:37
|
||||||
|
ASN1 OID: secp521r1
|
||||||
|
NIST CURVE: P-521
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withECDSA
|
||||||
|
Signature: 30:81:87:02:41:0d:e2:29:4a:eb:c8:4f:e9:22:13:46:
|
||||||
|
67:27:03:d2:0d:58:a4:f7:70:8b:aa:31:66:e4:87:aa:
|
||||||
|
d3:67:7c:d4:6c:2e:b1:28:00:03:cd:96:95:96:55:65:
|
||||||
|
1b:13:12:39:19:5e:d9:3d:eb:33:01:9e:1e:7f:bb:19:
|
||||||
|
3e:c0:df:a3:f8:fa:02:42:01:03:99:74:44:c2:2d:01:
|
||||||
|
3e:41:e3:e9:09:64:b4:4f:bb:48:b1:0b:56:4a:dd:ef:
|
||||||
|
90:fd:99:fc:3f:49:5e:99:26:22:e2:2c:84:fd:c9:ea:
|
||||||
|
00:d1:9a:27:ba:17:25:da:b2:bf:0c:b4:2e:b6:e2:45:
|
||||||
|
e8:92:01:7b:9b:3b:96:27:8a:7d
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Key encipherment
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
|
// openssl dsaparam -out dsaparam.pem 1024
|
||||||
|
// openssl gendsa -out dsakey.pem dsaparam.pem
|
||||||
|
// openssl req -new -key dsakey.pem -out test-dsa.csr \
|
||||||
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||||
|
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \
|
||||||
|
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||||
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||||
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
|
const IN_EXAMPLE_COM_DSA_1024 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIC/jCCAqoCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAcAwggE0BgcqhkjOOAQB
|
||||||
|
MIIBJwKBgQD8vvCmdM8wttdbq3kWigTEnnug4+2SLMl2RNXrlCQjmuZc7tGMyP1u
|
||||||
|
gsSc9Pxd/tMrPKRawFP5SvUOkZ4cIrujdJVTb/hlfnGH4cWACe8EupwRzoqwZB1x
|
||||||
|
awiHFzL9G6Go0HOy7bSbRdxBIYu46fnxNsDFf7lMlcBOKdq4Y12kvwIdAN4/vtK9
|
||||||
|
KxhQfcrrzHsPXW+/xW0CMfr+NQir8PkCgYEAiNdM7IRZhXPaGRtGDpepSoRAf4uQ
|
||||||
|
LWY9q+vFUx4fVRSSgwKBKLjW+BvzE2eJq0pXv7O09QHOghtcwzY3UrdN952sjUkJ
|
||||||
|
LItt+5FxB7/JqCBPRrrVsyGEjR3+WbeI3wl6OvQFxm/OTNTTkemFdAfpT/YDSw+n
|
||||||
|
1xLODTfegT/oyOoDgYUAAoGBAMz15lRPVAj8cje3ShbuACHPVE85d0Tk0Dw9qUcQ
|
||||||
|
NCNS6A3STSbUiLGKeiRMGg2v/HM9ivV8tq1rywmgBAwtidcQ6P5yqYSZs6z3x9xZ
|
||||||
|
OzeQ5jXftBQ1GXeU8zi1fC99inFGNixbPFVIz4/KiV0+So44n9ki2ylhbz0YQtpU
|
||||||
|
wMF+oG0wawYJKoZIhvcNAQkOMV4wXDAnBgNVHREEIDAeggtleGFtcGxlLmNvbYIP
|
||||||
|
d3d3LmV4YW1wbGUuY29tMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMG
|
||||||
|
A1UdJQQMMAoGCCsGAQUFBwMBMAsGCWCGSAFlAwQDAgNBADA+Ah0AkTogUUyKE5v9
|
||||||
|
ezKrOKpP07i2E9Zz0n/yjIvw4wIdAMB5yVMOEgI877vOFQ7zzf7oDR9eJMYlf4QV
|
||||||
|
2sQ=
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const OUT_EXAMPLE_COM_DSA_1024 = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: DSA
|
||||||
|
Length: 1024 bits
|
||||||
|
Pub: 00:cc:f5:e6:54:4f:54:08:fc:72:37:b7:4a:16:ee:00:
|
||||||
|
21:cf:54:4f:39:77:44:e4:d0:3c:3d:a9:47:10:34:23:
|
||||||
|
52:e8:0d:d2:4d:26:d4:88:b1:8a:7a:24:4c:1a:0d:af:
|
||||||
|
fc:73:3d:8a:f5:7c:b6:ad:6b:cb:09:a0:04:0c:2d:89:
|
||||||
|
d7:10:e8:fe:72:a9:84:99:b3:ac:f7:c7:dc:59:3b:37:
|
||||||
|
90:e6:35:df:b4:14:35:19:77:94:f3:38:b5:7c:2f:7d:
|
||||||
|
8a:71:46:36:2c:5b:3c:55:48:cf:8f:ca:89:5d:3e:4a:
|
||||||
|
8e:38:9f:d9:22:db:29:61:6f:3d:18:42:da:54:c0:c1:
|
||||||
|
7e
|
||||||
|
P: 00:fc:be:f0:a6:74:cf:30:b6:d7:5b:ab:79:16:8a:04:
|
||||||
|
c4:9e:7b:a0:e3:ed:92:2c:c9:76:44:d5:eb:94:24:23:
|
||||||
|
9a:e6:5c:ee:d1:8c:c8:fd:6e:82:c4:9c:f4:fc:5d:fe:
|
||||||
|
d3:2b:3c:a4:5a:c0:53:f9:4a:f5:0e:91:9e:1c:22:bb:
|
||||||
|
a3:74:95:53:6f:f8:65:7e:71:87:e1:c5:80:09:ef:04:
|
||||||
|
ba:9c:11:ce:8a:b0:64:1d:71:6b:08:87:17:32:fd:1b:
|
||||||
|
a1:a8:d0:73:b2:ed:b4:9b:45:dc:41:21:8b:b8:e9:f9:
|
||||||
|
f1:36:c0:c5:7f:b9:4c:95:c0:4e:29:da:b8:63:5d:a4:
|
||||||
|
bf
|
||||||
|
Q: 00:de:3f:be:d2:bd:2b:18:50:7d:ca:eb:cc:7b:0f:5d:
|
||||||
|
6f:bf:c5:6d:02:31:fa:fe:35:08:ab:f0:f9
|
||||||
|
G: 00:88:d7:4c:ec:84:59:85:73:da:19:1b:46:0e:97:a9:
|
||||||
|
4a:84:40:7f:8b:90:2d:66:3d:ab:eb:c5:53:1e:1f:55:
|
||||||
|
14:92:83:02:81:28:b8:d6:f8:1b:f3:13:67:89:ab:4a:
|
||||||
|
57:bf:b3:b4:f5:01:ce:82:1b:5c:c3:36:37:52:b7:4d:
|
||||||
|
f7:9d:ac:8d:49:09:2c:8b:6d:fb:91:71:07:bf:c9:a8:
|
||||||
|
20:4f:46:ba:d5:b3:21:84:8d:1d:fe:59:b7:88:df:09:
|
||||||
|
7a:3a:f4:05:c6:6f:ce:4c:d4:d3:91:e9:85:74:07:e9:
|
||||||
|
4f:f6:03:4b:0f:a7:d7:12:ce:0d:37:de:81:3f:e8:c8:
|
||||||
|
ea
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withDSA
|
||||||
|
Signature:
|
||||||
|
R: 00:91:3a:20:51:4c:8a:13:9b:fd:7b:32:ab:38:aa:4f:
|
||||||
|
d3:b8:b6:13:d6:73:d2:7f:f2:8c:8b:f0:e3
|
||||||
|
S: 00:c0:79:c9:53:0e:12:02:3c:ef:bb:ce:15:0e:f3:cd:
|
||||||
|
fe:e8:0d:1f:5e:24:c6:25:7f:84:15:da:c4
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Key encipherment
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
|
// openssl dsaparam -out dsaparam.pem 2048
|
||||||
|
// openssl gendsa -out dsakey.pem dsaparam.pem
|
||||||
|
// openssl req -new -key dsakey.pem -out test-dsa.csr \
|
||||||
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||||
|
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \
|
||||||
|
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||||
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||||
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
|
const IN_EXAMPLE_COM_DSA_2048 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIEfzCCBCwCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCA0IwggI1BgcqhkjOOAQB
|
||||||
|
MIICKAKCAQEAsvoKmCHcR2y8qQ/kpBHOvlaGifq//F/0zhWSpfjvwqI3g2EjqXL7
|
||||||
|
rCYyu9wxoogODo6Dnenxfw1xp3ZIJNCtfrSJyt0AudjOedtVWMSnTndoQVQtYSI0
|
||||||
|
mmrBAqFL26i1bmEMxsd6pz2nU3p8yGY/wpYiWwyy+/TZv8a2t58owpw9Qkm4cX4E
|
||||||
|
Po3ih/XbN6eooOx9ZaErcS9mg3UvwQDm0VYD3ZjSeqwP7YWGyhq7gPJsEiMrft12
|
||||||
|
1SjyNz8rkhXzqZFRujjmfTT5dpCC/Z4d7/ZE30tbqHaNDM+YwBrb/aL7PnoWs847
|
||||||
|
VpjCVxmVmgIPoMHlTbg29RsIUoFlFScaUQIdAMGwwpzilrReaEqcoX7PY5u4vtV0
|
||||||
|
5zuiVIqkdBMCggEAQZhk5qdAYoMvZhPi5TOgysTzQE1FeAEtgypxZI65TpwO/JOr
|
||||||
|
AX9vYZ/qCYX/ncj455qiPZenl59lo/iQPzhJUubuCevPWJ3dsKRbAyL/5NCwifnf
|
||||||
|
YBMJGj0UFGL4ekVV0emLL9H5eqYz64w0eV2Sp40O8yCu0qr7QTi3zpqzJZ43E+26
|
||||||
|
Z9bgR6c1lmgKW2QN72PHwMlTlq0O6mN+eikEWoGr09JWpXMThZemAO2mHLAiq6ju
|
||||||
|
0+zduzWZyjZPZA1B4XUlTgCtzHveYpUzZ1NhZyM8jcGFOmmZWAFNwt03bq9/Ma0q
|
||||||
|
3jB0Dyz7IDGm8D6Y770wJRP3jf7iCVYt8jB49gOCAQUAAoIBACnVv+1ROrUiHAwn
|
||||||
|
xXGlsZdTEYZfWbE8Cter15JNNqh/Z1cdIp9m1t/rVF69nSWQvrvLeFo5p5mGxK8r
|
||||||
|
IKHTZTaAn6uO6PcNJc6iB7fS15L4uiB7p73MdjE+3PcYMbhttDlexdm6QxsmCP1F
|
||||||
|
3LYW3Uh879AURWZwPH3z4NZL2u1AFSyS1vQhtiCmztq94QwhjoDf9anFR8q05dAC
|
||||||
|
juPlKYEIhMsoq+r/l/kOM1UghhXX6BmeF8R9hhW1p4Rv+gyAgbYjowJFtZnwE5p0
|
||||||
|
OYLJzSQWjFMYEzHAoH8J4+D5okt4IXEd0BDxLBkm1WonIxYL/NL95p3qXpgUXqRX
|
||||||
|
M9spEzWgbTBrBgkqhkiG9w0BCQ4xXjBcMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29t
|
||||||
|
gg93d3cuZXhhbXBsZS5jb20wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBaAw
|
||||||
|
EwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYJYIZIAWUDBAMCA0AAMD0CHQCyrstoqfvs
|
||||||
|
MCfsZUeycKrKQmAJAHxuoGPCKl7yAhwhNH9RNxBm5roO2U901BeF2p0pT410ghH8
|
||||||
|
oA+F
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const OUT_EXAMPLE_COM_DSA_2048 = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: DSA
|
||||||
|
Length: 2048 bits
|
||||||
|
Pub: 29:d5:bf:ed:51:3a:b5:22:1c:0c:27:c5:71:a5:b1:97:
|
||||||
|
53:11:86:5f:59:b1:3c:0a:d7:ab:d7:92:4d:36:a8:7f:
|
||||||
|
67:57:1d:22:9f:66:d6:df:eb:54:5e:bd:9d:25:90:be:
|
||||||
|
bb:cb:78:5a:39:a7:99:86:c4:af:2b:20:a1:d3:65:36:
|
||||||
|
80:9f:ab:8e:e8:f7:0d:25:ce:a2:07:b7:d2:d7:92:f8:
|
||||||
|
ba:20:7b:a7:bd:cc:76:31:3e:dc:f7:18:31:b8:6d:b4:
|
||||||
|
39:5e:c5:d9:ba:43:1b:26:08:fd:45:dc:b6:16:dd:48:
|
||||||
|
7c:ef:d0:14:45:66:70:3c:7d:f3:e0:d6:4b:da:ed:40:
|
||||||
|
15:2c:92:d6:f4:21:b6:20:a6:ce:da:bd:e1:0c:21:8e:
|
||||||
|
80:df:f5:a9:c5:47:ca:b4:e5:d0:02:8e:e3:e5:29:81:
|
||||||
|
08:84:cb:28:ab:ea:ff:97:f9:0e:33:55:20:86:15:d7:
|
||||||
|
e8:19:9e:17:c4:7d:86:15:b5:a7:84:6f:fa:0c:80:81:
|
||||||
|
b6:23:a3:02:45:b5:99:f0:13:9a:74:39:82:c9:cd:24:
|
||||||
|
16:8c:53:18:13:31:c0:a0:7f:09:e3:e0:f9:a2:4b:78:
|
||||||
|
21:71:1d:d0:10:f1:2c:19:26:d5:6a:27:23:16:0b:fc:
|
||||||
|
d2:fd:e6:9d:ea:5e:98:14:5e:a4:57:33:db:29:13:35
|
||||||
|
P: 00:b2:fa:0a:98:21:dc:47:6c:bc:a9:0f:e4:a4:11:ce:
|
||||||
|
be:56:86:89:fa:bf:fc:5f:f4:ce:15:92:a5:f8:ef:c2:
|
||||||
|
a2:37:83:61:23:a9:72:fb:ac:26:32:bb:dc:31:a2:88:
|
||||||
|
0e:0e:8e:83:9d:e9:f1:7f:0d:71:a7:76:48:24:d0:ad:
|
||||||
|
7e:b4:89:ca:dd:00:b9:d8:ce:79:db:55:58:c4:a7:4e:
|
||||||
|
77:68:41:54:2d:61:22:34:9a:6a:c1:02:a1:4b:db:a8:
|
||||||
|
b5:6e:61:0c:c6:c7:7a:a7:3d:a7:53:7a:7c:c8:66:3f:
|
||||||
|
c2:96:22:5b:0c:b2:fb:f4:d9:bf:c6:b6:b7:9f:28:c2:
|
||||||
|
9c:3d:42:49:b8:71:7e:04:3e:8d:e2:87:f5:db:37:a7:
|
||||||
|
a8:a0:ec:7d:65:a1:2b:71:2f:66:83:75:2f:c1:00:e6:
|
||||||
|
d1:56:03:dd:98:d2:7a:ac:0f:ed:85:86:ca:1a:bb:80:
|
||||||
|
f2:6c:12:23:2b:7e:dd:76:d5:28:f2:37:3f:2b:92:15:
|
||||||
|
f3:a9:91:51:ba:38:e6:7d:34:f9:76:90:82:fd:9e:1d:
|
||||||
|
ef:f6:44:df:4b:5b:a8:76:8d:0c:cf:98:c0:1a:db:fd:
|
||||||
|
a2:fb:3e:7a:16:b3:ce:3b:56:98:c2:57:19:95:9a:02:
|
||||||
|
0f:a0:c1:e5:4d:b8:36:f5:1b:08:52:81:65:15:27:1a:
|
||||||
|
51
|
||||||
|
Q: 00:c1:b0:c2:9c:e2:96:b4:5e:68:4a:9c:a1:7e:cf:63:
|
||||||
|
9b:b8:be:d5:74:e7:3b:a2:54:8a:a4:74:13
|
||||||
|
G: 41:98:64:e6:a7:40:62:83:2f:66:13:e2:e5:33:a0:ca:
|
||||||
|
c4:f3:40:4d:45:78:01:2d:83:2a:71:64:8e:b9:4e:9c:
|
||||||
|
0e:fc:93:ab:01:7f:6f:61:9f:ea:09:85:ff:9d:c8:f8:
|
||||||
|
e7:9a:a2:3d:97:a7:97:9f:65:a3:f8:90:3f:38:49:52:
|
||||||
|
e6:ee:09:eb:cf:58:9d:dd:b0:a4:5b:03:22:ff:e4:d0:
|
||||||
|
b0:89:f9:df:60:13:09:1a:3d:14:14:62:f8:7a:45:55:
|
||||||
|
d1:e9:8b:2f:d1:f9:7a:a6:33:eb:8c:34:79:5d:92:a7:
|
||||||
|
8d:0e:f3:20:ae:d2:aa:fb:41:38:b7:ce:9a:b3:25:9e:
|
||||||
|
37:13:ed:ba:67:d6:e0:47:a7:35:96:68:0a:5b:64:0d:
|
||||||
|
ef:63:c7:c0:c9:53:96:ad:0e:ea:63:7e:7a:29:04:5a:
|
||||||
|
81:ab:d3:d2:56:a5:73:13:85:97:a6:00:ed:a6:1c:b0:
|
||||||
|
22:ab:a8:ee:d3:ec:dd:bb:35:99:ca:36:4f:64:0d:41:
|
||||||
|
e1:75:25:4e:00:ad:cc:7b:de:62:95:33:67:53:61:67:
|
||||||
|
23:3c:8d:c1:85:3a:69:99:58:01:4d:c2:dd:37:6e:af:
|
||||||
|
7f:31:ad:2a:de:30:74:0f:2c:fb:20:31:a6:f0:3e:98:
|
||||||
|
ef:bd:30:25:13:f7:8d:fe:e2:09:56:2d:f2:30:78:f6
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withDSA
|
||||||
|
Signature:
|
||||||
|
R: 00:b2:ae:cb:68:a9:fb:ec:30:27:ec:65:47:b2:70:aa:
|
||||||
|
ca:42:60:09:00:7c:6e:a0:63:c2:2a:5e:f2
|
||||||
|
S: 21:34:7f:51:37:10:66:e6:ba:0e:d9:4f:74:d4:17:85:
|
||||||
|
da:9d:29:4f:8d:74:82:11:fc:a0:0f:85
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Key encipherment
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
|
// openssl req -newkey rsa:4096 -keyout test-rsa-4096.key -out test-rsa-4096.csr
|
||||||
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com"
|
||||||
|
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com,IP:127.0.0.1, \
|
||||||
|
// email:user@example.com,URI:http://example.com/api,otherName:1.2.3.4;UTF8:some value"
|
||||||
|
// -addext "basicConstraints = critical,CA:FALSE"
|
||||||
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment"
|
||||||
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
|
const IN_EXAMPLE_COM_SAN = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIFbTCCA1UCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggIPADCCAgoCggIBAJf8uQDFcQfj6qCuPa4hNyDWr3Lwzfc3qQZdOgNJ/kym
|
||||||
|
GxxRHUXJyBtgkmAqDoSGmg1hUWgt9eZwd/Cf4Wd3qr+Q0ppg6dwZeWgYSunseoKl
|
||||||
|
f0E5FvUfECNyDwCSbltN9TCsom2ePNOOJJHWo4Y3E3jGXz0n1Vwa6ePR0j62Rcey
|
||||||
|
4lHLscQ3GoNvMLcXbY1HIhnbaI25MmFPB8p4PvpPsAYgbWHbw0jIR9dSxEK0HAU3
|
||||||
|
2VkRkm8XaF4BOEfugqT3Bc7zAvwdFZRTTTZIICYW5T3zvtxBidJ8OSej16LV6ZeE
|
||||||
|
/4VcTzXYTzIUXbNaev3XN1r5ZodkbZvxxk/EZmfes2OtedPulW4TW27HSl6XBos/
|
||||||
|
8VQohelUXiyCLPrtbnjeHKSz47+ZAm23jMAFYWkTVdWvAa+G74UstuRRXfLAKCNv
|
||||||
|
7VeA3l8IgEkfj48u+EenV6cJ3ZJJ5/qvZo7OUjhAtYJmNtlRYE4r3uWRmaNXYwrD
|
||||||
|
7vJuMiZafaVC+74/UHLGGm7sHVJdo4KBO/LUbHJ/SKZIYMc14kJLOf6TPZXSGm9N
|
||||||
|
TxbOV9Vzcjzivq1HxaYirLAM+nyVApVwwpVq/uiEFz579yrwySvBuwnewfdfZ6EZ
|
||||||
|
iNAKiBwQ8diFMnFfd/28hJ8TrIlq+5bkVo1ODuhyRIw9YB19IrmytaVvkR8624Ld
|
||||||
|
AgMBAAGggbUwgbIGCSqGSIb3DQEJDjGBpDCBoTBsBgNVHREEZTBjggtleGFtcGxl
|
||||||
|
LmNvbYIPd3d3LmV4YW1wbGUuY29thwR/AAABgRB1c2VyQGV4YW1wbGUuY29thhZo
|
||||||
|
dHRwOi8vZXhhbXBsZS5jb20vYXBpoBMGAyoDBKAMDApzb21lIHZhbHVlMAwGA1Ud
|
||||||
|
EwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0G
|
||||||
|
CSqGSIb3DQEBCwUAA4ICAQAtOuh6MEralwgChJHBaGJavBxpCQ0p5K77RlAPIk5Q
|
||||||
|
Mv5086DxiZEFBKCRiZRtkOvo0aCHUn3awDrlEOgECiAYQqMIBUWeNwImtmpDopuI
|
||||||
|
ZMmVmzc2ojf9nUlPrPV+B6P2jTxTIQYpDQocbOgxDkcdZVSvLyMEFnHIMNQV7GS2
|
||||||
|
gBmUnPp+4z2d8X9XaRspkuEt2nbA1NoXekWaG46jG56VoBycepOiNkwL4AsqunLa
|
||||||
|
T0urcHq34g+HRQWwOA+q/72qP4oaj2ZO0fFJQl2ZsGRT/IuM1g2YsnVSpBOGY/J6
|
||||||
|
Qi2hDr6EEqphg501ny+FZE1BouQ/lSykafYyauwNq1puu/VyuF8grFmL0SoxWWfP
|
||||||
|
h6viblGM/Vu69Bhl4gkWKtufWpOVpCA4vHzes8IVMFg7vhpwm33Xjo0lCPcIUin6
|
||||||
|
0CqHZQCsWtj2yIAF66WHB0I1DHL5FNCWRPnQCo54qRZIYqtSP20QRr6GWC2d+ZgX
|
||||||
|
wDxRpmzr8T8owBYWw3j+RK9CtZoWO4O586UR4J1Bn5PQfoR78Z/4mzv2sxVi9Fdf
|
||||||
|
sJzlG6/nhmMaCqneIn97gkguvSgpOuKSeo/fjbpnthufgilrpDQoGrhZaXic0GVZ
|
||||||
|
6JmbOh3tLMVf4ooyyaLfOCfV2FN12rDa3pdWhQ4MVN4gg9U3Cq0x7yRQKiSBlBnw
|
||||||
|
oA==
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const OUT_EXAMPLE_COM_SAN = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: RSA
|
||||||
|
Length: 4096 bits
|
||||||
|
Modulus: 00:97:fc:b9:00:c5:71:07:e3:ea:a0:ae:3d:ae:21:37:
|
||||||
|
20:d6:af:72:f0:cd:f7:37:a9:06:5d:3a:03:49:fe:4c:
|
||||||
|
a6:1b:1c:51:1d:45:c9:c8:1b:60:92:60:2a:0e:84:86:
|
||||||
|
9a:0d:61:51:68:2d:f5:e6:70:77:f0:9f:e1:67:77:aa:
|
||||||
|
bf:90:d2:9a:60:e9:dc:19:79:68:18:4a:e9:ec:7a:82:
|
||||||
|
a5:7f:41:39:16:f5:1f:10:23:72:0f:00:92:6e:5b:4d:
|
||||||
|
f5:30:ac:a2:6d:9e:3c:d3:8e:24:91:d6:a3:86:37:13:
|
||||||
|
78:c6:5f:3d:27:d5:5c:1a:e9:e3:d1:d2:3e:b6:45:c7:
|
||||||
|
b2:e2:51:cb:b1:c4:37:1a:83:6f:30:b7:17:6d:8d:47:
|
||||||
|
22:19:db:68:8d:b9:32:61:4f:07:ca:78:3e:fa:4f:b0:
|
||||||
|
06:20:6d:61:db:c3:48:c8:47:d7:52:c4:42:b4:1c:05:
|
||||||
|
37:d9:59:11:92:6f:17:68:5e:01:38:47:ee:82:a4:f7:
|
||||||
|
05:ce:f3:02:fc:1d:15:94:53:4d:36:48:20:26:16:e5:
|
||||||
|
3d:f3:be:dc:41:89:d2:7c:39:27:a3:d7:a2:d5:e9:97:
|
||||||
|
84:ff:85:5c:4f:35:d8:4f:32:14:5d:b3:5a:7a:fd:d7:
|
||||||
|
37:5a:f9:66:87:64:6d:9b:f1:c6:4f:c4:66:67:de:b3:
|
||||||
|
63:ad:79:d3:ee:95:6e:13:5b:6e:c7:4a:5e:97:06:8b:
|
||||||
|
3f:f1:54:28:85:e9:54:5e:2c:82:2c:fa:ed:6e:78:de:
|
||||||
|
1c:a4:b3:e3:bf:99:02:6d:b7:8c:c0:05:61:69:13:55:
|
||||||
|
d5:af:01:af:86:ef:85:2c:b6:e4:51:5d:f2:c0:28:23:
|
||||||
|
6f:ed:57:80:de:5f:08:80:49:1f:8f:8f:2e:f8:47:a7:
|
||||||
|
57:a7:09:dd:92:49:e7:fa:af:66:8e:ce:52:38:40:b5:
|
||||||
|
82:66:36:d9:51:60:4e:2b:de:e5:91:99:a3:57:63:0a:
|
||||||
|
c3:ee:f2:6e:32:26:5a:7d:a5:42:fb:be:3f:50:72:c6:
|
||||||
|
1a:6e:ec:1d:52:5d:a3:82:81:3b:f2:d4:6c:72:7f:48:
|
||||||
|
a6:48:60:c7:35:e2:42:4b:39:fe:93:3d:95:d2:1a:6f:
|
||||||
|
4d:4f:16:ce:57:d5:73:72:3c:e2:be:ad:47:c5:a6:22:
|
||||||
|
ac:b0:0c:fa:7c:95:02:95:70:c2:95:6a:fe:e8:84:17:
|
||||||
|
3e:7b:f7:2a:f0:c9:2b:c1:bb:09:de:c1:f7:5f:67:a1:
|
||||||
|
19:88:d0:0a:88:1c:10:f1:d8:85:32:71:5f:77:fd:bc:
|
||||||
|
84:9f:13:ac:89:6a:fb:96:e4:56:8d:4e:0e:e8:72:44:
|
||||||
|
8c:3d:60:1d:7d:22:b9:b2:b5:a5:6f:91:1f:3a:db:82:
|
||||||
|
dd
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withRSA
|
||||||
|
Signature: 2d:3a:e8:7a:30:4a:da:97:08:02:84:91:c1:68:62:5a:
|
||||||
|
bc:1c:69:09:0d:29:e4:ae:fb:46:50:0f:22:4e:50:32:
|
||||||
|
fe:74:f3:a0:f1:89:91:05:04:a0:91:89:94:6d:90:eb:
|
||||||
|
e8:d1:a0:87:52:7d:da:c0:3a:e5:10:e8:04:0a:20:18:
|
||||||
|
42:a3:08:05:45:9e:37:02:26:b6:6a:43:a2:9b:88:64:
|
||||||
|
c9:95:9b:37:36:a2:37:fd:9d:49:4f:ac:f5:7e:07:a3:
|
||||||
|
f6:8d:3c:53:21:06:29:0d:0a:1c:6c:e8:31:0e:47:1d:
|
||||||
|
65:54:af:2f:23:04:16:71:c8:30:d4:15:ec:64:b6:80:
|
||||||
|
19:94:9c:fa:7e:e3:3d:9d:f1:7f:57:69:1b:29:92:e1:
|
||||||
|
2d:da:76:c0:d4:da:17:7a:45:9a:1b:8e:a3:1b:9e:95:
|
||||||
|
a0:1c:9c:7a:93:a2:36:4c:0b:e0:0b:2a:ba:72:da:4f:
|
||||||
|
4b:ab:70:7a:b7:e2:0f:87:45:05:b0:38:0f:aa:ff:bd:
|
||||||
|
aa:3f:8a:1a:8f:66:4e:d1:f1:49:42:5d:99:b0:64:53:
|
||||||
|
fc:8b:8c:d6:0d:98:b2:75:52:a4:13:86:63:f2:7a:42:
|
||||||
|
2d:a1:0e:be:84:12:aa:61:83:9d:35:9f:2f:85:64:4d:
|
||||||
|
41:a2:e4:3f:95:2c:a4:69:f6:32:6a:ec:0d:ab:5a:6e:
|
||||||
|
bb:f5:72:b8:5f:20:ac:59:8b:d1:2a:31:59:67:cf:87:
|
||||||
|
ab:e2:6e:51:8c:fd:5b:ba:f4:18:65:e2:09:16:2a:db:
|
||||||
|
9f:5a:93:95:a4:20:38:bc:7c:de:b3:c2:15:30:58:3b:
|
||||||
|
be:1a:70:9b:7d:d7:8e:8d:25:08:f7:08:52:29:fa:d0:
|
||||||
|
2a:87:65:00:ac:5a:d8:f6:c8:80:05:eb:a5:87:07:42:
|
||||||
|
35:0c:72:f9:14:d0:96:44:f9:d0:0a:8e:78:a9:16:48:
|
||||||
|
62:ab:52:3f:6d:10:46:be:86:58:2d:9d:f9:98:17:c0:
|
||||||
|
3c:51:a6:6c:eb:f1:3f:28:c0:16:16:c3:78:fe:44:af:
|
||||||
|
42:b5:9a:16:3b:83:b9:f3:a5:11:e0:9d:41:9f:93:d0:
|
||||||
|
7e:84:7b:f1:9f:f8:9b:3b:f6:b3:15:62:f4:57:5f:b0:
|
||||||
|
9c:e5:1b:af:e7:86:63:1a:0a:a9:de:22:7f:7b:82:48:
|
||||||
|
2e:bd:28:29:3a:e2:92:7a:8f:df:8d:ba:67:b6:1b:9f:
|
||||||
|
82:29:6b:a4:34:28:1a:b8:59:69:78:9c:d0:65:59:e8:
|
||||||
|
99:9b:3a:1d:ed:2c:c5:5f:e2:8a:32:c9:a2:df:38:27:
|
||||||
|
d5:d8:53:75:da:b0:da:de:97:56:85:0e:0c:54:de:20:
|
||||||
|
83:d5:37:0a:ad:31:ef:24:50:2a:24:81:94:19:f0:a0
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Key encipherment
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com
|
||||||
|
IP: 127.0.0.1
|
||||||
|
EMAIL: user@example.com
|
||||||
|
URI: http://example.com/api
|
||||||
|
Other: 1.2.3.4::some value`;
|
||||||
|
|
||||||
|
// openssl req -newkey rsa:2048 -keyout test-rsa-2048.key -out test-rsa-2048.csr \
|
||||||
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||||
|
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \
|
||||||
|
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||||
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment," \
|
||||||
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
|
const IN_EXAMPLE_COM_KEY_USAGE = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIDJDCCAgwCAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBAKHQWxqtdJQ1l7ApTgwgsyrN/kRDrog/DsUlZQg3YodY
|
||||||
|
4RRAgPr+AeQ1BhuWDVxaXein0XmXOESHgK9Z7X/hLgRy2ifK+n20Ij3+k6VSh6Lt
|
||||||
|
lpjUPwK7PWBtZ969DukBIvq64XrJTNWIJPvXXQxkL4dk5NcDY4TjXWt0GgDVR+GH
|
||||||
|
OU1JwfzviGVRdOmY8+Ckfxc+3QytTdP6KBQaiUk5sBEniovDpKfImtql72JsCRbA
|
||||||
|
9Wue7X4EbXi2zvoAlJ5NXF3Ps1q2XsVJeIx/mMDcgRW7s5AVM9NQW0O1JLoA7dY+
|
||||||
|
vSrKZj+ssuKCIWM7u9Big2I0miEl5AXrDlwZPBhM9FMCAwEAAaBtMGsGCSqGSIb3
|
||||||
|
DQEJDjFeMFwwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNv
|
||||||
|
bTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIB/jATBgNVHSUEDDAKBggrBgEF
|
||||||
|
BQcDATANBgkqhkiG9w0BAQsFAAOCAQEAPOr6jfq/mXilqXA11CTza69Ydd4fvp6q
|
||||||
|
UG47PefzQqSmYtpUytwZRLGQ1IFRlYeXwbazVLkRmLNwpbB8C5fh9FPp55JCpM/O
|
||||||
|
tgCW2uqLkCtkQMUCaSdRX/Y+9ypYhdBkSNv1Q+3QXi2jmi5QMqwerAwNmeXmH6AZ
|
||||||
|
swMgAhuoLS9OrIqHjFoHGoXsgXMkbLr6m6hgyFt8ZbbwK4WpVcgCZfhtBiLilCJN
|
||||||
|
Xr9GUXL3FqUb7sIaYKAaghr2haqKhFsIH57XVK3DZYhOkLd9uC8TLdl2e+t9Hcy9
|
||||||
|
ymLwiIGMUfuBQMP8nVu3jGXAQ5N4VV+IZfF8UaBFW8tG+Ms2TeW68Q==
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const OUT_EXAMPLE_COM_KEY_USAGE = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: RSA
|
||||||
|
Length: 2048 bits
|
||||||
|
Modulus: 00:a1:d0:5b:1a:ad:74:94:35:97:b0:29:4e:0c:20:b3:
|
||||||
|
2a:cd:fe:44:43:ae:88:3f:0e:c5:25:65:08:37:62:87:
|
||||||
|
58:e1:14:40:80:fa:fe:01:e4:35:06:1b:96:0d:5c:5a:
|
||||||
|
5d:e8:a7:d1:79:97:38:44:87:80:af:59:ed:7f:e1:2e:
|
||||||
|
04:72:da:27:ca:fa:7d:b4:22:3d:fe:93:a5:52:87:a2:
|
||||||
|
ed:96:98:d4:3f:02:bb:3d:60:6d:67:de:bd:0e:e9:01:
|
||||||
|
22:fa:ba:e1:7a:c9:4c:d5:88:24:fb:d7:5d:0c:64:2f:
|
||||||
|
87:64:e4:d7:03:63:84:e3:5d:6b:74:1a:00:d5:47:e1:
|
||||||
|
87:39:4d:49:c1:fc:ef:88:65:51:74:e9:98:f3:e0:a4:
|
||||||
|
7f:17:3e:dd:0c:ad:4d:d3:fa:28:14:1a:89:49:39:b0:
|
||||||
|
11:27:8a:8b:c3:a4:a7:c8:9a:da:a5:ef:62:6c:09:16:
|
||||||
|
c0:f5:6b:9e:ed:7e:04:6d:78:b6:ce:fa:00:94:9e:4d:
|
||||||
|
5c:5d:cf:b3:5a:b6:5e:c5:49:78:8c:7f:98:c0:dc:81:
|
||||||
|
15:bb:b3:90:15:33:d3:50:5b:43:b5:24:ba:00:ed:d6:
|
||||||
|
3e:bd:2a:ca:66:3f:ac:b2:e2:82:21:63:3b:bb:d0:62:
|
||||||
|
83:62:34:9a:21:25:e4:05:eb:0e:5c:19:3c:18:4c:f4:
|
||||||
|
53
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withRSA
|
||||||
|
Signature: 3c:ea:fa:8d:fa:bf:99:78:a5:a9:70:35:d4:24:f3:6b:
|
||||||
|
af:58:75:de:1f:be:9e:aa:50:6e:3b:3d:e7:f3:42:a4:
|
||||||
|
a6:62:da:54:ca:dc:19:44:b1:90:d4:81:51:95:87:97:
|
||||||
|
c1:b6:b3:54:b9:11:98:b3:70:a5:b0:7c:0b:97:e1:f4:
|
||||||
|
53:e9:e7:92:42:a4:cf:ce:b6:00:96:da:ea:8b:90:2b:
|
||||||
|
64:40:c5:02:69:27:51:5f:f6:3e:f7:2a:58:85:d0:64:
|
||||||
|
48:db:f5:43:ed:d0:5e:2d:a3:9a:2e:50:32:ac:1e:ac:
|
||||||
|
0c:0d:99:e5:e6:1f:a0:19:b3:03:20:02:1b:a8:2d:2f:
|
||||||
|
4e:ac:8a:87:8c:5a:07:1a:85:ec:81:73:24:6c:ba:fa:
|
||||||
|
9b:a8:60:c8:5b:7c:65:b6:f0:2b:85:a9:55:c8:02:65:
|
||||||
|
f8:6d:06:22:e2:94:22:4d:5e:bf:46:51:72:f7:16:a5:
|
||||||
|
1b:ee:c2:1a:60:a0:1a:82:1a:f6:85:aa:8a:84:5b:08:
|
||||||
|
1f:9e:d7:54:ad:c3:65:88:4e:90:b7:7d:b8:2f:13:2d:
|
||||||
|
d9:76:7b:eb:7d:1d:cc:bd:ca:62:f0:88:81:8c:51:fb:
|
||||||
|
81:40:c3:fc:9d:5b:b7:8c:65:c0:43:93:78:55:5f:88:
|
||||||
|
65:f1:7c:51:a0:45:5b:cb:46:f8:cb:36:4d:e5:ba:f1
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Non-repudiation
|
||||||
|
Key encipherment
|
||||||
|
Data encipherment
|
||||||
|
Key agreement
|
||||||
|
Key certificate signing
|
||||||
|
CRL signing
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
|
// openssl req -newkey rsa:2048 -keyout test-rsa-2048.key -out test-rsa-2048.csr \
|
||||||
|
// -subj "/C=CH/ST=Zurich/L=Zurich/O=Example RE/OU=IT Department/CN=example.com" \
|
||||||
|
// -addext "subjectAltName = DNS:example.com,DNS:www.example.com" \
|
||||||
|
// -addext "basicConstraints = critical,CA:FALSE" \
|
||||||
|
// -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||||
|
// -addext "extendedKeyUsage = serverAuth"
|
||||||
|
const IN_EXAMPLE_COM_EXTENDED_KEY_USAGE = `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIDpzCCAo8CAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||||
|
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||||
|
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB
|
||||||
|
BQADggEPADCCAQoCggEBAMjQ/Bz+CzA/WaS+Nyp3ijWzYlKY7GmA/a2FuzNSPQlr
|
||||||
|
WuGyZJcfb0CpLIpRF8qcDllAe+hFQnVGnk3svQIhfEOD7qwzBRMHVhe59jkv2kER
|
||||||
|
s+u88KBCNfIAS6m5d45y4xH338aXq4lZexiEASWHS7SsWAR3kL3c9p14U9EHOaym
|
||||||
|
ZWPO/SCfCJyhxszDLM2eG5S2rviuu9nY+rk0Oo7z8x8PZF9Wl1NamLl1tWPqsznS
|
||||||
|
3bfjdJYeUlm7XvTzC6EMAT6K/5ker0chl7Hg0mcEO9w4c2cSTAHvZ2b2sRYbxNQZ
|
||||||
|
49byQsRAXW8TNnOaK9Phmvwy/irEXU9PEl3u7KvSnNcCAwEAAaCB7zCB7AYJKoZI
|
||||||
|
hvcNAQkOMYHeMIHbMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29tgg93d3cuZXhhbXBs
|
||||||
|
ZS5jb20wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBaAwgZEGA1UdJQSBiTCB
|
||||||
|
hgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUF
|
||||||
|
BwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEEAYI3CgMBBgorBgEEAYI3
|
||||||
|
CgMDBgorBgEEAYI3CgMEBgorBgEEAYI3FAICBgorBgEEAYI3CgMDMA0GCSqGSIb3
|
||||||
|
DQEBCwUAA4IBAQCcYWj1eIxj/FUEhhm2lZr06Pq4GEtIVsMWw5IrUn2FIFb/yY8x
|
||||||
|
GHuB5v7XNA/8zhRWvIAXGaa8Bnajk4mR0rkxy1MXpd2YevdrF/XFa2Totv4E4/I6
|
||||||
|
pvrFefYTSGpmCu5zQTuoanM7JjE81vvbTLFdaHMdLOekpuK5v5kbuNdtDpEiAkd0
|
||||||
|
vmV4BQ0BV3b3zhIRQqBB60pSBHYvMhHNn/80RhVUQxaPTS7/AMHRZGRc1lD9/bjA
|
||||||
|
pMBis9CL4AbXtTcztU5qy4VpB1/Ej3AbAjuJIbpbPH6XtxIEtqdM4Seqi44w9oX4
|
||||||
|
rxQagXmvJPp+E4253EkeHwhfHh4SnJEtsibQ
|
||||||
|
-----END CERTIFICATE REQUEST-----`;
|
||||||
|
|
||||||
|
const OUT_EXAMPLE_COM_EXTENDED_KEY_USAGE = `Subject
|
||||||
|
C = CH
|
||||||
|
ST = Zurich
|
||||||
|
L = Zurich
|
||||||
|
O = Example RE
|
||||||
|
OU = IT Department
|
||||||
|
CN = example.com
|
||||||
|
Public Key
|
||||||
|
Algorithm: RSA
|
||||||
|
Length: 2048 bits
|
||||||
|
Modulus: 00:c8:d0:fc:1c:fe:0b:30:3f:59:a4:be:37:2a:77:8a:
|
||||||
|
35:b3:62:52:98:ec:69:80:fd:ad:85:bb:33:52:3d:09:
|
||||||
|
6b:5a:e1:b2:64:97:1f:6f:40:a9:2c:8a:51:17:ca:9c:
|
||||||
|
0e:59:40:7b:e8:45:42:75:46:9e:4d:ec:bd:02:21:7c:
|
||||||
|
43:83:ee:ac:33:05:13:07:56:17:b9:f6:39:2f:da:41:
|
||||||
|
11:b3:eb:bc:f0:a0:42:35:f2:00:4b:a9:b9:77:8e:72:
|
||||||
|
e3:11:f7:df:c6:97:ab:89:59:7b:18:84:01:25:87:4b:
|
||||||
|
b4:ac:58:04:77:90:bd:dc:f6:9d:78:53:d1:07:39:ac:
|
||||||
|
a6:65:63:ce:fd:20:9f:08:9c:a1:c6:cc:c3:2c:cd:9e:
|
||||||
|
1b:94:b6:ae:f8:ae:bb:d9:d8:fa:b9:34:3a:8e:f3:f3:
|
||||||
|
1f:0f:64:5f:56:97:53:5a:98:b9:75:b5:63:ea:b3:39:
|
||||||
|
d2:dd:b7:e3:74:96:1e:52:59:bb:5e:f4:f3:0b:a1:0c:
|
||||||
|
01:3e:8a:ff:99:1e:af:47:21:97:b1:e0:d2:67:04:3b:
|
||||||
|
dc:38:73:67:12:4c:01:ef:67:66:f6:b1:16:1b:c4:d4:
|
||||||
|
19:e3:d6:f2:42:c4:40:5d:6f:13:36:73:9a:2b:d3:e1:
|
||||||
|
9a:fc:32:fe:2a:c4:5d:4f:4f:12:5d:ee:ec:ab:d2:9c:
|
||||||
|
d7
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
Signature
|
||||||
|
Algorithm: SHA256withRSA
|
||||||
|
Signature: 9c:61:68:f5:78:8c:63:fc:55:04:86:19:b6:95:9a:f4:
|
||||||
|
e8:fa:b8:18:4b:48:56:c3:16:c3:92:2b:52:7d:85:20:
|
||||||
|
56:ff:c9:8f:31:18:7b:81:e6:fe:d7:34:0f:fc:ce:14:
|
||||||
|
56:bc:80:17:19:a6:bc:06:76:a3:93:89:91:d2:b9:31:
|
||||||
|
cb:53:17:a5:dd:98:7a:f7:6b:17:f5:c5:6b:64:e8:b6:
|
||||||
|
fe:04:e3:f2:3a:a6:fa:c5:79:f6:13:48:6a:66:0a:ee:
|
||||||
|
73:41:3b:a8:6a:73:3b:26:31:3c:d6:fb:db:4c:b1:5d:
|
||||||
|
68:73:1d:2c:e7:a4:a6:e2:b9:bf:99:1b:b8:d7:6d:0e:
|
||||||
|
91:22:02:47:74:be:65:78:05:0d:01:57:76:f7:ce:12:
|
||||||
|
11:42:a0:41:eb:4a:52:04:76:2f:32:11:cd:9f:ff:34:
|
||||||
|
46:15:54:43:16:8f:4d:2e:ff:00:c1:d1:64:64:5c:d6:
|
||||||
|
50:fd:fd:b8:c0:a4:c0:62:b3:d0:8b:e0:06:d7:b5:37:
|
||||||
|
33:b5:4e:6a:cb:85:69:07:5f:c4:8f:70:1b:02:3b:89:
|
||||||
|
21:ba:5b:3c:7e:97:b7:12:04:b6:a7:4c:e1:27:aa:8b:
|
||||||
|
8e:30:f6:85:f8:af:14:1a:81:79:af:24:fa:7e:13:8d:
|
||||||
|
b9:dc:49:1e:1f:08:5f:1e:1e:12:9c:91:2d:b2:26:d0
|
||||||
|
Requested Extensions
|
||||||
|
Basic Constraints: critical
|
||||||
|
CA = false
|
||||||
|
Key Usage: critical
|
||||||
|
Digital Signature
|
||||||
|
Key encipherment
|
||||||
|
Extended Key Usage:
|
||||||
|
TLS Web Server Authentication
|
||||||
|
TLS Web Client Authentication
|
||||||
|
Code signing
|
||||||
|
E-mail Protection (S/MIME)
|
||||||
|
Trusted Timestamping
|
||||||
|
Microsoft Individual Code Signing
|
||||||
|
Microsoft Commercial Code Signing
|
||||||
|
Microsoft Trust List Signing
|
||||||
|
Microsoft Server Gated Crypto
|
||||||
|
Microsoft Encrypted File System
|
||||||
|
Microsoft Smartcard Login
|
||||||
|
Microsoft Server Gated Crypto
|
||||||
|
Subject Alternative Name:
|
||||||
|
DNS: example.com
|
||||||
|
DNS: www.example.com`;
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
|
@ -184,7 +867,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Parse CSR",
|
"op": "Parse CSR",
|
||||||
"args": ["PEM", true]
|
"args": ["PEM"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -195,21 +878,107 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Parse CSR",
|
"op": "Parse CSR",
|
||||||
"args": ["PEM", true]
|
"args": ["PEM"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// RSA algorithm is the only one supported for CSR in node-forge as of 1.3.1
|
|
||||||
{
|
{
|
||||||
name: "Parse CSR: Example Certificate Signing Request (CSR) with EC 256",
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with EC 256",
|
||||||
input: IN_EXAMPLE_COM_EC,
|
input: IN_EXAMPLE_COM_EC_P256,
|
||||||
expectedError: true,
|
expectedOutput: OUT_EXAMPLE_COM_EC_P256,
|
||||||
expectedOutput: OUT_EXAMPLE_COM_EC,
|
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Parse CSR",
|
"op": "Parse CSR",
|
||||||
"args": ["PEM", true]
|
"args": ["PEM"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with EC 384",
|
||||||
|
input: IN_EXAMPLE_COM_EC_P384,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_EC_P384,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with EC 521",
|
||||||
|
input: IN_EXAMPLE_COM_EC_P521,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_EC_P521,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with DSA 1024",
|
||||||
|
input: IN_EXAMPLE_COM_DSA_1024,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_DSA_1024,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with DSA 2048",
|
||||||
|
input: IN_EXAMPLE_COM_DSA_2048,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_DSA_2048,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with DSA 2048",
|
||||||
|
input: IN_EXAMPLE_COM_DSA_2048,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_DSA_2048,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with various SAN types",
|
||||||
|
input: IN_EXAMPLE_COM_SAN,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_SAN,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with various Key Usages",
|
||||||
|
input: IN_EXAMPLE_COM_KEY_USAGE,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_KEY_USAGE,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parse CSR: Example Certificate Signing Request (CSR) with various Extended Key Usages",
|
||||||
|
input: IN_EXAMPLE_COM_EXTENDED_KEY_USAGE,
|
||||||
|
expectedOutput: OUT_EXAMPLE_COM_EXTENDED_KEY_USAGE,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "Parse CSR",
|
||||||
|
"args": ["PEM"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
215
tests/operations/tests/PubKeyFromCert.mjs
Normal file
215
tests/operations/tests/PubKeyFromCert.mjs
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
/**
|
||||||
|
* Public Key from Certificate
|
||||||
|
*
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2023
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
const RSA_CERT = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBfTCCASegAwIBAgIUeisK5Nwss2DGg5PCs4uSxxXyyNkwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwEzERMA8GA1UEAwwIUlNBIHRlc3QwHhcNMjExMTE5MTcyMDI2WhcNMzExMTE3
|
||||||
|
MTcyMDI2WjATMREwDwYDVQQDDAhSU0EgdGVzdDBcMA0GCSqGSIb3DQEBAQUAA0sA
|
||||||
|
MEgCQQDyq9A6emHSLczn5Omu5muy+AReC53pTGCrW6Bi65OoobahT2RUSzXCYuvB
|
||||||
|
757fLLTKz+dLeo6sFkNhIzHZI+n7AgMBAAGjUzBRMB0GA1UdDgQWBBRO+jvkqq5p
|
||||||
|
pnQgwMMnRoun6e7eiTAfBgNVHSMEGDAWgBRO+jvkqq5ppnQgwMMnRoun6e7eiTAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAR/5HAZM5qBhU/ezDUIFx
|
||||||
|
gmUGoFbIb5kJD41YCnaSdrgWglh4He4melSs42G/oxBBjuCJ0bUpqWnLl+lJkv1z
|
||||||
|
IA==
|
||||||
|
-----END CERTIFICATE-----`;
|
||||||
|
|
||||||
|
const RSA_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKr0Dp6YdItzOfk6a7ma7L4BF4LnelM
|
||||||
|
YKtboGLrk6ihtqFPZFRLNcJi68Hvnt8stMrP50t6jqwWQ2EjMdkj6fsCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
const EC_P256_CERT = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBfzCCASWgAwIBAgIUK4H8J3Hr7NpRLPrACj8Pje4JJJ0wCgYIKoZIzj0EAwIw
|
||||||
|
FTETMBEGA1UEAwwKUC0yNTYgdGVzdDAeFw0yMTExMTkxNzE5NDVaFw0zMTExMTcx
|
||||||
|
NzE5NDVaMBUxEzARBgNVBAMMClAtMjU2IHRlc3QwWTATBgcqhkjOPQIBBggqhkjO
|
||||||
|
PQMBBwNCAAQNRzwDQQM0qgJgg9YwfPXJTOoTmYmC6yBwATwfrzXR+QnxmZM2IIJr
|
||||||
|
qwuBHa8PVU2HZ2KKtaAo8fg9Uwpq/l7po1MwUTAdBgNVHQ4EFgQU/SxodXrpkybM
|
||||||
|
gcIgkxnRKd7HMzowHwYDVR0jBBgwFoAU/SxodXrpkybMgcIgkxnRKd7HMzowDwYD
|
||||||
|
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiBU9PrOa/kXCpTTBInRf/sN
|
||||||
|
ac2iDHmbdpWzcXI+xLKNYAIhAIRR1LRSHVwOTLQ/iBXd+8LCkm5aTB27RW46LN80
|
||||||
|
ylxt
|
||||||
|
-----END CERTIFICATE-----`;
|
||||||
|
|
||||||
|
const EC_P256_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDUc8A0EDNKoCYIPWMHz1yUzqE5mJ
|
||||||
|
gusgcAE8H6810fkJ8ZmTNiCCa6sLgR2vD1VNh2diirWgKPH4PVMKav5e6Q==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
const DSA_CERT = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEXzCCBA2gAwIBAgIUYYcPJB8UQLzUnqkGJvs3J4RI0OgwCwYJYIZIAWUDBAMC
|
||||||
|
MBMxETAPBgNVBAMMCERTQSBUZXN0MB4XDTIzMTAxNTAwMjEzNVoXDTMzMTAxMjAw
|
||||||
|
MjEzNVowEzERMA8GA1UEAwwIRFNBIFRlc3QwggNCMIICNQYHKoZIzjgEATCCAigC
|
||||||
|
ggEBALoLV+uz7vMYZCIuwXNkgZawvDgZAG1T7IiG030WgqesRNncuoUQOmAJCiuN
|
||||||
|
zkjVNSY08rabex/RIkWILvxP91SlzhA9t9+dp87p238ecxGa1sD2re+y35RP7IxN
|
||||||
|
T33633NtwGItZ3BqqAhoMmuwwwxau0E8zwYodTTlwTRp4QVPpMH1eJCUBeEzcWP5
|
||||||
|
ZZ1lRNhR5M2TqzSU3ya5/4c3a9rI86h9VIVgw8yVvw3y6yclzjALm2ntD5riskdM
|
||||||
|
Z6mMkfYQwEbIGRTELX6A7LZ0lX1CislenF9ASb2E4g2nGcMQ0uSGzA4W9mf6wwmP
|
||||||
|
S6iwX5+Qu/i6jCm5i37fQ1H5HHUCHQDA+UnPHM6PZEgfFen8djZpl/cl05MpWk+d
|
||||||
|
nikFAoIBADXOTpBw0WA+UihxDG+6qqM05kxVMYmz6IRZ/06ffZSGVFN6Bx1i0s3v
|
||||||
|
kzM5V8GsKpkKkSk7V8fTQnAIIlMmt1Y7ff+ng7+TfYotMrvvEYlolYK06J2WWoUA
|
||||||
|
8iKp8+n58vdoky+xZmuGmcvCAojVDbEeU2wEqYE1PzrHCSOoOiKB2P4fOhyuF+qx
|
||||||
|
E8nkzURIg2RmSSkqWOkXiWyKyfpUaB+4cEisp4ThENEPmdntE1vLh2r7EOIxpE5D
|
||||||
|
0NAy2wFKqe3ljfgE6XsPZKgVAguRDVpzdmL6WDY7DM/BcS726vx+kX55QDkszvec
|
||||||
|
raNirnir2QrB/a0JQjF6Y62yGmG7GF8DggEFAAKCAQBpN+w0N0b5IIAspXnlJ9yu
|
||||||
|
B6ORk3j/5rZ+DUtTzW1YAJI6xjTcFQvN7FpVLkmLtXKUXF04R+sdGJ7VFwOb0rba
|
||||||
|
L5vQzrqNkBrbgSzuzeloiG+7OLA6VeQtNbQh6OurrZFi9gY+qA5ciT9kQXyrHudV
|
||||||
|
Xu956NDrooRxmv6JIVFvToaNiwe2vcgdkALw8HUbLFYof4SAE9jgU8EpxTp02e8H
|
||||||
|
zvVSVa6yj1nnGhpzLPlEqF8TZvs9pTg2kIk3/zvWojMJoPyTALfbTjbAeiFMMeKN
|
||||||
|
K/CKOOJj23AVAZxpMSR6cUbrIcRdKDnhCTVkkxXUecAIUs6Mk10kSfkuiGl9LjKj
|
||||||
|
o1MwUTAdBgNVHQ4EFgQUE+xZdvgiDIFWKQskMYnNaZ3iPHAwHwYDVR0jBBgwFoAU
|
||||||
|
E+xZdvgiDIFWKQskMYnNaZ3iPHAwDwYDVR0TAQH/BAUwAwEB/zALBglghkgBZQME
|
||||||
|
AwIDPwAwPAIcZbtf4+bjXEGQqNs6IglLrOgIjYF46q7qCNfXmQIcMKUtH3S6sDJE
|
||||||
|
3ds9eL+oC+HPFlfUNfUiU30aDA==
|
||||||
|
-----END CERTIFICATE-----`;
|
||||||
|
|
||||||
|
const DSA_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIDQjCCAjUGByqGSM44BAEwggIoAoIBAQC6C1frs+7zGGQiLsFzZIGWsLw4GQBt
|
||||||
|
U+yIhtN9FoKnrETZ3LqFEDpgCQorjc5I1TUmNPK2m3sf0SJFiC78T/dUpc4QPbff
|
||||||
|
nafO6dt/HnMRmtbA9q3vst+UT+yMTU99+t9zbcBiLWdwaqgIaDJrsMMMWrtBPM8G
|
||||||
|
KHU05cE0aeEFT6TB9XiQlAXhM3Fj+WWdZUTYUeTNk6s0lN8muf+HN2vayPOofVSF
|
||||||
|
YMPMlb8N8usnJc4wC5tp7Q+a4rJHTGepjJH2EMBGyBkUxC1+gOy2dJV9QorJXpxf
|
||||||
|
QEm9hOINpxnDENLkhswOFvZn+sMJj0uosF+fkLv4uowpuYt+30NR+Rx1Ah0AwPlJ
|
||||||
|
zxzOj2RIHxXp/HY2aZf3JdOTKVpPnZ4pBQKCAQA1zk6QcNFgPlIocQxvuqqjNOZM
|
||||||
|
VTGJs+iEWf9On32UhlRTegcdYtLN75MzOVfBrCqZCpEpO1fH00JwCCJTJrdWO33/
|
||||||
|
p4O/k32KLTK77xGJaJWCtOidllqFAPIiqfPp+fL3aJMvsWZrhpnLwgKI1Q2xHlNs
|
||||||
|
BKmBNT86xwkjqDoigdj+HzocrhfqsRPJ5M1ESINkZkkpKljpF4lsisn6VGgfuHBI
|
||||||
|
rKeE4RDRD5nZ7RNby4dq+xDiMaROQ9DQMtsBSqnt5Y34BOl7D2SoFQILkQ1ac3Zi
|
||||||
|
+lg2OwzPwXEu9ur8fpF+eUA5LM73nK2jYq54q9kKwf2tCUIxemOtshphuxhfA4IB
|
||||||
|
BQACggEAaTfsNDdG+SCALKV55SfcrgejkZN4/+a2fg1LU81tWACSOsY03BULzexa
|
||||||
|
VS5Ji7VylFxdOEfrHRie1RcDm9K22i+b0M66jZAa24Es7s3paIhvuziwOlXkLTW0
|
||||||
|
Iejrq62RYvYGPqgOXIk/ZEF8qx7nVV7veejQ66KEcZr+iSFRb06GjYsHtr3IHZAC
|
||||||
|
8PB1GyxWKH+EgBPY4FPBKcU6dNnvB871UlWuso9Z5xoacyz5RKhfE2b7PaU4NpCJ
|
||||||
|
N/871qIzCaD8kwC32042wHohTDHijSvwijjiY9twFQGcaTEkenFG6yHEXSg54Qk1
|
||||||
|
ZJMV1HnACFLOjJNdJEn5LohpfS4yow==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
const ED25519_CERT = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBQjCB9aADAgECAhRjPJhrdNco5LzpsIs0vSLLaZaZ0DAFBgMrZXAwFzEVMBMG
|
||||||
|
A1UEAwwMRWQyNTUxOSBUZXN0MB4XDTIzMTAxNTAwMjMwOFoXDTMzMTAxMjAwMjMw
|
||||||
|
OFowFzEVMBMGA1UEAwwMRWQyNTUxOSBUZXN0MCowBQYDK2VwAyEAELP6AflXwsuZ
|
||||||
|
5q4NDIO0LP2iCdKRvds4nwsUmRhOw3ijUzBRMB0GA1UdDgQWBBRfxS9q0IemWxkH
|
||||||
|
4mwAwzr9dQx2xzAfBgNVHSMEGDAWgBRfxS9q0IemWxkH4mwAwzr9dQx2xzAPBgNV
|
||||||
|
HRMBAf8EBTADAQH/MAUGAytlcANBAI/+03iVq4yJ+DaLVs61w41cVX2UxKvquSzv
|
||||||
|
lllkpkclM9LH5dLrw4ArdTjS9zAjzY/02WkphHhICHXt3KqZTwI=
|
||||||
|
-----END CERTIFICATE-----`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
const ED25519_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MCowBQYDK2VwAyEAELP6AflXwsuZ5q4NDIO0LP2iCdKRvds4nwsUmRhOw3g=
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ED448_CERT = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBijCCAQqgAwIBAgIUZaCS7zEjOnQ7O4KUFym6fJF5vl8wBQYDK2VxMBUxEzAR
|
||||||
|
BgNVBAMMCkVkNDQ4IFRlc3QwHhcNMjMxMDE1MDAyMzI1WhcNMzMxMDEyMDAyMzI1
|
||||||
|
WjAVMRMwEQYDVQQDDApFZDQ0OCBUZXN0MEMwBQYDK2VxAzoAVN8kG0TMVyGOu/Ov
|
||||||
|
BTe8H0Wi4HJrQAlSv4XLwJbkuoi4EeRlEHQwXsNYLZTtY2Jra6AWhbVYYaEAo1Mw
|
||||||
|
UTAdBgNVHQ4EFgQUJFrepAf9YXrmDMSAzrMeYQmosd0wHwYDVR0jBBgwFoAUJFre
|
||||||
|
pAf9YXrmDMSAzrMeYQmosd0wDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXEDcwA+YiZj
|
||||||
|
puFr2aogfV1qg/ixk7qLi25BbKVNR6+7PEUjo7+4yBn9qnLbAHUGnHn7E96pSey9
|
||||||
|
VkLqpoDNMRcM3Eb6h3AJpQM0oxGj8q9arjDXqJkXgaO2e0tVn8KKVfy7S8qO72Kd
|
||||||
|
rWzZowcOjnWKhXm7JgA=
|
||||||
|
-----END CERTIFICATE-----`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
const ED448_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MEMwBQYDK2VxAzoAVN8kG0TMVyGOu/OvBTe8H0Wi4HJrQAlSv4XLwJbkuoi4EeRl
|
||||||
|
EHQwXsNYLZTtY2Jra6AWhbVYYaEA
|
||||||
|
-----END PUBLIC KEY-----`
|
||||||
|
*/
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Public Key from Certificate: Missing footer",
|
||||||
|
input: RSA_CERT.substring(0, RSA_CERT.length / 2),
|
||||||
|
expectedOutput: "PEM footer '-----END CERTIFICATE-----' not found",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Certificate",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test RSA certificate
|
||||||
|
{
|
||||||
|
name: "Public Key from Certificate: RSA",
|
||||||
|
input: RSA_CERT,
|
||||||
|
expectedOutput: (RSA_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Certificate",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test EC certificate
|
||||||
|
{
|
||||||
|
name: "Public Key from Certificate: EC",
|
||||||
|
input: EC_P256_CERT,
|
||||||
|
expectedOutput: (EC_P256_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Certificate",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test DSA certificate
|
||||||
|
{
|
||||||
|
name: "Public Key from Certificate: DSA",
|
||||||
|
input: DSA_CERT,
|
||||||
|
expectedOutput: (DSA_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Certificate",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test EdDSA certificates
|
||||||
|
{
|
||||||
|
name: "Public Key from Certificate: Ed25519",
|
||||||
|
input: ED25519_CERT,
|
||||||
|
expectedOutput: "Unsupported public key type",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Certificate",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from Certificate: Ed448",
|
||||||
|
input: ED448_CERT,
|
||||||
|
expectedOutput: "Unsupported public key type",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Certificate",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test multi-input
|
||||||
|
{
|
||||||
|
name: "Public Key from Certificate: Multiple certificates",
|
||||||
|
input: RSA_CERT + "\n" + EC_P256_CERT,
|
||||||
|
expectedOutput: (RSA_PUBKEY + "\n" + EC_P256_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Certificate",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]);
|
254
tests/operations/tests/PubKeyFromPrivKey.mjs
Normal file
254
tests/operations/tests/PubKeyFromPrivKey.mjs
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/**
|
||||||
|
* Public Key from Private Key
|
||||||
|
*
|
||||||
|
* @author cplussharp
|
||||||
|
* @copyright Crown Copyright 2023
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
const RSA_PRIVKEY_PKCS1 = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOQIBAAJBAPKr0Dp6YdItzOfk6a7ma7L4BF4LnelMYKtboGLrk6ihtqFPZFRL
|
||||||
|
NcJi68Hvnt8stMrP50t6jqwWQ2EjMdkj6fsCAwEAAQJAOJUpM0lv36MAQR3WAwsF
|
||||||
|
F7DOy+LnigteCvaNWiNVxZ6jByB5Qb7sall/Qlu9sFI0ZwrlVcKS0kldee7JTYlL
|
||||||
|
WQIhAP3UKEfOtpTgT1tYmdhaqjxqMfxBom0Ri+rt9ajlzs6vAiEA9L85B8/Gnb7p
|
||||||
|
6Af7/wpmafL277OV4X4xBfzMR+TUzHUCIBq+VLQkInaTH6lXL3ZtLwyIf9W9MJjf
|
||||||
|
RWeuRLjT5bM/AiBF7Kw6kx5Hy1fAtydEApCoDIaIjWJw/kC7WTJ0B+jUUQIgV6dw
|
||||||
|
NSyj0feakeD890gmId+lvl/w/3oUXiczqvl/N9o=
|
||||||
|
-----END RSA PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
const RSA_PRIVKEY_PKCS8 = `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA8qvQOnph0i3M5+Tp
|
||||||
|
ruZrsvgEXgud6Uxgq1ugYuuTqKG2oU9kVEs1wmLrwe+e3yy0ys/nS3qOrBZDYSMx
|
||||||
|
2SPp+wIDAQABAkA4lSkzSW/fowBBHdYDCwUXsM7L4ueKC14K9o1aI1XFnqMHIHlB
|
||||||
|
vuxqWX9CW72wUjRnCuVVwpLSSV157slNiUtZAiEA/dQoR862lOBPW1iZ2FqqPGox
|
||||||
|
/EGibRGL6u31qOXOzq8CIQD0vzkHz8advunoB/v/CmZp8vbvs5XhfjEF/MxH5NTM
|
||||||
|
dQIgGr5UtCQidpMfqVcvdm0vDIh/1b0wmN9FZ65EuNPlsz8CIEXsrDqTHkfLV8C3
|
||||||
|
J0QCkKgMhoiNYnD+QLtZMnQH6NRRAiBXp3A1LKPR95qR4Pz3SCYh36W+X/D/ehRe
|
||||||
|
JzOq+X832g==
|
||||||
|
-----END PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
const RSA_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKr0Dp6YdItzOfk6a7ma7L4BF4LnelM
|
||||||
|
YKtboGLrk6ihtqFPZFRLNcJi68Hvnt8stMrP50t6jqwWQ2EjMdkj6fsCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
const EC_P256_PRIVKEY_SEC1 = `-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEINtTjwUkgfAiSwqgcGAXWyE0ueIW6n2k395dmQZ3vGr4oAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEDUc8A0EDNKoCYIPWMHz1yUzqE5mJgusgcAE8H6810fkJ8ZmTNiCC
|
||||||
|
a6sLgR2vD1VNh2diirWgKPH4PVMKav5e6Q==
|
||||||
|
-----END EC PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
const EC_P256_PRIVKEY_PKCS8 = `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg21OPBSSB8CJLCqBw
|
||||||
|
YBdbITS54hbqfaTf3l2ZBne8avihRANCAAQNRzwDQQM0qgJgg9YwfPXJTOoTmYmC
|
||||||
|
6yBwATwfrzXR+QnxmZM2IIJrqwuBHa8PVU2HZ2KKtaAo8fg9Uwpq/l7p
|
||||||
|
-----END PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
const EC_P256_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDUc8A0EDNKoCYIPWMHz1yUzqE5mJ
|
||||||
|
gusgcAE8H6810fkJ8ZmTNiCCa6sLgR2vD1VNh2diirWgKPH4PVMKav5e6Q==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
const DSA_PRIVKEY_TRAD = `-----BEGIN DSA PRIVATE KEY-----
|
||||||
|
MIIDTQIBAAKCAQEAugtX67Pu8xhkIi7Bc2SBlrC8OBkAbVPsiIbTfRaCp6xE2dy6
|
||||||
|
hRA6YAkKK43OSNU1JjTytpt7H9EiRYgu/E/3VKXOED23352nzunbfx5zEZrWwPat
|
||||||
|
77LflE/sjE1Pffrfc23AYi1ncGqoCGgya7DDDFq7QTzPBih1NOXBNGnhBU+kwfV4
|
||||||
|
kJQF4TNxY/llnWVE2FHkzZOrNJTfJrn/hzdr2sjzqH1UhWDDzJW/DfLrJyXOMAub
|
||||||
|
ae0PmuKyR0xnqYyR9hDARsgZFMQtfoDstnSVfUKKyV6cX0BJvYTiDacZwxDS5IbM
|
||||||
|
Dhb2Z/rDCY9LqLBfn5C7+LqMKbmLft9DUfkcdQIdAMD5Sc8czo9kSB8V6fx2NmmX
|
||||||
|
9yXTkylaT52eKQUCggEANc5OkHDRYD5SKHEMb7qqozTmTFUxibPohFn/Tp99lIZU
|
||||||
|
U3oHHWLSze+TMzlXwawqmQqRKTtXx9NCcAgiUya3Vjt9/6eDv5N9ii0yu+8RiWiV
|
||||||
|
grTonZZahQDyIqnz6fny92iTL7Fma4aZy8ICiNUNsR5TbASpgTU/OscJI6g6IoHY
|
||||||
|
/h86HK4X6rETyeTNREiDZGZJKSpY6ReJbIrJ+lRoH7hwSKynhOEQ0Q+Z2e0TW8uH
|
||||||
|
avsQ4jGkTkPQ0DLbAUqp7eWN+ATpew9kqBUCC5ENWnN2YvpYNjsMz8FxLvbq/H6R
|
||||||
|
fnlAOSzO95yto2KueKvZCsH9rQlCMXpjrbIaYbsYXwKCAQBpN+w0N0b5IIAspXnl
|
||||||
|
J9yuB6ORk3j/5rZ+DUtTzW1YAJI6xjTcFQvN7FpVLkmLtXKUXF04R+sdGJ7VFwOb
|
||||||
|
0rbaL5vQzrqNkBrbgSzuzeloiG+7OLA6VeQtNbQh6OurrZFi9gY+qA5ciT9kQXyr
|
||||||
|
HudVXu956NDrooRxmv6JIVFvToaNiwe2vcgdkALw8HUbLFYof4SAE9jgU8EpxTp0
|
||||||
|
2e8HzvVSVa6yj1nnGhpzLPlEqF8TZvs9pTg2kIk3/zvWojMJoPyTALfbTjbAeiFM
|
||||||
|
MeKNK/CKOOJj23AVAZxpMSR6cUbrIcRdKDnhCTVkkxXUecAIUs6Mk10kSfkuiGl9
|
||||||
|
LjKjAhwpK4MOpkKEu+y308fZ+yZXypZW2m9Y/wOT0L4g
|
||||||
|
-----END DSA PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
const DSA_PRIVKEY_PKCS8 = `-----BEGIN PRIVATE KEY-----
|
||||||
|
MIICXAIBADCCAjUGByqGSM44BAEwggIoAoIBAQC6C1frs+7zGGQiLsFzZIGWsLw4
|
||||||
|
GQBtU+yIhtN9FoKnrETZ3LqFEDpgCQorjc5I1TUmNPK2m3sf0SJFiC78T/dUpc4Q
|
||||||
|
PbffnafO6dt/HnMRmtbA9q3vst+UT+yMTU99+t9zbcBiLWdwaqgIaDJrsMMMWrtB
|
||||||
|
PM8GKHU05cE0aeEFT6TB9XiQlAXhM3Fj+WWdZUTYUeTNk6s0lN8muf+HN2vayPOo
|
||||||
|
fVSFYMPMlb8N8usnJc4wC5tp7Q+a4rJHTGepjJH2EMBGyBkUxC1+gOy2dJV9QorJ
|
||||||
|
XpxfQEm9hOINpxnDENLkhswOFvZn+sMJj0uosF+fkLv4uowpuYt+30NR+Rx1Ah0A
|
||||||
|
wPlJzxzOj2RIHxXp/HY2aZf3JdOTKVpPnZ4pBQKCAQA1zk6QcNFgPlIocQxvuqqj
|
||||||
|
NOZMVTGJs+iEWf9On32UhlRTegcdYtLN75MzOVfBrCqZCpEpO1fH00JwCCJTJrdW
|
||||||
|
O33/p4O/k32KLTK77xGJaJWCtOidllqFAPIiqfPp+fL3aJMvsWZrhpnLwgKI1Q2x
|
||||||
|
HlNsBKmBNT86xwkjqDoigdj+HzocrhfqsRPJ5M1ESINkZkkpKljpF4lsisn6VGgf
|
||||||
|
uHBIrKeE4RDRD5nZ7RNby4dq+xDiMaROQ9DQMtsBSqnt5Y34BOl7D2SoFQILkQ1a
|
||||||
|
c3Zi+lg2OwzPwXEu9ur8fpF+eUA5LM73nK2jYq54q9kKwf2tCUIxemOtshphuxhf
|
||||||
|
BB4CHCkrgw6mQoS77LfTx9n7JlfKllbab1j/A5PQviA=
|
||||||
|
-----END PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
const DSA_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIDQjCCAjUGByqGSM44BAEwggIoAoIBAQC6C1frs+7zGGQiLsFzZIGWsLw4GQBt
|
||||||
|
U+yIhtN9FoKnrETZ3LqFEDpgCQorjc5I1TUmNPK2m3sf0SJFiC78T/dUpc4QPbff
|
||||||
|
nafO6dt/HnMRmtbA9q3vst+UT+yMTU99+t9zbcBiLWdwaqgIaDJrsMMMWrtBPM8G
|
||||||
|
KHU05cE0aeEFT6TB9XiQlAXhM3Fj+WWdZUTYUeTNk6s0lN8muf+HN2vayPOofVSF
|
||||||
|
YMPMlb8N8usnJc4wC5tp7Q+a4rJHTGepjJH2EMBGyBkUxC1+gOy2dJV9QorJXpxf
|
||||||
|
QEm9hOINpxnDENLkhswOFvZn+sMJj0uosF+fkLv4uowpuYt+30NR+Rx1Ah0AwPlJ
|
||||||
|
zxzOj2RIHxXp/HY2aZf3JdOTKVpPnZ4pBQKCAQA1zk6QcNFgPlIocQxvuqqjNOZM
|
||||||
|
VTGJs+iEWf9On32UhlRTegcdYtLN75MzOVfBrCqZCpEpO1fH00JwCCJTJrdWO33/
|
||||||
|
p4O/k32KLTK77xGJaJWCtOidllqFAPIiqfPp+fL3aJMvsWZrhpnLwgKI1Q2xHlNs
|
||||||
|
BKmBNT86xwkjqDoigdj+HzocrhfqsRPJ5M1ESINkZkkpKljpF4lsisn6VGgfuHBI
|
||||||
|
rKeE4RDRD5nZ7RNby4dq+xDiMaROQ9DQMtsBSqnt5Y34BOl7D2SoFQILkQ1ac3Zi
|
||||||
|
+lg2OwzPwXEu9ur8fpF+eUA5LM73nK2jYq54q9kKwf2tCUIxemOtshphuxhfA4IB
|
||||||
|
BQACggEAaTfsNDdG+SCALKV55SfcrgejkZN4/+a2fg1LU81tWACSOsY03BULzexa
|
||||||
|
VS5Ji7VylFxdOEfrHRie1RcDm9K22i+b0M66jZAa24Es7s3paIhvuziwOlXkLTW0
|
||||||
|
Iejrq62RYvYGPqgOXIk/ZEF8qx7nVV7veejQ66KEcZr+iSFRb06GjYsHtr3IHZAC
|
||||||
|
8PB1GyxWKH+EgBPY4FPBKcU6dNnvB871UlWuso9Z5xoacyz5RKhfE2b7PaU4NpCJ
|
||||||
|
N/871qIzCaD8kwC32042wHohTDHijSvwijjiY9twFQGcaTEkenFG6yHEXSg54Qk1
|
||||||
|
ZJMV1HnACFLOjJNdJEn5LohpfS4yow==
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
|
||||||
|
const ED25519_PRIVKEY = `-----BEGIN PRIVATE KEY-----
|
||||||
|
MC4CAQAwBQYDK2VwBCIEIC18vtoHINC8Mo9dTIqOrBs3J28ZvHrwzRq57g2kpV98
|
||||||
|
-----END PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
const ED25519_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MCowBQYDK2VwAyEAELP6AflXwsuZ5q4NDIO0LP2iCdKRvds4nwsUmRhOw3g=
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ED448_PRIVKEY = `-----BEGIN PRIVATE KEY-----
|
||||||
|
MEcCAQAwBQYDK2VxBDsEOWdGJ06bDcWznJhBoQqPeTfsCe+AvBv1n7KfIGYzR4tv
|
||||||
|
1kcwHnbxlemnCMgqvbrRXaLuFUBysUZThA==
|
||||||
|
-----END PRIVATE KEY-----`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
const ED448_PUBKEY = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MEMwBQYDK2VxAzoAVN8kG0TMVyGOu/OvBTe8H0Wi4HJrQAlSv4XLwJbkuoi4EeRl
|
||||||
|
EHQwXsNYLZTtY2Jra6AWhbVYYaEA
|
||||||
|
-----END PUBLIC KEY-----`;
|
||||||
|
*/
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: Missing footer",
|
||||||
|
input: RSA_PRIVKEY_PKCS1.substring(0, RSA_PRIVKEY_PKCS1.length / 2),
|
||||||
|
expectedOutput: "PEM footer '-----END RSA PRIVATE KEY-----' not found",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test RSA
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: RSA PKCS#1",
|
||||||
|
input: RSA_PRIVKEY_PKCS1,
|
||||||
|
expectedOutput: (RSA_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: RSA PKCS#8",
|
||||||
|
input: RSA_PRIVKEY_PKCS8,
|
||||||
|
expectedOutput: (RSA_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test EC certificate
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: EC SEC1",
|
||||||
|
input: EC_P256_PRIVKEY_SEC1,
|
||||||
|
expectedOutput: (EC_P256_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: EC PKCS#8",
|
||||||
|
input: EC_P256_PRIVKEY_PKCS8,
|
||||||
|
expectedOutput: (EC_P256_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test DSA
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: DSA Traditional",
|
||||||
|
input: DSA_PRIVKEY_TRAD,
|
||||||
|
expectedOutput: (DSA_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: DSA PKCS#8",
|
||||||
|
input: DSA_PRIVKEY_PKCS8,
|
||||||
|
expectedOutput: "DSA Private Key in PKCS#8 is not supported",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test EdDSA
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: Ed25519",
|
||||||
|
input: ED25519_PRIVKEY,
|
||||||
|
expectedOutput: "Unsupported key type: Error: malformed PKCS8 private key(code:004)",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: Ed448",
|
||||||
|
input: ED448_PRIVKEY,
|
||||||
|
expectedOutput: "Unsupported key type: Error: malformed PKCS8 private key(code:004)",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// test multi-input
|
||||||
|
{
|
||||||
|
name: "Public Key from Private Key: Multiple keys",
|
||||||
|
input: RSA_PRIVKEY_PKCS8 + "\n" + EC_P256_PRIVKEY_PKCS8,
|
||||||
|
expectedOutput: (RSA_PUBKEY + "\n" + EC_P256_PUBKEY + "\n").replace(/\r/g, "").replace(/\n/g, "\r\n"),
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Public Key from Private Key",
|
||||||
|
args: [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]);
|
|
@ -1,62 +1,42 @@
|
||||||
/**
|
/**
|
||||||
* Base64 tests.
|
* XXTEA tests.
|
||||||
*
|
*
|
||||||
* @author devcydo [devcydo@gmail.com]
|
* @author devcydo [devcydo@gmail.com]
|
||||||
*
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
* @copyright Crown Copyright 2022
|
* @copyright Crown Copyright 2024
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "XXTEA",
|
name: "XXTEA Encrypt and Decrypt",
|
||||||
input: "Hello World! 你好,中国!",
|
input: "Hello World! 你好,中国!",
|
||||||
expectedOutput: "QncB1C0rHQoZ1eRiPM4dsZtRi9pNrp7sqvX76cFXvrrIHXL6",
|
expectedOutput: "Hello World! 你好,中国!",
|
||||||
reecipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
args: "1234567890"
|
"op": "XXTEA Encrypt",
|
||||||
|
"args": [{ "option": "UTF8", "string": "1234567890" }]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"op": "XXTEA Decrypt",
|
||||||
|
"args": [{ "option": "UTF8", "string": "1234567890" }]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "XXTEA",
|
name: "XXTEA Encrypt",
|
||||||
input: "ნუ პანიკას",
|
input: "ნუ პანიკას",
|
||||||
expectedOutput: "PbWjnbFmP8Apu2MKOGNbjeW/72IZLlLMS/g82ozLxwE=",
|
expectedOutput: "3db5a39db1663fc029bb630a38635b8de5bfef62192e52cc4bf83cda8ccbc701",
|
||||||
reecipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
args: "1234567890"
|
"op": "XXTEA Encrypt",
|
||||||
|
"args": [{ "option": "UTF8", "string": "1234567890" }]
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "XXTEA",
|
|
||||||
input: "ნუ პანიკას",
|
|
||||||
expectedOutput: "dHrOJ4ClIx6gH33NPSafYR2GG7UqsazY6Xfb0iekBY4=",
|
|
||||||
reecipeConfig: [
|
|
||||||
{
|
{
|
||||||
args: "ll3kj209d2"
|
"op": "To Hex",
|
||||||
},
|
"args": ["None", 0]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
}
|
||||||
{
|
|
||||||
name: "XXTEA",
|
|
||||||
input: "",
|
|
||||||
expectedOutput: "Invalid input length (0)",
|
|
||||||
reecipeConfig: [
|
|
||||||
{
|
|
||||||
args: "1234567890"
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "XXTEA",
|
|
||||||
input: "",
|
|
||||||
expectedOutput: "Invalid input length (0)",
|
|
||||||
reecipeConfig: [
|
|
||||||
{
|
|
||||||
args: ""
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -22,7 +22,7 @@ export const PNG_HEX = "89504e470d0a1a0a0000000d49484452000000200000002008060000
|
||||||
* The CyberChef logo with 'chef'
|
* The CyberChef logo with 'chef'
|
||||||
* 32x32
|
* 32x32
|
||||||
*/
|
*/
|
||||||
export const PNG_CHEF_B64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAH40lEQVR4AaXBfVAU5wEH4N/77t7ufXAnHlwE5MuK1uApVo1ppNBxgpJKKyijaewYJzRj0eokjBpbp3HQ0VpN1fqHndCxNkW4UWf8KHZaa0yR1hPH04QGGwm9Ata7KN/c5m5v9+52t8tIp1QPJOnzEHw5TF1dnTMlJWVxOBxmfD7fjY0bN34EQAVAAWgAVEwAwcQQABSAtmXLFltlZeW7iYmJqwVBQCgUogA0QRAuDg4OfuxwOEpkWW5dunRpBQAFT8FifOTcuXPPz5w5cxPP87mqqoYAmKxW63N4RMUjxGazrbBard8hOp7ncziOe7O2tnaJ0Wi0l5WVnQCgIg6CsRG3270pOzv7CCHEgDgCgYAaCoUo4pAk6T7P81Oh8/l8FStXrvwt4mAxhnPnzi3Myso6Qggx4EswGo0ZeERTVRVjoYiPzJgxYyOl1ID/kyzLPevWrbsAgCAOBvExVVVVOzmOm4pxRCIRRCIRgnGwLJvwim7NmjUZdXV17+MxLOLTdBKejmACjEZjlqIoLwCgABSMQhGfGgqFmvB0GiZAlmV/OBz2AFDxGAZjyMzMvOt0OtcyDGPFiEgkAkVRwDAMhkmSpEWjUYJxyLLcU1xcnHvixIkGABpGEEIM6enpLxCMkpOT82JpaenLHMc9IwiCv6CgoG3RokWbjUbjTOh4nofX60VGRgaGBQIBNRQKUTyFz+fbWFZW9i5GmM3m9IaGhsb8/PxsihHbtm071traeikpKYnz+/2fLFiwILu8vPwXBw4cOK+qahQ6RVGgaRomIhwOd2qapmiapuoiGKWiomJbZmbm5OTk5K+y0BUUFHx33759P8jLy1vW1tb2Z+hqa2vR3Ny87/Dhwzs7OjrgcDgwUYqiiIWFhQvq6+sLzGazY9WqVe9hlPLy8rzTp097QqFQBwPd3r17a65evfo3l8u1H6O0tbW17t69e3t7ezvsdjsopRgcHITZbEYoFMLQ0BCRJAkcx2E0SZKI3+9/0NXVNd3j8fR1dna2K4oSYxjGuH79+h8WFxcXWSwWo8Fg4BldQk1NzaHjx4//+s6dOzcwSjQaFevr6z+orKys4DgOlFLwPA+bzQZVVWGz2TB37lx4vV5wHIdhQ0NDcDqddP78+Xmpqal07dq1r5WUlKw6pSOEsOvWrdvtdDqn2e1229DQUCLL83xCcnKy2e/3P0QcXq/3I5PJFAHAQWe329HV1YXk5GQEAgH19u3b1OFwQBRFaJoGq9WKvr4+LF68+NlYLCZYrdYUj8fTunz58sqGhoZ3qqqqlsybN6/x8uXLgf3795dRAAQ6RVFUxBd2u90ftLS0QBAEeDwe+Hw+tLS0wO12w+PxIC0tDZcuXcLFixexcOFCnDp1CoqiRAkhfDAYHLxy5cq1/Pz8ZRiFUkqgY1VVVaBLSkqyIj5DTk7ODIZhYDQaYTAYkJSUhGEcx6Gvrw8Mw2DWrFkQRRGUUlRXV6O6ulrEKC6X60PEwcqyPHD37t3eaTo8JneKxfjW1jdD/X9vplMmGQHL10Gkz0EG22Gyp2uTTFbtQTQKTdPQ3t6uASDQ7dq1C263u+rmzZt/xIhYLCYjDqppWuzChQt/WLFixcuUUh7/Rb//0iLP+u17qfbwLqj3ryChASAcAPVeQ5rZTCwMQ6BTVRXNzc3k+vXriMVi0DQNZrP5YH5+PoLB4KeiKHZIktSFOCh0R48e/emcOXNSt27desxoNCZC99o3Zy158fUfO1uuN8LORPAfiqohdeEqWJKzMMxkMoFSCnmyDEIIampqsGHDBjgcDjqgW758+WKXy3WpqKhoC+Jgoevu7m4vLCz81smTJ3+zZ8+eXlEUowkWs+nTm024VrMTqzcfgsXE48N+AYMw45MBBc+lyrjf2UlgMCBGYugv70chWwj+Mx49PT2oqalhJEnq4TgObrcbN27ceBVxEIxCCGHT09Odq/JSv+ZMZk8YIgKkmIrVb52A3ZGK42fP4tqtW9j7xhuwMAyabt2CYDKhK7MLxx4ew9uOt5EdzkYwGBxobGy0chxngG5gYGCby+U6hBFTpkyZJkmSEggE/sXgf6mCIDz83mxrhZlGn4cupmqYnV8Kk8WK+bm5KCsqgsVsRkwQ0NndjR5RRK4lF6VcKRJjiRhGCPE1NTW9brFYXhEE4bjL5foJAA0jQqHQkCzLAegonkQNLJmPcciyDCPLYlh/fz8ep6oqTUhI+AZ0PM/nL1u2bBrGQPEkTVXRjXHwPI8IdIRogiBA0zSMJknSV2w223boWJZ9NiUlZTPGwOJJWm8wUmPmTKWEgEEcDKWwOByYMWcOaEoKCCF4DIlEIi2CIOy1Wq0r/H7/EYyBRRzVf/rn+z/79oxNzyRw7wCwYYSqqvALAiwmExiWxcdtbeTS1ataLBaDxWJRSkpKGB2BLhqNNp4/f/4sgLMYB4v4tB/9/h+/WjMv5XfTkkwvsZzpKIBJlFKkmEzo8XoR7u+H0t2tZWRkaGlpacjIyGCIDjqO4+77/f5DmAAW4zjT8rAbQO2rPb1yjtnyc85gmGrgeUydPRvDog8eaIm9vRSjKIrymSiKW5qamvyYAAYT8Mva2juqqr43a/r0z3mOy2YZZjJ0fcGgNiiKBDpFUXyiKB5pbm5ev2PHjhZMEMEXRCnl/nLmTG5Wenpe18DApI7e3qDuzsGDB1vu3bsXwRf0bxUQXc2aUJWHAAAAAElFTkSuQmCC";
|
export const PNG_CHEF_B64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAHqElEQVR4AcXBfUyU9wEH8O/v9zz3PHfPvXLewXHnxYKgYCFW6ktHmXUySIdKcVlFs2ZkrRB1m6kx00XTbGJjFrvVTSexZusGviQqwsxImM5laOZclG3EisEXWK2cvBwcuYN7456XPawQb+fx4l/7fAji5Obmvrlx48ZKjUZjlyTpaXNz89nOzs42TDp37lzLwMCAcefOnWtPnz6d53A4CsPhMNPb2/v37du3/wuADIACUADImIZer3e3tLS0rVy50k2gIqo9e/b8et++fd8+ceLEqXA47Jk3b97SmpqaDTU1NT+ur68/BICeOXPmEsuyzry8vAcWi+XtQCCAYDBIASiBQOAPIyMjd+x2+7poNPpZSUnJuwAkJLFr165j1dXVlQUFBa+yUBUXF79TW1tbtWTJkrXd3d3XMam9vb325MmTH27durXc4XAwBoPh1Z6eHqSkpCzDl2R8iZhMpnKj0biBqHiez+I47v2GhoavabVaa0VFxacAZEwqLy/Pa2xsbI9EIk8YqA4ePPhJa2tre2Nj40d4hnz88cerMzMz1/T29rrS0tKcLMvC7/eDUooJg4ODBCpCCAghICqoxsfH+aqqqr2CIFTabLbykpIS74ULF24zDKPbvXv3nuLi4rUmk0mfmppqoQzDGMvKyl55+PDhdcRpampavnjx4v3d3d1wOByY4nQ6IQgCIpEIrFYrVq1aBVEUMcXv9yMjIwNOpxPp6emw2WzIz8//lUajMQNg9Xp9oSiKxvT0dLsgCF+hPM/rLRaL9tGjRwN4hmRnZ2+nlGoMBgMEQcAUk8mEkZERmM1mqORbt24hJSUFExRFgcVigc/ng9frxejoKHp6eiRRFCPl5eU7JEkaPXDgwPq+vr67p06d+lttbe0GCoBAJUmSjGcoz/N5SKKrqws2mw0TiMrv98PlcmFCIBBAQUEBBgYGEI1GEQqFwLIsA0C7Y8eOQwAIJlFKCVSsLMsSVHa73YRnFFUEsyOKooAQggmiKGJCcXExEoVCIagoAAlx2Gg0OtzR0dHndruz8YwcDAavGQyGr46NjSEQCMDlciEJBQBBgpaWFpjNZkyJRqOxYDB4DoCMBFRRFOnixYstmzdvrmQYRodJra2tx30+HxYtWgRZlpGMokIcnuchiiIcDgcEQYAgCGAYZrCysvKlioqKKgAKElCo6urqDmZnZxuOHDlyRhCEBZRSXV1dXaYgCLh//z7S09MxFwaDAbdv30ZWVhZ8Ph+i0SiCwWBqZ2enp6ys7H0kwULl8/me5OXlrTl+/PinwWDwc6gikYh49OjR39fX139w5cqVfwLQMAwDQgjiEUJAKcUUhmHQ1dWF1atXg+d5yLKMtrY2XL169beIwzAMhYogDiGE8jyfrtVqrcFgsDcWi40AMPT29g5TSrlwOAxFUSAIAib4/X55ZGSEiqIIQRAwRZKkUFFRUf6xY8c2m81mecuWLYcByJjEsqxJUUmSNMoijqIociQS8UQiEQ+S0Ol0SMRxHDiOQzxZliOxWKxv27Zth5CEKIoBTKL4P6OYnYIXRAhRAMiYAxazC9+4cePPRqPxG0jw9OlT9Pf3I1E4HL4GIIY5YDE7TVZWVjbDMEjEcRwsFgsSybK8EAADQMYsWMxgSZpeu6Uo53vMF//IIJQins46XzHrjIrH41E8Hg/iiaKYvWbNmq+3tbW1YhYE06OH38o5sfa1gmqe0+B/EWSseRdfxDi5/cED2tTUBEmSEE9RlJgq//Lly/cxA4ppvLM83WXXs9992N0DkfKYEohISF/+TehtCzAhJSUFK8pWIJoSxRSGYcBx3F99qtLS0ixGhWkwmMa3ljrWW3Ts28FwBK9t/gBpOYU4cPYKvNZcGMxpSLNa8dm9exA1GrKf7IdmqQbLVi7DG+43kJOTg6GhIafNZiuzWq0HMzMzuzs7O+8gCYoktr/uznCZ+aOYRCkDncmOFSuK8KDzHjKcToQDAYT8fjI2Nob33O/hSegJMvlM2O12aLVanyiK/+Y4bilRsSybimmwSCI3Vb+LoWQeElRv2oTqTZsgyTKC/f2YMDQ0hEJjIQoNhUAY/8Xz/LDX693rcrkuBYPB35w9e/YXmAbF86iGJQWYQTQahZZlMWF4eBiJZFmmBoOhCCqe518vLS3NwDQonqfIMgYwA57nMQ4VIUogEICiKIgXiUQyTSbTD6FiWTbX4XB8H9Ng8TzFOzb+icDp3iIEDJJgKIXebkd2fj6owwFCCBKQ8fHxjkAg8KHRaCz3eDxHMA0WSfzkcveffro+e0eqgfsIgAmTZFmGJxCAXqcDw7K409VF/tjWpoiiCL1eL61bt45REahisdhfmpubLwK4iBmwSE75UcvDk5tecVzKmKd7k+V0vwRgppTCodNh8NEjhIeHIQ0MKG63W3E6nXC73QxRQcVx3BOPx/NzzAGLGZzv6B8A0PCdQW80S9D/jNNoXBqeh+vllzEh1tenWLxeijiSJD0NhUI/uHbtmgdzwGAO6hoa7sqy/LuchQtHeY57iWWYFKiGxsaUkVCIQCVJUm8oFDpy8+bNqr1793ZgjgheEKWUu37+/JIF8+cv/dznM/d4vWOqu4cPH+54/PjxOF7QfwCiFwbr9BCaBwAAAABJRU5ErkJggg==";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The CyberChef logo with blur
|
* The CyberChef logo with blur
|
||||||
|
|
BIN
tests/samples/files/testocr.png
Normal file
BIN
tests/samples/files/testocr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
|
@ -1,7 +1,7 @@
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
const { ModifySourcePlugin } = require("modify-source-webpack-plugin");
|
const { ModifySourcePlugin, ReplaceOperation } = require("modify-source-webpack-plugin");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,13 +12,14 @@ const path = require("path");
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const d = new Date();
|
||||||
const banner = `/**
|
const banner = `/**
|
||||||
* CyberChef - The Cyber Swiss Army Knife
|
* CyberChef - The Cyber Swiss Army Knife
|
||||||
*
|
*
|
||||||
* @copyright Crown Copyright 2016
|
* @copyright Crown Copyright 2016-${d.getUTCFullYear()}
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*
|
*
|
||||||
* Copyright 2016 Crown Copyright
|
* Copyright 2016-${d.getUTCFullYear()} Crown Copyright
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -89,8 +90,9 @@ module.exports = {
|
||||||
{
|
{
|
||||||
// Fix toSpare(0) bug in Split.js by avoiding gutter accomodation
|
// Fix toSpare(0) bug in Split.js by avoiding gutter accomodation
|
||||||
test: /split\.es\.js$/,
|
test: /split\.es\.js$/,
|
||||||
modify: (src, path) =>
|
operations: [
|
||||||
src.replace("if (pixelSize < elementMinSize)", "if (false)")
|
new ReplaceOperation("once", "if (pixelSize < elementMinSize)", "if (false)")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -110,7 +112,8 @@ module.exports = {
|
||||||
"crypto": require.resolve("crypto-browserify"),
|
"crypto": require.resolve("crypto-browserify"),
|
||||||
"stream": require.resolve("stream-browserify"),
|
"stream": require.resolve("stream-browserify"),
|
||||||
"zlib": require.resolve("browserify-zlib"),
|
"zlib": require.resolve("browserify-zlib"),
|
||||||
"process": false
|
"process": false,
|
||||||
|
"vm": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
|
Loading…
Reference in a new issue