mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-07 23:15:14 -04:00
add formatter
This commit is contained in:
parent
c4e7c41a6e
commit
ce30989adc
693 changed files with 51226 additions and 26671 deletions
|
@ -9,7 +9,7 @@
|
|||
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {Rotor, Plugboard, a2i, i2a} from "./Enigma.mjs";
|
||||
import { Rotor, Plugboard, a2i, i2a } from "./Enigma.mjs";
|
||||
|
||||
/**
|
||||
* Convenience/optimisation subclass of Rotor
|
||||
|
@ -96,7 +96,7 @@ class SharedScrambler {
|
|||
constructor(rotors, reflector) {
|
||||
this.lowerCache = new Array(26);
|
||||
this.higherCache = new Array(26);
|
||||
for (let i=0; i<26; i++) {
|
||||
for (let i = 0; i < 26; i++) {
|
||||
this.higherCache[i] = new Array(26);
|
||||
}
|
||||
this.changeRotors(rotors, reflector);
|
||||
|
@ -121,7 +121,7 @@ class SharedScrambler {
|
|||
* the shared state, so should be 2 or more.
|
||||
*/
|
||||
step(n) {
|
||||
for (let i=0; i<n-1; i++) {
|
||||
for (let i = 0; i < n - 1; i++) {
|
||||
this.rotors[i].step();
|
||||
}
|
||||
this.cacheGen();
|
||||
|
@ -136,13 +136,13 @@ class SharedScrambler {
|
|||
* iterations.
|
||||
*/
|
||||
cacheGen() {
|
||||
for (let i=0; i<26; i++) {
|
||||
for (let i = 0; i < 26; i++) {
|
||||
this.lowerCache[i] = undefined;
|
||||
for (let j=0; j<26; j++) {
|
||||
for (let j = 0; j < 26; j++) {
|
||||
this.higherCache[i][j] = undefined;
|
||||
}
|
||||
}
|
||||
for (let i=0; i<26; i++) {
|
||||
for (let i = 0; i < 26; i++) {
|
||||
if (this.lowerCache[i] !== undefined) {
|
||||
continue;
|
||||
}
|
||||
|
@ -219,7 +219,6 @@ class Scrambler {
|
|||
this.cache = this.baseScrambler.higherCache[this.rotor.pos];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run a letter through the scrambler.
|
||||
* @param {number} i - The letter to transform (as a number)
|
||||
|
@ -262,7 +261,7 @@ class Scrambler {
|
|||
// Roll back the fast rotor by one step
|
||||
let pos = Utils.mod(this.rotor.pos - 1, 26);
|
||||
result += i2a(pos);
|
||||
for (let i=0; i<this.baseScrambler.rotors.length; i++) {
|
||||
for (let i = 0; i < this.baseScrambler.rotors.length; i++) {
|
||||
pos = this.baseScrambler.rotors[i].pos;
|
||||
result += i2a(pos);
|
||||
}
|
||||
|
@ -296,7 +295,14 @@ export class BombeMachine {
|
|||
* @param {boolean} check - Whether to use the checking machine
|
||||
* @param {function} update - Function to call to send status updates (optional)
|
||||
*/
|
||||
constructor(rotors, reflector, ciphertext, crib, check, update=undefined) {
|
||||
constructor(
|
||||
rotors,
|
||||
reflector,
|
||||
ciphertext,
|
||||
crib,
|
||||
check,
|
||||
update = undefined,
|
||||
) {
|
||||
if (ciphertext.length < crib.length) {
|
||||
throw new OperationError("Crib overruns supplied ciphertext");
|
||||
}
|
||||
|
@ -310,9 +316,11 @@ export class BombeMachine {
|
|||
// A shorter crib is preferable to reduce this chance, of course
|
||||
throw new OperationError("Crib is too long");
|
||||
}
|
||||
for (let i=0; i<crib.length; i++) {
|
||||
for (let i = 0; i < crib.length; i++) {
|
||||
if (ciphertext[i] === crib[i]) {
|
||||
throw new OperationError(`Invalid crib: character ${ciphertext[i]} at pos ${i} in both ciphertext and crib`);
|
||||
throw new OperationError(
|
||||
`Invalid crib: character ${ciphertext[i]} at pos ${i} in both ciphertext and crib`,
|
||||
);
|
||||
}
|
||||
}
|
||||
this.ciphertext = ciphertext;
|
||||
|
@ -325,22 +333,31 @@ export class BombeMachine {
|
|||
|
||||
// This is the bundle of wires corresponding to the 26 letters within each of the 26
|
||||
// possible nodes in the menu
|
||||
this.wires = new Array(26*26);
|
||||
this.wires = new Array(26 * 26);
|
||||
|
||||
// These are the pseudo-Engima devices corresponding to each edge in the menu, and the
|
||||
// nodes in the menu they each connect to
|
||||
this.scramblers = new Array();
|
||||
for (let i=0; i<26; i++) {
|
||||
for (let i = 0; i < 26; i++) {
|
||||
this.scramblers.push(new Array());
|
||||
}
|
||||
this.sharedScrambler = new SharedScrambler(this.baseRotors.slice(1), reflector);
|
||||
this.sharedScrambler = new SharedScrambler(
|
||||
this.baseRotors.slice(1),
|
||||
reflector,
|
||||
);
|
||||
this.allScramblers = new Array();
|
||||
this.indicator = undefined;
|
||||
for (const edge of edges) {
|
||||
const cRotor = this.baseRotors[0].copy();
|
||||
const end1 = a2i(edge.node1.letter);
|
||||
const end2 = a2i(edge.node2.letter);
|
||||
const scrambler = new Scrambler(this.sharedScrambler, cRotor, edge.pos, end1, end2);
|
||||
const scrambler = new Scrambler(
|
||||
this.sharedScrambler,
|
||||
cRotor,
|
||||
edge.pos,
|
||||
end1,
|
||||
end2,
|
||||
);
|
||||
if (edge.pos === 0) {
|
||||
this.indicator = scrambler;
|
||||
}
|
||||
|
@ -352,14 +369,23 @@ export class BombeMachine {
|
|||
// use one of the actual scramblers if there's one in the right position, but if not we'll
|
||||
// just create one.
|
||||
if (this.indicator === undefined) {
|
||||
this.indicator = new Scrambler(this.sharedScrambler, this.baseRotors[0].copy(), 0, undefined, undefined);
|
||||
this.indicator = new Scrambler(
|
||||
this.sharedScrambler,
|
||||
this.baseRotors[0].copy(),
|
||||
0,
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
this.allScramblers.push(this.indicator);
|
||||
}
|
||||
|
||||
this.testRegister = a2i(mostConnected.letter);
|
||||
// This is an arbitrary letter other than the most connected letter
|
||||
for (const edge of mostConnected.edges) {
|
||||
this.testInput = [this.testRegister, a2i(edge.getOther(mostConnected).letter)];
|
||||
this.testInput = [
|
||||
this.testRegister,
|
||||
a2i(edge.getOther(mostConnected).letter),
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -430,7 +456,8 @@ export class BombeMachine {
|
|||
continue;
|
||||
}
|
||||
// This is a newly visited node
|
||||
const [oLoops, oNNodes, oMostConnected, oNConnections, oEdges] = this.dfs(other);
|
||||
const [oLoops, oNNodes, oMostConnected, oNConnections, oEdges] =
|
||||
this.dfs(other);
|
||||
loops += oLoops;
|
||||
nNodes += oNNodes;
|
||||
edges = new Set([...edges, ...oEdges]);
|
||||
|
@ -465,7 +492,7 @@ export class BombeMachine {
|
|||
}
|
||||
}
|
||||
// Then all edges
|
||||
for (let i=0; i<this.crib.length; i++) {
|
||||
for (let i = 0; i < this.crib.length; i++) {
|
||||
const a = this.crib[i];
|
||||
const b = this.ciphertext[i];
|
||||
new Edge(i, nodes.get(a), nodes.get(b));
|
||||
|
@ -499,14 +526,14 @@ export class BombeMachine {
|
|||
* @param {number} j - Bombe stecker hypothesis wire within bundle
|
||||
*/
|
||||
energise(i, j) {
|
||||
const idx = 26*i + j;
|
||||
const idx = 26 * i + j;
|
||||
if (this.wires[idx]) {
|
||||
return;
|
||||
}
|
||||
this.wires[idx] = true;
|
||||
// Welchman's diagonal board: if A steckers to B, that implies B steckers to A. Handle
|
||||
// both.
|
||||
const idxPair = 26*j + i;
|
||||
const idxPair = 26 * j + i;
|
||||
this.wires[idxPair] = true;
|
||||
if (i === this.testRegister || j === this.testRegister) {
|
||||
this.energiseCount++;
|
||||
|
@ -516,12 +543,12 @@ export class BombeMachine {
|
|||
}
|
||||
}
|
||||
|
||||
for (let k=0; k<this.scramblers[i].length; k++) {
|
||||
for (let k = 0; k < this.scramblers[i].length; k++) {
|
||||
const scrambler = this.scramblers[i][k];
|
||||
const out = scrambler.transform(j);
|
||||
const other = scrambler.getOtherEnd(i);
|
||||
// Lift the pre-check before the call, to save some function call overhead
|
||||
const otherIdx = 26*other + out;
|
||||
const otherIdx = 26 * other + out;
|
||||
if (!this.wires[otherIdx]) {
|
||||
this.energise(other, out);
|
||||
if (this.energiseCount === 26) {
|
||||
|
@ -532,11 +559,11 @@ export class BombeMachine {
|
|||
if (i === j) {
|
||||
return;
|
||||
}
|
||||
for (let k=0; k<this.scramblers[j].length; k++) {
|
||||
for (let k = 0; k < this.scramblers[j].length; k++) {
|
||||
const scrambler = this.scramblers[j][k];
|
||||
const out = scrambler.transform(i);
|
||||
const other = scrambler.getOtherEnd(j);
|
||||
const otherIdx = 26*other + out;
|
||||
const otherIdx = 26 * other + out;
|
||||
if (!this.wires[otherIdx]) {
|
||||
this.energise(other, out);
|
||||
if (this.energiseCount === 26) {
|
||||
|
@ -561,8 +588,10 @@ export class BombeMachine {
|
|||
const res = [];
|
||||
const plugboard = new Plugboard(stecker);
|
||||
// The indicator scrambler starts in the right place for the beginning of the ciphertext.
|
||||
for (let i=0; i<Math.min(26, this.ciphertext.length); i++) {
|
||||
const t = this.indicator.transform(plugboard.transform(a2i(this.ciphertext[i])));
|
||||
for (let i = 0; i < Math.min(26, this.ciphertext.length); i++) {
|
||||
const t = this.indicator.transform(
|
||||
plugboard.transform(a2i(this.ciphertext[i])),
|
||||
);
|
||||
res.push(i2a(plugboard.transform(t)));
|
||||
this.indicator.step(1);
|
||||
}
|
||||
|
@ -602,7 +631,7 @@ export class BombeMachine {
|
|||
if (pair !== this.testInput[1]) {
|
||||
// We have a new hypothesis for this stop - apply the new one.
|
||||
// De-energise the board
|
||||
for (let i=0; i<this.wires.length; i++) {
|
||||
for (let i = 0; i < this.wires.length; i++) {
|
||||
this.wires[i] = false;
|
||||
}
|
||||
this.energiseCount = 0;
|
||||
|
@ -612,11 +641,11 @@ export class BombeMachine {
|
|||
|
||||
const results = new Set();
|
||||
results.add(this.formatPair(this.testRegister, pair));
|
||||
for (let i=0; i<26; i++) {
|
||||
for (let i = 0; i < 26; i++) {
|
||||
let count = 0;
|
||||
let other;
|
||||
for (let j=0; j<26; j++) {
|
||||
if (this.wires[i*26 + j]) {
|
||||
for (let j = 0; j < 26; j++) {
|
||||
if (this.wires[i * 26 + j]) {
|
||||
count++;
|
||||
other = j;
|
||||
}
|
||||
|
@ -649,8 +678,8 @@ export class BombeMachine {
|
|||
// started with are hypothesised to be a stecker pair.
|
||||
if (count === 25) {
|
||||
// Our steckering hypothesis is wrong. Correct value is the un-energised wire.
|
||||
for (let j=0; j<26; j++) {
|
||||
if (!this.wires[26*this.testRegister + j]) {
|
||||
for (let j = 0; j < 26; j++) {
|
||||
if (!this.wires[26 * this.testRegister + j]) {
|
||||
steckerPair = j;
|
||||
break;
|
||||
}
|
||||
|
@ -676,7 +705,11 @@ export class BombeMachine {
|
|||
if (newStecker !== "") {
|
||||
if (stecker !== undefined) {
|
||||
// Multiple hypotheses can't be ruled out.
|
||||
return [this.indicator.getPos(), "??", this.tryDecrypt("")];
|
||||
return [
|
||||
this.indicator.getPos(),
|
||||
"??",
|
||||
this.tryDecrypt(""),
|
||||
];
|
||||
}
|
||||
stecker = newStecker;
|
||||
}
|
||||
|
@ -713,9 +746,9 @@ export class BombeMachine {
|
|||
const result = [];
|
||||
// For each possible rotor setting
|
||||
const nChecks = Math.pow(26, this.baseRotors.length);
|
||||
for (let i=1; i<=nChecks; i++) {
|
||||
for (let i = 1; i <= nChecks; i++) {
|
||||
// Benchmarking suggests this is faster than using .fill()
|
||||
for (let i=0; i<this.wires.length; i++) {
|
||||
for (let i = 0; i < this.wires.length; i++) {
|
||||
this.wires[i] = false;
|
||||
}
|
||||
this.energiseCount = 0;
|
||||
|
@ -732,8 +765,8 @@ export class BombeMachine {
|
|||
// This loop counts how many rotors have reached their starting position (meaning the
|
||||
// next one needs to step as well)
|
||||
let n = 1;
|
||||
for (let j=1; j<this.baseRotors.length; j++) {
|
||||
if ((i % Math.pow(26, j)) === 0) {
|
||||
for (let j = 1; j < this.baseRotors.length; j++) {
|
||||
if (i % Math.pow(26, j) === 0) {
|
||||
n++;
|
||||
} else {
|
||||
break;
|
||||
|
@ -748,7 +781,7 @@ export class BombeMachine {
|
|||
// Send status messages at what seems to be a reasonably sensible frequency
|
||||
// (note this won't be triggered on 3-rotor runs - they run fast enough it doesn't seem necessary)
|
||||
if (n > 3) {
|
||||
this.update(this.nLoops, stops, i/nChecks);
|
||||
this.update(this.nLoops, stops, i / nChecks);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue