A console app to see random output.
You can read other Turninger posts which outline my progress building a the Fortuna CPRNG.
So far, we have implemented
BlockCypherCprngGenerator, which fills a
byte with random data using AES to encrypt a counter.
This time, we’re going to write a console app which will let us see random output as hex characters on the console. It will require accepting a seed from the command line to initialise the generator.
The app should also be able to write binary output, suitable for piping to an analysis program like dieharder. And also save output to a file.
Rather than starting with the boilerplate like last time, I’m going to start with the heart of app. Then I’ll work outwards to the interesting parts which support the core. Although it’s really pretty straight forward.
We start by loading, initialising and opening our inputs and outputs.
The core loop is fill a buffer with random bytes and then writes that buffer to the output stream. We use a fixed size buffer until the last request, where we allocate a smaller buffer for whatever is left over.
You can see the actual code in BitBucket, which has some more stuff going on (to print nice things to the console, and handle cancellation via
The first unknown is the
And my use of
var doesn’t help here!
That is, a method that takes a stream and byte array, and does something with them.
In this case, the output stream and our buffer of random bytes, and copies the buffer to the stream.
I’m using it as an abstraction to cope with two different output styles: binary and hex.
I’ve defined my actions inline, because they’re quite simple. The main complexity is writing hex characters (eg: 1B7F9D3A) needs to handle each byte in two halves.
The careful reader will also note that
outputStyle is a global.
Yes, it really is a global
All my command line parsing simply sets static variables.
Its not pretty, nor best practice, but its simple, direct and effective.
Getting the output stream is pretty easy. There are two obvious choices: a file or stdout.
I decided to sneak a
Null output in there, so I could eliminate a potential overhead when benchmarking.
Otherwise, I’m using the shortened
Con for the normal
And the OpenStandardOutput method to get a
Stream, rather than the
Writing binary to a
Stream works much better than a
TextWriter (I tried; it didn’t quite work).
Finally, the main input is some sort of seed value.
There are plenty of places we could get a seed from. For now, you have to pass it in via the command line (although I’m planning to gather entropy from the current system environment later).
Four options this time:
- No seed was supplied: we use an array of zeros.
- A hex string matching the desired key size: we’ll use that exactly as-is.
- A path to a file: grab the SHA256 hash of it.
- Anything else: assume a password and hash to get enough bytes.
You can see the other bits and pieces in BitBucket. They aren’t particularly relevant to getting random bytes, but are rather important to make a functional console app.
- A top level exception handler that wraps everything in a giant try-catch block.
- Command line parsing into static variables - not pretty, but very effective.
- Printing usage / help. Yep, every console app needs this.
- Printing what the program is doing to the console. So you know you have the right arguments.
CTRL+Ccancellation handler. To gracefully end.
Behold! The output of Terninger!
With no argument, we use a null seed, hex output and generate 64 bytes.
Because of the fixed seed, anyone who runs Terninger should get the same “random” bytes. Be this a warning to anyone who things things are random just because they look like garbage! (This kind of thing has caused me significant pain).
Choose a seed and more bytes.
On my rather old laptop, I get between 6.5MB and 7.0MB per second. That’s pretty poor considering benchmarks of more recent hardware for AES are closer to 600MB / sec. But its somewhere to start.
Next step to to analyse the random numbers produced by the generator to see how random they really are.