Skip to content

Instantly share code, notes, and snippets.

@SamKr
Created January 20, 2020 15:39
Show Gist options
  • Save SamKr/98b3dcd7a0b7b9c8cc00da2e32126909 to your computer and use it in GitHub Desktop.
Save SamKr/98b3dcd7a0b7b9c8cc00da2e32126909 to your computer and use it in GitHub Desktop.
Password Generator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
using System.Text;
public static class PasswordGenerator
{
public static string Generate(int length)
{
return Generate(length, PasswordCharacters.All, null);
}
public static string GenerateDefaultNoSimilars(int length = 8)
{
return Generate(length, PasswordCharacters.AllLetters | PasswordCharacters.AlphaNumeric | PasswordCharacters.Numbers, true);
}
public static string Generate(int length, PasswordCharacters allowedCharacters, bool noSimilarChars = false)
{
var excludeCharacters = new List<char> { '1', 'i', 'I', 'l', 'L', '0', 'o', 'O' };
var exclude = noSimilarChars ? excludeCharacters : null;
return Generate(length, allowedCharacters, exclude);
}
public static string Generate(int length, PasswordCharacters allowedCharacters, IEnumerable<char> excludeCharacters)
{
var password = InternalGenerate(length, allowedCharacters, excludeCharacters, () => new char[length], (pw, ch, index) => pw[index] = ch);
return new string(password);
}
public static SecureString GenerateSecure(int length)
{
return GenerateSecure(length, PasswordCharacters.All, null);
}
public static SecureString GenerateSecure(int length, PasswordCharacters allowedCharacters)
{
return GenerateSecure(length, allowedCharacters, null);
}
public static SecureString GenerateSecure(int length, PasswordCharacters allowedCharacters,
IEnumerable<char> excludeCharacters)
{
var password = InternalGenerate(length, allowedCharacters, excludeCharacters, () => new SecureString(), (pw, ch, index) => pw.AppendChar(ch));
password.MakeReadOnly();
return password;
}
private static T InternalGenerate<T>(int length, PasswordCharacters allowedCharacters, IEnumerable<char> excludeCharacters, Func<T> initialValue, Action<T, char, int> appender)
{
if (length <= 0) throw new ArgumentOutOfRangeException(nameof(length), "Password length must be greater than zero");
var randomBytes = new byte[length];
var randomNumberGenerator = new RNGCryptoServiceProvider();
randomNumberGenerator.GetBytes(randomBytes);
var allowedCharactersString = GenerateAllowedCharactersString(allowedCharacters, excludeCharacters);
var allowedCharactersCount = allowedCharactersString.Length;
var password = initialValue();
for (var i = 0; i < length; i++) appender(password, allowedCharactersString[randomBytes[i] % allowedCharactersCount], i);
return password;
}
private static string GenerateAllowedCharactersString(PasswordCharacters characters, IEnumerable<char> excludeCharacters)
{
var allowedCharactersString = new StringBuilder();
foreach (var type in AllowedPasswordCharacters)
{
if ((characters & type.Key) != type.Key) continue;
if (excludeCharacters == null) allowedCharactersString.Append(type.Value);
else allowedCharactersString.Append(type.Value.Where(c => !excludeCharacters.Contains(c)).ToArray());
}
return allowedCharactersString.ToString();
}
private static readonly Dictionary<PasswordCharacters, string> AllowedPasswordCharacters = new Dictionary<PasswordCharacters, string>(5)
{
{ PasswordCharacters.LowercaseLetters, "abcdefghijklmnopqrstuvwxyz" },
{ PasswordCharacters.UppercaseLetters, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" },
{ PasswordCharacters.Numbers, "0123456789" },
{ PasswordCharacters.Punctuations, @"~`!@#$%^&*()_-+={[}]|\:;""'<,>.?/" },
{ PasswordCharacters.Space, " " }
};
}
[Flags]
public enum PasswordCharacters
{
LowercaseLetters = 0x01,
UppercaseLetters = 0x02,
Numbers = 0x04,
Punctuations = 0x08,
Space = 0x10,
AllLetters = LowercaseLetters | UppercaseLetters,
AlphaNumeric = AllLetters | Numbers,
All = AllLetters | Numbers | Punctuations | Space
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment