mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-20 14:56:19 -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
|
- name: Set node version
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '20.x'
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -1266,19 +1266,26 @@ class Utils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the modular inverse of two values.
|
* Finds the modular inverse of two values.
|
||||||
|
* Uses the Extended Euclidean Algorithm.
|
||||||
*
|
*
|
||||||
* @author Matt C [matt@artemisbot.uk]
|
* @author Barry B [profbbrown@gmail.com]
|
||||||
* @param {number} x
|
* @param {number} a
|
||||||
* @param {number} y
|
* @param {number} n
|
||||||
* @returns {number}
|
* @returns {number|null}
|
||||||
*/
|
*/
|
||||||
static modInv(x, y) {
|
static modInv(a, n) {
|
||||||
x %= y;
|
let t = 0, newT = 1, r = n, newR = a;
|
||||||
for (let i = 1; i < y; i++) {
|
|
||||||
if ((x * i) % 26 === 1) {
|
while (newR !== 0) {
|
||||||
return i;
|
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 Matt C [matt@artemisbot.uk]
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
* @author Evie H [evie@evie.sh]
|
* @author Evie H [evie@evie.sh]
|
||||||
|
* @author Barry B [profbbrown@gmail.com]
|
||||||
*
|
*
|
||||||
* @copyright Crown Copyright 2018
|
* @copyright Crown Copyright 2018
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
|
@ -17,6 +18,7 @@ import CryptoJS from "crypto-js";
|
||||||
/**
|
/**
|
||||||
* Affine Cipher Encode operation.
|
* Affine Cipher Encode operation.
|
||||||
*
|
*
|
||||||
|
* @deprecated Use affineEcrypt instead.
|
||||||
* @author Matt C [matt@artemisbot.uk]
|
* @author Matt C [matt@artemisbot.uk]
|
||||||
* @param {string} input
|
* @param {string} input
|
||||||
* @param {Object[]} args
|
* @param {Object[]} args
|
||||||
|
@ -51,6 +53,166 @@ export function affineEncode(input, args) {
|
||||||
return output;
|
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
|
* Generates a polybius square for the given keyword
|
||||||
*
|
*
|
||||||
|
@ -86,3 +248,22 @@ export const format = {
|
||||||
"UTF16BE": CryptoJS.enc.Utf16BE,
|
"UTF16BE": CryptoJS.enc.Utf16BE,
|
||||||
"Latin1": CryptoJS.enc.Latin1,
|
"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 Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import { affineDecrypt, affineDecryptInverse, AFFINE_ALPHABETS } from "../lib/Ciphers.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Affine Cipher Decode operation
|
* Affine Cipher Decode operation
|
||||||
|
@ -21,7 +20,7 @@ class AffineCipherDecode extends Operation {
|
||||||
|
|
||||||
this.name = "Affine Cipher Decode";
|
this.name = "Affine Cipher Decode";
|
||||||
this.module = "Ciphers";
|
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.infoURL = "https://wikipedia.org/wiki/Affine_cipher";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -35,6 +34,16 @@ class AffineCipherDecode extends Operation {
|
||||||
"name": "b",
|
"name": "b",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"value": 0
|
"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
|
* @throws {OperationError} if a or b values are invalid
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const alphabet = "abcdefghijklmnopqrstuvwxyz",
|
const a = args[0], b = args[1], alphabet = args[2], useInverse = args[3];
|
||||||
[a, b] = args,
|
if (useInverse) return affineDecryptInverse(input, a, b, alphabet);
|
||||||
aModInv = Utils.modInv(a, 26); // Calculates modular inverse of a
|
else return affineDecrypt(input, a, b, alphabet);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import { affineEncode } from "../lib/Ciphers.mjs";
|
import { affineEncrypt, AFFINE_ALPHABETS } from "../lib/Ciphers.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Affine Cipher Encode operation
|
* Affine Cipher Encode operation
|
||||||
|
@ -20,7 +20,7 @@ class AffineCipherEncode extends Operation {
|
||||||
|
|
||||||
this.name = "Affine Cipher Encode";
|
this.name = "Affine Cipher Encode";
|
||||||
this.module = "Ciphers";
|
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.infoURL = "https://wikipedia.org/wiki/Affine_cipher";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
@ -34,6 +34,11 @@ class AffineCipherEncode extends Operation {
|
||||||
"name": "b",
|
"name": "b",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"value": 0
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Alphabet",
|
||||||
|
"type": "editableOption",
|
||||||
|
"value": AFFINE_ALPHABETS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -44,7 +49,8 @@ class AffineCipherEncode extends Operation {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
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.
|
* Cipher tests.
|
||||||
*
|
*
|
||||||
* @author Matt C [matt@artemisbot.uk]
|
* @author Matt C [matt@artemisbot.uk]
|
||||||
|
* @author Barry B [profbbrown@gmail.com]
|
||||||
* @author n1474335 [n1474335@gmail.com]
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
*
|
*
|
||||||
* @copyright Crown Copyright 2018
|
* @copyright Crown Copyright 2018
|
||||||
|
@ -18,7 +19,7 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Encode",
|
op: "Affine Cipher Encode",
|
||||||
args: [1, 0]
|
args: [1, 0, "a-z"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -29,7 +30,29 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Encode",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Encode",
|
op: "Affine Cipher Encode",
|
||||||
args: [1, 0]
|
args: [1, 0, "a-z"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Affine Encode: normal",
|
name: "Affine Encode: normal a-z",
|
||||||
input: "some keys are shaped as locks. index[me]",
|
input: "Some Keys Are Shaped As Locks. index[me]",
|
||||||
expectedOutput: "vhnl tldv xyl vcxelo xv qhrtv. zkolg[nl]",
|
expectedOutput: "Vhnl Tldv Xyl Vcxelo Xv Qhrtv. zkolg[nl]",
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Encode",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Decode",
|
op: "Affine Cipher Decode",
|
||||||
args: [1, 0]
|
args: [1, 0, "a-z", false]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -73,40 +118,128 @@ TestRegister.addTests([
|
||||||
recipeConfig: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Decode",
|
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]",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Decode",
|
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]",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Decode",
|
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]",
|
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: [
|
recipeConfig: [
|
||||||
{
|
{
|
||||||
op: "Affine Cipher Decode",
|
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