/// <summary> /// Guess key /// </summary> /// <param name="ciphertext"></param> /// <param name="keyLength"></param> /// <returns></returns> public static string GuessKey(string ciphertext, int keyLength, string language) { char[] key = new char[keyLength]; int numberLetters = Vigenere.LETTER_FREQUENCY[language].NumberOfLetters; // METHOD 1 : Using language frequency for mutual indices of coincidence for all cipher vectors for (int offset = 0; offset < keyLength; offset++) { double[] indices = new double[numberLetters]; double[] frequencies = Vigenere.Frenquencies(ciphertext, offset, keyLength).Select(Convert.ToDouble).ToArray(); indices = Vigenere.MutualIndicesOfCoincidence(Vigenere.LETTER_FREQUENCY[language].LetterFrequencies, 1, frequencies, frequencies.Sum()); int bestShift = 0; for (int shift = 1; shift < numberLetters; shift++) { if (indices[shift] > indices[bestShift]) { bestShift = shift; } } key[offset] = (char)(bestShift + 65); } // METHOD 2 : Using reference vector for mutual indices of coincidence for all other cipher vectors /*double[] frequenciesLang = Vigenere.LETTER_FREQUENCY[language].LetterFrequencies; * double[] frequenciesRef = Vigenere.Frenquencies(ciphertext, 0, keyLength).Select(Convert.ToDouble).ToArray(); * double lengthRef = frequenciesRef.Sum(); * * double[] indices = new double[numberLetters]; * indices = Vigenere.MutualIndicesOfCoincidence(frequenciesLang, 1, frequenciesRef, lengthRef); * * int shiftRef = 0; * for (int i = 1; i < numberLetters; i++) * if (indices[i] > indices[shiftRef]) * shiftRef = i; * * key[0] = (char)(shiftRef + 65); * * for (int offset = 1; offset < keyLength; offset++) * { * double[] frequenciesCmp = Vigenere.Frenquencies(ciphertext, offset, keyLength).Select(Convert.ToDouble).ToArray(); * double lengthCmp = frequenciesRef.Sum(); * * indices = Vigenere.MutualIndicesOfCoincidence(frequenciesRef, lengthRef, frequenciesCmp, lengthCmp); * * int bestShift = 0; * for (int i = 1; i < numberLetters; i++) * if (indices[i] > indices[bestShift]) * bestShift = i; * * key[offset] = (char)((bestShift + shiftRef) % numberLetters + 65); * }*/ return(new string(key)); }
/// <summary> /// Calculate index of coincidence /// </summary> /// <param name="ciphertext"></param> /// <param name="offset"></param> /// <param name="keyLength"></param> /// <returns></returns> private static double IndexOfCoincidence(string ciphertext, int offset, int keyLength, int numberLetters = 26) { double index = 0; int length = 0; int[] frequences = Vigenere.Frenquencies(ciphertext, offset, keyLength); for (int k = 0; k < numberLetters; k++) { index += frequences[k] * (frequences[k] - 1); length += frequences[k]; } return(index / (length * (length - 1))); }