320 lines
14 KiB
Plaintext
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()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|