mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-11 16:51:31 -04:00
Merge branch 'master' of github.com:gchq/CyberChef into simplify-recipe
This commit is contained in:
commit
a49d97f898
46 changed files with 9132 additions and 4884 deletions
61
src/core/operations/CipherSaber2Decrypt.mjs
Normal file
61
src/core/operations/CipherSaber2Decrypt.mjs
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { encode } from "../lib/CipherSaber2.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* CipherSaber2 Decrypt operation
|
||||
*/
|
||||
class CipherSaber2Decrypt extends Operation {
|
||||
|
||||
/**
|
||||
* CipherSaber2Decrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CipherSaber2 Decrypt";
|
||||
this.module = "Crypto";
|
||||
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Rounds",
|
||||
type: "number",
|
||||
value: 20
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = new Uint8Array(input);
|
||||
const result = [],
|
||||
key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
rounds = args[1];
|
||||
|
||||
const tempIVP = input.slice(0, 10);
|
||||
input = input.slice(10);
|
||||
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CipherSaber2Decrypt;
|
65
src/core/operations/CipherSaber2Encrypt.mjs
Normal file
65
src/core/operations/CipherSaber2Encrypt.mjs
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import crypto from "crypto";
|
||||
import { encode } from "../lib/CipherSaber2.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* CipherSaber2 Encrypt operation
|
||||
*/
|
||||
class CipherSaber2Encrypt extends Operation {
|
||||
|
||||
/**
|
||||
* CipherSaber2Encrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CipherSaber2 Encrypt";
|
||||
this.module = "Crypto";
|
||||
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
name: "Key",
|
||||
type: "toggleString",
|
||||
value: "",
|
||||
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
name: "Rounds",
|
||||
type: "number",
|
||||
value: 20
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = new Uint8Array(input);
|
||||
const result = [],
|
||||
key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
rounds = args[1];
|
||||
|
||||
// Assign into initialisation vector based on cipher mode.
|
||||
const tempIVP = crypto.randomBytes(10);
|
||||
for (let m = 0; m < 10; m++)
|
||||
result.push(tempIVP[m]);
|
||||
|
||||
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CipherSaber2Encrypt;
|
572
src/core/operations/Colossus.mjs
Normal file
572
src/core/operations/Colossus.mjs
Normal file
|
@ -0,0 +1,572 @@
|
|||
/**
|
||||
* Emulation of Colossus.
|
||||
*
|
||||
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { ColossusComputer } from "../lib/Colossus.mjs";
|
||||
import { SWITCHES, VALID_ITA2 } from "../lib/Lorenz.mjs";
|
||||
|
||||
/**
|
||||
* Colossus operation
|
||||
*/
|
||||
class Colossus extends Operation {
|
||||
|
||||
/**
|
||||
* Colossus constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
this.name = "Colossus";
|
||||
this.module = "Bletchley";
|
||||
this.description = "Colossus is the name of the world's first electronic computer. Ten Colossi were designed by Tommy Flowers and built at the Post Office Research Labs at Dollis Hill in 1943 during World War 2. They assisted with the breaking of the German Lorenz cipher attachment, a machine created to encipher communications between Hitler and his generals on the front lines.<br><br>To learn more, Virtual Colossus, an online, browser based simulation of a Colossus computer is available at <a href='https://virtualcolossus.co.uk' target='_blank'>virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Colossus' target='_blank'>here</a>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Colossus_computer";
|
||||
this.inputType = "string";
|
||||
this.outputType = "JSON";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
name: "Input",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "Pattern",
|
||||
type: "option",
|
||||
value: ["KH Pattern", "ZMUG Pattern", "BREAM Pattern"]
|
||||
},
|
||||
{
|
||||
name: "QBusZ",
|
||||
type: "option",
|
||||
value: ["", "Z", "ΔZ"]
|
||||
},
|
||||
{
|
||||
name: "QBusΧ",
|
||||
type: "option",
|
||||
value: ["", "Χ", "ΔΧ"]
|
||||
},
|
||||
{
|
||||
name: "QBusΨ",
|
||||
type: "option",
|
||||
value: ["", "Ψ", "ΔΨ"]
|
||||
},
|
||||
{
|
||||
name: "Limitation",
|
||||
type: "option",
|
||||
value: ["None", "Χ2", "Χ2 + P5", "X2 + Ψ1", "X2 + Ψ1 + P5"]
|
||||
},
|
||||
{
|
||||
name: "K Rack Option",
|
||||
type: "argSelector",
|
||||
value: [
|
||||
{
|
||||
name: "Select Program",
|
||||
on: [7],
|
||||
off: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||
},
|
||||
{
|
||||
name: "Top Section - Conditional",
|
||||
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
||||
off: [7, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||
},
|
||||
{
|
||||
name: "Bottom Section - Addition",
|
||||
on: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||
off: [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||
},
|
||||
{
|
||||
name: "Advanced",
|
||||
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||
off: [7]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Program to run",
|
||||
type: "option",
|
||||
value: ["", "Letter Count", "1+2=. (1+2 Break In, Find X1,X2)", "4=5=/1=2 (Given X1,X2 find X4,X5)", "/,5,U (Count chars to find X3)"]
|
||||
},
|
||||
{
|
||||
name: "K Rack: Conditional",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "R1-Q1",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q2",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q3",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q4",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Q5",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R1-Negate",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "R1-Counter",
|
||||
type: "option",
|
||||
value: ["", "1", "2", "3", "4", "5"]
|
||||
},
|
||||
{
|
||||
name: "R2-Q1",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q2",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q3",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q4",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Q5",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R2-Negate",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "R2-Counter",
|
||||
type: "option",
|
||||
value: ["", "1", "2", "3", "4", "5"]
|
||||
},
|
||||
{
|
||||
name: "R3-Q1",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q2",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q3",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q4",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Q5",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "R3-Negate",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "R3-Counter",
|
||||
type: "option",
|
||||
value: ["", "1", "2", "3", "4", "5"]
|
||||
},
|
||||
{
|
||||
name: "Negate All",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "K Rack: Addition",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "Add-Q1",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q2",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q3",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q4",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Q5",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add-Equals",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "Add-Counter1",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Add Negate All",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "Total Motor",
|
||||
type: "editableOptionShort",
|
||||
value: SWITCHES,
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "Master Control Panel",
|
||||
type: "label"
|
||||
},
|
||||
{
|
||||
name: "Set Total",
|
||||
type: "number",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "Fast Step",
|
||||
type: "option",
|
||||
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||
},
|
||||
{
|
||||
name: "Slow Step",
|
||||
type: "option",
|
||||
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||
},
|
||||
{
|
||||
name: "Start Χ1",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ2",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ3",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ4",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Χ5",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start M61",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start M37",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ1",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ2",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ3",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ4",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Start Ψ5",
|
||||
type: "number",
|
||||
value: 1
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {Object}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = input.toUpperCase();
|
||||
for (const character of input) {
|
||||
if (VALID_ITA2.indexOf(character) === -1) {
|
||||
let errltr = character;
|
||||
if (errltr === "\n") errltr = "Carriage Return";
|
||||
if (errltr === " ") errltr = "Space";
|
||||
throw new OperationError("Invalid ITA2 character : " + errltr);
|
||||
}
|
||||
}
|
||||
|
||||
const pattern = args[1];
|
||||
const qbusin = {
|
||||
"Z": args[2],
|
||||
"Chi": args[3],
|
||||
"Psi": args[4],
|
||||
};
|
||||
|
||||
const limitation = args[5];
|
||||
const lm = [false, false, false];
|
||||
if (limitation.includes("Χ2")) lm[0] = true;
|
||||
if (limitation.includes("Ψ1")) lm[1] = true;
|
||||
if (limitation.includes("P5")) lm[2] = true;
|
||||
const limit = {
|
||||
X2: lm[0], S1: lm[1], P5: lm[2]
|
||||
};
|
||||
|
||||
const KRackOpt = args[6];
|
||||
const setProgram = args[7];
|
||||
|
||||
if (KRackOpt === "Select Program" && setProgram !== "") {
|
||||
args = this.selectProgram(setProgram, args);
|
||||
}
|
||||
|
||||
const re = new RegExp("^$|^[.x]$");
|
||||
for (let qr=0;qr<3;qr++) {
|
||||
for (let a=0;a<5;a++) {
|
||||
if (!re.test(args[((qr*7)+(a+9))]))
|
||||
throw new OperationError("Switch R"+(qr+1)+"-Q"+(a+1)+" can only be set to blank, . or x");
|
||||
}
|
||||
}
|
||||
|
||||
if (!re.test(args[37])) throw new OperationError("Switch Add-Equals can only be set to blank, . or x");
|
||||
if (!re.test(args[40])) throw new OperationError("Switch Total Motor can only be set to blank, . or x");
|
||||
|
||||
// Q1,Q2,Q3,Q4,Q5,negate,counter1
|
||||
const qbusswitches = {
|
||||
condition: [
|
||||
{Qswitches: [args[9], args[10], args[11], args[12], args[13]], Negate: args[14], Counter: args[15]},
|
||||
{Qswitches: [args[16], args[17], args[18], args[19], args[20]], Negate: args[21], Counter: args[22]},
|
||||
{Qswitches: [args[23], args[24], args[25], args[26], args[27]], Negate: args[28], Counter: args[29]}
|
||||
],
|
||||
condNegateAll: args[30],
|
||||
addition: [
|
||||
{Qswitches: [args[32], args[33], args[34], args[35], args[36]], Equals: args[37], C1: args[38]}
|
||||
],
|
||||
addNegateAll: args[39],
|
||||
totalMotor: args[40]
|
||||
};
|
||||
|
||||
const settotal = parseInt(args[42], 10);
|
||||
if (settotal < 0 || settotal > 9999)
|
||||
throw new OperationError("Set Total must be between 0000 and 9999");
|
||||
|
||||
// null|fast|slow for each of S1-5,M1-2,X1-5
|
||||
const control = {
|
||||
fast: args[43],
|
||||
slow: args[44]
|
||||
};
|
||||
|
||||
// Start positions
|
||||
if (args[52]<1 || args[52]>43) throw new OperationError("Ψ1 start must be between 1 and 43");
|
||||
if (args[53]<1 || args[53]>47) throw new OperationError("Ψ2 start must be between 1 and 47");
|
||||
if (args[54]<1 || args[54]>51) throw new OperationError("Ψ3 start must be between 1 and 51");
|
||||
if (args[55]<1 || args[55]>53) throw new OperationError("Ψ4 start must be between 1 and 53");
|
||||
if (args[56]<1 || args[57]>59) throw new OperationError("Ψ5 start must be between 1 and 59");
|
||||
if (args[51]<1 || args[51]>37) throw new OperationError("Μ37 start must be between 1 and 37");
|
||||
if (args[50]<1 || args[50]>61) throw new OperationError("Μ61 start must be between 1 and 61");
|
||||
if (args[45]<1 || args[45]>41) throw new OperationError("Χ1 start must be between 1 and 41");
|
||||
if (args[46]<1 || args[46]>31) throw new OperationError("Χ2 start must be between 1 and 31");
|
||||
if (args[47]<1 || args[47]>29) throw new OperationError("Χ3 start must be between 1 and 29");
|
||||
if (args[48]<1 || args[48]>26) throw new OperationError("Χ4 start must be between 1 and 26");
|
||||
if (args[49]<1 || args[49]>23) throw new OperationError("Χ5 start must be between 1 and 23");
|
||||
|
||||
const starts = {
|
||||
X1: args[45], X2: args[46], X3: args[47], X4: args[48], X5: args[49],
|
||||
M61: args[50], M37: args[51],
|
||||
S1: args[52], S2: args[53], S3: args[54], S4: args[55], S5: args[56]
|
||||
};
|
||||
|
||||
const colossus = new ColossusComputer(input, pattern, qbusin, qbusswitches, control, starts, settotal, limit);
|
||||
const result = colossus.run();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select Program
|
||||
*
|
||||
* @param {string} progname
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
selectProgram(progname, args) {
|
||||
|
||||
// Basic Letter Count
|
||||
if (progname === "Letter Count") {
|
||||
// Set Conditional R1 : count every character into counter 1
|
||||
args[9] = "";
|
||||
args[10] = "";
|
||||
args[11] = "";
|
||||
args[12] = "";
|
||||
args[13] = "";
|
||||
args[14] = false;
|
||||
args[15] = "1";
|
||||
// clear Conditional R2 & R3
|
||||
args[22] = "";
|
||||
args[29] = "";
|
||||
// Clear Negate result
|
||||
args[30] = false;
|
||||
// Clear Addition row counter
|
||||
args[38] = false;
|
||||
}
|
||||
|
||||
// Bill Tutte's 1+2 Break In
|
||||
if (progname === "1+2=. (1+2 Break In, Find X1,X2)") {
|
||||
// Clear any other counters
|
||||
args[15] = ""; // Conditional R1
|
||||
args[22] = ""; // Conditional R2
|
||||
args[29] = ""; // Conditional R3
|
||||
// Set Add Q1+Q2=. into Counter 1
|
||||
args[32] = true;
|
||||
args[33] = true;
|
||||
args[34] = false;
|
||||
args[35] = false;
|
||||
args[36] = false;
|
||||
args[37] = ".";
|
||||
args[38] = true;
|
||||
}
|
||||
|
||||
// 4=3=/1=2 : Find X4 & X5 where X1 & X2 are known
|
||||
if (progname === "4=5=/1=2 (Given X1,X2 find X4,X5)") {
|
||||
// Set Conditional R1 : Match NOT ..?.. into counter 1
|
||||
args[9] = ".";
|
||||
args[10] = ".";
|
||||
args[11] = "";
|
||||
args[12] = ".";
|
||||
args[13] = ".";
|
||||
args[14] = true;
|
||||
args[15] = "1";
|
||||
// Set Conditional R2 : AND Match NOT xx?xx into counter 1
|
||||
args[16] = "x";
|
||||
args[17] = "x";
|
||||
args[18] = "";
|
||||
args[19] = "x";
|
||||
args[20] = "x";
|
||||
args[21] = true;
|
||||
args[22] = "1";
|
||||
// clear Conditional R3
|
||||
args[29] = "";
|
||||
// Negate result, giving NOT(NOT Q1 AND NOT Q2) which is equivalent to Q1 OR Q2
|
||||
args[30] = true;
|
||||
// Clear Addition row counter
|
||||
args[38] = false;
|
||||
}
|
||||
|
||||
// /,5,U : Count number of matches of /, 5 & U to find X3
|
||||
if (progname === "/,5,U (Count chars to find X3)") {
|
||||
// Set Conditional R1 : Match / char, ITA2 = ..... into counter 1
|
||||
args[9] = ".";
|
||||
args[10] = ".";
|
||||
args[11] = ".";
|
||||
args[12] = ".";
|
||||
args[13] = ".";
|
||||
args[14] = false;
|
||||
args[15] = "1";
|
||||
// Set Conditional R2 : Match 5 char, ITA2 = xx.xx into counter 2
|
||||
args[16] = "x";
|
||||
args[17] = "x";
|
||||
args[18] = ".";
|
||||
args[19] = "x";
|
||||
args[20] = "x";
|
||||
args[21] = false;
|
||||
args[22] = "2";
|
||||
// Set Conditional R3 : Match U char, ITA2 = xxx.. into counter 3
|
||||
args[23] = "x";
|
||||
args[24] = "x";
|
||||
args[25] = "x";
|
||||
args[26] = ".";
|
||||
args[27] = ".";
|
||||
args[28] = false;
|
||||
args[29] = "3";
|
||||
// Clear Negate result
|
||||
args[30] = false;
|
||||
// Clear Addition row counter
|
||||
args[38] = false;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays Colossus results in an HTML table
|
||||
*
|
||||
* @param {Object} output
|
||||
* @param {Object[]} output.counters
|
||||
* @returns {html}
|
||||
*/
|
||||
present(output) {
|
||||
let html = "Colossus Printer\n\n";
|
||||
html += output.printout + "\n\n";
|
||||
html += "Colossus Counters\n\n";
|
||||
html += "<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>C1</th> <th>C2</th> <th>C3</th> <th>C4</th> <th>C5</th></tr>\n";
|
||||
html += "<tr>";
|
||||
for (const ct of output.counters) {
|
||||
html += `<td>${ct}</td>\n`;
|
||||
}
|
||||
html += "</tr>";
|
||||
html += "</table>";
|
||||
return html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Colossus;
|
82
src/core/operations/ConvertToNATOAlphabet.mjs
Normal file
82
src/core/operations/ConvertToNATOAlphabet.mjs
Normal file
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* @author MarvinJWendt [git@marvinjwendt.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Convert to NATO alphabet operation
|
||||
*/
|
||||
class ConvertToNATOAlphabet extends Operation {
|
||||
/**
|
||||
* ConvertToNATOAlphabet constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert to NATO alphabet";
|
||||
this.module = "Default";
|
||||
this.description = "Converts characters to their representation in the NATO phonetic alphabet.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/NATO_phonetic_alphabet";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return input.replace(/[a-z0-9,/.]/ig, letter => {
|
||||
return lookup[letter.toUpperCase()];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const lookup = {
|
||||
"A": "Alfa ",
|
||||
"B": "Bravo ",
|
||||
"C": "Charlie ",
|
||||
"D": "Delta ",
|
||||
"E": "Echo ",
|
||||
"F": "Foxtrot ",
|
||||
"G": "Golf ",
|
||||
"H": "Hotel ",
|
||||
"I": "India ",
|
||||
"J": "Juliett ",
|
||||
"K": "Kilo ",
|
||||
"L": "Lima ",
|
||||
"M": "Mike ",
|
||||
"N": "November ",
|
||||
"O": "Oscar ",
|
||||
"P": "Papa ",
|
||||
"Q": "Quebec ",
|
||||
"R": "Romeo ",
|
||||
"S": "Sierra ",
|
||||
"T": "Tango ",
|
||||
"U": "Uniform ",
|
||||
"V": "Victor ",
|
||||
"W": "Whiskey ",
|
||||
"X": "X-ray ",
|
||||
"Y": "Yankee ",
|
||||
"Z": "Zulu ",
|
||||
"0": "Zero ",
|
||||
"1": "One ",
|
||||
"2": "Two ",
|
||||
"3": "Three ",
|
||||
"4": "Four ",
|
||||
"5": "Five ",
|
||||
"6": "Six ",
|
||||
"7": "Seven ",
|
||||
"8": "Eight ",
|
||||
"9": "Nine ",
|
||||
",": "Comma ",
|
||||
"/": "Fraction bar ",
|
||||
".": "Full stop ",
|
||||
};
|
||||
|
||||
export default ConvertToNATOAlphabet;
|
184
src/core/operations/GenerateImage.mjs
Normal file
184
src/core/operations/GenerateImage.mjs
Normal file
|
@ -0,0 +1,184 @@
|
|||
/**
|
||||
* @author pointhi [thomas.pointhuber@gmx.at]
|
||||
* @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 {isImage} from "../lib/FileType";
|
||||
import {toBase64} from "../lib/Base64";
|
||||
import jimp from "jimp";
|
||||
import {isWorkerEnvironment} from "../Utils";
|
||||
|
||||
/**
|
||||
* Generate Image operation
|
||||
*/
|
||||
class GenerateImage extends Operation {
|
||||
|
||||
/**
|
||||
* GenerateImage constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Generate Image";
|
||||
this.module = "Image";
|
||||
this.description = "Generates an image using the input as pixel values.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Mode",
|
||||
"type": "option",
|
||||
"value": ["Greyscale", "RG", "RGB", "RGBA", "Bits"]
|
||||
},
|
||||
{
|
||||
"name": "Pixel Scale Factor",
|
||||
"type": "number",
|
||||
"value": 8,
|
||||
},
|
||||
{
|
||||
"name": "Pixels per row",
|
||||
"type": "number",
|
||||
"value": 64,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [mode, scale, width] = args;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
if (scale <= 0) {
|
||||
throw new OperationError("Pixel Scale Factor needs to be > 0");
|
||||
}
|
||||
|
||||
if (width <= 0) {
|
||||
throw new OperationError("Pixels per Row needs to be > 0");
|
||||
}
|
||||
|
||||
const bytePerPixelMap = {
|
||||
"Greyscale": 1,
|
||||
"RG": 2,
|
||||
"RGB": 3,
|
||||
"RGBA": 4,
|
||||
"Bits": 1/8,
|
||||
};
|
||||
|
||||
const bytesPerPixel = bytePerPixelMap[mode];
|
||||
|
||||
if (bytesPerPixel > 0 && input.length % bytesPerPixel !== 0) {
|
||||
throw new OperationError(`Number of bytes is not a divisor of ${bytesPerPixel}`);
|
||||
}
|
||||
|
||||
const height = Math.ceil(input.length / bytesPerPixel / width);
|
||||
const image = await new jimp(width, height, (err, image) => {});
|
||||
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Generating image from data...");
|
||||
|
||||
if (mode === "Bits") {
|
||||
let index = 0;
|
||||
for (let j = 0; j < input.length; j++) {
|
||||
const curByte = Utils.bin(input[j]);
|
||||
for (let k = 0; k < 8; k++, index++) {
|
||||
const x = index % width;
|
||||
const y = Math.floor(index / width);
|
||||
|
||||
const value = curByte[k] === "0" ? 0xFF : 0x00;
|
||||
const pixel = jimp.rgbaToInt(value, value, value, 0xFF);
|
||||
image.setPixelColor(pixel, x, y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let i = 0;
|
||||
while (i < input.length) {
|
||||
const index = i / bytesPerPixel;
|
||||
const x = index % width;
|
||||
const y = Math.floor(index / width);
|
||||
|
||||
let red = 0x00;
|
||||
let green = 0x00;
|
||||
let blue = 0x00;
|
||||
let alpha = 0xFF;
|
||||
|
||||
switch (mode) {
|
||||
case "Greyscale":
|
||||
red = green = blue = input[i++];
|
||||
break;
|
||||
|
||||
case "RG":
|
||||
red = input[i++];
|
||||
green = input[i++];
|
||||
break;
|
||||
|
||||
case "RGB":
|
||||
red = input[i++];
|
||||
green = input[i++];
|
||||
blue = input[i++];
|
||||
break;
|
||||
|
||||
case "RGBA":
|
||||
red = input[i++];
|
||||
green = input[i++];
|
||||
blue = input[i++];
|
||||
alpha = input[i++];
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new OperationError(`Unsupported Mode: (${mode})`);
|
||||
}
|
||||
|
||||
try {
|
||||
const pixel = jimp.rgbaToInt(red, green, blue, alpha);
|
||||
image.setPixelColor(pixel, x, y);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error while generating image from pixel values. (${err})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scale !== 1) {
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Scaling image...");
|
||||
|
||||
image.scaleToFit(width*scale, height*scale, jimp.RESIZE_NEAREST_NEIGHBOR);
|
||||
}
|
||||
|
||||
try {
|
||||
const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error generating image. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the generated image using HTML for web apps
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GenerateImage;
|
|
@ -22,7 +22,7 @@ class Lorenz extends Operation {
|
|||
|
||||
this.name = "Lorenz";
|
||||
this.module = "Bletchley";
|
||||
this.description = "The Lorenz SZ40/42 cipher attachment was a WW2 German rotor cipher machine with twelve rotors which attached in-line between remote teleprinters.<br><br>It used the Vernam cipher with two groups of five rotors (named the psi(ψ) wheels and chi(χ) wheels at Bletchley Park) to create two pseudorandom streams of five bits, encoded in ITA2, which were XOR added to the plaintext. Two other rotors, dubbed the mu(μ) or motor wheels, could hold up the stepping of the psi wheels meaning they stepped intermittently.<br><br>Each rotor has a different number of cams/lugs around their circumference which could be set active or inactive changing the key stream.<br><br>Three models of the Lorenz are emulated, SZ40, SZ42a and SZ42b and three example wheel patterns (the lug settings) are included (KH, ZMUG & BREAM) with the option to set a custom set using the letter 'x' for active or '.' for an inactive lug.<br><br>The input can either be plaintext or ITA2 when sending and ITA2 when receiving.<br><br>To learn more, Virtual Lorenz, an online, browser based simulation of the Lorenz SZ40/42 is available at <a href='https://lorenz.virtualcolossus.co.uk' target='_blank'>https://lorenz.virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Lorenz-SZ' target='_blank'>here</a>.";
|
||||
this.description = "The Lorenz SZ40/42 cipher attachment was a WW2 German rotor cipher machine with twelve rotors which attached in-line between remote teleprinters.<br><br>It used the Vernam cipher with two groups of five rotors (named the psi(ψ) wheels and chi(χ) wheels at Bletchley Park) to create two pseudorandom streams of five bits, encoded in ITA2, which were XOR added to the plaintext. Two other rotors, dubbed the mu(μ) or motor wheels, could hold up the stepping of the psi wheels meaning they stepped intermittently.<br><br>Each rotor has a different number of cams/lugs around their circumference which could be set active or inactive changing the key stream.<br><br>Three models of the Lorenz are emulated, SZ40, SZ42a and SZ42b and three example wheel patterns (the lug settings) are included (KH, ZMUG & BREAM) with the option to set a custom set using the letter 'x' for active or '.' for an inactive lug.<br><br>The input can either be plaintext or ITA2 when sending and ITA2 when receiving.<br><br>To learn more, Virtual Lorenz, an online, browser based simulation of the Lorenz SZ40/42 is available at <a href='https://lorenz.virtualcolossus.co.uk' target='_blank'>lorenz.virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Lorenz-SZ' target='_blank'>here</a>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Lorenz_cipher";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -293,8 +293,8 @@ class Lorenz extends Operation {
|
|||
chosenSetting.S[3] = this.readLugs(lugs3);
|
||||
chosenSetting.S[4] = this.readLugs(lugs4);
|
||||
chosenSetting.S[5] = this.readLugs(lugs5);
|
||||
chosenSetting.M[1] = this.readLugs(lugm37);
|
||||
chosenSetting.M[2] = this.readLugs(lugm61);
|
||||
chosenSetting.M[1] = this.readLugs(lugm61);
|
||||
chosenSetting.M[2] = this.readLugs(lugm37);
|
||||
chosenSetting.X[1] = this.readLugs(lugx1);
|
||||
chosenSetting.X[2] = this.readLugs(lugx2);
|
||||
chosenSetting.X[3] = this.readLugs(lugx3);
|
||||
|
|
77
src/core/operations/LuhnChecksum.mjs
Normal file
77
src/core/operations/LuhnChecksum.mjs
Normal file
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* @author n1073645 [n1073645@gmail.com]
|
||||
* @copyright Crown Copyright 2020
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Luhn Checksum operation
|
||||
*/
|
||||
class LuhnChecksum extends Operation {
|
||||
|
||||
/**
|
||||
* LuhnChecksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Luhn Checksum";
|
||||
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.infoURL = "https://wikipedia.org/wiki/Luhn_algorithm";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Luhn Checksum from the input.
|
||||
*
|
||||
* @param {string} inputStr
|
||||
* @returns {number}
|
||||
*/
|
||||
checksum(inputStr) {
|
||||
let even = false;
|
||||
return inputStr.split("").reverse().reduce((acc, elem) => {
|
||||
// Convert element to integer.
|
||||
let temp = parseInt(elem, 10);
|
||||
|
||||
// If element is not an integer.
|
||||
if (isNaN(temp))
|
||||
throw new OperationError("Character: " + elem + " is not a digit.");
|
||||
|
||||
// If element is in an even position
|
||||
if (even) {
|
||||
// Double the element and add the quotient and remainder together.
|
||||
temp = 2 * elem;
|
||||
temp = Math.floor(temp/10) + (temp % 10);
|
||||
}
|
||||
|
||||
even = !even;
|
||||
return acc + temp;
|
||||
}, 0) % 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input) return "";
|
||||
|
||||
const checkSum = this.checksum(input);
|
||||
let checkDigit = this.checksum(input + "0");
|
||||
checkDigit = checkDigit === 0 ? 0 : (10-checkDigit);
|
||||
|
||||
return `Checksum: ${checkSum}
|
||||
Checkdigit: ${checkDigit}
|
||||
Luhn Validated String: ${input + "" + checkDigit}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default LuhnChecksum;
|
|
@ -144,7 +144,7 @@ class MultipleBombe extends Operation {
|
|||
* @param {number} progress - Progress (as a float in the range 0..1)
|
||||
*/
|
||||
updateStatus(nLoops, nStops, progress, start) {
|
||||
const elapsed = new Date().getTime() - start;
|
||||
const elapsed = Date.now() - start;
|
||||
const remaining = (elapsed / progress) * (1 - progress) / 1000;
|
||||
const hours = Math.floor(remaining / 3600);
|
||||
const minutes = `0${Math.floor((remaining % 3600) / 60)}`.slice(-2);
|
||||
|
@ -237,7 +237,7 @@ class MultipleBombe extends Operation {
|
|||
const totalRuns = choose(rotors.length, 3) * 6 * fourthRotors.length * reflectors.length;
|
||||
let nRuns = 0;
|
||||
let nStops = 0;
|
||||
const start = new Date().getTime();
|
||||
const start = Date.now();
|
||||
for (const rotor1 of rotors) {
|
||||
for (const rotor2 of rotors) {
|
||||
if (rotor2 === rotor1) {
|
||||
|
|
|
@ -45,7 +45,7 @@ class RegularExpression extends Operation {
|
|||
},
|
||||
{
|
||||
name: "Email address",
|
||||
value: "\\b(\\w[-.\\w]*)@([-\\w]+(?:\\.[-\\w]+)*)\\.([A-Za-z]{2,4})\\b"
|
||||
value: "(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?\\.)+[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\\])"
|
||||
},
|
||||
{
|
||||
name: "URL",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue