For example, to seed a new generator with the system secure random
Entropy) and generate some bytes (stepping the generator along
the way) one would do:
gen <- newGenIO :: IO HashDRBG let Right (randomBytes, newGen) = genBytes 1024 gen
or the same thing with your own entropy (throwing exceptions instead of dealing
Either this time):
let gen = throwLeft (newGen entropy) (bytes,gen') = throwLeft (genBytes 1024 gen) in ...
Selecting the underlying hash algorithm is supporting using *DRBGWith types:
gen <- newGenIO :: IO (HmacDRBGWith SHA224)
There are several modifiers that allow you to compose generators together, producing
generators with modified security, reseed, and performance properties.
will xor the random bytes of two generators.
GenBuffered will spark off work
to generate several megabytes of random data and keep that data buffered for
GenAutoReseed will use one generator to automatically reseed
another after every 32 kilobytes of requested randoms.
For a complex example, here is a generator that buffers several megabytes of random values which are an Xor of AES with a SHA384 hash that are each reseeded every 32kb with the output of a SHA512 HMAC generator. (Not to claim this has any enhanced security properties, but just to show the composition can be nested).
gen <- newGenIO :: IO (GenBuffered (GenAutoReseed (GenXor AesCntDRBG (HashDRBGWith SHA384)) HmacDRBG))
- type HmacDRBG = State SHA512
- type HashDRBG = State SHA512
- type CtrDRBG = State AESKey
- type HmacDRBGWith = State
- type HashDRBGWith = State
- type CtrDRBGWith = State
- data GenXor a b
- data GenBuffered g
- data GenAutoReseed a b
- newGenAutoReseed :: (CryptoRandomGen a, CryptoRandomGen b) => ByteString -> Word64 -> Either GenError (GenAutoReseed a b)
- newGenAutoReseedIO :: (CryptoRandomGen a, CryptoRandomGen b) => Word64 -> IO (GenAutoReseed a b)
- module Crypto.Random
- module Crypto.Types
Basic Hash-based Generators
The HMAC DRBG state (of kind * -> *) allowing selection of the underlying hash algorithm (SHA1, SHA224 ... SHA512)
The Hash DRBG state (of kind * -> *) allowing selection of the underlying hash algorithm.
The Hash DRBG state (of kind * -> *) allowing selection of the underlying cipher algorithm.
g :: GenXor a b generates bytes with sub-generators a and b
and exclusive-or's the outputs to produce the resulting bytes.
g :: GenBuffered a is a generator of type
a that attempts to
maintain a buffer of random values size >= 1MB and <= 5MB at any time.
g :: GenAutoReseed a b is a generator of type a that gets
automatically reseeded by generator b upon every 32kB generated.
reseed g ent will reseed both the component generators by
breaking ent up into two parts determined by the genSeedLength of each generator.
genBytes will generate the requested bytes with generator
a and reseed
b if there has been 32KB of generated data since the last reseed.
Note a request for > 32KB of data will be filled in one request to generator
a is reseeded by
genBytesWithEntropy is lifted into the same call for generator
it will still reseed from generator
b if the limit is hit.
Reseed interval: If generator
a needs a
genSeedLength a = a' and generator B
needs reseeded every
2^b bytes then a
GenAutoReseed a b will need reseeded every
2^15 * (2^b / a') bytes. For the common values of
a' = 128 and
2^b = 2^48 this
means reseeding every 2^56 byte. For the example numbers this translates to
about 200 years of continually generating random values at a rate of 10MB/s.
AutoReseed generator construction with custom reseed interval
newGenAutoReseed bs i creates a new
GenAutoReseed with a custom interval
i bytes using the provided entropy in
This is for extremely long running uses of
that can't explicitly reseed as often as a single underlying generator
would need (usually every 2^48 bytes).
newGenAutoReseedIO (2^48) :: IO (Either GenError (GenAutoReseed HashDRBG HashDRBG))
Will last for
2^48 * 2^41 bytes of randomly generated data. That's
2^49 terabytes of random values (128 byte reseeds every 2^48 bytes generated).