/// <summary> /// Friedman test /// </summary> /// <param name="ciphertext"></param> /// <param name="language"></param> /// <param name="results"></param> /// <param name="maxKeyLength"></param> /// <returns></returns> public static int FriedmanTest(string ciphertext, string language, out Dictionary <int, List <double> > results, int maxKeyLength = 16) { results = new Dictionary <int, List <double> >(); double languageIdc = Vigenere.LETTER_FREQUENCY[language].IndexOfCoincidence; double average = 0; double probableKeyAverage = 0; int probableKeyLength = 0; for (int keyLength = 2; keyLength <= maxKeyLength; keyLength++) { average = 0; results[keyLength] = new List <double>(); for (int offset = 0; offset < keyLength; offset++) { double idc = Vigenere.IndexOfCoincidence(ciphertext, offset, keyLength); results[keyLength].Add(idc); average += idc; } average = average / keyLength; if (Math.Abs(languageIdc - average) < Math.Abs(languageIdc - probableKeyAverage)) { probableKeyLength = keyLength; probableKeyAverage = average; } } return(probableKeyLength); }
private void btnRunFriedman_Click(object sender, EventArgs e) { if (this.txtCiphertext.Text == string.Empty) { MessageBox.Show(this, "The ciphertext message must be defined!", "Error"); } else { string ciphertext = this.txtCiphertext.Text.Replace(" ", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty); StringBuilder sb = new StringBuilder(); Dictionary <int, List <double> > friedmanResults; int probableKeyLength = Vigenere.FriedmanTest(ciphertext, this.cbbLanguage.Text, out friedmanResults, (int)this.nudMaxKeyLength.Value); sb.Append("Key length : IC(x)\r\n"); foreach (KeyValuePair <int, List <double> > friedmanResult in friedmanResults) { sb.Append(friedmanResult.Key + " :"); foreach (double value in friedmanResult.Value) { sb.Append(" " + Math.Round(value, 3)); } sb.Append("\r\n"); } this.txtResultFriedman.Text = sb.ToString(); this.txtProbableKeyLength.Text = probableKeyLength.ToString(); this.nudAnalyseFrequencyKeyLength.Value = probableKeyLength; } }
/// <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)); }
private void btnAnalyseFrequency_Click(object sender, EventArgs e) { if (this.txtCiphertext.Text == string.Empty) { MessageBox.Show(this, "The ciphertext message must be defined!", "Error"); } else { string ciphertext = this.txtCiphertext.Text.Replace(" ", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty); this.txtAnalyseFrequenciesKey.Text = Vigenere.GuessKey(ciphertext, (int)this.nudAnalyseFrequencyKeyLength.Value, this.cbbLanguage.Text); this.txtKey.Text = this.txtAnalyseFrequenciesKey.Text; } }
/// <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))); }
private void btnDecrypt_Click(object sender, EventArgs e) { if (this.txtCiphertext.Text == string.Empty) { MessageBox.Show(this, "The ciphertext message must be defined!", "Error"); } else if (this.txtKey.Text == string.Empty) { MessageBox.Show(this, "The key must be defined!", "Error"); } else { this.txtCleartext.Text = Vigenere.Decrypt(this.txtCiphertext.Text, this.txtKey.Text); } }
/// <summary> /// Decrypt the ciphertext message /// </summary> /// <param name="ciphertext"></param> /// <param name="key"></param> /// <returns></returns> public static string Decrypt(string ciphertext, string key) { return(Vigenere.ProcessKey(ciphertext, key, -1)); }
/// <summary> /// Encrypt the cleartext message /// </summary> /// <param name="cleartext"></param> /// <param name="key"></param> /// <returns></returns> public static string Encrypt(string cleartext, string key) { return(Vigenere.ProcessKey(cleartext, key, 1)); }