Skip to main content
corrected invalid to valid and removed magic number of "4" for sizeof(UInt32).
Source Link
Jesse C. Slicer
  • 14.6k
  • 1
  • 40
  • 54

Rather nice! One small improvement I'd make, is change the char[] LegalChars to IEnumerable<char> LegalChars so, for example, a string of invalidvalid characters can be passed in. Here's how I've modified the struct:

public struct SecurePasswordGenerator(int PasswordLength, IEnumerable<char>? LegalChars) : IEnumerable<char>
{
    //was used for test purposes calling from a static method
    ////private readonly int PasswordLength => passwordLength;

    private readonly char[] _legalChars = LegalChars?.ToArray() ?? [];

    public readonly string NextPassword() => new(this.ToArray());

    public static IEnumerable<string> GeneratePasswords(int size, SecurePasswordGenerator generator) =>
        generator.Chunk(size).Select(chunk => new string(chunk));

    readonly IEnumerator<char> IEnumerable<char>.GetEnumerator()
    {
        // ReSharper disable once ComplexConditionExpression
        bool isInvalidChars = _legalChars.Length == 0;

        if (isInvalidChars || PasswordLength <= 0)
        {
            yield break;
        }

        using RandomNumberGenerator rng = RandomNumberGenerator.Create();

        byte[] buffer = new byte[4byte[sizeof(UInt32) * PasswordLength];

        rng.GetBytes(buffer);
        for (int i = 0; i < PasswordLength; i++)
        {
            int offset = 4sizeof(UInt32) * i;
            uint rand = BitConverter.ToUInt32(buffer, offset);

            yield return _legalChars[(int)(rand % _legalChars.Length)];
        }
    }

    [DebuggerHidden, DebuggerStepThrough]
    readonly IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<char>)this).GetEnumerator();
}
```

Rather nice! One small improvement I'd make, is change the char[] LegalChars to IEnumerable<char> LegalChars so, for example, a string of invalid characters can be passed in. Here's how I've modified the struct:

public struct SecurePasswordGenerator(int PasswordLength, IEnumerable<char>? LegalChars) : IEnumerable<char>
{
    //was used for test purposes calling from a static method
    ////private readonly int PasswordLength => passwordLength;

    private readonly char[] _legalChars = LegalChars?.ToArray() ?? [];

    public readonly string NextPassword() => new(this.ToArray());

    public static IEnumerable<string> GeneratePasswords(int size, SecurePasswordGenerator generator) =>
        generator.Chunk(size).Select(chunk => new string(chunk));

    readonly IEnumerator<char> IEnumerable<char>.GetEnumerator()
    {
        // ReSharper disable once ComplexConditionExpression
        bool isInvalidChars = _legalChars.Length == 0;

        if (isInvalidChars || PasswordLength <= 0)
        {
            yield break;
        }

        using RandomNumberGenerator rng = RandomNumberGenerator.Create();

        byte[] buffer = new byte[4 * PasswordLength];

        rng.GetBytes(buffer);
        for (int i = 0; i < PasswordLength; i++)
        {
            int offset = 4 * i;
            uint rand = BitConverter.ToUInt32(buffer, offset);

            yield return _legalChars[(int)(rand % _legalChars.Length)];
        }
    }

    [DebuggerHidden, DebuggerStepThrough]
    readonly IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<char>)this).GetEnumerator();
}
```

Rather nice! One small improvement I'd make, is change the char[] LegalChars to IEnumerable<char> LegalChars so, for example, a string of valid characters can be passed in. Here's how I've modified the struct:

public struct SecurePasswordGenerator(int PasswordLength, IEnumerable<char>? LegalChars) : IEnumerable<char>
{
    //was used for test purposes calling from a static method
    ////private readonly int PasswordLength => passwordLength;

    private readonly char[] _legalChars = LegalChars?.ToArray() ?? [];

    public readonly string NextPassword() => new(this.ToArray());

    public static IEnumerable<string> GeneratePasswords(int size, SecurePasswordGenerator generator) =>
        generator.Chunk(size).Select(chunk => new string(chunk));

    readonly IEnumerator<char> IEnumerable<char>.GetEnumerator()
    {
        // ReSharper disable once ComplexConditionExpression
        bool isInvalidChars = _legalChars.Length == 0;

        if (isInvalidChars || PasswordLength <= 0)
        {
            yield break;
        }

        using RandomNumberGenerator rng = RandomNumberGenerator.Create();

        byte[] buffer = new byte[sizeof(UInt32) * PasswordLength];

        rng.GetBytes(buffer);
        for (int i = 0; i < PasswordLength; i++)
        {
            int offset = sizeof(UInt32) * i;
            uint rand = BitConverter.ToUInt32(buffer, offset);

            yield return _legalChars[(int)(rand % _legalChars.Length)];
        }
    }

    [DebuggerHidden, DebuggerStepThrough]
    readonly IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<char>)this).GetEnumerator();
}
Source Link
Jesse C. Slicer
  • 14.6k
  • 1
  • 40
  • 54

Rather nice! One small improvement I'd make, is change the char[] LegalChars to IEnumerable<char> LegalChars so, for example, a string of invalid characters can be passed in. Here's how I've modified the struct:

public struct SecurePasswordGenerator(int PasswordLength, IEnumerable<char>? LegalChars) : IEnumerable<char>
{
    //was used for test purposes calling from a static method
    ////private readonly int PasswordLength => passwordLength;

    private readonly char[] _legalChars = LegalChars?.ToArray() ?? [];

    public readonly string NextPassword() => new(this.ToArray());

    public static IEnumerable<string> GeneratePasswords(int size, SecurePasswordGenerator generator) =>
        generator.Chunk(size).Select(chunk => new string(chunk));

    readonly IEnumerator<char> IEnumerable<char>.GetEnumerator()
    {
        // ReSharper disable once ComplexConditionExpression
        bool isInvalidChars = _legalChars.Length == 0;

        if (isInvalidChars || PasswordLength <= 0)
        {
            yield break;
        }

        using RandomNumberGenerator rng = RandomNumberGenerator.Create();

        byte[] buffer = new byte[4 * PasswordLength];

        rng.GetBytes(buffer);
        for (int i = 0; i < PasswordLength; i++)
        {
            int offset = 4 * i;
            uint rand = BitConverter.ToUInt32(buffer, offset);

            yield return _legalChars[(int)(rand % _legalChars.Length)];
        }
    }

    [DebuggerHidden, DebuggerStepThrough]
    readonly IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<char>)this).GetEnumerator();
}
```