|
@@ -569,349 +569,6 @@ DES uses a key length of 8 bytes (64 bits).`;
|
|
|
},
|
|
|
|
|
|
|
|
|
- /**
|
|
|
- * Vigenère Encode operation.
|
|
|
- *
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} input
|
|
|
- * @param {Object[]} args
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- runVigenereEnc: function (input, args) {
|
|
|
- let alphabet = "abcdefghijklmnopqrstuvwxyz",
|
|
|
- key = args[0].toLowerCase(),
|
|
|
- output = "",
|
|
|
- fail = 0,
|
|
|
- keyIndex,
|
|
|
- msgIndex,
|
|
|
- chr;
|
|
|
-
|
|
|
- if (!key) return "No key entered";
|
|
|
- if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
|
|
|
-
|
|
|
- for (let i = 0; i < input.length; i++) {
|
|
|
- if (alphabet.indexOf(input[i]) >= 0) {
|
|
|
- // Get the corresponding character of key for the current letter, accounting
|
|
|
- // for chars not in alphabet
|
|
|
- chr = key[(i - fail) % key.length];
|
|
|
- // Get the location in the vigenere square of the key char
|
|
|
- keyIndex = alphabet.indexOf(chr);
|
|
|
- // Get the location in the vigenere square of the message char
|
|
|
- msgIndex = alphabet.indexOf(input[i]);
|
|
|
- // Get the encoded letter by finding the sum of indexes modulo 26 and finding
|
|
|
- // the letter corresponding to that
|
|
|
- output += alphabet[(keyIndex + msgIndex) % 26];
|
|
|
- } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
|
|
- chr = key[(i - fail) % key.length].toLowerCase();
|
|
|
- keyIndex = alphabet.indexOf(chr);
|
|
|
- msgIndex = alphabet.indexOf(input[i].toLowerCase());
|
|
|
- output += alphabet[(keyIndex + msgIndex) % 26].toUpperCase();
|
|
|
- } else {
|
|
|
- output += input[i];
|
|
|
- fail++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return output;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Vigenère Decode operation.
|
|
|
- *
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} input
|
|
|
- * @param {Object[]} args
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- runVigenereDec: function (input, args) {
|
|
|
- let alphabet = "abcdefghijklmnopqrstuvwxyz",
|
|
|
- key = args[0].toLowerCase(),
|
|
|
- output = "",
|
|
|
- fail = 0,
|
|
|
- keyIndex,
|
|
|
- msgIndex,
|
|
|
- chr;
|
|
|
-
|
|
|
- if (!key) return "No key entered";
|
|
|
- if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
|
|
|
-
|
|
|
- for (let i = 0; i < input.length; i++) {
|
|
|
- if (alphabet.indexOf(input[i]) >= 0) {
|
|
|
- chr = key[(i - fail) % key.length];
|
|
|
- keyIndex = alphabet.indexOf(chr);
|
|
|
- msgIndex = alphabet.indexOf(input[i]);
|
|
|
- // Subtract indexes from each other, add 26 just in case the value is negative,
|
|
|
- // modulo to remove if neccessary
|
|
|
- output += alphabet[(msgIndex - keyIndex + alphabet.length) % 26];
|
|
|
- } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
|
|
- chr = key[(i - fail) % key.length].toLowerCase();
|
|
|
- keyIndex = alphabet.indexOf(chr);
|
|
|
- msgIndex = alphabet.indexOf(input[i].toLowerCase());
|
|
|
- output += alphabet[(msgIndex + alphabet.length - keyIndex) % 26].toUpperCase();
|
|
|
- } else {
|
|
|
- output += input[i];
|
|
|
- fail++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return output;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * @constant
|
|
|
- * @default
|
|
|
- */
|
|
|
- AFFINE_A: 1,
|
|
|
- /**
|
|
|
- * @constant
|
|
|
- * @default
|
|
|
- */
|
|
|
- AFFINE_B: 0,
|
|
|
-
|
|
|
- /**
|
|
|
- * Affine Cipher Encode operation.
|
|
|
- *
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} input
|
|
|
- * @param {Object[]} args
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- runAffineEnc: function (input, args) {
|
|
|
- let alphabet = "abcdefghijklmnopqrstuvwxyz",
|
|
|
- a = args[0],
|
|
|
- b = args[1],
|
|
|
- output = "";
|
|
|
-
|
|
|
- if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
|
|
|
- return "The values of a and b can only be integers.";
|
|
|
- }
|
|
|
-
|
|
|
- for (let i = 0; i < input.length; i++) {
|
|
|
- if (alphabet.indexOf(input[i]) >= 0) {
|
|
|
- // Uses the affine function ax+b % m = y (where m is length of the alphabet)
|
|
|
- output += alphabet[((a * alphabet.indexOf(input[i])) + b) % 26];
|
|
|
- } else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
|
|
- // Same as above, accounting for uppercase
|
|
|
- output += alphabet[((a * alphabet.indexOf(input[i].toLowerCase())) + b) % 26].toUpperCase();
|
|
|
- } else {
|
|
|
- // Non-alphabetic characters
|
|
|
- output += input[i];
|
|
|
- }
|
|
|
- }
|
|
|
- return output;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Affine Cipher Decode operation.
|
|
|
- *
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} input
|
|
|
- * @param {Object[]} args
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- runAffineDec: function (input, args) {
|
|
|
- let alphabet = "abcdefghijklmnopqrstuvwxyz",
|
|
|
- a = args[0],
|
|
|
- b = args[1],
|
|
|
- output = "",
|
|
|
- aModInv;
|
|
|
-
|
|
|
- if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
|
|
|
- return "The values of a and b can only be integers.";
|
|
|
- }
|
|
|
-
|
|
|
- if (Utils.gcd(a, 26) !== 1) {
|
|
|
- return "The value of a must be coprime to 26.";
|
|
|
- }
|
|
|
-
|
|
|
- // Calculates modular inverse of a
|
|
|
- aModInv = Utils.modInv(a, 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;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Atbash Cipher Encode operation.
|
|
|
- *
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} input
|
|
|
- * @param {Object[]} args
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- runAtbash: function (input, args) {
|
|
|
- return Cipher.runAffineEnc(input, [25, 25]);
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Generates a polybius square for the given keyword
|
|
|
- *
|
|
|
- * @private
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} keyword - Must be upper case
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- _genPolybiusSquare: function (keyword) {
|
|
|
- const alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
|
|
|
- const polArray = `${keyword}${alpha}`.split("").unique();
|
|
|
- let polybius = [];
|
|
|
-
|
|
|
- for (let i = 0; i < 5; i++) {
|
|
|
- polybius[i] = polArray.slice(i*5, i*5 + 5);
|
|
|
- }
|
|
|
-
|
|
|
- return polybius;
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * Bifid Cipher Encode operation
|
|
|
- *
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} input
|
|
|
- * @param {Object[]} args
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- runBifidEnc: function (input, args) {
|
|
|
- const keywordStr = args[0].toUpperCase().replace("J", "I"),
|
|
|
- keyword = keywordStr.split("").unique(),
|
|
|
- alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
|
|
|
-
|
|
|
- let output = "",
|
|
|
- xCo = [],
|
|
|
- yCo = [],
|
|
|
- structure = [],
|
|
|
- count = 0;
|
|
|
-
|
|
|
- if (keyword.length > 25)
|
|
|
- return "The alphabet keyword must be less than 25 characters.";
|
|
|
-
|
|
|
- if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
|
|
|
- return "The key must consist only of letters";
|
|
|
-
|
|
|
- const polybius = Cipher._genPolybiusSquare(keywordStr);
|
|
|
-
|
|
|
- input.replace("J", "I").split("").forEach(letter => {
|
|
|
- let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
|
|
|
- polInd;
|
|
|
-
|
|
|
- if (alpInd) {
|
|
|
- for (let i = 0; i < 5; i++) {
|
|
|
- polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
|
|
|
- if (polInd >= 0) {
|
|
|
- xCo.push(polInd);
|
|
|
- yCo.push(i);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (alpha.split("").indexOf(letter) >= 0) {
|
|
|
- structure.push(true);
|
|
|
- } else if (alpInd) {
|
|
|
- structure.push(false);
|
|
|
- }
|
|
|
- } else {
|
|
|
- structure.push(letter);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- const trans = `${yCo.join("")}${xCo.join("")}`;
|
|
|
-
|
|
|
- structure.forEach(pos => {
|
|
|
- if (typeof pos === "boolean") {
|
|
|
- let coords = trans.substr(2*count, 2).split("");
|
|
|
-
|
|
|
- output += pos ?
|
|
|
- polybius[coords[0]][coords[1]] :
|
|
|
- polybius[coords[0]][coords[1]].toLocaleLowerCase();
|
|
|
- count++;
|
|
|
- } else {
|
|
|
- output += pos;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- return output;
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * Bifid Cipher Decode operation
|
|
|
- *
|
|
|
- * @author Matt C [matt@artemisbot.uk]
|
|
|
- * @param {string} input
|
|
|
- * @param {Object[]} args
|
|
|
- * @returns {string}
|
|
|
- */
|
|
|
- runBifidDec: function (input, args) {
|
|
|
- const keywordStr = args[0].toUpperCase().replace("J", "I"),
|
|
|
- keyword = keywordStr.split("").unique(),
|
|
|
- alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
|
|
|
-
|
|
|
- let output = "",
|
|
|
- structure = [],
|
|
|
- count = 0,
|
|
|
- trans = "";
|
|
|
-
|
|
|
- if (keyword.length > 25)
|
|
|
- return "The alphabet keyword must be less than 25 characters.";
|
|
|
-
|
|
|
- if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
|
|
|
- return "The key must consist only of letters";
|
|
|
-
|
|
|
- const polybius = Cipher._genPolybiusSquare(keywordStr);
|
|
|
-
|
|
|
- input.replace("J", "I").split("").forEach((letter) => {
|
|
|
- let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
|
|
|
- polInd;
|
|
|
-
|
|
|
- if (alpInd) {
|
|
|
- for (let i = 0; i < 5; i++) {
|
|
|
- polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
|
|
|
- if (polInd >= 0) {
|
|
|
- trans += `${i}${polInd}`;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (alpha.split("").indexOf(letter) >= 0) {
|
|
|
- structure.push(true);
|
|
|
- } else if (alpInd) {
|
|
|
- structure.push(false);
|
|
|
- }
|
|
|
- } else {
|
|
|
- structure.push(letter);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- structure.forEach(pos => {
|
|
|
- if (typeof pos === "boolean") {
|
|
|
- let coords = [trans[count], trans[count+trans.length/2]];
|
|
|
-
|
|
|
- output += pos ?
|
|
|
- polybius[coords[0]][coords[1]] :
|
|
|
- polybius[coords[0]][coords[1]].toLocaleLowerCase();
|
|
|
- count++;
|
|
|
- } else {
|
|
|
- output += pos;
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- return output;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
* @constant
|
|
|
* @default
|