/// <summary> /// Decrypt the given ciphertext using the pre-set list of decryption keys /// Assumes the list of decryption keys has been populated already /// </summary> static string DecryptCipherText(string cipherAsHex) { if (DecryptionKeys.Count == 0) { Console.WriteLine("ERROR: We don't seem to have a list of encryption keys."); return("ERROR"); } string decryptedCipher = string.Empty; byte[] cipherAsBytes = StringToByteArray(cipherAsHex); // Iterate over the give cipher text and decrypt for (int i = 0; i < cipherAsBytes.Length; i++) { // Find the decrytion key for this position DecryptionKey key = FindDecryptionKey(i); if (key == null) { // We don't have a key for this position somehow - output ? instead decryptedCipher += "?"; continue; } int xorResult = cipherAsBytes[i] ^ key.Key; // Convert to ASCII character char decryptedChar = Convert.ToChar(xorResult); decryptedCipher += decryptedChar; } return(decryptedCipher); }
static List <DecryptionKey> DecryptionKeys; // List of decryption keys per position (built up along the way) static void Main(string[] args) { // Read the given ciphertexts from the XML file where I store them CipherTexts = ReadCipherTexts(); DecryptionKeys = new List <DecryptionKey>(); Console.WriteLine("Read {0} ciphertexts from XML.", CipherTexts.Count); int currentCipherIndex = 0; // Iterating over Ciphers as Hex Strings while (currentCipherIndex < CipherTexts.Count) { Console.WriteLine("Current Cipher Index: " + currentCipherIndex); byte[] currentCipherAsBytes = StringToByteArray(CipherTexts[currentCipherIndex]); int currentByteIndex = 0; // Iterating over Bytes in the current Cipher while (currentByteIndex < currentCipherAsBytes.Length) { Console.WriteLine("Checking Index: " + currentByteIndex); // Get the current byte byte currentByteValue = (byte)currentCipherAsBytes.GetValue(currentByteIndex); // XOR this byte with the corresponding byte in each ciphertext (until we find a potential key) for (int i = currentCipherIndex + 1; i < CipherTexts.Count; i++) { byte[] cipherAsBytes = StringToByteArray(CipherTexts[i]); byte byteToXorAgainst; try { byteToXorAgainst = cipherAsBytes[currentByteIndex]; } catch { // No correspdonging byte at this location in this cipher (e.g. cipher could be shorter than the current one) continue; } // XOR int xor = currentByteValue ^ byteToXorAgainst; // Check if we got an uppercase ASCII character if (IsUpperCaseAscii(xor)) { Console.WriteLine("XOR of current check (" + xor + ") is an uppercase ASCII character, value is: " + Convert.ToChar(xor)); // This means that one of the plain text characters is a space and one is the lowercase ASCII equivalent of this character // We need to XOR each potential key with an ASCII space int potentialKey1 = currentByteValue ^ 32; int potentialKey2 = byteToXorAgainst ^ 32; // These are our pontetial keys Console.WriteLine("Potential Key 1 - " + potentialKey1); Console.WriteLine("Potential Key 2 - " + potentialKey2); // Check one of these keys is valid - if one isn't we'll assume the other is Console.WriteLine("Checking Potential Key - " + potentialKey1); if (CheckPotentialKey(potentialKey1, currentByteIndex)) { Console.WriteLine("Key is valid - " + potentialKey1); DecryptionKey key = new DecryptionKey(); key.Key = potentialKey1; key.Position = currentByteIndex; DecryptionKeys.Add(key); } else { Console.WriteLine("Key '" + potentialKey1 + "' not valid, assuming key '" + potentialKey2 + "' is valid"); DecryptionKey key = new DecryptionKey(); key.Key = potentialKey2; key.Position = currentByteIndex; DecryptionKeys.Add(key); } // Break out of checking further bytes at this position as we've found a valid key break; } } currentByteIndex++; } currentCipherIndex++; } // Decrypt the Ciphertexts Console.WriteLine("Now to decrypt the ciphertexts..."); for (int i = 0; i < CipherTexts.Count; i++) { string decryptedCipher = DecryptCipherText(CipherTexts[i]); Console.WriteLine("Decrypted Ciphertext at Position '" + i + "' - " + decryptedCipher); } }