Add Bacon cipher decoding

This commit is contained in:
Karsten Silkenbäumer 2019-03-02 15:00:42 +01:00
parent 8148c1a8a8
commit 77b098c5fe
5 changed files with 393 additions and 0 deletions

View File

@ -85,6 +85,7 @@
"Vigenère Decode",
"To Morse Code",
"From Morse Code",
"Bacon Cipher Decode",
"Bifid Cipher Encode",
"Bifid Cipher Decode",
"Affine Cipher Encode",

37
src/core/lib/Bacon.mjs Normal file
View File

@ -0,0 +1,37 @@
/**
* Bacon resources.
*
* @author Karsten Silkenbäumer [kassi@users.noreply.github.com]
* @copyright Karsten Silkenbäumer 2019
* @license Apache-2.0
*/
/**
* Bacon definitions.
*/
export const BACON_ALPHABET_REDUCED = "ABCDEFGHIKLMNOPQRSTUWXYZ";
export const BACON_ALPHABET_COMPLETE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
export const BACON_TRANSLATION_01 = "0/1";
export const BACON_TRANSLATION_AB = "A/B";
export const BACON_TRANSLATION_CASE = "Case";
export const BACON_TRANSLATION_AMNZ = "A-M/N-Z first letter";
export const BACON_TRANSLATIONS = [
BACON_TRANSLATION_01,
BACON_TRANSLATION_AB,
BACON_TRANSLATION_CASE,
BACON_TRANSLATION_AMNZ,
];
export const BACON_CLEARER_MAP = {
[BACON_TRANSLATIONS[0]]: /[^01]/g,
[BACON_TRANSLATIONS[1]]: /[^ABab]/g,
[BACON_TRANSLATIONS[2]]: /[^A-Za-z]/g,
};
export const BACON_NORMALIZE_MAP = {
[BACON_TRANSLATIONS[1]]: {
"A": "0",
"B": "1",
"a": "0",
"b": "1"
},
};

View File

@ -0,0 +1,108 @@
/**
* BaconCipher operation.
*
* @author kassi [kassi@users.noreply.github.com]
* @copyright Karsten Silkenbäumer 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import {
BACON_ALPHABET_REDUCED, BACON_ALPHABET_COMPLETE,
BACON_TRANSLATION_CASE, BACON_TRANSLATION_AMNZ, BACON_TRANSLATIONS, BACON_CLEARER_MAP, BACON_NORMALIZE_MAP
} from "../lib/Bacon";
/**
* BaconCipherDecode operation
*/
class BaconCipherDecode extends Operation {
/**
* BaconCipherDecode constructor
*/
constructor() {
super();
this.name = "Bacon Cipher Decode";
this.module = "Default";
this.description = "Bacon's cipher or the Baconian cipher is a method of steganography(a method of hiding a secret message as opposed to just a cipher) devised by Francis Bacon in 1605.[1][2][3] A message is concealed in the presentation of text, rather than its content.";
this.infoURL = "https://en.wikipedia.org/wiki/Bacon%27s_cipher";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Alphabet",
"type": "option",
"value": [BACON_ALPHABET_REDUCED, BACON_ALPHABET_COMPLETE]
},
{
"name": "Translation",
"type": "option",
"value": BACON_TRANSLATIONS
},
{
"name": "Invert Translation",
"type": "boolean",
"value": false
}
];
}
/**
* @param {String} input
* @param {Object[]} args
* @returns {String}
*/
run(input, args) {
const [alphabet, translation, invert] = args;
// split text into groups of 5 characters
// remove invalid characters
input = input.replace(BACON_CLEARER_MAP[translation], "");
// normalize to unique alphabet
if (BACON_NORMALIZE_MAP[translation] !== undefined) {
input = input.replace(/./g, function (c) {
return BACON_NORMALIZE_MAP[translation][c];
});
} else if (translation === BACON_TRANSLATION_CASE) {
const codeA = "A".charCodeAt(0);
const codeZ = "Z".charCodeAt(0);
input = input.replace(/./g, function (c) {
const code = c.charCodeAt(0);
if (code >= codeA && code <= codeZ) {
return "1";
} else {
return "0";
}
});
} else if (translation === BACON_TRANSLATION_AMNZ) {
const words = input.split(" ");
const letters = words.map(function (e) {
const code = e[0].toUpperCase().charCodeAt(0);
return code >= "N".charCodeAt(0) ? "1" : "0";
});
input = letters.join("");
}
if (invert) {
input = input.replace(/./g, function (c) {
return {
"0": "1",
"1": "0"
}[c];
});
}
// group into 5
const inputArray = input.match(/(.{5})/g) || [];
let output = "";
for (let index = 0; index < inputArray.length; index++) {
const code = inputArray[index];
const number = parseInt(code, 2);
output += number < alphabet.length ? alphabet[number] : "?";
}
return output;
}
}
export default BaconCipherDecode;

View File

@ -26,6 +26,7 @@ global.ENVIRONMENT_IS_WEB = function() {
import TestRegister from "./TestRegister";
import "./tests/BCD";
import "./tests/BSON";
import "./tests/BaconCipher";
import "./tests/Base58";
import "./tests/Base64";
import "./tests/Base62";

View File

@ -0,0 +1,246 @@
/**
* BaconCipher tests.
*
* @author Karsten Silkenbäumer [kassi@users.noreply.github.com]
* @copyright Karsten Silkenbäumer 2019
* @license Apache-2.0
*/
import TestRegister from "../TestRegister";
import { BACON_ALPHABET_REDUCED, BACON_ALPHABET_COMPLETE, BACON_TRANSLATIONS } from "../../../src/core/lib/Bacon";
const alphabets = [BACON_ALPHABET_REDUCED, BACON_ALPHABET_COMPLETE];
const translations = BACON_TRANSLATIONS;
TestRegister.addTests([
{
name: "Bacon Decode: no input",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[0], false]
}
],
},
{
name: "Bacon Decode: reduced alphabet 0/1",
input: "00011 00100 00010 01101 00011 01000 01100 00110 00001 00000 00010 01101 01100 10100 01101 10000 01001 10001",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[0], false]
}
],
},
{
name: "Bacon Decode: reduced alphabet 0/1 inverse",
input: "11100 11011 11101 10010 11100 10111 10011 11001 11110 11111 11101 10010 10011 01011 10010 01111 10110 01110",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[0], true]
}
],
},
{
name: "Bacon Decode: reduced alphabet A/B lower case",
input: "aaabb aabaa aaaba abbab aaabb abaaa abbaa aabba aaaab aaaaa aaaba abbab abbaa babaa abbab baaaa abaab baaab",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[1], false]
}
],
},
{
name: "Bacon Decode: reduced alphabet A/B lower case inverse",
input: "bbbaa bbabb bbbab baaba bbbaa babbb baabb bbaab bbbba bbbbb bbbab baaba baabb ababb baaba abbbb babba abbba",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[1], true]
}
],
},
{
name: "Bacon Decode: reduced alphabet A/B upper case",
input: "AAABB AABAA AAABA ABBAB AAABB ABAAA ABBAA AABBA AAAAB AAAAA AAABA ABBAB ABBAA BABAA ABBAB BAAAA ABAAB BAAAB",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[1], false]
}
],
},
{
name: "Bacon Decode: reduced alphabet A/B upper case inverse",
input: "BBBAA BBABB BBBAB BAABA BBBAA BABBB BAABB BBAAB BBBBA BBBBB BBBAB BAABA BAABB ABABB BAABA ABBBB BABBA ABBBA",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[1], true]
}
],
},
{
name: "Bacon Decode: reduced alphabet case code",
input: "thiS IsaN exampLe oF ThE bacON cIpher WIth upPPercasE letters tRanSLaTiNG to OnEs anD LoWErcase To zERoes. KS",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[2], false]
}
],
},
{
name: "Bacon Decode: reduced alphabet case code inverse",
input: "THIs iS An EXAMPlE Of tHe BACon CiPHER wiTH UPppERCASe LETTERS TrANslAtIng TO oNeS ANd lOweRCASE tO ZerOES. ks",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[2], true]
}
],
},
{
name: "Bacon Decode: reduced alphabet case code",
input: "A little example of the Bacon Cipher to be decoded. It is a working example and shorter than my others, but it anyways works tremendously. And just that's important, correct?",
expectedOutput: "DECODE",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[3], false]
}
],
},
{
name: "Bacon Decode: reduced alphabet case code inverse",
input: "Well, there's now another example which will be not only strange to read but sound weird for everyone not knowing what the thing is about. Nevertheless, works great out of the box.",
expectedOutput: "DECODE",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[0], translations[3], true]
}
],
},
{
name: "Bacon Decode: complete alphabet 0/1",
input: "00011 00100 00010 01110 00011 01000 01101 00110 00001 00000 00010 01110 01101 10110 01110 10001 01010 10010",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[0], false]
}
],
},
{
name: "Bacon Decode: complete alphabet 0/1 inverse",
input: "11100 11011 11101 10001 11100 10111 10010 11001 11110 11111 11101 10001 10010 01001 10001 01110 10101 01101",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[0], true]
}
],
},
{
name: "Bacon Decode: complete alphabet A/B lower case",
input: "aaabb aabaa aaaba abbba aaabb abaaa abbab aabba aaaab aaaaa aaaba abbba abbab babba abbba baaab ababa baaba",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[1], false]
}
],
},
{
name: "Bacon Decode: complete alphabet A/B lower case inverse",
input: "bbbaa bbabb bbbab baaab bbbaa babbb baaba bbaab bbbba bbbbb bbbab baaab baaba abaab baaab abbba babab abbab",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[1], true]
}
],
},
{
name: "Bacon Decode: complete alphabet A/B upper case",
input: "AAABB AABAA AAABA ABBBA AAABB ABAAA ABBAB AABBA AAAAB AAAAA AAABA ABBBA ABBAB BABBA ABBBA BAAAB ABABA BAABA",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[1], false]
}
],
},
{
name: "Bacon Decode: complete alphabet A/B upper case inverse",
input: "BBBAA BBABB BBBAB BAAAB BBBAA BABBB BAABA BBAAB BBBBA BBBBB BBBAB BAAAB BAABA ABAAB BAAAB ABBBA BABAB ABBAB",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[1], true]
}
],
},
{
name: "Bacon Decode: complete alphabet case code",
input: "thiS IsaN exampLe oF THe bacON cIpher WItH upPPercasE letters tRanSLAtiNG tO OnES anD LOwErcaSe To ZeRoeS. kS",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[2], false]
}
],
},
{
name: "Bacon Decode: complete alphabet case code inverse",
input: "THIs iSAn EXAMPlE Of thE BACon CiPHER wiTh UPppERCASe LETTERS TrANslaTIng To zEroES and LoWERcAsE tO oNEs. Ks",
expectedOutput: "DECODINGBACONWORKS",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[2], true]
}
],
},
{
name: "Bacon Decode: complete alphabet case code",
input: "A little example of the Bacon Cipher to be decoded. It is a working example and shorter than the first, but it anyways works tremendously. And just that's important, correct?",
expectedOutput: "DECODE",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[3], false]
}
],
},
{
name: "Bacon Decode: complete alphabet case code inverse",
input: "Well, there's now another example which will be not only strange to read but sound weird for everyone knowing nothing what the thing is about. Nevertheless, works great out of the box.",
expectedOutput: "DECODE",
recipeConfig: [
{
op: "Bacon Cipher Decode",
args: [alphabets[1], translations[3], true]
}
],
},
]);