Skip to content

Instantly share code, notes, and snippets.

@xt0rted
Last active July 21, 2025 20:24
Show Gist options
  • Select an option

  • Save xt0rted/ec780f5d404fb2b6967b18d05da033ca to your computer and use it in GitHub Desktop.

Select an option

Save xt0rted/ec780f5d404fb2b6967b18d05da033ca to your computer and use it in GitHub Desktop.

Revisions

  1. xt0rted revised this gist Jun 2, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Code.cs
    Original file line number Diff line number Diff line change
    @@ -211,6 +211,7 @@ public override int Next(int minValue, int maxValue)
    while (true)
    {
    _rng.GetBytes(_uint32Buffer);

    var rand = BitConverter.ToUInt32(_uint32Buffer, 0);

    var max = 1 + (long)uint.MaxValue;
  2. xt0rted revised this gist Jun 2, 2021. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion Code.cs
    Original file line number Diff line number Diff line change
    @@ -171,7 +171,6 @@ public class PasswordOptions
    public int Length { get; set; }
    }

    // Copied from https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom
    // Copied from https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom
    public class CryptoRandom : Random
    {
  3. xt0rted revised this gist Jun 2, 2021. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion Code.cs
    Original file line number Diff line number Diff line change
    @@ -171,6 +171,7 @@ public class PasswordOptions
    public int Length { get; set; }
    }

    // Copied from https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom
    // Copied from https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom
    public class CryptoRandom : Random
    {
    @@ -181,9 +182,11 @@ public CryptoRandom()
    {
    }

    #pragma warning disable IDE0060 // Remove unused parameter
    public CryptoRandom(int ignoredSeed)
    {
    }
    #pragma warning restore IDE0060 // Remove unused parameter

    public override int Next()
    {
    @@ -211,7 +214,7 @@ public override int Next(int minValue, int maxValue)
    _rng.GetBytes(_uint32Buffer);
    var rand = BitConverter.ToUInt32(_uint32Buffer, 0);

    var max = (1 + (long)uint.MaxValue);
    var max = 1 + (long)uint.MaxValue;
    var remainder = max % diff;

    if (rand < max - remainder)
  4. xt0rted revised this gist Jun 2, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Code.cs
    Original file line number Diff line number Diff line change
    @@ -171,7 +171,7 @@ public class PasswordOptions
    public int Length { get; set; }
    }

    // Coppied from https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom
    // Copied from https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom
    public class CryptoRandom : Random
    {
    private RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
  5. xt0rted revised this gist Jun 2, 2021. 1 changed file with 14 additions and 6 deletions.
    20 changes: 14 additions & 6 deletions Code.cs
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,7 @@ public static string Generate(PasswordOptions options)
    const string numberChars = "23456789"; // no 01
    const string specialChars = "!@#$%^&*";

    string allChars = "";
    var allChars = "";

    var positions = new List<char>();

    @@ -34,7 +34,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinLowercase > 0)
    {
    for (int i = 0; i < options.MinLowercase; i++)
    for (var i = 0; i < options.MinLowercase; i++)
    {
    positions.Add('l');
    }
    @@ -47,7 +47,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinUppercase > 0)
    {
    for (int i = 0; i < options.MinUppercase; i++)
    for (var i = 0; i < options.MinUppercase; i++)
    {
    positions.Add('u');
    }
    @@ -60,7 +60,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinNumbers > 0)
    {
    for (int i = 0; i < options.MinNumbers; i++)
    for (var i = 0; i < options.MinNumbers; i++)
    {
    positions.Add('n');
    }
    @@ -73,7 +73,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinSpecial > 0)
    {
    for (int i = 0; i < options.MinSpecial; i++)
    for (var i = 0; i < options.MinSpecial; i++)
    {
    positions.Add('s');
    }
    @@ -91,7 +91,7 @@ public static string Generate(PasswordOptions options)

    var password = "";

    for (int i = 0; i < positions.Count; i++)
    for (var i = 0; i < positions.Count; i++)
    {
    string positionChars = null;
    switch (positions[i])
    @@ -153,13 +153,21 @@ private static void ShuffleList<T>(Random rnd, List<T> list)
    public class PasswordOptions
    {
    public bool UseLowercase { get; set; }

    public bool UseUppercase { get; set; }

    public bool UseNumbers { get; set; }

    public bool UseSpecial { get; set; }

    public int MinLowercase { get; set; }

    public int MinUppercase { get; set; }

    public int MinNumbers { get; set; }

    public int MinSpecial { get; set; }

    public int Length { get; set; }
    }

  6. xt0rted revised this gist Jun 2, 2021. 2 changed files with 74 additions and 17 deletions.
    89 changes: 74 additions & 15 deletions Code.cs
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,7 @@ public static string Generate(PasswordOptions options)
    const string numberChars = "23456789"; // no 01
    const string specialChars = "!@#$%^&*";

    var allChars = "";
    string allChars = "";

    var positions = new List<char>();

    @@ -34,7 +34,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinLowercase > 0)
    {
    for (var i = 0; i < options.MinLowercase; i++)
    for (int i = 0; i < options.MinLowercase; i++)
    {
    positions.Add('l');
    }
    @@ -47,7 +47,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinUppercase > 0)
    {
    for (var i = 0; i < options.MinUppercase; i++)
    for (int i = 0; i < options.MinUppercase; i++)
    {
    positions.Add('u');
    }
    @@ -60,7 +60,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinNumbers > 0)
    {
    for (var i = 0; i < options.MinNumbers; i++)
    for (int i = 0; i < options.MinNumbers; i++)
    {
    positions.Add('n');
    }
    @@ -73,7 +73,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinSpecial > 0)
    {
    for (var i = 0; i < options.MinSpecial; i++)
    for (int i = 0; i < options.MinSpecial; i++)
    {
    positions.Add('s');
    }
    @@ -85,13 +85,13 @@ public static string Generate(PasswordOptions options)
    positions.Add('a');
    }

    var rnd = new Random();
    var rnd = new CryptoRandom();

    ShuffleList(rnd, positions);

    var password = "";

    for (var i = 0; i < positions.Count; i++)
    for (int i = 0; i < positions.Count; i++)
    {
    string positionChars = null;
    switch (positions[i])
    @@ -153,20 +153,79 @@ private static void ShuffleList<T>(Random rnd, List<T> list)
    public class PasswordOptions
    {
    public bool UseLowercase { get; set; }

    public bool UseUppercase { get; set; }

    public bool UseNumbers { get; set; }

    public bool UseSpecial { get; set; }

    public int MinLowercase { get; set; }

    public int MinUppercase { get; set; }

    public int MinNumbers { get; set; }

    public int MinSpecial { get; set; }

    public int Length { get; set; }
    }

    // Coppied from https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom
    public class CryptoRandom : Random
    {
    private RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
    private byte[] _uint32Buffer = new byte[4];

    public CryptoRandom()
    {
    }

    public CryptoRandom(int ignoredSeed)
    {
    }

    public override int Next()
    {
    _rng.GetBytes(_uint32Buffer);

    return BitConverter.ToInt32(_uint32Buffer, 0) & 0x7FFFFFFF;
    }

    public override int Next(int maxValue)
    {
    if (maxValue < 0) throw new ArgumentOutOfRangeException(nameof(maxValue));

    return Next(0, maxValue);
    }

    public override int Next(int minValue, int maxValue)
    {
    if (minValue > maxValue) throw new ArgumentOutOfRangeException(nameof(minValue));
    if (minValue == maxValue) return minValue;

    var diff = maxValue - minValue;

    while (true)
    {
    _rng.GetBytes(_uint32Buffer);
    var rand = BitConverter.ToUInt32(_uint32Buffer, 0);

    var max = (1 + (long)uint.MaxValue);
    var remainder = max % diff;

    if (rand < max - remainder)
    {
    return (int)(minValue + (rand % diff));
    }
    }
    }

    public override double NextDouble()
    {
    _rng.GetBytes(_uint32Buffer);

    var rand = BitConverter.ToUInt32(_uint32Buffer, 0);

    return rand / (1.0 + uint.MaxValue);
    }

    public override void NextBytes(byte[] buffer)
    {
    if (buffer is null) throw new ArgumentNullException(nameof(buffer));

    _rng.GetBytes(buffer);
    }
    }
    2 changes: 0 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -7,5 +7,3 @@ A couple minor changes to this version from the original are:
    - The exclusion of all vowels
    - The addition of a no consecutive character check
    - No ambiguous characters by default

    Ideally the use of `System.Random` would be replaced with `RNGCryptoServiceProvider` but that's out of scope of my use for this right now.
  7. xt0rted revised this gist Jun 2, 2021. 1 changed file with 27 additions and 19 deletions.
    46 changes: 27 additions & 19 deletions Code.cs
    Original file line number Diff line number Diff line change
    @@ -15,19 +15,6 @@ void Main()
    RandomPasswordGenerator.Generate(options).Dump();
    }

    public class PasswordOptions
    {
    public bool UseLowercase { get; set; }
    public bool UseUppercase { get; set; }
    public bool UseNumbers { get; set; }
    public bool UseSpecial { get; set; }
    public int MinLowercase { get; set; }
    public int MinUppercase { get; set; }
    public int MinNumbers { get; set; }
    public int MinSpecial { get; set; }
    public int Length { get; set; }
    }

    public class RandomPasswordGenerator
    {
    public static string Generate(PasswordOptions options)
    @@ -37,7 +24,7 @@ public static string Generate(PasswordOptions options)
    const string numberChars = "23456789"; // no 01
    const string specialChars = "!@#$%^&*";

    string allChars = "";
    var allChars = "";

    var positions = new List<char>();

    @@ -47,7 +34,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinLowercase > 0)
    {
    for (int i = 0; i < options.MinLowercase; i++)
    for (var i = 0; i < options.MinLowercase; i++)
    {
    positions.Add('l');
    }
    @@ -60,7 +47,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinUppercase > 0)
    {
    for (int i = 0; i < options.MinUppercase; i++)
    for (var i = 0; i < options.MinUppercase; i++)
    {
    positions.Add('u');
    }
    @@ -73,7 +60,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinNumbers > 0)
    {
    for (int i = 0; i < options.MinNumbers; i++)
    for (var i = 0; i < options.MinNumbers; i++)
    {
    positions.Add('n');
    }
    @@ -86,7 +73,7 @@ public static string Generate(PasswordOptions options)

    if (options.MinSpecial > 0)
    {
    for (int i = 0; i < options.MinSpecial; i++)
    for (var i = 0; i < options.MinSpecial; i++)
    {
    positions.Add('s');
    }
    @@ -104,7 +91,7 @@ public static string Generate(PasswordOptions options)

    var password = "";

    for (int i = 0; i < positions.Count; i++)
    for (var i = 0; i < positions.Count; i++)
    {
    string positionChars = null;
    switch (positions[i])
    @@ -162,3 +149,24 @@ private static void ShuffleList<T>(Random rnd, List<T> list)
    }
    }
    }

    public class PasswordOptions
    {
    public bool UseLowercase { get; set; }

    public bool UseUppercase { get; set; }

    public bool UseNumbers { get; set; }

    public bool UseSpecial { get; set; }

    public int MinLowercase { get; set; }

    public int MinUppercase { get; set; }

    public int MinNumbers { get; set; }

    public int MinSpecial { get; set; }

    public int Length { get; set; }
    }
  8. xt0rted revised this gist Jun 2, 2021. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions Code.cs
    Original file line number Diff line number Diff line change
    @@ -58,7 +58,7 @@ public static string Generate(PasswordOptions options)
    {
    allChars += uppercaseChars;

    if (options.UseUppercase && options.MinUppercase > 0)
    if (options.MinUppercase > 0)
    {
    for (int i = 0; i < options.MinUppercase; i++)
    {
    @@ -71,7 +71,7 @@ public static string Generate(PasswordOptions options)
    {
    allChars += numberChars;

    if (options.UseNumbers && options.MinNumbers > 0)
    if (options.MinNumbers > 0)
    {
    for (int i = 0; i < options.MinNumbers; i++)
    {
    @@ -84,7 +84,7 @@ public static string Generate(PasswordOptions options)
    {
    allChars += specialChars;

    if (options.UseSpecial && options.MinSpecial > 0)
    if (options.MinSpecial > 0)
    {
    for (int i = 0; i < options.MinSpecial; i++)
    {
  9. xt0rted revised this gist Jun 2, 2021. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -6,5 +6,6 @@ A couple minor changes to this version from the original are:

    - The exclusion of all vowels
    - The addition of a no consecutive character check
    - No ambiguous characters by default

    Ideally the use of `System.Random` would be replaced with `RNGCryptoServiceProvider` but that's out of scope of my use for this right now.
  10. xt0rted created this gist Jun 2, 2021.
    164 changes: 164 additions & 0 deletions Code.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,164 @@
    void Main()
    {
    var options = new PasswordOptions
    {
    Length = 13,
    MinLowercase = 2,
    MinNumbers = 2,
    MinSpecial = 1,
    MinUppercase = 2,
    UseLowercase = true,
    UseNumbers = true,
    UseSpecial = true,
    UseUppercase = true,
    };
    RandomPasswordGenerator.Generate(options).Dump();
    }

    public class PasswordOptions
    {
    public bool UseLowercase { get; set; }
    public bool UseUppercase { get; set; }
    public bool UseNumbers { get; set; }
    public bool UseSpecial { get; set; }
    public int MinLowercase { get; set; }
    public int MinUppercase { get; set; }
    public int MinNumbers { get; set; }
    public int MinSpecial { get; set; }
    public int Length { get; set; }
    }

    public class RandomPasswordGenerator
    {
    public static string Generate(PasswordOptions options)
    {
    const string lowercaseChars = "bcdfghjkmnpqrstvwxyz"; // no aeiou
    const string uppercaseChars = "BCDFGHJKLMNPQRSTVWXYZ"; // no AEIOU
    const string numberChars = "23456789"; // no 01
    const string specialChars = "!@#$%^&*";

    string allChars = "";

    var positions = new List<char>();

    if (options.UseLowercase)
    {
    allChars += lowercaseChars;

    if (options.MinLowercase > 0)
    {
    for (int i = 0; i < options.MinLowercase; i++)
    {
    positions.Add('l');
    }
    }
    }

    if (options.UseUppercase)
    {
    allChars += uppercaseChars;

    if (options.UseUppercase && options.MinUppercase > 0)
    {
    for (int i = 0; i < options.MinUppercase; i++)
    {
    positions.Add('u');
    }
    }
    }

    if (options.UseNumbers)
    {
    allChars += numberChars;

    if (options.UseNumbers && options.MinNumbers > 0)
    {
    for (int i = 0; i < options.MinNumbers; i++)
    {
    positions.Add('n');
    }
    }
    }

    if (options.UseSpecial)
    {
    allChars += specialChars;

    if (options.UseSpecial && options.MinSpecial > 0)
    {
    for (int i = 0; i < options.MinSpecial; i++)
    {
    positions.Add('s');
    }
    }
    }

    while (positions.Count < options.Length)
    {
    positions.Add('a');
    }

    var rnd = new Random();

    ShuffleList(rnd, positions);

    var password = "";

    for (int i = 0; i < positions.Count; i++)
    {
    string positionChars = null;
    switch (positions[i])
    {
    case 'l':
    positionChars = lowercaseChars;
    break;

    case 'u':
    positionChars = uppercaseChars;
    break;

    case 'n':
    positionChars = numberChars;
    break;

    case 's':
    positionChars = specialChars;
    break;

    case 'a':
    positionChars = allChars;
    break;

    default:
    break;
    }

    var randomCharIndex = rnd.Next(0, positionChars.Length - 1);
    var randomChar = positionChars[randomCharIndex];

    // no consecutive characters in a row
    if (i > 0 && password[i - 1] == randomChar)
    {
    i--;
    continue;
    }

    password += randomChar;
    }

    return password;
    }

    private static void ShuffleList<T>(Random rnd, List<T> list)
    {
    var length = list.Count - 1;
    while (length > 0)
    {
    var i = rnd.Next(0, length);

    (list[i], list[length]) = (list[length], list[i]);

    length--;
    }
    }
    }
    10 changes: 10 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    # README

    This is a C# port of Bitwarden's [random password algorithm](https://github.com/bitwarden/jslib/blob/b1d9b84eae451ec2edaf18b7256dd8361b0310ca/src/services/passwordGeneration.service.ts#L44-L155).

    A couple minor changes to this version from the original are:

    - The exclusion of all vowels
    - The addition of a no consecutive character check

    Ideally the use of `System.Random` would be replaced with `RNGCryptoServiceProvider` but that's out of scope of my use for this right now.