@@ -16,18 +16,18 @@
17module System.Entropy
17module System.Entropy
18 ( getEntropy,
18 ( getEntropy,
19−#if defined(isWindows)
19+ getHardwareEntropy,
20− module System.EntropyWindows
20+ CryptHandle,
25+#if defined(isWindows)
22import System.EntropyWindows
26import System.EntropyWindows
25− module System.EntropyXen
27import System.EntropyXen
29import System.EntropyXen
29− module System.EntropyNix
31import System.EntropyNix
31import System.EntropyNix
@@ -36,10 +36,42 @@ import qualified Data.ByteString as B
36import Control.Exception (bracket)
36import Control.Exception (bracket)
38-- |Get a specific number of bytes of cryptographically
38-- |Get a specific number of bytes of cryptographically
39−-- secure random data using the system-specific facilities.
39+-- secure random data using the *system-specific* sources.
40+-- (As of 0.4. Verions <0.4 mixed system and hardware sources)
41−-- Use RDRAND if available and XOR with '/dev/urandom' on *nix and CryptAPI when on
42−-- Windows. In short, this entropy is considered cryptographically secure
42+-- The returned random value is considered cryptographically secure but not true entropy.
43−-- but not true entropy.
43+--
44+-- On some platforms this requies a file handle which can lead to resource
45+-- exhaustion in some situations.
46+getEntropy :: Int -- ^ Number of bytes
44−getEntropy :: Int -> IO B.ByteString
47+ -> IO B.ByteString
45getEntropy = bracket openHandle closeHandle . flip hGetEntropy
48getEntropy = bracket openHandle closeHandle . flip hGetEntropy
50+-- |Get a specific number of bytes of cryptographically
51+-- secure random data using a supported *hardware* random bit generator.
53+-- If there is no hardware random number generator then @Nothing@ is returned.
54+-- If any call returns non-Nothing then it should never be @Nothing@ unless
55+-- there has been a hardware failure.
57+-- If trust of the CPU allows it and no context switching is important,
58+-- a bias to the hardware rng with system rng as fall back is trivial:
61+-- let fastRandom nr = maybe (getEntropy nr) pure =<< getHardwareEntropy nr
64+-- The old, @<0.4@, behavior is possible using @xor@ from 'Data.Bits':
68+-- do hwRnd <- maybe (replicate nr 0) BS.unpack <$> getHardwareEntropy nr
69+-- sysRnd <- BS.unpack <$> getEntropy nr
70+-- pure $ BS.pack $ zipWith xor sysRnd hwRnd
73+-- A less maliable mixing can be accomplished by replacing `xor` with a
74+-- composition of concat and cryptographic hash.
75+getHardwareEntropy :: Int -- ^ Number of bytes
76+ -> IO (Maybe B.ByteString)
77+getHardwareEntropy = hardwareRandom