Skip to content

Instantly share code, notes, and snippets.

@aliozgur
Last active December 4, 2019 11:03
Show Gist options
  • Save aliozgur/6726abb7eb61df4e47d8e2227274e519 to your computer and use it in GitHub Desktop.
Save aliozgur/6726abb7eb61df4e47d8e2227274e519 to your computer and use it in GitHub Desktop.
Strong password generator with C#
public static class PasswordGenerator
{
[Flags]
public enum PasswordGenerationOptions
{
HasDigit = 0b0001,
HasLowerLetter = 0b0010,
HasUpperLetter = 0b0100,
HasSpecialChar = 0b1000,
All = 0b1111
}
public static PasswordGenerationOptions LettersAndDigits = PasswordGenerationOptions.HasDigit | PasswordGenerationOptions.HasLowerLetter | PasswordGenerationOptions.HasUpperLetter;
public static PasswordGenerationOptions LettersAndSpecialChars = PasswordGenerationOptions.HasSpecialChar | PasswordGenerationOptions.HasLowerLetter | PasswordGenerationOptions.HasUpperLetter;
private static Dictionary<PasswordGenerationOptions, string> _randomChars = new Dictionary<PasswordGenerationOptions, string>()
{
{PasswordGenerationOptions.HasDigit,"123456789"},
{PasswordGenerationOptions.HasUpperLetter,"ABCDEFGHJKLMNPQRSTUVWXYZ"},
{PasswordGenerationOptions.HasLowerLetter,"abcdefghjkmnpqrstuvwxyz"},
{PasswordGenerationOptions.HasSpecialChar,"!@$?"},
};
public static string Generate(int requiredLength = 6, PasswordGenerationOptions options = PasswordGenerationOptions.All)
{
if (requiredLength < 6)
requiredLength = 6;
Random rand = new Random(Environment.TickCount);
var result = String.Empty;
var optionValues = Enum.GetValues(typeof(PasswordGenerationOptions)).Cast<PasswordGenerationOptions>();
var hasSpecialChar = (options & PasswordGenerationOptions.HasSpecialChar) == PasswordGenerationOptions.HasSpecialChar;
// Count provided options discarding PasswordGenerationOptions.All
var optionCount = optionValues.Aggregate(0, (acc, opt) => (options & opt) == opt && opt != PasswordGenerationOptions.All ? acc + 1 : acc);
// Pick all provided options except PasswordGenerationOptions.All
var effectiveOptions = optionValues.Where(opt => (options & opt) == opt && opt != PasswordGenerationOptions.All).ToList();
var specialCharCnt = requiredLength % 2 == 0 ? 2 : 1;
optionCount = hasSpecialChar ? optionCount - 1 : optionCount;
var len = hasSpecialChar ? requiredLength - specialCharCnt : requiredLength;
var minSliceLen = Math.DivRem(len, optionCount, out int rem);
var randomizedOptions = effectiveOptions.Select(opt => new { idx = rand.Next(0, effectiveOptions.Count - 1), option = opt }).OrderBy(r => r.idx).Select(r => r.option).ToList();
foreach (var option in randomizedOptions)
{
var isOptionHasSpecialChar = option == PasswordGenerationOptions.HasSpecialChar;
// PasswordGenerationOptions.HasSpecialChar has fixed slice length of 2
var sliceLen = isOptionHasSpecialChar ? specialCharCnt : minSliceLen;
result += PickChars(option, sliceLen);
// Pick the extra resulting from the remainder
if (!isOptionHasSpecialChar && rem > 0)
{
result += PickChars(option, 1);
rem--;
}
}
return Randomize(result);
}
private static string PickChars(PasswordGenerationOptions option, int count)
{
var result = String.Empty;
Random rand = new Random(Environment.TickCount);
var allChars = _randomChars[option];
for (var i = 0; i < count; i++)
{
result += allChars[rand.Next(0, allChars.Length - 1)];
}
return result;
}
private static string Randomize(string value)
{
Random r = new Random();
var len = value.Length;
return new string(value.ToCharArray().OrderBy(s => r.Next(0, len - 1)).ToArray());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment