2
0
mirror of https://github.com/gchq/CyberChef synced 2026-01-07 11:03:18 +00:00

Compare commits

..

58 Commits

Author SHA1 Message Date
n1474335
447be8af34 9.24.8 2021-02-11 16:14:48 +00:00
n1474335
0989550e5c Merge branch 'n1073645-keychainExtractor' 2021-02-11 16:14:34 +00:00
n1474335
4d9b48b4d8 Tidied whitespace 2021-02-11 16:14:23 +00:00
n1474335
979652387d Merge branch 'keychainExtractor' of https://github.com/n1073645/CyberChef into n1073645-keychainExtractor 2021-02-11 16:12:57 +00:00
n1474335
de84fbdd1c Renamed workflows 2021-02-10 18:37:46 +00:00
n1474335
170e564319 Fixed incomplete multi-character sanitization and incomplete URL substring sanitization issues. 2021-02-10 17:41:39 +00:00
n1474335
530836876f 9.24.7 2021-02-10 13:13:25 +00:00
n1474335
1abc46058c Added a CodeQL workflow to check for bugs through code analysis. Fixed numerous bugs and implemented safeguards as already reported. 2021-02-10 13:13:19 +00:00
n1474335
892a3716ed Added Crypt lib for common resources 2021-02-09 15:00:35 +00:00
n1474335
5d982a9c8d 9.24.6 2021-02-09 14:50:17 +00:00
n1474335
6206224f1e Merge branch 'alblue-master' 2021-02-09 14:46:19 +00:00
n1474335
766310e2c7 Frequency Distribution operation now displays an HTML table 2021-02-09 14:46:04 +00:00
n1474335
02a397d2ae Merge branch 'master' of https://github.com/alblue/CyberChef into alblue-master 2021-02-09 14:30:03 +00:00
n1474335
4563c86acd 9.24.5 2021-02-09 14:24:08 +00:00
n1474335
0a59f8068e Merge branch 'aussieklutz-master' 2021-02-09 14:23:18 +00:00
n1474335
24548e3a48 Tidied up JWT tests 2021-02-09 14:23:02 +00:00
n1474335
f4784d49e7 Merge branch 'master' of https://github.com/aussieklutz/CyberChef into aussieklutz-master 2021-02-09 14:16:36 +00:00
n1474335
14d5069c6e Merge branch 'mt3571-1073-jwt-verify' 2021-02-09 14:15:12 +00:00
n1474335
9fdd55c5c6 Tidied up JWT ops 2021-02-09 14:14:59 +00:00
n1474335
5bc523aeff Merge branch '1073-jwt-verify' of https://github.com/mt3571/CyberChef into mt3571-1073-jwt-verify 2021-02-09 14:02:21 +00:00
n1474335
3ae2e2e2c8 Fixed highlighting of op names where only the description has hit 2021-02-09 11:50:20 +00:00
n1474335
83e49da7f6 Fixed description hiighlighting issue 2021-02-09 11:37:25 +00:00
n1474335
fe6df8778f Fixed year in CHANGELOG records. Closes #1168 2021-02-09 11:26:00 +00:00
Alex Blewitt
69073c9d99 Add ASCII output for frequency table
When showing results in the frequency distribution table, it's quite
helpful to see the distribution of the ASCII letters, if any. Provide an
option to show this to show the characters alongside the code.

Fixes #1169.

Signed-off-by: Alex Blewitt <alex.blewitt@gmail.com>
2021-02-07 16:22:13 +00:00
aussieklutz
d5a0adea0c Update JWTVerify.mjs 2021-02-06 18:35:46 +10:00
aussieklutz
1bcb8e433d Update JWTVerify.mjs 2021-02-06 18:10:54 +10:00
aussieklutz
fa05cf1d78 Update JWTVerify.mjs
Enabled ESRSA verification.
2021-02-06 17:58:49 +10:00
aussieklutz
63dff0d34d Update JWTVerify.mjs
Enabled validation of ECSHA256 JWT tokens in the tests
2021-02-06 17:55:44 +10:00
aussieklutz
e228b197f9 Update JWTVerify.mjs 2021-02-06 17:45:42 +10:00
aussieklutz
4bbeb6caa3 Update JWTVerify.mjs
Add expectation for working RSASHA256 test, and comment out unused privatekey.
2021-02-06 17:42:42 +10:00
aussieklutz
139d25dff9 Update JWTVerify.mjs
Update RSASHA256 test with the public key derived from the pre-existing private key, and expect a working testcase.
2021-02-06 17:40:04 +10:00
aussieklutz
6984258404 Update JWTVerify.mjs
Enable verification of RSASHA256 and 512 tokens
2021-02-06 17:27:54 +10:00
n1474335
ba66fd6546 Fixed recursive matching arguments 2021-02-05 19:04:27 +00:00
n1474335
47bbefd81f Fixed recursive scoring results in fuzzy match lib 2021-02-05 18:24:15 +00:00
n1474335
50f796049c Fixed search test 2021-02-05 18:07:20 +00:00
n1474335
618da545b1 9.24.4 2021-02-05 17:55:10 +00:00
n1474335
21236f1938 Added fuzzy search for operations 2021-02-05 17:54:57 +00:00
n1474335
4169a15066 9.24.3 2021-02-03 19:07:46 +00:00
n1474335
6b10f61e11 Moved postinstall script to a Grunt task to fix relative calls. npm scripts now use local grunt install. 2021-02-03 19:07:39 +00:00
n1474335
83f119f7e4 9.24.2 2021-02-03 17:54:57 +00:00
n1474335
041c899a35 Comments are now treated as disabled so that they do not interfere with the Dish type. Closes #1126 and #1132. Thanks to @mt3571 for the suggestion. 2021-02-03 17:54:49 +00:00
n1474335
5412fc01b3 Merge branch 'Prinzhorn-base_64_order' 2021-02-02 17:36:23 +00:00
n1474335
76926d9252 Merge branch 'base_64_order' of https://github.com/Prinzhorn/CyberChef into Prinzhorn-base_64_order 2021-02-02 17:36:10 +00:00
n1474335
3270961574 Merge branch 'n1073645-microsoftDecoderMagic' 2021-02-02 17:29:41 +00:00
n1474335
9a1ef71aec Merge branch 'microsoftDecoderMagic' of https://github.com/n1073645/CyberChef into n1073645-microsoftDecoderMagic 2021-02-02 17:29:25 +00:00
n1474335
ba878925ad Merge branch 'Prinzhorn-boolean_args' 2021-02-02 17:23:23 +00:00
n1474335
8d6b71bfaa Merge branch 'boolean_args' of https://github.com/Prinzhorn/CyberChef into Prinzhorn-boolean_args 2021-02-02 17:23:05 +00:00
n1474335
b6845aa03c 9.24.1 2021-02-02 17:18:49 +00:00
n1474335
4a673bd92a AES Decrypt now supports Additional Authenticated Data in GCM mode. Added tests for ADD at each AES size. 2021-02-02 17:18:35 +00:00
n1474335
fdffabfdd4 Merge branch 'n1073645-AESGCMAAD' 2021-02-02 16:11:03 +00:00
n1474335
ba8591293b Merge branch 'AESGCMAAD' of https://github.com/n1073645/CyberChef into n1073645-AESGCMAAD 2021-02-02 16:10:47 +00:00
mt3571
887ea0cf06 Changed an incorrect name 2020-12-01 13:49:34 +00:00
mt3571
3e0525ee9e Added in a new file to store the list of JWT algorithms that can be used, as this error was occurring due to a mismatch between what you could sign and what you could verify 2020-12-01 13:38:01 +00:00
Alexander Prinzhorn
cb8fe42c66 Put Base64 after Base62 2020-04-16 10:20:38 +02:00
Alexander Prinzhorn
7f4b2574b0 Use proper booleans instead of relying on truthy/falsy values 2020-04-16 09:59:43 +02:00
n1073645
cc35127459 AAD for AES Added 2020-04-07 13:03:24 +01:00
n1073645
1f0fddd0e9 Added magic signature to Microsoft Script Decoder 2020-04-07 10:33:15 +01:00
n1073645
2e0af64ac3 PGP secring signatures and Mac OS X keyring extractor added 2020-03-17 14:53:05 +00:00
63 changed files with 877 additions and 268 deletions

View File

@@ -63,7 +63,8 @@
}],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double", {
"avoidEscape": true
"avoidEscape": true,
"allowTemplateLiterals": true
}],
"camelcase": ["error", {
"properties": "always"

32
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: "CodeQL Analysis"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '22 17 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -1,4 +1,4 @@
name: Master
name: "Master Build, Test & Deploy"
on:
push:

View File

@@ -1,4 +1,4 @@
name: PRs
name: "Pull Requests"
on:
pull_request:

View File

@@ -1,4 +1,4 @@
name: Release
name: "Releases"
on:
push:
@@ -47,6 +47,7 @@ jobs:
tag: ${{ github.ref }}
overwrite: true
file_glob: true
body: "See the [CHANGELOG](https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md) and [commit messages](https://github.com/gchq/CyberChef/commits/master) for details."
- name: Publish to NPM
if: success()

View File

@@ -2,7 +2,7 @@
## Versioning
CyberChef uses the [semver](https://semver.org/) system to manage versioning: MAJOR.MINOR.PATCH.
CyberChef uses the [semver](https://semver.org/) system to manage versioning: `<MAJOR>.<MINOR>.<PATCH>`.
- MAJOR version changes represent a significant change to the fundamental architecture of CyberChef and may (but don't always) make breaking changes that are not backwards compatible.
- MINOR version changes usually mean the addition of new operations or reasonably significant new features.
@@ -13,10 +13,10 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [9.24.0] - 2020-02-02
### [9.24.0] - 2021-02-02
- 'SM3' hashing function added along with more configuration options for other hashing operations [@n1073645] [@n1474335] | [#1022]
### [9.23.0] - 2020-02-01
### [9.23.0] - 2021-02-01
- Various RSA operations added to encrypt, decrypt, sign, verify and generate keys [@mattnotmitt] [@GCHQ77703] | [#652]
### [9.22.0] - 2021-02-01

View File

@@ -174,7 +174,7 @@ module.exports = function (grunt) {
// previous one fails. & would coninue on a fail
.join("&&")
// Windows does not support \n properly
.replace("\n", "\\n");
.replace(/\n/g, "\\n");
}
grunt.initConfig({
@@ -411,6 +411,16 @@ module.exports = function (grunt) {
]),
stdout: false,
},
fixCryptoApiImports: {
command: [
`[[ "$OSTYPE" == "darwin"* ]]`,
"&&",
`find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i '' -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`,
"||",
`find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`
].join(" "),
stdout: false
}
},
});
};

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.24.0",
"version": "9.24.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.24.0",
"version": "9.24.8",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -164,15 +164,15 @@
"zlibjs": "^0.3.1"
},
"scripts": {
"start": "grunt dev",
"build": "grunt prod",
"start": "npx grunt dev",
"build": "npx grunt prod",
"repl": "node src/node/repl.js",
"test": "grunt configTests && node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs",
"test-node-consumer": "grunt testnodeconsumer",
"testui": "grunt testui",
"test": "npx grunt configTests && node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs",
"test-node-consumer": "npx grunt testnodeconsumer",
"testui": "npx grunt testui",
"testuidev": "npx nightwatch --env=dev",
"lint": "grunt lint",
"postinstall": "bash postinstall.sh",
"lint": "npx grunt lint",
"postinstall": "npx grunt exec:fixCryptoApiImports",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
}
}

View File

@@ -1,8 +0,0 @@
#!/bin/bash
# Add file extensions to Crypto-Api imports
if [[ "$OSTYPE" == "darwin"* ]]; then
find ./node_modules/crypto-api/src/ \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i '' -e '/\.mjs/!s/\(from "\.[^"]*\)";/\1.mjs";/g'
else
find ./node_modules/crypto-api/src/ \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i -e '/\.mjs/!s/\(from "\.[^"]*\)";/\1.mjs";/g'
fi

View File

@@ -212,7 +212,7 @@ self.loadRequiredModules = function(recipeConfig) {
if (!(module in OpModules)) {
log.info(`Loading ${module} module`);
self.sendStatusMessage(`Loading ${module} module`);
self.importScripts(`${self.docURL}/modules/${module}.js`);
self.importScripts(`${self.docURL}/modules/${module}.js`); // lgtm [js/client-side-unvalidated-url-redirection]
self.sendStatusMessage("");
}
});

View File

@@ -207,7 +207,7 @@ class Dish {
const data = new Uint8Array(this.value.slice(0, 2048)),
types = detectFileType(data);
if (!types.length || !types[0].mime || !types[0].mime === "text/plain") {
if (!types.length || !types[0].mime || !(types[0].mime === "text/plain")) {
return null;
} else {
return types[0].mime;

View File

@@ -46,7 +46,7 @@ class Recipe {
module: OperationConfig[c.op].module,
ingValues: c.args,
breakpoint: c.breakpoint,
disabled: c.disabled,
disabled: c.disabled || c.op === "Comment",
});
});
}

View File

@@ -704,8 +704,21 @@ class Utils {
* Utils.stripHtmlTags("<div>Test</div>");
*/
static stripHtmlTags(htmlStr, removeScriptAndStyle=false) {
/**
* Recursively remove a pattern from a string until there are no more matches.
* Avoids incomplete sanitization e.g. "aabcbc".replace(/abc/g, "") === "abc"
*
* @param {RegExp} pattern
* @param {string} str
* @returns {string}
*/
function recursiveRemove(pattern, str) {
const newStr = str.replace(pattern, "");
return newStr.length === str.length ? newStr : recursiveRemove(pattern, newStr);
}
if (removeScriptAndStyle) {
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
htmlStr = recursiveRemove(/<(script|style)[^>]*>.*?<\/(script|style)>/gi, htmlStr);
}
return htmlStr.replace(/<[^>]+>/g, "");
}
@@ -729,11 +742,10 @@ class Utils {
">": "&gt;",
'"': "&quot;",
"'": "&#x27;", // &apos; not recommended because it's not in the HTML spec
"/": "&#x2F;", // forward slash is included as it helps end an HTML entity
"`": "&#x60;"
};
return str.replace(/[&<>"'/`]/g, function (match) {
return str.replace(/[&<>"'`]/g, function (match) {
return HTML_CHARS[match];
});
}
@@ -879,7 +891,7 @@ class Utils {
while ((m = recipeRegex.exec(recipe))) {
// Translate strings in args back to double-quotes
args = m[2]
.replace(/"/g, '\\"') // Escape double quotes
.replace(/"/g, '\\"') // Escape double quotes lgtm [js/incomplete-sanitization]
.replace(/(^|,|{|:)'/g, '$1"') // Replace opening ' with "
.replace(/([^\\]|(?:\\\\)+)'(,|:|}|$)/g, '$1"$2') // Replace closing ' with "
.replace(/\\'/g, "'"); // Unescape single quotes

View File

@@ -18,15 +18,15 @@
"From Binary",
"To Octal",
"From Octal",
"To Base64",
"From Base64",
"Show Base64 offsets",
"To Base32",
"From Base32",
"To Base58",
"From Base58",
"To Base62",
"From Base62",
"To Base64",
"From Base64",
"Show Base64 offsets",
"To Base85",
"From Base85",
"To Base",

View File

@@ -121,7 +121,7 @@ prompt.get(schema, (err, result) => {
const moduleName = result.opName.replace(/\w\S*/g, txt => {
return txt.charAt(0).toUpperCase() + txt.substr(1);
}).replace(/[\s-()/./]/g, "");
}).replace(/[\s-()./]/g, "");
const template = `/**

View File

@@ -32,9 +32,9 @@ export const ALPHABET_OPTIONS = [
* @returns {string}
*/
export function alphabetName(alphabet) {
alphabet = alphabet.replace("'", "&apos;");
alphabet = alphabet.replace("\"", "&quot;");
alphabet = alphabet.replace("\\", "&bsol;");
alphabet = alphabet.replace(/'/g, "&apos;");
alphabet = alphabet.replace(/"/g, "&quot;");
alphabet = alphabet.replace(/\\/g, "&bsol;");
let name;
ALPHABET_OPTIONS.forEach(function(a) {

View File

@@ -86,8 +86,8 @@ export function getScatterValues(input, recordDelimiter, fieldDelimiter, columnH
}
values = values.map(row => {
const x = parseFloat(row[0], 10),
y = parseFloat(row[1], 10);
const x = parseFloat(row[0]),
y = parseFloat(row[1]);
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
@@ -121,8 +121,8 @@ export function getScatterValuesWithColour(input, recordDelimiter, fieldDelimite
}
values = values.map(row => {
const x = parseFloat(row[0], 10),
y = parseFloat(row[1], 10),
const x = parseFloat(row[0]),
y = parseFloat(row[1]),
colour = row[2];
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
@@ -157,7 +157,7 @@ export function getSeriesValues(input, recordDelimiter, fieldDelimiter, columnHe
values.forEach(row => {
const serie = row[0],
xVal = row[1],
val = parseFloat(row[2], 10);
val = parseFloat(row[2]);
if (Number.isNaN(val)) throw new OperationError("Values must be numbers in base 10.");

9
src/core/lib/Crypt.mjs Normal file
View File

@@ -0,0 +1,9 @@
/**
* Crypt resources.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
export const cryptNotice = "WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";

View File

@@ -2197,14 +2197,14 @@ export const FILE_SIGNATURES = {
mime: "application/octet-stream",
description: "",
signature: {
0: 0x6b, // keych
0: 0x6b, // kych
1: 0x79,
2: 0x63,
3: 0x68,
4: 0x00,
5: 0x01
},
extractor: null
extractor: extractMacOSXKeychain
},
{
name: "TCP Packet",
@@ -2355,6 +2355,12 @@ export const FILE_SIGNATURES = {
1: 0x03,
2: 0xc6,
3: 0x04
},
{
0: 0x95,
1: 0x05,
2: 0x86,
3: 0x04
}
],
extractor: null
@@ -3406,6 +3412,26 @@ export function extractPListXML(bytes, offset) {
}
/**
* MacOS X Keychain Extactor.
*
* @param {Uint8Array} bytes
* @param {number} offset
* @returns {Uint8Array}
*/
export function extractMacOSXKeychain(bytes, offset) {
const stream = new Stream(bytes.slice(offset));
// Move to size field.
stream.moveTo(0x14);
// Move forwards by size.
stream.moveForwardsBy(stream.readInt(4));
return stream.carve();
}
/**
* OLE2 extractor.
*

View File

@@ -213,7 +213,7 @@ function locatePotentialSig(buf, sig, offset) {
export function isType(type, buf) {
const types = detectFileType(buf);
if (!(types && types.length)) return false;
if (!types.length) return false;
if (typeof type === "string") {
return types.reduce((acc, t) => {

View File

@@ -0,0 +1,219 @@
/**
* LICENSE
*
* This software is dual-licensed to the public domain and under the following
* license: you are granted a perpetual, irrevocable license to copy, modify,
* publish, and distribute this file as you see fit.
*
* VERSION
* 0.1.0 (2016-03-28) Initial release
*
* AUTHOR
* Forrest Smith
*
* CONTRIBUTORS
* J<>rgen Tjern<72> - async helper
* Anurag Awasthi - updated to 0.2.0
*/
const SEQUENTIAL_BONUS = 15; // bonus for adjacent matches
const SEPARATOR_BONUS = 30; // bonus if match occurs after a separator
const CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower
const FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched
const LEADING_LETTER_PENALTY = -5; // penalty applied for every letter in str before the first match
const MAX_LEADING_LETTER_PENALTY = -15; // maximum penalty for leading letters
const UNMATCHED_LETTER_PENALTY = -1;
/**
* Does a fuzzy search to find pattern inside a string.
* @param {*} pattern string pattern to search for
* @param {*} str string string which is being searched
* @returns [boolean, number] a boolean which tells if pattern was
* found or not and a search score
*/
export function fuzzyMatch(pattern, str) {
const recursionCount = 0;
const recursionLimit = 10;
const matches = [];
const maxMatches = 256;
return fuzzyMatchRecursive(
pattern,
str,
0 /* patternCurIndex */,
0 /* strCurrIndex */,
null /* srcMatces */,
matches,
maxMatches,
0 /* nextMatch */,
recursionCount,
recursionLimit
);
}
/**
* Recursive helper function
*/
function fuzzyMatchRecursive(
pattern,
str,
patternCurIndex,
strCurrIndex,
srcMatches,
matches,
maxMatches,
nextMatch,
recursionCount,
recursionLimit
) {
let outScore = 0;
// Return if recursion limit is reached.
if (++recursionCount >= recursionLimit) {
return [false, outScore, []];
}
// Return if we reached ends of strings.
if (patternCurIndex === pattern.length || strCurrIndex === str.length) {
return [false, outScore, []];
}
// Recursion params
let recursiveMatch = false;
let bestRecursiveMatches = [];
let bestRecursiveScore = 0;
// Loop through pattern and str looking for a match.
let firstMatch = true;
while (patternCurIndex < pattern.length && strCurrIndex < str.length) {
// Match found.
if (
pattern[patternCurIndex].toLowerCase() === str[strCurrIndex].toLowerCase()
) {
if (nextMatch >= maxMatches) {
return [false, outScore, []];
}
if (firstMatch && srcMatches) {
matches = [...srcMatches];
firstMatch = false;
}
const [matched, recursiveScore, recursiveMatches] = fuzzyMatchRecursive(
pattern,
str,
patternCurIndex,
strCurrIndex + 1,
matches,
recursiveMatches,
maxMatches,
nextMatch,
recursionCount,
recursionLimit
);
if (matched) {
// Pick best recursive score.
if (!recursiveMatch || recursiveScore > bestRecursiveScore) {
bestRecursiveMatches = [...recursiveMatches];
bestRecursiveScore = recursiveScore;
}
recursiveMatch = true;
}
matches[nextMatch++] = strCurrIndex;
++patternCurIndex;
}
++strCurrIndex;
}
const matched = patternCurIndex === pattern.length;
if (matched) {
outScore = 100;
// Apply leading letter penalty
let penalty = LEADING_LETTER_PENALTY * matches[0];
penalty =
penalty < MAX_LEADING_LETTER_PENALTY ?
MAX_LEADING_LETTER_PENALTY :
penalty;
outScore += penalty;
// Apply unmatched penalty
const unmatched = str.length - nextMatch;
outScore += UNMATCHED_LETTER_PENALTY * unmatched;
// Apply ordering bonuses
for (let i = 0; i < nextMatch; i++) {
const currIdx = matches[i];
if (i > 0) {
const prevIdx = matches[i - 1];
if (currIdx === prevIdx + 1) {
outScore += SEQUENTIAL_BONUS;
}
}
// Check for bonuses based on neighbor character value.
if (currIdx > 0) {
// Camel case
const neighbor = str[currIdx - 1];
const curr = str[currIdx];
if (
neighbor !== neighbor.toUpperCase() &&
curr !== curr.toLowerCase()
) {
outScore += CAMEL_BONUS;
}
const isNeighbourSeparator = neighbor === "_" || neighbor === " ";
if (isNeighbourSeparator) {
outScore += SEPARATOR_BONUS;
}
} else {
// First letter
outScore += FIRST_LETTER_BONUS;
}
}
// Return best result
if (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {
// Recursive score is better than "this"
matches = bestRecursiveMatches;
outScore = bestRecursiveScore;
return [true, outScore, matches];
} else if (matched) {
// "this" score is better than recursive
return [true, outScore, matches];
} else {
return [false, outScore, matches];
}
}
return [false, outScore, matches];
}
/**
* Turns a list of match indexes into a list of match ranges
*
* @author n1474335 [n1474335@gmail.com]
* @param [number] matches
* @returns [[number]]
*/
export function calcMatchRanges(matches) {
const ranges = [];
let start = matches[0],
curr = start;
matches.forEach(m => {
if (m === curr || m === curr + 1) curr = m;
else {
ranges.push([start, curr - start + 1]);
start = m;
curr = m;
}
});
ranges.push([start, curr - start + 1]);
return ranges;
}

24
src/core/lib/JWT.mjs Normal file
View File

@@ -0,0 +1,24 @@
/**
* JWT resources
*
* @author mt3571 [mt3571@protonmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
/**
* List of the JWT algorithms that can be used
*/
export const JWT_ALGORITHMS = [
"HS256",
"HS384",
"HS512",
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
"None"
];

View File

@@ -177,7 +177,7 @@ export default class Stream {
// Get the skip table.
const skiptable = preprocess(val, length);
let found = true;
let found;
while (this.position < this.length) {
// Until we hit the final element of val in the stream.

View File

@@ -41,8 +41,33 @@ class AESDecrypt extends Operation {
},
{
"name": "Mode",
"type": "option",
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
"type": "argSelector",
"value": [
{
name: "CBC",
off: [5, 6]
},
{
name: "CFB",
off: [5, 6]
},
{
name: "OFB",
off: [5, 6]
},
{
name: "CTR",
off: [5, 6]
},
{
name: "GCM",
on: [5, 6]
},
{
name: "ECB",
off: [5, 6]
}
]
},
{
"name": "Input",
@@ -59,6 +84,11 @@ class AESDecrypt extends Operation {
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
},
{
"name": "Additional Authenticated Data",
"type": "binaryString",
"value": ""
}
];
}
@@ -76,7 +106,8 @@ class AESDecrypt extends Operation {
mode = args[2],
inputType = args[3],
outputType = args[4],
gcmTag = Utils.convertToByteString(args[5].string, args[5].option);
gcmTag = Utils.convertToByteString(args[5].string, args[5].option),
aad = args[6];
if ([16, 24, 32].indexOf(key.length) < 0) {
throw new OperationError(`Invalid key length: ${key.length} bytes
@@ -92,7 +123,8 @@ The following algorithms will be used based on the size of the key:
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
decipher.start({
iv: iv.length === 0 ? "" : iv,
tag: gcmTag
tag: mode === "GCM" ? gcmTag : undefined,
additionalData: mode === "GCM" ? aad : undefined
});
decipher.update(forge.util.createBuffer(input));
const result = decipher.finish();

View File

@@ -41,8 +41,33 @@ class AESEncrypt extends Operation {
},
{
"name": "Mode",
"type": "option",
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
"type": "argSelector",
"value": [
{
name: "CBC",
off: [5]
},
{
name: "CFB",
off: [5]
},
{
name: "OFB",
off: [5]
},
{
name: "CTR",
off: [5]
},
{
name: "GCM",
on: [5]
},
{
name: "ECB",
off: [5]
}
]
},
{
"name": "Input",
@@ -53,6 +78,11 @@ class AESEncrypt extends Operation {
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
},
{
"name": "Additional Authenticated Data",
"type": "binaryString",
"value": ""
}
];
}
@@ -69,7 +99,8 @@ class AESEncrypt extends Operation {
iv = Utils.convertToByteString(args[1].string, args[1].option),
mode = args[2],
inputType = args[3],
outputType = args[4];
outputType = args[4],
aad = args[5];
if ([16, 24, 32].indexOf(key.length) < 0) {
throw new OperationError(`Invalid key length: ${key.length} bytes
@@ -83,7 +114,10 @@ The following algorithms will be used based on the size of the key:
input = Utils.convertToByteString(input, inputType);
const cipher = forge.cipher.createCipher("AES-" + mode, key);
cipher.start({iv: iv});
cipher.start({
iv: iv,
additionalData: mode === "GCM" ? aad : undefined
});
cipher.update(forge.util.createBuffer(input));
cipher.finish();

View File

@@ -125,7 +125,8 @@ class Colossus extends Operation {
},
{
name: "R1-Negate",
type: "boolean"
type: "boolean",
value: false
},
{
name: "R1-Counter",
@@ -164,7 +165,8 @@ class Colossus extends Operation {
},
{
name: "R2-Negate",
type: "boolean"
type: "boolean",
value: false
},
{
name: "R2-Counter",
@@ -203,7 +205,8 @@ class Colossus extends Operation {
},
{
name: "R3-Negate",
type: "boolean"
type: "boolean",
value: false
},
{
name: "R3-Counter",
@@ -212,7 +215,8 @@ class Colossus extends Operation {
},
{
name: "Negate All",
type: "boolean"
type: "boolean",
value: false
},
{
name: "K Rack: Addition",
@@ -220,23 +224,28 @@ class Colossus extends Operation {
},
{
name: "Add-Q1",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q2",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q3",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q4",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Q5",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add-Equals",
@@ -246,11 +255,13 @@ class Colossus extends Operation {
},
{
name: "Add-Counter1",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Add Negate All",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Total Motor",

View File

@@ -27,7 +27,7 @@ class ExtractDomains extends Operation {
{
"name": "Display total",
"type": "boolean",
"value": "Extract.DISPLAY_TOTAL"
"value": true
}
];
}

View File

@@ -39,8 +39,8 @@ class ExtractEmailAddresses extends Operation {
*/
run(input, args) {
const displayTotal = args[0],
// email regex from: https://www.regextester.com/98066
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/ig;
// email regex from: https://www.regextester.com/98066
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig;
return search(input, regex, null, displayTotal);
}

View File

@@ -38,7 +38,7 @@ class ExtractFiles extends Operation {
{
name: "Ignore failed extractions",
type: "boolean",
value: "true"
value: true
}
]);
}

View File

@@ -30,7 +30,12 @@ class FrequencyDistribution extends Operation {
{
"name": "Show 0%s",
"type": "boolean",
"value": "Entropy.FREQ_ZEROS"
"value": true
},
{
"name": "Show ASCII",
"type": "boolean",
"value": true
}
];
}
@@ -76,14 +81,14 @@ class FrequencyDistribution extends Operation {
* @returns {html}
*/
present(freq, args) {
const showZeroes = args[0];
const [showZeroes, showAscii] = args;
// Print
let output = `<canvas id='chart-area'></canvas><br>
Total data length: ${freq.dataLength}
Number of bytes represented: ${freq.bytesRepresented}
Number of bytes not represented: ${256 - freq.bytesRepresented}
Byte Percentage
<script>
var canvas = document.getElementById("chart-area"),
parentRect = canvas.parentNode.getBoundingClientRect(),
@@ -93,16 +98,32 @@ Byte Percentage
canvas.height = parentRect.height * 0.9;
CanvasComponents.drawBarChart(canvas, scores, "Byte", "Frequency %", 16, 6);
</script>`;
</script>
<table class="table table-hover table-sm">
<tr><th>Byte</th>${showAscii ? "<th>ASCII</th>" : ""}<th>Percentage</th><th></th></tr>`;
for (let i = 0; i < 256; i++) {
if (freq.distribution[i] || showZeroes) {
output += " " + Utils.hex(i, 2) + " (" +
(freq.percentages[i].toFixed(2).replace(".00", "") + "%)").padEnd(8, " ") +
Array(Math.ceil(freq.percentages[i])+1).join("|") + "\n";
let c = "";
if (showAscii) {
if (i <= 32) {
c = String.fromCharCode(0x2400 + i);
} else if (i === 127) {
c = String.fromCharCode(0x2421);
} else {
c = String.fromCharCode(i);
}
}
const bite = `<td>${Utils.hex(i, 2)}</td>`,
ascii = showAscii ? `<td>${c}</td>` : "",
percentage = `<td>${(freq.percentages[i].toFixed(2).replace(".00", "") + "%").padEnd(8, " ")}</td>`,
bars = `<td>${Array(Math.ceil(freq.percentages[i])+1).join("|")}</td>`;
output += `<tr>${bite}${ascii}${percentage}${bars}</tr>`;
}
}
output += "</table>";
return output;
}

View File

@@ -95,7 +95,7 @@ class FromBCD extends Operation {
if (!packed) {
// Discard each high nibble
for (let i = 0; i < nibbles.length; i++) {
nibbles.splice(i, 1);
nibbles.splice(i, 1); // lgtm [js/loop-iteration-skipped-due-to-shifting]
}
}

View File

@@ -46,7 +46,7 @@ class FromBase extends Operation {
}
const number = input.replace(/\s/g, "").split(".");
let result = new BigNumber(number[0], radix) || 0;
let result = new BigNumber(number[0], radix);
if (number.length === 1) return result;

View File

@@ -84,10 +84,10 @@ class FromBase32 extends Operation {
chr5 = ((enc7 & 7) << 5) | enc8;
output.push(chr1);
if (enc2 & 3 !== 0 || enc3 !== 32) output.push(chr2);
if (enc4 & 15 !== 0 || enc5 !== 32) output.push(chr3);
if (enc5 & 1 !== 0 || enc6 !== 32) output.push(chr4);
if (enc7 & 7 !== 0 || enc8 !== 32) output.push(chr5);
if ((enc2 & 3) !== 0 || enc3 !== 32) output.push(chr2);
if ((enc4 & 15) !== 0 || enc5 !== 32) output.push(chr3);
if ((enc5 & 1) !== 0 || enc6 !== 32) output.push(chr4);
if ((enc7 & 7) !== 0 || enc8 !== 32) output.push(chr5);
}
return output;

View File

@@ -9,9 +9,11 @@
import Operation from "../Operation.mjs";
import kbpgp from "kbpgp";
import { getSubkeySize, ASP } from "../lib/PGP.mjs";
import { cryptNotice } from "../lib/Crypt.mjs";
import * as es6promisify from "es6-promisify";
const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify;
/**
* Generate PGP Key Pair operation
*/
@@ -25,7 +27,7 @@ class GeneratePGPKeyPair extends Operation {
this.name = "Generate PGP Key Pair";
this.module = "PGP";
this.description = "Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.<br><br>WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";
this.description = `Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.<br><br>${cryptNotice}`;
this.infoURL = "https://wikipedia.org/wiki/Pretty_Good_Privacy";
this.inputType = "string";
this.outputType = "string";

View File

@@ -7,6 +7,7 @@
import Operation from "../Operation.mjs";
import forge from "node-forge";
import { cryptNotice } from "../lib/Crypt.mjs";
/**
* Generate RSA Key Pair operation
@@ -21,7 +22,7 @@ class GenerateRSAKeyPair extends Operation {
this.name = "Generate RSA Key Pair";
this.module = "Ciphers";
this.description = "Generate an RSA key pair with a given number of bits.<br><br>WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";
this.description = `Generate an RSA key pair with a given number of bits.<br><br>${cryptNotice}`;
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
this.inputType = "string";
this.outputType = "string";

View File

@@ -3,10 +3,11 @@
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import jwt from "jsonwebtoken";
import OperationError from "../errors/OperationError.mjs";
import {JWT_ALGORITHMS} from "../lib/JWT.mjs";
/**
* JWT Sign operation
@@ -34,18 +35,7 @@ class JWTSign extends Operation {
{
name: "Signing algorithm",
type: "option",
value: [
"HS256",
"HS384",
"HS512",
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
"None"
]
value: JWT_ALGORITHMS
}
];
}

View File

@@ -3,10 +3,11 @@
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import jwt from "jsonwebtoken";
import OperationError from "../errors/OperationError.mjs";
import {JWT_ALGORITHMS} from "../lib/JWT.mjs";
/**
* JWT Verify operation
@@ -27,7 +28,7 @@ class JWTVerify extends Operation {
this.outputType = "JSON";
this.args = [
{
name: "Private/Secret Key",
name: "Public/Secret Key",
type: "text",
value: "secret"
},
@@ -41,14 +42,11 @@ class JWTVerify extends Operation {
*/
run(input, args) {
const [key] = args;
const algos = JWT_ALGORITHMS;
algos[algos.indexOf("None")] = "none";
try {
const verified = jwt.verify(input, key, { algorithms: [
"HS256",
"HS384",
"HS512",
"none"
]});
const verified = jwt.verify(input, key, { algorithms: algos });
if (Object.prototype.hasOwnProperty.call(verified, "name") && verified.name === "JsonWebTokenError") {
throw new OperationError(verified.message);

View File

@@ -60,7 +60,8 @@ class Lorenz extends Operation {
},
{
name: "KT-Schalter",
type: "boolean"
type: "boolean",
value: false
},
{
name: "Mode",
@@ -375,7 +376,7 @@ class Lorenz extends Operation {
// Psi wheels only move sometimes, dependent on M37 current setting and limitations
const basicmotor = m37lug;
let totalmotor = basicmotor;
let totalmotor;
let lim = 0;
p5[2] = p5[1];

View File

@@ -24,6 +24,13 @@ class MicrosoftScriptDecoder extends Operation {
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.checks = [
{
pattern: "#@~\\^.{6}==(.+).{6}==\\^#~@",
flags: "i",
args: []
}
];
}
/**

View File

@@ -51,7 +51,7 @@ class OpticalCharacterRecognition extends Operation {
async run(input, args) {
const [showConfidence] = args;
if (!isWorkerEnvironment()) throw OperationError("This operation only works in a browser");
if (!isWorkerEnvironment()) throw new OperationError("This operation only works in a browser");
const type = isImage(input);
if (!type) {

View File

@@ -111,7 +111,7 @@ class PHPDeserialize extends Operation {
} else {
const numberCheck = lastItem.match(/[0-9]+/);
if (args[0] && numberCheck && numberCheck[0].length === lastItem.length) {
result.push("\"" + lastItem + "\": " + item);
result.push('"' + lastItem + '": ' + item);
} else {
result.push(lastItem + ": " + item);
}
@@ -149,11 +149,11 @@ class PHPDeserialize extends Operation {
const length = readUntil(":");
expect("\"");
const value = read(length);
expect("\";");
expect('";');
if (args[0]) {
return "\"" + value.replace(/"/g, "\\\"") + "\"";
return '"' + value.replace(/"/g, '\\"') + '"'; // lgtm [js/incomplete-sanitization]
} else {
return "\"" + value + "\"";
return '"' + value + '"';
}
}

View File

@@ -169,7 +169,7 @@ class ParseIPv6Address extends Operation {
// Detect possible EUI-64 addresses
if ((ipv6[5] & 0xff === 0xff) && (ipv6[6] >>> 8 === 0xfe)) {
if (((ipv6[5] & 0xff) === 0xff) && (ipv6[6] >>> 8 === 0xfe)) {
output += "\n\nThis IPv6 address contains a modified EUI-64 address, identified by the presence of FF:FE in the 12th and 13th octets.";
const intIdent = Utils.hex(ipv6[4] >>> 8) + ":" + Utils.hex(ipv6[4] & 0xff) + ":" +

View File

@@ -87,7 +87,7 @@ class ParseSSHHostKey extends Operation {
* @returns {byteArray}
*/
convertKeyToBinary(inputKey, inputFormat) {
const keyPattern = new RegExp(/^(?:[ssh]|[ecdsa-sha2])\S+\s+(\S*)/),
const keyPattern = new RegExp(/^(?:ssh|ecdsa-sha2)\S+\s+(\S*)/),
keyMatch = inputKey.match(keyPattern);
if (keyMatch) {

View File

@@ -45,7 +45,7 @@ class RegularExpression extends Operation {
},
{
name: "Email address",
value: "(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?\\.)+[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\\])"
value: "(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFF-a-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?\\.)+[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}\\])"
},
{
name: "URL",

View File

@@ -81,7 +81,7 @@ class SharpenImage extends Operation {
if (isWorkerEnvironment())
self.sendStatusMessage("Sharpening image... (Blurring cloned image)");
const blurImage = gaussianBlur(image.clone(), radius, 3);
const blurImage = gaussianBlur(image.clone(), radius);
if (isWorkerEnvironment())

View File

@@ -125,7 +125,7 @@ class Sort extends Operation {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(a_[i])) { // Compare numbers
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
@@ -163,7 +163,7 @@ class Sort extends Operation {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(a_[i])) { // Compare numbers
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}

View File

@@ -52,7 +52,7 @@ class ToCharcode extends Operation {
const delim = Utils.charRep(args[0] || "Space"),
base = args[1];
let output = "",
padding = 2,
padding,
ordinal;
if (base < 2 || base > 36) {

View File

@@ -47,7 +47,6 @@ class UnescapeUnicodeCharacters extends Operation {
while ((m = regex.exec(input))) {
// Add up to match
output += input.slice(i, m.index);
i = m.index;
// Add match
output += Utils.chr(parseInt(m[1], 16));

View File

@@ -153,7 +153,7 @@ class HTMLIngredient {
for (i = 0; i < this.value.length; i++) {
if ((m = this.value[i].match(/\[([a-z0-9 -()^]+)\]/i))) {
html += `<optgroup label="${m[1]}">`;
} else if ((m = this.value[i].match(/\[\/([a-z0-9 -()^]+)\]/i))) {
} else if (this.value[i].match(/\[\/([a-z0-9 -()^]+)\]/i)) {
html += "</optgroup>";
} else {
html += `<option ${this.defaultIndex === i ? "selected" : ""}>${this.value[i]}</option>`;
@@ -177,7 +177,7 @@ class HTMLIngredient {
for (i = 0; i < this.value.length; i++) {
if ((m = this.value[i].name.match(/\[([a-z0-9 -()^]+)\]/i))) {
html += `<optgroup label="${m[1]}">`;
} else if ((m = this.value[i].name.match(/\[\/([a-z0-9 -()^]+)\]/i))) {
} else if (this.value[i].name.match(/\[\/([a-z0-9 -()^]+)\]/i)) {
html += "</optgroup>";
} else {
const val = this.type === "populateMultiOption" ?

View File

@@ -5,6 +5,8 @@
*/
import HTMLIngredient from "./HTMLIngredient.mjs";
import Utils from "../core/Utils.mjs";
import url from "url";
/**
@@ -72,7 +74,7 @@ class HTMLOperation {
* @returns {string}
*/
toFullHtml() {
let html = `<div class="op-title">${this.name}</div>
let html = `<div class="op-title">${Utils.escapeHtml(this.name)}</div>
<div class="ingredients">`;
for (let i = 0; i < this.ingList.length; i++) {
@@ -91,32 +93,52 @@ class HTMLOperation {
/**
* Highlights the searched string in the name and description of the operation.
* Highlights searched strings in the name and description of the operation.
*
* @param {string} searchStr
* @param {number} namePos - The position of the search string in the operation name
* @param {number} descPos - The position of the search string in the operation description
* @param {[[number]]} nameIdxs - Indexes of the search strings in the operation name [[start, length]]
* @param {[[number]]} descIdxs - Indexes of the search strings in the operation description [[start, length]]
*/
highlightSearchString(searchStr, namePos, descPos) {
if (namePos >= 0) {
this.name = this.name.slice(0, namePos) + "<b><u>" +
this.name.slice(namePos, namePos + searchStr.length) + "</u></b>" +
this.name.slice(namePos + searchStr.length);
highlightSearchStrings(nameIdxs, descIdxs) {
if (nameIdxs.length && typeof nameIdxs[0][0] === "number") {
let opName = "",
pos = 0;
nameIdxs.forEach(idxs => {
const [start, length] = idxs;
if (typeof start !== "number") return;
opName += this.name.slice(pos, start) + "<b>" +
this.name.slice(start, start + length) + "</b>";
pos = start + length;
});
opName += this.name.slice(pos, this.name.length);
this.name = opName;
}
if (this.description && descPos >= 0) {
if (this.description && descIdxs.length && descIdxs[0][0] >= 0) {
// Find HTML tag offsets
const re = /<[^>]+>/g;
let match;
while ((match = re.exec(this.description))) {
// If the search string occurs within an HTML tag, return without highlighting it.
if (descPos >= match.index && descPos <= (match.index + match[0].length))
return;
const inHTMLTag = descIdxs.reduce((acc, idxs) => {
const start = idxs[0];
return start >= match.index && start <= (match.index + match[0].length);
}, false);
if (inHTMLTag) return;
}
this.description = this.description.slice(0, descPos) + "<b><u>" +
this.description.slice(descPos, descPos + searchStr.length) + "</u></b>" +
this.description.slice(descPos + searchStr.length);
let desc = "",
pos = 0;
descIdxs.forEach(idxs => {
const [start, length] = idxs;
desc += this.description.slice(pos, start) + "<b><u>" +
this.description.slice(start, start + length) + "</u></b>";
pos = start + length;
});
desc += this.description.slice(pos, this.description.length);
this.description = desc;
}
}
@@ -126,21 +148,29 @@ class HTMLOperation {
/**
* Given a URL for a Wikipedia (or other wiki) page, this function returns a link to that page.
*
* @param {string} url
* @param {string} urlStr
* @returns {string}
*/
function titleFromWikiLink(url) {
const splitURL = url.split("/");
if (splitURL.indexOf("wikipedia.org") < 0 && splitURL.indexOf("forensicswiki.org") < 0) {
// Not a wiki link, return full URL
return `<a href='${url}' target='_blank'>More Information<i class='material-icons inline-icon'>open_in_new</i></a>`;
function titleFromWikiLink(urlStr) {
const urlObj = url.parse(urlStr);
let wikiName = "",
pageTitle = "";
switch (urlObj.host) {
case "forensicswiki.xyz":
wikiName = "Forensics Wiki";
pageTitle = urlObj.query.substr(6).replace(/_/g, " "); // Chop off 'title='
break;
case "wikipedia.org":
wikiName = "Wikipedia";
pageTitle = urlObj.pathname.substr(6).replace(/_/g, " "); // Chop off '/wiki/'
break;
default:
// Not a wiki link, return full URL
return `<a href='${urlStr}' target='_blank'>More Information<i class='material-icons inline-icon'>open_in_new</i></a>`;
}
const wikiName = splitURL.indexOf("forensicswiki.org") < 0 ? "Wikipedia" : "Forensics Wiki";
const pageTitle = decodeURIComponent(splitURL[splitURL.length - 1])
.replace(/_/g, " ");
return `<a href='${url}' target='_blank'>${pageTitle}<i class='material-icons inline-icon'>open_in_new</i></a> on ${wikiName}`;
return `<a href='${urlObj.href}' target='_blank'>${pageTitle}<i class='material-icons inline-icon'>open_in_new</i></a> on ${wikiName}`;
}
export default HTMLOperation;

View File

@@ -153,7 +153,7 @@
<script type="text/javascript">
// Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
if (navigator.userAgent && navigator.userAgent.match(/Trident/)) {
document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
document.getElementById("notice").innerHTML += "Internet Explorer is not supported, please use Firefox or Chrome instead";
alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
}
</script>

View File

@@ -102,7 +102,7 @@ class ControlsWaiter {
const saveLinkEl = document.getElementById("save-link");
const saveLink = this.generateStateUrl(includeRecipe, includeInput, recipeConfig);
saveLinkEl.innerHTML = Utils.truncate(saveLink, 120);
saveLinkEl.innerHTML = Utils.escapeHtml(Utils.truncate(saveLink, 120));
saveLinkEl.setAttribute("href", saveLink);
}
@@ -138,7 +138,7 @@ class ControlsWaiter {
const params = [
includeRecipe ? ["recipe", recipeStr] : undefined,
includeInput ? ["input", input] : undefined,
includeInput ? ["input", Utils.escapeHtml(input)] : undefined,
];
const hash = params

View File

@@ -510,10 +510,6 @@ class InputWaiter {
if (inputNum !== activeTab) return;
const fileLoaded = document.getElementById("input-file-loaded");
let oldProgress = fileLoaded.textContent;
if (oldProgress !== "Error") {
oldProgress = parseInt(oldProgress.replace("%", ""), 10);
}
if (progress === "error") {
fileLoaded.textContent = "Error";
fileLoaded.style.color = "#FF0000";
@@ -1276,7 +1272,7 @@ class InputWaiter {
const func = function(time) {
if (this.mousedown) {
this.changeTabRight();
const newTime = (time > 50) ? time = time - 10 : 50;
const newTime = (time > 50) ? time - 10 : 50;
setTimeout(func.bind(this, [newTime]), newTime);
}
};
@@ -1293,7 +1289,7 @@ class InputWaiter {
const func = function(time) {
if (this.mousedown) {
this.changeTabLeft();
const newTime = (time > 50) ? time = time - 10 : 50;
const newTime = (time > 50) ? time - 10 : 50;
setTimeout(func.bind(this, [newTime]), newTime);
}
};

View File

@@ -6,6 +6,7 @@
import HTMLOperation from "../HTMLOperation.mjs";
import Sortable from "sortablejs";
import {fuzzyMatch, calcMatchRanges} from "../../core/lib/FuzzySearch.mjs";
/**
@@ -108,28 +109,33 @@ class OperationsWaiter {
const matchedOps = [];
const matchedDescs = [];
const searchStr = inStr.toLowerCase();
for (const opName in this.app.operations) {
const op = this.app.operations[opName];
const namePos = opName.toLowerCase().indexOf(searchStr);
const descPos = op.description.toLowerCase().indexOf(searchStr);
if (namePos >= 0 || descPos >= 0) {
// Match op name using fuzzy match
const [nameMatch, score, idxs] = fuzzyMatch(inStr, opName);
// Match description based on exact match
const descPos = op.description.toLowerCase().indexOf(inStr.toLowerCase());
if (nameMatch || descPos >= 0) {
const operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
if (highlight) {
operation.highlightSearchString(searchStr, namePos, descPos);
operation.highlightSearchStrings(calcMatchRanges(idxs), [[descPos, inStr.length]]);
}
if (namePos < 0) {
matchedOps.push(operation);
if (nameMatch) {
matchedOps.push([operation, score]);
} else {
matchedDescs.push(operation);
}
}
}
return matchedDescs.concat(matchedOps);
// Sort matched operations based on fuzzy score
matchedOps.sort((a, b) => b[1] - a[1]);
return matchedOps.map(a => a[0]).concat(matchedDescs);
}

View File

@@ -306,8 +306,6 @@ class OutputWaiter {
outputText.value = "";
outputHtml.innerHTML = "";
lines = 0;
length = 0;
this.toggleLoader(false);
return;
}
@@ -765,7 +763,7 @@ class OutputWaiter {
const func = function(time) {
if (this.mousedown) {
this.changeTabRight();
const newTime = (time > 50) ? time = time - 10 : 50;
const newTime = (time > 50) ? time - 10 : 50;
setTimeout(func.bind(this, [newTime]), newTime);
}
};
@@ -782,7 +780,7 @@ class OutputWaiter {
const func = function(time) {
if (this.mousedown) {
this.changeTabLeft();
const newTime = (time > 50) ? time = time - 10 : 50;
const newTime = (time > 50) ? time - 10 : 50;
setTimeout(func.bind(this, [newTime]), newTime);
}
};

View File

@@ -316,7 +316,7 @@ class RecipeWaiter {
};
} else if (ingList[j].getAttribute("type") === "number") {
// number
ingredients[j] = parseFloat(ingList[j].value, 10);
ingredients[j] = parseFloat(ingList[j].value);
} else {
// all others
ingredients[j] = ingList[j].value;

View File

@@ -218,7 +218,7 @@ module.exports = {
.clearValue("#search")
.setValue("#search", "md5")
.useXpath()
.waitForElementVisible("//ul[@id='search-results']//u[text()='MD5']", 1000);
.waitForElementVisible("//ul[@id='search-results']//b[text()='MD5']", 1000);
},
after: browser => {

View File

@@ -104,26 +104,26 @@ TestRegister.addTests([
}
]
},
// This test is a bit slow - it takes about 12s on my test hardware
{
name: "Bombe: 4 rotor",
input: "LUOXGJSHGEDSRDOQQX",
expectedMatch: /<td>LHSC<\/td> {2}<td>SS<\/td> {2}<td>HHHSSSGQUUQPKSEKWK<\/td>/,
recipeConfig: [
{
"op": "Bombe",
"args": [
"4-rotor",
"LEYJVCNIXWPBQMDRTAKZGFUHOS", // Beta
"EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
"AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
"BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
"AE BN CK DQ FU GY HW IJ LO MP RX SZ TV", // B thin
"THISISATESTMESSAGE", 0, false
]
}
]
},
// Takes a while to run, so disabling for general purpose testing. Re-enable if modifying this operation.
// {
// name: "Bombe: 4 rotor",
// input: "LUOXGJSHGEDSRDOQQX",
// expectedMatch: /<td>LHSC<\/td> {2}<td>SS<\/td> {2}<td>HHHSSSGQUUQPKSEKWK<\/td>/,
// recipeConfig: [
// {
// "op": "Bombe",
// "args": [
// "4-rotor",
// "LEYJVCNIXWPBQMDRTAKZGFUHOS", // Beta
// "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
// "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
// "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
// "AE BN CK DQ FU GY HW IJ LO MP RX SZ TV", // B thin
// "THISISATESTMESSAGE", 0, false
// ]
// }
// ]
// },
{
name: "Bombe: no crib",
input: "JBYALIHDYNUAAVKBYM",

File diff suppressed because one or more lines are too long

View File

@@ -25,15 +25,18 @@ TestRegister.addTests([
*
* from Crypto.Cipher import AES
* import binascii
*
* input_data = "0123456789ABCDEF"
* key = binascii.unhexlify("00112233445566778899aabbccddeeff")
* iv = binascii.unhexlify("ffeeddccbbaa99887766554433221100")
* aad = b'additional data'
*
* cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
* cipher.update(aad)
* cipher_text, tag = cipher.encrypt_and_digest(binascii.unhexlify(input_data))
*
* cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
* cipher.update(aad)
* decrypted = cipher.decrypt_and_verify(cipher_text, tag)
*
* key = binascii.hexlify(key).decode("UTF-8")
@@ -42,7 +45,7 @@ TestRegister.addTests([
* tag = binascii.hexlify(tag).decode("UTF-8")
* decrypted = binascii.hexlify(decrypted).decode("UTF-8")
*
* print("Key: {}\nIV : {}\nInput data: {}\n\nEncrypted ciphertext: {}\nGCM tag: {}\n\nDecrypted plaintext : {}".format(key, iv, input_data, cipher_text, tag, decrypted))
* print("Key: {}\nIV : {}\nInput data: {}\nAAD: {}\n\nEncrypted ciphertext: {}\nGCM tag: {}\n\nDecrypted plaintext : {}".format(key, iv, input_data, aad, cipher_text, tag, decrypted))
*
*
* Outputs:
@@ -192,7 +195,24 @@ Tag: 16a3e732a605cc9ca29108f742ca0743`,
"args": [
{"option": "Hex", "string": "00112233445566778899aabbccddeeff"},
{"option": "Hex", "string": ""},
"GCM", "Raw", "Hex"
"GCM", "Raw", "Hex", ""
]
}
],
},
{
name: "AES Encrypt: AES-128-GCM, ASCII, AAD",
input: "The quick brown fox jumps over the lazy dog.",
expectedOutput: `daa58faa056c52756aa488aeafbd265b6effcf4eca58220a97b0005b1a9b1e1c9e7a6725d35f5f79b9493de7
Tag: 3b5378917f67b0aade9891fc6c291646`,
recipeConfig: [
{
"op": "AES Encrypt",
"args": [
{"option": "Hex", "string": "00112233445566778899aabbccddeeff"},
{"option": "Hex", "string": "ffeeddccbbaa99887766554433221100"},
"GCM", "Raw", "Hex", "additional data"
]
}
],
@@ -269,7 +289,24 @@ Tag: 70fad2ca19412c20f40fd06918736e56`,
"args": [
{"option": "Hex", "string": "51e201d463698ef5f717f71f5b4712af"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex"
"GCM", "Hex", "Hex", ""
]
}
],
},
{
name: "AES Encrypt: AES-128-GCM, Binary, AAD",
input: "7a0e643132750e96d805d11e9e48e281fa39a41039286423cc1c045e5442b40bf1c3f2822bded3f9c8ef11cb25da64dda9c7ab87c246bd305385150c98f31465c2a6180fe81d31ea289b916504d5a12e1de26cb10adba84a0cb0c86f94bc14bc554f3018",
expectedOutput: `5a29debb5c5f38cdf8aee421bd94dbbf3399947faddf205f88b3ad8ecb0c51214ec0e28bf78942dfa212d7eb15259bbdcac677b4c05f473eeb9331d74f31d441d97d56eb5c73b586342d72128ca528813543dc0fc7eddb7477172cc9194c18b2e1383e4e
Tag: 61cc4b70809452b0b3e38f913fa0a109`,
recipeConfig: [
{
"op": "AES Encrypt",
"args": [
{"option": "Hex", "string": "51e201d463698ef5f717f71f5b4712af"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex", "additional data"
]
}
],
@@ -361,7 +398,24 @@ Tag: 86db597d5302595223cadbd990f1309b`,
"args": [
{"option": "Hex", "string": "6801ed503c9d96ee5f9d78b07ab1b295dba3c2adf81c7816"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex"
"GCM", "Hex", "Hex", ""
]
}
],
},
{
name: "AES Encrypt: AES-192-GCM, Binary, AAD",
input: "7a0e643132750e96d805d11e9e48e281fa39a41039286423cc1c045e5442b40bf1c3f2822bded3f9c8ef11cb25da64dda9c7ab87c246bd305385150c98f31465c2a6180fe81d31ea289b916504d5a12e1de26cb10adba84a0cb0c86f94bc14bc554f3018",
expectedOutput: `318b479d919d506f0cd904f2676fab263a7921b6d7e0514f36e03ae2333b77fa66ef5600babcb2ee9718aeb71fc357412343c1f2cb351d8715bb0aedae4a6468124f9c4aaf6a721b306beddbe63a978bec8baeeba4b663be33ee5bc982746bd4aed1c38b
Tag: aeedf3e6ca4201577c0cf3e9ce58159d`,
recipeConfig: [
{
"op": "AES Encrypt",
"args": [
{"option": "Hex", "string": "6801ed503c9d96ee5f9d78b07ab1b295dba3c2adf81c7816"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex", "additional data"
]
}
],
@@ -453,7 +507,24 @@ Tag: 821b1e5f32dad052e502775a523d957a`,
"args": [
{"option": "Hex", "string": "2d767f6e9333d1c77581946e160b2b7368c2cdd5e2b80f04ca09d64e02afbfe1"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex"
"GCM", "Hex", "Hex", ""
]
}
],
},
{
name: "AES Encrypt: AES-256-GCM, Binary, AAD",
input: "7a0e643132750e96d805d11e9e48e281fa39a41039286423cc1c045e5442b40bf1c3f2822bded3f9c8ef11cb25da64dda9c7ab87c246bd305385150c98f31465c2a6180fe81d31ea289b916504d5a12e1de26cb10adba84a0cb0c86f94bc14bc554f3018",
expectedOutput: `1287f188ad4d7ab0d9ff69b3c29cb11f861389532d8cb9337181da2e8cfc74a84927e8c0dd7a28a32fd485afe694259a63c199b199b95edd87c7aa95329feac340f2b78b72956a85f367044d821766b1b7135815571df44900695f1518cf3ae38ecb650f
Tag: a8f04c4d93bbef82bef61a103371aef9`,
recipeConfig: [
{
"op": "AES Encrypt",
"args": [
{"option": "Hex", "string": "2d767f6e9333d1c77581946e160b2b7368c2cdd5e2b80f04ca09d64e02afbfe1"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex", "additional data"
]
}
],
@@ -805,7 +876,25 @@ The following algorithms will be used based on the size of the key:
{"option": "Hex", "string": "00112233445566778899aabbccddeeff"},
{"option": "Hex", "string": ""},
"GCM", "Hex", "Raw",
{"option": "Hex", "string": "16a3e732a605cc9ca29108f742ca0743"}
{"option": "Hex", "string": "16a3e732a605cc9ca29108f742ca0743"},
""
]
}
],
},
{
name: "AES Decrypt: AES-128-GCM, ASCII, AAD",
input: "daa58faa056c52756aa488aeafbd265b6effcf4eca58220a97b0005b1a9b1e1c9e7a6725d35f5f79b9493de7",
expectedOutput: "The quick brown fox jumps over the lazy dog.",
recipeConfig: [
{
"op": "AES Decrypt",
"args": [
{"option": "Hex", "string": "00112233445566778899aabbccddeeff"},
{"option": "Hex", "string": "ffeeddccbbaa99887766554433221100"},
"GCM", "Hex", "Raw",
{"option": "Hex", "string": "3b5378917f67b0aade9891fc6c291646"},
"additional data"
]
}
],
@@ -885,7 +974,25 @@ The following algorithms will be used based on the size of the key:
{"option": "Hex", "string": "51e201d463698ef5f717f71f5b4712af"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex",
{"option": "Hex", "string": "70fad2ca19412c20f40fd06918736e56"}
{"option": "Hex", "string": "70fad2ca19412c20f40fd06918736e56"},
""
]
}
],
},
{
name: "AES Decrypt: AES-128-GCM, Binary, AAD",
input: "5a29debb5c5f38cdf8aee421bd94dbbf3399947faddf205f88b3ad8ecb0c51214ec0e28bf78942dfa212d7eb15259bbdcac677b4c05f473eeb9331d74f31d441d97d56eb5c73b586342d72128ca528813543dc0fc7eddb7477172cc9194c18b2e1383e4e",
expectedOutput: "7a0e643132750e96d805d11e9e48e281fa39a41039286423cc1c045e5442b40bf1c3f2822bded3f9c8ef11cb25da64dda9c7ab87c246bd305385150c98f31465c2a6180fe81d31ea289b916504d5a12e1de26cb10adba84a0cb0c86f94bc14bc554f3018",
recipeConfig: [
{
"op": "AES Decrypt",
"args": [
{"option": "Hex", "string": "51e201d463698ef5f717f71f5b4712af"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex",
{"option": "Hex", "string": "61cc4b70809452b0b3e38f913fa0a109"},
"additional data"
]
}
],
@@ -981,7 +1088,25 @@ The following algorithms will be used based on the size of the key:
{"option": "Hex", "string": "6801ed503c9d96ee5f9d78b07ab1b295dba3c2adf81c7816"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex",
{"option": "Hex", "string": "86db597d5302595223cadbd990f1309b"}
{"option": "Hex", "string": "86db597d5302595223cadbd990f1309b"},
""
]
}
],
},
{
name: "AES Decrypt: AES-192-GCM, Binary, AAD",
input: "318b479d919d506f0cd904f2676fab263a7921b6d7e0514f36e03ae2333b77fa66ef5600babcb2ee9718aeb71fc357412343c1f2cb351d8715bb0aedae4a6468124f9c4aaf6a721b306beddbe63a978bec8baeeba4b663be33ee5bc982746bd4aed1c38b",
expectedOutput: "7a0e643132750e96d805d11e9e48e281fa39a41039286423cc1c045e5442b40bf1c3f2822bded3f9c8ef11cb25da64dda9c7ab87c246bd305385150c98f31465c2a6180fe81d31ea289b916504d5a12e1de26cb10adba84a0cb0c86f94bc14bc554f3018",
recipeConfig: [
{
"op": "AES Decrypt",
"args": [
{"option": "Hex", "string": "6801ed503c9d96ee5f9d78b07ab1b295dba3c2adf81c7816"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex",
{"option": "Hex", "string": "aeedf3e6ca4201577c0cf3e9ce58159d"},
"additional data"
]
}
],
@@ -1077,7 +1202,25 @@ The following algorithms will be used based on the size of the key:
{"option": "Hex", "string": "2d767f6e9333d1c77581946e160b2b7368c2cdd5e2b80f04ca09d64e02afbfe1"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex",
{"option": "Hex", "string": "821b1e5f32dad052e502775a523d957a"}
{"option": "Hex", "string": "821b1e5f32dad052e502775a523d957a"},
""
]
}
],
},
{
name: "AES Decrypt: AES-256-GCM, Binary, AAD",
input: "1287f188ad4d7ab0d9ff69b3c29cb11f861389532d8cb9337181da2e8cfc74a84927e8c0dd7a28a32fd485afe694259a63c199b199b95edd87c7aa95329feac340f2b78b72956a85f367044d821766b1b7135815571df44900695f1518cf3ae38ecb650f",
expectedOutput: "7a0e643132750e96d805d11e9e48e281fa39a41039286423cc1c045e5442b40bf1c3f2822bded3f9c8ef11cb25da64dda9c7ab87c246bd305385150c98f31465c2a6180fe81d31ea289b916504d5a12e1de26cb10adba84a0cb0c86f94bc14bc554f3018",
recipeConfig: [
{
"op": "AES Decrypt",
"args": [
{"option": "Hex", "string": "2d767f6e9333d1c77581946e160b2b7368c2cdd5e2b80f04ca09d64e02afbfe1"},
{"option": "Hex", "string": "1748e7179bd56570d51fa4ba287cc3e5"},
"GCM", "Hex", "Hex",
{"option": "Hex", "string": "a8f04c4d93bbef82bef61a103371aef9"},
"additional data"
]
}
],

View File

@@ -14,10 +14,9 @@ const outputObject = JSON.stringify({
iat: 1
}, null, 4);
const invalidAlgorithm = "JsonWebTokenError: invalid algorithm";
const hsKey = "secret_cat";
const rsKey = `-----BEGIN RSA PRIVATE KEY-----
/* Retaining private key as a comment
const rsPriv = `-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw
33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW
+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
@@ -32,11 +31,24 @@ fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523
Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP
FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
-----END RSA PRIVATE KEY-----`;
const esKey = `-----BEGIN PRIVATE KEY-----
*/
const rsPub = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd
UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs
HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D
o2kQ+X5xK9cipRgEKwIDAQAB
-----END PUBLIC KEY-----`;
/* Retaining private key as a comment
const esPriv = `-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2
OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r
1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G
-----END PRIVATE KEY-----`;
*/
const esPub = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9
q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==
-----END PUBLIC KEY-----`;
TestRegister.addTests([
{
@@ -53,22 +65,22 @@ TestRegister.addTests([
{
name: "JWT Verify: RS",
input: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.MjEJhtZk2nXzigi24piMzANmrj3mILHJcDl0xOjl5a8EgdKVL1oaMEjTkMQp5RA8YrqeRBFaX-BGGCKOXn5zPY1DJwWsBUyN9C-wGR2Qye0eogH_3b4M9EW00TPCUPXm2rx8URFj7Wg9VlsmrGzLV2oKkPgkVxuFSxnpO3yjn1Y",
expectedOutput: invalidAlgorithm,
expectedOutput: outputObject,
recipeConfig: [
{
op: "JWT Verify",
args: [rsKey],
args: [rsPub],
}
],
},
{
name: "JWT Verify: ES",
input: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.WkECT51jSfpRkcpQ4x0h5Dwe7CFBI6u6Et2gWp91HC7mpN_qCFadRpsvJLtKubm6cJTLa68xtei0YrDD8fxIUA",
expectedOutput: invalidAlgorithm,
expectedOutput: outputObject,
recipeConfig: [
{
op: "JWT Verify",
args: [esKey],
args: [esPub],
}
],
}

View File

@@ -63,7 +63,8 @@ TestRegister.addTests([
{
"option": "Hex",
"string": ""
}
},
""
]
}
]