Passwords are a necessary evil in the computing world. Access or trust is granted to an object (such as a file, or system) for a subject (normally a user or process) by using some sort of key, which we refer to as passwords. That is all fine and dandy, and we all get that. But from a users perspective, passwords are typically thought of as simply a burden , something that gets in their way from doing the task at hand.
The weakest link is the human factor when it comes to security, and passwords are a big part of that. It is much easy for a user to enter a blank password to simply get past the prompt, or use really easy passwords. Movies using the latest and greatest MovieOS depict this weakness routinely, and we hear about simple passwords like their name, password, love, god and sex. We see people who are forced to use stronger passwords, write them down on yellow sticky notes and stick them to the monitor; some think they are being clever and put it under their keyboard. In all cases the user is simply trying to get on with their day-to-day lives, and don't realize the effects of weak passwords.
One of the interesting things these days on the Internet is that, for some reason many users think that they understand security issues more, in relation to the strength of keys via its bit size. Perhaps this has been distilled on users as they use digital certificates more as part of HTTPS/SSL sessions. Who knows. Although from a security perspective it has little real correlation, people more easily understand that a 56-bit key is weaker than a 128-bit key, and that the latter is better. This is an interesting observation, because we can use this to our advantage.
From my experience with users, they hate complex dialogs that puke up error boxes all the time stating that their password is not good enough. More to the point, most times they don't know WHY it isn't good enough, and get extremely frustrated. This article is an introduction to a generic password dialog/form in C#, that in real-time calculates the effective bit size of a password, and displays it to the user as they enter it in. This dialog can be easily extended to add rules to force a minimum size, and even force a combination of case sensitive letters, numbers and punctuation, but that is beyond the scope of this article.
Understanding password strength by the Effective Bit Size
Michael Howard did a good job in his latest book  discussing this in depth. Rather than regurgitate the entire text, there is an excellent table that sums it up. In it he breaks down different scenarios against the effective strength of a 56-bit and 128-bit key. The table looks something like this:
||26 (a-z or A-Z)
||52 (a-z and A-Z)
|Case-sensitive alpha and numeric
||62 (a-z, A-Z and 0-9)
|Case-sensitive alpha, numeric and punctuation
||93 (a-z, A-Z, 0-9 and punctuation)
* RPL=Required Password Length
As you can see, the more characters added to the set of possible characters directly reduces the number of characters required in the password to keep the same relative strength. With this though there is one important point to remember. The effective bit size of a password is an important variable when calculating its effective strength, but you cannot simply rely on that, if the password can be easily guessed. Let me give you a good example to illustrate this:
||Effective Key Strength|
From this you can see that by using a combination of case-sensitive letters, numbers and punctuation you can significantly increase the effective strength. But here is the kicker... every one of these passwords is in many of the brute-force dictionary attack tools I have (the same tools an attacker will probably have), rendering the passwords strength considerably lower; at this point it is actually pretty useless. This has to be considered when designing a good password, but that is out of the scope of this article.
Exploring the code
I included a sample form in password.cs that you can use to add to your own project. (Basically all you need to do is change the namespace and go to town). But for those interested, I am going to include a bit of comment on parts of the code.
The first piece that should be looked at is the
checkEffectiveBitSize() function. The meat of the calculation is in the line:
double result = Math.Log( Math.Pow( charSet, passSize ) ) / Math.Log( 2 );
This comes from the math involved in addressing the randomness of the English language, as found in the research paper from Claude Shannon titled "A Mathematical Theory of Computation" way back in 1948. Basically the effective bit strength of a random (notice I didn't say dictionary) password is log2(n^m), where n is the pool size of valid characters and m is the length of the password. The above calculation does just that!
The next piece that is interesting to note is how I calculated the actual number of valid characters, noted as n in the formula. I do this in the function
private int getCharSetUsed( string pass )
int ret = 0;
if( containsNumbers( pass ) )
ret += 10;
if( containsLowerCaseChars( pass ) )
ret += 26;
if( containsUpperCaseChars( pass ) )
ret += 26;
if( containsPunctuation( pass ) )
ret += 31;
The code itself is pretty boring, but it's interesting to talk about. The reason is through the understanding of HOW the characters are calculated by using regular expressions. Each of the contains<blah> functions uses a simply
Regex lookup to determine if it indeed contains that set of characters. As an example, here is the
private bool containsPunctuation( string str )
Regex pattern = new Regex( @"[\W|_]" );
return pattern.IsMatch( str );
If you haven't had a chance to use regular expressions in C# yet, you need to start! They are very powerful when dealing with input validation and are a MUST when dealing with the dynamics of potentially malicious and tainted data. I have loved this in Perl for years, and am happy to finally see it in a language like C# natively.
For those who might be wondering why I used that particular
Regex string, I need to explain what it says first. Basically it says "Is there a pattern match in str where there is NO case-sensitive alphanumeric characters or a _?". That basically leaves only the 31 punctuation keys. (Not entirely true since TAB is a valid key, but we will ignore that for this exercise). As my comment in the code points out, I have to explicitly state that a "_" is a valid punctuation character as it is treated as alphanumeric normally (Ya, I always thought that was stupid too). That's all there is to it!
I am sure I could go in and refactor this considerably to make it more efficient. I could take advantage of the event model and only recalc the last keystroke instead of the entire string, but this works fine for my needs right now. I could memory scrub the location that stores the password and could be more aggressive in the destruction of the UI components, to ensure they could not be poked. But that was beyond the scope of what I wanted to show you today. Hopefully you found this article interesting, insightful and above all, helpful. Maybe I will even see the dialog in some form in one of your applications.
One last thing before I close down vi. This dialog can help to show the effective bit strength of the password, but it's really useless if you do not handle password management securely. First and foremost, try not to store passwords on the system. If you cannot do this, then consider storing something like a hash instead of the password itself, and use strong DACL permissions to ensure only trusted subjects can access the object. Strong passwords will always be trumped by weak implementations and you need to consider this when designing your code.
Security is part of our every day life, and we should embrace it. Using techniques like this is a great start.
- The Center for Password Sanity
- Writing Secure Code
- Password Security: A Case Study
- 07/08/2003 - Initial submission