mirror of
https://github.com/gchq/CyberChef
synced 2025-12-05 23:53:27 +00:00
Compare commits
71 Commits
v10.17.1
...
feature/de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cc84b1c62 | ||
|
|
f02b3f22ad | ||
|
|
e9b8163626 | ||
|
|
20390ae08e | ||
|
|
fcdcce7ee4 | ||
|
|
3d017d5f84 | ||
|
|
5455061e15 | ||
|
|
f4995dbc30 | ||
|
|
cc7cc7f8fd | ||
|
|
6a92f922cb | ||
|
|
71c8c8aac0 | ||
|
|
3deb121043 | ||
|
|
1fcc365d9e | ||
|
|
3822c6c520 | ||
|
|
47c85a105d | ||
|
|
d3adfc7c3e | ||
|
|
270a333179 | ||
|
|
895a929925 | ||
|
|
1fde2fba29 | ||
|
|
a50d4d63eb | ||
|
|
dbc90090cf | ||
|
|
e65869a10b | ||
|
|
d635cca210 | ||
|
|
0e82e4b7c6 | ||
|
|
5f88ae44ec | ||
|
|
7a5225c961 | ||
|
|
a477f47aec | ||
|
|
965570d250 | ||
|
|
ab37c1e562 | ||
|
|
40fda00db4 | ||
|
|
d5374454f4 | ||
|
|
4c5577ddeb | ||
|
|
534ab23d9b | ||
|
|
fe9f4fa7a9 | ||
|
|
a8b1050d75 | ||
|
|
e80d3d59bc | ||
|
|
1efbd9dfd1 | ||
|
|
6c30c9c6b8 | ||
|
|
4528a1bdb6 | ||
|
|
c23a8de5a0 | ||
|
|
0cd4d41cdc | ||
|
|
2b275f0897 | ||
|
|
63913f4d45 | ||
|
|
b6c95492f1 | ||
|
|
ae03e34489 | ||
|
|
7eb887ca51 | ||
|
|
74d0166682 | ||
|
|
18159ce806 | ||
|
|
86d59783fa | ||
|
|
fb818c3149 | ||
|
|
37398188f9 | ||
|
|
d1a0da3f8d | ||
|
|
57c8c6dbc6 | ||
|
|
bbebba6481 | ||
|
|
f0a49fefa4 | ||
|
|
48f3bf9ea7 | ||
|
|
b7a7eebc78 | ||
|
|
2e76e44a5a | ||
|
|
718ce9ea11 | ||
|
|
a79be1e3ef | ||
|
|
0a709acafe | ||
|
|
29efd77eaf | ||
|
|
2d6ac8023e | ||
|
|
2f42f515b0 | ||
|
|
f304f0832b | ||
|
|
801f3a578d | ||
|
|
0a353eeb37 | ||
|
|
e3033173d7 | ||
|
|
1adc2ff930 | ||
|
|
fc40580dce | ||
|
|
5001adf221 |
@@ -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
|
||||
}
|
||||
}
|
||||
1
.github/workflows/master.yml
vendored
1
.github/workflows/master.yml
vendored
@@ -19,6 +19,7 @@ jobs:
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
export DETECT_CHROMEDRIVER_VERSION=true
|
||||
npm install
|
||||
npm run setheapsize
|
||||
|
||||
|
||||
1
.github/workflows/pull_requests.yml
vendored
1
.github/workflows/pull_requests.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
export DETECT_CHROMEDRIVER_VERSION=true
|
||||
npm install
|
||||
npm run setheapsize
|
||||
|
||||
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -13,6 +13,13 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
## 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]
|
||||
@@ -433,6 +440,8 @@ All major and minor version changes will be documented in this file. Details of
|
||||
## [4.0.0] - 2016-11-28
|
||||
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
||||
|
||||
[10.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
|
||||
@@ -619,6 +628,8 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[@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
|
||||
@@ -630,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
|
||||
[760eff4]: https://github.com/gchq/CyberChef/commit/760eff49b5307aaa3104c5e5b437ffe62299acd1
|
||||
[65ffd8d]: https://github.com/gchq/CyberChef/commit/65ffd8d65d88eb369f6f61a5d1d0f807179bffb7
|
||||
[0a353ee]: https://github.com/gchq/CyberChef/commit/0a353eeb378b9ca5d49e23c7dfc175ae07107b08
|
||||
|
||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||
|
||||
12
Gruntfile.js
12
Gruntfile.js
@@ -431,6 +431,18 @@ module.exports = function (grunt) {
|
||||
}
|
||||
},
|
||||
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"
|
||||
}
|
||||
},
|
||||
];
|
||||
4234
package-lock.json
generated
4234
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",
|
||||
"version": "10.17.1",
|
||||
"version": "10.19.4",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@@ -39,29 +39,31 @@
|
||||
"node >= 16"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.9",
|
||||
"@babel/eslint-parser": "^7.23.10",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.23.3",
|
||||
"@babel/plugin-transform-runtime": "^7.23.9",
|
||||
"@babel/preset-env": "^7.23.9",
|
||||
"@babel/runtime": "^7.23.9",
|
||||
"@codemirror/commands": "^6.3.3",
|
||||
"@codemirror/language": "^6.10.1",
|
||||
"@codemirror/search": "^6.5.5",
|
||||
"@codemirror/state": "^6.4.0",
|
||||
"@codemirror/view": "^6.23.1",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/eslint-parser": "^7.24.7",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.24.7",
|
||||
"@babel/plugin-transform-runtime": "^7.24.7",
|
||||
"@babel/preset-env": "^7.24.7",
|
||||
"@babel/runtime": "^7.24.7",
|
||||
"@codemirror/commands": "^6.6.0",
|
||||
"@codemirror/language": "^6.10.2",
|
||||
"@codemirror/search": "^6.5.6",
|
||||
"@codemirror/state": "^6.4.1",
|
||||
"@codemirror/view": "^6.28.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"base64-loader": "^1.0.0",
|
||||
"chromedriver": "^122.0.0",
|
||||
"chromedriver": "^130.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
"colors": "^1.4.0",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"core-js": "^3.35.1",
|
||||
"css-loader": "6.10.0",
|
||||
"eslint": "^8.56.0",
|
||||
"core-js": "^3.37.1",
|
||||
"css-loader": "7.1.2",
|
||||
"eslint": "^9.4.0",
|
||||
"eslint-plugin-jsdoc": "^48.2.9",
|
||||
"globals": "^15.4.0",
|
||||
"grunt": "^1.6.1",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-concurrent": "^3.0.0",
|
||||
@@ -69,25 +71,25 @@
|
||||
"grunt-contrib-connect": "^4.0.0",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"grunt-eslint": "^24.3.0",
|
||||
"grunt-eslint": "^25.0.0",
|
||||
"grunt-exec": "~3.0.0",
|
||||
"grunt-webpack": "^6.0.0",
|
||||
"grunt-zip": "^1.0.0",
|
||||
"html-webpack-plugin": "^5.6.0",
|
||||
"imports-loader": "^5.0.0",
|
||||
"mini-css-extract-plugin": "2.8.0",
|
||||
"modify-source-webpack-plugin": "^3.0.0",
|
||||
"nightwatch": "^3.4.0",
|
||||
"postcss": "^8.4.33",
|
||||
"mini-css-extract-plugin": "2.9.0",
|
||||
"modify-source-webpack-plugin": "^4.1.0",
|
||||
"nightwatch": "^3.6.3",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-css-variables": "^0.19.0",
|
||||
"postcss-import": "^16.0.0",
|
||||
"postcss-loader": "^8.1.0",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"prompt": "^1.3.0",
|
||||
"sitemap": "^7.1.1",
|
||||
"terser": "^5.27.0",
|
||||
"webpack": "^5.90.1",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"sitemap": "^8.0.0",
|
||||
"terser": "^5.31.1",
|
||||
"webpack": "^5.91.0",
|
||||
"webpack-bundle-analyzer": "^4.10.2",
|
||||
"webpack-dev-server": "5.0.4",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
@@ -96,6 +98,7 @@
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@blu3r4y/lzma": "^2.3.3",
|
||||
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
|
||||
"@xmldom/xmldom": "^0.8.10",
|
||||
"argon2-browser": "^1.18.0",
|
||||
"arrive": "^2.4.1",
|
||||
"avsc": "^5.7.7",
|
||||
@@ -115,26 +118,26 @@
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"ctph.js": "0.0.5",
|
||||
"d3": "7.8.5",
|
||||
"d3": "7.9.0",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"diff": "^5.1.0",
|
||||
"diff": "^5.2.0",
|
||||
"es6-promisify": "^7.0.0",
|
||||
"escodegen": "^2.1.0",
|
||||
"esprima": "^4.0.1",
|
||||
"exif-parser": "^0.1.12",
|
||||
"ieee754": "^1.1.13",
|
||||
"fernet": "^0.3.2",
|
||||
"fernet": "^0.4.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"flat": "^6.0.1",
|
||||
"geodesy": "1.1.3",
|
||||
"highlight.js": "^11.9.0",
|
||||
"jimp": "^0.16.13",
|
||||
"ieee754": "^1.2.1",
|
||||
"jimp": "^0.22.12",
|
||||
"jquery": "3.7.1",
|
||||
"js-crc": "^0.2.0",
|
||||
"js-sha3": "^0.9.3",
|
||||
"jsesc": "^3.0.2",
|
||||
"json5": "^2.2.3",
|
||||
"jsonpath-plus": "^8.0.0",
|
||||
"jsonpath-plus": "^9.0.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"jsqr": "^1.4.0",
|
||||
"jsrsasign": "^11.1.0",
|
||||
@@ -146,9 +149,9 @@
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"lz-string": "^1.5.0",
|
||||
"lz4js": "^0.2.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.44",
|
||||
"moment-timezone": "^0.5.45",
|
||||
"ngeohash": "^0.6.3",
|
||||
"node-forge": "^1.3.1",
|
||||
"node-md6": "^0.1.0",
|
||||
@@ -160,9 +163,9 @@
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^7.2.6",
|
||||
"protobufjs": "^7.3.1",
|
||||
"qr-image": "^3.2.0",
|
||||
"reflect-metadata": "^0.2.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rison": "^0.1.1",
|
||||
"scryptsy": "^2.1.0",
|
||||
"snackbarjs": "^1.1.0",
|
||||
@@ -170,12 +173,11 @@
|
||||
"split.js": "^1.6.5",
|
||||
"ssdeep.js": "0.0.3",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"tesseract.js": "5.0.4",
|
||||
"ua-parser-js": "^1.0.37",
|
||||
"tesseract.js": "5.1.0",
|
||||
"ua-parser-js": "^1.0.38",
|
||||
"unorm": "^1.6.0",
|
||||
"utf8": "^3.0.0",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"@xmldom/xmldom": "^0.8.0",
|
||||
"xpath": "0.0.34",
|
||||
"xregexp": "^5.1.1",
|
||||
"zlibjs": "^0.3.1"
|
||||
@@ -190,7 +192,7 @@
|
||||
"testui": "npx grunt testui",
|
||||
"testuidev": "npx nightwatch --env=dev",
|
||||
"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",
|
||||
"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`)'",
|
||||
|
||||
@@ -117,6 +117,8 @@
|
||||
"XOR Brute Force",
|
||||
"Vigenère Encode",
|
||||
"Vigenère Decode",
|
||||
"XXTEA Encrypt",
|
||||
"XXTEA Decrypt",
|
||||
"To Morse Code",
|
||||
"From Morse Code",
|
||||
"Bacon Cipher Encode",
|
||||
@@ -155,14 +157,14 @@
|
||||
"Typex",
|
||||
"Lorenz",
|
||||
"Colossus",
|
||||
"SIGABA",
|
||||
"XXTEA"
|
||||
"SIGABA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Public Key",
|
||||
"ops": [
|
||||
"Parse X.509 certificate",
|
||||
"Parse X.509 CRL",
|
||||
"Parse ASN.1 hex string",
|
||||
"PEM to Hex",
|
||||
"Hex to PEM",
|
||||
@@ -234,6 +236,7 @@
|
||||
"Parse IPv6 address",
|
||||
"Parse IPv4 header",
|
||||
"Parse TCP",
|
||||
"Parse TLS record",
|
||||
"Parse UDP",
|
||||
"Parse SSH Host Key",
|
||||
"Parse URI",
|
||||
|
||||
@@ -30,12 +30,12 @@ fs.readdirSync(path.join(dir, "../operations")).forEach(file => {
|
||||
|
||||
// Construct index file
|
||||
let code = `/**
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
* THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright ${new Date().getUTCFullYear()}
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
`;
|
||||
|
||||
opObjs.forEach(obj => {
|
||||
|
||||
@@ -44,7 +44,7 @@ export function toJA4(bytes) {
|
||||
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;
|
||||
let version = tlsr.handshake.value.helloVersion.value;
|
||||
for (const ext of tlsr.handshake.value.extensions.value) {
|
||||
if (ext.type.value === "supported_versions") {
|
||||
version = parseHighestSupportedVersion(ext.value.data);
|
||||
@@ -189,7 +189,7 @@ export function toJA4S(bytes) {
|
||||
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;
|
||||
let version = tlsr.handshake.value.helloVersion.value;
|
||||
for (const ext of tlsr.handshake.value.extensions.value) {
|
||||
if (ext.type.value === "supported_versions") {
|
||||
version = parseHighestSupportedVersion(ext.value.data);
|
||||
|
||||
@@ -26,6 +26,9 @@ export function objToTable(obj, nested=false) {
|
||||
</tr>`;
|
||||
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === "function")
|
||||
continue;
|
||||
|
||||
html += `<tr><td style='word-wrap: break-word'>${key}</td>`;
|
||||
if (typeof obj[key] === "object")
|
||||
html += `<td style='padding: 0'>${objToTable(obj[key], true)}</td>`;
|
||||
|
||||
@@ -10,7 +10,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import jsQR from "jsqr";
|
||||
import qr from "qr-image";
|
||||
import Utils from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Parses a QR code image from an image
|
||||
@@ -22,7 +22,7 @@ import jimp from "jimp";
|
||||
export async function parseQrCode(input, normalise) {
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error opening image. (${err})`);
|
||||
}
|
||||
@@ -33,8 +33,8 @@ export async function parseQrCode(input, normalise) {
|
||||
image.background(0xFFFFFFFF);
|
||||
image.normalize();
|
||||
image.greyscale();
|
||||
image = await image.getBufferAsync(jimp.MIME_JPEG);
|
||||
image = await jimp.read(image);
|
||||
image = await image.getBufferAsync(Jimp.MIME_JPEG);
|
||||
image = await Jimp.read(image);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error normalising image. (${err})`);
|
||||
|
||||
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 { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Add Text To Image operation
|
||||
@@ -127,7 +127,7 @@ class AddTextToImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -163,7 +163,7 @@ class AddTextToImage extends Operation {
|
||||
const font = fontsMap[fontFace];
|
||||
|
||||
// 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) {
|
||||
if (page.bitmap) {
|
||||
@@ -190,7 +190,7 @@ class AddTextToImage extends Operation {
|
||||
});
|
||||
|
||||
// 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);
|
||||
|
||||
// Scale the rendered text image to the correct size
|
||||
@@ -198,9 +198,9 @@ class AddTextToImage extends Operation {
|
||||
if (size !== 1) {
|
||||
// Use bicubic for decreasing size
|
||||
if (size > 1) {
|
||||
textImage.scale(scaleFactor, jimp.RESIZE_BICUBIC);
|
||||
textImage.scale(scaleFactor, Jimp.RESIZE_BICUBIC);
|
||||
} else {
|
||||
textImage.scale(scaleFactor, jimp.RESIZE_BILINEAR);
|
||||
textImage.scale(scaleFactor, Jimp.RESIZE_BILINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,9 +234,9 @@ class AddTextToImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Blur Image operation
|
||||
@@ -59,7 +59,7 @@ class BlurImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -79,9 +79,9 @@ class BlurImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Contain Image operation
|
||||
@@ -91,20 +91,20 @@ class ContainImage extends Operation {
|
||||
const [width, height, hAlign, vAlign, alg, opaqueBg] = args;
|
||||
|
||||
const resizeMap = {
|
||||
"Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR,
|
||||
"Bilinear": jimp.RESIZE_BILINEAR,
|
||||
"Bicubic": jimp.RESIZE_BICUBIC,
|
||||
"Hermite": jimp.RESIZE_HERMITE,
|
||||
"Bezier": jimp.RESIZE_BEZIER
|
||||
"Nearest Neighbour": Jimp.RESIZE_NEAREST_NEIGHBOR,
|
||||
"Bilinear": Jimp.RESIZE_BILINEAR,
|
||||
"Bicubic": Jimp.RESIZE_BICUBIC,
|
||||
"Hermite": Jimp.RESIZE_HERMITE,
|
||||
"Bezier": Jimp.RESIZE_BEZIER
|
||||
};
|
||||
|
||||
const alignMap = {
|
||||
"Left": jimp.HORIZONTAL_ALIGN_LEFT,
|
||||
"Center": jimp.HORIZONTAL_ALIGN_CENTER,
|
||||
"Right": jimp.HORIZONTAL_ALIGN_RIGHT,
|
||||
"Top": jimp.VERTICAL_ALIGN_TOP,
|
||||
"Middle": jimp.VERTICAL_ALIGN_MIDDLE,
|
||||
"Bottom": jimp.VERTICAL_ALIGN_BOTTOM
|
||||
"Left": Jimp.HORIZONTAL_ALIGN_LEFT,
|
||||
"Center": Jimp.HORIZONTAL_ALIGN_CENTER,
|
||||
"Right": Jimp.HORIZONTAL_ALIGN_RIGHT,
|
||||
"Top": Jimp.VERTICAL_ALIGN_TOP,
|
||||
"Middle": Jimp.VERTICAL_ALIGN_MIDDLE,
|
||||
"Bottom": Jimp.VERTICAL_ALIGN_BOTTOM
|
||||
};
|
||||
|
||||
if (!isImage(input)) {
|
||||
@@ -113,7 +113,7 @@ class ContainImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (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]);
|
||||
|
||||
if (opaqueBg) {
|
||||
const newImage = await jimp.read(width, height, 0x000000FF);
|
||||
const newImage = await Jimp.read(width, height, 0x000000FF);
|
||||
newImage.blit(image, 0, 0);
|
||||
image = newImage;
|
||||
}
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Convert Image Format operation
|
||||
@@ -76,19 +76,19 @@ class ConvertImageFormat extends Operation {
|
||||
async run(input, args) {
|
||||
const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args;
|
||||
const formatMap = {
|
||||
"JPEG": jimp.MIME_JPEG,
|
||||
"PNG": jimp.MIME_PNG,
|
||||
"BMP": jimp.MIME_BMP,
|
||||
"TIFF": jimp.MIME_TIFF
|
||||
"JPEG": Jimp.MIME_JPEG,
|
||||
"PNG": Jimp.MIME_PNG,
|
||||
"BMP": Jimp.MIME_BMP,
|
||||
"TIFF": Jimp.MIME_TIFF
|
||||
};
|
||||
|
||||
const pngFilterMap = {
|
||||
"Auto": jimp.PNG_FILTER_AUTO,
|
||||
"None": jimp.PNG_FILTER_NONE,
|
||||
"Sub": jimp.PNG_FILTER_SUB,
|
||||
"Up": jimp.PNG_FILTER_UP,
|
||||
"Average": jimp.PNG_FILTER_AVERAGE,
|
||||
"Paeth": jimp.PNG_FILTER_PATH
|
||||
"Auto": Jimp.PNG_FILTER_AUTO,
|
||||
"None": Jimp.PNG_FILTER_NONE,
|
||||
"Sub": Jimp.PNG_FILTER_SUB,
|
||||
"Up": Jimp.PNG_FILTER_UP,
|
||||
"Average": Jimp.PNG_FILTER_AVERAGE,
|
||||
"Paeth": Jimp.PNG_FILTER_PATH
|
||||
};
|
||||
|
||||
const mime = formatMap[format];
|
||||
@@ -98,7 +98,7 @@ class ConvertImageFormat extends Operation {
|
||||
}
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (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 { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Cover Image operation
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Crop Image operation
|
||||
@@ -99,7 +99,7 @@ class CropImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -119,9 +119,9 @@ class CropImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Image Dither operation
|
||||
@@ -44,7 +44,7 @@ class DitherImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -55,9 +55,9 @@ class DitherImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { fromBinary } from "../lib/Binary.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Extract LSB operation
|
||||
@@ -73,7 +73,7 @@ class ExtractLSB extends Operation {
|
||||
const bit = 7 - args.pop(),
|
||||
pixelOrder = args.pop(),
|
||||
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,
|
||||
height = parsedImage.bitmap.height,
|
||||
rgba = parsedImage.bitmap.data;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.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";
|
||||
|
||||
@@ -52,7 +52,7 @@ class ExtractRGBA extends Operation {
|
||||
|
||||
const delimiter = args[0],
|
||||
includeAlpha = args[1],
|
||||
parsedImage = await jimp.read(input);
|
||||
parsedImage = await Jimp.read(input);
|
||||
|
||||
let bitmap = parsedImage.bitmap.data;
|
||||
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 { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Flip Image operation
|
||||
@@ -51,7 +51,7 @@ class FlipImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -69,9 +69,9 @@ class FlipImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -55,22 +55,19 @@ class GOSTDecrypt extends Operation {
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
name: "GOST 28147 (1989)",
|
||||
on: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Magma, 2015)",
|
||||
off: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
off: [5]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
@@ -100,14 +97,30 @@ class GOSTDecrypt extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
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 iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
let blockLength, versionNum;
|
||||
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 algorithm = {
|
||||
|
||||
@@ -55,22 +55,19 @@ class GOSTEncrypt extends Operation {
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
name: "GOST 28147 (1989)",
|
||||
on: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Magma, 2015)",
|
||||
off: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
off: [5]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
@@ -100,14 +97,30 @@ class GOSTEncrypt extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
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 iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
let blockLength, versionNum;
|
||||
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 algorithm = {
|
||||
|
||||
@@ -55,22 +55,19 @@ class GOSTKeyUnwrap extends Operation {
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
name: "GOST 28147 (1989)",
|
||||
on: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Magma, 2015)",
|
||||
off: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
off: [5]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
@@ -90,14 +87,30 @@ class GOSTKeyUnwrap extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
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 ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
let blockLength, versionNum;
|
||||
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 algorithm = {
|
||||
|
||||
@@ -55,22 +55,19 @@ class GOSTKeyWrap extends Operation {
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
name: "GOST 28147 (1989)",
|
||||
on: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Magma, 2015)",
|
||||
off: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
off: [5]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
@@ -90,14 +87,30 @@ class GOSTKeyWrap extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
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 ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
let blockLength, versionNum;
|
||||
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 algorithm = {
|
||||
|
||||
@@ -55,22 +55,19 @@ class GOSTSign extends Operation {
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
name: "GOST 28147 (1989)",
|
||||
on: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Magma, 2015)",
|
||||
off: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
off: [5]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
@@ -93,14 +90,30 @@ class GOSTSign extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
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 iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
let blockLength, versionNum;
|
||||
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 algorithm = {
|
||||
|
||||
@@ -56,22 +56,19 @@ class GOSTVerify extends Operation {
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "GOST 28147 (Magma, 1989)",
|
||||
off: [5],
|
||||
on: [6]
|
||||
name: "GOST 28147 (1989)",
|
||||
on: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Magma, 2015)",
|
||||
off: [5]
|
||||
},
|
||||
{
|
||||
name: "GOST R 34.12 (Kuznyechik, 2015)",
|
||||
on: [5],
|
||||
off: [6]
|
||||
off: [5]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Block length",
|
||||
type: "option",
|
||||
value: ["64", "128"]
|
||||
},
|
||||
{
|
||||
name: "sBox",
|
||||
type: "option",
|
||||
@@ -86,15 +83,31 @@ class GOSTVerify extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
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 iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
|
||||
const mac = toHexFast(Utils.convertToByteArray(macObj.string, macObj.option));
|
||||
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
|
||||
|
||||
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
|
||||
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
|
||||
let blockLength, versionNum;
|
||||
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 algorithm = {
|
||||
|
||||
@@ -10,7 +10,7 @@ import Utils from "../Utils.mjs";
|
||||
import {isImage} from "../lib/FileType.mjs";
|
||||
import {toBase64} from "../lib/Base64.mjs";
|
||||
import {isWorkerEnvironment} from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Generate Image operation
|
||||
@@ -81,7 +81,7 @@ class GenerateImage extends Operation {
|
||||
}
|
||||
|
||||
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())
|
||||
self.sendStatusMessage("Generating image from data...");
|
||||
@@ -95,7 +95,7 @@ class GenerateImage extends Operation {
|
||||
const y = Math.floor(index / width);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ class GenerateImage extends Operation {
|
||||
}
|
||||
|
||||
try {
|
||||
const pixel = jimp.rgbaToInt(red, green, blue, alpha);
|
||||
const pixel = Jimp.rgbaToInt(red, green, blue, alpha);
|
||||
image.setPixelColor(pixel, x, y);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error while generating image from pixel values. (${err})`);
|
||||
@@ -151,11 +151,11 @@ class GenerateImage extends Operation {
|
||||
if (isWorkerEnvironment())
|
||||
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 {
|
||||
const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
const imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
return imageBuffer.buffer;
|
||||
} catch (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 { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Image Brightness / Contrast operation
|
||||
@@ -60,7 +60,7 @@ class ImageBrightnessContrast extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -78,9 +78,9 @@ class ImageBrightnessContrast extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Image Filter operation
|
||||
@@ -54,7 +54,7 @@ class ImageFilter extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -69,9 +69,9 @@ class ImageFilter extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Image Hue/Saturation/Lightness operation
|
||||
@@ -68,7 +68,7 @@ class ImageHueSaturationLightness extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -106,9 +106,9 @@ class ImageHueSaturationLightness extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Image Opacity operation
|
||||
@@ -53,7 +53,7 @@ class ImageOpacity extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -64,9 +64,9 @@ class ImageOpacity extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Invert Image operation
|
||||
@@ -44,7 +44,7 @@ class InvertImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -55,9 +55,9 @@ class InvertImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -35,12 +35,6 @@ class JPathExpression extends Operation {
|
||||
name: "Result delimiter",
|
||||
type: "binaryShortString",
|
||||
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}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [query, delimiter, preventEval] = args;
|
||||
const [query, delimiter] = args;
|
||||
let results, jsonObj;
|
||||
|
||||
try {
|
||||
@@ -63,8 +57,7 @@ class JPathExpression extends Operation {
|
||||
try {
|
||||
results = JSONPath({
|
||||
path: query,
|
||||
json: jsonObj,
|
||||
preventEval: preventEval
|
||||
json: jsonObj
|
||||
});
|
||||
} catch (err) {
|
||||
throw new OperationError(`Invalid JPath expression: ${err.message}`);
|
||||
|
||||
@@ -36,6 +36,11 @@ class JWTSign extends Operation {
|
||||
name: "Signing algorithm",
|
||||
type: "option",
|
||||
value: JWT_ALGORITHMS
|
||||
},
|
||||
{
|
||||
name: "Header",
|
||||
type: "text",
|
||||
value: "{}"
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -46,11 +51,12 @@ class JWTSign extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [key, algorithm] = args;
|
||||
const [key, algorithm, header] = args;
|
||||
|
||||
try {
|
||||
return jwt.sign(input, key, {
|
||||
algorithm: algorithm === "None" ? "none" : algorithm
|
||||
algorithm: algorithm === "None" ? "none" : algorithm,
|
||||
header: JSON.parse(header || "{}")
|
||||
});
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error: Have you entered the key correctly? The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.
|
||||
|
||||
@@ -22,7 +22,7 @@ class JWTVerify extends Operation {
|
||||
|
||||
this.name = "JWT Verify";
|
||||
this.module = "Crypto";
|
||||
this.description = "Verifies that a JSON Web Token is valid and has been signed with the provided secret / private key.<br><br>The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.";
|
||||
this.description = "Verifies that a JSON Web Token is valid and has been signed with the provided secret / private key.<br><br>The key should be either the secret for HMAC algorithms or the PEM-encoded public key for RSA and ECDSA.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/JSON_Web_Token";
|
||||
this.inputType = "string";
|
||||
this.outputType = "JSON";
|
||||
|
||||
@@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Normalise Image operation
|
||||
@@ -43,7 +43,7 @@ class NormaliseImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error opening image file. (${err})`);
|
||||
}
|
||||
@@ -53,9 +53,9 @@ class NormaliseImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -12,9 +12,10 @@ import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
|
||||
import process from "process";
|
||||
import { createWorker } from "tesseract.js";
|
||||
|
||||
const OEM_MODES = ["Tesseract only", "LSTM only", "Tesseract/LSTM Combined"];
|
||||
|
||||
/**
|
||||
* Optical Character Recognition operation
|
||||
*/
|
||||
@@ -37,6 +38,12 @@ class OpticalCharacterRecognition extends Operation {
|
||||
name: "Show confidence",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "OCR Engine Mode",
|
||||
type: "option",
|
||||
value: OEM_MODES,
|
||||
defaultIndex: 1
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -47,7 +54,7 @@ class OpticalCharacterRecognition extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [showConfidence] = args;
|
||||
const [showConfidence, oemChoice] = args;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
const assetDir = isWorkerEnvironment() ? `${self.docURL}/assets/` : `${process.cwd()}/src/core/vendor/`;
|
||||
const assetDir = `${self.docURL}/assets/`;
|
||||
const oem = OEM_MODES.indexOf(oemChoice);
|
||||
|
||||
try {
|
||||
self.sendStatusMessage("Spinning up Tesseract worker...");
|
||||
const image = `data:${type};base64,${toBase64(input)}`;
|
||||
const worker = createWorker({
|
||||
const worker = await createWorker("eng", oem, {
|
||||
workerPath: `${assetDir}tesseract/worker.min.js`,
|
||||
langPath: `${assetDir}tesseract/lang-data`,
|
||||
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...");
|
||||
const result = await worker.recognize(image);
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import r from "jsrsasign";
|
||||
import Operation from "../Operation.mjs";
|
||||
import forge from "node-forge";
|
||||
import { formatDnObj } from "../lib/PublicKey.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
@@ -30,16 +31,6 @@ class ParseCSR extends Operation {
|
||||
"name": "Input format",
|
||||
"type": "option",
|
||||
"value": ["PEM"]
|
||||
},
|
||||
{
|
||||
"name": "Key type",
|
||||
"type": "option",
|
||||
"value": ["RSA"]
|
||||
},
|
||||
{
|
||||
"name": "Strict ASN.1 value lengths",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
@@ -61,73 +52,71 @@ class ParseCSR extends Operation {
|
||||
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 `Version: ${1 + csr.version} (0x${Utils.hex(csr.version)})
|
||||
Subject${formatSubject(csr.subject)}
|
||||
Subject Alternative Names${formatSubjectAlternativeNames(csr)}
|
||||
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)}`;
|
||||
return `Subject\n${formatDnObj(csrParam.subject, 2)}
|
||||
Public Key${formatSubjectPublicKey(csrParam.sbjpubkey)}
|
||||
Signature${formatSignature(csrParam.sigalg, csrParam.sighex)}
|
||||
Requested Extensions${formatRequestedExtensions(csrParam)}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Subject of the request as a multi-line string
|
||||
* @param {*} subject CSR Subject
|
||||
* @returns Multi-line string describing Subject
|
||||
* Format signature of a CSR
|
||||
* @param {*} sigAlg string
|
||||
* @param {*} sigHex string
|
||||
* @returns Multi-line string describing CSR Signature
|
||||
*/
|
||||
function formatSubject(subject) {
|
||||
let out = "\n";
|
||||
function formatSignature(sigAlg, sigHex) {
|
||||
let out = `\n`;
|
||||
|
||||
for (const attribute of subject.attributes) {
|
||||
out += ` ${attribute.shortName} = ${attribute.value}\n`;
|
||||
out += ` Algorithm: ${sigAlg}\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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format Subject Alternative Names from the name `subjectAltName` extension
|
||||
* @param {*} extension CSR object
|
||||
* @returns Multi-line string describing Subject Alternative Names
|
||||
* Format Subject Public Key from PEM encoded public key string
|
||||
* @param {*} publicKeyPEM string
|
||||
* @returns Multi-line string describing Subject Public Key Info
|
||||
*/
|
||||
function formatSubjectAlternativeNames(csr) {
|
||||
function formatSubjectPublicKey(publicKeyPEM) {
|
||||
let out = "\n";
|
||||
|
||||
for (const attribute of csr.attributes) {
|
||||
for (const extension of attribute.extensions) {
|
||||
if (extension.name === "subjectAltName") {
|
||||
const names = [];
|
||||
for (const altName of extension.altNames) {
|
||||
switch (altName.type) {
|
||||
case 1:
|
||||
names.push(`EMAIL: ${altName.value}`);
|
||||
break;
|
||||
case 2:
|
||||
names.push(`DNS: ${altName.value}`);
|
||||
break;
|
||||
case 6:
|
||||
names.push(`URI: ${altName.value}`);
|
||||
break;
|
||||
case 7:
|
||||
names.push(`IP: ${altName.ip}`);
|
||||
break;
|
||||
default:
|
||||
names.push(`(unable to format type ${altName.type} name)\n`);
|
||||
}
|
||||
}
|
||||
out += indent(2, names);
|
||||
}
|
||||
}
|
||||
const publicKey = r.KEYUTIL.getKey(publicKeyPEM);
|
||||
if (publicKey instanceof r.RSAKey) {
|
||||
out += ` Algorithm: RSA
|
||||
Length: ${publicKey.n.bitLength()} bits
|
||||
Modulus: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.n))}
|
||||
Exponent: ${publicKey.e} (0x${Utils.hex(publicKey.e)})\n`;
|
||||
} else if (publicKey instanceof r.KJUR.crypto.ECDSA) {
|
||||
out += ` Algorithm: ECDSA
|
||||
Length: ${publicKey.ecparams.keylen} bits
|
||||
Pub: ${formatHexOntoMultiLine(publicKey.pubKeyHex)}
|
||||
ASN1 OID: ${r.KJUR.crypto.ECDSA.getName(publicKey.getShortNISTPCurveName())}
|
||||
NIST CURVE: ${publicKey.getShortNISTPCurveName()}\n`;
|
||||
} else if (publicKey instanceof r.KJUR.crypto.DSA) {
|
||||
out += ` Algorithm: DSA
|
||||
Length: ${publicKey.p.toString(16).length * 4} bits
|
||||
Pub: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.y))}
|
||||
P: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.p))}
|
||||
Q: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.q))}
|
||||
G: ${formatHexOntoMultiLine(absBigIntToHex(publicKey.g))}\n`;
|
||||
} else {
|
||||
out += `unsupported public key algorithm\n`;
|
||||
}
|
||||
|
||||
return chop(out);
|
||||
@@ -135,45 +124,105 @@ function formatSubjectAlternativeNames(csr) {
|
||||
|
||||
/**
|
||||
* Format known extensions of a CSR
|
||||
* @param {*} csr CSR object
|
||||
* @returns Multi-line string describing attributes
|
||||
* @param {*} csrParam object
|
||||
* @returns Multi-line string describing CSR Requested Extensions
|
||||
*/
|
||||
function formatExtensions(csr) {
|
||||
let out = "\n";
|
||||
function formatRequestedExtensions(csrParam) {
|
||||
const formattedExtensions = new Array(4).fill("");
|
||||
|
||||
for (const attribute of csr.attributes) {
|
||||
for (const extension of attribute.extensions) {
|
||||
// formatted separately
|
||||
if (extension.name === "subjectAltName") {
|
||||
continue;
|
||||
}
|
||||
out += ` ${extension.name}${(extension.critical ? " CRITICAL" : "")}:\n`;
|
||||
if (Object.hasOwn(csrParam, "extreq")) {
|
||||
for (const extension of csrParam.extreq) {
|
||||
let parts = [];
|
||||
switch (extension.name) {
|
||||
switch (extension.extname) {
|
||||
case "basicConstraints" :
|
||||
parts = describeBasicConstraints(extension);
|
||||
formattedExtensions[0] = ` Basic Constraints:${formatExtensionCriticalTag(extension)}\n${indent(4, parts)}`;
|
||||
break;
|
||||
case "keyUsage" :
|
||||
parts = describeKeyUsage(extension);
|
||||
formattedExtensions[1] = ` Key Usage:${formatExtensionCriticalTag(extension)}\n${indent(4, parts)}`;
|
||||
break;
|
||||
case "extKeyUsage" :
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @returns Hex string as a multi-line hex string
|
||||
* @returns String as a multi-line string
|
||||
*/
|
||||
function formatMultiLine(longStr) {
|
||||
const lines = [];
|
||||
@@ -194,8 +243,8 @@ function formatMultiLine(longStr) {
|
||||
function describeBasicConstraints(extension) {
|
||||
const constraints = [];
|
||||
|
||||
constraints.push(`CA = ${extension.cA}`);
|
||||
if (extension.pathLenConstraint !== undefined) constraints.push(`PathLenConstraint = ${extension.pathLenConstraint}`);
|
||||
constraints.push(`CA = ${Object.hasOwn(extension, "cA") && extension.cA ? "true" : "false"}`);
|
||||
if (Object.hasOwn(extension, "pathLen")) constraints.push(`PathLenConstraint = ${extension.pathLen}`);
|
||||
|
||||
return constraints;
|
||||
}
|
||||
@@ -209,15 +258,27 @@ function describeBasicConstraints(extension) {
|
||||
function describeKeyUsage(extension) {
|
||||
const usage = [];
|
||||
|
||||
if (extension.digitalSignature) usage.push("Digital signature");
|
||||
if (extension.nonRepudiation) usage.push("Non-repudiation");
|
||||
if (extension.keyEncipherment) usage.push("Key encipherment");
|
||||
if (extension.dataEncipherment) usage.push("Data encipherment");
|
||||
if (extension.keyAgreement) usage.push("Key agreement");
|
||||
if (extension.keyCertSign) usage.push("Key certificate signing");
|
||||
if (extension.cRLSign) usage.push("CRL signing");
|
||||
if (extension.encipherOnly) usage.push("Encipher only");
|
||||
if (extension.decipherOnly) usage.push("Decipher only");
|
||||
const kuIdentifierToName = {
|
||||
digitalSignature: "Digital Signature",
|
||||
nonRepudiation: "Non-repudiation",
|
||||
keyEncipherment: "Key encipherment",
|
||||
dataEncipherment: "Data encipherment",
|
||||
keyAgreement: "Key agreement",
|
||||
keyCertSign: "Key certificate signing",
|
||||
cRLSign: "CRL signing",
|
||||
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)");
|
||||
|
||||
@@ -233,23 +294,79 @@ function describeKeyUsage(extension) {
|
||||
function describeExtendedKeyUsage(extension) {
|
||||
const usage = [];
|
||||
|
||||
if (extension.serverAuth) usage.push("TLS Web Server Authentication");
|
||||
if (extension.clientAuth) usage.push("TLS Web Client Authentication");
|
||||
if (extension.codeSigning) usage.push("Code signing");
|
||||
if (extension.emailProtection) usage.push("E-mail Protection (S/MIME)");
|
||||
if (extension.timeStamping) usage.push("Trusted Timestamping");
|
||||
if (extension.msCodeInd) usage.push("Microsoft Individual Code Signing");
|
||||
if (extension.msCodeCom) usage.push("Microsoft Commercial Code Signing");
|
||||
if (extension.msCTLSign) usage.push("Microsoft Trust List Signing");
|
||||
if (extension.msSGC) usage.push("Microsoft Server Gated Crypto");
|
||||
if (extension.msEFS) usage.push("Microsoft Encrypted File System");
|
||||
if (extension.nsSGC) usage.push("Netscape Server Gated Crypto");
|
||||
const ekuIdentifierToName = {
|
||||
"serverAuth": "TLS Web Server Authentication",
|
||||
"clientAuth": "TLS Web Client Authentication",
|
||||
"codeSigning": "Code signing",
|
||||
"emailProtection": "E-mail Protection (S/MIME)",
|
||||
"timeStamping": "Trusted Timestamping",
|
||||
"1.3.6.1.4.1.311.2.1.21": "Microsoft Individual Code Signing", // msCodeInd
|
||||
"1.3.6.1.4.1.311.2.1.22": "Microsoft Commercial Code Signing", // msCodeCom
|
||||
"1.3.6.1.4.1.311.10.3.1": "Microsoft Trust List Signing", // msCTLSign
|
||||
"1.3.6.1.4.1.311.10.3.3": "Microsoft Server Gated Crypto", // msSGC
|
||||
"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)");
|
||||
|
||||
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.
|
||||
* @param {*} n How many leading spaces
|
||||
|
||||
884
src/core/operations/ParseTLSRecord.mjs
Normal file
884
src/core/operations/ParseTLSRecord.mjs
Normal file
@@ -0,0 +1,884 @@
|
||||
/**
|
||||
* @author c65722 []
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import {toHexFast} from "../lib/Hex.mjs";
|
||||
import {objToTable} from "../lib/Protocol.mjs";
|
||||
import Stream from "../lib/Stream.mjs";
|
||||
|
||||
/**
|
||||
* Parse TLS record operation.
|
||||
*/
|
||||
class ParseTLSRecord extends Operation {
|
||||
|
||||
/**
|
||||
* ParseTLSRecord constructor.
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Parse TLS record";
|
||||
this.module = "Default";
|
||||
this.description = "Parses one or more TLS records";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Transport_Layer_Security";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "json";
|
||||
this.presentType = "html";
|
||||
this.args = [];
|
||||
this._handshakeParser = new HandshakeParser();
|
||||
this._contentTypes = new Map();
|
||||
|
||||
for (const key in ContentType) {
|
||||
this._contentTypes[ContentType[key]] = key.toString().toLocaleLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input - Stream, containing one or more raw TLS Records.
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} Array of Object representations of TLS Records contained within input.
|
||||
*/
|
||||
run(input, args) {
|
||||
const s = new Stream(new Uint8Array(input));
|
||||
|
||||
const output = [];
|
||||
|
||||
while (s.hasMore()) {
|
||||
const record = this._readRecord(s);
|
||||
if (record) {
|
||||
output.push(record);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a TLS Record from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw TLS Record.
|
||||
* @returns {Object} Object representation of TLS Record.
|
||||
*/
|
||||
_readRecord(input) {
|
||||
const RECORD_HEADER_LEN = 5;
|
||||
|
||||
if (input.position + RECORD_HEADER_LEN > input.length) {
|
||||
input.moveTo(input.length);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const type = input.readInt(1);
|
||||
const typeString = this._contentTypes[type] ?? type.toString();
|
||||
const version = "0x" + toHexFast(input.getBytes(2));
|
||||
const length = input.readInt(2);
|
||||
const content = input.getBytes(length);
|
||||
const truncated = content.length < length;
|
||||
|
||||
const recordHeader = new RecordHeader(typeString, version, length, truncated);
|
||||
|
||||
if (!content.length) {
|
||||
return {...recordHeader};
|
||||
}
|
||||
|
||||
if (type === ContentType.HANDSHAKE) {
|
||||
return this._handshakeParser.parse(new Stream(content), recordHeader);
|
||||
}
|
||||
|
||||
const record = {...recordHeader};
|
||||
record.value = "0x" + toHexFast(content);
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the parsed TLS Records in a tabular style.
|
||||
*
|
||||
* @param {Object[]} data - Array of Object representations of the TLS Records.
|
||||
* @returns {html} HTML representation of TLS Records contained within data.
|
||||
*/
|
||||
present(data) {
|
||||
return data.map(r => objToTable(r)).join("\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
export default ParseTLSRecord;
|
||||
|
||||
/**
|
||||
* Repesents the known values of type field of a TLS Record header.
|
||||
*/
|
||||
const ContentType = Object.freeze({
|
||||
CHANGE_CIPHER_SPEC: 20,
|
||||
ALERT: 21,
|
||||
HANDSHAKE: 22,
|
||||
APPLICATION_DATA: 23,
|
||||
});
|
||||
|
||||
/**
|
||||
* Represents a TLS Record header
|
||||
*/
|
||||
class RecordHeader {
|
||||
/**
|
||||
* RecordHeader cosntructor.
|
||||
*
|
||||
* @param {string} type - String representation of TLS Record type field.
|
||||
* @param {string} version - Hex representation of TLS Record version field.
|
||||
* @param {int} length - Length of TLS Record.
|
||||
* @param {bool} truncated - Is TLS Record truncated.
|
||||
*/
|
||||
constructor(type, version, length, truncated) {
|
||||
this.type = type;
|
||||
this.version = version;
|
||||
this.length = length;
|
||||
|
||||
if (truncated) {
|
||||
this.truncated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake messages.
|
||||
*/
|
||||
class HandshakeParser {
|
||||
|
||||
/**
|
||||
* HandshakeParser constructor.
|
||||
*/
|
||||
constructor() {
|
||||
this._clientHelloParser = new ClientHelloParser();
|
||||
this._serverHelloParser = new ServerHelloParser();
|
||||
this._newSessionTicketParser = new NewSessionTicketParser();
|
||||
this._certificateParser = new CertificateParser();
|
||||
this._certificateRequestParser = new CertificateRequestParser();
|
||||
this._certificateVerifyParser = new CertificateVerifyParser();
|
||||
this._handshakeTypes = new Map();
|
||||
|
||||
for (const key in HandshakeType) {
|
||||
this._handshakeTypes[HandshakeType[key]] = key.toString().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single TLS handshake message.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw Handshake message.
|
||||
* @param {RecordHeader} recordHeader - TLS Record header.
|
||||
* @returns {Object} Object representation of Handshake.
|
||||
*/
|
||||
parse(input, recordHeader) {
|
||||
const output = {...recordHeader};
|
||||
|
||||
if (!input.hasMore()) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const handshakeType = input.readInt(1);
|
||||
output.handshakeType = this._handshakeTypes[handshakeType] ?? handshakeType.toString();
|
||||
|
||||
if (input.position + 3 > input.length) {
|
||||
input.moveTo(input.length);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
const handshakeLength = input.readInt(3);
|
||||
|
||||
if (handshakeLength + 4 !== recordHeader.length) {
|
||||
input.moveTo(0);
|
||||
|
||||
output.handshakeType = this._handshakeTypes[HandshakeType.FINISHED];
|
||||
output.handshakeValue = "0x" + toHexFast(input.bytes);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
const content = input.getBytes(handshakeLength);
|
||||
if (!content.length) {
|
||||
return output;
|
||||
}
|
||||
|
||||
switch (handshakeType) {
|
||||
case HandshakeType.CLIENT_HELLO:
|
||||
return {...output, ...this._clientHelloParser.parse(new Stream(content))};
|
||||
case HandshakeType.SERVER_HELLO:
|
||||
return {...output, ...this._serverHelloParser.parse(new Stream(content))};
|
||||
case HandshakeType.NEW_SESSION_TICKET:
|
||||
return {...output, ...this._newSessionTicketParser.parse(new Stream(content))};
|
||||
case HandshakeType.CERTIFICATE:
|
||||
return {...output, ...this._certificateParser.parse(new Stream(content))};
|
||||
case HandshakeType.CERTIFICATE_REQUEST:
|
||||
return {...output, ...this._certificateRequestParser.parse(new Stream(content))};
|
||||
case HandshakeType.CERTIFICATE_VERIFY:
|
||||
return {...output, ...this._certificateVerifyParser.parse(new Stream(content))};
|
||||
default:
|
||||
output.handshakeValue = "0x" + toHexFast(content);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the known values of the msg_type field of a TLS Handshake message.
|
||||
*/
|
||||
const HandshakeType = Object.freeze({
|
||||
HELLO_REQUEST: 0,
|
||||
CLIENT_HELLO: 1,
|
||||
SERVER_HELLO: 2,
|
||||
NEW_SESSION_TICKET: 4,
|
||||
CERTIFICATE: 11,
|
||||
SERVER_KEY_EXCHANGE: 12,
|
||||
CERTIFICATE_REQUEST: 13,
|
||||
SERVER_HELLO_DONE: 14,
|
||||
CERTIFICATE_VERIFY: 15,
|
||||
CLIENT_KEY_EXCHANGE: 16,
|
||||
FINISHED: 20,
|
||||
});
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake ClientHello messages.
|
||||
*/
|
||||
class ClientHelloParser {
|
||||
|
||||
/**
|
||||
* ClientHelloParser constructor.
|
||||
*/
|
||||
constructor() {
|
||||
this._extensionsParser = new ExtensionsParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single TLS Handshake ClientHello message.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ClientHello message.
|
||||
* @returns {Object} Object representation of ClientHello.
|
||||
*/
|
||||
parse(input) {
|
||||
const output = {};
|
||||
|
||||
output.clientVersion = this._readClientVersion(input);
|
||||
output.random = this._readRandom(input);
|
||||
|
||||
const sessionID = this._readSessionID(input);
|
||||
if (sessionID) {
|
||||
output.sessionID = sessionID;
|
||||
}
|
||||
|
||||
output.cipherSuites = this._readCipherSuites(input);
|
||||
output.compressionMethods = this._readCompressionMethods(input);
|
||||
output.extensions = this._readExtensions(input);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the client_version field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ClientHello message, with position before client_version field.
|
||||
* @returns {string} Hex representation of client_version.
|
||||
*/
|
||||
_readClientVersion(input) {
|
||||
return readBytesAsHex(input, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the random field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ClientHello message, with position before random field.
|
||||
* @returns {string} Hex representation of random.
|
||||
*/
|
||||
_readRandom(input) {
|
||||
return readBytesAsHex(input, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the session_id field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ClientHello message, with position before session_id length field.
|
||||
* @returns {string} Hex representation of session_id, or empty string if session_id not present.
|
||||
*/
|
||||
_readSessionID(input) {
|
||||
return readSizePrefixedBytesAsHex(input, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the cipher_suites field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ClientHello message, with position before cipher_suites length field.
|
||||
* @returns {Object} Object represention of cipher_suites field.
|
||||
*/
|
||||
_readCipherSuites(input) {
|
||||
const output = {};
|
||||
|
||||
output.length = input.readInt(2);
|
||||
if (!output.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const cipherSuites = new Stream(input.getBytes(output.length));
|
||||
if (cipherSuites.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = [];
|
||||
|
||||
while (cipherSuites.hasMore()) {
|
||||
const cipherSuite = readBytesAsHex(cipherSuites, 2);
|
||||
if (cipherSuite) {
|
||||
output.values.push(cipherSuite);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the compression_methods field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ClientHello message, with position before compression_methods length field.
|
||||
* @returns {Object} Object representation of compression_methods field.
|
||||
*/
|
||||
_readCompressionMethods(input) {
|
||||
const output = {};
|
||||
|
||||
output.length = input.readInt(1);
|
||||
if (!output.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const compressionMethods = new Stream(input.getBytes(output.length));
|
||||
if (compressionMethods.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = [];
|
||||
|
||||
while (compressionMethods.hasMore()) {
|
||||
const compressionMethod = readBytesAsHex(compressionMethods, 1);
|
||||
if (compressionMethod) {
|
||||
output.values.push(compressionMethod);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the extensions field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ClientHello message, with position before extensions length field.
|
||||
* @returns {Object} Object representations of extensions field.
|
||||
*/
|
||||
_readExtensions(input) {
|
||||
const output = {};
|
||||
|
||||
output.length = input.readInt(2);
|
||||
if (!output.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const extensions = new Stream(input.getBytes(output.length));
|
||||
if (extensions.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = this._extensionsParser.parse(extensions);
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake ServeHello messages.
|
||||
*/
|
||||
class ServerHelloParser {
|
||||
|
||||
/**
|
||||
* ServerHelloParser constructor.
|
||||
*/
|
||||
constructor() {
|
||||
this._extensionsParser = new ExtensionsParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single TLS Handshake ServerHello message.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ServerHello message.
|
||||
* @return {Object} Object representation of ServerHello.
|
||||
*/
|
||||
parse(input) {
|
||||
const output = {};
|
||||
|
||||
output.serverVersion = this._readServerVersion(input);
|
||||
output.random = this._readRandom(input);
|
||||
|
||||
const sessionID = this._readSessionID(input);
|
||||
if (sessionID) {
|
||||
output.sessionID = sessionID;
|
||||
}
|
||||
|
||||
output.cipherSuite = this._readCipherSuite(input);
|
||||
output.compressionMethod = this._readCompressionMethod(input);
|
||||
output.extensions = this._readExtensions(input);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the server_version field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ServerHello message, with position before server_version field.
|
||||
* @returns {string} Hex representation of server_version.
|
||||
*/
|
||||
_readServerVersion(input) {
|
||||
return readBytesAsHex(input, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the random field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ServerHello message, with position before random field.
|
||||
* @returns {string} Hex representation of random.
|
||||
*/
|
||||
_readRandom(input) {
|
||||
return readBytesAsHex(input, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the session_id field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ServertHello message, with position before session_id length field.
|
||||
* @returns {string} Hex representation of session_id, or empty string if session_id not present.
|
||||
*/
|
||||
_readSessionID(input) {
|
||||
return readSizePrefixedBytesAsHex(input, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the cipher_suite field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ServerHello message, with position before cipher_suite field.
|
||||
* @returns {string} Hex represention of cipher_suite.
|
||||
*/
|
||||
_readCipherSuite(input) {
|
||||
return readBytesAsHex(input, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the compression_method field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ServerHello message, with position before compression_method field.
|
||||
* @returns {string} Hex represention of compression_method.
|
||||
*/
|
||||
_readCompressionMethod(input) {
|
||||
return readBytesAsHex(input, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the extensions field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw ServerHello message, with position before extensions length field.
|
||||
* @returns {Object} Object representation of extensions field.
|
||||
*/
|
||||
_readExtensions(input) {
|
||||
const output = {};
|
||||
|
||||
output.length = input.readInt(2);
|
||||
if (!output.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const extensions = new Stream(input.getBytes(output.length));
|
||||
if (extensions.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = this._extensionsParser.parse(extensions);
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake Hello Extensions.
|
||||
*/
|
||||
class ExtensionsParser {
|
||||
|
||||
/**
|
||||
* Parses a stream of TLS Handshake Hello Extensions.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing multiple raw Extensions, with position before first extension length field.
|
||||
* @returns {Object[]} Array of Object representations of Extensions contained within input.
|
||||
*/
|
||||
parse(input) {
|
||||
const output = [];
|
||||
|
||||
while (input.hasMore()) {
|
||||
const extension = this._readExtension(input);
|
||||
if (extension) {
|
||||
output.push(extension);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single Extension from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a list of Extensions, with position before the length field of the next Extension.
|
||||
* @returns {Object} Object representation of Extension.
|
||||
*/
|
||||
_readExtension(input) {
|
||||
const output = {};
|
||||
|
||||
if (input.position + 4 > input.length) {
|
||||
input.moveTo(input.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
output.type = "0x" + toHexFast(input.getBytes(2));
|
||||
output.length = input.readInt(2);
|
||||
if (!output.length) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const value = input.getBytes(output.length);
|
||||
if (!value || value.length !== output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
if (value && value.length) {
|
||||
output.value = "0x" + toHexFast(value);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake NewSessionTicket messages.
|
||||
*/
|
||||
class NewSessionTicketParser {
|
||||
|
||||
/**
|
||||
* Parses a single TLS Handshake NewSessionTicket message.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw NewSessionTicket message.
|
||||
* @returns {Object} Object representation of NewSessionTicket.
|
||||
*/
|
||||
parse(input) {
|
||||
return {
|
||||
ticketLifetimeHint: this._readTicketLifetimeHint(input),
|
||||
ticket: this._readTicket(input),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the ticket_lifetime_hint field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw NewSessionTicket message, with position before ticket_lifetime_hint field.
|
||||
* @returns {string} Lifetime hint, in seconds.
|
||||
*/
|
||||
_readTicketLifetimeHint(input) {
|
||||
if (input.position + 4 > input.length) {
|
||||
input.moveTo(input.length);
|
||||
return "";
|
||||
}
|
||||
|
||||
return input.readInt(4) + "s";
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the ticket field fromt the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw NewSessionTicket message, with position before ticket length field.
|
||||
* @returns {string} Hex representation of ticket.
|
||||
*/
|
||||
_readTicket(input) {
|
||||
return readSizePrefixedBytesAsHex(input, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake Certificate messages.
|
||||
*/
|
||||
class CertificateParser {
|
||||
|
||||
/**
|
||||
* Parses a single TLS Handshake Certificate message.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw Certificate message.
|
||||
* @returns {Object} Object representation of Certificate.
|
||||
*/
|
||||
parse(input) {
|
||||
const output = {};
|
||||
|
||||
output.certificateList = this._readCertificateList(input);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the certificate_list field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw Certificate message, with position before certificate_list length field.
|
||||
* @returns {string[]} Array of strings, each containing a hex representation of a value within the certificate_list field.
|
||||
*/
|
||||
_readCertificateList(input) {
|
||||
const output = {};
|
||||
|
||||
if (input.position + 3 > input.length) {
|
||||
input.moveTo(input.length);
|
||||
return output;
|
||||
}
|
||||
|
||||
output.length = input.readInt(3);
|
||||
if (!output.length) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const certificates = new Stream(input.getBytes(output.length));
|
||||
if (certificates.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = [];
|
||||
|
||||
while (certificates.hasMore()) {
|
||||
const certificate = this._readCertificate(certificates);
|
||||
if (certificate) {
|
||||
output.values.push(certificate);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single certificate from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a list of certificicates, with position before the length field of the next certificate.
|
||||
* @returns {string} Hex representation of certificate.
|
||||
*/
|
||||
_readCertificate(input) {
|
||||
return readSizePrefixedBytesAsHex(input, 3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake CertificateRequest messages.
|
||||
*/
|
||||
class CertificateRequestParser {
|
||||
|
||||
/**
|
||||
* Parses a single TLS Handshake CertificateRequest message.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateRequest message.
|
||||
* @return {Object} Object representation of CertificateRequest.
|
||||
*/
|
||||
parse(input) {
|
||||
const output = {};
|
||||
|
||||
output.certificateTypes = this._readCertificateTypes(input);
|
||||
output.supportedSignatureAlgorithms = this._readSupportedSignatureAlgorithms(input);
|
||||
|
||||
const certificateAuthorities = this._readCertificateAuthorities(input);
|
||||
if (certificateAuthorities.length) {
|
||||
output.certificateAuthorities = certificateAuthorities;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the certificate_types field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateRequest message, with position before certificate_types length field.
|
||||
* @return {string[]} Array of strings, each containing a hex representation of a value within the certificate_types field.
|
||||
*/
|
||||
_readCertificateTypes(input) {
|
||||
const output = {};
|
||||
|
||||
output.length = input.readInt(1);
|
||||
if (!output.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const certificateTypes = new Stream(input.getBytes(output.length));
|
||||
if (certificateTypes.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = [];
|
||||
|
||||
while (certificateTypes.hasMore()) {
|
||||
const certificateType = readBytesAsHex(certificateTypes, 1);
|
||||
if (certificateType) {
|
||||
output.values.push(certificateType);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the supported_signature_algorithms field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateRequest message, with position before supported_signature_algorithms length field.
|
||||
* @returns {string[]} Array of strings, each containing a hex representation of a value within the supported_signature_algorithms field.
|
||||
*/
|
||||
_readSupportedSignatureAlgorithms(input) {
|
||||
const output = {};
|
||||
|
||||
output.length = input.readInt(2);
|
||||
if (!output.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const signatureAlgorithms = new Stream(input.getBytes(output.length));
|
||||
if (signatureAlgorithms.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = [];
|
||||
|
||||
while (signatureAlgorithms.hasMore()) {
|
||||
const signatureAlgorithm = readBytesAsHex(signatureAlgorithms, 2);
|
||||
if (signatureAlgorithm) {
|
||||
output.values.push(signatureAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the certificate_authorities field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateRequest message, with position before certificate_authorities length field.
|
||||
* @returns {string[]} Array of strings, each containing a hex representation of a value within the certificate_authorities field.
|
||||
*/
|
||||
_readCertificateAuthorities(input) {
|
||||
const output = {};
|
||||
|
||||
output.length = input.readInt(2);
|
||||
if (!output.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const certificateAuthorities = new Stream(input.getBytes(output.length));
|
||||
if (certificateAuthorities.length < output.length) {
|
||||
output.truncated = true;
|
||||
}
|
||||
|
||||
output.values = [];
|
||||
|
||||
while (certificateAuthorities.hasMore()) {
|
||||
const certificateAuthority = this._readCertificateAuthority(certificateAuthorities);
|
||||
if (certificateAuthority) {
|
||||
output.values.push(certificateAuthority);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single certificate authority from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a list of raw certificate authorities, with position before the length field of the next certificate authority.
|
||||
* @returns {string} Hex representation of certificate authority.
|
||||
*/
|
||||
_readCertificateAuthority(input) {
|
||||
return readSizePrefixedBytesAsHex(input, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses TLS Handshake CertificateVerify messages.
|
||||
*/
|
||||
class CertificateVerifyParser {
|
||||
|
||||
/**
|
||||
* Parses a single CertificateVerify Message.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateVerify message.
|
||||
* @returns {Object} Object representation of CertificateVerify.
|
||||
*/
|
||||
parse(input) {
|
||||
return {
|
||||
algorithmHash: this._readAlgorithmHash(input),
|
||||
algorithmSignature: this._readAlgorithmSignature(input),
|
||||
signature: this._readSignature(input),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the algorithm.hash field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateVerify message, with position before algorithm.hash field.
|
||||
* @return {string} Hex representation of hash algorithm.
|
||||
*/
|
||||
_readAlgorithmHash(input) {
|
||||
return readBytesAsHex(input, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the algorithm.signature field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateVerify message, with position before algorithm.signature field.
|
||||
* @return {string} Hex representation of signature algorithm.
|
||||
*/
|
||||
_readAlgorithmSignature(input) {
|
||||
return readBytesAsHex(input, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the signature field from the following bytes in the provided Stream.
|
||||
*
|
||||
* @param {Stream} input - Stream, containing a raw CertificateVerify message, with position before signature field.
|
||||
* @return {string} Hex representation of signature.
|
||||
*/
|
||||
_readSignature(input) {
|
||||
return readSizePrefixedBytesAsHex(input, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the following size prefixed bytes from the provided Stream, and reuturn as a hex string.
|
||||
*
|
||||
* @param {Stream} input - Stream to read from.
|
||||
* @param {int} sizePrefixLength - Length of the size prefix field.
|
||||
* @returns {string} Hex representation of bytes read from Stream, empty string is returned if
|
||||
* field cannot be read in full.
|
||||
*/
|
||||
function readSizePrefixedBytesAsHex(input, sizePrefixLength) {
|
||||
const length = input.readInt(sizePrefixLength);
|
||||
if (!length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return readBytesAsHex(input, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read n bytes from the provided Stream, and return as a hex string.
|
||||
*
|
||||
* @param {Stream} input - Stream to read from.
|
||||
* @param {int} n - Number of bytes to read.
|
||||
* @returns {string} Hex representation of bytes read from Stream, or empty string if field cannot
|
||||
* be read in full.
|
||||
*/
|
||||
function readBytesAsHex(input, n) {
|
||||
const bytes = input.getBytes(n);
|
||||
if (!bytes || bytes.length !== n) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return "0x" + toHexFast(bytes);
|
||||
}
|
||||
391
src/core/operations/ParseX509CRL.mjs
Normal file
391
src/core/operations/ParseX509CRL.mjs
Normal file
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
* @author robinsandhu
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import r from "jsrsasign";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { fromBase64 } from "../lib/Base64.mjs";
|
||||
import { toHex } from "../lib/Hex.mjs";
|
||||
import { formatDnObj } from "../lib/PublicKey.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Parse X.509 CRL operation
|
||||
*/
|
||||
class ParseX509CRL extends Operation {
|
||||
|
||||
/**
|
||||
* ParseX509CRL constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Parse X.509 CRL";
|
||||
this.module = "PublicKey";
|
||||
this.description = "Parse Certificate Revocation List (CRL)";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Certificate_revocation_list";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input format",
|
||||
"type": "option",
|
||||
"value": ["PEM", "DER Hex", "Base64", "Raw"]
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
"pattern": "^-+BEGIN X509 CRL-+\\r?\\n[\\da-z+/\\n\\r]+-+END X509 CRL-+\\r?\\n?$",
|
||||
"flags": "i",
|
||||
"args": ["PEM"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string} Human-readable description of a Certificate Revocation List (CRL).
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input.length) {
|
||||
return "No input";
|
||||
}
|
||||
|
||||
const inputFormat = args[0];
|
||||
|
||||
let undefinedInputFormat = false;
|
||||
try {
|
||||
switch (inputFormat) {
|
||||
case "DER Hex":
|
||||
input = input.replace(/\s/g, "").toLowerCase();
|
||||
break;
|
||||
case "PEM":
|
||||
break;
|
||||
case "Base64":
|
||||
input = toHex(fromBase64(input, null, "byteArray"), "");
|
||||
break;
|
||||
case "Raw":
|
||||
input = toHex(Utils.strToArrayBuffer(input), "");
|
||||
break;
|
||||
default:
|
||||
undefinedInputFormat = true;
|
||||
}
|
||||
} catch (e) {
|
||||
throw "Certificate load error (non-certificate input?)";
|
||||
}
|
||||
if (undefinedInputFormat) throw "Undefined input format";
|
||||
|
||||
const crl = new r.X509CRL(input);
|
||||
|
||||
let out = `Certificate Revocation List (CRL):
|
||||
Version: ${crl.getVersion() === null ? "1 (0x0)" : "2 (0x1)"}
|
||||
Signature Algorithm: ${crl.getSignatureAlgorithmField()}
|
||||
Issuer:\n${formatDnObj(crl.getIssuer(), 8)}
|
||||
Last Update: ${generalizedDateTimeToUTC(crl.getThisUpdate())}
|
||||
Next Update: ${generalizedDateTimeToUTC(crl.getNextUpdate())}\n`;
|
||||
|
||||
if (crl.getParam().ext !== undefined) {
|
||||
out += `\tCRL extensions:\n${formatCRLExtensions(crl.getParam().ext, 8)}\n`;
|
||||
}
|
||||
|
||||
out += `Revoked Certificates:\n${formatRevokedCertificates(crl.getRevCertArray(), 4)}
|
||||
Signature Value:\n${formatCRLSignature(crl.getSignatureValueHex(), 8)}`;
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generalized date time string to UTC.
|
||||
* @param {string} datetime
|
||||
* @returns UTC datetime string.
|
||||
*/
|
||||
function generalizedDateTimeToUTC(datetime) {
|
||||
// Ensure the string is in the correct format
|
||||
if (!/^\d{12,14}Z$/.test(datetime)) {
|
||||
throw new OperationError(`failed to format datetime string ${datetime}`);
|
||||
}
|
||||
|
||||
// Extract components
|
||||
let centuary = "20";
|
||||
if (datetime.length === 15) {
|
||||
centuary = datetime.substring(0, 2);
|
||||
datetime = datetime.slice(2);
|
||||
}
|
||||
const year = centuary + datetime.substring(0, 2);
|
||||
const month = datetime.substring(2, 4);
|
||||
const day = datetime.substring(4, 6);
|
||||
const hour = datetime.substring(6, 8);
|
||||
const minute = datetime.substring(8, 10);
|
||||
const second = datetime.substring(10, 12);
|
||||
|
||||
// Construct ISO 8601 format string
|
||||
const isoString = `${year}-${month}-${day}T${hour}:${minute}:${second}Z`;
|
||||
|
||||
// Parse using standard Date object
|
||||
const isoDateTime = new Date(isoString);
|
||||
|
||||
return isoDateTime.toUTCString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format CRL extensions.
|
||||
* @param {r.ExtParam[] | undefined} extensions
|
||||
* @param {Number} indent
|
||||
* @returns Formatted string detailing CRL extensions.
|
||||
*/
|
||||
function formatCRLExtensions(extensions, indent) {
|
||||
if (Array.isArray(extensions) === false || extensions.length === 0) {
|
||||
return indentString(`No CRL extensions.`, indent);
|
||||
}
|
||||
|
||||
let out = ``;
|
||||
|
||||
extensions.sort((a, b) => {
|
||||
if (!Object.hasOwn(a, "extname") || !Object.hasOwn(b, "extname")) {
|
||||
return 0;
|
||||
}
|
||||
if (a.extname < b.extname) {
|
||||
return -1;
|
||||
} else if (a.extname === b.extname) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
extensions.forEach((ext) => {
|
||||
if (!Object.hasOwn(ext, "extname")) {
|
||||
throw new OperationError(`CRL entry extension object missing 'extname' key: ${ext}`);
|
||||
}
|
||||
switch (ext.extname) {
|
||||
case "authorityKeyIdentifier":
|
||||
out += `X509v3 Authority Key Identifier:\n`;
|
||||
if (Object.hasOwn(ext, "kid")) {
|
||||
out += `\tkeyid:${colonDelimitedHexFormatString(ext.kid.hex.toUpperCase())}\n`;
|
||||
}
|
||||
if (Object.hasOwn(ext, "issuer")) {
|
||||
out += `\tDirName:${ext.issuer.str}\n`;
|
||||
}
|
||||
if (Object.hasOwn(ext, "sn")) {
|
||||
out += `\tserial:${colonDelimitedHexFormatString(ext.sn.hex.toUpperCase())}\n`;
|
||||
}
|
||||
break;
|
||||
case "cRLDistributionPoints":
|
||||
out += `X509v3 CRL Distribution Points:\n`;
|
||||
ext.array.forEach((distPoint) => {
|
||||
const fullName = `Full Name:\n${formatGeneralNames(distPoint.dpname.full, 4)}`;
|
||||
out += indentString(fullName, 4) + "\n";
|
||||
});
|
||||
break;
|
||||
case "cRLNumber":
|
||||
if (!Object.hasOwn(ext, "num")) {
|
||||
throw new OperationError(`'cRLNumber' CRL entry extension missing 'num' key: ${ext}`);
|
||||
}
|
||||
out += `X509v3 CRL Number:\n\t${ext.num.hex.toUpperCase()}\n`;
|
||||
break;
|
||||
case "issuerAltName":
|
||||
out += `X509v3 Issuer Alternative Name:\n${formatGeneralNames(ext.array, 4)}\n`;
|
||||
break;
|
||||
default:
|
||||
out += `${ext.extname}:\n`;
|
||||
out += `\tUnsupported CRL extension. Try openssl CLI.\n`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return indentString(chop(out), indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format general names array.
|
||||
* @param {Object[]} names
|
||||
* @returns Multi-line formatted string describing all supported general name types.
|
||||
*/
|
||||
function formatGeneralNames(names, indent) {
|
||||
let out = ``;
|
||||
|
||||
names.forEach((name) => {
|
||||
const key = Object.keys(name)[0];
|
||||
|
||||
switch (key) {
|
||||
case "ip":
|
||||
out += `IP:${name.ip}\n`;
|
||||
break;
|
||||
case "dns":
|
||||
out += `DNS:${name.dns}\n`;
|
||||
break;
|
||||
case "uri":
|
||||
out += `URI:${name.uri}\n`;
|
||||
break;
|
||||
case "rfc822":
|
||||
out += `EMAIL:${name.rfc822}\n`;
|
||||
break;
|
||||
case "dn":
|
||||
out += `DIR:${name.dn.str}\n`;
|
||||
break;
|
||||
case "other":
|
||||
out += `OtherName:${name.other.oid}::${Object.values(name.other.value)[0].str}\n`;
|
||||
break;
|
||||
default:
|
||||
out += `${key}: unsupported general name type`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return indentString(chop(out), indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Colon-delimited hex formatted output.
|
||||
* @param {string} hexString Hex String
|
||||
* @returns String representing input hex string with colon delimiter.
|
||||
*/
|
||||
function colonDelimitedHexFormatString(hexString) {
|
||||
if (hexString.length % 2 !== 0) {
|
||||
hexString = "0" + hexString;
|
||||
}
|
||||
|
||||
return chop(hexString.replace(/(..)/g, "$&:"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format revoked certificates array
|
||||
* @param {r.RevokedCertificate[] | null} revokedCertificates
|
||||
* @param {Number} indent
|
||||
* @returns Multi-line formatted string output of revoked certificates array
|
||||
*/
|
||||
function formatRevokedCertificates(revokedCertificates, indent) {
|
||||
if (Array.isArray(revokedCertificates) === false || revokedCertificates.length === 0) {
|
||||
return indentString("No Revoked Certificates.", indent);
|
||||
}
|
||||
|
||||
let out=``;
|
||||
|
||||
revokedCertificates.forEach((revCert) => {
|
||||
if (!Object.hasOwn(revCert, "sn") || !Object.hasOwn(revCert, "date")) {
|
||||
throw new OperationError("invalid revoked certificate object, missing either serial number or date");
|
||||
}
|
||||
|
||||
out += `Serial Number: ${revCert.sn.hex.toUpperCase()}
|
||||
Revocation Date: ${generalizedDateTimeToUTC(revCert.date)}\n`;
|
||||
if (Object.hasOwn(revCert, "ext") && Array.isArray(revCert.ext) && revCert.ext.length !== 0) {
|
||||
out += `\tCRL entry extensions:\n${indentString(formatCRLEntryExtensions(revCert.ext), 2*indent)}\n`;
|
||||
}
|
||||
});
|
||||
|
||||
return indentString(chop(out), indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format CRL entry extensions.
|
||||
* @param {Object[]} exts
|
||||
* @returns Formatted multi-line string describing CRL entry extensions.
|
||||
*/
|
||||
function formatCRLEntryExtensions(exts) {
|
||||
let out = ``;
|
||||
|
||||
const crlReasonCodeToReasonMessage = {
|
||||
0: "Unspecified",
|
||||
1: "Key Compromise",
|
||||
2: "CA Compromise",
|
||||
3: "Affiliation Changed",
|
||||
4: "Superseded",
|
||||
5: "Cessation Of Operation",
|
||||
6: "Certificate Hold",
|
||||
8: "Remove From CRL",
|
||||
9: "Privilege Withdrawn",
|
||||
10: "AA Compromise",
|
||||
};
|
||||
|
||||
const holdInstructionOIDToName = {
|
||||
"1.2.840.10040.2.1": "Hold Instruction None",
|
||||
"1.2.840.10040.2.2": "Hold Instruction Call Issuer",
|
||||
"1.2.840.10040.2.3": "Hold Instruction Reject",
|
||||
};
|
||||
|
||||
exts.forEach((ext) => {
|
||||
if (!Object.hasOwn(ext, "extname")) {
|
||||
throw new OperationError(`CRL entry extension object missing 'extname' key: ${ext}`);
|
||||
}
|
||||
switch (ext.extname) {
|
||||
case "cRLReason":
|
||||
if (!Object.hasOwn(ext, "code")) {
|
||||
throw new OperationError(`'cRLReason' CRL entry extension missing 'code' key: ${ext}`);
|
||||
}
|
||||
out += `X509v3 CRL Reason Code:
|
||||
${Object.hasOwn(crlReasonCodeToReasonMessage, ext.code) ? crlReasonCodeToReasonMessage[ext.code] : `invalid reason code: ${ext.code}`}\n`;
|
||||
break;
|
||||
case "2.5.29.23": // Hold instruction
|
||||
out += `Hold Instruction Code:\n\t${Object.hasOwn(holdInstructionOIDToName, ext.extn.oid) ? holdInstructionOIDToName[ext.extn.oid] : `${ext.extn.oid}: unknown hold instruction OID`}\n`;
|
||||
break;
|
||||
case "2.5.29.24": // Invalidity Date
|
||||
out += `Invalidity Date:\n\t${generalizedDateTimeToUTC(ext.extn.gentime.str)}\n`;
|
||||
break;
|
||||
default:
|
||||
out += `${ext.extname}:\n`;
|
||||
out += `\tUnsupported CRL entry extension. Try openssl CLI.\n`;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return chop(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format CRL signature.
|
||||
* @param {String} sigHex
|
||||
* @param {Number} indent
|
||||
* @returns String representing hex signature value formatted on multiple lines.
|
||||
*/
|
||||
function formatCRLSignature(sigHex, indent) {
|
||||
if (sigHex.length % 2 !== 0) {
|
||||
sigHex = "0" + sigHex;
|
||||
}
|
||||
|
||||
return indentString(formatMultiLine(chop(sigHex.replace(/(..)/g, "$&:"))), indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format string onto multiple lines.
|
||||
* @param {string} longStr
|
||||
* @returns String as a multi-line string.
|
||||
*/
|
||||
function formatMultiLine(longStr) {
|
||||
const lines = [];
|
||||
|
||||
for (let remain = longStr ; remain !== "" ; remain = remain.substring(54)) {
|
||||
lines.push(remain.substring(0, 54));
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent a multi-line string by n spaces.
|
||||
* @param {string} input String
|
||||
* @param {number} spaces How many leading spaces
|
||||
* @returns Indented string.
|
||||
*/
|
||||
function indentString(input, spaces) {
|
||||
const indent = " ".repeat(spaces);
|
||||
return input.replace(/^/gm, indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove last character from a string.
|
||||
* @param {string} s String
|
||||
* @returns Chopped string.
|
||||
*/
|
||||
function chop(s) {
|
||||
if (s.length < 1) {
|
||||
return s;
|
||||
}
|
||||
return s.substring(0, s.length - 1);
|
||||
}
|
||||
|
||||
export default ParseX509CRL;
|
||||
@@ -60,7 +60,7 @@ class RSASign extends Operation {
|
||||
const privateKey = forge.pki.decryptRsaPrivateKey(key, password);
|
||||
// Generate message hash
|
||||
const md = MD_ALGORITHMS[mdAlgo].create();
|
||||
md.update(input, "utf8");
|
||||
md.update(input, "raw");
|
||||
// Sign message hash
|
||||
const sig = privateKey.sign(md);
|
||||
return sig;
|
||||
|
||||
@@ -8,6 +8,7 @@ import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import forge from "node-forge";
|
||||
import { MD_ALGORITHMS } from "../lib/RSA.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* RSA Verify operation
|
||||
@@ -37,6 +38,11 @@ class RSAVerify extends Operation {
|
||||
type: "text",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
name: "Message format",
|
||||
type: "option",
|
||||
value: ["Raw", "Hex", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Message Digest Algorithm",
|
||||
type: "option",
|
||||
@@ -51,7 +57,7 @@ class RSAVerify extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [pemKey, message, mdAlgo] = args;
|
||||
const [pemKey, message, format, mdAlgo] = args;
|
||||
if (pemKey.replace("-----BEGIN RSA PUBLIC KEY-----", "").length === 0) {
|
||||
throw new OperationError("Please enter a public key.");
|
||||
}
|
||||
@@ -60,7 +66,8 @@ class RSAVerify extends Operation {
|
||||
const pubKey = forge.pki.publicKeyFromPem(pemKey);
|
||||
// Generate message digest
|
||||
const md = MD_ALGORITHMS[mdAlgo].create();
|
||||
md.update(message, "utf8");
|
||||
const messageStr = Utils.convertToByteString(message, format);
|
||||
md.update(messageStr, "raw");
|
||||
// Compare signed message digest and generated message digest
|
||||
const result = pubKey.verify(md.digest().bytes(), input);
|
||||
return result ? "Verified OK" : "Verification Failure";
|
||||
|
||||
@@ -10,7 +10,7 @@ import Utils from "../Utils.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { runHash } from "../lib/Hash.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Randomize Colour Palette operation
|
||||
@@ -48,7 +48,7 @@ class RandomizeColourPalette extends Operation {
|
||||
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
||||
|
||||
const seed = args[0] || (Math.random().toString().substr(2)),
|
||||
parsedImage = await jimp.read(input),
|
||||
parsedImage = await Jimp.read(input),
|
||||
width = parsedImage.bitmap.width,
|
||||
height = parsedImage.bitmap.height;
|
||||
|
||||
@@ -61,7 +61,7 @@ class RandomizeColourPalette extends Operation {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Resize Image operation
|
||||
@@ -80,11 +80,11 @@ class ResizeImage extends Operation {
|
||||
resizeAlg = args[4];
|
||||
|
||||
const resizeMap = {
|
||||
"Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR,
|
||||
"Bilinear": jimp.RESIZE_BILINEAR,
|
||||
"Bicubic": jimp.RESIZE_BICUBIC,
|
||||
"Hermite": jimp.RESIZE_HERMITE,
|
||||
"Bezier": jimp.RESIZE_BEZIER
|
||||
"Nearest Neighbour": Jimp.RESIZE_NEAREST_NEIGHBOR,
|
||||
"Bilinear": Jimp.RESIZE_BILINEAR,
|
||||
"Bicubic": Jimp.RESIZE_BICUBIC,
|
||||
"Hermite": Jimp.RESIZE_HERMITE,
|
||||
"Bezier": Jimp.RESIZE_BEZIER
|
||||
};
|
||||
|
||||
if (!isImage(input)) {
|
||||
@@ -93,7 +93,7 @@ class ResizeImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -113,9 +113,9 @@ class ResizeImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Rotate Image operation
|
||||
@@ -52,7 +52,7 @@ class RotateImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -63,9 +63,9 @@ class RotateImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -40,7 +40,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "1st cipher rotor intial value",
|
||||
name: "1st cipher rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -56,7 +56,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "2nd cipher rotor intial value",
|
||||
name: "2nd cipher rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -72,7 +72,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "3rd cipher rotor intial value",
|
||||
name: "3rd cipher rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -88,7 +88,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "4th cipher rotor intial value",
|
||||
name: "4th cipher rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -104,7 +104,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "5th cipher rotor intial value",
|
||||
name: "5th cipher rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -120,7 +120,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "1st control rotor intial value",
|
||||
name: "1st control rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -136,7 +136,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "2nd control rotor intial value",
|
||||
name: "2nd control rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -152,7 +152,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "3rd control rotor intial value",
|
||||
name: "3rd control rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -168,7 +168,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "4th control rotor intial value",
|
||||
name: "4th control rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -184,7 +184,7 @@ class Sigaba extends Operation {
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "5th control rotor intial value",
|
||||
name: "5th control rotor initial value",
|
||||
type: "option",
|
||||
value: LETTERS
|
||||
},
|
||||
@@ -195,7 +195,7 @@ class Sigaba extends Operation {
|
||||
defaultIndex: 0
|
||||
},
|
||||
{
|
||||
name: "1st index rotor intial value",
|
||||
name: "1st index rotor initial value",
|
||||
type: "option",
|
||||
value: NUMBERS
|
||||
},
|
||||
@@ -206,7 +206,7 @@ class Sigaba extends Operation {
|
||||
defaultIndex: 0
|
||||
},
|
||||
{
|
||||
name: "2nd index rotor intial value",
|
||||
name: "2nd index rotor initial value",
|
||||
type: "option",
|
||||
value: NUMBERS
|
||||
},
|
||||
@@ -217,7 +217,7 @@ class Sigaba extends Operation {
|
||||
defaultIndex: 0
|
||||
},
|
||||
{
|
||||
name: "3rd index rotor intial value",
|
||||
name: "3rd index rotor initial value",
|
||||
type: "option",
|
||||
value: NUMBERS
|
||||
},
|
||||
@@ -228,7 +228,7 @@ class Sigaba extends Operation {
|
||||
defaultIndex: 0
|
||||
},
|
||||
{
|
||||
name: "4th index rotor intial value",
|
||||
name: "4th index rotor initial value",
|
||||
type: "option",
|
||||
value: NUMBERS
|
||||
},
|
||||
@@ -239,7 +239,7 @@ class Sigaba extends Operation {
|
||||
defaultIndex: 0
|
||||
},
|
||||
{
|
||||
name: "5th index rotor intial value",
|
||||
name: "5th index rotor initial value",
|
||||
type: "option",
|
||||
value: NUMBERS
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Sharpen Image operation
|
||||
@@ -68,7 +68,7 @@ class SharpenImage extends Operation {
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
image = await Jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
@@ -137,9 +137,9 @@ class SharpenImage extends Operation {
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
imageBuffer = await image.getBufferAsync(Jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {isImage} from "../lib/FileType.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* Split Colour Channels operation
|
||||
@@ -41,7 +41,7 @@ class SplitColourChannels extends Operation {
|
||||
// Make sure that the input is an image
|
||||
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) => {
|
||||
try {
|
||||
@@ -51,7 +51,7 @@ class SplitColourChannels extends Operation {
|
||||
{apply: "blue", 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"}));
|
||||
} catch (err) {
|
||||
reject(new OperationError(`Could not split red channel: ${err}`));
|
||||
@@ -64,7 +64,7 @@ class SplitColourChannels extends Operation {
|
||||
.color([
|
||||
{apply: "red", 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"}));
|
||||
} catch (err) {
|
||||
reject(new OperationError(`Could not split green channel: ${err}`));
|
||||
@@ -77,7 +77,7 @@ class SplitColourChannels extends Operation {
|
||||
.color([
|
||||
{apply: "red", 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"}));
|
||||
} catch (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 { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import jimp from "jimp";
|
||||
import Jimp from "jimp/es/index.js";
|
||||
|
||||
/**
|
||||
* View Bit Plane operation
|
||||
@@ -52,7 +52,7 @@ class ViewBitPlane extends Operation {
|
||||
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
||||
|
||||
const [colour, bit] = args,
|
||||
parsedImage = await jimp.read(input),
|
||||
parsedImage = await Jimp.read(input),
|
||||
width = parsedImage.bitmap.width,
|
||||
height = parsedImage.bitmap.height,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -52,12 +52,6 @@ class XPathExpression extends Operation {
|
||||
try {
|
||||
doc = new xmldom.DOMParser({
|
||||
errorHandler: {
|
||||
warning(w) {
|
||||
throw w;
|
||||
},
|
||||
error(e) {
|
||||
throw e;
|
||||
},
|
||||
fatalError(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.
|
||||
---------------------------------------------------------------------------------------------------------------------------
|
||||
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,
|
||||
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
|
||||
@@ -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.
|
||||
---------------------------------------------------------------------------------------------------------------------------
|
||||
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 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
|
||||
|
||||
@@ -23,7 +23,7 @@ const dir = path.join(`${process.cwd()}/src/node`);
|
||||
if (!fs.existsSync(dir)) {
|
||||
console.log("\nCWD: " + process.cwd());
|
||||
console.log("Error: generateNodeIndex.mjs should be run from the project root");
|
||||
console.log("Example> node --experimental-modules src/core/config/scripts/generateNodeIndex.mjs");
|
||||
console.log("Example> node --experimental-modules src/node/config/scripts/generateNodeIndex.mjs");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ class App {
|
||||
|
||||
this.baking = false;
|
||||
this.autoBake_ = false;
|
||||
this.autoBakePause = false;
|
||||
this.progress = 0;
|
||||
this.ingId = 0;
|
||||
|
||||
@@ -155,11 +154,6 @@ class App {
|
||||
* Runs Auto Bake if it is set.
|
||||
*/
|
||||
autoBake() {
|
||||
// If autoBakePause is set, we are loading a full recipe (and potentially input), so there is no
|
||||
// need to set the staleness indicator. Just exit and wait until auto bake is called after loading
|
||||
// has completed.
|
||||
if (this.autoBakePause) return false;
|
||||
|
||||
if (this.baking) {
|
||||
this.manager.worker.cancelBakeForAutoBake();
|
||||
this.baking = false;
|
||||
@@ -478,7 +472,6 @@ class App {
|
||||
* @fires Manager#statechange
|
||||
*/
|
||||
loadURIParams(params=this.getURIParams()) {
|
||||
this.autoBakePause = true;
|
||||
this.uriParams = params;
|
||||
|
||||
// Read in recipe from URI params
|
||||
@@ -507,7 +500,7 @@ class App {
|
||||
// Input Character Encoding
|
||||
// Must be set before the input is loaded
|
||||
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
|
||||
@@ -545,7 +538,6 @@ class App {
|
||||
this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme));
|
||||
}
|
||||
|
||||
this.autoBakePause = false;
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
}
|
||||
|
||||
@@ -579,10 +571,6 @@ class App {
|
||||
setRecipeConfig(recipeConfig) {
|
||||
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++) {
|
||||
const item = this.manager.recipe.addOperation(recipeConfig[i].op);
|
||||
|
||||
@@ -617,9 +605,6 @@ class App {
|
||||
|
||||
this.progress = 0;
|
||||
}
|
||||
|
||||
// Unpause auto bake
|
||||
this.autoBakePause = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ class HTMLCategory {
|
||||
let html = `<div class="panel category">
|
||||
<a class="category-title" data-toggle="collapse" data-target="#${catName}">
|
||||
${this.name}
|
||||
<span class="op-count hidden">
|
||||
${this.opList.length}
|
||||
</span>
|
||||
</a>
|
||||
<div id="${catName}" class="panel-collapse collapse ${(this.selected ? " show" : "")}" data-parent="#categories">
|
||||
<ul class="op-list">`;
|
||||
|
||||
@@ -229,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]#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]#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]", "change", this.options.numberChange, this.options);
|
||||
this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
|
||||
@@ -270,7 +271,7 @@ class Manager {
|
||||
* @param {Object} [scope=this] - The object to bind to the callback function
|
||||
*
|
||||
* @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
|
||||
* this.addMultiEventListener("search", "keyup paste search", this.search, this);
|
||||
*/
|
||||
@@ -291,7 +292,7 @@ class Manager {
|
||||
* @param {Object} [scope=this] - The object to bind to the callback function
|
||||
*
|
||||
* @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
|
||||
* this.addMultiEventListener(".saveable", "keyup paste", this.save, this);
|
||||
*/
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
<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>">
|
||||
Operations
|
||||
<span class="op-count"></span>
|
||||
</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>">
|
||||
<ul id="search-results" class="op-list"></ul>
|
||||
@@ -521,6 +522,13 @@
|
||||
Keep the current tab in sync between the input and output
|
||||
</label>
|
||||
</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 class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" id="reset-options">Reset options to default</button>
|
||||
|
||||
@@ -51,7 +51,8 @@ function main() {
|
||||
logLevel: "info",
|
||||
autoMagic: true,
|
||||
imagePreview: true,
|
||||
syncTabs: true
|
||||
syncTabs: true,
|
||||
showCatCount: false,
|
||||
};
|
||||
|
||||
document.removeEventListener("DOMContentLoaded", main, false);
|
||||
|
||||
@@ -40,4 +40,13 @@
|
||||
margin: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
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;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.blur {
|
||||
color: transparent !important;
|
||||
text-shadow: rgba(0, 0, 0, 0.95) 0 0 10px !important;
|
||||
|
||||
@@ -215,13 +215,16 @@ class InputWaiter {
|
||||
* Handler for Chr Enc change events
|
||||
* Sets the input character encoding
|
||||
* @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;
|
||||
this.inputChrEnc = chrEncVal;
|
||||
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+/");
|
||||
this.app.updateURL(true, inputStr);
|
||||
}
|
||||
|
||||
// Trigger a state change
|
||||
if (!silent) window.dispatchEvent(this.manager.statechange);
|
||||
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,10 @@ class OperationsWaiter {
|
||||
*/
|
||||
opListCreate(e) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -293,6 +297,18 @@ class OperationsWaiter {
|
||||
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;
|
||||
|
||||
@@ -50,6 +50,7 @@ class OptionsWaiter {
|
||||
|
||||
// Initialise options
|
||||
this.setWordWrap();
|
||||
this.manager.ops.setCatCount();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -174,16 +174,19 @@ module.exports = {
|
||||
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");
|
||||
|
||||
browser
|
||||
.sendKeys("#input-text .cm-content", "2")
|
||||
.waitForElementNotVisible("#stale-indicator")
|
||||
.waitForElementNotVisible("#output-loader");
|
||||
|
||||
@@ -192,6 +195,7 @@ module.exports = {
|
||||
|
||||
// Turn autobake off again
|
||||
browser.click("#auto-bake-label");
|
||||
browser.expect.element("#auto-bake").to.not.be.selected.before(1000);
|
||||
},
|
||||
|
||||
"Special content": browser => {
|
||||
|
||||
@@ -236,7 +236,7 @@ module.exports = {
|
||||
// testOp(browser, "OR", "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");
|
||||
// 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, "PGP Decrypt", "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 {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
||||
* @param {string} input - input text for test
|
||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
||||
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||
*/
|
||||
function bakeOp(browser, opName, input, args=[]) {
|
||||
browser.perform(function() {
|
||||
@@ -425,12 +425,12 @@ function bakeOp(browser, opName, input, args=[]) {
|
||||
* @param {Browser} browser - Nightwatch client
|
||||
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
|
||||
* @param {string} input - input text
|
||||
* @param {string} output - expected output
|
||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
||||
* @param {string|RegExp} output - expected output
|
||||
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||
*/
|
||||
function testOp(browser, opName, input, output, args=[]) {
|
||||
bakeOp(browser, opName, input, args);
|
||||
utils.expectOutput(browser, output);
|
||||
utils.expectOutput(browser, output, true);
|
||||
}
|
||||
|
||||
/** @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} input - input text
|
||||
* @param {string} cssSelector - CSS selector for HTML output
|
||||
* @param {string} output - expected output
|
||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
||||
* @param {string|RegExp} output - expected output
|
||||
* @param {Array<string>|Array<Array<string>>} [args=[]] - arguments, nested if multiple ops
|
||||
*/
|
||||
function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
|
||||
bakeOp(browser, opName, input, args);
|
||||
@@ -459,9 +459,9 @@ function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
|
||||
* @param {Browser} browser - Nightwatch client
|
||||
* @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 {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() {
|
||||
console.log(`Current test: ${opName}`);
|
||||
});
|
||||
@@ -481,11 +481,12 @@ function testOpImage(browser, opName, filename, args) {
|
||||
* @param {Browser} browser - Nightwatch client
|
||||
* @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} cssSelector - CSS selector for HTML output
|
||||
* @param {string} output - expected output
|
||||
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
|
||||
* @param {string|boolean} cssSelector - CSS selector for HTML output or false for normal text output
|
||||
* @param {string|RegExp} output - expected output
|
||||
* @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() {
|
||||
console.log(`Current test: ${opName}`);
|
||||
});
|
||||
@@ -494,9 +495,14 @@ function testOpFile(browser, opName, filename, cssSelector, output, args) {
|
||||
browser.pause(100).waitForElementVisible("#stale-indicator", 5000);
|
||||
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);
|
||||
} else if (output instanceof RegExp) {
|
||||
// HTML output - RegEx match
|
||||
browser.expect.element("#output-html " + cssSelector).text.that.matches(output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ function setInput(browser, input, type=true) {
|
||||
browser.execute(text => {
|
||||
window.app.setInput(text);
|
||||
}, [input]);
|
||||
browser.pause(100);
|
||||
}
|
||||
expectInput(browser, input);
|
||||
}
|
||||
|
||||
/** @function
|
||||
@@ -48,6 +50,11 @@ function setInput(browser, input, type=true) {
|
||||
* @param {Browser} browser - Nightwatch client
|
||||
*/
|
||||
function bake(browser) {
|
||||
browser
|
||||
// Ensure we're not currently busy
|
||||
.waitForElementNotVisible("#output-loader", 5000)
|
||||
.expect.element("#bake span").text.to.equal("BAKE!");
|
||||
|
||||
browser
|
||||
.click("#bake")
|
||||
.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));
|
||||
}
|
||||
|
||||
clear(browser);
|
||||
setInput(browser, input, false);
|
||||
browser
|
||||
.urlHash("recipe=" + recipeConfig)
|
||||
@@ -173,8 +179,19 @@ function loadRecipe(browser, opName, input, args) {
|
||||
*
|
||||
* @param {Browser} browser - Nightwatch client
|
||||
* @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 => {
|
||||
return window.app.manager.output.outputEditorView.state.doc.toString();
|
||||
}, [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
|
||||
* Uploads a file using the #open-file input
|
||||
*
|
||||
@@ -245,6 +280,7 @@ module.exports = {
|
||||
paste: paste,
|
||||
loadRecipe: loadRecipe,
|
||||
expectOutput: expectOutput,
|
||||
expectInput: expectInput,
|
||||
uploadFile: uploadFile,
|
||||
uploadFolder: uploadFolder
|
||||
};
|
||||
|
||||
@@ -115,6 +115,7 @@ import "./tests/ParseObjectIDTimestamp.mjs";
|
||||
import "./tests/ParseQRCode.mjs";
|
||||
import "./tests/ParseSSHHostKey.mjs";
|
||||
import "./tests/ParseTCP.mjs";
|
||||
import "./tests/ParseTLSRecord.mjs";
|
||||
import "./tests/ParseTLV.mjs";
|
||||
import "./tests/ParseUDP.mjs";
|
||||
import "./tests/PEMtoHex.mjs";
|
||||
@@ -153,6 +154,7 @@ import "./tests/UnescapeString.mjs";
|
||||
import "./tests/Unicode.mjs";
|
||||
import "./tests/YARA.mjs";
|
||||
import "./tests/ParseCSR.mjs";
|
||||
import "./tests/XXTEA.mjs";
|
||||
|
||||
const testStatus = {
|
||||
allTestsPassing: true,
|
||||
|
||||
@@ -189,7 +189,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["", "\n", true]
|
||||
"args": ["", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -205,7 +205,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$.store.book[*].author", "\n", true]
|
||||
"args": ["$.store.book[*].author", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -223,7 +223,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..title", "\n", true]
|
||||
"args": ["$..title", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -238,7 +238,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$.store.*", "\n", true]
|
||||
"args": ["$.store.*", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -249,7 +249,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[-1:]", "\n", true]
|
||||
"args": ["$..book[-1:]", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -263,7 +263,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[:2]", "\n", true]
|
||||
"args": ["$..book[:2]", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -277,7 +277,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[?(@.isbn)]", "\n", false]
|
||||
"args": ["$..book[?(@.isbn)]", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -292,7 +292,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"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: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[?(@.price<10)]", "\n", false]
|
||||
"args": ["$..book[?(@.price<10)]", "\n"]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -318,12 +318,11 @@ TestRegister.addTests([
|
||||
"op": "JPath expression",
|
||||
"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'}});\")();)]",
|
||||
"\n",
|
||||
true
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
expectedOutput: "Invalid JPath expression: Eval [?(expr)] prevented in JSONPath expression."
|
||||
expectedMatch: /^Invalid JPath expression: jsonPath: self is not defined:/
|
||||
},
|
||||
{
|
||||
name: "CSS selector",
|
||||
|
||||
@@ -14,7 +14,7 @@ import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "GOST Encrypt: Magma",
|
||||
name: "GOST Encrypt: 1989",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "f124ac5c0853870906dbaf9b56",
|
||||
recipeConfig: [
|
||||
@@ -25,8 +25,7 @@ TestRegister.addTests([
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"64",
|
||||
"GOST 28147 (1989)",
|
||||
"E-SC",
|
||||
"OFB",
|
||||
"CP",
|
||||
@@ -48,7 +47,6 @@ TestRegister.addTests([
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"128",
|
||||
"E-SC",
|
||||
"CBC",
|
||||
"CP",
|
||||
@@ -58,7 +56,7 @@ TestRegister.addTests([
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GOST Decrypt: Magma",
|
||||
name: "GOST Decrypt: 1989",
|
||||
input: "f124ac5c0853870906dbaf9b56",
|
||||
expectedOutput: "Hello, World!",
|
||||
recipeConfig: [
|
||||
@@ -69,8 +67,7 @@ TestRegister.addTests([
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Hex",
|
||||
"Raw",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"128",
|
||||
"GOST 28147 (1989)",
|
||||
"E-SC",
|
||||
"OFB",
|
||||
"CP",
|
||||
@@ -92,7 +89,6 @@ TestRegister.addTests([
|
||||
"Hex",
|
||||
"Raw",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"128",
|
||||
"E-TEST",
|
||||
"CBC",
|
||||
"CP",
|
||||
@@ -113,8 +109,7 @@ TestRegister.addTests([
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"64",
|
||||
"GOST 28147 (1989)",
|
||||
"E-C",
|
||||
48
|
||||
]
|
||||
@@ -134,7 +129,6 @@ TestRegister.addTests([
|
||||
{ "option": "Hex", "string": "42b77fb3d6f6bf04" },
|
||||
"Raw",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"128",
|
||||
"E-TEST"
|
||||
]
|
||||
}
|
||||
@@ -152,8 +146,7 @@ TestRegister.addTests([
|
||||
{ "option": "Hex", "string": "0011223344556677" },
|
||||
"Raw",
|
||||
"Hex",
|
||||
"GOST R 34.12 (Kuznyechik, 2015)",
|
||||
"64",
|
||||
"GOST R 34.12 (Magma, 2015)",
|
||||
"E-TEST",
|
||||
"CP"
|
||||
]
|
||||
@@ -172,8 +165,7 @@ TestRegister.addTests([
|
||||
{ "option": "Latin1", "string": "00112233" },
|
||||
"Hex",
|
||||
"Raw",
|
||||
"GOST 28147 (Magma, 1989)",
|
||||
"64",
|
||||
"GOST 28147 (1989)",
|
||||
"E-Z",
|
||||
"CP"
|
||||
]
|
||||
|
||||
@@ -44,7 +44,18 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [hsKey, "HS256"],
|
||||
args: [hsKey, "HS256", "{}"],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: HS256 with custom header",
|
||||
input: inputObject,
|
||||
expectedOutput: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImN1c3RvbS5rZXkifQ.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.kXln8btJburfRlND8IDZAQ8NZGFFZhvHyooHa6N9za8",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [hsKey, "HS256", `{"kid":"custom.key"}`],
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -55,7 +66,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [hsKey, "HS384"],
|
||||
args: [hsKey, "HS384", "{}"],
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -66,7 +77,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [hsKey, "HS512"],
|
||||
args: [hsKey, "HS512", "{}"],
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -77,7 +88,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "ES256"],
|
||||
args: [esKey, "ES256", "{}"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
@@ -92,7 +103,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "ES384"],
|
||||
args: [esKey, "ES384", "{}"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
@@ -107,7 +118,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "ES512"],
|
||||
args: [esKey, "ES512", "{}"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
@@ -122,7 +133,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [rsKey, "RS256"],
|
||||
args: [rsKey, "RS256", "{}"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
@@ -137,7 +148,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [rsKey, "RS384"],
|
||||
args: [rsKey, "RS384", "{}"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
@@ -152,7 +163,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "RS512"],
|
||||
args: [esKey, "RS512", "{}"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
|
||||
@@ -29,31 +29,28 @@ NFgFNIvSXhbqMYoHAAApMHJOxiWpBFdYKp3tESnlgh2lUh7lQtmOjD4a1dzfU8PU
|
||||
oViyp+UJGasN2WRd+4VtaPw64w==
|
||||
-----END CERTIFICATE REQUEST-----`;
|
||||
|
||||
const OUT_EXAMPLE_COM_RSA_1024 = `Version: 1 (0x00)
|
||||
Subject
|
||||
C = CH
|
||||
const OUT_EXAMPLE_COM_RSA_1024 = `Subject
|
||||
C = CH
|
||||
ST = Zurich
|
||||
L = Zurich
|
||||
O = Example RE
|
||||
L = Zurich
|
||||
O = Example RE
|
||||
OU = IT Department
|
||||
CN = example.com
|
||||
Subject Alternative Names
|
||||
DNS: example.com
|
||||
DNS: www.example.com
|
||||
Public Key
|
||||
Algorithm: RSA
|
||||
Length: 1024 bits
|
||||
Modulus: ae:b4:eb:2c:8e:85:93:38:d7:f0:56:5f:72:5b:76:a3:
|
||||
1d:43:cf:b2:91:c2:de:5f:e9:f7:d9:89:ce:ed:c0:b0:
|
||||
0a:27:86:a8:fc:7d:c0:3e:3c:28:15:55:17:1a:38:8d:
|
||||
8f:f5:c5:d9:19:48:77:85:31:07:56:fa:0a:05:a3:ba:
|
||||
30:5b:f5:6e:75:ad:37:6f:7d:62:f2:00:7b:2b:2d:ca:
|
||||
6d:a5:5c:fe:57:d6:3c:5f:d9:04:14:24:46:18:3c:86:
|
||||
e7:e5:fe:36:ee:82:3b:34:e9:50:f0:e3:e1:b2:08:5f:
|
||||
fb:8f:93:77:c3:60:31:2a:2c:29:55:cb:cf:d5:4b:8f
|
||||
Modulus: 00:ae:b4:eb:2c:8e:85:93:38:d7:f0:56:5f:72:5b:76:
|
||||
a3:1d:43:cf:b2:91:c2:de:5f:e9:f7:d9:89:ce:ed:c0:
|
||||
b0:0a:27:86:a8:fc:7d:c0:3e:3c:28:15:55:17:1a:38:
|
||||
8d:8f:f5:c5:d9:19:48:77:85:31:07:56:fa:0a:05:a3:
|
||||
ba:30:5b:f5:6e:75:ad:37:6f:7d:62:f2:00:7b:2b:2d:
|
||||
ca:6d:a5:5c:fe:57:d6:3c:5f:d9:04:14:24:46:18:3c:
|
||||
86:e7:e5:fe:36:ee:82:3b:34:e9:50:f0:e3:e1:b2:08:
|
||||
5f:fb:8f:93:77:c3:60:31:2a:2c:29:55:cb:cf:d5:4b:
|
||||
8f
|
||||
Exponent: 65537 (0x10001)
|
||||
Signature
|
||||
Algorithm: sha256WithRSAEncryption
|
||||
Algorithm: SHA256withRSA
|
||||
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:
|
||||
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:
|
||||
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
|
||||
Extensions
|
||||
basicConstraints CRITICAL:
|
||||
Requested Extensions
|
||||
Basic Constraints: critical
|
||||
CA = false
|
||||
keyUsage CRITICAL:
|
||||
Digital signature
|
||||
Key Usage: critical
|
||||
Digital Signature
|
||||
Key encipherment
|
||||
extKeyUsage:
|
||||
TLS Web Server Authentication`;
|
||||
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" \
|
||||
@@ -97,39 +97,36 @@ m9cpVxuxGLtONBnohzohnFECytSXWEXPIj8L9SpYK97G02nJYYCAcb5BF11Alfux
|
||||
sNxtsr6zgPaLRrvOBT11WxJVKerbhfezAJ3naem1eM3VLxCGWwMwxg==
|
||||
-----END CERTIFICATE REQUEST-----`;
|
||||
|
||||
const OUT_EXAMPLE_COM_RSA_2048 = `Version: 1 (0x00)
|
||||
Subject
|
||||
C = CH
|
||||
const OUT_EXAMPLE_COM_RSA_2048 = `Subject
|
||||
C = CH
|
||||
ST = Zurich
|
||||
L = Zurich
|
||||
O = Example RE
|
||||
L = Zurich
|
||||
O = Example RE
|
||||
OU = IT Department
|
||||
CN = example.com
|
||||
Subject Alternative Names
|
||||
DNS: example.com
|
||||
DNS: www.example.com
|
||||
Public Key
|
||||
Algorithm: RSA
|
||||
Length: 2048 bits
|
||||
Modulus: a3:e8:80:b9:96:3e:e2:bf:20:67:5c:b7:6b:ff:dc:c1:
|
||||
4a:55:a5:5e:2a:9d:87:97:96:ad:ff:30:c5:2c:20:1e:
|
||||
e7:56:f0:87:b0:6a:35:52:44:72:2e:00:a7:09:57:03:
|
||||
55:95:99:03:c1:14:12:65:63:04:19:56:3c:f9:50:03:
|
||||
76:0a:63:47:c6:e7:79:9d:5d:37:62:66:76:fc:89:a5:
|
||||
47:3a:4a:71:93:0f:a9:4f:a5:88:90:82:d3:82:fe:5c:
|
||||
86:ce:77:1f:95:cf:9d:9d:17:ef:82:73:e1:6e:48:5a:
|
||||
bc:d3:7c:96:fa:a7:9f:2b:c2:6c:24:d3:bd:2a:e3:f1:
|
||||
44:b6:0a:48:00:03:6b:d3:08:26:2b:2b:bb:53:f3:70:
|
||||
10:0e:72:29:8e:98:d9:c5:5a:ea:3e:2c:ab:1d:e2:55:
|
||||
37:d0:e1:31:0d:d2:87:c2:dc:ad:eb:63:23:d5:cd:e8:
|
||||
94:ed:49:8e:f9:23:b5:65:a3:c0:72:3e:d0:48:13:8e:
|
||||
f9:1e:5e:57:14:61:9b:ef:2e:5c:ac:74:a1:11:31:1a:
|
||||
33:bc:c4:c6:aa:aa:07:58:28:16:97:e4:6a:f5:9e:8f:
|
||||
4e:03:6c:44:ee:02:2a:e8:35:67:09:a1:f3:2e:9a:71:
|
||||
9e:ec:61:bf:dd:6a:bf:07:39:ea:89:9d:cd:29:0a:ff
|
||||
Modulus: 00:a3:e8:80:b9:96:3e:e2:bf:20:67:5c:b7:6b:ff:dc:
|
||||
c1:4a:55:a5:5e:2a:9d:87:97:96:ad:ff:30:c5:2c:20:
|
||||
1e:e7:56:f0:87:b0:6a:35:52:44:72:2e:00:a7:09:57:
|
||||
03:55:95:99:03:c1:14:12:65:63:04:19:56:3c:f9:50:
|
||||
03:76:0a:63:47:c6:e7:79:9d:5d:37:62:66:76:fc:89:
|
||||
a5:47:3a:4a:71:93:0f:a9:4f:a5:88:90:82:d3:82:fe:
|
||||
5c:86:ce:77:1f:95:cf:9d:9d:17:ef:82:73:e1:6e:48:
|
||||
5a:bc:d3:7c:96:fa:a7:9f:2b:c2:6c:24:d3:bd:2a:e3:
|
||||
f1:44:b6:0a:48:00:03:6b:d3:08:26:2b:2b:bb:53:f3:
|
||||
70:10:0e:72:29:8e:98:d9:c5:5a:ea:3e:2c:ab:1d:e2:
|
||||
55:37:d0:e1:31:0d:d2:87:c2:dc:ad:eb:63:23:d5:cd:
|
||||
e8:94:ed:49:8e:f9:23:b5:65:a3:c0:72:3e:d0:48:13:
|
||||
8e:f9:1e:5e:57:14:61:9b:ef:2e:5c:ac:74:a1:11:31:
|
||||
1a:33:bc:c4:c6:aa:aa:07:58:28:16:97:e4:6a:f5:9e:
|
||||
8f:4e:03:6c:44:ee:02:2a:e8:35:67:09:a1:f3:2e:9a:
|
||||
71:9e:ec:61:bf:dd:6a:bf:07:39:ea:89:9d:cd:29:0a:
|
||||
ff
|
||||
Exponent: 65537 (0x10001)
|
||||
Signature
|
||||
Algorithm: sha256WithRSAEncryption
|
||||
Algorithm: SHA256withRSA
|
||||
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:
|
||||
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:
|
||||
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
|
||||
Extensions
|
||||
basicConstraints CRITICAL:
|
||||
Requested Extensions
|
||||
Basic Constraints: critical
|
||||
CA = false
|
||||
keyUsage CRITICAL:
|
||||
Digital signature
|
||||
Key Usage: critical
|
||||
Digital Signature
|
||||
Key encipherment
|
||||
extKeyUsage:
|
||||
TLS Web Server Authentication`;
|
||||
Extended Key Usage:
|
||||
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 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 "keyUsage = critical,digitalSignature,keyEncipherment" \
|
||||
// -addext "extendedKeyUsage = serverAuth"
|
||||
const IN_EXAMPLE_COM_EC = `-----BEGIN CERTIFICATE REQUEST-----
|
||||
const IN_EXAMPLE_COM_EC_P256 = `-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBmzCCAUECAQAwcjELMAkGA1UEBhMCQ0gxDzANBgNVBAgMBlp1cmljaDEPMA0G
|
||||
A1UEBwwGWnVyaWNoMRMwEQYDVQQKDApFeGFtcGxlIFJFMRYwFAYDVQQLDA1JVCBE
|
||||
ZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqG
|
||||
@@ -174,7 +174,690 @@ zj0EAwIDSAAwRQIgQkum/qaLzE3QZ3WD00uLpalUn113FObd7rM5Mr3HQwQCIQCr
|
||||
7OjzYI9v7qIJp/E9N16XfJN87G2ZVIZ4FuPXVjokCQ==
|
||||
-----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([
|
||||
{
|
||||
@@ -184,7 +867,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Parse CSR",
|
||||
"args": ["PEM", true]
|
||||
"args": ["PEM"]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -195,21 +878,107 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"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",
|
||||
input: IN_EXAMPLE_COM_EC,
|
||||
expectedError: true,
|
||||
expectedOutput: OUT_EXAMPLE_COM_EC,
|
||||
input: IN_EXAMPLE_COM_EC_P256,
|
||||
expectedOutput: OUT_EXAMPLE_COM_EC_P256,
|
||||
recipeConfig: [
|
||||
{
|
||||
"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"]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
|
||||
2045
tests/operations/tests/ParseTLSRecord.mjs
Normal file
2045
tests/operations/tests/ParseTLSRecord.mjs
Normal file
File diff suppressed because one or more lines are too long
331
tests/operations/tests/ParseX509CRL.mjs
Normal file
331
tests/operations/tests/ParseX509CRL.mjs
Normal file
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* Parse X.509 CRL tests.
|
||||
*
|
||||
* @author robinsandhu
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
const IN_CRL_PEM_RSA = `-----BEGIN X509 CRL-----
|
||||
MIID7jCCAdYCAQEwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCVUsxDzANBgNV
|
||||
BAgMBkxvbmRvbjELMAkGA1UECgwCQkIxFTATBgNVBAMMDFRlc3QgUm9vdCBDQRcN
|
||||
MjQwODI1MTE0OTEwWhcNMjQwOTI0MTE0OTEwWjA1MDMCAhAAFw0yNDA4MjUwMzIz
|
||||
MDhaMB4wCgYDVR0VBAMKAQYwEAYDVR0XBAkGByqGSM44AgOgggEnMIIBIzAJBgNV
|
||||
HRIEAjAAMH0GA1UdIwR2MHSAFLjJrf2oUFTVhW40i0xgL7BJtodGoUakRDBCMQsw
|
||||
CQYDVQQGEwJVSzEPMA0GA1UECAwGTG9uZG9uMQswCQYDVQQKDAJCQjEVMBMGA1UE
|
||||
AwwMVGVzdCBSb290IENBghQ3XUv2vXwRfMxGGv/XLywm+B5LPTAtBgNVHS4EJjAk
|
||||
MCKgIKAehhxodHRwOi8vZXhhbXBsZS5jb20vZGVsdGEtY3JsMFsGA1UdHwRUMFIw
|
||||
IaAfoB2GG2h0dHA6Ly9leGFtcGxlLmNvbS9mdWxsLWNybDAhoB+gHYYbbGRhcDov
|
||||
L2V4YW1wbGUuY29tL2Z1bGwtY3JsMAqgCKAGhwR/AAABMAsGA1UdFAQEAgIePDAN
|
||||
BgkqhkiG9w0BAQsFAAOCAgEAAxsr+9nELUVWhFekwy6GsqH8xOf6EqGjRaEdX49W
|
||||
mB40m2VajOkK8UHGoVyZzoDI2r/c8OPXUtbpK0fpvEl3SZU5j/C8JbZaZFFrEGeH
|
||||
fSEqdVHFjohpawNcG41Qs+YT21TBqH1hD5yVI7gjVvfKICRfxDpl5oGClxBCVOSV
|
||||
gVtLbe9q44uCBJ1kUkoc9Vz47Hv7JyckgqVXkORWHt2SFNALxlMEzOEQTpuC5Kcb
|
||||
4i7hTCUF+kpkIvr02LJImq0Aaqzs6cC/DcdJiRPPyfaN8fQryFv76gg9i8zZcb6c
|
||||
W42rvumiyw+7nnZfmq53webr5fCHaXhZk47ASOJD6GC5cX9rje1qGRgULXRhqcvK
|
||||
n319s2iXj3FStDDorKGgsCV2zYmotX17ExB98CcCgBE52zMtRZilwhOGeh8mx3qT
|
||||
l0W2B8uKKAq5BMmiziSBzQt700JPiruURZXbQ1fH1n7pKP6wGEh2e9TfQMlN20hE
|
||||
I+CMt+1bG0Bpt5AfiwE8UykQ/WvpVxdJrgj0JM0yA37KfC8XD+cmavJ5/grorbj3
|
||||
t0zBdK7bl+Y45VU/5/mX5ZR3O3ea1RclPM3hKMREfPneOlpan6r3dVwFqEN/TeTu
|
||||
46vuDeKaEr3yJkOFfy0lSYPhPhzhU5vDR5ibxqvwxZNznI2AdTnZLEf8LRqnTVo1
|
||||
qx0=
|
||||
-----END X509 CRL-----`;
|
||||
|
||||
const OUT_CRL_PEM_RSA = `Certificate Revocation List (CRL):
|
||||
Version: 2 (0x1)
|
||||
Signature Algorithm: SHA256withRSA
|
||||
Issuer:
|
||||
C = UK
|
||||
ST = London
|
||||
O = BB
|
||||
CN = Test Root CA
|
||||
Last Update: Sun, 25 Aug 2024 11:49:10 GMT
|
||||
Next Update: Tue, 24 Sep 2024 11:49:10 GMT
|
||||
CRL extensions:
|
||||
2.5.29.46:
|
||||
Unsupported CRL extension. Try openssl CLI.
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:B8:C9:AD:FD:A8:50:54:D5:85:6E:34:8B:4C:60:2F:B0:49:B6:87:46
|
||||
DirName:/C=UK/ST=London/O=BB/CN=Test Root CA
|
||||
serial:37:5D:4B:F6:BD:7C:11:7C:CC:46:1A:FF:D7:2F:2C:26:F8:1E:4B:3D
|
||||
X509v3 CRL Distribution Points:
|
||||
Full Name:
|
||||
URI:http://example.com/full-crl
|
||||
Full Name:
|
||||
URI:ldap://example.com/full-crl
|
||||
Full Name:
|
||||
IP:127.0.0.1
|
||||
X509v3 CRL Number:
|
||||
1E3C
|
||||
issuerAltName:
|
||||
Unsupported CRL extension. Try openssl CLI.
|
||||
Revoked Certificates:
|
||||
Serial Number: 1000
|
||||
Revocation Date: Sun, 25 Aug 2024 03:23:08 GMT
|
||||
CRL entry extensions:
|
||||
X509v3 CRL Reason Code:
|
||||
Certificate Hold
|
||||
Hold Instruction Code:
|
||||
Hold Instruction Reject
|
||||
Signature Value:
|
||||
03:1b:2b:fb:d9:c4:2d:45:56:84:57:a4:c3:2e:86:b2:a1:fc:
|
||||
c4:e7:fa:12:a1:a3:45:a1:1d:5f:8f:56:98:1e:34:9b:65:5a:
|
||||
8c:e9:0a:f1:41:c6:a1:5c:99:ce:80:c8:da:bf:dc:f0:e3:d7:
|
||||
52:d6:e9:2b:47:e9:bc:49:77:49:95:39:8f:f0:bc:25:b6:5a:
|
||||
64:51:6b:10:67:87:7d:21:2a:75:51:c5:8e:88:69:6b:03:5c:
|
||||
1b:8d:50:b3:e6:13:db:54:c1:a8:7d:61:0f:9c:95:23:b8:23:
|
||||
56:f7:ca:20:24:5f:c4:3a:65:e6:81:82:97:10:42:54:e4:95:
|
||||
81:5b:4b:6d:ef:6a:e3:8b:82:04:9d:64:52:4a:1c:f5:5c:f8:
|
||||
ec:7b:fb:27:27:24:82:a5:57:90:e4:56:1e:dd:92:14:d0:0b:
|
||||
c6:53:04:cc:e1:10:4e:9b:82:e4:a7:1b:e2:2e:e1:4c:25:05:
|
||||
fa:4a:64:22:fa:f4:d8:b2:48:9a:ad:00:6a:ac:ec:e9:c0:bf:
|
||||
0d:c7:49:89:13:cf:c9:f6:8d:f1:f4:2b:c8:5b:fb:ea:08:3d:
|
||||
8b:cc:d9:71:be:9c:5b:8d:ab:be:e9:a2:cb:0f:bb:9e:76:5f:
|
||||
9a:ae:77:c1:e6:eb:e5:f0:87:69:78:59:93:8e:c0:48:e2:43:
|
||||
e8:60:b9:71:7f:6b:8d:ed:6a:19:18:14:2d:74:61:a9:cb:ca:
|
||||
9f:7d:7d:b3:68:97:8f:71:52:b4:30:e8:ac:a1:a0:b0:25:76:
|
||||
cd:89:a8:b5:7d:7b:13:10:7d:f0:27:02:80:11:39:db:33:2d:
|
||||
45:98:a5:c2:13:86:7a:1f:26:c7:7a:93:97:45:b6:07:cb:8a:
|
||||
28:0a:b9:04:c9:a2:ce:24:81:cd:0b:7b:d3:42:4f:8a:bb:94:
|
||||
45:95:db:43:57:c7:d6:7e:e9:28:fe:b0:18:48:76:7b:d4:df:
|
||||
40:c9:4d:db:48:44:23:e0:8c:b7:ed:5b:1b:40:69:b7:90:1f:
|
||||
8b:01:3c:53:29:10:fd:6b:e9:57:17:49:ae:08:f4:24:cd:32:
|
||||
03:7e:ca:7c:2f:17:0f:e7:26:6a:f2:79:fe:0a:e8:ad:b8:f7:
|
||||
b7:4c:c1:74:ae:db:97:e6:38:e5:55:3f:e7:f9:97:e5:94:77:
|
||||
3b:77:9a:d5:17:25:3c:cd:e1:28:c4:44:7c:f9:de:3a:5a:5a:
|
||||
9f:aa:f7:75:5c:05:a8:43:7f:4d:e4:ee:e3:ab:ee:0d:e2:9a:
|
||||
12:bd:f2:26:43:85:7f:2d:25:49:83:e1:3e:1c:e1:53:9b:c3:
|
||||
47:98:9b:c6:ab:f0:c5:93:73:9c:8d:80:75:39:d9:2c:47:fc:
|
||||
2d:1a:a7:4d:5a:35:ab:1d`;
|
||||
|
||||
const IN_CRL_PEM_RSA_CRL_REASON_AND_INVALIDITY_DATE = `-----BEGIN X509 CRL-----
|
||||
MIID9jCCAd4CAQEwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCVUsxDzANBgNV
|
||||
BAgMBkxvbmRvbjELMAkGA1UECgwCQkIxFTATBgNVBAMMDFRlc3QgUm9vdCBDQRcN
|
||||
MjQwODI1MTIwODU2WhcNMjQwOTI0MTIwODU2WjA9MDsCAhAAFw0yNDA4MjUxMjA4
|
||||
NDhaMCYwCgYDVR0VBAMKAQEwGAYDVR0YBBEYDzIwMjQwODI1MDAwMDAwWqCCAScw
|
||||
ggEjMAkGA1UdEgQCMAAwfQYDVR0jBHYwdIAUuMmt/ahQVNWFbjSLTGAvsEm2h0ah
|
||||
RqREMEIxCzAJBgNVBAYTAlVLMQ8wDQYDVQQIDAZMb25kb24xCzAJBgNVBAoMAkJC
|
||||
MRUwEwYDVQQDDAxUZXN0IFJvb3QgQ0GCFDddS/a9fBF8zEYa/9cvLCb4Hks9MC0G
|
||||
A1UdLgQmMCQwIqAgoB6GHGh0dHA6Ly9leGFtcGxlLmNvbS9kZWx0YS1jcmwwWwYD
|
||||
VR0fBFQwUjAhoB+gHYYbaHR0cDovL2V4YW1wbGUuY29tL2Z1bGwtY3JsMCGgH6Ad
|
||||
hhtsZGFwOi8vZXhhbXBsZS5jb20vZnVsbC1jcmwwCqAIoAaHBH8AAAEwCwYDVR0U
|
||||
BAQCAh49MA0GCSqGSIb3DQEBCwUAA4ICAQByLp7JWQmB1NhlLACH6zFOe31yCTVy
|
||||
xJQtgujtSri1LNu6IwzBGsKBQIl3ucwMxPvoZzlujNLmshUT3nSogV0/5n1q0Gyj
|
||||
5Yiz2iw8mmKJLmGZ9Oz3QoGxgFww0/0x/VwRHuS2hw+A7JB8tO/2nW3oTclvS55l
|
||||
R+VtkDjUN58+Yl2SQksvb3qD6bHHJTCaP7Dskls0fdBIoYIDvZejrTYSSzTX/Kw4
|
||||
735P0GBMhj7zVF8azGz2PFpSISg4huJMyp7EDKZf2c2dnkuwmEUlPQEBLX25j/Il
|
||||
81OxfVVFja+wUagaGtjEPGy5gsU8zFwkWhjaD5PGBbZvnT+EDsOtJPU7Ot/sBHfz
|
||||
XqUtMrfmz/S/GsQ+QCpnBvarBy9QYuk9M0ePBGy33CUQpjPULxuJJVAHxNoetHCv
|
||||
7udng2Pi4D8vDNfzbMwHt7HurMo0CsSju+cL4rnIfsz02RrD9WC84KxBLWkqC7Hi
|
||||
IKGIpF740Yc4BliVE1HDaOKyI6FEft5asj3OgXwmBw7pVlxSNWACaA2vOFkdN/V5
|
||||
XZZjVJdRJxkgEfCvsJVenFp8ND6gmJmWum7tqM5ytmiXjPtejsPpVq4IclG+Yhnr
|
||||
tFQ9TDEuCrNsRIGGGDodyXq1+kGXY0w8RqGEb7J4Og/M6r4LMAKPkO7e0nEibTqX
|
||||
d2igvR2e5p+yKw==
|
||||
-----END X509 CRL-----`;
|
||||
|
||||
const OUT_CRL_PEM_RSA_CRL_REASON_AND_INVALIDITY_DATE = `Certificate Revocation List (CRL):
|
||||
Version: 2 (0x1)
|
||||
Signature Algorithm: SHA256withRSA
|
||||
Issuer:
|
||||
C = UK
|
||||
ST = London
|
||||
O = BB
|
||||
CN = Test Root CA
|
||||
Last Update: Sun, 25 Aug 2024 12:08:56 GMT
|
||||
Next Update: Tue, 24 Sep 2024 12:08:56 GMT
|
||||
CRL extensions:
|
||||
2.5.29.46:
|
||||
Unsupported CRL extension. Try openssl CLI.
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:B8:C9:AD:FD:A8:50:54:D5:85:6E:34:8B:4C:60:2F:B0:49:B6:87:46
|
||||
DirName:/C=UK/ST=London/O=BB/CN=Test Root CA
|
||||
serial:37:5D:4B:F6:BD:7C:11:7C:CC:46:1A:FF:D7:2F:2C:26:F8:1E:4B:3D
|
||||
X509v3 CRL Distribution Points:
|
||||
Full Name:
|
||||
URI:http://example.com/full-crl
|
||||
Full Name:
|
||||
URI:ldap://example.com/full-crl
|
||||
Full Name:
|
||||
IP:127.0.0.1
|
||||
X509v3 CRL Number:
|
||||
1E3D
|
||||
issuerAltName:
|
||||
Unsupported CRL extension. Try openssl CLI.
|
||||
Revoked Certificates:
|
||||
Serial Number: 1000
|
||||
Revocation Date: Sun, 25 Aug 2024 12:08:48 GMT
|
||||
CRL entry extensions:
|
||||
X509v3 CRL Reason Code:
|
||||
Key Compromise
|
||||
Invalidity Date:
|
||||
Sun, 25 Aug 2024 00:00:00 GMT
|
||||
Signature Value:
|
||||
72:2e:9e:c9:59:09:81:d4:d8:65:2c:00:87:eb:31:4e:7b:7d:
|
||||
72:09:35:72:c4:94:2d:82:e8:ed:4a:b8:b5:2c:db:ba:23:0c:
|
||||
c1:1a:c2:81:40:89:77:b9:cc:0c:c4:fb:e8:67:39:6e:8c:d2:
|
||||
e6:b2:15:13:de:74:a8:81:5d:3f:e6:7d:6a:d0:6c:a3:e5:88:
|
||||
b3:da:2c:3c:9a:62:89:2e:61:99:f4:ec:f7:42:81:b1:80:5c:
|
||||
30:d3:fd:31:fd:5c:11:1e:e4:b6:87:0f:80:ec:90:7c:b4:ef:
|
||||
f6:9d:6d:e8:4d:c9:6f:4b:9e:65:47:e5:6d:90:38:d4:37:9f:
|
||||
3e:62:5d:92:42:4b:2f:6f:7a:83:e9:b1:c7:25:30:9a:3f:b0:
|
||||
ec:92:5b:34:7d:d0:48:a1:82:03:bd:97:a3:ad:36:12:4b:34:
|
||||
d7:fc:ac:38:ef:7e:4f:d0:60:4c:86:3e:f3:54:5f:1a:cc:6c:
|
||||
f6:3c:5a:52:21:28:38:86:e2:4c:ca:9e:c4:0c:a6:5f:d9:cd:
|
||||
9d:9e:4b:b0:98:45:25:3d:01:01:2d:7d:b9:8f:f2:25:f3:53:
|
||||
b1:7d:55:45:8d:af:b0:51:a8:1a:1a:d8:c4:3c:6c:b9:82:c5:
|
||||
3c:cc:5c:24:5a:18:da:0f:93:c6:05:b6:6f:9d:3f:84:0e:c3:
|
||||
ad:24:f5:3b:3a:df:ec:04:77:f3:5e:a5:2d:32:b7:e6:cf:f4:
|
||||
bf:1a:c4:3e:40:2a:67:06:f6:ab:07:2f:50:62:e9:3d:33:47:
|
||||
8f:04:6c:b7:dc:25:10:a6:33:d4:2f:1b:89:25:50:07:c4:da:
|
||||
1e:b4:70:af:ee:e7:67:83:63:e2:e0:3f:2f:0c:d7:f3:6c:cc:
|
||||
07:b7:b1:ee:ac:ca:34:0a:c4:a3:bb:e7:0b:e2:b9:c8:7e:cc:
|
||||
f4:d9:1a:c3:f5:60:bc:e0:ac:41:2d:69:2a:0b:b1:e2:20:a1:
|
||||
88:a4:5e:f8:d1:87:38:06:58:95:13:51:c3:68:e2:b2:23:a1:
|
||||
44:7e:de:5a:b2:3d:ce:81:7c:26:07:0e:e9:56:5c:52:35:60:
|
||||
02:68:0d:af:38:59:1d:37:f5:79:5d:96:63:54:97:51:27:19:
|
||||
20:11:f0:af:b0:95:5e:9c:5a:7c:34:3e:a0:98:99:96:ba:6e:
|
||||
ed:a8:ce:72:b6:68:97:8c:fb:5e:8e:c3:e9:56:ae:08:72:51:
|
||||
be:62:19:eb:b4:54:3d:4c:31:2e:0a:b3:6c:44:81:86:18:3a:
|
||||
1d:c9:7a:b5:fa:41:97:63:4c:3c:46:a1:84:6f:b2:78:3a:0f:
|
||||
cc:ea:be:0b:30:02:8f:90:ee:de:d2:71:22:6d:3a:97:77:68:
|
||||
a0:bd:1d:9e:e6:9f:b2:2b`;
|
||||
|
||||
const IN_CRL_PEM_RSA_CRL_EXTENSIONS = `-----BEGIN X509 CRL-----
|
||||
MIIE0DCCArgCAQEwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCVUsxDzANBgNV
|
||||
BAgMBkxvbmRvbjELMAkGA1UECgwCQkIxFTATBgNVBAMMDFRlc3QgUm9vdCBDQRcN
|
||||
MjQwODI1MTIzNzEwWhcNMjQwOTI0MTIzNzEwWjA9MDsCAhAAFw0yNDA4MjUxMjA4
|
||||
NDhaMCYwCgYDVR0VBAMKAQEwGAYDVR0YBBEYDzIwMjQwODI1MDAwMDAwWqCCAgEw
|
||||
ggH9MIHiBgNVHRIEgdowgdegFAYEKgMEBaAMFgpDdXN0b21OYW1lgQ5jYUBleGFt
|
||||
cGxlLmNvbYYSaHR0cDovL2V4YW1wbGUuY29tgg5jYS5leGFtcGxlLmNvbYcEwKgB
|
||||
AaSBhDCBgTELMAkGA1UEBhMCVVMxFTATBgNVBAgMDEV4YW1wbGVTdGF0ZTEUMBIG
|
||||
A1UEBwwLRXhhbXBsZUNpdHkxEzARBgNVBAoMCkV4YW1wbGVPcmcxFDASBgNVBAsM
|
||||
C0V4YW1wbGVVbml0MRowGAYDVQQDDBFFeGFtcGxlQ29tbW9uTmFtZTB9BgNVHSME
|
||||
djB0gBS4ya39qFBU1YVuNItMYC+wSbaHRqFGpEQwQjELMAkGA1UEBhMCVUsxDzAN
|
||||
BgNVBAgMBkxvbmRvbjELMAkGA1UECgwCQkIxFTATBgNVBAMMDFRlc3QgUm9vdCBD
|
||||
QYIUN11L9r18EXzMRhr/1y8sJvgeSz0wLQYDVR0uBCYwJDAioCCgHoYcaHR0cDov
|
||||
L2V4YW1wbGUuY29tL2RlbHRhLWNybDBbBgNVHR8EVDBSMCGgH6AdhhtodHRwOi8v
|
||||
ZXhhbXBsZS5jb20vZnVsbC1jcmwwIaAfoB2GG2xkYXA6Ly9leGFtcGxlLmNvbS9m
|
||||
dWxsLWNybDAKoAigBocEfwAAATALBgNVHRQEBAICHkIwDQYJKoZIhvcNAQELBQAD
|
||||
ggIBAF/9L4aGmId2igw7+MfDxokevIJkJX/MkmHpXBl1b4hL85FGD7OPCmn47VzC
|
||||
Wejlc/AQB7mWyUugvrVEq/FiCO8a8Fieyjw5uCYz0eiNnuvHVRGM2mOEkiA0I/rn
|
||||
F5AFB1YfCFGXPyRkXNRbOBE91mhOzh1H9PX2qVnj5l3KsPE/7YuteacR0TkfkRJa
|
||||
BXLic+5F/CCV/J/iYR7LncuLUlhBfsosG/ucHL70EytlfX6CBWY3kBbmj7nd497T
|
||||
QG392+m9xp7MIsJAS+3qEzwJAfni6zUV0fWh/ucOl8BIjHEh97VqI3+8yzhdXfkF
|
||||
2gkfpkqJQY0+5OO1VSRYTlQNld3QjN/VVJjatfHyaXfPCx4VEKW1kWYo+0zxO4SL
|
||||
SB/+S/o99bCeNy1MXqEvy5HoDwFHePXGsAEPHWPdj7EWm7g9T/Fl1iSR6hpohvDD
|
||||
K4LaGdVhzvCraLIh8H7XW3KztvZvDQejYQAgADW0UO0rFHJ1XXhKYSqXNGnfDt+3
|
||||
cRpt2XxSxt5HJtHlatiI25PuBMNWV2Zod4RHB/8UEvs1KC7dcwkAiCEY+E3o/zkC
|
||||
rdZ/8XtNf5a4WSN/D7pPsfsO6SE+7lxkJ+UQcZLXAz8b5ArPTlWt2HdJIBEVs25K
|
||||
FAkizyldhnAcNHFk7XN94eTLNeD6hUbFL9pNHiSmKu5A9YW0
|
||||
-----END X509 CRL-----`;
|
||||
|
||||
const OUT_CRL_PEM_RSA_CRL_EXTENSIONS = `Certificate Revocation List (CRL):
|
||||
Version: 2 (0x1)
|
||||
Signature Algorithm: SHA256withRSA
|
||||
Issuer:
|
||||
C = UK
|
||||
ST = London
|
||||
O = BB
|
||||
CN = Test Root CA
|
||||
Last Update: Sun, 25 Aug 2024 12:37:10 GMT
|
||||
Next Update: Tue, 24 Sep 2024 12:37:10 GMT
|
||||
CRL extensions:
|
||||
2.5.29.46:
|
||||
Unsupported CRL extension. Try openssl CLI.
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:B8:C9:AD:FD:A8:50:54:D5:85:6E:34:8B:4C:60:2F:B0:49:B6:87:46
|
||||
DirName:/C=UK/ST=London/O=BB/CN=Test Root CA
|
||||
serial:37:5D:4B:F6:BD:7C:11:7C:CC:46:1A:FF:D7:2F:2C:26:F8:1E:4B:3D
|
||||
X509v3 CRL Distribution Points:
|
||||
Full Name:
|
||||
URI:http://example.com/full-crl
|
||||
Full Name:
|
||||
URI:ldap://example.com/full-crl
|
||||
Full Name:
|
||||
IP:127.0.0.1
|
||||
X509v3 CRL Number:
|
||||
1E42
|
||||
X509v3 Issuer Alternative Name:
|
||||
OtherName:1.2.3.4.5::CustomName
|
||||
EMAIL:ca@example.com
|
||||
URI:http://example.com
|
||||
DNS:ca.example.com
|
||||
IP:192.168.1.1
|
||||
DIR:/C=US/ST=ExampleState/L=ExampleCity/O=ExampleOrg/OU=ExampleUnit/CN=ExampleCommonName
|
||||
Revoked Certificates:
|
||||
Serial Number: 1000
|
||||
Revocation Date: Sun, 25 Aug 2024 12:08:48 GMT
|
||||
CRL entry extensions:
|
||||
X509v3 CRL Reason Code:
|
||||
Key Compromise
|
||||
Invalidity Date:
|
||||
Sun, 25 Aug 2024 00:00:00 GMT
|
||||
Signature Value:
|
||||
5f:fd:2f:86:86:98:87:76:8a:0c:3b:f8:c7:c3:c6:89:1e:bc:
|
||||
82:64:25:7f:cc:92:61:e9:5c:19:75:6f:88:4b:f3:91:46:0f:
|
||||
b3:8f:0a:69:f8:ed:5c:c2:59:e8:e5:73:f0:10:07:b9:96:c9:
|
||||
4b:a0:be:b5:44:ab:f1:62:08:ef:1a:f0:58:9e:ca:3c:39:b8:
|
||||
26:33:d1:e8:8d:9e:eb:c7:55:11:8c:da:63:84:92:20:34:23:
|
||||
fa:e7:17:90:05:07:56:1f:08:51:97:3f:24:64:5c:d4:5b:38:
|
||||
11:3d:d6:68:4e:ce:1d:47:f4:f5:f6:a9:59:e3:e6:5d:ca:b0:
|
||||
f1:3f:ed:8b:ad:79:a7:11:d1:39:1f:91:12:5a:05:72:e2:73:
|
||||
ee:45:fc:20:95:fc:9f:e2:61:1e:cb:9d:cb:8b:52:58:41:7e:
|
||||
ca:2c:1b:fb:9c:1c:be:f4:13:2b:65:7d:7e:82:05:66:37:90:
|
||||
16:e6:8f:b9:dd:e3:de:d3:40:6d:fd:db:e9:bd:c6:9e:cc:22:
|
||||
c2:40:4b:ed:ea:13:3c:09:01:f9:e2:eb:35:15:d1:f5:a1:fe:
|
||||
e7:0e:97:c0:48:8c:71:21:f7:b5:6a:23:7f:bc:cb:38:5d:5d:
|
||||
f9:05:da:09:1f:a6:4a:89:41:8d:3e:e4:e3:b5:55:24:58:4e:
|
||||
54:0d:95:dd:d0:8c:df:d5:54:98:da:b5:f1:f2:69:77:cf:0b:
|
||||
1e:15:10:a5:b5:91:66:28:fb:4c:f1:3b:84:8b:48:1f:fe:4b:
|
||||
fa:3d:f5:b0:9e:37:2d:4c:5e:a1:2f:cb:91:e8:0f:01:47:78:
|
||||
f5:c6:b0:01:0f:1d:63:dd:8f:b1:16:9b:b8:3d:4f:f1:65:d6:
|
||||
24:91:ea:1a:68:86:f0:c3:2b:82:da:19:d5:61:ce:f0:ab:68:
|
||||
b2:21:f0:7e:d7:5b:72:b3:b6:f6:6f:0d:07:a3:61:00:20:00:
|
||||
35:b4:50:ed:2b:14:72:75:5d:78:4a:61:2a:97:34:69:df:0e:
|
||||
df:b7:71:1a:6d:d9:7c:52:c6:de:47:26:d1:e5:6a:d8:88:db:
|
||||
93:ee:04:c3:56:57:66:68:77:84:47:07:ff:14:12:fb:35:28:
|
||||
2e:dd:73:09:00:88:21:18:f8:4d:e8:ff:39:02:ad:d6:7f:f1:
|
||||
7b:4d:7f:96:b8:59:23:7f:0f:ba:4f:b1:fb:0e:e9:21:3e:ee:
|
||||
5c:64:27:e5:10:71:92:d7:03:3f:1b:e4:0a:cf:4e:55:ad:d8:
|
||||
77:49:20:11:15:b3:6e:4a:14:09:22:cf:29:5d:86:70:1c:34:
|
||||
71:64:ed:73:7d:e1:e4:cb:35:e0:fa:85:46:c5:2f:da:4d:1e:
|
||||
24:a6:2a:ee:40:f5:85:b4`;
|
||||
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Parse X.509 CRL: Example PEM encoded CRL with RSA signature",
|
||||
input: IN_CRL_PEM_RSA,
|
||||
expectedOutput: OUT_CRL_PEM_RSA,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Parse X.509 CRL",
|
||||
"args": ["PEM"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Parse X.509 CRL: Example PEM encoded CRL with RSA signature, CRL Reason and Invalidity Date",
|
||||
input: IN_CRL_PEM_RSA_CRL_REASON_AND_INVALIDITY_DATE,
|
||||
expectedOutput: OUT_CRL_PEM_RSA_CRL_REASON_AND_INVALIDITY_DATE,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Parse X.509 CRL",
|
||||
"args": ["PEM"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Parse X.509 CRL: Example PEM encoded CRL with RSA signature and CRL Extensions",
|
||||
input: IN_CRL_PEM_RSA_CRL_EXTENSIONS,
|
||||
expectedOutput: OUT_CRL_PEM_RSA_CRL_EXTENSIONS,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Parse X.509 CRL",
|
||||
"args": ["PEM"]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
@@ -1,62 +1,42 @@
|
||||
/**
|
||||
* Base64 tests.
|
||||
* XXTEA tests.
|
||||
*
|
||||
* @author devcydo [devcydo@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2022
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "XXTEA",
|
||||
name: "XXTEA Encrypt and Decrypt",
|
||||
input: "Hello World! 你好,中国!",
|
||||
expectedOutput: "QncB1C0rHQoZ1eRiPM4dsZtRi9pNrp7sqvX76cFXvrrIHXL6",
|
||||
reecipeConfig: [
|
||||
expectedOutput: "Hello World! 你好,中国!",
|
||||
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: "ნუ პანიკას",
|
||||
expectedOutput: "PbWjnbFmP8Apu2MKOGNbjeW/72IZLlLMS/g82ozLxwE=",
|
||||
reecipeConfig: [
|
||||
expectedOutput: "3db5a39db1663fc029bb630a38635b8de5bfef62192e52cc4bf83cda8ccbc701",
|
||||
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'
|
||||
* 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
|
||||
|
||||
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 MiniCssExtractPlugin = require("mini-css-extract-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");
|
||||
|
||||
/**
|
||||
@@ -12,13 +12,14 @@ const path = require("path");
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
const d = new Date();
|
||||
const banner = `/**
|
||||
* CyberChef - The Cyber Swiss Army Knife
|
||||
*
|
||||
* @copyright Crown Copyright 2016
|
||||
* @copyright Crown Copyright 2016-${d.getUTCFullYear()}
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* Copyright 2016 Crown Copyright
|
||||
* Copyright 2016-${d.getUTCFullYear()} Crown Copyright
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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
|
||||
test: /split\.es\.js$/,
|
||||
modify: (src, path) =>
|
||||
src.replace("if (pixelSize < elementMinSize)", "if (false)")
|
||||
operations: [
|
||||
new ReplaceOperation("once", "if (pixelSize < elementMinSize)", "if (false)")
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -110,7 +112,8 @@ module.exports = {
|
||||
"crypto": require.resolve("crypto-browserify"),
|
||||
"stream": require.resolve("stream-browserify"),
|
||||
"zlib": require.resolve("browserify-zlib"),
|
||||
"process": false
|
||||
"process": false,
|
||||
"vm": false
|
||||
}
|
||||
},
|
||||
module: {
|
||||
|
||||
Reference in New Issue
Block a user