PwGenCryptoSource class
A PwGenCryptoSource is the random source that the package uses when a recipe’s RandomSource is Nothing. It implements PwGenRandom with the random numbers of the Windows Cryptography API: Next Generation (CNG).
The class has no public member of its own. Its one method, NextInRange, is Private and is reached through a variable of the type PwGenRandom. The package’s own description of the class calls it internal. It is declared without Private, and has neither a Private constructor nor [COMCreatable(False)], so a project can create one with New.
Dim src As PwGenRandom = New PwGenCryptoSource
PwGenError.Clear
Dim n As Long = src.NextInRange(1, 6)
Debug.Print n >= 1 And n <= 6 ' True
Debug.Print src.NextInRange(3, 3) ' 3
A variable declared with the class itself cannot call the method, because it is Private. The compiler reports TB5027, Unrecognized member ‘NextInRange’:
Dim s As New PwGenCryptoSource
Debug.Print s.NextInRange(1, 6)
How the numbers are produced
The source asks Windows for random bytes with BCryptGenRandom from bcrypt.dll. It passes no algorithm handle and the flag BCRYPT_USE_SYSTEM_PREFERRED_RNG, so the generator is the one that Windows prefers for the system. The package’s source comments call the source cryptographically secure. The strength is that of this Windows generator, and the package adds no random numbers of its own.
For each number the source works as follows:
- It asks for four random bytes and reads them as an unsigned 32-bit number r, from 0 to 4294967295.
- It computes the size of the interval, s = upperBound - lowerBound + 1, and the largest multiple of s that is not above 2^32, called the limit.
- If r is not below the limit, it discards r and asks for four new bytes. The discarded numbers are the reason that every number of the interval is equally likely: a plain remainder of r divided by s would favour the small numbers when s does not divide 2^32.
- Otherwise it returns lowerBound + (r mod s).
The class keeps no state. The package creates one instance when it first needs it and shares it.
Errors
The source raises no run-time error. It reports a problem through the last error of the package, PwGenError, and returns 0:
InvalidRange, with the message lowerBound is greater than upperBound, when the bounds are reversed. The origin is an empty string.RngFailed, with the message BCryptGenRandom failed, when the Windows function does not return success. The origin is an empty string. When PwGen.Generate calls the source, it replaces the origin with its own, such asPwGen.Generate.
Dim src As PwGenRandom = New PwGenCryptoSource
PwGenError.Clear
Debug.Print src.NextInRange(5, 1) ' 0
Debug.Print PwGenError.Code ' InvalidRange
Debug.Print PwGenError.Origin = "" ' True
Warning
In version 1.0.8.0, NextInRange does not clear the last error before it starts, and it returns 0 whenever the last error is already set. It raises no error and sets no error of its own, so a direct call made after any earlier failure of the package returns 0 even when the bounds do not include 0, and the last error still belongs to the earlier failure. Call PwGenError.Clear first. The functions of PwGen do this themselves, so a recipe is not affected.
Dim src As PwGenRandom = New PwGenCryptoSource
Dim o As PwGenOptions = PwGenOptions.Alphanumeric
o.Length = 0
PwGen.Generate o
Debug.Print PwGenError.Code ' InvalidLength
Debug.Print src.NextInRange(1, 6) ' 0
Debug.Print PwGenError.Code ' InvalidLength
PwGenError.Clear
Dim n As Long = src.NextInRange(1, 6)
Debug.Print n >= 1 And n <= 6 ' True
Methods
NextInRange
Returns a whole number between two bounds, both included.
Syntax: source.NextInRange ( lowerBound, upperBound ) As Long
The method is Private: it is called through a PwGenRandom variable, as PwGenRandom.NextInRange describes. The two parameters are Long values; lowerBound must not be above upperBound.
Returns the number, or 0 after InvalidRange or RngFailed. The bounds can be any two Long values, in the right order.
See Also
- PwGenRandom interface – the interface the class implements
- PwGenOptions class – the RandomSource property
- PwGenError class – reports
InvalidRangeandRngFailed - tsPwGen Package – the package