using System; using System.Collections.Generic; using System.Linq; using System.Text; using ExtensionMethods; using System.Text.RegularExpressions; namespace CryptanalysisCore { public class Transposition : Cipher { private Random random = new Random(); public const int MaxKeyLength = 20; public const int MinKeyLength = 2; public const int TestKeyLengthAttack = 0; public override string Encrypt(string opentext, string key) { base.Encrypt(opentext, key); string[] columns = GetEncryptColumns(opentext, key); var orderedColumns = ColumnEncryptOrder(columns, key); var result = orderedColumns.Values.Implode(); return result; } public override string Decrypt(string ciphertext, string key) { base.Decrypt(ciphertext, key); var columns = GetDecryptColumns(ciphertext, key); var orderedColumns = ColumnDecryptOrder(columns, key); var result = GetOpentext(orderedColumns); return result; } /// /// Ze seřazených sloupců vrátí otevřený text /// /// /// private string GetOpentext(string[] orderedColumns) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < orderedColumns[0].Length; i++) { for (int j = 0; j < orderedColumns.Length; j++) { sb.Append(orderedColumns[j][i].ToString()); } } return sb.ToString(); } /// /// Vrátí sloupečky v zašifrovaném textu /// /// /// /// private string[] GetDecryptColumns(string ciphertext, string key) { return GetDecryptColumns(ciphertext, key.Length); } private string[] GetDecryptColumns(string ciphertext, int keyLength) { int columnsLength = (int)((double)ciphertext.Length / (double)keyLength); string[] columns = new string[keyLength]; for (int i = 0; i < keyLength; i++) { columns[i] = ciphertext.Substring(i * columnsLength, columnsLength); } return columns; } /// /// Vrátí pořadí sloupců při dešifrování /// /// /// /// private string[] ColumnDecryptOrder(string[] columns, string key) { Dictionary indexesColumns = new Dictionary(); for (int i = 0; i < key.Length; i++) { indexesColumns[GetColumnKey(indexesColumns.Keys.ToArray(), key[i])] = i; } indexesColumns = indexesColumns.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); string[] orderColumns = new string[key.Length]; int counter = 0; foreach (var pair in indexesColumns) { orderColumns[pair.Value] = columns[counter++]; } return orderColumns; } /// /// Vrátí pořadí sloupců při šifrování /// /// /// /// private Dictionary ColumnEncryptOrder(string[] columns, string key) { Dictionary indexesColumns = new Dictionary(); for (int i = 0; i < key.Length; i++) { indexesColumns[GetColumnKey(indexesColumns.Keys.ToArray(), key[i])] = columns[i]; } var result = indexesColumns.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); return result; } /// /// Najde první možný validní klíč sloepce. Pokud existuje "x" a "xx", vrátí "xxx" apod. /// /// /// /// private string GetColumnKey(string[] indexesColumns, char currKey) { string modifKey = currKey.ToString(); while (indexesColumns.Contains(modifKey)) modifKey += currKey.ToString(); return modifKey; } /// /// Vrátí sloupečky v textu podle délky klíče při šifrování /// /// /// /// private string[] GetEncryptColumns(string opentext, string key) { return GetEncryptColumns(opentext, key.Length); } private string[] GetEncryptColumns(string opentext, int keyLength) { int columnLength = (int)Math.Ceiling((double)opentext.Length / (double)keyLength); string[] columns = new string[keyLength]; for (int i = 0; i < keyLength; i++) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < columnLength; j++) { int index = j * keyLength + i; if (index < opentext.Length) sb.Append(opentext[index]); else sb.Append(Text.RandomString(1)); } columns[i] = sb.ToString(); } return columns; } protected override bool IsKeyValid(string key) { return key.Length >= MinKeyLength && Regex.IsMatch(key, @"^[a-z\?]+$"); } protected override void SetCrackMethods() { CrackMethods = new CrackMethod[] { TestKeyLength }; } /*********** test key length attack *******************/ private List TestKeyLength(string ciphertext, Storage.Languages language) { int averageKeyLength = 10; int minSentenceLength = 40; var keyLengths = Maths.AllDivisors(ciphertext.Length); var orderKeyLengths = keyLengths.OrderBy(x => Math.Abs(x - averageKeyLength)).ToArray(); foreach (int keyLength in orderKeyLengths) { string[] columns = GetDecryptColumns(ciphertext, keyLength); string sentence = GetOpentext(columns).Take(minSentenceLength); var lang = Storage.GetLangChar(language); DictionaryAttack attack = new DictionaryAttack(lang.Dictionary, lang.SortedDictionary); attack.Start(sentence, keyLength); } return new List() { "abc" }; } private string[] GetColumns(string ciphertext, int keyLength) { return null; } /********************** konec ************************/ public override string RandomKey() { int length = random.Next(2, MaxKeyLength); return Text.RandomString(length); } } }