Skip to content

Instantly share code, notes, and snippets.

@vadviktor
Created December 30, 2022 16:07
Show Gist options
  • Save vadviktor/e59137cbd64dec2933b3af4407a35395 to your computer and use it in GitHub Desktop.
Save vadviktor/e59137cbd64dec2933b3af4407a35395 to your computer and use it in GitHub Desktop.
Generate random passwords in C#, taken from .Net Framework 4.8.2
// https://github.com/microsoft/referencesource/blob/master/System.Web/CrossSiteScriptingValidation.cs
private static readonly char[] StartingChars = new char[] { '<', '&' };
private static bool IsAtoZ(char c)
{
return c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';
}
private static bool IsDangerousString(string s)
{
for (var i = 0;;)
{
// Look for the start of one of our patterns
var n = s.IndexOfAny(StartingChars, i);
// If not found, the string is safe
if (n < 0) return false;
// If it's the last char, it's safe
if (n == s.Length - 1) return false;
switch (s[n])
{
case '<':
// If the < is followed by a letter or '!', it's unsafe (looks like a tag or HTML comment)
if (IsAtoZ(s[n + 1]) || s[n + 1] == '!' || s[n + 1] == '/' || s[n + 1] == '?') return true;
break;
case '&':
// If the & is followed by a #, it's unsafe (e.g. &#83;)
if (s[n + 1] == '#') return true;
break;
}
// Continue searching
i = n + 1;
}
}
// https://github.com/microsoft/referencesource/blob/master/System.Web/Security/Membership.cs
private static readonly char[] Punctuations = "!@#$%^&*()_-+=[{]};:>|./?".ToCharArray();
public static string GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
{
if (length is < 1 or > 128)
{
throw new ArgumentException("Length is incorrect");
}
if (numberOfNonAlphanumericCharacters > length || numberOfNonAlphanumericCharacters < 0)
{
throw new ArgumentException("Not enough non-alphanumeric characters");
}
string password;
do
{
var buf = new byte[length];
var cBuf = new char[length];
var count = 0;
RandomNumberGenerator.Create().GetBytes(buf);
for (int iter = 0; iter < length; iter++)
{
var i = buf[iter] % 87;
if (i < 10)
cBuf[iter] = (char)('0' + i);
else if (i < 36)
cBuf[iter] = (char)('A' + i - 10);
else if (i < 62)
cBuf[iter] = (char)('a' + i - 36);
else
{
cBuf[iter] = Punctuations[i - 62];
count++;
}
}
if (count < numberOfNonAlphanumericCharacters)
{
int j;
Random rand = new Random();
for (j = 0; j < numberOfNonAlphanumericCharacters - count; j++)
{
int k;
do
{
k = rand.Next(0, length);
} while (!Char.IsLetterOrDigit(cBuf[k]));
cBuf[k] = Punctuations[rand.Next(0, Punctuations.Length)];
}
}
password = new string(cBuf);
} while (IsDangerousString(password));
return password;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment