mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-20 06:55:08 -04:00
Merge 31e6ce5aa8
into 7c8be12d52
This commit is contained in:
commit
a67291d212
6 changed files with 374 additions and 61 deletions
2
.github/workflows/master.yml
vendored
2
.github/workflows/master.yml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
|||
- name: Set node version
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
|
|
|
@ -1266,19 +1266,26 @@ class Utils {
|
|||
|
||||
/**
|
||||
* Finds the modular inverse of two values.
|
||||
* Uses the Extended Euclidean Algorithm.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {number}
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {number} a
|
||||
* @param {number} n
|
||||
* @returns {number|null}
|
||||
*/
|
||||
static modInv(x, y) {
|
||||
x %= y;
|
||||
for (let i = 1; i < y; i++) {
|
||||
if ((x * i) % 26 === 1) {
|
||||
return i;
|
||||
}
|
||||
static modInv(a, n) {
|
||||
let t = 0, newT = 1, r = n, newR = a;
|
||||
|
||||
while (newR !== 0) {
|
||||
const q = Math.floor(r / newR);
|
||||
[t, newT] = [newT, t - q * newT];
|
||||
[r, newR] = [newR, r - q * newR];
|
||||
}
|
||||
|
||||
if (r > 1) return null;
|
||||
if (t < 0) t = t + n;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @author Evie H [evie@evie.sh]
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
|
@ -17,6 +18,7 @@ import CryptoJS from "crypto-js";
|
|||
/**
|
||||
* Affine Cipher Encode operation.
|
||||
*
|
||||
* @deprecated Use affineEcrypt instead.
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
|
@ -51,6 +53,166 @@ export function affineEncode(input, args) {
|
|||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic affine encrypt/decrypt operation.
|
||||
* Allows for an expanded alphabet.
|
||||
*
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {string} input
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @param {string} alphabet
|
||||
* @param {function} affineFn
|
||||
* @returns {string}
|
||||
*/
|
||||
export function affineApplication(input, a, b, alphabet, affineFn) {
|
||||
if (alphabet === "")
|
||||
throw new OperationError("The alphabet cannot be empty.");
|
||||
|
||||
alphabet = Utils.expandAlphRange(alphabet);
|
||||
let output = "";
|
||||
const modulus = alphabet.length;
|
||||
|
||||
// If the alphabet contains letters of all the same case,
|
||||
// the assumption will be to match case.
|
||||
const hasLower = /[a-z]/.test(alphabet);
|
||||
const hasUpper = /[A-Z]/.test(alphabet);
|
||||
const matchCase = (hasLower && hasUpper) ? false : true;
|
||||
|
||||
// If we are matching case, convert entire alphabet to lowercase.
|
||||
// This will simplify the encryption.
|
||||
if (matchCase)
|
||||
alphabet = alphabet.map((c) => c.toLowerCase());
|
||||
|
||||
if (a === undefined || a === "" || isNaN(a)) a = 1;
|
||||
if (b === undefined || b === "" || isNaN(b)) b = 0;
|
||||
|
||||
if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
|
||||
throw new OperationError("The values of a and b can only be integers.");
|
||||
}
|
||||
|
||||
if (Utils.gcd(a, modulus) !== 1) {
|
||||
throw new OperationError("The value of `a` (" + a + ") must be coprime to " + modulus + ".");
|
||||
}
|
||||
|
||||
// Apply affine function to each character in the input
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
let outChar = "";
|
||||
|
||||
let inChar = input[i];
|
||||
if (matchCase && isUpperCase(inChar)) inChar = inChar.toLowerCase();
|
||||
|
||||
const inVal = alphabet.indexOf(inChar);
|
||||
|
||||
if (inVal >= 0) {
|
||||
outChar = alphabet[affineFn(inVal, a, b, modulus)];
|
||||
if (matchCase && isUpperCase(input[i])) outChar = outChar.toUpperCase();
|
||||
} else {
|
||||
outChar += input[i];
|
||||
}
|
||||
|
||||
output += outChar;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the affine encryption function to p.
|
||||
*
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {integer} p - Plaintext value
|
||||
* @param {integer} a - Multiplier coefficient
|
||||
* @param {integer} b - Addition coefficient
|
||||
* @param {integer} m - Modulus
|
||||
* @returns {integer}
|
||||
*/
|
||||
const encryptFn = function(p, a, b, m) {
|
||||
return (a * p + b) % m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply the affine decryption function to c.
|
||||
*
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {integer} c - Ciphertext value
|
||||
* @param {integer} a - Multiplicative inverse coefficient
|
||||
* @param {integer} b - Additive inverse coefficient
|
||||
* @param {integer} m - Modulus
|
||||
* @returns {integer}
|
||||
*/
|
||||
const decryptFn = function(c, a, b, m) {
|
||||
return ((c + b) * a) % m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Affine encrypt operation.
|
||||
* Allows for an expanded alphabet.
|
||||
*
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {string} input
|
||||
* @param {integer} a
|
||||
* @param {integer} b
|
||||
* @param {string} alphabet
|
||||
* @returns {string}
|
||||
*/
|
||||
export function affineEncrypt(input, a, b, alphabet="a-z") {
|
||||
return affineApplication(input, a, b, alphabet, encryptFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affine Cipher Decrypt operation using the coefficients that were used to encrypt.
|
||||
* The modular inverses will be calculated.
|
||||
*
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {string} input
|
||||
* @param {integer} a
|
||||
* @param {integer} b
|
||||
* @param {string} alphabet
|
||||
* @returns {string}
|
||||
*/
|
||||
export function affineDecrypt(input, a, b, alphabet="a-z") {
|
||||
// Because we are calculating the modulus and inverses here, we have to perform
|
||||
// many of the same tests that the affineApplication function does.
|
||||
// TODO: figure out a way to avoid doing the tests twice.
|
||||
// Idea: make a checkInputs function.
|
||||
// Idea: move the tests into the affineEncrypt and affineDecryptInverse functions
|
||||
// so that affineApplication assumes valid inputs
|
||||
if (alphabet === "")
|
||||
throw new OperationError("The alphabet cannot be empty.");
|
||||
|
||||
if (a === undefined || a === "" || isNaN(a)) a = 1;
|
||||
if (b === undefined || b === "" || isNaN(b)) b = 0;
|
||||
|
||||
if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
|
||||
throw new OperationError("The values of a and b can only be integers.");
|
||||
}
|
||||
|
||||
const m = Utils.expandAlphRange(alphabet).length;
|
||||
if (Utils.gcd(a, m) !== 1)
|
||||
throw new OperationError("The value of `a` (" + a + ") must be coprime to " + m + ".");
|
||||
|
||||
const aInv = Utils.modInv(a, m);
|
||||
const bInv = (m - b) % m;
|
||||
if (aInv === null || aInv === undefined)
|
||||
throw new OperationError("The value of `a` (" + a + ") must be coprime to " + m + ".");
|
||||
else return affineApplication(input, aInv, bInv, alphabet, decryptFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Affine Cipher Decrypt operation using modular inverse coefficients
|
||||
* supplied by the user.
|
||||
*
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {string} input
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @param {string} alphabet
|
||||
* @returns {string}
|
||||
*/
|
||||
export function affineDecryptInverse(input, a, b, alphabet="a-z") {
|
||||
return affineApplication(input, a, b, alphabet, decryptFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a polybius square for the given keyword
|
||||
*
|
||||
|
@ -86,3 +248,22 @@ export const format = {
|
|||
"UTF16BE": CryptoJS.enc.Utf16BE,
|
||||
"Latin1": CryptoJS.enc.Latin1,
|
||||
};
|
||||
|
||||
export const AFFINE_ALPHABETS = [
|
||||
{name: "Letters, match case: a-z", value: "a-z"},
|
||||
{name: "Letters, case sensitive: A-Za-z", value: "A-Za-z"},
|
||||
{name: "Word characters: A-Za-z0-9_", value: "A-Za-z0-9_"},
|
||||
{name: "Printable ASCII: space-~", value: "\\x20-~"}
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns true if the given character is uppercase
|
||||
*
|
||||
* @private
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @param {string} c - A character
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isUpperCase(c) {
|
||||
return c.toUpperCase() === c;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { affineDecrypt, affineDecryptInverse, AFFINE_ALPHABETS } from "../lib/Ciphers.mjs";
|
||||
|
||||
/**
|
||||
* Affine Cipher Decode operation
|
||||
|
@ -21,7 +20,7 @@ class AffineCipherDecode extends Operation {
|
|||
|
||||
this.name = "Affine Cipher Decode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The Affine cipher is a type of monoalphabetic substitution cipher. To decrypt, each letter in an alphabet is mapped to its numeric equivalent, decrypted by a mathematical function, and converted back to a letter.";
|
||||
this.description = "The Affine cipher is a type of monoalphabetic substitution cipher. To decrypt, each letter in an alphabet is mapped to its numeric equivalent, decrypted by a mathematical function (the inverse of ax+b % m), and converted back to a letter.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Affine_cipher";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -35,6 +34,16 @@ class AffineCipherDecode extends Operation {
|
|||
"name": "b",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Alphabet",
|
||||
"type": "editableOption",
|
||||
"value": AFFINE_ALPHABETS
|
||||
},
|
||||
{
|
||||
"name": "Use modular inverse values",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -47,32 +56,9 @@ class AffineCipherDecode extends Operation {
|
|||
* @throws {OperationError} if a or b values are invalid
|
||||
*/
|
||||
run(input, args) {
|
||||
const alphabet = "abcdefghijklmnopqrstuvwxyz",
|
||||
[a, b] = args,
|
||||
aModInv = Utils.modInv(a, 26); // Calculates modular inverse of a
|
||||
let output = "";
|
||||
|
||||
if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
|
||||
throw new OperationError("The values of a and b can only be integers.");
|
||||
}
|
||||
|
||||
if (Utils.gcd(a, 26) !== 1) {
|
||||
throw new OperationError("The value of `a` must be coprime to 26.");
|
||||
}
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
if (alphabet.indexOf(input[i]) >= 0) {
|
||||
// Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)
|
||||
output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];
|
||||
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
||||
// Same as above, accounting for uppercase
|
||||
output += alphabet[Utils.mod((alphabet.indexOf(input[i].toLowerCase()) - b) * aModInv, 26)].toUpperCase();
|
||||
} else {
|
||||
// Non-alphabetic characters
|
||||
output += input[i];
|
||||
}
|
||||
}
|
||||
return output;
|
||||
const a = args[0], b = args[1], alphabet = args[2], useInverse = args[3];
|
||||
if (useInverse) return affineDecryptInverse(input, a, b, alphabet);
|
||||
else return affineDecrypt(input, a, b, alphabet);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import { affineEncode } from "../lib/Ciphers.mjs";
|
||||
import { affineEncrypt, AFFINE_ALPHABETS } from "../lib/Ciphers.mjs";
|
||||
|
||||
/**
|
||||
* Affine Cipher Encode operation
|
||||
|
@ -20,7 +20,7 @@ class AffineCipherEncode extends Operation {
|
|||
|
||||
this.name = "Affine Cipher Encode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The Affine cipher is a type of monoalphabetic substitution cipher, wherein each letter in an alphabet is mapped to its numeric equivalent, encrypted using simple mathematical function, <code>(ax + b) % 26</code>, and converted back to a letter.";
|
||||
this.description = "The Affine cipher is a type of monoalphabetic substitution cipher, wherein each letter in an alphabet is mapped to its numeric equivalent, encrypted using simple mathematical function, <code>(ax + b) % m</code>, and converted back to a letter.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Affine_cipher";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
@ -34,6 +34,11 @@ class AffineCipherEncode extends Operation {
|
|||
"name": "b",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Alphabet",
|
||||
"type": "editableOption",
|
||||
"value": AFFINE_ALPHABETS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -44,7 +49,8 @@ class AffineCipherEncode extends Operation {
|
|||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return affineEncode(input, args);
|
||||
const a = args[0], b = args[1], alphabet = args[2];
|
||||
return affineEncrypt(input, a, b, alphabet);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Cipher tests.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @author Barry B [profbbrown@gmail.com]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
|
@ -18,7 +19,7 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [1, 0]
|
||||
args: [1, 0, "a-z"]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
@ -29,7 +30,29 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [0.1, 0.00001]
|
||||
args: [0.1, 0.00001, "a-z"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Encode: invalid a & b, empty alphabet",
|
||||
input: "some keys are shaped as locks. index[me]",
|
||||
expectedOutput: "The alphabet cannot be empty.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [0.1, 0.00001, ""]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Encode: valid a & b, empty alphabet",
|
||||
input: "some keys are shaped as locks. index[me]",
|
||||
expectedOutput: "The alphabet cannot be empty.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [7, 23, ""]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
@ -40,18 +63,40 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [1, 0]
|
||||
args: [1, 0, "a-z"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Encode: normal",
|
||||
input: "some keys are shaped as locks. index[me]",
|
||||
expectedOutput: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
|
||||
name: "Affine Encode: normal a-z",
|
||||
input: "Some Keys Are Shaped As Locks. index[me]",
|
||||
expectedOutput: "Vhnl Tldv Xyl Vcxelo Xv Qhrtv. zkolg[nl]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [23, 23]
|
||||
args: [23, 23, "a-z"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Encode: normal A-Za-z",
|
||||
input: "Some Keys Are Shaped As Locks. index[me]",
|
||||
expectedOutput: "VHNl tldv XYl VCxelO Xv QHrTv. ZkOlG[Nl]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [23, 23, "A-Za-z"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Encode: normal, printable ASCII",
|
||||
input: "Some Keys Are Shaped As Locks. index[me]",
|
||||
expectedOutput: "XCtz7^zk@76)z7X`}Zzc76@7uCLF@\\7w,czTRtz!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Encode",
|
||||
args: [23, 23, "\\u0020-~"]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
@ -62,7 +107,7 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [1, 0]
|
||||
args: [1, 0, "a-z", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
@ -73,40 +118,128 @@ TestRegister.addTests([
|
|||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [0.1, 0.00001]
|
||||
args: [0.1, 0.00001, "a-z", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: invalid a (coprime)",
|
||||
name: "Affine Decode: valid a & b, empty alphabet",
|
||||
input: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "The value of `a` must be coprime to 26.",
|
||||
expectedOutput: "The alphabet cannot be empty.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [8, 23]
|
||||
args: [23, 23, "", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: no effect",
|
||||
name: "Affine Decode: invalid a & b (non-integer), empty alphabet",
|
||||
input: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "The alphabet cannot be empty.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [1, 0]
|
||||
args: [0.1, 0.00001, "", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: normal",
|
||||
name: "Affine Decode: invalid a (non-coprime)",
|
||||
input: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "some keys are shaped as locks. index[me]",
|
||||
expectedOutput: "The value of `a` (8) must be coprime to 26.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [23, 23]
|
||||
args: [8, 23, "a-z", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: invalid a (non-coprime), printable ASCII",
|
||||
input: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "The value of `a` (5) must be coprime to 95.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [5, 23, "\\u0020-~", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: no effect, match case",
|
||||
input: "Vhnl Tldv Xyl Vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "Vhnl Tldv Xyl Vcxelo xv qhrtv. zkolg[nl]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [1, 0, "a-z", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: no effect, case sensitive",
|
||||
input: "Vhnl Tldv Xyl Vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "Vhnl Tldv Xyl Vcxelo xv qhrtv. zkolg[nl]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [1, 0, "A-Za-z", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: normal, case sensitive",
|
||||
input: "Vhnl Tldv Xyl Vcxelo xv qhrtv. zkolg[nl]",
|
||||
expectedOutput: "SOMe keys ARe SHapeD as lOcKs. InDeX[Me]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [23, 23, "A-Za-z", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: normal, match case",
|
||||
input: "Vhnl Tldv Xyl Vcxelo Xv Qhrtv. zkolg[nl]",
|
||||
expectedOutput: "Some Keys Are Shaped As Locks. index[me]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [23, 23, "a-z", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: normal, inverse",
|
||||
input: "Vhnl Tldv Xyl Vcxelo Xv Qhrtv. zkolg[nl]",
|
||||
expectedOutput: "Some Keys Are Shaped As Locks. index[me]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [17, 3, "a-z", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: normal, printable ASCII",
|
||||
input: "XCtz7^zk@76)z7X`}Zzc76@7uCLF@\\7w,czTRtz!",
|
||||
expectedOutput: "Some Keys Are Shaped As Locks. index[me]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [23, 23, "\u0020-~", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Affine Decode: normal, printable ASCII, inverse",
|
||||
input: "XCtz7^zk@76)z7X`}Zzc76@7uCLF@\\7w,czTRtz!",
|
||||
expectedOutput: "Some Keys Are Shaped As Locks. index[me]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Affine Cipher Decode",
|
||||
args: [62, 72, "\u0020-~", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue