Public API - ligos/readablepassphrasegenerator GitHub Wiki

Public API

To illustrate the Public API, I'll reproduce the examples from How to Use the Console App in C#.

Use the NuGet package to install the API.

Getting Started

Once you have installed the nuget package, the simplest usage is:

var generator = MurrayGrant.ReadablePassphrase.Generator.Create();    // Create the generator.
var phrase = generator.Generate(PhraseStrength.Random);    // Generate a phrase.

And if you want to calculate the combinations like the console app did:

var combinations = generator.CalculateCombinations(PhraseStrength.Random);    
var min = combinations.Shortest;
var max = combinations.Longest;
var weightedAvg = combinations.OptionalAverage;
// Each of the above properties has a related one ending in AsEntropyBits as well.

Simple!

(More information about Counting Combinations).

Stronger Phrases

To generate phrases of different strength, choose a different PhraseStrength enum value.

var phrase = generator.Generate(PhraseStrength.Normal);    // Generate a phrase.

The generate method takes an overload for custom strengths: an IEnumerable<Clause>. Each PhraseStrength enum corresponds to a particular collection of Clause objects. You can see exactly what they look like in the static Clause.CreatePhraseDescription() methods. And you can parse a textual version an IEnumerable<Clause> using the static Clause.CreateCollectionFromTextString() method (see Custom Phrase Description for this textual format).

var phraseDescription = Clause.CreateCollectionFromTextString( ... );
var phrase = generator.Generate(phraseDescription);    // Generate a phrase.

And for multiple phrases you'll need to use an extremely advanced feature of C#: a loop.

for (int i = 0; i < 10; i++)
{
    var phrase = generator.Generate(PhraseStrength.Normal);
}

Random Phrases

Each of the PhraseStrength.Random... items correspond to a collection of base PhraseStrengths. One is chosen at random before using the normal logic to build a clause. You can find out what those mappings are in the PhraseDescription.Clause.RandomMappings static dictionary. They are based on the average length of the generated phrases by each PhraseStrength.

You can also define your own custom random strengths by selecting your own combination of PhraseStrength values and passing them to ReadablePassphraseGenerator.Generate(IEnumerable<PhraseStrength>) overload like so:

// New up a generator and load a dictionary as above.
...
var options = new [] {
    PhraseStrength.Normal,
    PhraseStrength.Strong,
    PhraseStrength.Insane,
    // And so on.
};
var phrase = generator.Generate(options);    // Generate a phrase based on one of the options provided.

Cache the Default Dictionary

Loading the dictionary involves decompressing and deserialising an XML file. Rather than reloading the default dictionary every time, you can cache it.

private static WordDictionary CachedDictionary;

// Cache the dictionary (not entirely threadsafe, but close enough).
if (CachedDictionary == null) {
	CachedDictionary = MurrayGrant.ReadablePassphrase.Dictionaries.Load();
}
var generator = MurrayGrant.ReadablePassphrase.Generator.Create(words: CachedDictionary);    // Create the generator.
var phrase = generator.Generate(PhraseStrength.Random);    // Generate a phrase.

API

There are only a few methods on the generator. Most have overloads to choose between a PhraseStrength enum and IEnumerable<Clause>.

public sealed class ReadablePassphraseGenerator
{
    // This has overloads for files and streams.
    public void LoadDictionary(dictionaryLoader, arguments) { ... }
    // This returns a bool and exception information rather than throwing.
    public bool TryLoadDictionary(dictionaryLoader, arguments, out exception) { ... }
    // Finally, if you manually load a dictionary from your own loader, this allows you to set it.
    public void SetDictionary(WordDictionary words) {}

    // This returns a 3 doubles representing the min, max and average combinations for a particular phrase strength.
    public PhraseCombinations CalculateCombinations() { ... }

    // Generates a passphrase as a string, in a StringBuilder. Fastest and lest secure.
    public String Generate() { ... }
    // Generates a passphrase as a SecureString. Slowest and most secure.
    public SecureString GenerateAsSecure() { ... }
    // Generates a passphrase as a UTF8 byte[]. Only slightly slower than Generate(), but the string is still unencrypted.
    public byte[]() GenerateAsUtf8Bytes() { ... }
}

There are three variations of Generate(). One returns a normal string, one a SecureString, and the final one a UTF8 encoded byte[].

The secure version builds the final passphrase in the SecureString character by character; the phrase is never visible as an unencrypted string. (Although, the dictionary words are stored in memory as unencrypted strings). This secure version is used by the KeePass plugin under Windows, if you are not using mutators.

The standard one, returning an ordinary String, is used by the console app (since the passphrase will be visible on the console anyway!).

The UTF8 version builds the phrase as UTF8 encoded characters in a List<byte> and returns the final result as a byte[]. This allows you to deterministicly overwrite the resulting characters with zeros when you're finished with it, but the passphrase is still unencrypted. The UTF8 version is used by the KeePass plugin under non-Windows operating systems (such as Linux) as I've observed corruption when using the secure version.

Note that the use of Mutators requires the unencrypted String form of Generate().

Mutators

Mutators may be supplied as an optional parameter to the unencrypted String form of Generate().

Mutators must implement IMutator, which has a single method Mutate (StringBuilder passphrase, RandomSourceBase random). Based on the name on the tin "Mutator" and the interface, mutators are expected to change the generated passphrase, not return a new passphrase.

When multiple mutators are applied, each is applied in turn.

Note that mutators assume the space (U+0020) is used to delimit words. The Generate() method will always use space when mutators is in use, and then replace the space with a custom delimiter after all mutators are applied.

My Random is Better Than Yours

The usefulness of any password or passphrase is entirely dependent on its random number generator (as I found very painfully). By default, the generator uses RNGCryptoServiceProvider. But you can pass a different one into its constructor. You must inherit RandomSourceBase and override byte[] GetRandomBytes(int numberOfBytes) which produces some number of random bytes (this should be trivial for any low level random number generator). The KeePass plugin uses KeePass's CryptoRandomStream instead.

Further Details

For all the gory details of how to use the API, look at the Console app or the Test app (which counts words, combinations, does a couple of short benchmarks, dumps some statistics and more).

⚠️ **GitHub.com Fallback** ⚠️