git.iko.soy/typeable/entropy
on main help sign in
Add some docs on the new getHardwareEntropy
6c7df01Thomas M. DuBuisson
System/Entropy.hs+43−11
@@ -16,18 +16,18 @@
16
16
17module System.Entropy
17module System.Entropy
18 ( getEntropy,
18 ( getEntropy,
19−#if defined(isWindows)
19+ getHardwareEntropy,
20− module System.EntropyWindows
20+ CryptHandle,
21+ openHandle,
22+ hGetEntropy,
23+ closeHandle
21 ) where
24 ) where
25+#if defined(isWindows)
22import System.EntropyWindows
26import System.EntropyWindows
23#else
27#else
24#ifdef XEN
28#ifdef XEN
25− module System.EntropyXen
26− ) where
27import System.EntropyXen
29import System.EntropyXen
28#else
30#else
29− module System.EntropyNix
30− ) where
31import System.EntropyNix
31import System.EntropyNix
32#endif
32#endif
33#endif
33#endif
@@ -36,10 +36,42 @@ import qualified Data.ByteString as B
36import Control.Exception (bracket)
36import Control.Exception (bracket)
37
37
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)
40--
41--
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
49+
50+-- |Get a specific number of bytes of cryptographically
51+-- secure random data using a supported *hardware* random bit generator.
52+--
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.
56+--
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:
59+--
60+-- @
61+-- let fastRandom nr = maybe (getEntropy nr) pure =<< getHardwareEntropy nr
62+-- @
63+--
64+-- The old, @<0.4@, behavior is possible using @xor@ from 'Data.Bits':
65+--
66+-- @
67+-- let oldRandom nr =
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
71+-- @
72+--
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
System/EntropyNix.hs+4−4
@@ -13,7 +13,7 @@ module System.EntropyNix
13 , openHandle
13 , openHandle
14 , hGetEntropy
14 , hGetEntropy
15 , closeHandle
15 , closeHandle
16− , hardwareRNG
16+ , hardwareRandom
17 ) where
17 ) where
18
18
19import Control.Monad (liftM, when)
19import Control.Monad (liftM, when)
@@ -46,9 +46,9 @@ data CryptHandle
46-- Supported hardware:
46-- Supported hardware:
47-- * RDRAND
47-- * RDRAND
48-- * Patches welcome
48-- * Patches welcome
49−hardwareRNG :: Int -> IO (Maybe B.ByteString)
49+hardwareRandom :: Int -> IO (Maybe B.ByteString)
50#ifdef HAVE_RDRAND
50#ifdef HAVE_RDRAND
51−hardwareRNG n =
51+hardwareRandom n =
52 do b <- cpuHasRdRand
52 do b <- cpuHasRdRand
53 if b
53 if b
54 then Just <$> B.create n (\ptr ->
54 then Just <$> B.create n (\ptr ->
@@ -56,7 +56,7 @@ hardwareRNG n =
56 when (r /= 0) (fail "RDRand failed to gather entropy"))
56 when (r /= 0) (fail "RDRand failed to gather entropy"))
57 else pure Nothing
57 else pure Nothing
58#else
58#else
59−hardwareRNG _ = pure Nothing
59+hardwareRandom _ = pure Nothing
60#endif
60#endif
61
61
62-- |Open a `CryptHandle`
62-- |Open a `CryptHandle`
System/EntropyWindows.hs+5−5
@@ -12,7 +12,7 @@ module System.EntropyWindows
12 , openHandle
12 , openHandle
13 , hGetEntropy
13 , hGetEntropy
14 , closeHandle
14 , closeHandle
15− , hardwareRNG
15+ , hardwareRandom
16 ) where
16 ) where
17
17
18import Control.Monad (liftM, when)
18import Control.Monad (liftM, when)
@@ -73,9 +73,9 @@ data CryptHandle
73-- Supported hardware:
73-- Supported hardware:
74-- * RDRAND
74-- * RDRAND
75-- * Patches welcome
75-- * Patches welcome
76−hardwareRNG :: Int -> IO (Maybe B.ByteString)
76+hardwareRandom :: Int -> IO (Maybe B.ByteString)
77#ifdef HAVE_RDRAND
77#ifdef HAVE_RDRAND
78−hardwareRNG n =
78+hardwareRandom n =
79 do b <- cpuHasRdRand
79 do b <- cpuHasRdRand
80 if b
80 if b
81 then Just <$> BI.create n (\ptr ->
81 then Just <$> BI.create n (\ptr ->
@@ -83,7 +83,7 @@ hardwareRNG n =
83 when (r /= 0) (fail "RDRand failed to gather entropy"))
83 when (r /= 0) (fail "RDRand failed to gather entropy"))
84 else pure Nothing
84 else pure Nothing
85#else
85#else
86−hardwareRNG _ = pure Nothing
86+hardwareRandom _ = pure Nothing
87#endif
87#endif
88
88
89-- Define the constants we need from WinCrypt.h
89-- Define the constants we need from WinCrypt.h
@@ -135,5 +135,5 @@ closeHandle :: CryptHandle -> IO ()
135closeHandle (CH h) = cryptReleaseCtx h
135closeHandle (CH h) = cryptReleaseCtx h
136
136
137-- |Read from `CryptHandle`
137-- |Read from `CryptHandle`
138−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
138+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
139hGetEntropy (CH h) n = cryptGenRandom h n
139hGetEntropy (CH h) n = cryptGenRandom h n
System/EntropyXen.hs+2−2
@@ -55,8 +55,8 @@ closeHandle UseRdRand = return ()
55-- Supported hardware:
55-- Supported hardware:
56-- * RDRAND
56-- * RDRAND
57-- * Patches welcome
57-- * Patches welcome
58−hardwareRNG :: Int -> IO (Maybe B.ByteString)
58+hardwareRandom :: Int -> IO (Maybe B.ByteString)
59−hardwareRNG sz = Just <$> hGetEntropy UseRdRand sz
59+hardwareRandom sz = Just <$> hGetEntropy UseRdRand sz
60
60
61-- |Read random data from a `CryptHandle`, which uses RDRAND (when on Xen)
61-- |Read random data from a `CryptHandle`, which uses RDRAND (when on Xen)
62hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
62hGetEntropy :: CryptHandle -> Int -> IO B.ByteString