using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using ExtensionMethods; namespace CryptanalysisCore { public class Caesar : Cipher { public const int BruteForceID = 0; public const int TriangleID = 1; public Caesar() : base() { //ExceptionText = "Klíčem musí být právě jedno malé písmeno anglické abecedy."; CipherType = Storage.Ciphers.caesar; } protected override void SetCrackMethods() { CrackMethods = new CrackMethod[] { BruteForceAttack, TriangleAttack }; } /// /// Metoda zašifruje předaný text pomocí Caesarovy šifry. Každé písmeno v řetězci /// bude posunuto o tolik znaků, kolik udává parametr 'Klíč'. /// /// Řetězec, který má být zašifrován. /// Znak anglické abecedy, který bude hrát úlohu klíče. /// Zašifrovaný řetězec. public override string Encrypt(string opentext, string key) { base.Encrypt(opentext, key); char[] ciphertext = new char[opentext.Length]; for (int i = 0; i < ciphertext.Length; i++) { if (opentext[i] == ' ') ciphertext[i] = ' '; else ciphertext[i] = Analyse.MoveCharacter(opentext[i], key[0]); } return new string(ciphertext).ToUpper(); } /*public override List Crack(string ciphertext, int attackType, Storage.Languages language) { return CrackMethods[attackType](ciphertext, language); }*/ /// /// Dešifruje zašifrovaný text podle předaného klíče. /// /// Text, který má být dešifrován. /// Klíč, podle kterého má probíhat dešifrování. /// Dešifrovaný text. public override string Decrypt(string ciphertext, string key) { base.Decrypt(ciphertext, key); // Transformujeme klic tak, abychom mohli pouzit standardni // funkci na Caesarovu sifru int movedKey = (int)'z' - (int)key[0] + (int)'a' + 1; if (movedKey > 'z') movedKey -= Analyse.AlphabetLetterCount; char decryptKey = (char)movedKey; string cipherTextLower = ciphertext.ToLower(); char[] opentext = new char[ciphertext.Length]; for (int i = 0; i < opentext.Length; i++) { if (cipherTextLower[i] == ' ') opentext[i] = ' '; else opentext[i] = Analyse.MoveCharacter(cipherTextLower[i], decryptKey); } return new string(opentext).ToLower(); } /// /// Ze dvou zadaných znaků vypočítá klíč, kterým byly tyto znaky zašifrovány. /// /// Znak z otevřeného textu /// Znak ze zašifrovaného textu /// Klíč private char GetKeyFromLetters(char cipherLetter, char openLetter) { int c = (int)cipherLetter - (int)'a'; int d = (int)openLetter - (int)'a'; int temp = (cipherLetter - openLetter + Analyse.AlphabetLetterCount); return ((char)((temp % Analyse.AlphabetLetterCount) + 'a')); } private char[] GetPolygonKeys(char[] topTextLetters, char[] topLetters, int complementSize) { return TextAnalysis.PolygonAttack(topTextLetters, topLetters, complementSize) .Select(x => GetKeyFromLetters(x[0], topLetters[0])).ToArray(); } /// /// Provede trojúhelníkový útok na šifru /// /// /// public List TriangleAttack(string ciphertext, Storage.Languages language) { bool modern = true; if (modern) { ciphertext = Analyse.NormalizeText(ciphertext, Analyse.TextTypes.WithoutSpacesLower); int polygonSize = 3; int complementSize = 10; var topLetters = Storage.GetLangChar(language).Letters.OrderByDescending(x => x.Value).Take(polygonSize).Select(x => x.Key[0]).ToArray(); var bottomLetters = Storage.GetLangChar(language).Letters.OrderBy(x => x.Value).Take(polygonSize).Select(x => x.Key[0]).ToArray(); var letters = TextAnalysis.GetOccurrence(ciphertext, 1); var topTextLetters = letters.OrderByDescending(x => x.Value).Take(complementSize).Select(x => x.Key[0]).ToArray(); var bottomTextLetters = letters.OrderBy(x => x.Value).Take(complementSize).Select(x => x.Key[0]).ToArray(); var keysTop = GetPolygonKeys(topTextLetters, topLetters, complementSize); var keysBottom = GetPolygonKeys(bottomTextLetters, bottomLetters, complementSize); if (keysTop.Length == 0) throw new Exceptions.MatchNotFound(); var interKeys = keysBottom.Intersect(keysTop).ToList(); if (interKeys.Count > 0) { return interKeys.Select(x => x.ToString()).ToList(); } else { var unionKeys = keysBottom.Union(keysTop).Select(x => x.ToString()).ToList(); if (unionKeys.Count > 0) { return unionKeys; } else { throw new Exceptions.MatchNotFound(); } } } else { char[] keysTop = GetTriangle(ciphertext, true, language); char[] keysLess = GetTriangle(ciphertext, false, language); char[] universalKeys = keysLess.Intersect(keysTop).ToArray(); string key; if (universalKeys.Length == 1) { key = universalKeys[0].ToString(); return new List() { key }; } else { char[] unionsKeys = keysLess.Union(keysTop).ToArray(); if (unionsKeys.Length != 0) { key = unionsKeys[0].ToString(); return new List() { key }; } } throw new Exceptions.MatchNotFound(); } } /// /// Vrátí pole klíčů, které jsou možnými klíči dané šifry /// /// Informace o šifrovém textu /// Pole klíčů private char[] GetTriangle(string ciphertext, bool orderByDescending, Storage.Languages language) { char[] topCiphertextLetters; char[] topLanguagesLetters; int max = 9; if (orderByDescending) { topCiphertextLetters = Analyse.CharsRelativeOccurrence(ciphertext.ToLower()).OrderByDescending(x => x.Value).Take(max).Select(x => x.Key.ToString().ToLower()[0]).ToArray(); topLanguagesLetters = Storage.GetLangChar(language).Letters.Where(x => x.Key != " ").OrderByDescending(x => x.Value).Take(3).Select(x => x.Key.ToLower()[0]).ToArray(); } else { topCiphertextLetters = Analyse.CharsRelativeOccurrence(ciphertext.ToLower()).OrderBy(x => x.Value).Take(max).Select(x => x.Key.ToString().ToLower()[0]).ToArray(); topLanguagesLetters = Storage.GetLangChar(language).Letters.Where(x => x.Key != " ").OrderBy(x => x.Value).Take(3).Select(x => x.Key.ToLower()[0]).ToArray(); } List triples = FindEquivalentTriple(topLanguagesLetters, topCiphertextLetters); if (triples.Count == 0) throw new Exceptions.MatchNotFound(); return GetKeysFromTriples(topLanguagesLetters[0], triples); } /// /// Vrátí seznam klíčů, kterým byl zašifrován předaný text /// /// Nejčastější písmeno v daném jazyce /// Seznam trojic /// Pole klíčů private char[] GetKeysFromTriples(char topLetter, List triples) { List keys = new List(); triples.ForEach(triple => keys.Add(GetKeyFromLetters(triple[0], topLetter))); return keys.ToArray(); } /// /// Zjistí všechny trojice písmen v zašifrovaném textu, které mají stejné vzdálenosti /// jako nejčastější písmena v běžném textu. /// /// /// /// Seznam odpovídajících trojic písmen. private List FindEquivalentTriple(char[] topLanguagesLetters, char[] topCiphertextLetters) { int[] distances = GetDistances(topLanguagesLetters); List equivalentTriples = new List(); for (int i = 0; i < topCiphertextLetters.Length; i++) { for (int j = 0; j < topCiphertextLetters.Length; j++) { if (Analyse.MinDistance(topCiphertextLetters[i], topCiphertextLetters[j]) == distances[0]) { for (int k = 0; k < topCiphertextLetters.Length; k++) { if (k != i && k != j) { if (Analyse.MinDistance(topCiphertextLetters[j], topCiphertextLetters[k]) == distances[1] && Analyse.MinDistance(topCiphertextLetters[i], topCiphertextLetters[k]) == distances[2]) { equivalentTriples.Add(new char[] { topCiphertextLetters[i], topCiphertextLetters[j], topCiphertextLetters[k] }); } } } } } } return equivalentTriples; } /// /// Vrací pole reprezentující vzdálenosti v předaných písmenech /// /// pole písmen, ve kterých budeme hledat vzdálenosti /// Pole vzdáleností. private int[] GetDistances(char[] topLanguagesLetters) { int[] distances = new int[3]; Cycles.From0ToI(3, i => distances[i] = Analyse.MinDistance(topLanguagesLetters[i], topLanguagesLetters[(i + 1) % 3])); return distances; } /// /// Provede útok testováním všech dostupných klíčů /// a následně vybere nejpravděpodobnější variantu. /// /// /// public List BruteForceAttack(string ciphertext, Storage.Languages language) { Dictionary probability = new Dictionary(); Caesar caesar = new Caesar(); string opentext; Analyse.DoAlphabet(letter => { opentext = caesar.Decrypt(ciphertext, letter.ToString()); probability[letter] = Analyse.SimilarityIndex(Analyse.NormalizeText(opentext, Analyse.TextTypes.WithoutSpacesLower), Storage.GetLangChar(language)); }); var resultPacket = probability.OrderBy(x => x.Value).ToArray()[0].Key; return new List() { resultPacket.ToString() }; } /// /// Zjistí, zda je předaný klíč platný klíč Caesarovy šifry /// /// Šifrovací klíč /// True v případě, že je klíč platný, false jinak public override bool IsKeyValid(string key) { return Regex.IsMatch(key, @"^[a-zA-Z]$"); } /// /// Vygeneruje náhodný klíč pro Caesarovu šifru /// Nevygeneruje špatný klíč 'a'. /// /// Náhodný klíč. public override string RandomKey() { Random Rand = new Random(); return ((char)((int)'b' + Rand.Next(24))).ToString(); } } }