Introduction

Background

My purpose for creating this example stemmed from evaluating various third party password generation tools and wanting to know what it would really take to implement my own password generator. In my research I came across Kevin Stewart's article and noticed his use of the RNGCryptoServiceProvider and became curious why this class from the Cryptography namespace was used instead of the Random class.

Further research on the RNGCryptoServiceProvider class led me to find it makes use of Windows modules that have completed FIPS-140 (Federal Information Processing Standard) US government standard which provide a benchmark for implementing cryptographic software. See the Microsoft FIPS - 140 Evaluation article for more information.

Requirements

The types of characters included in the passwords needed to be configurable. The length of the password needed to have a variant length that was chosen randomly. Finally I wanted to randomly determine which character type to append (number, uppercase, lowercase or symbol).

Implementation

Below I've outlined the purpose for each of the methods included in the process of creating the passwords.

RandomNumber.Next(int max)

This method provides a wrapper around the RNGCryptoServiceProvider class allowing for easy creation of a random number. See below...

getCharacterTypes()

I used an enum to to indicate which character types were available to create the passwords. In this method I iterate through the character types and determine if a particular character type is available for use based on a value set to a corresponding property that indicates whether or not to include a given character type.

Usage

Accept the defaults

If you'd just like to accept the default pre-initialized lengths and to include all of the character types, it's as easy as the following two lines of code:

Password password = new Password();
password.Create();

Configure the types of characters to include

There are properties in the Password class allowing you to indicate whether or not you'd like to IncludeUpper (uppercase), IncludeLower (lowercase), IncludeSymbols (!@#$) and IncludeNumbers (12345*). These properties can be set after a password object has already been created or they can be set during the creation of the object via parameters in the constructor.

Create fixed length passwords

One recent suggestion by Gabe Wishnie was to make it so you could explicitly set the password length without having the length chosen at random. A quick test showed this functionality was already built in if used in the following manner.

Conclusion

The value in this project can be seen as it could be applied to various concepts. The random number method supplied in this article or Kevin Stewart's could also be used to randomly select words from a string array read from a text file. Combine this with a Captcha control and you'll have a decent validation control. Hope all of you find my implementation of use!

Nice work. I have a minor quibble with the Next() method in your RandomNumber class:

The integers you get from the RNGCryptoServiceProvider bytes are guaranteed to be evenly distributed across the range of integers. But when you try to translate those into the range the caller requested, your line int value = BitConverter.ToInt32(bytes, 0) % max; will result in a remainder that is biased toward the low side of the requested range. This is because, most of the time, max will not divide evenly into the range of integers. Random values at the top end of the integer range will always result in remainders at the bottom end of the requested range.

For example, suppose Integer.MaxValue = 100 and your random bytes are evenly distributed across that range. The caller requests max = 12. For Integers up to 96, the function will return values evenly distributed up to 12. But for Integers 97 to 100, the function will always return values distributed from 1 to 4. Therefore, there is a slightly higher probability that the numbers returned will fall from 1 to 4 than from 5 to 12.

Of course, since Integer.MaxValue is large, the bias is greatly reduced for small values of max. But for large values of Max, say Integer.MaxValue * 2 / 3, there is a fairly significant bias: numbers from the bottom half of the range are twice as likely as numbers from the top half of the range. Granted, in your CryptoPasswordGenerator class, the method is only used to pick from a set of characters that is very small compared with the range of all Integers, so the bias will be very small.

I suggest solving this minor issue by adding a loop which throws out any random Integers near the top of the range that would result in biased remainders. This is what Kevin Stewart did in his project at http://www.codeproject.com/KB/cs/pwdgen.aspx[^].

I only took math up till my second year of university, but I'm pretty sure my analysis is correct

Hi,
Thanks for publishing the code, saved me some time.
I did however make one addition which may interest you, according to microsoft a strong password has between 6 and 10 characters and includes at least:

one special character
one uppercase letter
one lowercase letter
one number

Although this is possible with your code, it does not enforce this, you may by chance get a password missing one or more of these character types.

I think this password generator is a great idea but when it comes to password generating id rather use another concept (hashing). This requires you come up with one master password for everything. This way you only have to remember one password. I then take the master password/url/login combination and has it. I allow the user to select how many character password they want and i return that many characters from the hash i created. For how many passwords i have there is no way that i can remember them all. Yes you can build a password db but this is a lot easier. Just as long as you can remember your login name and master password you can generate the password for every site you visit. I have been doing this for quite some time and i love it.

I think you are mistaking my demo console application what I use to generate passwords for the various applications I use. It was only provided as an example application required by the upload. My intent for using the password generator is for web sites and applications that require password generation as a business requirement. Maybe I should've included a web application as an example.

I'm not sure I follow. In my example where would you implement PasswordDeriveBytes? I'm using the RNGCryptoServiceProvider for random number generation. Then using the random number that was generated from the RNGCryptoServiceProvider's GetBytes(byte[]) method. I'm not attempting to encrypt the password I generated. I'm attempting to randomly create the password.