/// <summary>
        /// Returns the best key using the caesar cipher
        /// </summary>
        /// <param name="str">Ciphertext.</param>
        /// <returns></returns>
        public static Dictionary <char, char> CheckCaesar(String str)
        {
            Quadgram_Analysis analysis = new Quadgram_Analysis();

            Dictionary <char, char> key = null;

            double bestFitness = -99999;

            String alphabet = "abcdefghijklmnopqrstuvwxyz";

            for (int amt = 1; amt < 26; amt++)
            {
                //shift each character of the string "amt" number of letters
                String shiftedString = Shift(str, amt);

                //test the fitness of this shifted string
                double curFitness = analysis.TestKeyFitness(GetQuadgrams(shiftedString));

                if (curFitness > bestFitness)
                {
                    //builds a key from this shift if it's the best we've seen
                    key = new Dictionary <char, char>();

                    //we know the key for the shift, so we're going to go trhough the alphabet and
                    //shift each character the correct amount to build a key
                    for (int i = 0; i < 26; i++)
                    {
                        //a bit of a hack, but to utilize the shift() method on characters,
                        //converts the char to a string, and converts it back to a char array
                        //since it's only a character, we know the answer is in index 0
                        char[] shiftedChar = Shift(alphabet[i].ToString(), amt).ToCharArray();

                        key.Add(alphabet[i], shiftedChar[0]);
                    }
                    bestFitness = curFitness;
                }
            }
            return(key);
        }
示例#2
0
        public static String  Decipher(String encStr)
        {
            Quadgram_Analysis analysis = new Quadgram_Analysis();

            Dictionary <char, char> parentKey = GenerateRandomKey();

            HashSet <String> testedKeys = new HashSet <String>();

            testedKeys.Add(ReadKey(parentKey));

            double fitness = analysis.TestKeyFitness(GetQuadgrams(DecipherMessageUsingKey(parentKey, encStr)));

            String message = encStr.ToString();

            double highest    = -999999;
            double absHighest = -99999;
            int    tries      = 0;
            int    abs        = 0;

            String thisMessage = null;
            String retMessage  = null;

            while (abs < 15)
            {
                thisMessage = null;

                for (int i = 0; i < 1000; i++)
                {
                    Dictionary <char, char> childKey = new Dictionary <char, char>(parentKey);

                    do
                    {
                        SwapTwoLetters(childKey);
                    } while (testedKeys.Contains(ReadKey(childKey)));



                    String currentMessage = DecipherMessageUsingKey(childKey, message);


                    double newFitness = 0;


                    newFitness = analysis.TestKeyFitness(GetQuadgrams(currentMessage));


                    if (newFitness > fitness)
                    {
                        fitness     = newFitness;
                        parentKey   = new Dictionary <char, char>(childKey);
                        thisMessage = currentMessage;
                    }

                    testedKeys.Add(ReadKey(childKey));
                }
                //Console.WriteLine(fitness);
                if (fitness > highest)
                {
                    tries      = 0;
                    highest    = fitness;
                    retMessage = thisMessage;
                    Console.WriteLine(thisMessage + " " + fitness);
                    if (fitness > absHighest)
                    {
                        absHighest = fitness;
                        abs++;
                        Console.WriteLine(abs);
                    }
                }
                else if (fitness == highest || fitness < highest)
                {
                    tries++;
                    //Console.WriteLine(++tries);
                    do
                    {
                        parentKey = GenerateRandomKey();
                    } while (testedKeys.Contains(ReadKey(parentKey)));


                    fitness = analysis.TestKeyFitness(GetQuadgrams(DecipherMessageUsingKey(parentKey, encStr)));

                    //stuck at local max
                    if (tries > 100)
                    {
                        Console.WriteLine("hit local max");
                        highest = -99999;
                    }
                }

                //tries++;
            }

            return(retMessage);
        }
        /// <summary>
        /// Deciphers ciphertext using a hill climbing algorithm.
        ///
        /// Algorithm orginally explained at
        /// http://practicalcryptography.com/cryptanalysis/stochastic-searching/cryptanalysis-simple-substitution-cipher/
        ///
        /// Has a difference that rather than randomly switching letters, it switches letters iteratively.
        /// Read somewhere that was slightly better, also gives a clearer point where to stop.
        /// </summary>
        /// <param name="encStr"></param>
        /// <returns>Returns a char-char dictionary giving the algorithm's
        /// best guess for the key. Each key relates to it's corresponding
        /// ciphertext character. </returns>
        public static Dictionary <char, char> Decipher(String encStr)
        {
            HashSet <String> testedKeys = new HashSet <string>();

            Quadgram_Analysis       analysis = new Quadgram_Analysis();
            Dictionary <char, char> retKey   = null;

            //we're going to get the best ceasar key and fitness for future use
            Dictionary <char, char> caesarKey = CheckCaesar(encStr);
            double caesarFitness = analysis.TestKeyFitness(GetQuadgrams(DecipherMessageUsingKey(caesarKey, encStr)));

            //best fitness we've encountered
            double bestFitness = -99999;

            //number of times we've encountered the best fitness
            int bestFitnesses = 0;

            for (int k = 0; k < 1000; k++)
            {
                //generate a random key and check its fitness
                Dictionary <char, char> key = GenerateRandomKey();

                double fitness = analysis.TestKeyFitness(GetQuadgrams(DecipherMessageUsingKey(key, encStr)));

                //determines if we've found a better key for this key
                bool betterKeyFound;

                do
                {
                    betterKeyFound = false;

                    /*
                     * We're going to loop through the key and test all possible "shuffles" of this key,
                     * in which we switch each letter with every other letter and see what the fitness is.
                     * If the fitness is better, then we will go with that key and continue switching letters.
                     */
                    for (int i = 0; i < 25; i++)
                    {
                        for (int j = 1; j < 26; j++)
                        {
                            //switch letters
                            KeyValuePair <char, char> temp  = key.ElementAt(i);
                            KeyValuePair <char, char> temp1 = key.ElementAt(j);
                            key[temp.Key]  = temp1.Value;
                            key[temp1.Key] = temp.Value;

                            //get the fitness of this new message
                            double newFitness = analysis.TestKeyFitness(GetQuadgrams(DecipherMessageUsingKey(key, encStr)));


                            if (newFitness > fitness)
                            {
                                betterKeyFound = true;
                                fitness        = newFitness;

                                if (fitness > bestFitness)
                                {
                                    bestFitness   = fitness;
                                    bestFitnesses = 1;
                                    retKey        = key;
                                }
                                else if (fitness == bestFitness)
                                {
                                    /*if we've hit the same best fitness 3 times and it's
                                     * better than any caesar fitness we've seen, we'll assume that's
                                     * probably the best guess, and we'll end the algorithm.
                                     */
                                    if (++bestFitnesses == 3 && bestFitness > caesarFitness)
                                    {
                                        return(key);
                                    }
                                }
                            }
                            else
                            {
                                /*
                                 * Otherwise, we did not get a better key with this switch, so let's
                                 * revert the changes back.
                                 */
                                key[temp.Key]  = temp.Value;
                                key[temp1.Key] = temp1.Value;
                            }
                        }
                    }

                    /*
                     * If it ISN'T a caesar cipher, the caesar fitness should be terrible
                     * and we should've found a better fitness through this algorithm
                     * by now. Thus, if we've tried 650 keys and NONE of them are better than
                     * the caesar cipher....it's probably a caesar cipher.
                     */
                    if ((bestFitness < caesarFitness))
                    {
                        return(caesarKey);
                    }
                } while (betterKeyFound);
            }

            return(retKey);
        }