Last active
August 29, 2015 14:05
-
-
Save MatthewVines/8fb347da3540afdeec52 to your computer and use it in GitHub Desktop.
Generates a random string from a given set of rules about length and charater sets.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static string GenerateRandomString(int minLength, int maxLength, int minLCaseCount, int minUCaseCount, int minNumCount, int minSpecialCount) | |
{ | |
char[] randomString; | |
const string LCaseChars = "abcdefgijkmnopqrstwxyz"; | |
const string UCaseChars = "ABCDEFGHJKLMNPQRSTWXYZ"; | |
const string NumericChars = "23456789"; | |
const string SpecialChars = "*$-+?_&=!%{}/"; | |
Hashtable charGroupsUsed = new Hashtable(); | |
charGroupsUsed.Add("lcase", minLCaseCount); | |
charGroupsUsed.Add("ucase", minUCaseCount); | |
charGroupsUsed.Add("num", minNumCount); | |
charGroupsUsed.Add("special", minSpecialCount); | |
// Because we cannot use the default randomizer, which is based on the | |
// current time (it will produce the same "random" number within a | |
// second), we will use a random number generator to seed the | |
// randomizer. | |
// Use a 4-byte array to fill it with random bytes and convert it then | |
// to an integer value. | |
byte[] randomBytes = new byte[4]; | |
// Generate 4 random bytes. | |
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); | |
rng.GetBytes(randomBytes); | |
// Convert 4 bytes into a 32-bit integer value. | |
int seed = (randomBytes[0] & 0x7f) << 24 | | |
randomBytes[1] << 16 | | |
randomBytes[2] << 8 | | |
randomBytes[3]; | |
// Create a randomizer from the seed. | |
Random random = new Random(seed); | |
// Allocate appropriate memory for the password. | |
if (minLength < maxLength) | |
{ | |
randomString = new char[random.Next(minLength, maxLength + 1)]; | |
} | |
else | |
{ | |
randomString = new char[minLength]; | |
} | |
int requiredCharactersLeft = minLCaseCount + minUCaseCount + minNumCount + minSpecialCount; | |
// Build the password. | |
for (int i = 0; i < randomString.Length; i++) | |
{ | |
string selectableChars = ""; | |
// if we still have plenty of characters left to acheive our minimum requirements. | |
if (requiredCharactersLeft < randomString.Length - i) | |
{ | |
// choose from any group at random | |
selectableChars = LCaseChars + UCaseChars + NumericChars + SpecialChars; | |
} | |
else // we are out of wiggle room, choose from a random group that still needs to have a minimum required. | |
{ | |
// choose only from a group that we need to satisfy a minimum for. | |
foreach (DictionaryEntry charGroup in charGroupsUsed) | |
{ | |
if ((int)charGroup.Value > 0) | |
{ | |
switch (charGroup.Key.ToString()) | |
{ | |
case "lcase": | |
selectableChars += LCaseChars; | |
break; | |
case "ucase": | |
selectableChars += UCaseChars; | |
break; | |
case "num": | |
selectableChars += NumericChars; | |
break; | |
case "special": | |
selectableChars += SpecialChars; | |
break; | |
} | |
} | |
} | |
} | |
// Now that the string is built, get the next random character. | |
char nextChar = selectableChars[random.Next(0, selectableChars.Length - 1)]; | |
// Tac it onto our password. | |
randomString[i] = nextChar; | |
// Now figure out where it came from, and decrement the appropriate minimum value. | |
if (LCaseChars.Contains(nextChar)) | |
{ | |
charGroupsUsed["lcase"] = (int)charGroupsUsed["lcase"] - 1; | |
if ((int)charGroupsUsed["lcase"] >= 0) | |
{ | |
requiredCharactersLeft--; | |
} | |
} | |
else if (UCaseChars.Contains(nextChar)) | |
{ | |
charGroupsUsed["ucase"] = (int)charGroupsUsed["ucase"] - 1; | |
if ((int)charGroupsUsed["ucase"] >= 0) | |
{ | |
requiredCharactersLeft--; | |
} | |
} | |
else if (NumericChars.Contains(nextChar)) | |
{ | |
charGroupsUsed["num"] = (int)charGroupsUsed["num"] - 1; | |
if ((int)charGroupsUsed["num"] >= 0) | |
{ | |
requiredCharactersLeft--; | |
} | |
} | |
else if (SpecialChars.Contains(nextChar)) | |
{ | |
charGroupsUsed["special"] = (int)charGroupsUsed["special"] - 1; | |
if ((int)charGroupsUsed["special"] >= 0) | |
{ | |
requiredCharactersLeft--; | |
} | |
} | |
} | |
return new string(randomString); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment