[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);
}
}