Pages

Monday, October 13, 2008

Cryptographically Random Password Generator

Introduction

Creating a password is easy. However, creating a strong password is not easy. Most passwords are simple variations of dictionary words, often with random numbers at the end of them or are simple substitutions (1s for I's, the "@" symbol for A's, and so forth). The problem with this scheme is that it is easily guessable by sophisticated password-guessing software. Such software, such as that by Access Data, can crack open passwords that follow such simplistic patterns, even if those passwords include multiple intentionally misspelled words, random numbers, and other common patterns.
The Problem

The problem with passwords is that they are not random. They're based on predictable patterns. They're easy to remember and, consequently, easy to crack. Some passwords need not be complex. The complexity of the password should be commensurate with a) the possible attack vectors, and b) the value of the data or resource protected by that password. For example, ATM pins are 4-digit. But they're reasonably secure because they're not subject to brute force attacks.

So, when do you need to use non-trivial, random passwords? It's important to use such passwords when employing the use of encryption on data that can potentially be analyzed and where a brute force attack can be waged on the password protecting that data. AES-256 is meaningless if the password can be cracked in ten minutes.
The Solution

Use a cryptographically random password in cases where security is essential. The Cryptographically Random Password Generator provides such a service. How does it work? The first step is to get a cryptographically random 32-bit integer. There's a Random class provided by Microsoft in the System namespace (that you'll use), but the level of entropy (randomness) is minimal if you rely only on that class. Instead, you'll use the RNGCryptoServiceProvider namespace, provided in System.Security.Cryptography:

byte[] randomBytes = new byte[4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
Int32 randomInt=BitConverter.ToInt32(randomBytes, 0);
return randomInt;

Good; you now have a 32-bit integer that is totally random. You safely can use this cryptographically random integer as a seed in the Random class. In fact, you'll generate a new random seed per iteration (per password character). Why? Because if you use the random value as the initial seed, the password entropy is still not cryptographically random. You've generated a random seed, but given that seed, the Random class's generated values are still pretty predictable. Hence, you generate a new seed every time you need a character, and Random uses that random seed.

So, why do you need Random if you have the RNGCryptoServiceProvider class? The answer is that you'll need to map a randomly generated value to an array. The array will hold a character set—a list of allowable characters in our password. By default, that list will include the letters a-z, A-Z, and also 0-9 and some special characters (ten of them). Hence, the list includes a total of 72 distinct characters. The main iteration loop that populates the final password string looks something like this:

for (int i = 0; i < len; i++)
{
// Get our cryptographically random 32-bit integer & use it
// as a seed in the Random class
// NOTE: The random value is generated PER ITERATION, meaning
// that the System.Random class is re-instantiated every
// iteration with a new, cryptographically random numeric seed.
int randInt32 = RandomInt32Value.GetRandomInt();
Random r = new Random(randInt32);

int nextInt=r.Next(possibleChars.Length);
char c = possibleChars[nextInt];
builder.Append(c);
}

The static method call to RandomInt32Value accomplishes the task of getting the random 32-bit integer because that class encapsulates the necessary calls to the RNGCryptoServiceProvider class. For utility's sake, the application provided includes the ability to set the password length and the set of possible characters, as in the screen shot below:

Finally, note that the application provides the capability of viewing the statistical frequency distribution of the generated password. Why would you need this? For testing sake, you could generate a 10,000 character password using the available characters (or, for simplicity, just certain characters, like 0-9). Theory suggests that, roughly speaking, the generated characters will have an equal chance of being selected in the final passphrase. For example, I generated a 10,000 character passphrase using the characters 0 through 9. The values selected were roughly equal in frequency (a good sign of randomness, meaning that the randomness algorithm does not show statistical favoritism).

Conclusion

Data that is meant to be secure and that relies on user-generated passwords to secure the data are at risk. You can use a secure password generation mechanism, like the Cryptographically Random Password Generator, to generate random passwords using a variable character set and a length of your choosing. Write your password down and put it in a secure location. Rest assured that if the medium that contains your data is lost, your data will nonetheless be secure because the encryption key will be impossible to break with today's technology (or even tomorrow's?).

Comments and feedback on this article and the application are welcome. If you have suggestions, please don't hesitate to let me know at your leisure.

About the Author

I am a software engineer based in Raleigh, NC. I have experience in C, C++, Java, C#, and other languages.

I am married and have a beautiful wife named Amanda. Absent of kids, we have three house cats.

In my spare time, I also write a blog on political topics and current events (www.gmgdesign.com/go).

Downloads

# RandPasswordGen_demo.zip - Executable
# RandPasswordGen_src.zip - Source code

0 comments: