mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-24 08:46:19 -04:00
Refactor affine encrypt/decrypt functions
This commit is contained in:
parent
de57002c6f
commit
979de8e488
1 changed files with 154 additions and 0 deletions
|
@ -51,6 +51,141 @@ 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) {
|
||||||
|
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) {
|
||||||
|
for (let i = 0; i < alphabet.length; i++)
|
||||||
|
alphabet[i] = alphabet[i].toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
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` 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 - Multiplier coefficient
|
||||||
|
* @param {integer} b - Addition 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") {
|
||||||
|
const m = Utils.expandAlphRange(alphabet).length;
|
||||||
|
const aInv = Utils.modInv(a, m);
|
||||||
|
const bInv = (m - b) % m;
|
||||||
|
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 +221,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: sp-~", value: " -~"}
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue