This page lists more technical details of the implementation of the site and exactly how it generates passwords.
I'm a Windows .NET developer, but .NET Core has let me host on Linux! This lets me save a few dollars on licenses and means I can get away with lower cost hardware.
Previous I was running:
From GitHub. Under the Apache License.
I'm developing using Visual Studio. Dependencies are referenced by nuget or included as binary assets. There is no database behind the scenes.
The fundamental building block of any password generator is a cryptographic random number generator. The key requirements of which are:
The standard option on Windows .NET is to use RNGCryptoServiceProvider
.
But I don't want to put all my eggs in one basket, so I'm using a random number generator which derives its data from many sources.
This is called Terninger, which is my own implementation of Fortuna, a CRNG designed by Bruce Schneier.
Prior to May 2018, I was using a random number generator of my own design. I don't believe this had any serious flaws, but Terninger is of much higher quality.
The core PRNG (AES in counter mode) was put through 4 separate random number test suites. These were: PractRand, RaBiGeTe, TestU01 and Dieharder. It even passed them all!
The pooled generator uses the same core PRNG (as specified in Fortuna). As long as the pool accumulates entropy and reseeds the internal PRNG (and yes, I've checked it does), the above results apply to every random number used by Make Me a Password.
No matter what randomisation algorithms are used, without a good source of entropy you'll get the same numbers out the other end. The following sources are used by Terninger:
RNGCryptoServiceProvider
)See here for further details of the base sources used. Over time, I expect to add other sources, as time allows me to implement them.
Each algorithm is implemented in MVC controller classes named (for example) ApiPassphraseV1Controller
.
Generally, they are table lookups. Where the table varies from style to style.
By convention, a method SelectPhrases()
/ SelectPasswords()
/ SelectPINs()
returns one or more passwords based on the parameters supplied.
More details can be found in the API documentation.
The hex passwords are taken directly from the random number generator without any modification. No lookups, tables or hash functions here. Just raw, unadulterated bytes.
Each word is chosen from the dictionary as a giant lookup. After the phrase is constructed, it may be rejected if it does not meet the length requirements. After 100 attempts without meeting length requirements, a null passphrase will be returned.
Uses a lookup into vowel and consonant sounds. Some very basic logic is used to alternate between vowels and consonants, but I could do much better cleaning up double letters and so on.
This calls out to my Readabable Passphrase library. Source code is available. After the phrase is constructed, it may be rejected if it does not meet the length requirements. After 100 attempts without meeting length requirements, a null passphrase will be returned.
PINs are constructed as a lookup into the digits 0..9
.
After a PIN is constructed, it may be rejected if it is on the blacklist.
Patterns use a more complex algorithm.
There are too many code points to do lookups into a full table of known characters. So generating Unicode passwords uses a different algorithm.