SiriusStarr / elm-password-strength / Rumkin

This module implements the popular F/OSS password strength check available at rumkin.com. A more detailed description may be found at that link, as well as the rationale behind it.

Usage Notes

The results returned by this module should be identical to those obtained from the live version of the strength test at rumkin.com. They will, however, differ from the version available as source for download, as there is a bug in which characters in keyboard punctuation `~-_=+[{]}|;:'",<.>/?\ contribute an additional sequence space of only 20 instead of the correct 22. As this bug is fixed in the live version, it is fixed in this package as well.

Warning: Common password warnings returned by this package are not factored into the overall strength of the password. As such, while a warning of "Common password!" will be returned for the password "raidersofthelostark", its strength will be Strong and its supposed entropy 70.5 bits, despite it being a weak, common password. Consider using Zxcvbn/ZxcvbnPlus if you require common passwords to impact the overall score and not merely be presented as warnings.

The computational performance of this library is quite good, with essentially instantaneous results.

While it does contain a common word list, the library is relatively light. Sizes for an extremely simple example application follow:

Normal Usage

For normal usage of this module, only the function getStats and the returned types RumkinResult and Strength are necessary.

getStats : String -> RumkinResult

Given a password, check it for common passwords and score it, returning the result.


type alias RumkinResult =
{ warnings : List String
, length : Basics.Int
, strength : Strength
, strengthComment : String
, entropy : Basics.Float
, charsetSize : Basics.Int 
}

The results returned by getStats, containing the following fields:


type Strength
    = VeryWeak
    | Weak
    | Reasonable
    | Strong
    | VeryStrong

The overall strength of the password, along with the string that will be found in strengthComment. These do not take into account common passwords.

Custom Usage

The sequence frequency and common password lists used by this package are compressed and require parsing prior to use. If you wish to control exactly when that happens (and cache it in your model), the following functions are available.

getCustomStats : Internal.FrequencyList -> Internal.CommonPasswordList -> String -> RumkinResult

getStats with a provided frequency list and common password list. This may be used to control the point at which parsing these lists is performed or to run the algorithm with custom frequency/password lists.

parseFrequencyList : String -> Result String Internal.FrequencyList

Given a ompressed/encoded sequence frequency list, try to parse it. In general, this should only be used to parse the list at Rumkin.Frequency.frequencyList, but it may be used to parse custom frequency lists, if they are encoded the same. The description of the frequency list encoding follows:

The frequency thing is a bit more interesting, but still not too complex. Each three letters are base-95 encoded number representing the chance that this combination comes next. Subtract the value of ' ' from each of the three, then ((((first_value * 95) + second_value) * 95) + third_value) will give you the odds that this pair is grouped together. The first is " " (non-alpha chars), then " a", " b", etc. " y", " z", "a ", "aa", "ab", and so on. If you decrypt the table successfully, you should see a really large number for "qu".

parseCommonList : String -> Result String Internal.CommonPasswordList

Given a compressed/encoded common password list, try to parse it. In general, this should only be used to parse the list at Rumkin.Common.commonList, but it may be used to parse custom common password lists, if they are encoded the same. The description of the common password list encoding follows:

The compression algorithm is very basic - the first letter is upper case, and it means to copy X letters from the previous word. A = 0, B = 1, etc. So, if I had "apple apricot banana", it would compress to "AappleCricotAbanana".