CryptoWorkbench/cryptoworkbench.csharp
2016-09-21 19:10:34 -05:00

320 lines
14 KiB
Plaintext

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using AniNIX.TheRaven;
namespace AniNIX.Crypto {
public class Workbench {
public string inputText { get; private set; }
public string workSpace { get; private set; }
public StringBuilder HelpText = new StringBuilder();
public Dictionary<String,Cipher> SwitchCases = new Dictionary<String,Cipher>();
// The workbench needs to maintain an instance of each ciphersuite for operation.
private Substitution _sub;
private Analysis _analysis;
private Simple _simple;
private Caesarian _caesar;
private Affine _affine;
private Vigenere _vig;
private ColumnTransposition _col;
private Ubchi _ubchi;
// If this is true, we will prevent prompt and filesystem access.
private bool _isBlind = false;
/// <summary>
/// Read in a cipher either from a filename or from stdin
/// <summary>
/// <param name="line">user input</param>
private void ReadCipher(String[] line) {
// If a filename's not provided.
if (line == null || line.Length !=2) {
Console.WriteLine("Please paste your ciphertext.");
string readLn = Console.ReadLine();
StringBuilder sb = new StringBuilder();
//Read lines from stdin until a blank line is given.
while (readLn != null && !String.IsNullOrWhiteSpace((readLn))) {
sb.AppendLine(readLn);
readLn=Console.ReadLine();
}
// The user's input is the trimmed sum of the lines.
inputText = sb.ToString().Trim();
} else {
// Try to read the file into the input.
try {
StringBuilder sb = new StringBuilder();
StreamReader fileReader = new StreamReader(line[1]);
String lineR = fileReader.ReadLine();
while (lineR != null) {
sb.AppendLine(lineR);
lineR = fileReader.ReadLine();
}
fileReader.Dispose();
fileReader = null;
inputText = sb.ToString().Trim();
Console.WriteLine(String.Format("Read {0}",line[1]));
}
// If there's a problem, input is null.
catch (Exception e) {
Console.Error.WriteLine(e.Message);
inputText = null;
}
}
workSpace = inputText;
}
/// <summary>
/// Create a new workbench from input.
/// </summary>
/// <param name="args">the arguments provided for execution</param>
public Workbench(string[] args) {
// If args are null, read from STDIN.
if (args.Length == 0) {
ReadCipher(null);
// If there's only one arg and that's --blind, set the blind option and read from stdin.
} else if (args.Length == 1) {
if (args[0].Equals("--blind")) {
this._isBlind = true;
ReadCipher(null);
// Otherwise, try to use the first argument as a filename.
} else {
String[] line = new String[2];
line[0] = "reread";
line[1] = args[0];
ReadCipher(line);
}
// Otherwise, give some help and exit.
} else {
Console.Error.WriteLine("The only argument allowed is a filename containing the ciphertext or --blind to block filesystem access.");
System.Environment.Exit(1);
}
// Seed the helptext.
HelpText.Append("You can get help on any command by running \"<command> help\".\nSuppress printing the cipher with a trailing ;.\nAvailable commands:\n");
// Don't tell users about things they can't use.
if (!_isBlind) {
HelpText.Append("reread -- Read in a new cipher\n");
HelpText.Append("write -- write the workspace to a file\n");
}
HelpText.Append("regex -- Check for strings with the two regex arguments: [search] [filter]\n");
HelpText.Append("reset -- reset workspace to the ciphertext.\n");
HelpText.Append("links -- show some helpful links\n");
HelpText.Append("help -- show this HelpText\n");
HelpText.Append("print -- show the current workspace\n");
HelpText.Append("display -- alias of print\n");
HelpText.Append("exit -- exit and show the result.\n");
HelpText.Append("quit -- alias of exit.\n");
// Initialize the ciphersuites.
_sub = new Substitution(this);
_analysis = new Analysis(this);
_simple = new Simple(this);
_caesar = new Caesarian(this);
_affine = new Affine(this);
_vig = new Vigenere(this);
_col = new ColumnTransposition(this);
_ubchi = new Ubchi(this);
}
/// <summary>
/// Convert this workbench into a readable string.
/// </summary>
public override String ToString() {
StringBuilder currentStatus = new StringBuilder();
currentStatus.Append("Input:\n");
currentStatus.Append(this.inputText);
currentStatus.Append("\n");
currentStatus.Append("Workspace:\n");
currentStatus.Append(this.workSpace);
return currentStatus.ToString();
}
/// <summary>
/// Display this workbench to stdout with colors.
/// </summary>
public void Print() {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Input:");
Console.ResetColor();
Console.WriteLine(this.inputText);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Workspace:");
Console.ResetColor();
List<String> topletters = Analysis.GetMostCommonLetters(workSpace).Take(5).ToList();//cyan
List<String> bigrams = Analysis.Top(Analysis.GetSubstrings(workSpace,2)); //yellow
List<String> trigrams = Analysis.Top(Analysis.GetSubstrings(workSpace,3));//magenta
for (int i = 0; i < workSpace.Length; i++) {
if (i < workSpace.Length-1 && workSpace[i] == workSpace[i+1]) {
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(workSpace[i++]);
} else if (i < workSpace.Length-2 && trigrams.Contains(workSpace.Substring(i,3))) {
Console.ForegroundColor = ConsoleColor.Magenta;
Console.Write(workSpace[i++]);
Console.Write(workSpace[i++]);
} else if (i < workSpace.Length-1 && bigrams.Contains(workSpace.Substring(i,2))) {
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(workSpace[i++]);
} else if (topletters.Contains(workSpace[i].ToString())) {
Console.ForegroundColor = ConsoleColor.Cyan;
}
Console.Write(workSpace[i]);
Console.ResetColor();
}
Console.WriteLine();
}
/// <summary>
/// Show some helpful links.
/// </summary>
public static void HelpfulLinks() {
StringBuilder linksText = new StringBuilder();
linksText.Append("http://www.visca.com/regexdict/ -- RegEx word dictionary\n");
linksText.Append("http://rumkin.com/tools/cipher/ -- Cipher tools\n");
linksText.Append("http://norvig.com/mayzner.html -- Frequency analysis\n");
Console.Write(linksText.ToString());
}
/// <summary>
/// Save the workspace to a file
/// </summary>
/// <param name="workSpace"> what to write </param>
/// <param name="line"> user input, which should include a file</param>
public void WriteWorkspace(String workSpace, String[] line) {
// Require a filename.
if (line == null || line.Length != 2) {
Console.Error.WriteLine("Need a file.");
return;
}
try {
// If we are actually given a file, write the workspace to a file and close.
StreamWriter fileWriter = new StreamWriter(line[1],false);
fileWriter.WriteLine(workSpace);
fileWriter.Dispose();
fileWriter = null;
Console.WriteLine(String.Format("Wrote file {0}",line[1]));
} catch (Exception e) {
// Let the user know the file's not writeable.
Console.WriteLine(String.Format("Couldn't write file.\n{0}",e.Message));
}
}
/// <summary>
/// Interact with the user.
/// </summary>
public void Run() {
// Display the header.
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("### Welcome to the AniNIX::CryptoWorkbench ###");
Console.ResetColor();
try {
// Set the initial command to be show the helptext.
string command = "help";
string read = "help";
string[] line;
bool showCipher=true;
// Until the user exits...
while (command != "exit" && command != "quit") {
// parse shell-type command unification with semicolons
foreach (String executable in read.Split(';')) {
// If the command is only whitespace, continue and don't show the cipher.
if (String.IsNullOrWhiteSpace(executable)) {
showCipher = false; // if the last nonwhitespace character is a semicolon, we won't bother printing.
continue;
}
// Otherwise we will show the cipehr.
showCipher = true;
line = executable.Trim().Split(' ');
command = line[0];
// Command is first space-delimited entry.
switch (command) {
case "reread":
if (!_isBlind) ReadCipher(line);
break;
case "write":
if (!_isBlind) WriteWorkspace(workSpace,line);
break;
case "reset":
this.workSpace = this.inputText;
Console.Clear();
Console.WriteLine("Reset.");
break;
case "links":
HelpfulLinks();
break;
case "regex":
try {
if (line.Length == 3) {
Console.Write(RavenExecute.Command(String.Format("bash /usr/local/src/CryptoWorkbench/regex-lookup.bash \"{0}\" \"{1}\"",line[1].Replace("\\","\\\\").Replace("$","\\$"),line[2].Replace("\\","\\\\").Replace("$","\\$"))));
} else if (line.Length == 2) {
Console.Write(RavenExecute.Command(String.Format("bash /usr/local/src/CryptoWorkbench/regex-lookup.bash \"{0}\"",line[1].Replace("\\","\\\\").Replace("$","\\$"))));
} else {
Console.Error.WriteLine("Need at least one search term.");
}
} catch (Exception e) {
Console.Error.WriteLine(e.ToString());
}
break;
case "help":
Console.WriteLine(HelpText.ToString());
break;
case "display":
case "print":
showCipher = true;
break;
case "exit":
case "quit":
throw new Exception("");
default:
try {
workSpace = SwitchCases[command].RunCommand(this.workSpace,this.inputText,line);
} catch (Exception e) {
Console.Error.WriteLine("Command not found.");
}
break;
}
}
// Show the cipher if the user asked.
if (showCipher) Print();
// Display an AniNIX-standard prompt.
Console.Write("\nWhat command would you like to execute?\n");
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("|");
Console.ResetColor();
Console.Write("> ");
read = Console.ReadLine().Trim();
}
// If we run into trouble, tell the user.
} catch (Exception e) {
Console.Error.WriteLine(e.Message);
}
// When we exit, show the result to the user.
finally {
Console.WriteLine("\nFinal result:");
this.Print();
}
}
/// <summary>
/// Create and execute a workbench program.
/// </summary>
public static void Main(string[] args) {
Workbench cw = new Workbench(args);
try {
cw.Run();
} catch (NullReferenceException e) {
Console.Error.WriteLine(String.Format("Caught {0}",e.GetType().ToString()));
}
}
}
}