private static void CombinationCount(ReadablePassphraseGenerator generator)
        {
            Console.WriteLine();
            Console.WriteLine("Combination count:");

            foreach (var strength in RandomStrengths)
            {
                var combinations = generator.CalculateCombinations(strength);
                Console.WriteLine("  {0}: {1:E3} ({2:N2} bits)", strength, combinations.ToString(), combinations.EntropyBitsToString());
            }
            Console.WriteLine();

            var predefined = new PhraseStrength[]
            {
                PhraseStrength.Normal, PhraseStrength.NormalAnd, PhraseStrength.NormalSpeech, PhraseStrength.NormalEqual, PhraseStrength.NormalEqualAnd, PhraseStrength.NormalEqualSpeech, PhraseStrength.NormalRequired, PhraseStrength.NormalRequiredAnd, PhraseStrength.NormalRequiredSpeech,
                PhraseStrength.Strong, PhraseStrength.StrongAnd, PhraseStrength.StrongSpeech, PhraseStrength.StrongEqual, PhraseStrength.StrongEqualAnd, PhraseStrength.StrongEqualSpeech, PhraseStrength.StrongRequired, PhraseStrength.StrongRequiredAnd, PhraseStrength.StrongRequiredSpeech,
                PhraseStrength.Insane, PhraseStrength.InsaneAnd, PhraseStrength.InsaneSpeech, PhraseStrength.InsaneEqual, PhraseStrength.InsaneEqualAnd, PhraseStrength.InsaneEqualSpeech, PhraseStrength.InsaneRequired, PhraseStrength.InsaneRequiredAnd, PhraseStrength.InsaneRequiredSpeech,
            };

            for (int i = 0; i < predefined.Length; i++)
            {
                var strength     = predefined[i];
                var combinations = generator.CalculateCombinations(strength);
                Console.WriteLine("  {0}: {1:E3} ({2:N2} bits)", strength, combinations.ToString(), combinations.EntropyBitsToString());
                if ((i + 1) % 9 == 0)
                {
                    Console.WriteLine();
                }
            }
        }
        private static void GenerateCustomSamples(IEnumerable <MurrayGrant.ReadablePassphrase.PhraseDescription.Clause> clause, ReadablePassphraseGenerator generator, int count)
        {
            Console.WriteLine();
            Console.WriteLine("Custom samples:");
            var combinations = generator.CalculateCombinations(clause);

            Console.WriteLine("Combinations: {0:E3} ({1:N2} bits)", combinations.ToString(), combinations.EntropyBitsToString());
            for (int i = 0; i < count; i++)
            {
                Console.WriteLine(generator.Generate(clause));
            }
        }
Beispiel #3
0
        static void RunMain()
        {
            // Generate and print phrases.
            if (!quiet)
            {
                var ver = GetProgramVersion();
                var idx = ver.IndexOf('.', ver.IndexOf('.', ver.IndexOf('.') + 1) + 1);
                Console.WriteLine("Readable Passphrase Generator {0}", ver.Substring(0, idx));
            }
            if (!quiet && anyLength > 0)
            {
                Console.WriteLine("Generating {0:N0} non-grammatic phrase(s) of length '{1}'...", count, anyLength);
            }
            else if (!quiet && String.IsNullOrEmpty(customPhrasePath))
            {
                Console.WriteLine("Generating {0:N0} phrase(s) of strength '{1}'...", count, strength);
            }
            else if (!quiet && !String.IsNullOrEmpty(customPhrasePath))
            {
                Console.WriteLine("Generating {0:N0} phrase(s) based on phrase description in '{1}'...", count, System.IO.Path.GetFileName(customPhrasePath));
            }
            if (!quiet && (maxLength < Int32.MaxValue || minLength > 1))
            {
                Console.WriteLine("Must be between {0:N0} and {1} characters.", minLength, maxLength == Int32.MaxValue ? "∞" : maxLength.ToString("N0"));
            }

            var generator = new ReadablePassphraseGenerator();

            // Must load dictionary before trying to generate.
            var dictSw  = System.Diagnostics.Stopwatch.StartNew();
            var loaderT = GetDictionaryLoaderType();

            // If the internal dictionary loader is being used and no other arguments are specified, tell it to use the default dictionary.
            if (loaderT == typeof(ExplicitXmlDictionaryLoader) && String.IsNullOrEmpty(loaderArguments.Trim()))
            {
                loaderArguments = "useDefaultDictionary=true";
            }

            // And load our dictionary!
            using (var loader = Activator.CreateInstance(loaderT) as IDictionaryLoader)
            {
                if (loader == null)
                {
                    throw new Exception($"Unable to create instance of dictionary loader {loaderT.FullName}");
                }
                generator.LoadDictionary(loader, loaderArguments);
            }
            dictSw.Stop();

            // Summarise actions and combinations / entropy.
            if (!quiet)
            {
                Console.WriteLine("Dictionary contains {0:N0} words (loaded in {1:N2}ms)", generator.Dictionary.Count, dictSw.Elapsed.TotalMilliseconds);
                PhraseCombinations combinations;
                if (anyLength > 0)
                {
                    combinations = generator.CalculateCombinations(NonGrammaticalClause(anyLength));
                }
                else if (strength != PhraseStrength.Custom)
                {
                    combinations = generator.CalculateCombinations(strength);
                }
                else
                {
                    combinations = generator.CalculateCombinations(phraseDescription);
                }
                Console.WriteLine("Average combinations ~{0:E3} (~{1:N2} bits)", combinations.OptionalAverage, combinations.OptionalAverageAsEntropyBits);
                Console.WriteLine("Total combinations {0:E3} - {1:E3} ({2:N2} - {3:N2} bits)", combinations.Shortest, combinations.Longest, combinations.ShortestAsEntropyBits, combinations.LongestAsEntropyBits);

                var upperTypeText = upperStyle == AllUppercaseStyles.RunOfLetters ? " run"
                                  : upperStyle == AllUppercaseStyles.WholeWord ? " word"
                                  : "";
                var upperTypeText2 = upperStyle == AllUppercaseStyles.RunOfLetters ? "run"
                                   : upperStyle == AllUppercaseStyles.WholeWord ? "word"
                                   : "capital";
                if (applyStandardMutators)
                {
                    Console.WriteLine("Using standard mutators (2 numbers, 2 capitals, period at end)");
                }
                else if (applyAlternativeMutators)
                {
                    Console.WriteLine("Using alternate mutators (2 numbers, 1 whole capital word, period at end)");
                }
                else if (numericStyle != 0 && upperStyle != 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText}, numeric and constant mutators ({upperCount:N0} {upperTypeText2}(s), {numericCount:N0} number(s))");
                }
                else if (numericStyle != 0 && upperStyle != 0 && constantStyle == 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText} and numeric mutators ({upperCount:N0} {upperTypeText2}(s), {numericCount:N0} number(s))");
                }
                else if (numericStyle == 0 && upperStyle != 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText} and constant mutators ({upperCount:N0} {upperTypeText2}(s))");
                }
                else if (numericStyle == 0 && upperStyle != 0 && constantStyle == 0)
                {
                    Console.WriteLine($"Using upper case{upperTypeText} mutator only ({upperCount:N0} {upperTypeText2}(s))");
                }
                else if (numericStyle != 0 && upperStyle == 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using numeric and constant mutators ({numericCount:N0} number(s))");
                }
                else if (numericStyle != 0 && upperStyle == 0 && constantStyle == 0)
                {
                    Console.WriteLine($"Using numeric mutator only ({numericCount:N0} number(s))");
                }
                else if (numericStyle == 0 && upperStyle == 0 && constantStyle != 0)
                {
                    Console.WriteLine($"Using constant mutator only");
                }
                else
                {
                    Console.WriteLine("Using no mutators");
                }
                Console.WriteLine();
            }

            // Generate!
            var genSw       = System.Diagnostics.Stopwatch.StartNew();
            int generated   = 0;
            int attempts    = 0;
            int maxAttempts = count * MaxAttemptsPerCount;
            var mutators    = applyStandardMutators ? new IMutator[] { UppercaseMutator.Basic, NumericMutator.Basic, ConstantMutator.Basic }
                         : applyAlternativeMutators ? new IMutator[] { UppercaseWordMutator.Basic, NumericMutator.Basic, ConstantMutator.Basic }
                         : Enumerable.Empty <IMutator>();

            if (upperStyle > 0 && upperStyle <= AllUppercaseStyles.Anywhere)
            {
                mutators = mutators.Concat(new IMutator[] { new UppercaseMutator()
                                                            {
                                                                When = (UppercaseStyles)upperStyle, NumberOfCharactersToCapitalise = upperCount
                                                            } });
            }
            if (upperStyle == AllUppercaseStyles.RunOfLetters)
            {
                mutators = mutators.Concat(new IMutator[] { new UppercaseRunMutator()
                                                            {
                                                                NumberOfRuns = upperCount
                                                            } });
            }
            if (upperStyle == AllUppercaseStyles.WholeWord)
            {
                mutators = mutators.Concat(new IMutator[] { new UppercaseWordMutator()
                                                            {
                                                                NumberOfWordsToCapitalise = upperCount
                                                            } });
            }
            if (numericStyle != 0)
            {
                mutators = mutators.Concat(new IMutator[] { new NumericMutator()
                                                            {
                                                                When = numericStyle, NumberOfNumbersToAdd = numericCount
                                                            } });
            }
            if (constantStyle != 0)
            {
                mutators = mutators.Concat(new IMutator[] { new ConstantMutator()
                                                            {
                                                                When = constantStyle, ValueToAdd = constantValue
                                                            } });
            }
            while (generated < count)
            {
                // Generate phrase.
                // We always include spaces in the phrase because the mutators rely on whitespace.
                string phrase;
                attempts++;
                if (anyLength > 0)
                {
                    phrase = generator.Generate(NonGrammaticalClause(anyLength), " ", mutators);
                }
                else if (strength == PhraseStrength.Custom)
                {
                    phrase = generator.Generate(phraseDescription, " ", mutators);
                }
                else
                {
                    phrase = generator.Generate(strength, " ", mutators);
                }

                // After mutators are applied, it's safe to remove white space.
                if (wordSeparator != " ")
                {
                    phrase = phrase.Replace(" ", wordSeparator);
                }

                // Clamp the length.
                if (phrase.Length >= minLength && phrase.Length <= maxLength)
                {
                    Console.WriteLine(phrase);
                    generated++;
                }
                if (attempts >= maxAttempts)
                {
                    break;
                }
            }
            genSw.Stop();

            // Summarise result.
            if (!quiet)
            {
                Console.WriteLine();
                Console.WriteLine("Generated {0:N0} phrase(s) in {1:N2}ms.", generated, genSw.Elapsed.TotalMilliseconds);
                if (attempts >= maxAttempts)
                {
                    Console.WriteLine("But unable to generate requested {0:N0} phrase(s) after {1:N0} attempts." + Environment.NewLine + "Perhaps try changing the minimum or maximum phrase length.", count, attempts);
                }
            }
        }
        private static void WriteStatisticsFor(ReadablePassphraseGenerator generator, PhraseStrength strength, int count, string filename)
        {
            Console.Write("Writing statistics to '{0}'...", filename);

            var wordHistogram           = new Dictionary <int, int>();
            var charHistogram           = new Dictionary <int, int>();
            var keepassQualityHistogram = new Dictionary <uint, int>();
            var combinations            = generator.CalculateCombinations(strength);

            for (int i = 0; i < count; i++)
            {
                var phrase = generator.Generate(strength);

                if (!charHistogram.ContainsKey(phrase.Length))
                {
                    charHistogram.Add(phrase.Length, 0);
                }
                charHistogram[phrase.Length] = charHistogram[phrase.Length] + 1;

                var wordCount = phrase.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).Length;
                if (!wordHistogram.ContainsKey(wordCount))
                {
                    wordHistogram.Add(wordCount, 0);
                }
                wordHistogram[wordCount] = wordHistogram[wordCount] + 1;

                var keePassQualityEst = KeePassLib.Cryptography.QualityEstimation.EstimatePasswordBits(phrase.ToCharArray());
                if (!keepassQualityHistogram.ContainsKey(keePassQualityEst))
                {
                    keepassQualityHistogram.Add(keePassQualityEst, 0);
                }
                keepassQualityHistogram[keePassQualityEst] = keepassQualityHistogram[keePassQualityEst] + 1;
            }

            using (var writer = new System.IO.StreamWriter(filename, false, Encoding.UTF8))
            {
                writer.WriteLine("Word histogram");
                for (int i = wordHistogram.Keys.Min(); i < wordHistogram.Keys.Max() + 1; i++)
                {
                    writer.WriteLine("{0},{1}", i, wordHistogram.ContainsKey(i) ? wordHistogram[i] : 0);
                }
                writer.WriteLine();

                writer.WriteLine("Character histogram");
                for (int i = charHistogram.Keys.Min(); i < charHistogram.Keys.Max() + 1; i++)
                {
                    writer.WriteLine("{0},{1}", i, charHistogram.ContainsKey(i) ? charHistogram[i] : 0);
                }
                writer.WriteLine();

                writer.WriteLine("KeePass Quality Estimate");
                for (uint i = keepassQualityHistogram.Keys.Min(); i < keepassQualityHistogram.Keys.Max() + 1; i++)
                {
                    writer.WriteLine("{0},{1}", i, keepassQualityHistogram.ContainsKey(i) ? keepassQualityHistogram[i] : 0);
                }
                writer.WriteLine();

                writer.WriteLine("Combination counts");
                writer.WriteLine("Min:,{0:E3},{1:N2}", combinations.Shortest, combinations.ShortestAsEntropyBits);
                writer.WriteLine("Max:,{0:E3},{1:N2}", combinations.Longest, combinations.LongestAsEntropyBits);
                writer.WriteLine("Avg:,{0:E3},{1:N2}", combinations.OptionalAverage, combinations.OptionalAverageAsEntropyBits);

                writer.WriteLine();
                writer.WriteLine("Samples:");
                for (int i = 0; i < 20; i++)
                {
                    writer.WriteLine(generator.Generate(strength));
                }
            }

            Console.WriteLine(" Done.");

            bool isFirst = !System.IO.File.Exists(AllStatsCharFilename);

            using (var writer = new System.IO.StreamWriter(AllStatsCharFilename, true, Encoding.UTF8))
            {
                if (isFirst)
                {
                    writer.WriteLine("Strength,Min,Max,Avg,Median,Samples");
                }
                writer.WriteLine("{0},{1},{2},{3},{4},{5}", strength.ToString(), charHistogram.Keys.Min(), charHistogram.Keys.Max(), GetAvg(charHistogram), GetMedian(charHistogram), count);
            }
        }