Password Generator - ASP.NET

Overview

We had an application where we wanted to upload a list of users into our ASP.NET website, and automatically generate password for them, which we would later email to them. This article provides code to generate a random password based on the length and minimum number of special (i.e. non-alphanumeric) characters required.

Code

{copytext|code}
[Flags]
public enum CharacterGroup { UpperCase=1, LowerCase=2, Number=4, Special=8 }

public static class PasswordGenerator
{
    /*  To avoid confusion between letters and numbers in various fonts, we intentially omit 
        the following characters

        Uppercase: I, O
        Lowercase: i, l
        Numbers:   0, 1
        */
    private static readonly string[] CHAR_GROUPS = new string[]{
        "ABCDEFGHJKLMNPQRSTUVWXYZ", 
        "`~!@#$%^&*()_-+={[}]|\\:;\"'<,>.?/",
        "abcdefghjkmnopqrstuvwxyz",
        "23456789" 
    };

    public static string GeneratePassword(int length, int minSpecialChars, CharacterGroup groups)
    {
        //--- Inits ---------------------------------------------------------------------------
        int groupFlags = (int)groups;
        string result = "";
        string deck = "";
        Random r = new Random();

        if (minSpecialChars > 0)
            groups |= CharacterGroup.Special;
            
        //--- Build the deck ------------------------------------------------------------------
        // and select one character from each required character group
        for (int i = 0; i <= 3; i++)
        {
            int flag = (int)Math.Pow(2D, (double)i);
            if (FlagIsSet(groupFlags, flag))
            {
                int n = r.Next(CHAR_GROUPS[i].Length);
                result += CHAR_GROUPS[i].Substring(n, 1);
                deck += CHAR_GROUPS[i];
            }
        }

        char[] deckChars = deck.ToCharArray();

        //--- Enforce Minimum-Special-Characters ----------------------------------------------
        // we already have one from the above code.
        for (int i = 2; i <= minSpecialChars; i++)
        {
            int n = r.Next(CHAR_GROUPS[1].Length);
            result += CHAR_GROUPS[1].Substring(n, 1);
        }

        //--- Enforce Length ------------------------------------------------------------------
        // Append additional characters as needed to reach the required length
        if (result.Length < length)
        {
            for (int i = 0; i < 10000; i++)
            {
                int a = 0;
                int b = 0;

                while (a == 0)
                {
                    a = r.Next(deck.Length);
                    b = r.Next(deck.Length);
                }

                char c = deckChars[a];
                deckChars[a] = deckChars[b];
                deckChars[b] = c;
            }

            result += new string(deckChars).Substring(0, length - result.Length);
        }

        //--- Scramble the letters ------------------------------------------------------------
        char[] resultChars = result.ToCharArray();

        for (int i = 0; i < 100; i++)
        {
            int a = 0;
            int b = 0;

            while (a == 0)
            {
                a = r.Next(result.Length);
                b = r.Next(result.Length);
            }

            char c = resultChars[a];
            resultChars[a] = resultChars[b];
            resultChars[b] = c;
        }

        result = new string(resultChars);
        return result;
    }
    private static bool FlagIsSet(int input, int flag)
    {
        int n = (input & flag);
        return (n > 0);
    }
}