using System; using System.Linq; using System.IO; using System.Text; using System.Collections.Generic; namespace AniNIX.Crypto { public class Affine : Cipher { public override String Description() { return "The Affine cipher\nKey format is two numbers, where the second number is coprime to the first.\n\nExample: affine encrypt 5 3\n\n"; } public override String Command() {return "affine";} public Affine(Workbench w) : base (w) {} /// /// Encrypt a string with the Affine cipher /// /// A parameter for X /// A parameter for Y /// The line given by the user /// The return value public override String Encrypt(String workSpace,String inputText,String[] line) { // Affine requires two numbers if (line == null || line.Length != 4) { Console.Error.WriteLine("Malformed!"); return workSpace; } char[] changed = workSpace.ToCharArray(); try { // Convert the first number to an int int a = Int32.Parse(line[2]); // Validate the first number is coprime to 26. try { MultiplicativeInverse(a); } catch (Exception e) { Console.Error.WriteLine(String.Format("Value a <{0}> is not coprime to 26.\n{1}",a,e.Message)); return workSpace; } // Convert the second number to an int int b = Int32.Parse(line[3]); // For each letter in the workSpace, apply the forumula e(x) = (ax + b) mod m for (int i = 0; i < changed.Length; i++) { if (Char.IsLetter(changed[i])) { int baseC = (Char.IsUpper(changed[i])) ? (int)'A' : (int)'a'; int modC = (int)changed[i] - baseC; changed[i] = (char)(((a*modC+b)%26)+baseC); } } // If there's a problem solving, tell the user. } catch (Exception e) { Console.Error.WriteLine(String.Format("Failed!\n{0}",e.Message)); return workSpace; } return new String(changed); } /// /// Find the multiplicative inverse of a number. /// /// A number /// The inverse public int MultiplicativeInverse(int a) { for (int x=1; x < 27; x++) { //Try to find a number where the input times that number mod 26 is 1. If we roll through 26 numbers and don't find it, there isn't one. if ((a*x)%26 == 1) { return x; } } throw new Exception("A is not coprime."); } /// /// Decrypt a string with the cipher /// /// A parameter for X /// A parameter for Y /// The user input /// The decrypted string public override String Decrypt(String workSpace,String inputText,String[] line) { // Decryption requires two numbers. if (line == null || line.Length != 4) { Console.Error.WriteLine("Malformed!"); return workSpace; } char[] changed = workSpace.ToCharArray(); try { //Convert both numbers to ints int a = Int32.Parse(line[2]); int b = Int32.Parse(line[3]); //Find the multiplicative inverse of the first. int multiinv = MultiplicativeInverse(a); // For each character, decrypt with d(x) = a-1(x - b) mod m for (int i = 0; i < changed.Length; i++) { if (Char.IsLetter(changed[i])) { int baseC = (Char.IsUpper(changed[i])) ? (int)'A' : (int)'a'; int modC = (int)changed[i] - baseC; int modResult = (multiinv * (modC-b))%26; modResult = (modResult < 0) ? modResult+26 : modResult; // In case modResult is negative, add 26 back changed[i] = (char)(modResult+baseC); } } } catch (Exception e) { Console.Error.WriteLine(String.Format("Failed!\n{0}",e.Message)); return workSpace; } return new String(changed); } } }