Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Cryptographically Strong Random Password Generation

3.20/5 (15 votes)
1 Nov 2005CPOL3 min read 1   1.8K  
An article on creating a simple, but robust cryptographically strong password generator.

Sample Image - CryptoPasswordGenerator.gif

Introduction

This article is another simple but robust password generator based on similar concepts presented in Kevin Stewart's C# Password Generator.

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...

C#
public static int Next(int max)
{
    if(max <= 0)
    {
        throw new ArgumentOutOfRangeException("max");
    }
    _Random.GetBytes(bytes);
    int value = BitConverter.ToInt32(bytes, 0) % max;
    if(value < 0)
    {
        value = -value;
    }
    return value;
}

The _Random field being used by this method is a static instance of the RNGCryptoServiceProvider class.

Character Types

The char arrays below define the character types that are available for use during password generation.

C#
private static readonly char[] _Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
private static readonly char[] _Numbers = "1234567890".ToCharArray();
private static readonly char[] _Symbols = "!@#$%^&*.?".ToCharArray();

Create()

The Create method does four different functions. It initializes the available character types, determines the length of the password to create, creates and finally returns the generated password.

C#
public string Create()
{
    _CharacterTypes = getCharacterTypes();
    StringBuilder password = new StringBuilder(_MaximumLength);

    //Get a random length for the password.
    int currentPasswordLength = RandomNumber.Next(_MaximumLength);
    //Only allow for passwords greater than or equal to the minimum length.
    if(currentPasswordLength < _MinimumLength)
    { 
        currentPasswordLength = _MinimumLength;
    }
    //Generate the password
    for(int i = 0; i < currentPasswordLength; i++)
    {
        password.Append(getCharacter());
    }
    return password.ToString();
}

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.

C#
private string[] getCharacterTypes()
{
    ArrayList characterTypes = new ArrayList();
    foreach(string characterType in Enum.GetNames(typeof(CharacterType)))
    {
        CharacterType currentType = 
          (CharacterType)Enum.Parse(typeof(CharacterType), 
          characterType, false);
        bool addType = false;
        switch(currentType)
        {
            case CharacterType.Lowercase:
                addType = IncludeLower;
                break;
            case CharacterType.Number:
                addType = IncludeNumber;
                break;
            case CharacterType.Special:
                addType = IncludeSpecial;
                break;
            case CharacterType.Uppercase:
                addType = IncludeUpper;
                break;
        }
        if(addType)
        {
            characterTypes.Add(characterType);
        }
    }
    return (string[])characterTypes.ToArray(typeof(string));
}

getCharacter()

This method randomly determines which type of character to get from the character types, then randomly determines which character from that subset and returns the value.

C#
private string getCharacter()
{
    string characterType = 
      _CharacterTypes[RandomNumber.Next(_CharacterTypes.Length)];
    CharacterType typeToGet = 
      (CharacterType)Enum.Parse(typeof(CharacterType), characterType, false);
    switch(typeToGet)
    {
        case CharacterType.Lowercase:
            return _Letters[RandomNumber.Next(_Letters.Length)].ToString().ToLower();
        case CharacterType.Uppercase:
            return _Letters[RandomNumber.Next(_Letters.Length)].ToString().ToUpper();
        case CharacterType.Number:
            return _Numbers[RandomNumber.Next(_Numbers.Length)].ToString();
        case CharacterType.Special:
            return _Symbols[RandomNumber.Next(_Symbols.Length)].ToString();
    }
    return null;
}

Usage

The example is easy to use and very configurable.

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:

C#
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.

C#
Password password = new Password(false, false, true, false);
password.Create();

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.

C#
Password password = new Password();
password.MinimumLength = 8;
password.MaximumLength = 8;
password.Create();

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!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)