crypto-keygen-suite
Version:
Key generation utilities for cryptographic operations. YES I RENAMED IT. SIX STATE PROTOCOL!!! See its folder for all <3
187 lines (154 loc) • 5.55 kB
JavaScript
import { program } from "commander";
const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Rotor wirings historical (right-to-left)
const ROTORS = {
I: "EKMFLGDQVZNTOWYHXUSPAIBRCJ",
II: "AJDKSIRUXBLHWTMCQGZNPYFVOE",
III: "BDFHJLCPRTXVZNYEIWGAKMUSQO",
IV: "ESOVPZJAYQUIRHXLNFTGKDCMWB",
V: "VZBRGITYUPSDNHLXAWMJQOFECK",
VI: "JPGVOUMFYQBENHZRDKASXLICTW",
VII: "NZJHGRCXMYSWBOUFAIVLPEKQDT",
VIII: "FKQHTLXOCBJSPDZRAMEWNIUYGV",
};
const REFLECTORS = {
B: "YRUHQSLDPXNGOKMIEBFZCWVJAT",
C: "FVPJIAOYEDRZXWGCTKUQSBNMHL",
};
// Sanitize input: uppercase and keep letters only
function sanitizeInput(input) {
return input.toUpperCase().replace(/[^A-Z]/g, "");
}
// Plugboard class: swaps pairs of letters
class Plugboard {
constructor(pairs) {
this.mapping = {};
if (!pairs) return;
for (const pair of pairs) {
if (pair.length !== 2) continue;
const [a, b] = pair.toUpperCase().split("");
this.mapping[a] = b;
this.mapping[b] = a;
}
}
swap(char) {
return this.mapping[char] || char;
}
}
// Rotor class
class Rotor {
constructor(wiring, positionChar = "A") {
this.wiring = wiring;
this.position = ALPHABET.indexOf(positionChar.toUpperCase());
this.ringSetting = 0; // For future: ring settings can be added
}
// Map input letter through rotor forward (right to left)
forward(c) {
const index = (ALPHABET.indexOf(c) + this.position - this.ringSetting + 26) % 26;
const wiredChar = this.wiring[index];
const outputIndex = (ALPHABET.indexOf(wiredChar) - this.position + this.ringSetting + 26) % 26;
return ALPHABET[outputIndex];
}
// Map input letter through rotor backward (left to right)
backward(c) {
const index = (ALPHABET.indexOf(c) + this.position - this.ringSetting + 26) % 26;
const wiredIndex = this.wiring.indexOf(ALPHABET[index]);
const outputIndex = (wiredIndex - this.position + this.ringSetting + 26) % 26;
return ALPHABET[outputIndex];
}
// Rotate rotor by one position, returns true if at notch to step next rotor (simplified no notches)
step() {
this.position = (this.position + 1) % 26;
return false; // Not implementing notch stepping here for simplicity
}
}
// Reflector class
class Reflector {
constructor(wiring) {
this.wiring = wiring;
}
reflect(c) {
return this.wiring[ALPHABET.indexOf(c)];
}
}
// Enigma machine class
class Enigma {
constructor(rotorNames, rotorPositions, reflectorName, plugboardPairs) {
if (rotorNames.length !== rotorPositions.length) {
throw new Error("Rotor names and positions count mismatch");
}
this.rotors = rotorNames.map((r, i) => new Rotor(ROTORS[r], rotorPositions[i]));
this.reflector = new Reflector(REFLECTORS[reflectorName]);
this.plugboard = new Plugboard(plugboardPairs);
}
stepRotors() {
// Simple stepping: rightmost rotor always steps
// Double stepping and notches not implemented for simplicity
if (this.rotors.length === 0) return;
this.rotors[0].step();
}
processChar(c) {
if (!ALPHABET.includes(c)) return c; // Preserve non-alpha if any
this.stepRotors();
// Through plugboard in
let ch = this.plugboard.swap(c);
// Forward through rotors (right to left)
for (const rotor of this.rotors) {
ch = rotor.forward(ch);
}
// Reflect
ch = this.reflector.reflect(ch);
// Backward through rotors (left to right)
for (let i = this.rotors.length - 1; i >= 0; i--) {
ch = this.rotors[i].backward(ch);
}
// Through plugboard out
ch = this.plugboard.swap(ch);
return ch;
}
encrypt(text) {
const sanitized = sanitizeInput(text);
let result = "";
for (const c of sanitized) {
result += this.processChar(c);
}
return result;
}
}
// CLI setup with Commander.js
program
.argument('<mode>', 'encrypt or decrypt')
.argument('<text>', 'text to encrypt/decrypt')
.option('--rotors <rotors>', 'Comma-separated rotors (I-VIII)', 'I,II,III')
.option('--positions <positions>', 'Comma-separated rotor start positions (A-Z)', 'A,A,A')
.option('--reflector <reflector>', 'Reflector (B or C)', 'B')
.option('--plugboard <pairs...>', 'Plugboard pairs e.g. AB CD EF');
program.parse();
const options = program.opts();
const mode = program.args[0].toLowerCase();
const inputText = program.args[1];
// Parse rotor names & positions
const rotorNames = options.rotors.split(",").map(r => r.trim().toUpperCase());
const rotorPositions = options.positions.split(",").map(p => p.trim().toUpperCase());
// Validate reflector choice
const reflectorName = options.reflector.toUpperCase();
if (!REFLECTORS[reflectorName]) {
console.error(`Invalid reflector ${reflectorName}. Choose B or C.`);
process.exit(1);
}
// Plugboard pairs (uppercase, max 10 pairs recommended)
const plugboardPairs = options.plugboard || [];
try {
const enigma = new Enigma(rotorNames, rotorPositions, reflectorName, plugboardPairs);
if (mode !== "encrypt" && mode !== "decrypt") {
console.error("Mode must be either 'encrypt' or 'decrypt'");
process.exit(1);
}
// Enigma encryption/decryption are symmetric
const output = enigma.encrypt(inputText);
console.log("Result:", output);
} catch (e) {
console.error("Error:", e.message);
process.exit(1);
}