Generate a random password in C#

[password]

As I mentioned in a recent post, you should always use a strong password for every login. Remember, a computer can perform millions or billions of operations per second, so your daughter’s birthday or the name of your son’s guinea pig is just too easy to guess.

This example simply wraps the password generation form used by the example Make a password manager in C#. Use the check boxes to indicate which types of characters you want to allow or require. You can enter specific characters in the text box below the last entry, Space, if you want to include a specific set of characters.

Enter the minimum and maximum length of the password and then click Generate. The program uses the inputs you provided to generate a password, displays it at the bottom, and selects it so you can easily press Ctrl+C to copy it to the clipboard.

If you don’t like the password the program gave you, simply click Generate again to make a new one.

There are a couple of interesting pieces of code in this example. The following code executes when you click one of the Lowercase check boxes.

// Required implies allowed.
private void chkRequireLowercase_CheckedChanged(object sender,
    EventArgs e)
{
    if (chkRequireLowercase.Checked)
        chkAllowLowercase.Checked = true;
}

// Not allowed implies not required.
private void chkAllowLowercase_CheckedChanged(object sender,
    EventArgs e)
{
    if (!chkAllowLowercase.Checked)
        chkRequireLowercase.Checked = false;
}

When you check the “require lowercase” checkbox, then you must also allow lowercase letters, so the program checks the “allow lowercase” box.

Similarly, if you uncheck the “allow lowercase” check box, then you cannot require lowercase letters, so the program unchecks the “require lowercase” box.

The other pairs of check boxes have similar event handlers.

When you click the Generate button, the following code executes.

// Generate a new password.
private void btnGenerate_Click(object sender, EventArgs e)
{
    try
    {
        txtPassword.Text = RandomPassword();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    txtPassword.SelectAll();
    txtPassword.Focus();
}

This code calls the RandomPassword method to generate the password. If there is an error, the code displays it. The code finishes by selecting the password in the txtPassword text box and giving that control focus.

The following code is where all of the real fun happens.

// Generate a password that meets the reuirements.
private string RandomPassword()
{
    const string LOWER = "abcdefghijklmnopqrstuvwxyz";
    const string UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const string NUMBER = "0123456789";
    const string SPECIAL = @"~!@#$%^&*():;[]{}<>,.?/\|";
    string other = txtOther.Text;
    if (chkRequireOther.Checked && (other.Length < 1))
    {
        MessageBox.Show("You cannot require characters " +
            "from a blank string.",
            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        txtOther.Focus();
        return txtPassword.Text;
    }

    // Make a list of allowed characters.
    string allowed = "";
    if (chkAllowLowercase.Checked) allowed += LOWER;
    if (chkAllowUppercase.Checked) allowed += UPPER;
    if (chkAllowNumber.Checked) allowed += NUMBER;
    if (chkAllowSpecial.Checked) allowed += SPECIAL;
    if (chkAllowUnderscore.Checked) allowed += "_";
    if (chkAllowSpace.Checked) allowed += " ";
    if (chkAllowOther.Checked) allowed += other;

    // Pick the number of characters.
    int min_chars = int.Parse(txtMinLength.Text);
    int max_chars = int.Parse(txtMaxLength.Text);
    int num_chars = Crypto.RandomInteger(min_chars, max_chars);

    // Satisfy requirements.
    string password = "";
    if (chkRequireLowercase.Checked &&
        (password.IndexOfAny(LOWER.ToCharArray()) == -1))
        password += RandomChar(LOWER);
    if (chkRequireUppercase.Checked &&
        (password.IndexOfAny(UPPER.ToCharArray()) == -1))
        password += RandomChar(UPPER);
    if (chkRequireNumber.Checked &&
        (password.IndexOfAny(NUMBER.ToCharArray()) == -1))
        password += RandomChar(NUMBER);
    if (chkRequireSpecial.Checked &&
        (password.IndexOfAny(SPECIAL.ToCharArray()) == -1))
        password += RandomChar(SPECIAL);
    if (chkRequireUnderscore.Checked &&
        (password.IndexOfAny("_".ToCharArray()) == -1))
        password += "_";
    if (chkRequireSpace.Checked &&
        (password.IndexOfAny(" ".ToCharArray()) == -1))
        password += " ";
    if (chkRequireOther.Checked &&
        (password.IndexOfAny(other.ToCharArray()) == -1))
        password += RandomChar(other);

    // Add the remaining characters randomly.
    while (password.Length < num_chars)
        password += RandomChar(allowed);

    // Randomize (to mix up the required characters at the front).
    password = RandomizeString(password);

    return password;
}

The RandomPassword method defines the standard groups of characters. It then makes a string containing all of the allowed characters. For each group of characters, it checks the corresponding “allow” check box and, if that box is checked, it adds the correct characters to the allowed string. It uses the RandomChar method described shortly to pick a random character from the appropriate group.

Next, the code gets the minimum and maximum password length. It then calls the Crypto.RandomInteger helper method to get a length for the password between those bounds. (Download the code to see how that method works.)

The code then adds characters to the password to satisfy any required characters. For each type of character, the program checks its “required” check box. If the box is checked, the code also checks the current password string to see if it already contains one of the required characters. The second test is mostly unnecessary because the password is initially blank and the character groups do not overlap. For example, if a lowercase letter is required, it has not already been added to the password by one of the character groups previously considered. I structured the test this way in case the “other” category contains characters that are already in other groups or in case you modify the groups so there is overlap.

The code then enters a loop where it adds random characters to the password until the password has the desired length. Note that the password may have a longer than desired length if that length is short and you require many characters. For example, if the maximum password length is four but you require uppercase, lowercase, numbers, special underscore, and space, then the required characters will make the password six characters long.

Finally, the code calls the RandomizeString method (described shortly) to scramble the characters in the string. It does this because the beginning of the string was filled with required characters. Randomizing the string allows the characters to end up in anym position.

The following code shows the RandomChar method

// Return a random character from a string.
private string RandomChar(string str)
{
    return str.Substring(Crypto.RandomInteger(0, str.Length - 1), 1);
}

This method uses Crypto.RandomInteger to pick a random integer between 0 and the last index in the string. It then returns the string’s character at that position.

The following code shows the RandomizeString method.

// Return a random permutation of a string.
private string RandomizeString(string str)
{
    string result = "";
    while (str.Length > 0)
    {
        // Pick a random character.
        int i =
            Crypto.RandomInteger(0, str.Length - 1);
        result += str.Substring(i, 1);
        str = str.Remove(i, 1);
    }
    return result;
}

This method randomizes the letters in a string. It creates a new blank string. It then enters a loop that executes as long as the input string is non-blank.

Each time through the loop, the code uses Crypto.RandomInteger to a random index in the string. It adds the character at that index to the growing result string and then removes the character from the input string.

The code uses the Crypto.RandomInteger method to pick random values between minimum and maximum bounds. That method uses a RNGCryptoServiceProvider ro generate the random value.

Download the example to see how that method works and to see additional details.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in algorithms, cryptography, internet and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.