mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-21 07:16:17 -04:00
Merge branch 'master' into push-input-through-postmessage
This commit is contained in:
commit
f4988328be
42 changed files with 8758 additions and 3372 deletions
17
.cspell.json
Normal file
17
.cspell.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"version": "0.2",
|
||||||
|
"language": "en,en-gb",
|
||||||
|
"words": [],
|
||||||
|
"dictionaries": [
|
||||||
|
"npm",
|
||||||
|
"softwareTerms",
|
||||||
|
"node",
|
||||||
|
"html",
|
||||||
|
"css",
|
||||||
|
"bash",
|
||||||
|
"en-gb",
|
||||||
|
"misc"
|
||||||
|
],
|
||||||
|
"ignorePaths": ["package.json", "package-lock.json", "node_modules"]
|
||||||
|
}
|
||||||
|
|
9536
package-lock.json
generated
9536
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -61,6 +61,7 @@
|
||||||
"compression-webpack-plugin": "^11.1.0",
|
"compression-webpack-plugin": "^11.1.0",
|
||||||
"copy-webpack-plugin": "^12.0.2",
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
"core-js": "^3.37.1",
|
"core-js": "^3.37.1",
|
||||||
|
"cspell": "^8.17.3",
|
||||||
"css-loader": "7.1.2",
|
"css-loader": "7.1.2",
|
||||||
"eslint": "^9.4.0",
|
"eslint": "^9.4.0",
|
||||||
"eslint-plugin-jsdoc": "^48.2.9",
|
"eslint-plugin-jsdoc": "^48.2.9",
|
||||||
|
@ -160,7 +161,7 @@
|
||||||
"notepack.io": "^3.0.1",
|
"notepack.io": "^3.0.1",
|
||||||
"ntlm": "^0.1.3",
|
"ntlm": "^0.1.3",
|
||||||
"nwmatcher": "^1.4.4",
|
"nwmatcher": "^1.4.4",
|
||||||
"otp": "0.1.3",
|
"otpauth": "9.3.6",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
|
@ -193,6 +194,7 @@
|
||||||
"testui": "npx grunt testui",
|
"testui": "npx grunt testui",
|
||||||
"testuidev": "npx nightwatch --env=dev",
|
"testuidev": "npx nightwatch --env=dev",
|
||||||
"lint": "npx grunt lint",
|
"lint": "npx grunt lint",
|
||||||
|
"lint:grammar": "cspell ./src",
|
||||||
"postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup && npx grunt exec:fixJimpModule",
|
"postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup && npx grunt exec:fixJimpModule",
|
||||||
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
|
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
|
||||||
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",
|
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",
|
||||||
|
|
|
@ -74,7 +74,10 @@
|
||||||
"CBOR Decode",
|
"CBOR Decode",
|
||||||
"Caret/M-decode",
|
"Caret/M-decode",
|
||||||
"Rison Encode",
|
"Rison Encode",
|
||||||
"Rison Decode"
|
"Rison Decode",
|
||||||
|
"To Modhex",
|
||||||
|
"From Modhex",
|
||||||
|
"MIME Decoding"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -234,7 +237,9 @@
|
||||||
"Parse User Agent",
|
"Parse User Agent",
|
||||||
"Parse IP range",
|
"Parse IP range",
|
||||||
"Parse IPv6 address",
|
"Parse IPv6 address",
|
||||||
|
"IPv6 Transition Addresses",
|
||||||
"Parse IPv4 header",
|
"Parse IPv4 header",
|
||||||
|
"Strip IPv4 header",
|
||||||
"Parse TCP",
|
"Parse TCP",
|
||||||
"Strip TCP header",
|
"Strip TCP header",
|
||||||
"Parse TLS record",
|
"Parse TLS record",
|
||||||
|
@ -272,7 +277,8 @@
|
||||||
"Unicode Text Format",
|
"Unicode Text Format",
|
||||||
"Remove Diacritics",
|
"Remove Diacritics",
|
||||||
"Unescape Unicode Characters",
|
"Unescape Unicode Characters",
|
||||||
"Convert to NATO alphabet"
|
"Convert to NATO alphabet",
|
||||||
|
"Convert Leet Speak"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -324,7 +330,9 @@
|
||||||
"Unescape string",
|
"Unescape string",
|
||||||
"Pseudo-Random Number Generator",
|
"Pseudo-Random Number Generator",
|
||||||
"Sleep",
|
"Sleep",
|
||||||
"File Tree"
|
"File Tree",
|
||||||
|
"Take nth bytes",
|
||||||
|
"Drop nth bytes"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,3 +62,9 @@ export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:"
|
||||||
* Domain name regular expression
|
* Domain name regular expression
|
||||||
*/
|
*/
|
||||||
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DMARC Domain name regular expression
|
||||||
|
*/
|
||||||
|
export const DMARC_DOMAIN_REGEX = /\b((?=[a-z0-9_-]{1,63}\.)(xn--)?[a-z0-9_]+(-[a-z0-9_]+)*\.)+[a-z]{2,63}\b/ig;
|
||||||
|
|
165
src/core/lib/Modhex.mjs
Normal file
165
src/core/lib/Modhex.mjs
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/**
|
||||||
|
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { fromHex, toHex } from "./Hex.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modhex alphabet.
|
||||||
|
*/
|
||||||
|
const MODHEX_ALPHABET = "cbdefghijklnrtuv";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modhex alphabet map.
|
||||||
|
*/
|
||||||
|
const MODHEX_ALPHABET_MAP = MODHEX_ALPHABET.split("");
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hex alphabet to substitute Modhex.
|
||||||
|
*/
|
||||||
|
const HEX_ALPHABET = "0123456789abcdef";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hex alphabet map to substitute Modhex.
|
||||||
|
*/
|
||||||
|
const HEX_ALPHABET_MAP = HEX_ALPHABET.split("");
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a byte array into a modhex string.
|
||||||
|
*
|
||||||
|
* @param {byteArray|Uint8Array|ArrayBuffer} data
|
||||||
|
* @param {string} [delim=" "]
|
||||||
|
* @param {number} [padding=2]
|
||||||
|
* @returns {string}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // returns "cl bf bu"
|
||||||
|
* toModhex([10,20,30]);
|
||||||
|
*
|
||||||
|
* // returns "cl:bf:bu"
|
||||||
|
* toModhex([10,20,30], ":");
|
||||||
|
*/
|
||||||
|
export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
|
||||||
|
if (!data) return "";
|
||||||
|
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||||
|
|
||||||
|
const regularHexString = toHex(data, "", padding, "", 0);
|
||||||
|
|
||||||
|
let modhexString = "";
|
||||||
|
for (const letter of regularHexString.split("")) {
|
||||||
|
modhexString += MODHEX_ALPHABET_MAP[HEX_ALPHABET_MAP.indexOf(letter)];
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = "";
|
||||||
|
const groupingRegexp = new RegExp(`.{1,${padding}}`, "g");
|
||||||
|
const groupedModhex = modhexString.match(groupingRegexp);
|
||||||
|
|
||||||
|
for (let i = 0; i < groupedModhex.length; i++) {
|
||||||
|
const group = groupedModhex[i];
|
||||||
|
output += group + delim;
|
||||||
|
|
||||||
|
if (extraDelim) {
|
||||||
|
output += extraDelim;
|
||||||
|
}
|
||||||
|
// Add LF after each lineSize amount of bytes but not at the end
|
||||||
|
if ((i !== groupedModhex.length - 1) && ((i + 1) % lineSize === 0)) {
|
||||||
|
output += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the extraDelim at the end (if there is one)
|
||||||
|
// and remove the delim at the end, but if it's prepended there's nothing to remove
|
||||||
|
const rTruncLen = extraDelim.length + delim.length;
|
||||||
|
if (rTruncLen) {
|
||||||
|
// If rTruncLen === 0 then output.slice(0,0) will be returned, which is nothing
|
||||||
|
return output.slice(0, -rTruncLen);
|
||||||
|
} else {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a byte array into a modhex string as efficiently as possible with no options.
|
||||||
|
*
|
||||||
|
* @param {byteArray|Uint8Array|ArrayBuffer} data
|
||||||
|
* @returns {string}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // returns "clbfbu"
|
||||||
|
* toModhexFast([10,20,30]);
|
||||||
|
*/
|
||||||
|
export function toModhexFast(data) {
|
||||||
|
if (!data) return "";
|
||||||
|
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||||
|
|
||||||
|
const output = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
output.push(MODHEX_ALPHABET_MAP[(data[i] >> 4) & 0xf]);
|
||||||
|
output.push(MODHEX_ALPHABET_MAP[data[i] & 0xf]);
|
||||||
|
}
|
||||||
|
return output.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a modhex string into a byte array.
|
||||||
|
*
|
||||||
|
* @param {string} data
|
||||||
|
* @param {string} [delim]
|
||||||
|
* @param {number} [byteLen=2]
|
||||||
|
* @returns {byteArray}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // returns [10,20,30]
|
||||||
|
* fromModhex("cl bf bu");
|
||||||
|
*
|
||||||
|
* // returns [10,20,30]
|
||||||
|
* fromModhex("cl:bf:bu", "Colon");
|
||||||
|
*/
|
||||||
|
export function fromModhex(data, delim="Auto", byteLen=2) {
|
||||||
|
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
|
||||||
|
throw new OperationError("Byte length must be a positive integer");
|
||||||
|
|
||||||
|
// The `.replace(/\s/g, "")` an interesting workaround: Hex "multiline" tests aren't actually
|
||||||
|
// multiline. Tests for Modhex fixes that, thus exposing the issue.
|
||||||
|
data = data.toLowerCase().replace(/\s/g, "");
|
||||||
|
|
||||||
|
if (delim !== "None") {
|
||||||
|
const delimRegex = delim === "Auto" ? /[^cbdefghijklnrtuv]/gi : Utils.regexRep(delim);
|
||||||
|
data = data.split(delimRegex);
|
||||||
|
} else {
|
||||||
|
data = [data];
|
||||||
|
}
|
||||||
|
|
||||||
|
let regularHexString = "";
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
for (const letter of data[i].split("")) {
|
||||||
|
regularHexString += HEX_ALPHABET_MAP[MODHEX_ALPHABET_MAP.indexOf(letter)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = fromHex(regularHexString, "None", byteLen);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Modhex delimiters.
|
||||||
|
*/
|
||||||
|
export const TO_MODHEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "None"];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From Modhex delimiters.
|
||||||
|
*/
|
||||||
|
export const FROM_MODHEX_DELIM_OPTIONS = ["Auto"].concat(TO_MODHEX_DELIM_OPTIONS);
|
|
@ -76,8 +76,8 @@ class BlowfishDecrypt extends Operation {
|
||||||
Blowfish's key length needs to be between 4 and 56 bytes (32-448 bits).`);
|
Blowfish's key length needs to be between 4 and 56 bytes (32-448 bits).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iv.length !== 8) {
|
if (mode !== "ECB" && iv.length !== 8) {
|
||||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes. Expected 8 bytes`);
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes. Expected 8 bytes.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
input = Utils.convertToByteString(input, inputType);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
|
@ -76,8 +76,8 @@ class BlowfishEncrypt extends Operation {
|
||||||
Blowfish's key length needs to be between 4 and 56 bytes (32-448 bits).`);
|
Blowfish's key length needs to be between 4 and 56 bytes (32-448 bits).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iv.length !== 8) {
|
if (mode !== "ECB" && iv.length !== 8) {
|
||||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes. Expected 8 bytes`);
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes. Expected 8 bytes.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
input = Utils.convertToByteString(input, inputType);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
116
src/core/operations/ConvertLeetSpeak.mjs
Normal file
116
src/core/operations/ConvertLeetSpeak.mjs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/**
|
||||||
|
* @author bartblaze []
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Leet Speak operation
|
||||||
|
*/
|
||||||
|
class ConvertLeetSpeak extends Operation {
|
||||||
|
/**
|
||||||
|
* ConvertLeetSpeak constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Convert Leet Speak";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts to and from Leet Speak.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Leet";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Direction",
|
||||||
|
type: "option",
|
||||||
|
value: ["To Leet Speak", "From Leet Speak"],
|
||||||
|
defaultIndex: 0
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const direction = args[0];
|
||||||
|
|
||||||
|
if (direction === "To Leet Speak") {
|
||||||
|
return input.replace(/[a-z]/gi, char => {
|
||||||
|
const leetChar = toLeetMap[char.toLowerCase()] || char;
|
||||||
|
return char === char.toUpperCase() ? leetChar.toUpperCase() : leetChar;
|
||||||
|
});
|
||||||
|
} else if (direction === "From Leet Speak") {
|
||||||
|
return input.replace(/[48cd3f6h1jklmn0pqr57uvwxyz]/gi, char => {
|
||||||
|
const normalChar = fromLeetMap[char] || char;
|
||||||
|
return normalChar;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toLeetMap = {
|
||||||
|
"a": "4",
|
||||||
|
"b": "b",
|
||||||
|
"c": "c",
|
||||||
|
"d": "d",
|
||||||
|
"e": "3",
|
||||||
|
"f": "f",
|
||||||
|
"g": "g",
|
||||||
|
"h": "h",
|
||||||
|
"i": "1",
|
||||||
|
"j": "j",
|
||||||
|
"k": "k",
|
||||||
|
"l": "l",
|
||||||
|
"m": "m",
|
||||||
|
"n": "n",
|
||||||
|
"o": "0",
|
||||||
|
"p": "p",
|
||||||
|
"q": "q",
|
||||||
|
"r": "r",
|
||||||
|
"s": "5",
|
||||||
|
"t": "7",
|
||||||
|
"u": "u",
|
||||||
|
"v": "v",
|
||||||
|
"w": "w",
|
||||||
|
"x": "x",
|
||||||
|
"y": "y",
|
||||||
|
"z": "z"
|
||||||
|
};
|
||||||
|
|
||||||
|
const fromLeetMap = {
|
||||||
|
"4": "a",
|
||||||
|
"b": "b",
|
||||||
|
"c": "c",
|
||||||
|
"d": "d",
|
||||||
|
"3": "e",
|
||||||
|
"f": "f",
|
||||||
|
"g": "g",
|
||||||
|
"h": "h",
|
||||||
|
"1": "i",
|
||||||
|
"j": "j",
|
||||||
|
"k": "k",
|
||||||
|
"l": "l",
|
||||||
|
"m": "m",
|
||||||
|
"n": "n",
|
||||||
|
"0": "o",
|
||||||
|
"p": "p",
|
||||||
|
"q": "q",
|
||||||
|
"r": "r",
|
||||||
|
"5": "s",
|
||||||
|
"7": "t",
|
||||||
|
"u": "u",
|
||||||
|
"v": "v",
|
||||||
|
"w": "w",
|
||||||
|
"x": "x",
|
||||||
|
"y": "y",
|
||||||
|
"z": "z"
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConvertLeetSpeak;
|
||||||
|
|
|
@ -22,7 +22,7 @@ class DESDecrypt extends Operation {
|
||||||
|
|
||||||
this.name = "DES Decrypt";
|
this.name = "DES Decrypt";
|
||||||
this.module = "Ciphers";
|
this.module = "Ciphers";
|
||||||
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -72,8 +72,7 @@ class DESDecrypt extends Operation {
|
||||||
if (key.length !== 8) {
|
if (key.length !== 8) {
|
||||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
|
|
||||||
DES uses a key length of 8 bytes (64 bits).
|
DES uses a key length of 8 bytes (64 bits).`);
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
|
||||||
}
|
}
|
||||||
if (iv.length !== 8 && mode !== "ECB") {
|
if (iv.length !== 8 && mode !== "ECB") {
|
||||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||||
|
|
|
@ -22,7 +22,7 @@ class DESEncrypt extends Operation {
|
||||||
|
|
||||||
this.name = "DES Encrypt";
|
this.name = "DES Encrypt";
|
||||||
this.module = "Ciphers";
|
this.module = "Ciphers";
|
||||||
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br>Triple DES uses a key length of 24 bytes (192 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.<br><br><b>Key:</b> DES uses a key length of 8 bytes (64 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -70,8 +70,7 @@ class DESEncrypt extends Operation {
|
||||||
if (key.length !== 8) {
|
if (key.length !== 8) {
|
||||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
|
|
||||||
DES uses a key length of 8 bytes (64 bits).
|
DES uses a key length of 8 bytes (64 bits).`);
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
|
||||||
}
|
}
|
||||||
if (iv.length !== 8 && mode !== "ECB") {
|
if (iv.length !== 8 && mode !== "ECB") {
|
||||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||||
|
|
79
src/core/operations/DropNthBytes.mjs
Normal file
79
src/core/operations/DropNthBytes.mjs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
* @author Oshawk [oshawk@protonmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop nth bytes operation
|
||||||
|
*/
|
||||||
|
class DropNthBytes extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DropNthBytes constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Drop nth bytes";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Drops every nth byte starting with a given byte.";
|
||||||
|
this.infoURL = "";
|
||||||
|
this.inputType = "byteArray";
|
||||||
|
this.outputType = "byteArray";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Drop every",
|
||||||
|
type: "number",
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Starting at",
|
||||||
|
type: "number",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Apply to each line",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {byteArray} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {byteArray}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const n = args[0];
|
||||||
|
const start = args[1];
|
||||||
|
const eachLine = args[2];
|
||||||
|
|
||||||
|
if (parseInt(n, 10) !== n || n <= 0) {
|
||||||
|
throw new OperationError("'Drop every' must be a positive integer.");
|
||||||
|
}
|
||||||
|
if (parseInt(start, 10) !== start || start < 0) {
|
||||||
|
throw new OperationError("'Starting at' must be a positive or zero integer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
const output = [];
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
if (eachLine && input[i] === 0x0a) {
|
||||||
|
output.push(0x0a);
|
||||||
|
offset = i + 1;
|
||||||
|
} else if (i - offset < start || (i - (start + offset)) % n !== 0) {
|
||||||
|
output.push(input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DropNthBytes;
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
|
import { search, DOMAIN_REGEX, DMARC_DOMAIN_REGEX } from "../lib/Extract.mjs";
|
||||||
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
import { caseInsensitiveSort } from "../lib/Sort.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,6 +39,11 @@ class ExtractDomains extends Operation {
|
||||||
name: "Unique",
|
name: "Unique",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Underscore (DMARC, DKIM, etc)",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -49,11 +54,11 @@ class ExtractDomains extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const [displayTotal, sort, unique] = args;
|
const [displayTotal, sort, unique, dmarc] = args;
|
||||||
|
|
||||||
const results = search(
|
const results = search(
|
||||||
input,
|
input,
|
||||||
DOMAIN_REGEX,
|
dmarc ? DMARC_DOMAIN_REGEX : DOMAIN_REGEX,
|
||||||
null,
|
null,
|
||||||
sort ? caseInsensitiveSort : null,
|
sort ? caseInsensitiveSort : null,
|
||||||
unique
|
unique
|
||||||
|
|
84
src/core/operations/FromModhex.mjs
Normal file
84
src/core/operations/FromModhex.mjs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import { FROM_MODHEX_DELIM_OPTIONS, fromModhex } from "../lib/Modhex.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From Modhex operation
|
||||||
|
*/
|
||||||
|
class FromModhex extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FromModhex constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "From Modhex";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts a modhex byte string back into its raw value.";
|
||||||
|
this.infoURL = "https://en.wikipedia.org/wiki/YubiKey#ModHex";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "byteArray";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Delimiter",
|
||||||
|
type: "option",
|
||||||
|
value: FROM_MODHEX_DELIM_OPTIONS
|
||||||
|
}
|
||||||
|
];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^(?:[cbdefghijklnrtuv]{2})+$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^[cbdefghijklnrtuv]{2}(?: [cbdefghijklnrtuv]{2})*$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Space"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^[cbdefghijklnrtuv]{2}(?:,[cbdefghijklnrtuv]{2})*$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Comma"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^[cbdefghijklnrtuv]{2}(?:;[cbdefghijklnrtuv]{2})*$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Semi-colon"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^[cbdefghijklnrtuv]{2}(?::[cbdefghijklnrtuv]{2})*$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Colon"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^[cbdefghijklnrtuv]{2}(?:\\n[cbdefghijklnrtuv]{2})*$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["Line feed"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^[cbdefghijklnrtuv]{2}(?:\\r\\n[cbdefghijklnrtuv]{2})*$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["CRLF"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {byteArray}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const delim = args[0] || "Auto";
|
||||||
|
return fromModhex(input, delim, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FromModhex;
|
|
@ -5,16 +5,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import otp from "otp";
|
import * as OTPAuth from "otpauth";
|
||||||
import ToBase32 from "./ToBase32.mjs";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate HOTP operation
|
* Generate HOTP operation
|
||||||
*/
|
*/
|
||||||
class GenerateHOTP extends Operation {
|
class GenerateHOTP extends Operation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GenerateHOTP constructor
|
*
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
@ -31,11 +29,6 @@ class GenerateHOTP extends Operation {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Key size",
|
|
||||||
"type": "number",
|
|
||||||
"value": 32
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Code length",
|
"name": "Code length",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
@ -50,21 +43,26 @@ class GenerateHOTP extends Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ArrayBuffer} input
|
*
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const otpObj = otp({
|
const secretStr = new TextDecoder("utf-8").decode(input).trim();
|
||||||
name: args[0],
|
const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
|
||||||
keySize: args[1],
|
|
||||||
codeLength: args[2],
|
|
||||||
secret: (new ToBase32).run(input, []).split("=")[0],
|
|
||||||
});
|
|
||||||
const counter = args[3];
|
|
||||||
return `URI: ${otpObj.hotpURL}\n\nPassword: ${otpObj.hotp(counter)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const hotp = new OTPAuth.HOTP({
|
||||||
|
issuer: "",
|
||||||
|
label: args[0],
|
||||||
|
algorithm: "SHA1",
|
||||||
|
digits: args[1],
|
||||||
|
counter: args[2],
|
||||||
|
secret: OTPAuth.Secret.fromBase32(secret)
|
||||||
|
});
|
||||||
|
|
||||||
|
const uri = hotp.toString();
|
||||||
|
const code = hotp.generate();
|
||||||
|
|
||||||
|
return `URI: ${uri}\n\nPassword: ${code}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GenerateHOTP;
|
export default GenerateHOTP;
|
||||||
|
|
|
@ -5,20 +5,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import otp from "otp";
|
import * as OTPAuth from "otpauth";
|
||||||
import ToBase32 from "./ToBase32.mjs";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate TOTP operation
|
* Generate TOTP operation
|
||||||
*/
|
*/
|
||||||
class GenerateTOTP extends Operation {
|
class GenerateTOTP extends Operation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GenerateTOTP constructor
|
*
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Generate TOTP";
|
this.name = "Generate TOTP";
|
||||||
this.module = "Default";
|
this.module = "Default";
|
||||||
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
|
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
|
||||||
|
@ -31,11 +28,6 @@ class GenerateTOTP extends Operation {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"value": ""
|
"value": ""
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Key size",
|
|
||||||
"type": "number",
|
|
||||||
"value": 32
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Code length",
|
"name": "Code length",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
|
@ -55,22 +47,27 @@ class GenerateTOTP extends Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ArrayBuffer} input
|
*
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const otpObj = otp({
|
const secretStr = new TextDecoder("utf-8").decode(input).trim();
|
||||||
name: args[0],
|
const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
|
||||||
keySize: args[1],
|
|
||||||
codeLength: args[2],
|
|
||||||
secret: (new ToBase32).run(input, []).split("=")[0],
|
|
||||||
epoch: args[3],
|
|
||||||
timeSlice: args[4]
|
|
||||||
});
|
|
||||||
return `URI: ${otpObj.totpURL}\n\nPassword: ${otpObj.totp()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const totp = new OTPAuth.TOTP({
|
||||||
|
issuer: "",
|
||||||
|
label: args[0],
|
||||||
|
algorithm: "SHA1",
|
||||||
|
digits: args[1],
|
||||||
|
period: args[3],
|
||||||
|
epoch: args[2] * 1000, // Convert seconds to milliseconds
|
||||||
|
secret: OTPAuth.Secret.fromBase32(secret)
|
||||||
|
});
|
||||||
|
|
||||||
|
const uri = totp.toString();
|
||||||
|
const code = totp.generate();
|
||||||
|
|
||||||
|
return `URI: ${uri}\n\nPassword: ${code}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GenerateTOTP;
|
export default GenerateTOTP;
|
||||||
|
|
209
src/core/operations/IPv6TransitionAddresses.mjs
Normal file
209
src/core/operations/IPv6TransitionAddresses.mjs
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/**
|
||||||
|
* @author jb30795 [jb30795@proton.me]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv6 Transition Addresses operation
|
||||||
|
*/
|
||||||
|
class IPv6TransitionAddresses extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv6TransitionAddresses constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "IPv6 Transition Addresses";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts IPv4 addresses to their IPv6 Transition addresses. IPv6 Transition addresses can also be converted back into their original IPv4 address. MAC addresses can also be converted into the EUI-64 format, this can them be appended to your IPv6 /64 range to obtain a full /128 address.<br><br>Transition technologies enable translation between IPv4 and IPv6 addresses or tunneling to allow traffic to pass through the incompatible network, allowing the two standards to coexist.<br><br>Only /24 ranges and currently handled. Remove headers to easily copy out results.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/IPv6_transition_mechanism";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Ignore ranges",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Remove headers",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const XOR = {"0": "2", "1": "3", "2": "0", "3": "1", "4": "6", "5": "7", "6": "4", "7": "5", "8": "a", "9": "b", "a": "8", "b": "9", "c": "e", "d": "f", "e": "c", "f": "d"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to convert to hex
|
||||||
|
*/
|
||||||
|
function hexify(octet) {
|
||||||
|
return Number(octet).toString(16).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to convert Hex to Int
|
||||||
|
*/
|
||||||
|
function intify(hex) {
|
||||||
|
return parseInt(hex, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function converts IPv4 to IPv6 Transtion address
|
||||||
|
*/
|
||||||
|
function ipTransition(input, range) {
|
||||||
|
let output = "";
|
||||||
|
const HEXIP = input.split(".");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 6to4
|
||||||
|
*/
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "6to4: ";
|
||||||
|
}
|
||||||
|
output += "2002:" + hexify(HEXIP[0]) + hexify(HEXIP[1]) + ":" + hexify(HEXIP[2]);
|
||||||
|
if (range) {
|
||||||
|
output += "00::/40\n";
|
||||||
|
} else {
|
||||||
|
output += hexify(HEXIP[3]) + "::/48\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapped
|
||||||
|
*/
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "IPv4 Mapped: ";
|
||||||
|
}
|
||||||
|
output += "::ffff:" + hexify(HEXIP[0]) + hexify(HEXIP[1]) + ":" + hexify(HEXIP[2]);
|
||||||
|
if (range) {
|
||||||
|
output += "00/120\n";
|
||||||
|
} else {
|
||||||
|
output += hexify(HEXIP[3]) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translated
|
||||||
|
*/
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "IPv4 Translated: ";
|
||||||
|
}
|
||||||
|
output += "::ffff:0:" + hexify(HEXIP[0]) + hexify(HEXIP[1]) + ":" + hexify(HEXIP[2]);
|
||||||
|
if (range) {
|
||||||
|
output += "00/120\n";
|
||||||
|
} else {
|
||||||
|
output += hexify(HEXIP[3]) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nat64
|
||||||
|
*/
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "Nat 64: ";
|
||||||
|
}
|
||||||
|
output += "64:ff9b::" + hexify(HEXIP[0]) + hexify(HEXIP[1]) + ":" + hexify(HEXIP[2]);
|
||||||
|
if (range) {
|
||||||
|
output += "00/120\n";
|
||||||
|
} else {
|
||||||
|
output += hexify(HEXIP[3]) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert MAC to EUI-64
|
||||||
|
*/
|
||||||
|
function macTransition(input) {
|
||||||
|
let output = "";
|
||||||
|
const MACPARTS = input.split(":");
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "EUI-64 Interface ID: ";
|
||||||
|
}
|
||||||
|
const MAC = MACPARTS[0] + MACPARTS[1] + ":" + MACPARTS[2] + "ff:fe" + MACPARTS[3] + ":" + MACPARTS[4] + MACPARTS[5];
|
||||||
|
output += MAC.slice(0, 1) + XOR[MAC.slice(1, 2)] + MAC.slice(2);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert IPv6 address to its original IPv4 or MAC address
|
||||||
|
*/
|
||||||
|
function unTransition(input) {
|
||||||
|
let output = "";
|
||||||
|
let hextets = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 6to4
|
||||||
|
*/
|
||||||
|
if (input.startsWith("2002:")) {
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "IPv4: ";
|
||||||
|
}
|
||||||
|
output += String(intify(input.slice(5, 7))) + "." + String(intify(input.slice(7, 9)))+ "." + String(intify(input.slice(10, 12)))+ "." + String(intify(input.slice(12, 14))) + "\n";
|
||||||
|
} else if (input.startsWith("::ffff:") || input.startsWith("0000:0000:0000:0000:0000:ffff:") || input.startsWith("::ffff:0000:") || input.startsWith("0000:0000:0000:0000:ffff:0000:") || input.startsWith("64:ff9b::") || input.startsWith("0064:ff9b:0000:0000:0000:0000:")) {
|
||||||
|
/**
|
||||||
|
* Mapped/Translated/Nat64
|
||||||
|
*/
|
||||||
|
hextets = /:([0-9a-z]{1,4}):[0-9a-z]{1,4}$/.exec(input)[1].padStart(4, "0") + /:([0-9a-z]{1,4})$/.exec(input)[1].padStart(4, "0");
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "IPv4: ";
|
||||||
|
}
|
||||||
|
output += intify(hextets.slice(-8, -7) + hextets.slice(-7, -6)) + "." +intify(hextets.slice(-6, -5) + hextets.slice(-5, -4)) + "." +intify(hextets.slice(-4, -3) + hextets.slice(-3, -2)) + "." +intify(hextets.slice(-2, -1) + hextets.slice(-1,)) + "\n";
|
||||||
|
} else if (input.slice(-12, -7).toUpperCase() === "FF:FE") {
|
||||||
|
/**
|
||||||
|
* EUI-64
|
||||||
|
*/
|
||||||
|
if (!args[1]) {
|
||||||
|
output += "Mac Address: ";
|
||||||
|
}
|
||||||
|
const MAC = (input.slice(-19, -17) + ":" + input.slice(-17, -15) + ":" + input.slice(-14, -12) + ":" + input.slice(-7, -5) + ":" + input.slice(-4, -2) + ":" + input.slice(-2,)).toUpperCase();
|
||||||
|
output += MAC.slice(0, 1) + XOR[MAC.slice(1, 2)] + MAC.slice(2) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main
|
||||||
|
*/
|
||||||
|
let output = "";
|
||||||
|
let inputs = input.split("\n");
|
||||||
|
// Remove blank rows
|
||||||
|
inputs = inputs.filter(Boolean);
|
||||||
|
|
||||||
|
for (let i = 0; i < inputs.length; i++) {
|
||||||
|
// if ignore ranges is checked and input is a range, skip
|
||||||
|
if ((args[0] && !inputs[i].includes("/")) || (!args[0])) {
|
||||||
|
if (/^[0-9]{1,3}(?:\.[0-9]{1,3}){3}$/.test(inputs[i])) {
|
||||||
|
output += ipTransition(inputs[i], false);
|
||||||
|
} else if (/\/24$/.test(inputs[i])) {
|
||||||
|
output += ipTransition(inputs[i], true);
|
||||||
|
} else if (/^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$/.test(inputs[i])) {
|
||||||
|
output += macTransition(inputs[i]);
|
||||||
|
} else if (/^((?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/.test(inputs[i])) {
|
||||||
|
output += unTransition(inputs[i]);
|
||||||
|
} else {
|
||||||
|
output = "Enter compressed or expanded IPv6 address, IPv4 address or MAC Address.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IPv6TransitionAddresses;
|
|
@ -1,5 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @author n1073645 [n1073645@gmail.com]
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @author k3ach [k3ach@proton.me]
|
||||||
* @copyright Crown Copyright 2020
|
* @copyright Crown Copyright 2020
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -20,39 +21,46 @@ class LuhnChecksum extends Operation {
|
||||||
|
|
||||||
this.name = "Luhn Checksum";
|
this.name = "Luhn Checksum";
|
||||||
this.module = "Default";
|
this.module = "Default";
|
||||||
this.description = "The Luhn algorithm, also known as the modulus 10 or mod 10 algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers and Canadian Social Insurance Numbers.";
|
this.description = "The Luhn mod N algorithm using the english alphabet. The Luhn mod N algorithm is an extension to the Luhn algorithm (also known as mod 10 algorithm) that allows it to work with sequences of values in any even-numbered base. This can be useful when a check digit is required to validate an identification string composed of letters, a combination of letters and digits or any arbitrary set of N characters where N is divisible by 2.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Luhn_algorithm";
|
this.infoURL = "https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [];
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Radix",
|
||||||
|
"type": "number",
|
||||||
|
"value": 10
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the Luhn Checksum from the input.
|
* Generates the Luhn checksum from the input.
|
||||||
*
|
*
|
||||||
* @param {string} inputStr
|
* @param {string} inputStr
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
checksum(inputStr) {
|
checksum(inputStr, radix = 10) {
|
||||||
let even = false;
|
let even = false;
|
||||||
return inputStr.split("").reverse().reduce((acc, elem) => {
|
return inputStr.split("").reverse().reduce((acc, elem) => {
|
||||||
// Convert element to integer.
|
// Convert element to an integer based on the provided radix.
|
||||||
let temp = parseInt(elem, 10);
|
let temp = parseInt(elem, radix);
|
||||||
|
|
||||||
// If element is not an integer.
|
// If element is not a valid number in the given radix.
|
||||||
if (isNaN(temp))
|
if (isNaN(temp)) {
|
||||||
throw new OperationError("Character: " + elem + " is not a digit.");
|
throw new Error("Character: " + elem + " is not valid in radix " + radix + ".");
|
||||||
|
}
|
||||||
|
|
||||||
// If element is in an even position
|
// If element is in an even position
|
||||||
if (even) {
|
if (even) {
|
||||||
// Double the element and add the quotient and remainder together.
|
// Double the element and sum the quotient and remainder.
|
||||||
temp = 2 * elem;
|
temp = 2 * temp;
|
||||||
temp = Math.floor(temp/10) + (temp % 10);
|
temp = Math.floor(temp / radix) + (temp % radix);
|
||||||
}
|
}
|
||||||
|
|
||||||
even = !even;
|
even = !even;
|
||||||
return acc + temp;
|
return acc + temp;
|
||||||
}, 0) % 10;
|
}, 0) % radix; // Use radix as the modulus base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,9 +71,20 @@ class LuhnChecksum extends Operation {
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
if (!input) return "";
|
if (!input) return "";
|
||||||
|
|
||||||
const checkSum = this.checksum(input);
|
const radix = args[0];
|
||||||
let checkDigit = this.checksum(input + "0");
|
|
||||||
checkDigit = checkDigit === 0 ? 0 : (10-checkDigit);
|
if (radix < 2 || radix > 36) {
|
||||||
|
throw new OperationError("Error: Radix argument must be between 2 and 36");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (radix % 2 !== 0) {
|
||||||
|
throw new OperationError("Error: Radix argument must be divisible by 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkSum = this.checksum(input, radix).toString(radix);
|
||||||
|
let checkDigit = this.checksum(input + "0", radix);
|
||||||
|
checkDigit = checkDigit === 0 ? 0 : (radix - checkDigit);
|
||||||
|
checkDigit = checkDigit.toString(radix);
|
||||||
|
|
||||||
return `Checksum: ${checkSum}
|
return `Checksum: ${checkSum}
|
||||||
Checkdigit: ${checkDigit}
|
Checkdigit: ${checkDigit}
|
||||||
|
|
171
src/core/operations/MIMEDecoding.mjs
Normal file
171
src/core/operations/MIMEDecoding.mjs
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
/**
|
||||||
|
* @author mshwed [m@ttshwed.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import { fromHex } from "../lib/Hex.mjs";
|
||||||
|
import { fromBase64 } from "../lib/Base64.mjs";
|
||||||
|
import cptable from "codepage";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIME Decoding operation
|
||||||
|
*/
|
||||||
|
class MIMEDecoding extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIMEDecoding constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "MIME Decoding";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Enables the decoding of MIME message header extensions for non-ASCII text";
|
||||||
|
this.infoURL = "https://tools.ietf.org/html/rfc2047";
|
||||||
|
this.inputType = "byteArray";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {byteArray} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const mimeEncodedText = Utils.byteArrayToUtf8(input);
|
||||||
|
const encodedHeaders = mimeEncodedText.replace(/\r\n/g, "\n");
|
||||||
|
|
||||||
|
const decodedHeader = this.decodeHeaders(encodedHeaders);
|
||||||
|
|
||||||
|
return decodedHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode MIME header strings
|
||||||
|
*
|
||||||
|
* @param headerString
|
||||||
|
*/
|
||||||
|
decodeHeaders(headerString) {
|
||||||
|
// No encoded words detected
|
||||||
|
let i = headerString.indexOf("=?");
|
||||||
|
if (i === -1) return headerString;
|
||||||
|
|
||||||
|
let decodedHeaders = headerString.slice(0, i);
|
||||||
|
let header = headerString.slice(i);
|
||||||
|
|
||||||
|
let isBetweenWords = false;
|
||||||
|
let start, cur, charset, encoding, j, end, text;
|
||||||
|
while (header.length > -1) {
|
||||||
|
start = header.indexOf("=?");
|
||||||
|
if (start === -1) break;
|
||||||
|
cur = start + "=?".length;
|
||||||
|
|
||||||
|
i = header.slice(cur).indexOf("?");
|
||||||
|
if (i === -1) break;
|
||||||
|
|
||||||
|
charset = header.slice(cur, cur + i);
|
||||||
|
cur += i + "?".length;
|
||||||
|
|
||||||
|
if (header.length < cur + "Q??=".length) break;
|
||||||
|
|
||||||
|
encoding = header[cur];
|
||||||
|
cur += 1;
|
||||||
|
|
||||||
|
if (header[cur] !== "?") break;
|
||||||
|
|
||||||
|
cur += 1;
|
||||||
|
|
||||||
|
j = header.slice(cur).indexOf("?=");
|
||||||
|
if (j === -1) break;
|
||||||
|
|
||||||
|
text = header.slice(cur, cur + j);
|
||||||
|
end = cur + j + "?=".length;
|
||||||
|
|
||||||
|
if (encoding.toLowerCase() === "b") {
|
||||||
|
text = fromBase64(text);
|
||||||
|
} else if (encoding.toLowerCase() === "q") {
|
||||||
|
text = this.parseQEncodedWord(text);
|
||||||
|
} else {
|
||||||
|
isBetweenWords = false;
|
||||||
|
decodedHeaders += header.slice(0, start + 2);
|
||||||
|
header = header.slice(start + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start > 0 && (!isBetweenWords || header.slice(0, start).search(/\S/g) > -1)) {
|
||||||
|
decodedHeaders += header.slice(0, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedHeaders += this.convertFromCharset(charset, text);
|
||||||
|
|
||||||
|
header = header.slice(end);
|
||||||
|
isBetweenWords = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.length > 0) {
|
||||||
|
decodedHeaders += header;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decodedHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts decoded text for supported charsets.
|
||||||
|
* Supports UTF-8, US-ASCII, ISO-8859-*
|
||||||
|
*
|
||||||
|
* @param encodedWord
|
||||||
|
*/
|
||||||
|
convertFromCharset(charset, encodedText) {
|
||||||
|
charset = charset.toLowerCase();
|
||||||
|
const parsedCharset = charset.split("-");
|
||||||
|
|
||||||
|
if (parsedCharset.length === 2 && parsedCharset[0] === "utf" && charset === "utf-8") {
|
||||||
|
return cptable.utils.decode(65001, encodedText);
|
||||||
|
} else if (parsedCharset.length === 2 && charset === "us-ascii") {
|
||||||
|
return cptable.utils.decode(20127, encodedText);
|
||||||
|
} else if (parsedCharset.length === 3 && parsedCharset[0] === "iso" && parsedCharset[1] === "8859") {
|
||||||
|
const isoCharset = parseInt(parsedCharset[2], 10);
|
||||||
|
if (isoCharset >= 1 && isoCharset <= 16) {
|
||||||
|
return cptable.utils.decode(28590 + isoCharset, encodedText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new OperationError("Unhandled Charset");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a Q encoded word
|
||||||
|
*
|
||||||
|
* @param encodedWord
|
||||||
|
*/
|
||||||
|
parseQEncodedWord(encodedWord) {
|
||||||
|
let decodedWord = "";
|
||||||
|
for (let i = 0; i < encodedWord.length; i++) {
|
||||||
|
if (encodedWord[i] === "_") {
|
||||||
|
decodedWord += " ";
|
||||||
|
// Parse hex encoding
|
||||||
|
} else if (encodedWord[i] === "=") {
|
||||||
|
if ((i + 2) >= encodedWord.length) throw new OperationError("Incorrectly Encoded Word");
|
||||||
|
const decodedHex = Utils.byteArrayToChars(fromHex(encodedWord.substring(i + 1, i + 3)));
|
||||||
|
decodedWord += decodedHex;
|
||||||
|
i += 2;
|
||||||
|
} else if (
|
||||||
|
(encodedWord[i].charCodeAt(0) >= " ".charCodeAt(0) && encodedWord[i].charCodeAt(0) <= "~".charCodeAt(0)) ||
|
||||||
|
encodedWord[i] === "\n" ||
|
||||||
|
encodedWord[i] === "\r" ||
|
||||||
|
encodedWord[i] === "\t") {
|
||||||
|
decodedWord += encodedWord[i];
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Incorrectly Encoded Word");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decodedWord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MIMEDecoding;
|
|
@ -59,15 +59,16 @@ class ROT13 extends Operation {
|
||||||
rot13Upperacse = args[1],
|
rot13Upperacse = args[1],
|
||||||
rotNumbers = args[2];
|
rotNumbers = args[2];
|
||||||
let amount = args[3],
|
let amount = args[3],
|
||||||
chr;
|
amountNumbers = args[3];
|
||||||
|
|
||||||
if (amount) {
|
if (amount) {
|
||||||
if (amount < 0) {
|
if (amount < 0) {
|
||||||
amount = 26 - (Math.abs(amount) % 26);
|
amount = 26 - (Math.abs(amount) % 26);
|
||||||
|
amountNumbers = 10 - (Math.abs(amountNumbers) % 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < input.length; i++) {
|
for (let i = 0; i < input.length; i++) {
|
||||||
chr = input[i];
|
let chr = input[i];
|
||||||
if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case
|
if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case
|
||||||
chr = (chr - 65 + amount) % 26;
|
chr = (chr - 65 + amount) % 26;
|
||||||
output[i] = chr + 65;
|
output[i] = chr + 65;
|
||||||
|
@ -75,7 +76,7 @@ class ROT13 extends Operation {
|
||||||
chr = (chr - 97 + amount) % 26;
|
chr = (chr - 97 + amount) % 26;
|
||||||
output[i] = chr + 97;
|
output[i] = chr + 97;
|
||||||
} else if (rotNumbers && chr >= 48 && chr <= 57) { // Numbers
|
} else if (rotNumbers && chr >= 48 && chr <= 57) { // Numbers
|
||||||
chr = (chr - 48 + amount) % 10;
|
chr = (chr - 48 + amountNumbers) % 10;
|
||||||
output[i] = chr + 48;
|
output[i] = chr + 48;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
57
src/core/operations/StripIPv4Header.mjs
Normal file
57
src/core/operations/StripIPv4Header.mjs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* @author c65722 []
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Stream from "../lib/Stream.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip IPv4 header operation
|
||||||
|
*/
|
||||||
|
class StripIPv4Header extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StripIPv4Header constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Strip IPv4 header";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Strips the IPv4 header from an IPv4 packet, outputting the payload.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/IPv4";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const MIN_HEADER_LEN = 20;
|
||||||
|
|
||||||
|
const s = new Stream(new Uint8Array(input));
|
||||||
|
if (s.length < MIN_HEADER_LEN) {
|
||||||
|
throw new OperationError("Input length is less than minimum IPv4 header length");
|
||||||
|
}
|
||||||
|
|
||||||
|
const ihl = s.readInt(1) & 0x0f;
|
||||||
|
const dataOffsetBytes = ihl * 4;
|
||||||
|
if (s.length < dataOffsetBytes) {
|
||||||
|
throw new OperationError("Input length is less than IHL");
|
||||||
|
}
|
||||||
|
|
||||||
|
s.moveTo(dataOffsetBytes);
|
||||||
|
|
||||||
|
return s.getBytes().buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StripIPv4Header;
|
79
src/core/operations/TakeNthBytes.mjs
Normal file
79
src/core/operations/TakeNthBytes.mjs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
* @author Oshawk [oshawk@protonmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take nth bytes operation
|
||||||
|
*/
|
||||||
|
class TakeNthBytes extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TakeNthBytes constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Take nth bytes";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Takes every nth byte starting with a given byte.";
|
||||||
|
this.infoURL = "";
|
||||||
|
this.inputType = "byteArray";
|
||||||
|
this.outputType = "byteArray";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Take every",
|
||||||
|
type: "number",
|
||||||
|
value: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Starting at",
|
||||||
|
type: "number",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Apply to each line",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {byteArray} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {byteArray}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const n = args[0];
|
||||||
|
const start = args[1];
|
||||||
|
const eachLine = args[2];
|
||||||
|
|
||||||
|
if (parseInt(n, 10) !== n || n <= 0) {
|
||||||
|
throw new OperationError("'Take every' must be a positive integer.");
|
||||||
|
}
|
||||||
|
if (parseInt(start, 10) !== start || start < 0) {
|
||||||
|
throw new OperationError("'Starting at' must be a positive or zero integer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
const output = [];
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
if (eachLine && input[i] === 0x0a) {
|
||||||
|
output.push(0x0a);
|
||||||
|
offset = i + 1;
|
||||||
|
} else if (i - offset >= start && (i - (start + offset)) % n === 0) {
|
||||||
|
output.push(input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TakeNthBytes;
|
55
src/core/operations/ToModhex.mjs
Normal file
55
src/core/operations/ToModhex.mjs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import { TO_MODHEX_DELIM_OPTIONS, toModhex } from "../lib/Modhex.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Modhex operation
|
||||||
|
*/
|
||||||
|
class ToModhex extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToModhex constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "To Modhex";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts the input string to modhex bytes separated by the specified delimiter.";
|
||||||
|
this.infoURL = "https://en.wikipedia.org/wiki/YubiKey#ModHex";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Delimiter",
|
||||||
|
type: "option",
|
||||||
|
value: TO_MODHEX_DELIM_OPTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bytes per line",
|
||||||
|
type: "number",
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const delim = Utils.charRep(args[0]);
|
||||||
|
const lineSize = args[1];
|
||||||
|
|
||||||
|
return toModhex(new Uint8Array(input), delim, 2, "", lineSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToModhex;
|
|
@ -22,7 +22,7 @@ class TripleDESDecrypt extends Operation {
|
||||||
|
|
||||||
this.name = "Triple DES Decrypt";
|
this.name = "Triple DES Decrypt";
|
||||||
this.module = "Ciphers";
|
this.module = "Ciphers";
|
||||||
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -73,8 +73,7 @@ class TripleDESDecrypt extends Operation {
|
||||||
if (key.length !== 24 && key.length !== 16) {
|
if (key.length !== 24 && key.length !== 16) {
|
||||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
|
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).
|
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||||
DES uses a key length of 8 bytes (64 bits).`);
|
|
||||||
}
|
}
|
||||||
if (iv.length !== 8 && mode !== "ECB") {
|
if (iv.length !== 8 && mode !== "ECB") {
|
||||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||||
|
|
|
@ -22,7 +22,7 @@ class TripleDESEncrypt extends Operation {
|
||||||
|
|
||||||
this.name = "Triple DES Encrypt";
|
this.name = "Triple DES Encrypt";
|
||||||
this.module = "Ciphers";
|
this.module = "Ciphers";
|
||||||
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
this.description = "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br><br>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
this.infoURL = "https://wikipedia.org/wiki/Triple_DES";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -72,8 +72,7 @@ class TripleDESEncrypt extends Operation {
|
||||||
if (key.length !== 24 && key.length !== 16) {
|
if (key.length !== 24 && key.length !== 16) {
|
||||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
|
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).
|
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||||
DES uses a key length of 8 bytes (64 bits).`);
|
|
||||||
}
|
}
|
||||||
if (iv.length !== 8 && mode !== "ECB") {
|
if (iv.length !== 8 && mode !== "ECB") {
|
||||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||||
|
|
3
src/web/App.mjs
Executable file → Normal file
3
src/web/App.mjs
Executable file → Normal file
|
@ -60,6 +60,7 @@ class App {
|
||||||
|
|
||||||
this.initialiseSplitter();
|
this.initialiseSplitter();
|
||||||
this.loadLocalStorage();
|
this.loadLocalStorage();
|
||||||
|
this.manager.options.applyPreferredColorScheme();
|
||||||
this.populateOperationsList();
|
this.populateOperationsList();
|
||||||
this.manager.setup();
|
this.manager.setup();
|
||||||
this.manager.output.saveBombe();
|
this.manager.output.saveBombe();
|
||||||
|
@ -536,6 +537,8 @@ class App {
|
||||||
// Read in theme from URI params
|
// Read in theme from URI params
|
||||||
if (this.uriParams.theme) {
|
if (this.uriParams.theme) {
|
||||||
this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme));
|
this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme));
|
||||||
|
} else {
|
||||||
|
this.manager.options.applyPreferredColorScheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.dispatchEvent(this.manager.statechange);
|
window.dispatchEvent(this.manager.statechange);
|
||||||
|
|
8
src/web/waiters/OptionsWaiter.mjs
Executable file → Normal file
8
src/web/waiters/OptionsWaiter.mjs
Executable file → Normal file
|
@ -163,6 +163,14 @@ class OptionsWaiter {
|
||||||
themeSelect.selectedIndex = themeSelect.querySelector(`option[value="${theme}"`).index;
|
themeSelect.selectedIndex = themeSelect.querySelector(`option[value="${theme}"`).index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the user's preferred color scheme using the `prefers-color-scheme` media query.
|
||||||
|
*/
|
||||||
|
applyPreferredColorScheme() {
|
||||||
|
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||||
|
const theme = prefersDarkScheme ? "dark" : "classic";
|
||||||
|
this.changeTheme(theme);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the console logging level.
|
* Changes the console logging level.
|
||||||
|
|
|
@ -675,42 +675,42 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"Loading from URL": browser => {
|
// "Loading from URL": browser => {
|
||||||
utils.clear(browser);
|
// utils.clear(browser);
|
||||||
|
|
||||||
/* Side panel displays correct info */
|
// /* Side panel displays correct info */
|
||||||
utils.uploadFile(browser, "files/TowelDay.jpeg");
|
// utils.uploadFile(browser, "files/TowelDay.jpeg");
|
||||||
|
|
||||||
browser
|
// browser
|
||||||
.waitForElementVisible("#input-text .cm-file-details")
|
// .waitForElementVisible("#input-text .cm-file-details")
|
||||||
.waitForElementVisible("#input-text .cm-file-details .file-details-toggle-shown")
|
// .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-thumbnail")
|
||||||
.waitForElementVisible("#input-text .cm-file-details .file-details-name")
|
// .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-size")
|
||||||
.waitForElementVisible("#input-text .cm-file-details .file-details-type")
|
// .waitForElementVisible("#input-text .cm-file-details .file-details-type")
|
||||||
.waitForElementVisible("#input-text .cm-file-details .file-details-loaded");
|
// .waitForElementVisible("#input-text .cm-file-details .file-details-loaded");
|
||||||
|
|
||||||
/* Complex deep link populates the input correctly (encoding, eol, input) */
|
// /* Complex deep link populates the input correctly (encoding, eol, input) */
|
||||||
browser
|
// browser
|
||||||
.urlHash("recipe=To_Base64('A-Za-z0-9%2B/%3D')&input=VGhlIHNoaXBzIGh1bmcgaW4gdGhlIHNreSBpbiBtdWNoIHRoZSBzYW1lIHdheSB0aGF0IGJyaWNrcyBkb24ndC4M&ienc=21866&oenc=1201&ieol=FF&oeol=PS")
|
// .urlHash("recipe=To_Base64('A-Za-z0-9%2B/%3D')&input=VGhlIHNoaXBzIGh1bmcgaW4gdGhlIHNreSBpbiBtdWNoIHRoZSBzYW1lIHdheSB0aGF0IGJyaWNrcyBkb24ndC4M&ienc=21866&oenc=1201&ieol=FF&oeol=PS")
|
||||||
.waitForElementVisible("#rec-list li.operation");
|
// .waitForElementVisible("#rec-list li.operation");
|
||||||
|
|
||||||
browser.expect.element(`#input-text .cm-content`).to.have.property("textContent").match(/^.{65}$/);
|
// 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-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 .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("#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("#output-text .chr-enc-value").text.that.equals("UTF-16BE");
|
||||||
|
|
||||||
browser.expect.element("#input-text .eol-value").text.that.equals("FF");
|
// browser.expect.element("#input-text .eol-value").text.that.equals("FF");
|
||||||
browser.expect.element("#output-text .eol-value").text.that.equals("PS");
|
// browser.expect.element("#output-text .eol-value").text.that.equals("PS");
|
||||||
|
|
||||||
utils.bake(browser);
|
// utils.bake(browser);
|
||||||
|
|
||||||
browser.expect.element(`#output-text .cm-content`).to.have.property("textContent").match(/^.{44}$/);
|
// 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-length-value").text.to.equal("44");
|
||||||
browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("1");
|
// browser.expect.element("#output-text .cm-status-bar .stats-lines-value").text.to.equal("1");
|
||||||
},
|
// },
|
||||||
|
|
||||||
"Replace input with output": browser => {
|
"Replace input with output": browser => {
|
||||||
/* Input is correctly populated */
|
/* Input is correctly populated */
|
||||||
|
|
|
@ -119,7 +119,7 @@ TestRegister.addApiTests([
|
||||||
assert.strictEqual(result[0].module, "Ciphers");
|
assert.strictEqual(result[0].module, "Ciphers");
|
||||||
assert.strictEqual(result[0].inputType, "string");
|
assert.strictEqual(result[0].inputType, "string");
|
||||||
assert.strictEqual(result[0].outputType, "string");
|
assert.strictEqual(result[0].outputType, "string");
|
||||||
assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br>DES uses a key length of 8 bytes (64 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.");
|
assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.<br><br><b>Key:</b> Triple DES uses a key length of 24 bytes (192 bits).<br><br><b>IV:</b> The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used as a default.");
|
||||||
assert.strictEqual(result[0].args.length, 5);
|
assert.strictEqual(result[0].args.length, 5);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
@ -575,12 +575,11 @@ Top Drawer`, {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("Generate HOTP", () => {
|
it("Generate HOTP", () => {
|
||||||
const result = chef.generateHOTP("Cut The Mustard", {
|
const result = chef.generateHOTP("JBSWY3DPEHPK3PXP", {
|
||||||
name: "colonel",
|
|
||||||
});
|
});
|
||||||
const expected = `URI: otpauth://hotp/colonel?secret=IN2XIICUNBSSATLVON2GC4TE
|
const expected = `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0
|
||||||
|
|
||||||
Password: 034148`;
|
Password: 282760`;
|
||||||
assert.strictEqual(result.toString(), expected);
|
assert.strictEqual(result.toString(), expected);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
@ -54,11 +54,13 @@ import "./tests/Comment.mjs";
|
||||||
import "./tests/Compress.mjs";
|
import "./tests/Compress.mjs";
|
||||||
import "./tests/ConditionalJump.mjs";
|
import "./tests/ConditionalJump.mjs";
|
||||||
import "./tests/ConvertCoordinateFormat.mjs";
|
import "./tests/ConvertCoordinateFormat.mjs";
|
||||||
|
import "./tests/ConvertLeetSpeak.mjs";
|
||||||
import "./tests/ConvertToNATOAlphabet.mjs";
|
import "./tests/ConvertToNATOAlphabet.mjs";
|
||||||
import "./tests/Crypt.mjs";
|
import "./tests/Crypt.mjs";
|
||||||
import "./tests/CSV.mjs";
|
import "./tests/CSV.mjs";
|
||||||
import "./tests/DateTime.mjs";
|
import "./tests/DateTime.mjs";
|
||||||
import "./tests/DefangIP.mjs";
|
import "./tests/DefangIP.mjs";
|
||||||
|
import "./tests/DropNthBytes.mjs";
|
||||||
import "./tests/ECDSA.mjs";
|
import "./tests/ECDSA.mjs";
|
||||||
import "./tests/ELFInfo.mjs";
|
import "./tests/ELFInfo.mjs";
|
||||||
import "./tests/Enigma.mjs";
|
import "./tests/Enigma.mjs";
|
||||||
|
@ -102,6 +104,8 @@ import "./tests/LZNT1Decompress.mjs";
|
||||||
import "./tests/LZString.mjs";
|
import "./tests/LZString.mjs";
|
||||||
import "./tests/Magic.mjs";
|
import "./tests/Magic.mjs";
|
||||||
import "./tests/Media.mjs";
|
import "./tests/Media.mjs";
|
||||||
|
import "./tests/MIMEDecoding.mjs";
|
||||||
|
import "./tests/Modhex.mjs";
|
||||||
import "./tests/MorseCode.mjs";
|
import "./tests/MorseCode.mjs";
|
||||||
import "./tests/MS.mjs";
|
import "./tests/MS.mjs";
|
||||||
import "./tests/MultipleBombe.mjs";
|
import "./tests/MultipleBombe.mjs";
|
||||||
|
@ -143,11 +147,13 @@ import "./tests/SIGABA.mjs";
|
||||||
import "./tests/SM4.mjs";
|
import "./tests/SM4.mjs";
|
||||||
// import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet
|
// import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet
|
||||||
import "./tests/StrUtils.mjs";
|
import "./tests/StrUtils.mjs";
|
||||||
|
import "./tests/StripIPv4Header.mjs";
|
||||||
import "./tests/StripTCPHeader.mjs";
|
import "./tests/StripTCPHeader.mjs";
|
||||||
import "./tests/StripUDPHeader.mjs";
|
import "./tests/StripUDPHeader.mjs";
|
||||||
import "./tests/Subsection.mjs";
|
import "./tests/Subsection.mjs";
|
||||||
import "./tests/SwapCase.mjs";
|
import "./tests/SwapCase.mjs";
|
||||||
import "./tests/SymmetricDifference.mjs";
|
import "./tests/SymmetricDifference.mjs";
|
||||||
|
import "./tests/TakeNthBytes.mjs";
|
||||||
import "./tests/TextEncodingBruteForce.mjs";
|
import "./tests/TextEncodingBruteForce.mjs";
|
||||||
import "./tests/ToFromInsensitiveRegex.mjs";
|
import "./tests/ToFromInsensitiveRegex.mjs";
|
||||||
import "./tests/TranslateDateTimeFormat.mjs";
|
import "./tests/TranslateDateTimeFormat.mjs";
|
||||||
|
|
55
tests/operations/tests/ConvertLeetSpeak.mjs
Normal file
55
tests/operations/tests/ConvertLeetSpeak.mjs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* @author bartblaze []
|
||||||
|
* @copyright Crown Copyright 2025
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Convert to Leet Speak: basic text",
|
||||||
|
input: "leet",
|
||||||
|
expectedOutput: "l337",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert Leet Speak",
|
||||||
|
args: ["To Leet Speak"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Convert from Leet Speak: basic leet",
|
||||||
|
input: "l337",
|
||||||
|
expectedOutput: "leet",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert Leet Speak",
|
||||||
|
args: ["From Leet Speak"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Convert to Leet Speak: basic text, keep case",
|
||||||
|
input: "HELLO",
|
||||||
|
expectedOutput: "H3LL0",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert Leet Speak",
|
||||||
|
args: ["To Leet Speak"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Convert from Leet Speak: basic leet, keep case",
|
||||||
|
input: "H3LL0",
|
||||||
|
expectedOutput: "HeLLo",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Convert Leet Speak",
|
||||||
|
args: ["From Leet Speak"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
|
@ -580,8 +580,7 @@ Tag: a8f04c4d93bbef82bef61a103371aef9`,
|
||||||
input: "",
|
input: "",
|
||||||
expectedOutput: `Invalid key length: 0 bytes
|
expectedOutput: `Invalid key length: 0 bytes
|
||||||
|
|
||||||
DES uses a key length of 8 bytes (64 bits).
|
DES uses a key length of 8 bytes (64 bits).`,
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).`,
|
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "DES Encrypt",
|
"op": "DES Encrypt",
|
||||||
|
@ -674,8 +673,7 @@ Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||||
input: "",
|
input: "",
|
||||||
expectedOutput: `Invalid key length: 0 bytes
|
expectedOutput: `Invalid key length: 0 bytes
|
||||||
|
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).
|
Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||||
DES uses a key length of 8 bytes (64 bits).`,
|
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Triple DES Encrypt",
|
"op": "Triple DES Encrypt",
|
||||||
|
@ -1300,8 +1298,7 @@ The following algorithms will be used based on the size of the key:
|
||||||
input: "",
|
input: "",
|
||||||
expectedOutput: `Invalid key length: 0 bytes
|
expectedOutput: `Invalid key length: 0 bytes
|
||||||
|
|
||||||
DES uses a key length of 8 bytes (64 bits).
|
DES uses a key length of 8 bytes (64 bits).`,
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).`,
|
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "DES Decrypt",
|
"op": "DES Decrypt",
|
||||||
|
@ -1394,8 +1391,7 @@ Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||||
input: "",
|
input: "",
|
||||||
expectedOutput: `Invalid key length: 0 bytes
|
expectedOutput: `Invalid key length: 0 bytes
|
||||||
|
|
||||||
Triple DES uses a key length of 24 bytes (192 bits).
|
Triple DES uses a key length of 24 bytes (192 bits).`,
|
||||||
DES uses a key length of 8 bytes (64 bits).`,
|
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
"op": "Triple DES Decrypt",
|
"op": "Triple DES Decrypt",
|
||||||
|
@ -1579,19 +1575,31 @@ DES uses a key length of 8 bytes (64 bits).`,
|
||||||
from Crypto.Cipher import Blowfish
|
from Crypto.Cipher import Blowfish
|
||||||
import binascii
|
import binascii
|
||||||
|
|
||||||
input_data = b"The quick brown fox jumps over the lazy dog."
|
# Blowfish cipher parameters - key, mode, iv, segment_size, nonce
|
||||||
key = binascii.unhexlify("0011223344556677")
|
key = binascii.unhexlify("0011223344556677")
|
||||||
iv = binascii.unhexlify("0000000000000000")
|
|
||||||
mode = Blowfish.MODE_CBC
|
mode = Blowfish.MODE_CBC
|
||||||
|
kwargs = {}
|
||||||
|
iv = binascii.unhexlify("ffeeddccbbaa9988")
|
||||||
|
if mode in [Blowfish.MODE_CBC, Blowfish.MODE_CFB, Blowfish.MODE_OFB]:
|
||||||
|
kwargs = {"iv": iv}
|
||||||
|
if mode == Blowfish.MODE_CFB:
|
||||||
|
kwargs["segment_size"] = 64
|
||||||
|
if mode == Blowfish.MODE_CTR:
|
||||||
|
nonce = binascii.unhexlify("0000000000000000")
|
||||||
|
nonce = nonce[:7]
|
||||||
|
kwargs["nonce"] = nonce
|
||||||
|
|
||||||
|
cipher = Blowfish.new(key, mode, **kwargs)
|
||||||
|
|
||||||
|
# Input data and padding
|
||||||
|
input_data = b"The quick brown fox jumps over the lazy dog."
|
||||||
if mode == Blowfish.MODE_ECB or mode == Blowfish.MODE_CBC:
|
if mode == Blowfish.MODE_ECB or mode == Blowfish.MODE_CBC:
|
||||||
padding_len = 8-(len(input_data) & 7)
|
padding_len = 8-(len(input_data) & 7)
|
||||||
for i in range(padding_len):
|
for i in range(padding_len):
|
||||||
input_data += bytes([padding_len])
|
input_data += bytes([padding_len])
|
||||||
|
|
||||||
cipher = Blowfish.new(key, mode) # set iv, nonce, segment_size etc. here
|
# Encrypted text
|
||||||
cipher_text = cipher.encrypt(input_data)
|
cipher_text = cipher.encrypt(input_data)
|
||||||
|
|
||||||
cipher_text = binascii.hexlify(cipher_text).decode("UTF-8")
|
cipher_text = binascii.hexlify(cipher_text).decode("UTF-8")
|
||||||
|
|
||||||
print("Encrypted: {}".format(cipher_text))
|
print("Encrypted: {}".format(cipher_text))
|
||||||
|
|
123
tests/operations/tests/DropNthBytes.mjs
Normal file
123
tests/operations/tests/DropNthBytes.mjs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* @author Oshawk [oshawk@protonmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop nth bytes tests
|
||||||
|
*/
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 0, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Nothing (apply to each line)",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 0, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Basic single line",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "1235679",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 0, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Basic single line (apply to each line)",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "1235679",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 0, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Complex single line",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "01234678",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 5, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Complex single line (apply to each line)",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "01234678",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 5, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Basic multi line",
|
||||||
|
input: "01234\n56789",
|
||||||
|
expectedOutput: "123\n5689",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 0, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Basic multi line (apply to each line)",
|
||||||
|
input: "01234\n56789",
|
||||||
|
expectedOutput: "123\n678",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 0, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Complex multi line",
|
||||||
|
input: "01234\n56789",
|
||||||
|
expectedOutput: "012345679",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 5, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Drop nth bytes: Complex multi line (apply to each line)",
|
||||||
|
input: "012345\n6789ab",
|
||||||
|
expectedOutput: "01234\n6789a",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Drop nth bytes",
|
||||||
|
args: [4, 5, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]);
|
63
tests/operations/tests/IPv6Transition.mjs
Normal file
63
tests/operations/tests/IPv6Transition.mjs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* IPv6Transition tests.
|
||||||
|
*
|
||||||
|
* @author jb30795
|
||||||
|
*
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "IPv6 Transition: IPv4 to IPv6",
|
||||||
|
input: "198.51.100.7",
|
||||||
|
expectedOutput: "6to4: 2002:c633:6407::/48\nIPv4 Mapped: ::ffff:c633:6407\nIPv4 Translated: ::ffff:0:c633:6407\nNat 64: 64:ff9b::c633:6407",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "IPv6 Transition Addresses",
|
||||||
|
args: [true, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
name: "IPv6 Transition: IPv4 /24 Range to IPv6",
|
||||||
|
input: "198.51.100.0/24",
|
||||||
|
expectedOutput: "6to4: 2002:c633:6400::/40\nIPv4 Mapped: ::ffff:c633:6400/120\nIPv4 Translated: ::ffff:0:c633:6400/120\nNat 64: 64:ff9b::c633:6400/120",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "IPv6 Transition Addresses",
|
||||||
|
args: [false, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
name: "IPv6 Transition: IPv4 to IPv6 Remove headers",
|
||||||
|
input: "198.51.100.7",
|
||||||
|
expectedOutput: "2002:c633:6407::/48\n::ffff:c633:6407\n::ffff:0:c633:6407\n64:ff9b::c633:6407",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "IPv6 Transition Addresses",
|
||||||
|
args: [true, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
name: "IPv6 Transition: IPv6 to IPv4",
|
||||||
|
input: "64:ff9b::c633:6407",
|
||||||
|
expectedOutput: "IPv4: 198.51.100.7",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "IPv6 Transition Addresses",
|
||||||
|
args: [true, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
name: "IPv6 Transition: MAC to EUI-64",
|
||||||
|
input: "a1:b2:c3:d4:e5:f6",
|
||||||
|
expectedOutput: "EUI-64 Interface ID: a3b2:c3ff:fed4:e5f6",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "IPv6 Transition Addresses",
|
||||||
|
args: [true, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
|
@ -2,11 +2,392 @@
|
||||||
* From Decimal tests
|
* From Decimal tests
|
||||||
*
|
*
|
||||||
* @author n1073645 [n1073645@gmail.com]
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @author k3ach [k3ach@proton.me]
|
||||||
* @copyright Crown Copyright 2020
|
* @copyright Crown Copyright 2020
|
||||||
* @licence Apache-2.0
|
* @licence Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../lib/TestRegister.mjs";
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
radix: 2,
|
||||||
|
input: "01",
|
||||||
|
checksum: "1",
|
||||||
|
checkdigit: "1",
|
||||||
|
}, {
|
||||||
|
radix: 2,
|
||||||
|
input: "001111",
|
||||||
|
checksum: "0",
|
||||||
|
checkdigit: "0",
|
||||||
|
}, {
|
||||||
|
radix: 2,
|
||||||
|
input: "00011101",
|
||||||
|
checksum: "0",
|
||||||
|
checkdigit: "0",
|
||||||
|
}, {
|
||||||
|
radix: 2,
|
||||||
|
input: "0100101101",
|
||||||
|
checksum: "1",
|
||||||
|
checkdigit: "1",
|
||||||
|
}, {
|
||||||
|
radix: 4,
|
||||||
|
input: "0123",
|
||||||
|
checksum: "1",
|
||||||
|
checkdigit: "1",
|
||||||
|
}, {
|
||||||
|
radix: 4,
|
||||||
|
input: "130100",
|
||||||
|
checksum: "2",
|
||||||
|
checkdigit: "2",
|
||||||
|
}, {
|
||||||
|
radix: 4,
|
||||||
|
input: "32020313",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "0",
|
||||||
|
}, {
|
||||||
|
radix: 4,
|
||||||
|
input: "302233210112",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "0",
|
||||||
|
}, {
|
||||||
|
radix: 6,
|
||||||
|
input: "012345",
|
||||||
|
checksum: "4",
|
||||||
|
checkdigit: "4",
|
||||||
|
}, {
|
||||||
|
radix: 6,
|
||||||
|
input: "134255",
|
||||||
|
checksum: "2",
|
||||||
|
checkdigit: "4",
|
||||||
|
}, {
|
||||||
|
radix: 6,
|
||||||
|
input: "15021453",
|
||||||
|
checksum: "5",
|
||||||
|
checkdigit: "4",
|
||||||
|
}, {
|
||||||
|
radix: 6,
|
||||||
|
input: "211450230513",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "1",
|
||||||
|
}, {
|
||||||
|
radix: 8,
|
||||||
|
input: "01234567",
|
||||||
|
checksum: "2",
|
||||||
|
checkdigit: "2",
|
||||||
|
}, {
|
||||||
|
radix: 8,
|
||||||
|
input: "340624",
|
||||||
|
checksum: "0",
|
||||||
|
checkdigit: "4",
|
||||||
|
}, {
|
||||||
|
radix: 8,
|
||||||
|
input: "07260247",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "3",
|
||||||
|
}, {
|
||||||
|
radix: 8,
|
||||||
|
input: "026742114675",
|
||||||
|
checksum: "7",
|
||||||
|
checkdigit: "1",
|
||||||
|
}, {
|
||||||
|
radix: 10,
|
||||||
|
input: "0123456789",
|
||||||
|
checksum: "7",
|
||||||
|
checkdigit: "7",
|
||||||
|
}, {
|
||||||
|
radix: 10,
|
||||||
|
input: "468543",
|
||||||
|
checksum: "7",
|
||||||
|
checkdigit: "4",
|
||||||
|
}, {
|
||||||
|
radix: 10,
|
||||||
|
input: "59377601",
|
||||||
|
checksum: "5",
|
||||||
|
checkdigit: "6",
|
||||||
|
}, {
|
||||||
|
radix: 10,
|
||||||
|
input: "013909981254",
|
||||||
|
checksum: "1",
|
||||||
|
checkdigit: "3",
|
||||||
|
}, {
|
||||||
|
radix: 12,
|
||||||
|
input: "0123456789ab",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "3",
|
||||||
|
}, {
|
||||||
|
radix: 12,
|
||||||
|
input: "284685",
|
||||||
|
checksum: "0",
|
||||||
|
checkdigit: "6",
|
||||||
|
}, {
|
||||||
|
radix: 12,
|
||||||
|
input: "951a2661",
|
||||||
|
checksum: "0",
|
||||||
|
checkdigit: "8",
|
||||||
|
}, {
|
||||||
|
radix: 12,
|
||||||
|
input: "898202676387",
|
||||||
|
checksum: "b",
|
||||||
|
checkdigit: "9",
|
||||||
|
}, {
|
||||||
|
radix: 14,
|
||||||
|
input: "0123456789abcd",
|
||||||
|
checksum: "a",
|
||||||
|
checkdigit: "a",
|
||||||
|
}, {
|
||||||
|
radix: 14,
|
||||||
|
input: "33db25",
|
||||||
|
checksum: "0",
|
||||||
|
checkdigit: "d",
|
||||||
|
}, {
|
||||||
|
radix: 14,
|
||||||
|
input: "0b4ac128",
|
||||||
|
checksum: "b",
|
||||||
|
checkdigit: "3",
|
||||||
|
}, {
|
||||||
|
radix: 14,
|
||||||
|
input: "3d1c6d16160d",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "c",
|
||||||
|
}, {
|
||||||
|
radix: 16,
|
||||||
|
input: "0123456789abcdef",
|
||||||
|
checksum: "4",
|
||||||
|
checkdigit: "4",
|
||||||
|
}, {
|
||||||
|
radix: 16,
|
||||||
|
input: "e1fe64",
|
||||||
|
checksum: "b",
|
||||||
|
checkdigit: "6",
|
||||||
|
}, {
|
||||||
|
radix: 16,
|
||||||
|
input: "241a5dcd",
|
||||||
|
checksum: "1",
|
||||||
|
checkdigit: "9",
|
||||||
|
}, {
|
||||||
|
radix: 16,
|
||||||
|
input: "1fea740e0e1f",
|
||||||
|
checksum: "7",
|
||||||
|
checkdigit: "4",
|
||||||
|
}, {
|
||||||
|
radix: 18,
|
||||||
|
input: "0123456789abcdefgh",
|
||||||
|
checksum: "d",
|
||||||
|
checkdigit: "d",
|
||||||
|
}, {
|
||||||
|
radix: 18,
|
||||||
|
input: "995dgf",
|
||||||
|
checksum: "9",
|
||||||
|
checkdigit: "1",
|
||||||
|
}, {
|
||||||
|
radix: 18,
|
||||||
|
input: "9f80h32h",
|
||||||
|
checksum: "1",
|
||||||
|
checkdigit: "0",
|
||||||
|
}, {
|
||||||
|
radix: 18,
|
||||||
|
input: "5f9428e493g4",
|
||||||
|
checksum: "8",
|
||||||
|
checkdigit: "c",
|
||||||
|
}, {
|
||||||
|
radix: 20,
|
||||||
|
input: "0123456789abcdefghij",
|
||||||
|
checksum: "5",
|
||||||
|
checkdigit: "5",
|
||||||
|
}, {
|
||||||
|
radix: 20,
|
||||||
|
input: "918jci",
|
||||||
|
checksum: "h",
|
||||||
|
checkdigit: "d",
|
||||||
|
}, {
|
||||||
|
radix: 20,
|
||||||
|
input: "jab7j50d",
|
||||||
|
checksum: "g",
|
||||||
|
checkdigit: "j",
|
||||||
|
}, {
|
||||||
|
radix: 20,
|
||||||
|
input: "c56fe85eb6gg",
|
||||||
|
checksum: "g",
|
||||||
|
checkdigit: "5",
|
||||||
|
}, {
|
||||||
|
radix: 22,
|
||||||
|
input: "0123456789abcdefghijkl",
|
||||||
|
checksum: "g",
|
||||||
|
checkdigit: "g",
|
||||||
|
}, {
|
||||||
|
radix: 22,
|
||||||
|
input: "de57le",
|
||||||
|
checksum: "5",
|
||||||
|
checkdigit: "l",
|
||||||
|
}, {
|
||||||
|
radix: 22,
|
||||||
|
input: "e3fg6dfc",
|
||||||
|
checksum: "f",
|
||||||
|
checkdigit: "d",
|
||||||
|
}, {
|
||||||
|
radix: 22,
|
||||||
|
input: "1f8l80ai4kbg",
|
||||||
|
checksum: "l",
|
||||||
|
checkdigit: "f",
|
||||||
|
}, {
|
||||||
|
radix: 24,
|
||||||
|
input: "0123456789abcdefghijklmn",
|
||||||
|
checksum: "6",
|
||||||
|
checkdigit: "6",
|
||||||
|
}, {
|
||||||
|
radix: 24,
|
||||||
|
input: "agne7d",
|
||||||
|
checksum: "4",
|
||||||
|
checkdigit: "f",
|
||||||
|
}, {
|
||||||
|
radix: 24,
|
||||||
|
input: "1l4d9cf4",
|
||||||
|
checksum: "d",
|
||||||
|
checkdigit: "c",
|
||||||
|
}, {
|
||||||
|
radix: 24,
|
||||||
|
input: "blc1j09i3296",
|
||||||
|
checksum: "8",
|
||||||
|
checkdigit: "7",
|
||||||
|
}, {
|
||||||
|
radix: 26,
|
||||||
|
input: "0123456789abcdefghijklmnop",
|
||||||
|
checksum: "j",
|
||||||
|
checkdigit: "j",
|
||||||
|
}, {
|
||||||
|
radix: 26,
|
||||||
|
input: "82n9op",
|
||||||
|
checksum: "i",
|
||||||
|
checkdigit: "2",
|
||||||
|
}, {
|
||||||
|
radix: 26,
|
||||||
|
input: "e9cddn70",
|
||||||
|
checksum: "9",
|
||||||
|
checkdigit: "i",
|
||||||
|
}, {
|
||||||
|
radix: 26,
|
||||||
|
input: "ck0ep419knom",
|
||||||
|
checksum: "p",
|
||||||
|
checkdigit: "g",
|
||||||
|
}, {
|
||||||
|
radix: 28,
|
||||||
|
input: "0123456789abcdefghijklmnopqr",
|
||||||
|
checksum: "7",
|
||||||
|
checkdigit: "7",
|
||||||
|
}, {
|
||||||
|
radix: 28,
|
||||||
|
input: "a6hnoo",
|
||||||
|
checksum: "h",
|
||||||
|
checkdigit: "9",
|
||||||
|
}, {
|
||||||
|
radix: 28,
|
||||||
|
input: "lblc7kh0",
|
||||||
|
checksum: "a",
|
||||||
|
checkdigit: "f",
|
||||||
|
}, {
|
||||||
|
radix: 28,
|
||||||
|
input: "64k5piod3lmf",
|
||||||
|
checksum: "0",
|
||||||
|
checkdigit: "p",
|
||||||
|
}, {
|
||||||
|
radix: 30,
|
||||||
|
input: "0123456789abcdefghijklmnopqrst",
|
||||||
|
checksum: "m",
|
||||||
|
checkdigit: "m",
|
||||||
|
}, {
|
||||||
|
radix: 30,
|
||||||
|
input: "t69j7d",
|
||||||
|
checksum: "9",
|
||||||
|
checkdigit: "s",
|
||||||
|
}, {
|
||||||
|
radix: 30,
|
||||||
|
input: "p54o9ig3",
|
||||||
|
checksum: "a",
|
||||||
|
checkdigit: "o",
|
||||||
|
}, {
|
||||||
|
radix: 30,
|
||||||
|
input: "gc1njrt55030",
|
||||||
|
checksum: "6",
|
||||||
|
checkdigit: "1",
|
||||||
|
}, {
|
||||||
|
radix: 32,
|
||||||
|
input: "0123456789abcdefghijklmnopqrstuv",
|
||||||
|
checksum: "8",
|
||||||
|
checkdigit: "8",
|
||||||
|
}, {
|
||||||
|
radix: 32,
|
||||||
|
input: "rdou19",
|
||||||
|
checksum: "u",
|
||||||
|
checkdigit: "3",
|
||||||
|
}, {
|
||||||
|
radix: 32,
|
||||||
|
input: "ighj0pc7",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "8",
|
||||||
|
}, {
|
||||||
|
radix: 32,
|
||||||
|
input: "op4nn5fvjsrs",
|
||||||
|
checksum: "g",
|
||||||
|
checkdigit: "j",
|
||||||
|
}, {
|
||||||
|
radix: 34,
|
||||||
|
input: "0123456789abcdefghijklmnopqrstuvwx",
|
||||||
|
checksum: "p",
|
||||||
|
checkdigit: "p",
|
||||||
|
}, {
|
||||||
|
radix: 34,
|
||||||
|
input: "nvftj5",
|
||||||
|
checksum: "b",
|
||||||
|
checkdigit: "f",
|
||||||
|
}, {
|
||||||
|
radix: 34,
|
||||||
|
input: "u9v9g162",
|
||||||
|
checksum: "j",
|
||||||
|
checkdigit: "b",
|
||||||
|
}, {
|
||||||
|
radix: 34,
|
||||||
|
input: "o5gqg5d7gjh9",
|
||||||
|
checksum: "5",
|
||||||
|
checkdigit: "q",
|
||||||
|
}, {
|
||||||
|
radix: 36,
|
||||||
|
input: "0123456789abcdefghijklmnopqrstuvwxyz",
|
||||||
|
checksum: "9",
|
||||||
|
checkdigit: "9",
|
||||||
|
}, {
|
||||||
|
radix: 36,
|
||||||
|
input: "29zehu",
|
||||||
|
checksum: "i",
|
||||||
|
checkdigit: "j",
|
||||||
|
}, {
|
||||||
|
radix: 36,
|
||||||
|
input: "1snmikbu",
|
||||||
|
checksum: "s",
|
||||||
|
checkdigit: "v",
|
||||||
|
}, {
|
||||||
|
radix: 36,
|
||||||
|
input: "jpkar545q7gb",
|
||||||
|
checksum: "3",
|
||||||
|
checkdigit: "d",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
testCases.forEach(element => {
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Luhn Checksum Mod " + element.radix + " on " + element.input,
|
||||||
|
input: element.input,
|
||||||
|
expectedOutput: "Checksum: " + element.checksum + "\nCheckdigit: " + element.checkdigit + "\nLuhn Validated String: " + element.input + element.checkdigit,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Luhn Checksum",
|
||||||
|
args: [element.radix]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Luhn Checksum on standard data",
|
name: "Luhn Checksum on standard data",
|
||||||
|
@ -15,7 +396,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Luhn Checksum",
|
op: "Luhn Checksum",
|
||||||
args: []
|
args: [10]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -26,7 +407,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Luhn Checksum",
|
op: "Luhn Checksum",
|
||||||
args: []
|
args: [10]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -37,18 +418,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Luhn Checksum",
|
op: "Luhn Checksum",
|
||||||
args: []
|
args: [10]
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Luhn Checksum on invalid data",
|
|
||||||
input: "35641709b012469",
|
|
||||||
expectedOutput: "Character: b is not a digit.",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "Luhn Checksum",
|
|
||||||
args: []
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -59,8 +429,8 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Luhn Checksum",
|
op: "Luhn Checksum",
|
||||||
args: []
|
args: [10]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
89
tests/operations/tests/MIMEDecoding.mjs
Normal file
89
tests/operations/tests/MIMEDecoding.mjs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/**
|
||||||
|
* MIME Header Decoding tests
|
||||||
|
*
|
||||||
|
* @author mshwed [m@ttshwed.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Encoded comments",
|
||||||
|
input: "(=?ISO-8859-1?Q?a?=)",
|
||||||
|
expectedOutput: "(a)",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "MIME Decoding",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Encoded adjacent comments whitespace",
|
||||||
|
input: "(=?ISO-8859-1?Q?a?= b)",
|
||||||
|
expectedOutput: "(a b)",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "MIME Decoding",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Encoded adjacent single whitespace ignored",
|
||||||
|
input: "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)",
|
||||||
|
expectedOutput: "(ab)",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "MIME Decoding",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Encoded adjacent double whitespace ignored",
|
||||||
|
input: "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)",
|
||||||
|
expectedOutput: "(ab)",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "MIME Decoding",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Encoded adjacent CRLF whitespace ignored",
|
||||||
|
input: "(=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?=)",
|
||||||
|
expectedOutput: "(ab)",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "MIME Decoding",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "UTF-8 Encodings Multiple Headers",
|
||||||
|
input: "=?utf-8?q?=C3=89ric?= <eric@example.org>, =?utf-8?q?Ana=C3=AFs?= <anais@example.org>",
|
||||||
|
expectedOutput: "Éric <eric@example.org>, Anaïs <anais@example.org>",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "MIME Decoding",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ISO Decoding",
|
||||||
|
input: "From: =?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>\nTo: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>\nCC: =?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>\nSubject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\n=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=",
|
||||||
|
expectedOutput: "From: Keith Moore <moore@cs.utk.edu>\nTo: Keld Jørn Simonsen <keld@dkuug.dk>\nCC: André Pirard <PIRARD@vm1.ulg.ac.be>\nSubject: If you can read this you understand the example.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "MIME Decoding",
|
||||||
|
"args": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
150
tests/operations/tests/Modhex.mjs
Normal file
150
tests/operations/tests/Modhex.mjs
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/**
|
||||||
|
* Modhex operation tests.
|
||||||
|
* @author linuxgemini [ilteris@asenkron.com.tr]
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "ASCII to Modhex stream",
|
||||||
|
input: "aberystwyth",
|
||||||
|
expectedOutput: "hbhdhgidikieifiiikifhj",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Modhex",
|
||||||
|
"args": [
|
||||||
|
"None",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ASCII to Modhex with colon deliminator",
|
||||||
|
input: "aberystwyth",
|
||||||
|
expectedOutput: "hb:hd:hg:id:ik:ie:if:ii:ik:if:hj",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Modhex",
|
||||||
|
"args": [
|
||||||
|
"Colon",
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Modhex stream to UTF-8",
|
||||||
|
input: "uhkgkbuhkgkbugltlkugltkc",
|
||||||
|
expectedOutput: "救救孩子",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Modhex",
|
||||||
|
"args": [
|
||||||
|
"Auto"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mixed case Modhex stream to UTF-8",
|
||||||
|
input: "uhKGkbUHkgkBUGltlkugltkc",
|
||||||
|
expectedOutput: "救救孩子",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Modhex",
|
||||||
|
"args": [
|
||||||
|
"Auto"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mutiline Modhex with comma to ASCII (Auto Mode)",
|
||||||
|
input: "fk,dc,ie,hb,ii,dc,ht,ik,ie,hg,hr,hh,dc,ie,hk,\n\
|
||||||
|
if,if,hk,hu,hi,dc,hk,hu,dc,if,hj,hg,dc,he,id,\n\
|
||||||
|
hv,if,he,hj,dc,hv,hh,dc,if,hj,hg,dc,if,hj,hk,\n\
|
||||||
|
ie,dc,hh,hk,hi,dc,if,id,hg,hg,dr,dc,ie,if,hb,\n\
|
||||||
|
id,ih,hk,hu,hi,dc,if,hv,dc,hf,hg,hb,if,hj,dr,\n\
|
||||||
|
dc,hl,ig,ie,if,dc,hd,hg,he,hb,ig,ie,hg,dc,fk,\n\
|
||||||
|
dc,he,hv,ig,hr,hf,hu,di,if,dc,ht,hb,hn,hg,dc,\n\
|
||||||
|
ig,ic,dc,ht,ik,dc,ht,hk,hu,hf,dc,ii,hj,hk,he,\n\
|
||||||
|
hj,dc,hv,hh,dc,if,hj,hg,dc,hh,hk,hi,ie,dc,fk,\n\
|
||||||
|
dc,ii,hv,ig,hr,hf,dc,he,hj,hv,hv,ie,hg,du",
|
||||||
|
expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Modhex",
|
||||||
|
"args": [
|
||||||
|
"Auto"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mutiline Modhex with percent to ASCII (Percent Mode)",
|
||||||
|
input: "fk%dc%ie%hb%ii%dc%ht%ik%ie%hg%hr%hh%dc%ie%hk%\n\
|
||||||
|
if%if%hk%hu%hi%dc%hk%hu%dc%if%hj%hg%dc%he%id%\n\
|
||||||
|
hv%if%he%hj%dc%hv%hh%dc%if%hj%hg%dc%if%hj%hk%\n\
|
||||||
|
ie%dc%hh%hk%hi%dc%if%id%hg%hg%dr%dc%ie%if%hb%\n\
|
||||||
|
id%ih%hk%hu%hi%dc%if%hv%dc%hf%hg%hb%if%hj%dr%\n\
|
||||||
|
dc%hl%ig%ie%if%dc%hd%hg%he%hb%ig%ie%hg%dc%fk%\n\
|
||||||
|
dc%he%hv%ig%hr%hf%hu%di%if%dc%ht%hb%hn%hg%dc%\n\
|
||||||
|
ig%ic%dc%ht%ik%dc%ht%hk%hu%hf%dc%ii%hj%hk%he%\n\
|
||||||
|
hj%dc%hv%hh%dc%if%hj%hg%dc%hh%hk%hi%ie%dc%fk%\n\
|
||||||
|
dc%ii%hv%ig%hr%hf%dc%he%hj%hv%hv%ie%hg%du",
|
||||||
|
expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Modhex",
|
||||||
|
"args": [
|
||||||
|
"Percent"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mutiline Modhex with semicolon to ASCII (Semi-colon Mode)",
|
||||||
|
input: "fk;dc;ie;hb;ii;dc;ht;ik;ie;hg;hr;hh;dc;ie;hk;\n\
|
||||||
|
if;if;hk;hu;hi;dc;hk;hu;dc;if;hj;hg;dc;he;id;\n\
|
||||||
|
hv;if;he;hj;dc;hv;hh;dc;if;hj;hg;dc;if;hj;hk;\n\
|
||||||
|
ie;dc;hh;hk;hi;dc;if;id;hg;hg;dr;dc;ie;if;hb;\n\
|
||||||
|
id;ih;hk;hu;hi;dc;if;hv;dc;hf;hg;hb;if;hj;dr;\n\
|
||||||
|
dc;hl;ig;ie;if;dc;hd;hg;he;hb;ig;ie;hg;dc;fk;\n\
|
||||||
|
dc;he;hv;ig;hr;hf;hu;di;if;dc;ht;hb;hn;hg;dc;\n\
|
||||||
|
ig;ic;dc;ht;ik;dc;ht;hk;hu;hf;dc;ii;hj;hk;he;\n\
|
||||||
|
hj;dc;hv;hh;dc;if;hj;hg;dc;hh;hk;hi;ie;dc;fk;\n\
|
||||||
|
dc;ii;hv;ig;hr;hf;dc;he;hj;hv;hv;ie;hg;du",
|
||||||
|
expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "From Modhex",
|
||||||
|
"args": [
|
||||||
|
"Semi-colon"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ASCII to Modhex with comma and line breaks",
|
||||||
|
input: "aberystwyth",
|
||||||
|
expectedOutput: "hb,hd,hg,id,\nik,ie,if,ii,\nik,if,hj",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
"op": "To Modhex",
|
||||||
|
"args": [
|
||||||
|
"Comma",
|
||||||
|
4
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]);
|
|
@ -11,12 +11,12 @@ import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
name: "Generate HOTP",
|
name: "Generate HOTP",
|
||||||
input: "12345678901234567890",
|
input: "JBSWY3DPEHPK3PXP",
|
||||||
expectedOutput: "URI: otpauth://hotp/OTPAuthentication?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ\n\nPassword: 755224",
|
expectedOutput: `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Generate HOTP",
|
op: "Generate HOTP",
|
||||||
args: ["", 32, 6, 0],
|
args: ["", 6, 0], // [Name, Code length, Counter]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -135,10 +135,21 @@ TestRegister.addTests([
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ROT13: no shift amount",
|
||||||
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "ROT13",
|
||||||
|
args: [true, true, true, 0]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ROT13: normal",
|
name: "ROT13: normal",
|
||||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt.",
|
expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt. 3456789012",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "ROT13",
|
op: "ROT13",
|
||||||
|
@ -146,10 +157,21 @@ TestRegister.addTests([
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ROT13: negative shift amount",
|
||||||
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt. 7890123456",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "ROT13",
|
||||||
|
args: [true, true, true, -13]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ROT13: full loop",
|
name: "ROT13: full loop",
|
||||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 6789012345",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "ROT13",
|
op: "ROT13",
|
||||||
|
@ -157,10 +179,21 @@ TestRegister.addTests([
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ROT13: full loop (negative shift amount)",
|
||||||
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 4567890123",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "ROT13",
|
||||||
|
args: [true, true, true, -26]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ROT13: lowercase only",
|
name: "ROT13: lowercase only",
|
||||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
expectedOutput: "Tur Qhvpx Bebja Fbk Jhzcrq Oire Tur Lnml Dbt.",
|
expectedOutput: "Tur Qhvpx Bebja Fbk Jhzcrq Oire Tur Lnml Dbt. 0123456789",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "ROT13",
|
op: "ROT13",
|
||||||
|
@ -170,8 +203,8 @@ TestRegister.addTests([
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ROT13: uppercase only",
|
name: "ROT13: uppercase only",
|
||||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
expectedOutput: "Ghe Duick Orown Sox Wumped Bver Ghe Yazy Qog.",
|
expectedOutput: "Ghe Duick Orown Sox Wumped Bver Ghe Yazy Qog. 0123456789",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "ROT13",
|
op: "ROT13",
|
||||||
|
@ -179,6 +212,50 @@ TestRegister.addTests([
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ROT13: numbers only",
|
||||||
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 5678901234",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "ROT13",
|
||||||
|
args: [false, false, true, 5]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ROT13: numbers only (negative shift amount)",
|
||||||
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 5678901234",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "ROT13",
|
||||||
|
args: [false, false, true, 5]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ROT13: numbers only loop",
|
||||||
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "ROT13",
|
||||||
|
args: [false, false, true, 10]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ROT13: numbers only loop (negative shift amount)",
|
||||||
|
input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "ROT13",
|
||||||
|
args: [false, false, true, -10]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "ROT47: nothing",
|
name: "ROT47: nothing",
|
||||||
input: "",
|
input: "",
|
||||||
|
|
126
tests/operations/tests/StripIPv4Header.mjs
Normal file
126
tests/operations/tests/StripIPv4Header.mjs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/**
|
||||||
|
* Strip IPv4 header tests.
|
||||||
|
*
|
||||||
|
* @author c65722 []
|
||||||
|
* @copyright Crown Copyright 2024
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Strip IPv4 header: No options, No payload",
|
||||||
|
input: "450000140005400080060000c0a80001c0a80002",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hex",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Strip IPv4 header",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Hex",
|
||||||
|
args: ["None", 0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Strip IPv4 header: No options, Payload",
|
||||||
|
input: "450000140005400080060000c0a80001c0a80002ffffffffffffffff",
|
||||||
|
expectedOutput: "ffffffffffffffff",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hex",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Strip IPv4 header",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Hex",
|
||||||
|
args: ["None", 0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Strip IPv4 header: Options, No payload",
|
||||||
|
input: "460000140005400080060000c0a80001c0a8000207000000",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hex",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Strip IPv4 header",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Hex",
|
||||||
|
args: ["None", 0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Strip IPv4 header: Options, Payload",
|
||||||
|
input: "460000140005400080060000c0a80001c0a8000207000000ffffffffffffffff",
|
||||||
|
expectedOutput: "ffffffffffffffff",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hex",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Strip IPv4 header",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Hex",
|
||||||
|
args: ["None", 0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Strip IPv4 header: Input length lesss than minimum header length",
|
||||||
|
input: "450000140005400080060000c0a80001c0a800",
|
||||||
|
expectedOutput: "Input length is less than minimum IPv4 header length",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hex",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Strip IPv4 header",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Hex",
|
||||||
|
args: ["None", 0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Strip IPv4 header: Input length less than IHL",
|
||||||
|
input: "460000140005400080060000c0a80001c0a80000",
|
||||||
|
expectedOutput: "Input length is less than IHL",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Hex",
|
||||||
|
args: ["None"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Strip IPv4 header",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Hex",
|
||||||
|
args: ["None", 0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
123
tests/operations/tests/TakeNthBytes.mjs
Normal file
123
tests/operations/tests/TakeNthBytes.mjs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* @author Oshawk [oshawk@protonmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import TestRegister from "../../lib/TestRegister.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take nth bytes tests
|
||||||
|
*/
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 0, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Nothing (apply to each line)",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 0, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Basic single line",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "048",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 0, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Basic single line (apply to each line)",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "048",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 0, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Complex single line",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "59",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 5, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Complex single line (apply to each line)",
|
||||||
|
input: "0123456789",
|
||||||
|
expectedOutput: "59",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 5, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Basic multi line",
|
||||||
|
input: "01234\n56789",
|
||||||
|
expectedOutput: "047",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 0, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Basic multi line (apply to each line)",
|
||||||
|
input: "01234\n56789",
|
||||||
|
expectedOutput: "04\n59",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 0, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Complex multi line",
|
||||||
|
input: "01234\n56789",
|
||||||
|
expectedOutput: "\n8",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 5, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Take nth bytes: Complex multi line (apply to each line)",
|
||||||
|
input: "012345\n6789ab",
|
||||||
|
expectedOutput: "5\nb",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Take nth bytes",
|
||||||
|
args: [4, 5, true],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]);
|
Loading…
Add table
Add a link
Reference in a new issue