using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
namespace AniNIX.Crypto {
public class Substitution : Cipher {
public char[] EngCommon = {'e','t','a','o','i','n','s','h','r','d','l','u','c','m','w','f','y','g','p','b','v','k','x','j','q','z'};
public override String Description() { return "Subsitution cipher suite\nKey format is \"E[EEE]=d[ddd]\", where E is the character in the cipher and d is the intended character in the workspace."; }
public override String Command() { return "sub"; }
public Substitution(Workbench w) : base (w) {}
///
/// We should be able to act on a workspace and command line. Most ciphers will sue the same syntax. Those that don't can override.
///
/// The current version of the text being worked on.
/// The command sequence.
/// The updated version of the workSpace
public override String RunCommand(String workSpace,String inputText,String[] line) {
if (workSpace == null || line == null || line.Length < 2) {
Console.Error.WriteLine("Malformed request.");
return workSpace;
}
switch (line[1]) {
case "encrypt":
return Encrypt(workSpace,inputText,line);
case "decrypt":
return Decrypt(workSpace,inputText,line);
case "try-common":
return TryCommon(inputText);
case "help":
GetHelp();
return workSpace;
default:
Console.Error.WriteLine("Invalid command. Type help for more.");
return workSpace;
}
}
///
/// Show the helptext for this cipher. By default, most ciphers will only have encrypt, decrypt, and help functions.
///
/// This is the incoming line and we use it to get the cipher name
public override void GetHelp() {
Console.WriteLine(String.Format("Help for the {0} cipher suite.\n{1}\n",Command(),Description()));
Console.WriteLine("encrypt key[s] -- encrypt with the key[s]\ndecrypt key[s] -- decrypt with the key[s]\ntry-common -- try common sub keys\nhelp -- show this helptext.");
}
///
/// Encrypt a string with the cipher, replacing one character with another.
///
/// The working copy of the cipher
/// The original cipher
/// The user input
/// The encrypted string
public override String Encrypt(String workSpace, String cipher, String[] line) {
if (line.Length < 3) {
Console.Error.WriteLine("Bad formatting.");
return workSpace;
}
char[] changed = workSpace.ToCharArray();
for (int i=2; i
/// Perform a frequency analysis and see if ETAOIN substitution will solve the problem. TODO this should look at a dictionary for confirmation.
///
/// the string to analyze and brute-force
/// an attempted solution.
public String TryCommon(String workSpace) {
// Get the frequency analysis
List sortedChars = Analysis.GetMostCommonLetters(workSpace.ToLower());
// Strip to lower for now and replace. TODO ensure all manipulation is done in lower case and restored later.
char[] modified = workSpace.ToLower().ToCharArray();
char replaceChar;
// For each character in the string, replace with its frequency map equivalent.
for (int i = 0; i < modified.Length; i++) {
if (!Char.IsLetter(modified[i])) { continue; }
Console.WriteLine(String.Format("Character <{0}> occurs {1}st in frequency, corresponding with <{2}> -- replacing...",
modified[i],
sortedChars.IndexOf(modified[i].ToString()),
EngCommon[sortedChars.IndexOf(modified[i].ToString())]));
replaceChar = EngCommon[sortedChars.IndexOf(modified[i].ToString())];
replaceChar = (workSpace[i] == Char.ToLower(workSpace[i])) ? replaceChar : Char.ToUpper(replaceChar);
modified[i] = replaceChar;
}
return new String(modified);
}
}
}