resolve conflicts, merge master

This commit is contained in:
Robin Scholtes 2023-08-15 20:58:24 +12:00
commit e5e82032eb
24 changed files with 1111 additions and 1548 deletions

View file

@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [10.5.0] - 2023-07-14
- Added GOST Encrypt, Decrypt, Sign, Verify, Key Wrap, and Key Unwrap operations [@n1474335] | [#592]
### [10.4.0] - 2023-03-24
- Added 'Generate De Bruijn Sequence' operation [@gchq77703] | [#493]
@ -371,6 +374,7 @@ All major and minor version changes will be documented in this file. Details of
[10.5.0]: https://github.com/gchq/CyberChef/releases/tag/v10.5.0
[10.4.0]: https://github.com/gchq/CyberChef/releases/tag/v10.4.0
[10.3.0]: https://github.com/gchq/CyberChef/releases/tag/v10.3.0
[10.2.0]: https://github.com/gchq/CyberChef/releases/tag/v10.2.0
@ -641,4 +645,5 @@ All major and minor version changes will be documented in this file. Details of
[#1528]: https://github.com/gchq/CyberChef/pull/1528
[#661]: https://github.com/gchq/CyberChef/pull/661
[#493]: https://github.com/gchq/CyberChef/pull/493
[#592]: https://github.com/gchq/CyberChef/issues/592

View file

@ -197,6 +197,7 @@ module.exports = function (grunt) {
},
webpack: {
options: webpackConfig,
myConfig: webpackConfig,
web: webpackProdConf(),
},
"webpack-dev-server": {

109
package-lock.json generated
View file

@ -1,18 +1,19 @@
{
"name": "cyberchef",
"version": "10.4.0",
"version": "10.5.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cyberchef",
"version": "10.4.0",
"version": "10.5.2",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@astronautlabs/amf": "^0.0.6",
"@babel/polyfill": "^7.12.1",
"@blu3r4y/lzma": "^2.3.3",
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
"argon2-browser": "^1.18.0",
"arrive": "^2.4.1",
"avsc": "^5.7.7",
@ -111,7 +112,7 @@
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-transform-builtin-extend": "1.1.2",
"base64-loader": "^1.0.0",
"chromedriver": "^113.0.0",
"chromedriver": "^114.0.2",
"cli-progress": "^3.12.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^11.0.0",
@ -133,7 +134,7 @@
"imports-loader": "^4.0.1",
"mini-css-extract-plugin": "2.7.3",
"modify-source-webpack-plugin": "^3.0.0",
"nightwatch": "^2.6.19",
"nightwatch": "^2.6.16",
"postcss": "^8.4.21",
"postcss-css-variables": "^0.18.0",
"postcss-import": "^15.1.0",
@ -2537,9 +2538,9 @@
}
},
"node_modules/@nightwatch/html-reporter-template": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@nightwatch/html-reporter-template/-/html-reporter-template-0.2.1.tgz",
"integrity": "sha512-GEBeGoXVmTYPtNC4Yq34vfgxf6mlFyEagxpsfH18Qe5BvctF2rprX+wI5dKBm9p5IqHo6ZOcXHCufOeP3cjuOw==",
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/@nightwatch/html-reporter-template/-/html-reporter-template-0.1.4.tgz",
"integrity": "sha512-fVylXypRuNJbyFAwY/5H2QM1A1XVoZWis0zhiMwA5LQN0cxHzpG2aUheb+qP1EfkxhFxwSUHOcrvphFLbPA8ow==",
"dev": true
},
"node_modules/@nodelib/fs.scandir": {
@ -2820,6 +2821,11 @@
"dev": true,
"license": "ISC"
},
"node_modules/@wavesenterprise/crypto-gost-js": {
"version": "2.1.0-RC1",
"resolved": "https://registry.npmjs.org/@wavesenterprise/crypto-gost-js/-/crypto-gost-js-2.1.0-RC1.tgz",
"integrity": "sha512-liAR3/T/vxnEgNUE00Llt+sDvKYqo+sm/L7tqkJorg2ha3SsplOSXAqpH0t4Ya0gRj8qN8zXqO+WwLCxXXuQcw=="
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.1",
"dev": true,
@ -3341,9 +3347,9 @@
}
},
"node_modules/axios": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.15.0",
@ -4369,15 +4375,15 @@
}
},
"node_modules/chromedriver": {
"version": "113.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-113.0.0.tgz",
"integrity": "sha512-UnQlt2kPicYXVNHPzy9HfcWvEbKJjjKAEaatdcnP/lCIRwuSoZFVLH0HVDAGdbraXp3dNVhfE2Qx7gw8TnHnPw==",
"version": "114.0.2",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.2.tgz",
"integrity": "sha512-v0qrXRBknbxqmtklG7RWOe3TJ/dLaHhtB0jVxE7BAdYERxUjEaNRyqBwoGgVfQDibHCB0swzvzsj158nnfPgZw==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"@testim/chrome-version": "^1.1.3",
"axios": "^1.2.1",
"compare-versions": "^5.0.1",
"axios": "^1.4.0",
"compare-versions": "^5.0.3",
"extract-zip": "^2.0.1",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^1.1.0",
@ -4558,9 +4564,9 @@
"license": "MIT"
},
"node_modules/compare-versions": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.1.tgz",
"integrity": "sha512-v8Au3l0b+Nwkp4G142JcgJFh1/TUhdxut7wzD1Nq1dyp5oa3tXaqb03EXOAB6jS4gMlalkjAUPZBMiAfKUixHQ==",
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz",
"integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==",
"dev": true
},
"node_modules/compressible": {
@ -9623,6 +9629,11 @@
"mkdirp": "bin/cmd.js"
}
},
"node_modules/mkpath": {
"version": "1.0.0",
"dev": true,
"license": "MIT"
},
"node_modules/mocha": {
"version": "9.2.2",
"dev": true,
@ -9923,13 +9934,13 @@
}
},
"node_modules/nightwatch": {
"version": "2.6.20",
"resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-2.6.20.tgz",
"integrity": "sha512-XEyxuSGhESdHj4LHqA5snrc/nMgH4tsB/mWrbyGt3EwW1AgjyE7DRzJUbhG7J00Np3Dv3k2nmyJs0Xq0FX/yvQ==",
"version": "2.6.16",
"resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-2.6.16.tgz",
"integrity": "sha512-U24L11WQlYS6TYdGx1h+xMfxw3jjhmoOjYEIBV3WQNwuWqpWzwIaG0gr3WonCwiEgKvSquLSuXhm5vd1U3JdiQ==",
"dev": true,
"dependencies": {
"@nightwatch/chai": "5.0.2",
"@nightwatch/html-reporter-template": "0.2.1",
"@nightwatch/html-reporter-template": "0.1.4",
"ansi-to-html": "0.7.2",
"assertion-error": "1.1.0",
"boxen": "5.1.2",
@ -9950,6 +9961,7 @@
"lodash.pick": "4.4.0",
"minimatch": "3.1.2",
"minimist": "1.2.6",
"mkpath": "1.0.0",
"mocha": "9.2.2",
"nightwatch-axe-verbose": "^2.1.0",
"open": "8.4.0",
@ -11247,8 +11259,9 @@
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"dev": true,
"license": "MIT"
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true
},
"node_modules/psl": {
"version": "1.9.0",
@ -15531,9 +15544,9 @@
}
},
"@nightwatch/html-reporter-template": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@nightwatch/html-reporter-template/-/html-reporter-template-0.2.1.tgz",
"integrity": "sha512-GEBeGoXVmTYPtNC4Yq34vfgxf6mlFyEagxpsfH18Qe5BvctF2rprX+wI5dKBm9p5IqHo6ZOcXHCufOeP3cjuOw==",
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/@nightwatch/html-reporter-template/-/html-reporter-template-0.1.4.tgz",
"integrity": "sha512-fVylXypRuNJbyFAwY/5H2QM1A1XVoZWis0zhiMwA5LQN0cxHzpG2aUheb+qP1EfkxhFxwSUHOcrvphFLbPA8ow==",
"dev": true
},
"@nodelib/fs.scandir": {
@ -15763,6 +15776,11 @@
"version": "1.1.2",
"dev": true
},
"@wavesenterprise/crypto-gost-js": {
"version": "2.1.0-RC1",
"resolved": "https://registry.npmjs.org/@wavesenterprise/crypto-gost-js/-/crypto-gost-js-2.1.0-RC1.tgz",
"integrity": "sha512-liAR3/T/vxnEgNUE00Llt+sDvKYqo+sm/L7tqkJorg2ha3SsplOSXAqpH0t4Ya0gRj8qN8zXqO+WwLCxXXuQcw=="
},
"@webassemblyjs/ast": {
"version": "1.11.1",
"dev": true,
@ -16139,9 +16157,9 @@
"dev": true
},
"axios": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
"dev": true,
"requires": {
"follow-redirects": "^1.15.0",
@ -16828,14 +16846,14 @@
"dev": true
},
"chromedriver": {
"version": "113.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-113.0.0.tgz",
"integrity": "sha512-UnQlt2kPicYXVNHPzy9HfcWvEbKJjjKAEaatdcnP/lCIRwuSoZFVLH0HVDAGdbraXp3dNVhfE2Qx7gw8TnHnPw==",
"version": "114.0.2",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-114.0.2.tgz",
"integrity": "sha512-v0qrXRBknbxqmtklG7RWOe3TJ/dLaHhtB0jVxE7BAdYERxUjEaNRyqBwoGgVfQDibHCB0swzvzsj158nnfPgZw==",
"dev": true,
"requires": {
"@testim/chrome-version": "^1.1.3",
"axios": "^1.2.1",
"compare-versions": "^5.0.1",
"axios": "^1.4.0",
"compare-versions": "^5.0.3",
"extract-zip": "^2.0.1",
"https-proxy-agent": "^5.0.1",
"proxy-from-env": "^1.1.0",
@ -16954,9 +16972,9 @@
"dev": true
},
"compare-versions": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.1.tgz",
"integrity": "sha512-v8Au3l0b+Nwkp4G142JcgJFh1/TUhdxut7wzD1Nq1dyp5oa3tXaqb03EXOAB6jS4gMlalkjAUPZBMiAfKUixHQ==",
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz",
"integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==",
"dev": true
},
"compressible": {
@ -20369,6 +20387,10 @@
"minimist": "^1.2.6"
}
},
"mkpath": {
"version": "1.0.0",
"dev": true
},
"mocha": {
"version": "9.2.2",
"dev": true,
@ -20569,13 +20591,13 @@
"version": "0.6.3"
},
"nightwatch": {
"version": "2.6.20",
"resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-2.6.20.tgz",
"integrity": "sha512-XEyxuSGhESdHj4LHqA5snrc/nMgH4tsB/mWrbyGt3EwW1AgjyE7DRzJUbhG7J00Np3Dv3k2nmyJs0Xq0FX/yvQ==",
"version": "2.6.16",
"resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-2.6.16.tgz",
"integrity": "sha512-U24L11WQlYS6TYdGx1h+xMfxw3jjhmoOjYEIBV3WQNwuWqpWzwIaG0gr3WonCwiEgKvSquLSuXhm5vd1U3JdiQ==",
"dev": true,
"requires": {
"@nightwatch/chai": "5.0.2",
"@nightwatch/html-reporter-template": "0.2.1",
"@nightwatch/html-reporter-template": "0.1.4",
"ansi-to-html": "0.7.2",
"assertion-error": "1.1.0",
"boxen": "5.1.2",
@ -20596,6 +20618,7 @@
"lodash.pick": "4.4.0",
"minimatch": "3.1.2",
"minimist": "1.2.6",
"mkpath": "1.0.0",
"mocha": "9.2.2",
"nightwatch-axe-verbose": "^2.1.0",
"open": "8.4.0",
@ -21432,6 +21455,8 @@
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"dev": true
},
"psl": {

View file

@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "10.4.0",
"version": "10.5.2",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@ -55,7 +55,7 @@
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-transform-builtin-extend": "1.1.2",
"base64-loader": "^1.0.0",
"chromedriver": "^113.0.0",
"chromedriver": "^114.0.2",
"cli-progress": "^3.12.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^11.0.0",
@ -77,7 +77,7 @@
"imports-loader": "^4.0.1",
"mini-css-extract-plugin": "2.7.3",
"modify-source-webpack-plugin": "^3.0.0",
"nightwatch": "^2.6.19",
"nightwatch": "^2.6.16",
"postcss": "^8.4.21",
"postcss-css-variables": "^0.18.0",
"postcss-import": "^15.1.0",
@ -95,6 +95,7 @@
"@astronautlabs/amf": "^0.0.6",
"@babel/polyfill": "^7.12.1",
"@blu3r4y/lzma": "^2.3.3",
"@wavesenterprise/crypto-gost-js": "^2.1.0-RC1",
"argon2-browser": "^1.18.0",
"arrive": "^2.4.1",
"avsc": "^5.7.7",
@ -181,7 +182,7 @@
"build": "npx grunt prod",
"node": "npx grunt node",
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-experimental-fetch --no-warnings src/node/repl.mjs",
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch tests/operations/index.mjs",
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation --openssl-legacy-provider --no-experimental-fetch --trace-uncaught tests/operations/index.mjs",
"testnodeconsumer": "npx grunt testnodeconsumer",
"testui": "npx grunt testui",
"testuidev": "npx nightwatch --env=dev",

View file

@ -91,6 +91,12 @@
"Rabbit",
"SM4 Encrypt",
"SM4 Decrypt",
"GOST Encrypt",
"GOST Decrypt",
"GOST Sign",
"GOST Verify",
"GOST Key Wrap",
"GOST Key Unwrap",
"ROT13",
"ROT13 Brute Force",
"ROT47",
@ -370,7 +376,7 @@
"Snefru",
"BLAKE2b",
"BLAKE2s",
"GOST hash",
"GOST Hash",
"Streebog",
"SSDEEP",
"CTPH",

View file

@ -0,0 +1,138 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { toHexFast, fromHex } from "../lib/Hex.mjs";
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
/**
* GOST Decrypt operation
*/
class GOSTDecrypt extends Operation {
/**
* GOSTDecrypt constructor
*/
constructor() {
super();
this.name = "GOST Decrypt";
this.module = "Ciphers";
this.description = "The GOST block cipher (Magma), defined in the standard GOST 28147-89 (RFC 5830), is a Soviet and Russian government standard symmetric key block cipher with a block size of 64 bits. The original standard, published in 1989, did not give the cipher any name, but the most recent revision of the standard, GOST R 34.12-2015 (RFC 7801, RFC 8891), specifies that it may be referred to as Magma. The GOST hash function is based on this cipher. The new standard also specifies a new 128-bit block cipher called Kuznyechik.<br><br>Developed in the 1970s, the standard had been marked 'Top Secret' and then downgraded to 'Secret' in 1990. Shortly after the dissolution of the USSR, it was declassified and it was released to the public in 1994. GOST 28147 was a Soviet alternative to the United States standard algorithm, DES. Thus, the two are very similar in structure.";
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "IV",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Input type",
type: "option",
value: ["Hex", "Raw"]
},
{
name: "Output type",
type: "option",
value: ["Raw", "Hex"]
},
{
name: "Algorithm",
type: "argSelector",
value: [
{
name: "GOST 28147 (Magma, 1989)",
off: [5],
on: [6]
},
{
name: "GOST R 34.12 (Kuznyechik, 2015)",
on: [5],
off: [6]
}
]
},
{
name: "Block length",
type: "option",
value: ["64", "128"]
},
{
name: "sBox",
type: "option",
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
},
{
name: "Block mode",
type: "option",
value: ["ECB", "CFB", "OFB", "CTR", "CBC"]
},
{
name: "Key meshing mode",
type: "option",
value: ["NO", "CP"]
},
{
name: "Padding",
type: "option",
value: ["NO", "PKCS5", "ZERO", "RANDOM", "BIT"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [keyObj, ivObj, inputType, outputType, version, length, sBox, blockMode, keyMeshing, padding] = args;
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
const sBoxVal = versionNum === 1989 ? sBox : null;
const algorithm = {
version: versionNum,
length: blockLength,
mode: "ES",
sBox: sBoxVal,
block: blockMode,
keyMeshing: keyMeshing,
padding: padding
};
try {
const Hex = CryptoGost.coding.Hex;
if (iv) algorithm.iv = Hex.decode(iv);
const cipher = GostEngine.getGostCipher(algorithm);
const out = Hex.encode(cipher.decrypt(Hex.decode(key), Hex.decode(input)));
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
} catch (err) {
throw new OperationError(err);
}
}
}
export default GOSTDecrypt;

View file

@ -0,0 +1,138 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { toHexFast, fromHex } from "../lib/Hex.mjs";
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
/**
* GOST Encrypt operation
*/
class GOSTEncrypt extends Operation {
/**
* GOSTEncrypt constructor
*/
constructor() {
super();
this.name = "GOST Encrypt";
this.module = "Ciphers";
this.description = "The GOST block cipher (Magma), defined in the standard GOST 28147-89 (RFC 5830), is a Soviet and Russian government standard symmetric key block cipher with a block size of 64 bits. The original standard, published in 1989, did not give the cipher any name, but the most recent revision of the standard, GOST R 34.12-2015 (RFC 7801, RFC 8891), specifies that it may be referred to as Magma. The GOST hash function is based on this cipher. The new standard also specifies a new 128-bit block cipher called Kuznyechik.<br><br>Developed in the 1970s, the standard had been marked 'Top Secret' and then downgraded to 'Secret' in 1990. Shortly after the dissolution of the USSR, it was declassified and it was released to the public in 1994. GOST 28147 was a Soviet alternative to the United States standard algorithm, DES. Thus, the two are very similar in structure.";
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "IV",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Input type",
type: "option",
value: ["Raw", "Hex"]
},
{
name: "Output type",
type: "option",
value: ["Hex", "Raw"]
},
{
name: "Algorithm",
type: "argSelector",
value: [
{
name: "GOST 28147 (Magma, 1989)",
off: [5],
on: [6]
},
{
name: "GOST R 34.12 (Kuznyechik, 2015)",
on: [5],
off: [6]
}
]
},
{
name: "Block length",
type: "option",
value: ["64", "128"]
},
{
name: "sBox",
type: "option",
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
},
{
name: "Block mode",
type: "option",
value: ["ECB", "CFB", "OFB", "CTR", "CBC"]
},
{
name: "Key meshing mode",
type: "option",
value: ["NO", "CP"]
},
{
name: "Padding",
type: "option",
value: ["NO", "PKCS5", "ZERO", "RANDOM", "BIT"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [keyObj, ivObj, inputType, outputType, version, length, sBox, blockMode, keyMeshing, padding] = args;
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
const sBoxVal = versionNum === 1989 ? sBox : null;
const algorithm = {
version: versionNum,
length: blockLength,
mode: "ES",
sBox: sBoxVal,
block: blockMode,
keyMeshing: keyMeshing,
padding: padding
};
try {
const Hex = CryptoGost.coding.Hex;
if (iv) algorithm.iv = Hex.decode(iv);
const cipher = GostEngine.getGostCipher(algorithm);
const out = Hex.encode(cipher.encrypt(Hex.decode(key), Hex.decode(input)));
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
} catch (err) {
throw new OperationError(err);
}
}
}
export default GOSTEncrypt;

View file

@ -20,7 +20,7 @@ class GOSTHash extends Operation {
constructor() {
super();
this.name = "GOST hash";
this.name = "GOST Hash";
this.module = "Hashing";
this.description = "The GOST hash function, defined in the standards GOST R 34.11-94 and GOST 34.311-95 is a 256-bit cryptographic hash function. It was initially defined in the Russian national standard GOST R 34.11-94 <i>Information Technology Cryptographic Information Security Hash Function</i>. The equivalent standard used by other member-states of the CIS is GOST 34.311-95.<br><br>This function must not be confused with a different Streebog hash function, which is defined in the new revision of the standard GOST R 34.11-2012.<br><br>The GOST hash function is based on the GOST block cipher.";
this.infoURL = "https://wikipedia.org/wiki/GOST_(hash_function)";
@ -28,20 +28,30 @@ class GOSTHash extends Operation {
this.outputType = "string";
this.args = [
{
"name": "S-Box",
"type": "option",
"value": [
"D-A",
"D-SC",
"E-TEST",
"E-A",
"E-B",
"E-C",
"E-D",
"E-SC",
"E-Z",
"D-TEST"
name: "Algorithm",
type: "argSelector",
value: [
{
name: "GOST 28147 (1994)",
off: [1],
on: [2]
},
{
name: "GOST R 34.11 (Streebog, 2012)",
on: [1],
off: [2]
}
]
},
{
name: "Digest length",
type: "option",
value: ["256", "512"]
},
{
name: "sBox",
type: "option",
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
}
];
}
@ -52,13 +62,23 @@ class GOSTHash extends Operation {
* @returns {string}
*/
run(input, args) {
const [version, length, sBox] = args;
const versionNum = version === "GOST 28147 (1994)" ? 1994 : 2012;
const algorithm = {
name: versionNum === 1994 ? "GOST 28147" : "GOST R 34.10",
version: versionNum,
mode: "HASH"
};
if (versionNum === 1994) {
algorithm.sBox = sBox;
} else {
algorithm.length = parseInt(length, 10);
}
try {
const sBox = args[1];
const gostDigest = new GostDigest({
name: "GOST R 34.11",
version: 1994,
sBox: sBox
});
const gostDigest = new GostDigest(algorithm);
return toHexFast(gostDigest.digest(input));
} catch (err) {

View file

@ -0,0 +1,129 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { toHexFast, fromHex } from "../lib/Hex.mjs";
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
/**
* GOST Key Unwrap operation
*/
class GOSTKeyUnwrap extends Operation {
/**
* GOSTKeyUnwrap constructor
*/
constructor() {
super();
this.name = "GOST Key Unwrap";
this.module = "Ciphers";
this.description = "A decryptor for keys wrapped using one of the GOST block ciphers.";
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "User Key Material",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Input type",
type: "option",
value: ["Hex", "Raw"]
},
{
name: "Output type",
type: "option",
value: ["Raw", "Hex"]
},
{
name: "Algorithm",
type: "argSelector",
value: [
{
name: "GOST 28147 (Magma, 1989)",
off: [5],
on: [6]
},
{
name: "GOST R 34.12 (Kuznyechik, 2015)",
on: [5],
off: [6]
}
]
},
{
name: "Block length",
type: "option",
value: ["64", "128"]
},
{
name: "sBox",
type: "option",
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
},
{
name: "Key wrapping",
type: "option",
value: ["NO", "CP", "SC"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [keyObj, ukmObj, inputType, outputType, version, length, sBox, keyWrapping] = args;
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
const sBoxVal = versionNum === 1989 ? sBox : null;
const algorithm = {
version: versionNum,
length: blockLength,
mode: "KW",
sBox: sBoxVal,
keyWrapping: keyWrapping
};
try {
const Hex = CryptoGost.coding.Hex;
algorithm.ukm = Hex.decode(ukm);
const cipher = GostEngine.getGostCipher(algorithm);
const out = Hex.encode(cipher.unwrapKey(Hex.decode(key), Hex.decode(input)));
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
} catch (err) {
if (err.toString().includes("Invalid typed array length")) {
throw new OperationError("Incorrect input length. Must be a multiple of the block size.");
}
throw new OperationError(err);
}
}
}
export default GOSTKeyUnwrap;

View file

@ -0,0 +1,129 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { toHexFast, fromHex } from "../lib/Hex.mjs";
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
/**
* GOST Key Wrap operation
*/
class GOSTKeyWrap extends Operation {
/**
* GOSTKeyWrap constructor
*/
constructor() {
super();
this.name = "GOST Key Wrap";
this.module = "Ciphers";
this.description = "A key wrapping algorithm for protecting keys in untrusted storage using one of the GOST block cipers.";
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "User Key Material",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Input type",
type: "option",
value: ["Raw", "Hex"]
},
{
name: "Output type",
type: "option",
value: ["Hex", "Raw"]
},
{
name: "Algorithm",
type: "argSelector",
value: [
{
name: "GOST 28147 (Magma, 1989)",
off: [5],
on: [6]
},
{
name: "GOST R 34.12 (Kuznyechik, 2015)",
on: [5],
off: [6]
}
]
},
{
name: "Block length",
type: "option",
value: ["64", "128"]
},
{
name: "sBox",
type: "option",
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
},
{
name: "Key wrapping",
type: "option",
value: ["NO", "CP", "SC"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [keyObj, ukmObj, inputType, outputType, version, length, sBox, keyWrapping] = args;
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
const ukm = toHexFast(Utils.convertToByteArray(ukmObj.string, ukmObj.option));
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
const sBoxVal = versionNum === 1989 ? sBox : null;
const algorithm = {
version: versionNum,
length: blockLength,
mode: "KW",
sBox: sBoxVal,
keyWrapping: keyWrapping
};
try {
const Hex = CryptoGost.coding.Hex;
algorithm.ukm = Hex.decode(ukm);
const cipher = GostEngine.getGostCipher(algorithm);
const out = Hex.encode(cipher.wrapKey(Hex.decode(key), Hex.decode(input)));
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
} catch (err) {
if (err.toString().includes("Invalid typed array length")) {
throw new OperationError("Incorrect input length. Must be a multiple of the block size.");
}
throw new OperationError(err);
}
}
}
export default GOSTKeyWrap;

View file

@ -0,0 +1,129 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { toHexFast, fromHex } from "../lib/Hex.mjs";
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
/**
* GOST Sign operation
*/
class GOSTSign extends Operation {
/**
* GOSTSign constructor
*/
constructor() {
super();
this.name = "GOST Sign";
this.module = "Ciphers";
this.description = "Sign a plaintext message using one of the GOST block ciphers.";
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "IV",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Input type",
type: "option",
value: ["Raw", "Hex"]
},
{
name: "Output type",
type: "option",
value: ["Hex", "Raw"]
},
{
name: "Algorithm",
type: "argSelector",
value: [
{
name: "GOST 28147 (Magma, 1989)",
off: [5],
on: [6]
},
{
name: "GOST R 34.12 (Kuznyechik, 2015)",
on: [5],
off: [6]
}
]
},
{
name: "Block length",
type: "option",
value: ["64", "128"]
},
{
name: "sBox",
type: "option",
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
},
{
name: "MAC length",
type: "number",
value: 32,
min: 8,
max: 64,
step: 8
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [keyObj, ivObj, inputType, outputType, version, length, sBox, macLength] = args;
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
const sBoxVal = versionNum === 1989 ? sBox : null;
const algorithm = {
version: versionNum,
length: blockLength,
mode: "MAC",
sBox: sBoxVal,
macLength: macLength
};
try {
const Hex = CryptoGost.coding.Hex;
if (iv) algorithm.iv = Hex.decode(iv);
const cipher = GostEngine.getGostCipher(algorithm);
const out = Hex.encode(cipher.sign(Hex.decode(key), Hex.decode(input)));
return outputType === "Hex" ? out : Utils.byteArrayToChars(fromHex(out));
} catch (err) {
throw new OperationError(err);
}
}
}
export default GOSTSign;

View file

@ -0,0 +1,123 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
import { toHexFast } from "../lib/Hex.mjs";
import { CryptoGost, GostEngine } from "@wavesenterprise/crypto-gost-js/index.js";
/**
* GOST Verify operation
*/
class GOSTVerify extends Operation {
/**
* GOSTVerify constructor
*/
constructor() {
super();
this.name = "GOST Verify";
this.module = "Ciphers";
this.description = "Verify the signature of a plaintext message using one of the GOST block ciphers. Enter the signature in the MAC field.";
this.infoURL = "https://wikipedia.org/wiki/GOST_(block_cipher)";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "IV",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "MAC",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
},
{
name: "Input type",
type: "option",
value: ["Raw", "Hex"]
},
{
name: "Algorithm",
type: "argSelector",
value: [
{
name: "GOST 28147 (Magma, 1989)",
off: [5],
on: [6]
},
{
name: "GOST R 34.12 (Kuznyechik, 2015)",
on: [5],
off: [6]
}
]
},
{
name: "Block length",
type: "option",
value: ["64", "128"]
},
{
name: "sBox",
type: "option",
value: ["E-TEST", "E-A", "E-B", "E-C", "E-D", "E-SC", "E-Z", "D-TEST", "D-A", "D-SC"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
async run(input, args) {
const [keyObj, ivObj, macObj, inputType, version, length, sBox] = args;
const key = toHexFast(Utils.convertToByteArray(keyObj.string, keyObj.option));
const iv = toHexFast(Utils.convertToByteArray(ivObj.string, ivObj.option));
const mac = toHexFast(Utils.convertToByteArray(macObj.string, macObj.option));
input = inputType === "Hex" ? input : toHexFast(Utils.strToArrayBuffer(input));
const versionNum = version === "GOST 28147 (Magma, 1989)" ? 1989 : 2015;
const blockLength = versionNum === 1989 ? 64 : parseInt(length, 10);
const sBoxVal = versionNum === 1989 ? sBox : null;
const algorithm = {
version: versionNum,
length: blockLength,
mode: "MAC",
sBox: sBoxVal,
macLength: mac.length * 4
};
try {
const Hex = CryptoGost.coding.Hex;
if (iv) algorithm.iv = Hex.decode(iv);
const cipher = GostEngine.getGostCipher(algorithm);
const out = cipher.verify(Hex.decode(key), Hex.decode(mac), Hex.decode(input));
return out ? "The signature matches" : "The signature does not match";
} catch (err) {
throw new OperationError(err);
}
}
}
export default GOSTVerify;

View file

@ -108,7 +108,7 @@ class GenerateAllHashes extends Operation {
{name: "BLAKE2s-256", algo: (new BLAKE2s), inputType: "arrayBuffer", params: ["256", "Hex", {string: "", option: "UTF8"}]},
{name: "Streebog-256", algo: (new Streebog), inputType: "arrayBuffer", params: ["256"]},
{name: "Streebog-512", algo: (new Streebog), inputType: "arrayBuffer", params: ["512"]},
{name: "GOST", algo: (new GOSTHash), inputType: "arrayBuffer", params: ["D-A"]},
{name: "GOST", algo: (new GOSTHash), inputType: "arrayBuffer", params: ["GOST 28147 (1994)", "256", "D-A"]},
{name: "LM Hash", algo: (new LMHash), inputType: "str", params: []},
{name: "NT Hash", algo: (new NTHash), inputType: "str", params: []},
{name: "SSDEEP", algo: (new SSDEEP()), inputType: "str"},

View file

@ -28,7 +28,7 @@ class Streebog extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Size",
"name": "Digest length",
"type": "option",
"value": ["256", "512"]
}
@ -41,13 +41,16 @@ class Streebog extends Operation {
* @returns {string}
*/
run(input, args) {
try {
const length = parseInt(args[0], 10);
const gostDigest = new GostDigest({
name: "GOST R 34.11",
const [length] = args;
const algorithm = {
version: 2012,
length: length
});
mode: "HASH",
length: parseInt(length, 10)
};
try {
const gostDigest = new GostDigest(algorithm);
return toHexFast(gostDigest.digest(input));
} catch (err) {

View file

@ -1 +0,0 @@
actual mobile device tests go here

View file

@ -1,261 +0,0 @@
/**
* Tests to ensure that the app loads correctly in a reasonable time and that operations can be run.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
const utils = require("./browserUtils.js");
module.exports = {
before: browser => {
browser
.resizeWindow(1280, 800)
.url(browser.launchUrl);
},
"Loading screen": browser => {
// Check that the loading screen appears and then disappears within a reasonable time
browser
.waitForElementVisible("#preloader", 300)
.waitForElementNotPresent("#preloader", 10000);
},
"App loaded": browser => {
browser.useCss();
// Check that various important elements are loaded
browser.expect.element("#operations").to.be.visible;
browser.expect.element("#recipe").to.be.visible;
browser.expect.element("#input").to.be.present;
browser.expect.element("#output").to.be.present;
browser.expect.element(".op-list").to.be.present;
browser.expect.element("#rec-list").to.be.visible;
browser.expect.element("#controls").to.be.visible;
browser.expect.element("#input-text").to.be.visible;
browser.expect.element("#output-text").to.be.visible;
},
"Operations loaded": browser => {
browser.useXpath();
// Check that an operation in every category has been populated
browser.expect.element("//li[contains(@class, 'operation') and text()='To Base64']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='To Binary']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='AES Decrypt']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='PEM to Hex']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Power Set']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Parse IP range']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Remove Diacritics']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Sort']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='To UNIX Timestamp']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Extract dates']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Gzip']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Keccak']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='JSON Beautify']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Detect File Type']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Play Media']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Disassemble x86']").to.be.present;
browser.expect.element("//li[contains(@class, 'operation') and text()='Register']").to.be.present;
},
"Recipe can be run": browser => {
const toHex = "//li[contains(@class, 'operation') and text()='To Hex']";
const op = "#rec-list .operation .op-title";
// Check that operation is visible
browser
.useXpath()
.expect.element(toHex).to.be.visible;
// Add it to the recipe by double clicking
browser
.useXpath()
.moveToElement(toHex, 10, 10)
.useCss()
.waitForElementVisible(".popover-body", 1000)
.doubleClick("xpath", toHex);
// Confirm that it has been added to the recipe
browser
.useCss()
.waitForElementVisible(op, 100)
.expect.element(op).text.to.contain("To Hex");
// Enter input
browser
.useCss()
.sendKeys("#input-text .cm-content", "Don't Panic.")
.pause(1000)
.click("#bake");
// Check output
browser
.useCss()
.waitForElementNotVisible("#stale-indicator", 1000)
.expect.element("#output-text .cm-content").text.that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e");
// Clear recipe
browser
.useCss()
.moveToElement(op, 10, 10)
.waitForElementNotPresent(".popover-body", 1000)
.click("#clr-recipe")
.waitForElementNotPresent(op);
},
"Test every module": browser => {
browser.useCss();
// BSON
loadOp("BSON deserialise", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Charts
loadOp("Entropy", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Ciphers
loadOp("AES Encrypt", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Code
loadOp("XPath expression", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Compression
loadOp("Gzip", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Crypto
loadOp("MD5", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Default
loadOp("Fork", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Diff
loadOp("Diff", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Encodings
loadOp("Encode text", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Hashing
loadOp("Streebog", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Image
loadOp("Extract EXIF", browser)
.waitForElementNotVisible("#output-loader", 5000);
// PGP
loadOp("PGP Encrypt", browser)
.waitForElementNotVisible("#output-loader", 5000);
// PublicKey
loadOp("Hex to PEM", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Regex
loadOp("Strings", browser)
.waitForElementNotVisible("#output-loader", 5000);
// Shellcode
loadOp("Disassemble x86", browser)
.waitForElementNotVisible("#output-loader", 5000);
// URL
loadOp("URL Encode", browser)
.waitForElementNotVisible("#output-loader", 5000);
// UserAgent
loadOp("Parse User Agent", browser)
.waitForElementNotVisible("#output-loader", 5000);
// YARA
loadOp("YARA Rules", browser)
.waitForElementNotVisible("#output-loader", 5000);
browser.click("#clr-recipe");
},
"Move around the UI": browser => {
const otherCat = "//a[contains(@class, 'category-title') and contains(@data-target, '#catOther')]",
genUUID = "//li[contains(@class, 'operation') and text()='Generate UUID']";
browser.useXpath();
// Scroll to a lower category
browser
.getLocationInView(otherCat)
.expect.element(otherCat).to.be.visible;
// Open category
browser
.click(otherCat)
.expect.element(genUUID).to.be.visible;
// Add op to recipe
/* mouseButtonUp drops wherever the actual cursor is, not necessarily in the right place,
so we can't test Sortable.js properly using Nightwatch. html-dnd doesn't work either.
Instead of relying on drag and drop, we double click on the op to load it. */
browser
.getLocationInView(genUUID)
.moveToElement(genUUID, 10, 10)
.doubleClick("xpath", genUUID)
.useCss()
.waitForElementVisible(".operation .op-title", 1000)
.waitForElementNotVisible("#stale-indicator", 1000)
.expect.element("#output-text .cm-content").text.which.matches(/[\da-f-]{36}/);
browser.click("#clr-recipe");
},
"Search": browser => {
// Search for an op
browser
.useCss()
.clearValue("#search")
.setValue("#search", "md5")
.useXpath()
.waitForElementVisible("//ul[@id='search-results']//b[text()='MD5']", 1000);
},
"Alert bar": browser => {
// Bake nothing to create an empty output which can be copied
utils.clear(browser);
utils.bake(browser);
// Alert bar shows and contains correct content
browser
.click("#copy-output")
.waitForElementVisible("#snackbar-container")
.waitForElementVisible("#snackbar-container .snackbar-content")
.expect.element("#snackbar-container .snackbar-content").text.to.equal("Copied raw output successfully.");
// Alert bar disappears after the correct amount of time
// Should disappear after 2000ms
browser
.waitForElementNotPresent("#snackbar-container .snackbar-content", 2500)
.waitForElementNotVisible("#snackbar-container");
},
after: browser => {
browser.end();
}
};
/**
* Clears the current recipe and loads a new operation.
*
* @param {string} opName
* @param {Browser} browser
*/
function loadOp(opName, browser) {
return browser
.useCss()
.click("#clr-recipe")
.urlHash("op=" + opName);
}

View file

@ -1,704 +0,0 @@
/**
* Tests for input and output of various types to ensure the editors work as expected
* and retain data integrity, especially when it comes to special characters.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
// import {
// clear,
// utils.setInput,
// bake,
// setChrEnc,
// setEOLSeq,
// copy,
// paste,
// loadRecipe,
// expectOutput,
// uploadFile,
// uploadFolder
// } from "./browserUtils.js";
const utils = require("./browserUtils.js");
const SPECIAL_CHARS = [
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f",
"\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f",
"\u007f",
"\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f",
"\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f",
"\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9\ufffa\ufffb\ufffc"
].join("");
const ALL_BYTES = [
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f",
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f",
"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f",
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f",
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f",
"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f",
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f",
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f",
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf",
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf",
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf",
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf",
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef",
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
].join("");
const PUA_CHARS = "\ue000\ue001\uf8fe\uf8ff";
const MULTI_LINE_STRING =`"You know," said Arthur, "it's at times like this, when I'm trapped in a Vogon airlock with a man from Betelgeuse, and about to die of asphyxiation in deep space that I really wish I'd listened to what my mother told me when I was young."
"Why, what did she tell you?"
"I don't know, I didn't listen."`;
const SELECTABLE_STRING = `ONE
two
ONE
three
ONE
four
ONE`;
// Descriptions for named control characters
const CONTROL_CHAR_NAMES = {
0: "null",
7: "bell",
8: "backspace",
10: "line feed",
11: "vertical tab",
13: "carriage return",
27: "escape",
8203: "zero width space",
8204: "zero width non-joiner",
8205: "zero width joiner",
8206: "left-to-right mark",
8207: "right-to-left mark",
8232: "line separator",
8237: "left-to-right override",
8238: "right-to-left override",
8294: "left-to-right isolate",
8295: "right-to-left isolate",
8297: "pop directional isolate",
8233: "paragraph separator",
65279: "zero width no-break space",
65532: "object replacement"
};
module.exports = {
before: browser => {
browser
.resizeWindow(1280, 800)
.url(browser.launchUrl)
.useCss()
.waitForElementNotPresent("#preloader", 10000)
.click("#auto-bake-label");
},
"CodeMirror has loaded correctly": browser => {
/* Editor has initialised */
browser
.useCss()
// Input
.waitForElementVisible("#input-text")
.waitForElementVisible("#input-text .cm-editor")
.waitForElementVisible("#input-text .cm-editor .cm-scroller")
.waitForElementVisible("#input-text .cm-editor .cm-scroller .cm-content")
.waitForElementVisible("#input-text .cm-editor .cm-scroller .cm-content .cm-line")
// Output
.waitForElementVisible("#output-text")
.waitForElementVisible("#output-text .cm-editor")
.waitForElementVisible("#output-text .cm-editor .cm-scroller")
.waitForElementVisible("#output-text .cm-editor .cm-scroller .cm-content")
.waitForElementVisible("#output-text .cm-editor .cm-scroller .cm-content .cm-line");
/* Status bar is showing and has correct values */
browser // Input
.waitForElementVisible("#input-text .cm-status-bar")
.waitForElementVisible("#input-text .cm-status-bar .stats-length-value")
.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("0");
browser.waitForElementVisible("#input-text .cm-status-bar .stats-lines-value")
.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("1");
browser.waitForElementVisible("#input-text .cm-status-bar .chr-enc-value")
.expect.element("#input-text .cm-status-bar .chr-enc-value").text.to.equal("Raw Bytes");
browser.waitForElementVisible("#input-text .cm-status-bar .eol-value")
.expect.element("#input-text .cm-status-bar .eol-value").text.to.equal("LF");
browser // Output
.waitForElementVisible("#output-text .cm-status-bar")
.waitForElementVisible("#output-text .cm-status-bar .stats-length-value")
.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("0");
browser.waitForElementVisible("#output-text .cm-status-bar .stats-lines-value")
.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("1");
browser.waitForElementVisible("#output-text .cm-status-bar .baking-time-info")
.expect.element("#output-text .cm-status-bar .baking-time-info").text.to.contain("ms");
browser.waitForElementVisible("#output-text .cm-status-bar .chr-enc-value")
.expect.element("#output-text .cm-status-bar .chr-enc-value").text.to.equal("Raw Bytes");
browser.waitForElementVisible("#output-text .cm-status-bar .eol-value")
.expect.element("#output-text .cm-status-bar .eol-value").text.to.equal("LF");
},
"Adding content": browser => {
/* Status bar updates correctly */
utils.setInput(browser, MULTI_LINE_STRING);
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("3");
browser.expect.element("#input-text .cm-status-bar .chr-enc-value").text.to.equal("Raw Bytes");
browser.expect.element("#input-text .cm-status-bar .eol-value").text.to.equal("LF");
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("0");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("1");
browser.expect.element("#output-text .cm-status-bar .baking-time-info").text.to.contain("ms");
browser.expect.element("#output-text .cm-status-bar .chr-enc-value").text.to.equal("Raw Bytes");
browser.expect.element("#output-text .cm-status-bar .eol-value").text.to.equal("LF");
/* Output updates correctly */
utils.bake(browser);
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("3");
browser.expect.element("#output-text .cm-status-bar .baking-time-info").text.to.contain("ms");
browser.expect.element("#output-text .cm-status-bar .chr-enc-value").text.to.equal("Raw Bytes");
browser.expect.element("#output-text .cm-status-bar .eol-value").text.to.equal("LF");
},
"Special content": browser => {
/* Special characters are rendered correctly */
utils.setInput(browser, SPECIAL_CHARS, false);
// First line
for (let i = 0x0; i <= 0x8; i++) {
browser.expect.element(`#input-text .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(${i+1})`)
.to.have.property("title").equals(`Control character ${CONTROL_CHAR_NAMES[i] || "0x" + i.toString(16)}`);
browser.expect.element(`#input-text .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(${i+1})`)
.text.to.equal(String.fromCharCode(0x2400 + i));
}
// Tab \u0009
browser.expect.element(`#input-text .cm-line:nth-of-type(1)`).to.have.property("textContent").match(/\u0009$/);
// Line feed \u000a
browser.expect.element(`#input-text .cm-line:nth-of-type(1)`).to.have.property("textContent").match(/^.{10}$/);
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("2");
// Second line
for (let i = 0x0b; i < SPECIAL_CHARS.length; i++) {
const index = SPECIAL_CHARS.charCodeAt(i);
const name = CONTROL_CHAR_NAMES[index] || "0x" + index.toString(16);
const value = index >= 32 ? "\u2022" : String.fromCharCode(0x2400 + index);
browser.expect.element(`#input-text .cm-line:nth-of-type(2) .cm-specialChar:nth-of-type(${i-10})`)
.to.have.property("title").equals(`Control character ${name}`);
browser.expect.element(`#input-text .cm-line:nth-of-type(2) .cm-specialChar:nth-of-type(${i-10})`)
.text.to.equal(value);
}
/* Output renders correctly */
utils.setChrEnc(browser, "output", "UTF-8");
utils.bake(browser);
// First line
for (let i = 0x0; i <= 0x8; i++) {
browser.expect.element(`#output-text .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(${i+1})`)
.to.have.property("title").equals(`Control character ${CONTROL_CHAR_NAMES[i] || "0x" + i.toString(16)}`);
browser.expect.element(`#output-text .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(${i+1})`)
.text.to.equal(String.fromCharCode(0x2400 + i));
}
// Tab \u0009
browser.expect.element(`#output-text .cm-line:nth-of-type(1)`).to.have.property("textContent").match(/\u0009$/);
// Line feed \u000a
browser.expect.element(`#output-text .cm-line:nth-of-type(1)`).to.have.property("textContent").match(/^.{10}$/);
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("2");
// Second line
for (let i = 0x0b; i < SPECIAL_CHARS.length; i++) {
const index = SPECIAL_CHARS.charCodeAt(i);
const name = CONTROL_CHAR_NAMES[index] || "0x" + index.toString(16);
const value = index >= 32 ? "\u2022" : String.fromCharCode(0x2400 + index);
browser.expect.element(`#output-text .cm-content .cm-line:nth-of-type(2) .cm-specialChar:nth-of-type(${i-10})`)
.to.have.property("title").equals(`Control character ${name}`);
browser.expect.element(`#output-text .cm-content .cm-line:nth-of-type(2) .cm-specialChar:nth-of-type(${i-10})`)
.text.to.equal(value);
}
/* Bytes are rendered correctly */
utils.setInput(browser, ALL_BYTES, false);
// Expect length to be 255, since one character is creating a newline
browser.expect.element(`#input-text .cm-content`).to.have.property("textContent").match(/^.{255}$/);
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("256");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("2");
/* PUA \ue000-\uf8ff */
utils.setInput(browser, PUA_CHARS, false);
utils.setChrEnc(browser, "output", "UTF-8");
utils.bake(browser);
// Confirm input and output as expected
/* In order to render whitespace characters as control character pictures in the output, even
when they are the designated line separator, CyberChef sometimes chooses to represent them
internally using the Unicode Private Use Area (https://en.wikipedia.org/wiki/Private_Use_Areas).
See `Utils.escapeWhitespace()` for an example of this.
Therefore, PUA characters should be rendered normally in the Input but as control character
pictures in the output.
*/
browser.expect.element(`#input-text .cm-content`).to.have.property("textContent").match(/^\ue000\ue001\uf8fe\uf8ff$/);
browser.expect.element(`#output-text .cm-content`).to.have.property("textContent").match(/^\u2400\u2401\u3cfe\u3cff$/);
/* Can be copied */
utils.setInput(browser, SPECIAL_CHARS, false);
utils.setChrEnc(browser, "output", "UTF-8");
utils.bake(browser);
// Manual copy
browser
.doubleClick("#output-text .cm-content .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(1)")
.waitForElementVisible("#output-text .cm-selectionBackground");
utils.copy(browser);
utils.paste(browser, "#search"); // Paste into search box as this won't mess with the values
// Ensure that the values are as expected
browser.expect.element("#search").to.have.value.that.equals("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008");
browser.clearValue("#search");
// Raw copy
browser
.click("#copy-output")
.pause(100);
utils.paste(browser, "#search"); // Paste into search box as this won't mess with the values
// Ensure that the values are as expected
browser.expect.element("#search").to.have.value.that.matches(/^\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009/);
browser.clearValue("#search");
},
"HTML output": browser => {
/* Displays correctly */
utils.loadRecipe(browser, "Entropy", ALL_BYTES);
utils.bake(browser);
browser
.waitForElementVisible("#output-html")
.waitForElementVisible("#output-html #chart-area");
/* Status bar widgets are disabled */
browser.expect.element("#output-text .cm-status-bar .disabled .stats-length-value").to.be.visible;
browser.expect.element("#output-text .cm-status-bar .disabled .stats-lines-value").to.be.visible;
browser.expect.element("#output-text .cm-status-bar .disabled .chr-enc-value").to.be.visible;
browser.expect.element("#output-text .cm-status-bar .disabled .eol-value").to.be.visible;
/* Displays special chars correctly */
utils.loadRecipe(browser, "To Table", ",\u0000\u0001\u0002\u0003\u0004", [",", "\\r\\n", false, "HTML"]);
utils.bake(browser);
for (let i = 0x0; i <= 0x4; i++) {
browser.expect.element(`#output-html .cm-specialChar:nth-of-type(${i+1})`)
.to.have.property("title").equals(`Control character ${CONTROL_CHAR_NAMES[i] || "0x" + i.toString(16)}`);
browser.expect.element(`#output-html .cm-specialChar:nth-of-type(${i+1})`)
.text.to.equal(String.fromCharCode(0x2400 + i));
}
/* Can be copied */
// Raw copy
browser
.click("#copy-output")
.pause(100);
utils.paste(browser, "#search"); // Paste into search box as this won't mess with the values
// Ensure that the values are as expected
browser.expect.element("#search").to.have.value.that.matches(/\u0000\u0001\u0002\u0003\u0004/);
browser.clearValue("#search");
},
"Highlighting": browser => {
utils.setInput(browser, SELECTABLE_STRING);
utils.bake(browser);
/* Selecting input text also selects other instances in input and output */
browser // Input
.click("#auto-bake-label")
.doubleClick("#input-text .cm-content .cm-line:nth-of-type(1)")
.waitForElementVisible("#input-text .cm-selectionLayer .cm-selectionBackground")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(1) .cm-selectionMatch")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(2) .cm-selectionMatch")
.waitForElementVisible("#input-text .cm-content .cm-line:nth-of-type(3) .cm-selectionMatch")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(4) .cm-selectionMatch")
.waitForElementVisible("#input-text .cm-content .cm-line:nth-of-type(5) .cm-selectionMatch")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(6) .cm-selectionMatch")
.waitForElementVisible("#input-text .cm-content .cm-line:nth-of-type(7) .cm-selectionMatch");
browser // Output
.waitForElementVisible("#output-text .cm-selectionLayer .cm-selectionBackground")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(1) .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(2) .cm-selectionMatch")
.waitForElementVisible("#output-text .cm-content .cm-line:nth-of-type(3) .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(4) .cm-selectionMatch")
.waitForElementVisible("#output-text .cm-content .cm-line:nth-of-type(5) .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(6) .cm-selectionMatch")
.waitForElementVisible("#output-text .cm-content .cm-line:nth-of-type(7) .cm-selectionMatch");
/* Selecting output text highlights in input */
browser // Output
.click("#output-text")
.waitForElementNotPresent("#input-text .cm-selectionLayer .cm-selectionBackground")
.waitForElementNotPresent("#output-text .cm-selectionLayer .cm-selectionBackground")
.waitForElementNotPresent("#input-text .cm-content .cm-line .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line .cm-selectionMatch")
.doubleClick("#output-text .cm-content .cm-line:nth-of-type(7)")
.waitForElementVisible("#output-text .cm-selectionLayer .cm-selectionBackground")
.waitForElementVisible("#output-text .cm-content .cm-line:nth-of-type(1) .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(2) .cm-selectionMatch")
.waitForElementVisible("#output-text .cm-content .cm-line:nth-of-type(3) .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(4) .cm-selectionMatch")
.waitForElementVisible("#output-text .cm-content .cm-line:nth-of-type(5) .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(6) .cm-selectionMatch")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(7) .cm-selectionMatch");
browser // Input
.waitForElementVisible("#input-text .cm-selectionLayer .cm-selectionBackground")
.waitForElementVisible("#input-text .cm-content .cm-line:nth-of-type(1) .cm-selectionMatch")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(2) .cm-selectionMatch")
.waitForElementVisible("#input-text .cm-content .cm-line:nth-of-type(3) .cm-selectionMatch")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(4) .cm-selectionMatch")
.waitForElementVisible("#input-text .cm-content .cm-line:nth-of-type(5) .cm-selectionMatch")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(6) .cm-selectionMatch")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(7) .cm-selectionMatch");
// Turn autobake off again
browser.click("#auto-bake-label");
},
"Character encoding": browser => {
const CHINESE_CHARS = "不要恐慌。";
/* Dropup works */
/* Selecting changes output correctly */
utils.setInput(browser, CHINESE_CHARS, false);
utils.setChrEnc(browser, "input", "UTF-8");
utils.bake(browser);
utils.expectOutput(browser, "\u00E4\u00B8\u008D\u00E8\u00A6\u0081\u00E6\u0081\u0090\u00E6\u0085\u008C\u00E3\u0080\u0082");
/* Changing output to match input works as expected */
utils.setChrEnc(browser, "output", "UTF-8");
utils.bake(browser);
utils.expectOutput(browser, CHINESE_CHARS);
/* Encodings appear in the URL */
browser.assert.urlContains("ienc=65001");
browser.assert.urlContains("oenc=65001");
/* Preserved when changing tabs */
browser
.click("#btn-new-tab")
.waitForElementVisible("#input-tabs li:nth-of-type(2).active-input-tab");
browser.expect.element("#input-text .chr-enc-value").text.that.equals("Raw Bytes");
browser.expect.element("#output-text .chr-enc-value").text.that.equals("Raw Bytes");
utils.setChrEnc(browser, "input", "UTF-7");
utils.setChrEnc(browser, "output", "UTF-7");
browser
.click("#input-tabs li:nth-of-type(1)")
.waitForElementVisible("#input-tabs li:nth-of-type(1).active-input-tab");
browser.expect.element("#input-text .chr-enc-value").text.that.equals("UTF-8");
browser.expect.element("#output-text .chr-enc-value").text.that.equals("UTF-8");
/* Try various encodings */
// These are not meant to be realistic encodings for this data
utils.setInput(browser, CHINESE_CHARS, false);
utils.setChrEnc(browser, "input", "UTF-8");
utils.setChrEnc(browser, "output", "UTF-16LE");
utils.bake(browser);
utils.expectOutput(browser, "\uB8E4\uE88D\u81A6\u81E6\uE690\u8C85\u80E3");
utils.setChrEnc(browser, "output", "Simplified Chinese GBK");
utils.bake(browser);
utils.expectOutput(browser, "\u6D93\u5D88\uFDFF\u93AD\u612D\u53A1\u9286\u0000");
utils.setChrEnc(browser, "input", "UTF-7");
utils.bake(browser);
utils.expectOutput(browser, "+Tg0-+iYE-+YFA-+YUw-");
utils.setChrEnc(browser, "input", "Traditional Chinese Big5");
utils.bake(browser);
utils.expectOutput(browser, "\u3043\u74B6\uFDFF\u7A3A\uFDFF");
utils.setChrEnc(browser, "output", "Windows-1251 Cyrillic");
utils.bake(browser);
utils.expectOutput(browser, "\u00A4\u0408\u00ADn\u00AE\u0408\u00B7W\u040EC");
},
"Line endings": browser => {
/* Dropup works */
/* Selecting changes view in input */
utils.setInput(browser, MULTI_LINE_STRING);
// Line endings: LF
// Input
browser
.waitForElementPresent("#input-text .cm-content .cm-line:nth-of-type(3)")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(4)")
.waitForElementNotPresent("#input-text .cm-content .cm-specialChar");
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("3");
// Output
utils.bake(browser);
browser
.waitForElementPresent("#output-text .cm-content .cm-line:nth-of-type(3)")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(4)")
.waitForElementNotPresent("#output-text .cm-content .cm-specialChar");
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("3");
// Input EOL: VT
utils.setEOLSeq(browser, "input", "VT");
// Input
browser
.waitForElementPresent("#input-text .cm-content .cm-line:nth-of-type(1)")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(2)")
.waitForElementPresent("#input-text .cm-content .cm-specialChar");
browser.expect.element("#input-text .cm-content .cm-specialChar").text.to.equal("␊");
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("1");
// Output
utils.bake(browser);
browser
.waitForElementPresent("#output-text .cm-content .cm-line:nth-of-type(3)")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(4)")
.waitForElementNotPresent("#output-text .cm-content .cm-specialChar");
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("3");
// Output EOL: VT
utils.setEOLSeq(browser, "output", "VT");
// Input
browser
.waitForElementPresent("#input-text .cm-content .cm-line:nth-of-type(1)")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(2)")
.waitForElementPresent("#input-text .cm-content .cm-specialChar");
browser.expect.element("#input-text .cm-content .cm-specialChar").text.to.equal("␊");
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("1");
// Output
browser
.waitForElementPresent("#output-text .cm-content .cm-line:nth-of-type(1)")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(2)")
.waitForElementPresent("#output-text .cm-content .cm-specialChar");
browser.expect.element("#output-text .cm-content .cm-specialChar").text.to.equal("␊");
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("301");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("1");
/* Adding new line ending changes output correctly */
browser.sendKeys("#input-text .cm-content", browser.Keys.RETURN);
// Input
browser
.waitForElementPresent("#input-text .cm-content .cm-line:nth-of-type(2)")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(3)");
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("302");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("2");
// Output
utils.bake(browser);
browser
.waitForElementPresent("#output-text .cm-content .cm-line:nth-of-type(2)")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(3)");
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("302");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("2");
// Input EOL: CRLF
utils.setEOLSeq(browser, "input", "CRLF");
// Output EOL: CR
utils.setEOLSeq(browser, "output", "CR");
browser.sendKeys("#input-text .cm-content", browser.Keys.RETURN);
// Input
browser
.waitForElementPresent("#input-text .cm-content .cm-line:nth-of-type(2)")
.waitForElementNotPresent("#input-text .cm-content .cm-line:nth-of-type(3)")
.waitForElementPresent("#input-text .cm-content .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(3)");
browser.expect.element("#input-text .cm-content .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(3)").text.to.equal("␋");
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("304");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("2");
// Output
utils.bake(browser);
browser
.waitForElementPresent("#output-text .cm-content .cm-line:nth-of-type(2)")
.waitForElementNotPresent("#output-text .cm-content .cm-line:nth-of-type(3)")
.waitForElementPresent("#output-text .cm-content .cm-line:nth-of-type(2) .cm-specialChar");
browser.expect.element("#output-text .cm-content .cm-line:nth-of-type(2) .cm-specialChar").text.to.equal("␊");
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("304");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("2");
/* Line endings appear in the URL */
browser.assert.urlContains("ieol=%0D%0A");
browser.assert.urlContains("oeol=%0D");
/* Preserved when changing tabs */
browser
.click("#btn-new-tab")
.waitForElementVisible("#input-tabs li:nth-of-type(2).active-input-tab");
browser.expect.element("#input-text .eol-value").text.that.equals("LF");
browser.expect.element("#output-text .eol-value").text.that.equals("LF");
utils.setEOLSeq(browser, "input", "FF");
utils.setEOLSeq(browser, "output", "LS");
browser
.click("#input-tabs li:nth-of-type(1)")
.waitForElementVisible("#input-tabs li:nth-of-type(1).active-input-tab");
browser.expect.element("#input-text .eol-value").text.that.equals("CRLF");
browser.expect.element("#output-text .eol-value").text.that.equals("CR");
},
"File inputs": browser => {
utils.clear(browser);
/* Side panel displays correct info */
utils.uploadFile(browser, "files/TowelDay.jpeg");
browser
.waitForElementVisible("#input-text .cm-file-details")
.waitForElementVisible("#input-text .cm-file-details .file-details-toggle-shown")
.waitForElementVisible("#input-text .cm-file-details .file-details-thumbnail")
.waitForElementVisible("#input-text .cm-file-details .file-details-name")
.waitForElementVisible("#input-text .cm-file-details .file-details-size")
.waitForElementVisible("#input-text .cm-file-details .file-details-type")
.waitForElementVisible("#input-text .cm-file-details .file-details-loaded");
browser.expect.element("#input-text .cm-file-details .file-details-name").text.that.equals("TowelDay.jpeg");
browser.expect.element("#input-text .cm-file-details .file-details-size").text.that.equals("61,379 bytes");
browser.expect.element("#input-text .cm-file-details .file-details-type").text.that.equals("image/jpeg");
browser.expect.element("#input-text .cm-file-details .file-details-loaded").text.that.equals("100%");
/* Side panel can be hidden */
browser
.click("#input-text .cm-file-details .file-details-toggle-shown")
.waitForElementNotPresent("#input-text .cm-file-details .file-details-toggle-shown")
.waitForElementVisible("#input-text .cm-file-details .file-details-toggle-hidden")
.expect.element("#input-text .cm-file-details").to.have.css("width").which.equals("1px");
browser
.click("#input-text .cm-file-details .file-details-toggle-hidden")
.waitForElementNotPresent("#input-text .cm-file-details .file-details-toggle-hidden")
.waitForElementVisible("#input-text .cm-file-details .file-details-toggle-shown")
.expect.element("#input-text .cm-file-details").to.have.css("width").which.equals("200px");
},
"Folder inputs": browser => {
utils.clear(browser);
/* Side panel displays correct info */
utils.uploadFolder(browser, "files");
// Loop through tabs
for (let i = 1; i < 3; i++) {
browser
.click(`#input-tabs li:nth-of-type(${i})`)
.waitForElementVisible(`#input-tabs li:nth-of-type(${i}).active-input-tab`);
browser
.waitForElementVisible("#input-text .cm-file-details")
.waitForElementVisible("#input-text .cm-file-details .file-details-toggle-shown")
.waitForElementVisible("#input-text .cm-file-details .file-details-thumbnail")
.waitForElementVisible("#input-text .cm-file-details .file-details-name")
.waitForElementVisible("#input-text .cm-file-details .file-details-size")
.waitForElementVisible("#input-text .cm-file-details .file-details-type")
.waitForElementVisible("#input-text .cm-file-details .file-details-loaded");
browser.getText("#input-text .cm-file-details .file-details-name", function(result) {
switch (result.value) {
case "TowelDay.jpeg":
browser.expect.element("#input-text .cm-file-details .file-details-name").text.that.equals("TowelDay.jpeg");
browser.expect.element("#input-text .cm-file-details .file-details-size").text.that.equals("61,379 bytes");
browser.expect.element("#input-text .cm-file-details .file-details-type").text.that.equals("image/jpeg");
browser.expect.element("#input-text .cm-file-details .file-details-loaded").text.that.equals("100%");
break;
case "Hitchhikers_Guide.jpeg":
browser.expect.element("#input-text .cm-file-details .file-details-name").text.that.equals("Hitchhikers_Guide.jpeg");
browser.expect.element("#input-text .cm-file-details .file-details-size").text.that.equals("36,595 bytes");
browser.expect.element("#input-text .cm-file-details .file-details-type").text.that.equals("image/jpeg");
browser.expect.element("#input-text .cm-file-details .file-details-loaded").text.that.equals("100%");
break;
default:
break;
}
});
}
},
"Loading from URL": browser => {
/* Complex deep link populates the input correctly (encoding, eol, input) */
browser
.urlHash("recipe=To_Base64('A-Za-z0-9%2B/%3D')&input=VGhlIHNoaXBzIGh1bmcgaW4gdGhlIHNreSBpbiBtdWNoIHRoZSBzYW1lIHdheSB0aGF0IGJyaWNrcyBkb24ndC4M&ienc=21866&oenc=1201&ieol=%0C&oeol=%E2%80%A9")
.waitForElementVisible("#rec-list li.operation");
browser.expect.element(`#input-text .cm-content`).to.have.property("textContent").match(/^.{65}$/);
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("66");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("2");
browser.expect.element("#input-text .chr-enc-value").text.that.equals("KOI8-U Ukrainian Cyrillic");
browser.expect.element("#output-text .chr-enc-value").text.that.equals("UTF-16BE");
browser.expect.element("#input-text .eol-value").text.that.equals("FF");
browser.expect.element("#output-text .eol-value").text.that.equals("PS");
utils.bake(browser);
browser.expect.element(`#output-text .cm-content`).to.have.property("textContent").match(/^.{44}$/);
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("44");
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("1");
},
"Replace input with output": browser => {
/* Input is correctly populated */
utils.loadRecipe(browser, "XOR", "The ships hung in the sky in much the same way that bricks don't.", [{ "option": "Hex", "string": "65" }, "Standard", false]);
utils.setChrEnc(browser, "input", "UTF-32LE");
utils.setChrEnc(browser, "output", "UTF-7");
utils.setEOLSeq(browser, "input", "CRLF");
utils.setEOLSeq(browser, "output", "LS");
browser
.sendKeys("#input-text .cm-content", browser.Keys.RETURN)
.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("2");
utils.bake(browser);
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("67");
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("2");
browser.expect.element("#input-text .chr-enc-value").text.that.equals("UTF-32LE");
browser.expect.element("#input-text .eol-value").text.that.equals("CRLF");
browser.expect.element("#output-text .cm-status-bar .stats-length-value").text.to.equal("268");
browser
.click("#switch")
.waitForElementVisible("#stale-indicator");
browser.expect.element("#input-text .cm-status-bar .stats-length-value").text.to.equal("268");
/* Special characters, encodings and line endings all as expected */
browser.expect.element("#input-text .cm-status-bar .stats-lines-value").text.to.equal("1");
browser.expect.element("#input-text .chr-enc-value").text.that.equals("UTF-7");
browser.expect.element("#input-text .eol-value").text.that.equals("LS");
browser.expect.element("#input-text .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(1)").text.to.equal("␍");
browser.expect.element("#input-text .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(49)").text.to.equal("␑");
browser.waitForElementNotPresent("#input-text .cm-line:nth-of-type(1) .cm-specialChar:nth-of-type(50)");
},
after: browser => {
browser.end();
}
};

View file

@ -1,502 +0,0 @@
/**
* Tests for operations.
* The primary purpose for these test is to ensure that the operations
* output something vaguely expected (i.e. they aren't completely broken
* after a dependency update or changes to the UI), rather than to confirm
* that this output is actually accurate. Accuracy of output and testing
* of edge cases should be carried out in the operations test suite found
* in /tests/operations as this is much faster and easier to configure
* than the UI tests found here.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
const utils = require("./browserUtils.js");
module.exports = {
before: browser => {
browser
.resizeWindow(1280, 800)
.url(browser.launchUrl)
.useCss()
.waitForElementNotPresent("#preloader", 10000)
.click("#auto-bake-label");
},
"Sanity check operations": async browser => {
const Images = await import("../samples/Images.mjs");
testOp(browser, "A1Z26 Cipher Decode", "20 5 19 20 15 21 20 16 21 20", "testoutput");
testOp(browser, "A1Z26 Cipher Encode", "test input", "20 5 19 20 9 14 16 21 20");
testOp(browser, "ADD", "test input", "Ê»ÉÊv¿ÄÆËÊ", [{ "option": "Hex", "string": "56" }]);
testOp(browser, "AES Decrypt", "b443f7f7c16ac5396a34273f6f639caa", "test output", [{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" }, { "option": "Hex", "string": "00000000000000000000000000000000" }, "CBC", "Hex", "Raw", { "option": "Hex", "string": "" }]);
testOp(browser, "AES Encrypt", "test input", "e42eb8fbfb7a98fff061cd2c1a794d92", [{"option": "Hex", "string": "00112233445566778899aabbccddeeff"}, {"option": "Hex", "string": "00000000000000000000000000000000"}, "CBC", "Raw", "Hex"]);
testOp(browser, "AND", "test input", "4$04 $044", [{ "option": "Hex", "string": "34" }]);
testOp(browser, "Add line numbers", "test input", "1 test input");
testOp(browser, ["From Hex", "Add Text To Image", "To Base64"], Images.PNG_HEX, Images.PNG_CHEF_B64, [[], ["Chef", "Center", "Middle", 0, 0, 16], []]);
testOp(browser, "Adler-32 Checksum", "test input", "16160411");
testOp(browser, "Affine Cipher Decode", "test input", "rcqr glnsr", [1, 2]);
testOp(browser, "Affine Cipher Encode", "test input", "njln rbfpn", [2, 1]);
testOp(browser, "AMF Decode", "\u000A\u0013\u0001\u0003a\u0006\u0009test", /"\$value": "test"/);
testOp(browser, "AMF Encode", '{"a": "test"}', "\u000A\u0013\u0001\u0003a\u0006\u0009test");
testOp(browser, "Analyse hash", "0123456789abcdef", /CRC-64/);
testOp(browser, "Atbash Cipher", "test input", "gvhg rmkfg");
// testOp(browser, "Avro to JSON", "test input", "test_output");
testOp(browser, "BLAKE2b", "test input", "33ebdc8f38177f3f3f334eeb117a84e11f061bbca4db6b8923e5cec85103f59f415551a5d5a933fdb6305dc7bf84671c2540b463dbfa08ee1895cfaa5bd780b5", ["512", "Hex", { "option": "UTF8", "string": "pass" }]);
testOp(browser, "BLAKE2s", "test input", "defe73d61dfa6e5807e4f9643e159a09ccda6be3c26dcd65f8a9bb38bfc973a7", ["256", "Hex", { "option": "UTF8", "string": "pass" }]);
testOp(browser, "BSON deserialise", "\u0011\u0000\u0000\u0000\u0002a\u0000\u0005\u0000\u0000\u0000test\u0000\u0000", '{\u000A "a": "test"\u000A}');
testOp(browser, "BSON serialise", '{"a":"test"}', "\u0011\u0000\u0000\u0000\u0002a\u0000\u0005\u0000\u0000\u0000test\u0000\u0000");
// testOp(browser, "Bacon Cipher Decode", "test input", "test_output");
// testOp(browser, "Bacon Cipher Encode", "test input", "test_output");
testOp(browser, "Bcrypt", "test input", /^\$2a\$06\$.{53}$/, [6]);
testOp(browser, "Bcrypt compare", "test input", "Match: test input", ["$2a$05$FCfBSVX7OeRkK.9kQVFCiOYu9XtwtIbePqUiroD1lkASW9q5QClzG"]);
testOp(browser, "Bcrypt parse", "$2a$05$kXWtAIGB/R8VEzInoM5ocOTBtyc0m2YTIwFiBU/0XoW032f9QrkWW", /Rounds: 5/);
testOp(browser, "Bifid Cipher Decode", "qblb tfovy", "test input", ["pass"]);
testOp(browser, "Bifid Cipher Encode", "test input", "qblb tfovy", ["pass"]);
testOp(browser, "Bit shift left", "test input", "\u00E8\u00CA\u00E6\u00E8@\u00D2\u00DC\u00E0\u00EA\u00E8");
testOp(browser, "Bit shift right", "test input", ":29:\u0010478::");
testOp(browser, "Blowfish Decrypt", "10884e15427dd84ec35204e9c8e921ae", "test_output", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Hex", "Raw"]);
testOp(browser, "Blowfish Encrypt", "test input", "f0fadbd1d90d774f714248cf26b96410", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Raw", "Hex"]);
testOp(browser, ["From Hex", "Blur Image", "To Base64"], Images.PNG_HEX, Images.PNG_BLUR_B64);
testOpHtml(browser, "Bombe", "XTSYN WAEUG EZALY NRQIM AMLZX MFUOD AWXLY LZCUZ QOQBQ JLCPK NDDRW F", "table tr:last-child td:first-child", "ECG", ["3-rotor", "LEYJVCNIXWPBQMDRTAKZGFUHOS", "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", "HELLO CYBER CHEFU SER", 0, true]);
testOp(browser, ["Bzip2 Compress", "To Hex"], "test input", "42 5a 68 39 31 41 59 26 53 59 cf 96 82 1d 00 00 03 91 80 40 00 02 21 4e 00 20 00 21 90 c2 10 c0 88 33 92 8e df 17 72 45 38 50 90 cf 96 82 1d");
testOp(browser, ["From Hex", "Bzip2 Decompress"], "425a68393141592653597b0884b7000003038000008200ce00200021a647a4218013709517c5dc914e14241ec2212dc0", "test_output", [[], [true]]);
// testOp(browser, "CBOR Decode", "test input", "test output");
// testOp(browser, "CBOR Encode", "test input", "test output");
testOp(browser, "CRC-16 Checksum", "test input", "77c7");
testOp(browser, "CRC-32 Checksum", "test input", "29822bc8");
testOp(browser, "CRC-8 Checksum", "test input", "9d");
// testOp(browser, "CSS Beautify", "test input", "test_output");
// testOp(browser, "CSS Minify", "test input", "test_output");
// testOp(browser, "CSS selector", "test input", "test_output");
// testOp(browser, "CSV to JSON", "test input", "test_output");
// testOp(browser, "CTPH", "test input", "test_output");
// testOp(browser, "Cartesian Product", "test input", "test_output");
// testOp(browser, "Change IP format", "test input", "test_output");
// testOp(browser, "Chi Square", "test input", "test_output");
// testOp(browser, "CipherSaber2 Decrypt", "test input", "test_output");
// testOp(browser, "CipherSaber2 Encrypt", "test input", "test_output");
// testOp(browser, "Citrix CTX1 Decode", "test input", "test_output");
// testOp(browser, "Citrix CTX1 Encode", "test input", "test_output");
testOpHtml(browser, "Colossus", "CTBKJUVXHZ-H3L4QV+YEZUK+SXOZ/N", "table tr:last-child td:first-child", "30", ["", "KH Pattern", "Z", "", "", "None", "Select Program", "Letter Count", "", "", "", "", "", "", false, "", "", "", "", "", "", false, "", "", "", "", "", "", false, "", false, "", false, false, false, false, false, "", false, false, "", "", 0, "", "", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
// testOp(browser, "Comment", "test input", "test_output");
// testOp(browser, "Compare CTPH hashes", "test input", "test_output");
// testOp(browser, "Compare SSDEEP hashes", "test input", "test_output");
// testOp(browser, "Conditional Jump", "test input", "test_output");
testOpImage(browser, "Contain Image", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Convert area", "test input", "test_output");
// testOp(browser, "Convert co-ordinate format", "test input", "test_output");
// testOp(browser, "Convert data units", "test input", "test_output");
// testOp(browser, "Convert distance", "test input", "test_output");
testOpImage(browser, "Convert Image Format", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Convert mass", "test input", "test_output");
// testOp(browser, "Convert speed", "test input", "test_output");
// testOp(browser, "Convert to NATO alphabet", "test input", "test_output");
// testOp(browser, "Count occurrences", "test input", "test_output");
testOpImage(browser, "Cover Image", "files/Hitchhikers_Guide.jpeg");
testOpImage(browser, "Crop Image", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "CSS Selector", "test input", "test output");
// testOp(browser, "DES Decrypt", "test input", "test_output");
// testOp(browser, "DES Encrypt", "test input", "test_output");
// testOp(browser, "DNS over HTTPS", "test input", "test_output");
// testOp(browser, "Dechunk HTTP response", "test input", "test_output");
// testOp(browser, "Decode NetBIOS Name", "test input", "test_output");
// testOp(browser, "Decode text", "test input", "test_output");
// testOp(browser, "Defang IP Addresses", "test input", "test_output");
// testOp(browser, "Defang URL", "test input", "test_output");
// testOp(browser, "Derive EVP key", "test input", "test_output");
// testOp(browser, "Derive PBKDF2 key", "test input", "test_output");
// testOp(browser, "Detect File Type", "test input", "test_output");
testOpHtml(browser, "Diff", "The cat sat on the mat\n\nThe mat cat on the sat", ".hl5:first-child", "mat", ["\\n\\n", "Word", true, true, false, false]);
// testOp(browser, "Disassemble x86", "test input", "test_output");
testOpImage(browser, "Dither Image", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Divide", "test input", "test_output");
// testOp(browser, "Drop bytes", "test input", "test_output");
// testOp(browser, "Encode NetBIOS Name", "test input", "test_output");
// testOp(browser, "Encode text", "test input", "test_output");
// testOp(browser, "Enigma", "test input", "test_output");
testOpHtml(browser, "Entropy", "test input", "", /Shannon entropy: 2.8464393446710154/);
// testOp(browser, "Escape string", "test input", "test_output");
// testOp(browser, "Escape Unicode Characters", "test input", "test_output");
// testOp(browser, "Expand alphabet range", "test input", "test_output");
// testOp(browser, "Extract dates", "test input", "test_output");
// testOp(browser, "Extract domains", "test input", "test_output");
// testOp(browser, "Extract EXIF", "test input", "test_output");
// testOp(browser, "Extract email addresses", "test input", "test_output");
// testOp(browser, "Extract file paths", "test input", "test_output");
testOpFile(browser, "Extract Files", "files/Hitchhikers_Guide.jpeg", ".card:last-child .collapsed", "extracted_at_0x3d38.zlib");
testOpFile(browser, "Extract ID3", "files/mp3example.mp3", "tr:last-child td:last-child", "Kevin MacLeod");
// testOp(browser, "Extract IP addresses", "test input", "test_output");
// testOp(browser, "Extract LSB", "test input", "test_output");
// testOp(browser, "Extract MAC addresses", "test input", "test_output");
// testOp(browser, "Extract RGBA", "test input", "test_output");
// testOp(browser, "Extract URLs", "test input", "test_output");
// testOp(browser, "Filter", "test input", "test_output");
// testOp(browser, "Find / Replace", "test input", "test_output");
// testOp(browser, "Fletcher-16 Checksum", "test input", "test_output");
// testOp(browser, "Fletcher-32 Checksum", "test input", "test_output");
// testOp(browser, "Fletcher-64 Checksum", "test input", "test_output");
// testOp(browser, "Fletcher-8 Checksum", "test input", "test_output");
testOpImage(browser, "Flip Image", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Fork", "test input", "test_output");
// testOp(browser, "Format MAC addresses", "test input", "test_output");
testOpHtml(browser, "Frequency distribution", "test input", "", /Number of bytes not represented: 248/);
// testOp(browser, "From BCD", "test input", "test_output");
// testOp(browser, "From Base", "test input", "test_output");
// testOp(browser, "From Base32", "test input", "test_output");
// testOp(browser, "From Base58", "test input", "test_output");
// testOp(browser, "From Base62", "test input", "test_output");
// testOp(browser, "From Base64", "test input", "test_output");
// testOp(browser, "From Base85", "test input", "test_output");
// testOp(browser, "From Binary", "test input", "test_output");
// testOp(browser, "From Braille", "test input", "test_output");
// testOp(browser, "From Case Insensitive Regex", "test input", "test_output");
// testOp(browser, "From Charcode", "test input", "test_output");
// testOp(browser, "From Decimal", "test input", "test_output");
// testOp(browser, "From HTML Entity", "test input", "test_output");
// testOp(browser, "From Hex", "test input", "test_output");
// testOp(browser, "From Hex Content", "test input", "test_output");
// testOp(browser, "From Hexdump", "test input", "test_output");
// testOp(browser, "From MessagePack", "test input", "test_output");
// testOp(browser, "From Morse Code", "test input", "test_output");
// testOp(browser, "From Octal", "test input", "test_output");
// testOp(browser, "From Punycode", "test input", "test_output");
// testOp(browser, "From Quoted Printable", "test input", "test_output");
// testOp(browser, "From UNIX Timestamp", "test input", "test_output");
testOpHtml(browser, "Fuzzy Match", "test input", "b:last-child", "in", ["tein", 15, 30, 30, 15, -5, -15, -1]);
// testOp(browser, "GOST hash", "test input", "test_output");
// testOp(browser, "Generate all hashes", "test input", "test_output");
// testOp(browser, "Generate HOTP", "test input", "test_output");
testOpHtml(browser, "Generate Image", "test input", "img", "");
// testOp(browser, "Generate Lorem Ipsum", "test input", "test_output");
// testOp(browser, "Generate PGP Key Pair", "test input", "test_output");
testOpHtml(browser, "Generate QR Code", "test input", "img", "");
// testOp(browser, "Generate TOTP", "test input", "test_output");
// testOp(browser, "Generate UUID", "test input", "test_output");
// testOp(browser, "Generic Code Beautify", "test input", "test_output");
// testOp(browser, "Group IP addresses", "test input", "test_output");
// testOp(browser, "Gunzip", "test input", "test_output");
// testOp(browser, "Gzip", "test input", "test_output");
// testOp(browser, "HAS-160", "test input", "test_output");
// testOp(browser, "HMAC", "test input", "test_output");
// testOp(browser, "HTML To Text", "test input", "test_output");
// testOp(browser, "HTTP request", "test input", "test_output");
// testOp(browser, "Hamming Distance", "test input", "test_output");
// testOp(browser, "Haversine distance", "test input", "test_output");
// testOp(browser, "Head", "test input", "test_output");
testOpHtml(browser, "Heatmap chart", "X Y\n0 1\n1 2", "svg", /X/);
testOpHtml(browser, "Hex Density chart", "X Y\n0 1\n1 2", "svg", /X/);
// testOp(browser, "Hex to Object Identifier", "test input", "test_output");
// testOp(browser, "Hex to PEM", "test input", "test_output");
testOpImage(browser, "Image Brightness / Contrast", "files/Hitchhikers_Guide.jpeg");
testOpImage(browser, "Image Filter", "files/Hitchhikers_Guide.jpeg");
testOpImage(browser, "Image Hue/Saturation/Lightness", "files/Hitchhikers_Guide.jpeg");
testOpImage(browser, "Image Opacity", "files/Hitchhikers_Guide.jpeg");
testOpHtml(browser, "Index of Coincidence", "test input", "", /Index of Coincidence: 0.08333333333333333/);
testOpImage(browser, "Invert Image", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "JPath expression", "test input", "test_output");
testOpHtml(browser, "JSON Beautify", "{a:1}", ".json-dict .json-literal", "1");
// testOp(browser, "JSON Minify", "test input", "test_output");
// testOp(browser, "JSON to CSV", "test input", "test_output");
// testOp(browser, "JWT Decode", "test input", "test_output");
// testOp(browser, "JWT Sign", "test input", "test_output");
// testOp(browser, "JWT Verify", "test input", "test_output");
// testOp(browser, "JavaScript Beautify", "test input", "test_output");
// testOp(browser, "JavaScript Minify", "test input", "test_output");
// testOp(browser, "JavaScript Parser", "test input", "test_output");
// testOp(browser, "Jump", "test input", "test_output");
// testOp(browser, "Keccak", "test input", "test_output");
// testOp(browser, "Label", "test input", "test_output");
// testOp(browser, "LM Hash", "test input", "test output");
// testOp(browser, "Lorenz", "test input", "test_output");
// testOp(browser, "Luhn Checksum", "test input", "test_output");
// testOp(browser, "LZ String", "test input", "test output");
// testOp(browser, "LZ4 Compress", "test input", "test output");
// testOp(browser, "LZ4 Decompress", "test input", "test output");
// testOp(browser, "LZMA Compress", "test input", "test output");
// testOp(browser, "LZMA Decompress", "test input", "test output");
// testOp(browser, "MD2", "test input", "test_output");
// testOp(browser, "MD4", "test input", "test_output");
// testOp(browser, "MD5", "test input", "test_output");
// testOp(browser, "MD6", "test input", "test_output");
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(1) th:nth-of-type(2)", "Result snippet");
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(2) td:nth-of-type(2)", "test_output");
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(2) td:nth-of-type(1)", /Base64/);
// testOp(browser, "Mean", "test input", "test_output");
// testOp(browser, "Median", "test input", "test_output");`
// testOp(browser, "Merge", "test input", "test_output");`
// testOp(browser, "Microsoft Script Decoder", "test input", "test_output");
// testOp(browser, "Multiple Bombe", "test input", "test_output");
// testOp(browser, "Multiply", "test input", "test_output");
// testOp(browser, "NOT", "test input", "test_output");
// testOp(browser, "Normalise Image", "test input", "test_output");
// testOp(browser, "Normalise Unicode", "test input", "test_output");
// testOp(browser, "Numberwang", "test input", "test_output");
// 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");
// 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");
// testOp(browser, "PGP Encrypt", "test input", "test_output");
// testOp(browser, "PGP Encrypt and Sign", "test input", "test_output");
// testOp(browser, "PGP Verify", "test input", "test_output");
// testOp(browser, "PHP Deserialize", "test input", "test_output");
// testOp(browser, "Pad lines", "test input", "test_output");
// testOp(browser, "Parse ASN.1 hex string", "test input", "test_output");
testOpHtml(browser, "Parse colour code", "#000", ".colorpicker-preview", "rgb(0, 0, 0)");
testOpHtml(browser, "Parse DateTime", "01/12/2000 13:00:00", "", /Date: Friday 1st December 2000/);
// testOp(browser, "Parse IP range", "test input", "test_output");
testOpHtml(browser, "Parse IPv4 header", "45 c0 00 c4 02 89 00 00 ff 11 1e 8c c0 a8 0c 01 c0 a8 0c 02", "tr:last-child td:last-child", "192.168.12.2");
// testOp(browser, "Parse IPv6 address", "test input", "test_output");
// testOp(browser, "Parse ObjectID timestamp", "test input", "test_output");
// testOp(browser, "Parse QR Code", "test input", "test_output");
// testOp(browser, "Parse SSH Host Key", "test input", "test_output");
testOpHtml(browser, "Parse TCP", "c2eb0050a138132e70dc9fb9501804025ea70000", "tr:nth-of-type(2) td:last-child", "49899");
// testOp(browser, "Parse TLV", "test input", "test_output");
testOpHtml(browser, "Parse UDP", "04 89 00 35 00 2c 01 01", "tr:last-child td:last-child", "0x0101");
// testOp(browser, "Parse UNIX file permissions", "test input", "test_output");
// testOp(browser, "Parse URI", "test input", "test_output");
// testOp(browser, "Parse User Agent", "test input", "test_output");
// testOp(browser, "Parse X.509 certificate", "test input", "test_output");
testOpFile(browser, "Play Media", "files/mp3example.mp3", "audio", "");
// testOp(browser, "Power Set", "test input", "test_output");
// testOp(browser, "Protobuf Decode", "test input", "test_output");
// testOp(browser, "Pseudo-Random Number Generator", "test input", "test_output");
// testOp(browser, "RC2 Decrypt", "test input", "test_output");
// testOp(browser, "RC2 Encrypt", "test input", "test_output");
// testOp(browser, "RC4", "test input", "test_output");
// testOp(browser, "RC4 Drop", "test input", "test_output");
// testOp(browser, "RIPEMD", "test input", "test_output");
// testOp(browser, "ROT13", "test input", "test_output");
// testOp(browser, "ROT47", "test input", "test_output");
// testOp(browser, "ROT8000", "test input", "test_output");
// testOp(browser, "Rail Fence Cipher Decode", "test input", "test_output");
// testOp(browser, "Rail Fence Cipher Encode", "test input", "test_output");
testOpImage(browser, "Randomize Colour Palette", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Raw Deflate", "test input", "test_output");
// testOp(browser, "Raw Inflate", "test input", "test_output");
// testOp(browser, "Register", "test input", "test_output");
testOpHtml(browser, "Regular expression", "The cat sat on the mat", ".hl2:last-child", "mat", ["User defined", ".at", true, true, false, false, false, false, "Highlight matches"]);
// testOp(browser, "Remove Diacritics", "test input", "test_output");
// testOp(browser, "Remove EXIF", "test input", "test_output");
// testOp(browser, "Remove line numbers", "test input", "test_output");
// testOp(browser, "Remove null bytes", "test input", "test_output");
// testOp(browser, "Remove whitespace", "test input", "test_output");
testOpImage(browser, "Render Image", "files/Hitchhikers_Guide.jpeg");
testOpHtml(browser, "Render Markdown", "# test input", "h1", "test input");
testOpImage(browser, "Resize Image", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Return", "test input", "test_output");
// testOp(browser, "Reverse", "test input", "test_output");
testOpImage(browser, "Rotate Image", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Rotate left", "test input", "test_output");
// testOp(browser, "Rotate right", "test input", "test_output");
// testOp(browser, "Scrypt", "test input", "test output");
// testOp(browser, "SHA0", "test input", "test_output");
// testOp(browser, "SHA1", "test input", "test_output");
// testOp(browser, "SHA2", "test input", "test_output");
// testOp(browser, "SHA3", "test input", "test_output");
// testOp(browser, "SQL Beautify", "test input", "test_output");
// testOp(browser, "SQL Minify", "test input", "test_output");
// testOp(browser, "SSDEEP", "test input", "test_output");
// testOp(browser, "SUB", "test input", "test_output");
// testOp(browser, "Scan for Embedded Files", "test input", "test_output");
testOpHtml(browser, "Scatter chart", "a b\n1 2", "svg", /a/);
// testOp(browser, "Scrypt", "test input", "test_output");
testOpHtml(browser, "Series chart", "1 2 3\n4 5 6", "svg", /3/);
// testOp(browser, "Set Difference", "test input", "test_output");
// testOp(browser, "Set Intersection", "test input", "test_output");
// testOp(browser, "Set Union", "test input", "test_output");
// testOp(browser, "Shake", "test input", "test_output");
testOpImage(browser, "Sharpen Image", "files/Hitchhikers_Guide.jpeg");
testOpHtml(browser, "Show Base64 offsets", "test input", "span:nth-last-of-type(2)", "B");
testOpHtml(browser, "Show on map", "51.5007° N, 0.1246° W", "#presentedMap .leaflet-popup-content", "51.5007,-0.1246");
// testOp(browser, "Sleep", "test input", "test_output");
// testOp(browser, "SM3", "test input", "test output");
// testOp(browser, "Snefru", "test input", "test_output");
// testOp(browser, "Sort", "test input", "test_output");
// testOp(browser, "Split", "test input", "test_output");
// testOpImage(browser, "Split Colour Channels", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Standard Deviation", "test input", "test_output");
// testOp(browser, "Streebog", "test input", "test_output");
// testOp(browser, "Strings", "test input", "test_output");
// testOp(browser, "Strip HTML tags", "test input", "test_output");
// testOp(browser, "Strip HTTP headers", "test input", "test_output");
// testOp(browser, "Subsection", "test input", "test_output");
// testOp(browser, "Substitute", "test input", "test_output");
// testOp(browser, "Subtract", "test input", "test_output");
// testOp(browser, "Sum", "test input", "test_output");
// testOp(browser, "Swap endianness", "test input", "test_output");
// testOp(browser, "Symmetric Difference", "test input", "test_output");
testOpHtml(browser, "Syntax highlighter", "var a = [4,5,6]", ".hljs-selector-attr", "[4,5,6]");
// testOp(browser, "TCP/IP Checksum", "test input", "test_output");
// testOp(browser, "Tail", "test input", "test_output");
// testOp(browser, "Take bytes", "test input", "test_output");
testOp(browser, "Tar", "test input", /^file\.txt\x00{92}/);
testOpHtml(browser, "Text Encoding Brute Force", "test input", "tr:nth-of-type(4) td:last-child", /t\u2400e\u2400s\u2400t\u2400/);
// testOp(browser, "To BCD", "test input", "test_output");
// testOp(browser, "To Base", "test input", "test_output");
// testOp(browser, "To Base32", "test input", "test_output");
// testOp(browser, "To Base58", "test input", "test_output");
// testOp(browser, "To Base62", "test input", "test_output");
// testOp(browser, "To Base64", "test input", "test_output");
// testOp(browser, "To Base85", "test input", "test_output");
// testOp(browser, "To Binary", "test input", "test_output");
// testOp(browser, "To Braille", "test input", "test_output");
// testOp(browser, "To Camel case", "test input", "test_output");
// testOp(browser, "To Case Insensitive Regex", "test input", "test_output");
// testOp(browser, "To Charcode", "test input", "test_output");
// testOp(browser, "To Decimal", "test input", "test_output");
// testOp(browser, "To HTML Entity", "test input", "test_output");
// testOp(browser, "To Hex", "test input", "test_output");
// testOp(browser, "To Hex Content", "test input", "test_output");
// testOp(browser, "To Hexdump", "test input", "test_output");
// testOp(browser, "To Kebab case", "test input", "test_output");
// testOp(browser, "To Lower case", "test input", "test_output");
// testOp(browser, "To MessagePack", "test input", "test_output");
// testOp(browser, "To Morse Code", "test input", "test_output");
// testOp(browser, "To Octal", "test input", "test_output");
// testOp(browser, "To Punycode", "test input", "test_output");
// testOp(browser, "To Quoted Printable", "test input", "test_output");
// testOp(browser, "To Snake case", "test input", "test_output");
testOpHtml(browser, "To Table", "a,b,c\n1,2,3", "", /| a | b | c |/);
// testOp(browser, "To UNIX Timestamp", "test input", "test_output");
// testOp(browser, "To Upper case", "test input", "test_output");
// testOp(browser, "Translate DateTime Format", "test input", "test_output");
// testOp(browser, "Triple DES Decrypt", "test input", "test_output");
// testOp(browser, "Triple DES Encrypt", "test input", "test_output");
// testOp(browser, "Typex", "test input", "test_output");
// testOp(browser, "UNIX Timestamp to Windows Filetime", "test input", "test_output");
// testOp(browser, "URL Decode", "test input", "test_output");
// testOp(browser, "URL Encode", "test input", "test_output");
// testOp(browser, "Unescape string", "test input", "test_output");
// testOp(browser, "Unescape Unicode Characters", "test input", "test_output");
// testOp(browser, "Unique", "test input", "test_output");
testOpHtml(browser, ["Tar", "Untar"], "test input", ".float-right", /10 bytes/);
testOpHtml(browser, ["Zip", "Unzip"], "test input", "#files span.float-right", /10 bytes/);
// testOp(browser, "VarInt Decode", "test input", "test_output");
// testOp(browser, "VarInt Encode", "test input", "test_output");
testOpImage(browser, "View Bit Plane", "files/Hitchhikers_Guide.jpeg");
// testOp(browser, "Vigenère Decode", "test input", "test_output");
// testOp(browser, "Vigenère Encode", "test input", "test_output");
testOp(browser, "Whirlpool", "test input", "8a0ee6885ba241353d17cbbe5f06538a7f04c8c955d376c20d6233fd4dd41aaffd13291447090ce781b5f940da266ed6d02cf8b79d4867065d10bdfc04166f38");
// testOp(browser, "Windows Filetime to UNIX Timestamp", "test input", "test_output");
testOp(browser, "XKCD Random Number", "test input", "4");
// testOp(browser, "XML Beautify", "test input", "test_output");
// testOp(browser, "XML Minify", "test input", "test_output");
// testOp(browser, "XOR", "test input", "test_output");
// testOp(browser, "XOR Brute Force", "test input", "test_output");
// testOp(browser, "XPath expression", "test input", "test_output");
// testOp(browser, "YARA Rules", "test input", "test_output");
testOp(browser, "Zip", "test input", /^PK\u0003\u0004\u0014\u0000{3}/);
// testOp(browser, "Zlib Deflate", "test input", "test_output");
// testOp(browser, "Zlib Inflate", "test input", "test_output");
},
after: browser => {
browser.end();
}
};
/** @function
* Clears the current recipe and bakes a new operation.
*
* @param {Browser} browser - Nightwatch client
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
* @param {string} input - input text for test
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
*/
function bakeOp(browser, opName, input, args=[]) {
browser.perform(function() {
console.log(`Current test: ${opName}`);
});
utils.loadRecipe(browser, opName, input, args);
browser.waitForElementVisible("#stale-indicator", 5000);
utils.bake(browser);
}
/** @function
* Clears the current recipe and tests a new operation.
*
* @param {Browser} browser - Nightwatch client
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
* @param {string} input - input text
* @param {string} output - expected output
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
*/
function testOp(browser, opName, input, output, args=[]) {
bakeOp(browser, opName, input, args);
utils.expectOutput(browser, output);
}
/** @function
* Clears the current recipe and tests a new operation with HTML output.
*
* @param {Browser} browser - Nightwatch client
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
* @param {string} input - input text
* @param {string} cssSelector - CSS selector for HTML output
* @param {string} output - expected output
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
*/
function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
bakeOp(browser, opName, input, args);
if (typeof output === "string") {
browser.expect.element("#output-html " + cssSelector).text.that.equals(output);
} else if (output instanceof RegExp) {
browser.expect.element("#output-html " + cssSelector).text.that.matches(output);
}
}
/** @function
* Clears the current recipe and tests a new Image-based operation.
*
* @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
*/
function testOpImage(browser, opName, filename, args) {
browser.perform(function() {
console.log(`Current test: ${opName}`);
});
utils.loadRecipe(browser, opName, "", args);
utils.uploadFile(browser, filename);
browser.waitForElementVisible("#stale-indicator", 5000);
utils.bake(browser);
browser
.waitForElementVisible("#output-html img")
.expect.element("#output-html img").to.have.css("width").which.matches(/^[^0]\d*px/);
}
/** @function
* Clears the current recipe and tests a new File-based operation.
*
* @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
*/
function testOpFile(browser, opName, filename, cssSelector, output, args) {
browser.perform(function() {
console.log(`Current test: ${opName}`);
});
utils.loadRecipe(browser, opName, "", args);
utils.uploadFile(browser, filename);
browser.pause(100).waitForElementVisible("#stale-indicator", 5000);
utils.bake(browser);
if (typeof output === "string") {
browser.expect.element("#output-html " + cssSelector).text.that.equals(output);
} else if (output instanceof RegExp) {
browser.expect.element("#output-html " + cssSelector).text.that.matches(output);
}
}

View file

@ -134,6 +134,7 @@ import "./tests/LevenshteinDistance.mjs";
import "./tests/SwapCase.mjs";
import "./tests/HKDF.mjs";
import "./tests/GenerateDeBruijnSequence.mjs";
import "./tests/GOST.mjs";
// Cannot test operations that use the File type yet
// import "./tests/SplitColourChannels.mjs";

View file

@ -0,0 +1,183 @@
/**
* GOST tests.
*
* The GOST library already includes a range of tests for the correctness of
* the algorithms. These tests are intended only to confirm that the library
* has been correctly integrated into CyberChef.
*
* @author n1474335 [n1474335@gmail.com]
*
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "GOST Encrypt: Magma",
input: "Hello, World!",
expectedOutput: "f124ac5c0853870906dbaf9b56",
recipeConfig: [
{
op: "GOST Encrypt",
args: [
{ "option": "Hex", "string": "00112233" },
{ "option": "Hex", "string": "0011223344556677" },
"Raw",
"Hex",
"GOST 28147 (Magma, 1989)",
"64",
"E-SC",
"OFB",
"CP",
"ZERO"
]
}
],
},
{
name: "GOST Encrypt: Kuznyechik",
input: "Hello, World!",
expectedOutput: "8673d490dfa4a66d5e3ff00ba316724f",
recipeConfig: [
{
op: "GOST Encrypt",
args: [
{ "option": "Hex", "string": "00112233" },
{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" },
"Raw",
"Hex",
"GOST R 34.12 (Kuznyechik, 2015)",
"128",
"E-SC",
"CBC",
"CP",
"PKCS5"
]
}
],
},
{
name: "GOST Decrypt: Magma",
input: "f124ac5c0853870906dbaf9b56",
expectedOutput: "Hello, World!",
recipeConfig: [
{
op: "GOST Decrypt",
args: [
{ "option": "Hex", "string": "00112233" },
{ "option": "Hex", "string": "0011223344556677" },
"Hex",
"Raw",
"GOST 28147 (Magma, 1989)",
"128",
"E-SC",
"OFB",
"CP",
"ZERO"
]
}
],
},
{
name: "GOST Decrypt: Kuznyechik",
input: "8673d490dfa4a66d5e3ff00ba316724f",
expectedOutput: "Hello, World!\0\0\0",
recipeConfig: [
{
op: "GOST Decrypt",
args: [
{ "option": "Hex", "string": "00112233" },
{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" },
"Hex",
"Raw",
"GOST R 34.12 (Kuznyechik, 2015)",
"128",
"E-TEST",
"CBC",
"CP",
"PKCS5"
]
}
],
},
{
name: "GOST Sign",
input: "Hello, World!",
expectedOutput: "810d0c40e965",
recipeConfig: [
{
op: "GOST Sign",
args: [
{ "option": "Hex", "string": "00112233" },
{ "option": "Hex", "string": "0011223344556677" },
"Raw",
"Hex",
"GOST 28147 (Magma, 1989)",
"64",
"E-C",
48
]
}
],
},
{
name: "GOST Verify",
input: "Hello, World!",
expectedOutput: "The signature matches",
recipeConfig: [
{
op: "GOST Verify",
args: [
{ "option": "Hex", "string": "00112233" },
{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" },
{ "option": "Hex", "string": "42b77fb3d6f6bf04" },
"Raw",
"GOST R 34.12 (Kuznyechik, 2015)",
"128",
"E-TEST"
]
}
],
},
{
name: "GOST Key Wrap",
input: "Hello, World!123",
expectedOutput: "0bb706e92487fceef97589911faeb28200000000000000000000000000000000\r\n6b7bfd16",
recipeConfig: [
{
op: "GOST Key Wrap",
args: [
{ "option": "Hex", "string": "00112233" },
{ "option": "Hex", "string": "0011223344556677" },
"Raw",
"Hex",
"GOST R 34.12 (Kuznyechik, 2015)",
"64",
"E-TEST",
"CP"
]
}
],
},
{
name: "GOST Key Unwrap",
input: "c8e58458a42d21974d50103d59b469f2c8e58458a42d21974d50103d59b469f2\r\na32a1575",
expectedOutput: "0123456789abcdef0123456789abcdef",
recipeConfig: [
{
op: "GOST Key Unwrap",
args: [
{ "option": "Hex", "string": "" },
{ "option": "Latin1", "string": "00112233" },
"Hex",
"Raw",
"GOST 28147 (Magma, 1989)",
"64",
"E-Z",
"CP"
]
}
],
},
]);

View file

@ -1094,8 +1094,8 @@ TestRegister.addTests([
expectedOutput: "981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0",
recipeConfig: [
{
op: "GOST hash",
args: ["D-A"]
op: "GOST Hash",
args: ["GOST 28147 (1994)", "256", "D-A"]
}
]
},
@ -1105,8 +1105,8 @@ TestRegister.addTests([
expectedOutput: "2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb",
recipeConfig: [
{
op: "GOST hash",
args: ["D-A"]
op: "GOST Hash",
args: ["GOST 28147 (1994)", "256", "D-A"]
}
]
},