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)); } }
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); } }