Edit:This password utilities library has now been substantially upgraded and open-sourced with an MIT license. You can find a .NET 4.0 version of the library and an example graphical interface in a Google Code Mercurial repository.
As discussed in the first installment of this series, I'm on a mission to create a C# utilities library covering the following areas:
- Specifying password policies that can match most application requirements.
- Generating cryptographically-secure random passwords that satisfy a specified password policy.
- Measuring the strength (or more precisely, entropy) of human-generated and machine-generated passwords.
- Using random salts and key stretching to make password hashes more secure than the original passwords.
- Measuring the additional strength added by iterative salted hashes.
- Timing the password generation and password hashing processes.
Most applications that use a password or passphrase for user authentication also have a policy that dictates the password complexity requirements. These requirements range from a simple minimum length to some very complex rules. There's a decent case for arguing that the more complex policies might actually reduce security in some circumstances. This is because these policies encourage users to invent easier-to-remember (i.e. weaker) passwords or to write down passwords in order to remember them.
Another problem with password policies is that they're mainly aimed at reducing the threat of direct attacks on the application (the online attack) or on the application's login database (the offline attack). They ignore other attacks such as keylogging and botnets, which could be considered as more common threats than the direct attacks.
Finally, you might want to explain to your over-eager security team that the vast majority of end-users quite rationally believe that:
- The chance of their account being compromised by a direct online attack is almost zero.
- The chance of their account being compromised by a direct offline attack is very low.
- Their bank will likely make good any financial losses resulting from a direct offline/online compromise.
- Given the above three facts, it doesn't make sense to spend any time choosing strong passwords and never re-using passwords on other websites.
Moving swiftly on...let's look at the source code of PasswordPolicy.cs, a class that implements policies used to control the generation and validation of passwords. The constants in the following screenshot define all of the possible symbol groups, and individual symbols within those groups, that can be used to create passwords controlled by this policy generator. Note that symbols normally considered to be confusing, such as 0, O, I, 1, etc, have already been removed. I've split punctuation symbols into their own group as applications such as Gmail allow their use whilst prohibiting other non-alphanumeric ASCII symbols. I've also included some non-ASCII symbols, as an increasing number of applications are now Unicode-aware. Feel free to tune these constants to suit your applications. Be aware that if you add or remove any symbol groups, you will need to change the SymbolType enumeration and also any code that uses that enumeration.
The class constructor allows either the default password policy or a custom one. For a custom policy, the full list of parameters is shown in the screenshot. The use of symbols from each symbol group can be prohibited by passing null for that symbol group, made optional by passing zero, or made mandatory by passing the minimum number of password characters that must be drawn from that symbol group.
The default policy doesn't try to do anything clever. It works on the principle that password length is the best security, hence the minimum length of 14. Non-ASCII symbols are prohibited, all other symbol groups are allowed but optional. Again, you can change this default policy as required.
These two properties return a byte array or Unicode string containing the full list of symbols allowed in any password matching the current policy.
For any password matching the current policy, this method provides the major input to a formula for measuring the entropy of randomly-generated passwords matching this policy. We'll take a detailed look at this formula in a later installment.
Not shown is the method that calculates whether a given password matches the current policy. But you can view and download PasswordPolicy.cs. The complete library, including this class, will be posted at the end of this series. In the next installment, we'll look at the die-rolling class.