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 GenerateSamples(PhraseStrength strength, ReadablePassphraseGenerator generator, int count) { Console.WriteLine(); Console.WriteLine("Samples:"); for (int i = 0; i < count; i++) { Console.WriteLine(generator.Generate(strength)); } }
private static void TestGeneration(ReadablePassphraseGenerator generator, PhraseStrength strength, int iterations) { Console.Write("Testing {0:N0} string phrases of strength {1}...", iterations, strength); for (int i = 0; i < iterations; i++) { generator.Generate(strength); } Console.WriteLine(" OK."); }
private static void GenerateDelimiterSamples(PhraseStrength strength, ReadablePassphraseGenerator generator, int count, string delimiter) { Console.WriteLine(); Console.WriteLine("Delimited Samples ('{0}'):", delimiter); for (int i = 0; i < count; i++) { Console.WriteLine(generator.Generate(strength, wordDelimiter: delimiter)); } }
private static void GenerateMutatedSamples(PhraseStrength strength, ReadablePassphraseGenerator generator, int count, IEnumerable <IMutator> mutators) { Console.WriteLine(); Console.WriteLine("Mutated Samples:"); for (int i = 0; i < count; i++) { var passphrase = generator.Generate(strength, mutators: mutators); Console.WriteLine(passphrase); } }
/// <summary> /// Calculates the number of possible combinations of phrases based on the current dictionary and given phrase strength. /// </summary> public PhraseCombinations CalculateCombinations(PhraseStrength strength) { if (Clause.RandomMappings.ContainsKey(strength)) { return(this.CalculateCombinations(Clause.RandomMappings[strength])); } else { return(this.CalculateCombinations(Clause.CreatePhraseDescription(strength, this.Randomness))); } }
/// <summary> /// Generates a single phrase based on the given phrase strength in a UTF8 <c>byte[]</c>. /// This is slightly slower than <c>Generate()</c> and allows deterministic destruction of the data, but is still unencrypted. /// </summary> /// <param name="strength">One of the predefined <c>PhraseStrength</c> enumeration members.</param> /// <param name="includeSpacesBetweenWords">Include spaces between words (defaults to true).</param> public byte[] GenerateAsUtf8Bytes(PhraseStrength strength, bool includeSpacesBetweenWords) { return(GenerateAsUtf8Bytes(Clause.CreatePhraseDescription(strength, Randomness), includeSpacesBetweenWords)); }
/// <summary> /// Generates a single phrase based on the given phrase strength in a UTF8 <c>byte[]</c>. /// This is slightly slower than <c>Generate()</c> and allows deterministic destruction of the data, but is still unencrypted. /// </summary> public byte[] GenerateAsUtf8Bytes(PhraseStrength strength) { return(GenerateAsUtf8Bytes(Clause.CreatePhraseDescription(strength, Randomness), " ")); }
/// <summary> /// Generates a single phrase based on the given phrase strength in a <c>StringBuilder</c>. /// This is the fastest and least secure method. /// </summary> /// <param name="strength">One of the predefined <c>PhraseStrength</c> enumeration members (default: Random).</param> /// <param name="wordDelimiter">The string to place between each word in the passphrase (default: single space).</param> /// /// <param name="mutators">Applies one or more mutators to the passphrase after it is generated (default: none).</param> public String Generate(PhraseStrength strength = PhraseStrength.Random, string wordDelimiter = " ", IEnumerable <IMutator>?mutators = null) { return(Generate(Clause.CreatePhraseDescription(strength, Randomness), wordDelimiter, mutators)); }
/// <summary> /// Generates a single phrase as a <c>SecureString</c> based on the given phrase strength. /// This is the slowest and most secure method. /// </summary> /// <param name="strength">One of the predefined <c>PhraseStrength</c> enumeration members.</param> /// <param name="wordDelimiter">The string to place between each word in the passphrase.</param> public SecureString GenerateAsSecure(PhraseStrength strength, string wordDelimiter) { return(GenerateAsSecure(Clause.CreatePhraseDescription(strength, Randomness), wordDelimiter)); }
/// <summary> /// Generates a single phrase as a <c>SecureString</c> based on the given phrase strength. /// This is the slowest and most secure method. /// </summary> /// <param name="strength">One of the predefined <c>PhraseStrength</c> enumeration members.</param> /// <param name="includeSpacesBetweenWords">Include spaces between words (defaults to true).</param> public SecureString GenerateAsSecure(PhraseStrength strength, bool includeSpacesBetweenWords) { return(GenerateAsSecure(Clause.CreatePhraseDescription(strength, Randomness), includeSpacesBetweenWords)); }
private IEnumerable <string> SelectPhrases(IRandomNumberGenerator random, PhraseStrength strength, int phraseCount, bool includeSpaces, int minChars, int maxChars, NumericStyles whenNumeric, int numbersToAdd, AllUppercaseStyles whenUpper, int uppersToAdd) { if (minChars > maxChars) { yield break; } phraseCount = Math.Min(phraseCount, MaxCount); if (phraseCount <= 0) { yield break; } var sw = System.Diagnostics.Stopwatch.StartNew(); var generator = this.GetGenerator(random); int attempts = 0; ICollection <IMutator> mutators = null; if (whenNumeric != NumericStyles.Never || whenUpper != AllUppercaseStyles.Never) { mutators = new List <IMutator>(); } if (whenNumeric != NumericStyles.Never) { mutators.Add(new NumericMutator() { When = whenNumeric, NumberOfNumbersToAdd = numbersToAdd }); } if (whenUpper == AllUppercaseStyles.Anywhere) { mutators.Add(new UppercaseMutator() { When = UppercaseStyles.Anywhere, NumberOfCharactersToCapitalise = uppersToAdd }); } else if (whenUpper == AllUppercaseStyles.StartOfWord) { mutators.Add(new UppercaseMutator() { When = UppercaseStyles.StartOfWord, NumberOfCharactersToCapitalise = uppersToAdd }); } else if (whenUpper == AllUppercaseStyles.WholeWord) { mutators.Add(new UppercaseWordMutator() { NumberOfWordsToCapitalise = uppersToAdd }); } else if (whenUpper == AllUppercaseStyles.RunOfLetters) { mutators.Add(new UppercaseRunMutator() { NumberOfRuns = uppersToAdd }); } for (int c = 0; c < phraseCount; c++) { string candidate = ""; do { // Generate a phrase. candidate = generator.Generate(strength, " ", mutators); // Finally, remove spaces if required (as the mutators depend on whitespace to do their work). if (!includeSpaces) { candidate = new string(candidate.Where(ch => ch != ' ').ToArray()); } attempts++; // Ensure the final phrase is within the min / max chars. } while (attempts < MaxAttemptsPerCount && (candidate.Length < minChars || candidate.Length > maxChars)); if (attempts >= MaxAttemptsPerCount) { candidate = "A passphrase could not be found matching your minimum and maximum length requirements"; } // Yield the phrase and reset state. yield return(candidate); attempts = 0; } sw.Stop(); var bytesRequested = (int)((random as Terninger.Random.CypherBasedPrngGenerator)?.BytesRequested).GetValueOrDefault(); RandomService.LogPasswordStat("ReadablePassphrase", phraseCount, sw.Elapsed, bytesRequested, IPAddressHelpers.GetHostOrCacheIp(Request).AddressFamily, HttpContext.GetApiKeyId()); if (!IpThrottlerService.HasAnyUsage(IPAddressHelpers.GetHostOrCacheIp(this.HttpContext.Request))) { RandomService.AddWebRequestEntropy(this.Request); } IpThrottlerService.IncrementUsage(IPAddressHelpers.GetHostOrCacheIp(this.HttpContext.Request), phraseCount); }
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); } }
private static void BenchmarkUtf8Generation(ReadablePassphraseGenerator generator, PhraseStrength strength, int iterations) { Console.WriteLine(); Console.WriteLine("Benchmark of {0:N0} UTF8 phrases of strength {1}...", iterations, strength); var sw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) { generator.GenerateAsUtf8Bytes(strength); } sw.Stop(); Console.WriteLine(" in {0:N3}ms", sw.Elapsed.TotalMilliseconds); }
private static void TestTextualParsing(ReadablePassphraseGenerator generator, PhraseStrength strength) { Console.WriteLine("Testing parsing of textual phrase strength {0}...", strength); var description = Clause.CreatePhraseDescription(strength, generator.Randomness); var sb = new StringBuilder(); foreach (var c in description) { c.ToStringBuilder(sb); } var textualDescription = sb.ToString(); Console.Write(" Generation OK."); var customStrength = Clause.CreateCollectionFromTextString(textualDescription); Console.Write(" Parsing OK."); generator.Generate(customStrength); Console.WriteLine(" Passphrase OK."); }
/// <summary> /// Generates a single phrase based on the given phrase strength in a UTF8 <c>byte[]</c>. /// This is slightly slower than <c>Generate()</c> and allows deterministic destruction of the data, but is still unencrypted. /// </summary> /// <param name="strength">One of the predefined <c>PhraseStrength</c> enumeration members.</param> /// <param name="wordDelimiter">The string to place between each word in the passphrase.</param> public byte[] GenerateAsUtf8Bytes(PhraseStrength strength, string wordDelimiter) { return(GenerateAsUtf8Bytes(Clause.CreatePhraseDescription(strength, Randomness), wordDelimiter)); }
static bool ParseCommandLine(string[] args) { for (int i = 0; i < args.Length; i++) { var arg = args[i].ToLower().Trim(); if (arg.StartsWith("-") || arg.StartsWith("--") || arg.StartsWith("/")) { arg = arg.Replace("--", "").Replace("-", "").Replace("/", ""); } if (arg == "c" || arg == "count") { if (!Int32.TryParse(args[i + 1].Trim(), out count)) { Console.WriteLine("Unable to parse number '{0}' for 'count' option.", args[i + 1]); return(false); } i++; } else if (arg == "s" || arg == "strength") { if (!Enum.GetNames(typeof(PhraseStrength)).Select(x => x.ToLower()).Contains(args[i + 1])) { Console.WriteLine("Unknown 'strength' option '{0}'.", args[i + 1]); return(false); } strength = (PhraseStrength)Enum.Parse(typeof(PhraseStrength), args[i + 1], true); i++; } else if (arg == "spaces") { bool includeSpaces; if (!Boolean.TryParse(args[i + 1], out includeSpaces)) { Console.WriteLine("Invalid boolean '{0}' for 'spaces' option.", args[i + 1]); return(false); } else if (includeSpaces) { wordSeparator = " "; } else if (!includeSpaces) { wordSeparator = ""; } i++; } else if (arg == "separator") { wordSeparator = args[i + 1]; i++; } else if (arg == "d" || arg == "dict") { var customDictionaryPath = args[i + 1]; loaderArguments = "file=" + customDictionaryPath; if (!System.IO.File.Exists(customDictionaryPath)) { Console.WriteLine("Unable to find file '{0}' for 'dict' option.", customDictionaryPath); return(false); } i++; } else if (arg == "l" || arg == "loaderdll") { loaderDll = args[i + 1]; if (!System.IO.File.Exists(loaderDll)) { Console.WriteLine("Unable to find file '{0}' for 'loaderdll' option.", loaderDll); return(false); } i++; } else if (arg == "t" || arg == "loadertype") { loaderType = args[i + 1]; i++; } else if (arg == "a" || arg == "loaderargs") { loaderArguments = args[i + 1]; i++; } else if (arg == "n" || arg == "nongrammar") { if (!Int32.TryParse(args[i + 1].Trim(), out anyLength)) { Console.WriteLine("Unable to parse number '{0}' for 'nongrammar' option.", args[i + 1]); return(false); } i++; } else if (arg == "p" || arg == "phrase") { customPhrasePath = args[i + 1]; if (!System.IO.File.Exists(customPhrasePath)) { Console.WriteLine("Unable to find file '{0}' for 'phrase' option.", args[i + 1]); return(false); } try { phraseDescription = ReadablePassphrase.PhraseDescription.Clause.CreateCollectionFromTextString(System.IO.File.ReadAllText(customPhrasePath)); } catch (PhraseDescriptionParseException ex) { Console.WriteLine("Unable to parse file '{0}' for 'phrase' option:", args[i + 1]); Console.WriteLine(" {0}", ex.Message); if (ex.InnerException != null) { Console.WriteLine(" {0}: {1}", ex.InnerException.GetType().Name, ex.InnerException.Message); } } i++; } else if (arg == "min") { if (!Int32.TryParse(args[i + 1].Trim(), out minLength)) { Console.WriteLine("Unable to parse number '{0}' for 'min' option.", args[i + 1]); return(false); } i++; } else if (arg == "max") { if (!Int32.TryParse(args[i + 1].Trim(), out maxLength)) { Console.WriteLine("Unable to parse number '{0}' for 'max' option.", args[i + 1]); return(false); } i++; } else if (arg == "m" || arg == "stdMutators") { applyStandardMutators = true; } else if (arg == "m2" || arg == "altMutators") { applyAlternativeMutators = true; } else if (arg == "mutnumeric") { if (!Enum.GetNames(typeof(NumericStyles)).Select(x => x.ToLower()).Contains(args[i + 1])) { Console.WriteLine("Unknown 'mutNumeric' option '{0}'.", args[i + 1]); return(false); } numericStyle = (NumericStyles)Enum.Parse(typeof(NumericStyles), args[i + 1], true); i++; } else if (arg == "mutnumericcount") { if (!Int32.TryParse(args[i + 1].Trim(), out numericCount)) { Console.WriteLine("Unable to parse number '{0}' for 'mutNumericCount' option.", args[i + 1]); return(false); } i++; } else if (arg == "mutupper") { if (!Enum.GetNames(typeof(AllUppercaseStyles)).Select(x => x.ToLower()).Contains(args[i + 1])) { Console.WriteLine("Unknown 'mutUpper' option '{0}'.", args[i + 1]); return(false); } upperStyle = (AllUppercaseStyles)Enum.Parse(typeof(AllUppercaseStyles), args[i + 1], true); i++; } else if (arg == "mutuppercount") { if (!Int32.TryParse(args[i + 1].Trim(), out upperCount)) { Console.WriteLine("Unable to parse number '{0}' for 'mutUpperCount' option.", args[i + 1]); return(false); } i++; } else if (arg == "mutconstant") { if (!Enum.GetNames(typeof(ConstantStyles)).Select(x => x.ToLower()).Contains(args[i + 1])) { Console.WriteLine("Unknown 'mutConstant' option '{0}'.", args[i + 1]); return(false); } constantStyle = (ConstantStyles)Enum.Parse(typeof(ConstantStyles), args[i + 1], true); i++; } else if (arg == "mutconstantvalue") { constantValue = args[i + 1]; i++; } else if (arg == "q" || arg == "quiet") { quiet = true; } else if (arg == "h" || arg == "help") { PrintUsage(); Environment.Exit(0); } else { Console.WriteLine("Unknown argument '{0}'.", arg); return(false); } } return(true); }
/// <summary> /// Generates a single phrase as a <c>SecureString</c> based on the given phrase strength. /// This is the slowest and most secure method. /// </summary> public SecureString GenerateAsSecure(PhraseStrength strength) { return(GenerateAsSecure(Clause.CreatePhraseDescription(strength, Randomness), " ")); }
private IEnumerable <string> SelectPhrases(WordDictionary dictionary, IRandomNumberGenerator random, PhraseStrength strength, int phraseCount, bool includeSpaces, int minChars, int maxChars, NumericStyles whenNumeric, int numbersToAdd, AllUppercaseStyles whenUpper, int uppersToAdd) { if (minChars > maxChars) { yield break; } phraseCount = Math.Min(phraseCount, MaxCount); if (phraseCount <= 0) { yield break; } var sw = System.Diagnostics.Stopwatch.StartNew(); var generator = this.GetGenerator(dictionary, random); int attempts = 0; // Setup mutators. ICollection <IMutator> mutators = null; if (whenNumeric != NumericStyles.Never || whenUpper != AllUppercaseStyles.Never) { mutators = new List <IMutator>(); } if (whenNumeric != NumericStyles.Never) { mutators.Add(new NumericMutator() { When = whenNumeric, NumberOfNumbersToAdd = numbersToAdd }); } if (whenUpper == AllUppercaseStyles.Anywhere) { mutators.Add(new UppercaseMutator() { When = UppercaseStyles.Anywhere, NumberOfCharactersToCapitalise = uppersToAdd }); } else if (whenUpper == AllUppercaseStyles.StartOfWord) { mutators.Add(new UppercaseMutator() { When = UppercaseStyles.StartOfWord, NumberOfCharactersToCapitalise = uppersToAdd }); } else if (whenUpper == AllUppercaseStyles.WholeWord) { mutators.Add(new UppercaseWordMutator() { NumberOfWordsToCapitalise = uppersToAdd }); } else if (whenUpper == AllUppercaseStyles.RunOfLetters) { mutators.Add(new UppercaseRunMutator() { NumberOfRuns = uppersToAdd }); } for (int c = 0; c < phraseCount; c++) { string candidate = ""; do { // Generate a phrase. candidate = generator.Generate(strength, " ", mutators); // Finally, remove spaces if required (as the mutators depend on whitespace to do their work). if (!includeSpaces) { candidate = new string(candidate.Where(ch => ch != ' ').ToArray()); } attempts++; // Ensure the final phrase is within the min / max chars. } while (attempts < MaxAttemptsPerCount && (candidate.Length < minChars || candidate.Length > maxChars)); if (attempts >= MaxAttemptsPerCount) { candidate = "A passphrase could not be found matching your minimum and maximum length requirements"; } // Yield the phrase and reset state. yield return(candidate); attempts = 0; } sw.Stop(); PostSelectionAction("ReadablePassphrase", phraseCount, sw.Elapsed, random); }
private static void GenerateSamples(PhraseStrength strength, ReadablePassphraseGenerator generator) { GenerateSamples(strength, generator, 20); }