I need to generate random
PIN and
PUK codes which will be used in
SIM profiles. The codes will typically be between 4 and 8 digits.
The random source is a
HSM and is accessed over a HTTP/2 based network connection (actually
gRPC). The cost to call the HSM is high compared to the cost of the number of bytes being requested (for example, to get 20 bytes, it is way more costly to make 20 single bytes requests compared to one 20 byte request). The random digit strings must have the same degree of
randomness as the bytes provided by the HSM.
There is also a requirement to use
Java 11.
I have found two solutions which seem to work well, but I would be interested in hearing about any other ideas, or suggestion on how to improve what I am done.
The first approach is to use a BigInteger, constructed from an array of random bytes large enough to create a value with sufficient length, and then use the last
n digits of the
String representation. Since the String representation does not include leading zero, they may need to prepended to returned value.
I found that if the number of bytes used was too small, then the distribution would be biased, favouring the lower-order digits.
The other approach was to split the bytes in to nibbles/semi-octets, and filter-out any values greater than 9. Doing this, there is the chance that a large number (potentially all) of the bytes provided could contain nibble values which were larger than 9, so it is not possible to predict how many bytes would be needed from the HSM in-advance. I implemented a stateful supplier which would request a number of bytes based on a hint, filter them, and then provide one at a time them as required, If the demand exhausted the number of stored filtered values, it would request another lot of bytes.
Both implementations perform similarly in terms if distribution and execute time, but the using BigInteger around 50% faster.