git.iko.soy/typeable/entropy
on main help sign in
Separate system and HW entropy sources.

Since this was once a hot topic this commit deserves a few comments. Some users are resistant to the inclusion of RDRAND, most notably issue #30 but also the unfortunately-heated issue #14 (now ancient). This is because the ease with which a backdoor could live inside any hardware RNG and how especially damaging it can be if able to peek at the inputs of other sources. My stance - prior and present - has been that software back-doors (such as one impacting `urandom`) are of greater concern wrt mass-surveillance or APTs. I'd even cynically say people are unintentionally trusting UPS and their front porch more than Intel. What has changed, aside from my willingness to spend time on this while waiting for a delayed flight, is 1. I had agreed that the entropy package is supposed to be lower-level in that it provides the most fundamental primitives of access to the system _and_ the hardware RNG as rather blatantly evidenced by the very module name it occupies and 2. I have a long-running concern that eventually someone disgruntled will fork entropy, rather than pursue any of the discussed alternatives for which I'd accept a patch, and thus cause more fragmentation and package clutter for upstream devs. The community is already fragile in too many regards. Let's reflect on the first issue - that `entropy` and any module claiming the name `System.Random` is low level and should provide the most primitive operations. It would be appropriate to develop a light weight and formally analyzed randomness pool such as Fortuna. Entropy could be a dependency of this library. I acknowledge the benefit to complexity ratio is speculative and require buy-in to a mental model of the adversary that, discussions have revealed, is unpopular. -TomMD

commit16309d3134fdc39af71f7121432f5078290a883e authorThomas M. DuBuisson <tommd@galois.com> dateThu 12 Oct 2017, 19:23 (9 years ago) parent43457a7
5 files changed+74−50
README.md+19−3 System/EntropyNix.hs+19−21 System/EntropyWindows.hs+21−21 System/EntropyXen.hs+12−2 entropy.cabal+3−3
README.md+19−3
@@ -1,9 +1,25 @@
11# Introduction
22
3−This package allows Haskell users to easily acquire entropy for use in
4−critical security applications by calling out to either windows crypto api,
5−unix/linux's `/dev/urandom`, or the RDRAND instruction.
3+This package allows Haskell users to easily acquire entropy for use in critical
4+security applications by calling out to either windows crypto api, unix/linux's
5+`/dev/urandom`. Hardware RNGs (currently RDRAND, patches welcome) are supported
6+via the `hardwareRNG` function.
7+
8+If you wish to obtain an XOR of the hardware and system RNG consider:
9+
10+```
11+import Data.Bits (xor)
12+import qualified Data.ByteString as B
13+import qualified Control.Exception as X
14+
15+xorRNG sz = do hw <- hardwareRNG sz
16+ h <- openHandle
17+ sys <- hGetEntropy h `X.finally` closeHandle h
18+ pure $ B.pack $ B.zipWith xor hw sys
19+```
620
721This package supports Windows, {li,u}nix, QNX, and has preliminary support for HaLVM.
822
23+Typically tested on Linux and OSX - testers are as welcome as patches.
24+
925[![Build Status](https://travis-ci.org/TomMD/entropy.svg?branch=master)](https://travis-ci.org/TomMD/entropy)
System/EntropyNix.hs+19−21
@@ -13,6 +13,7 @@ module System.EntropyNix
1313 , openHandle
1414 , hGetEntropy
1515 , closeHandle
16+ , hardwareRNG
1617 ) where
1718
1819import Control.Monad (liftM, when)
@@ -38,20 +39,29 @@ source = "/dev/urandom"
3839-- |Handle for manual resource management
3940data CryptHandle
4041 = CH Fd
42+
43+-- | Get random values from the hardward RNG or return Nothing if no
44+-- supported hardware RNG is available.
45+--
46+-- Supported hardware:
47+-- * RDRAND
48+-- * Patches welcome
49+hardwareRNG :: Int -> IO (Maybe B.ByteString)
4150#ifdef HAVE_RDRAND
42− | UseRdRand Fd
51+hardwareRNG n =
52+ do b <- cpuHasRdRand
53+ if b
54+ then Just <$> B.create n (\ptr ->
55+ do r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
56+ when (r /= 0) (fail "RDRand failed to gather entropy"))
57+ else pure Nothing
58+#else
59+hardwareRNG _ = pure Nothing
4360#endif
4461
4562-- |Open a `CryptHandle`
4663openHandle :: IO CryptHandle
47−openHandle = do
48−#ifdef HAVE_RDRAND
49− b <- cpuHasRdRand
50− if b then UseRdRand `fmap` nonRDRandHandle
51− else CH `fmap` nonRDRandHandle
52−#else
53− CH `fmap` nonRDRandHandle
54−#endif
64+openHandle = do CH `fmap` nonRDRandHandle
5565 where
5666 nonRDRandHandle :: IO Fd
5767 nonRDRandHandle = openFd source ReadOnly Nothing defaultFileFlags
@@ -59,22 +69,10 @@ openHandle = do
5969-- |Close the `CryptHandle`
6070closeHandle :: CryptHandle -> IO ()
6171closeHandle (CH h) = closeFd h
62−#ifdef HAVE_RDRAND
63−closeHandle (UseRdRand h) = closeFd h
64−#endif
6572
6673-- |Read random data from a `CryptHandle`
6774hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
6875hGetEntropy (CH h) = fdReadBS h
69−#ifdef HAVE_RDRAND
70−hGetEntropy (UseRdRand h) = \n ->
71− do bsURandom <- fdReadBS h n
72− bsRDRAND <- B.create n $ \ptr -> do
73− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
74− when (r /= 0)
75− (fail "RDRand failed to gather entropy")
76− return $ B.pack $ B.zipWith xor bsURandom bsRDRAND
77−#endif
7876
7977fdReadBS :: Fd -> Int -> IO B.ByteString
8078fdReadBS fd n =
System/EntropyWindows.hs+21−21
@@ -4,7 +4,7 @@
44 Stability: beta
55 Portability: portable
66
7− Obtain entropy from system sources or x86 RDRAND when available.
7+ Obtain entropy from system sources.
88-}
99
1010module System.EntropyWindows
@@ -12,6 +12,7 @@ module System.EntropyWindows
1212 , openHandle
1313 , hGetEntropy
1414 , closeHandle
15+ , hardwareRNG
1516 ) where
1617
1718import Control.Monad (liftM, when)
@@ -64,8 +65,25 @@ cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
6465
6566data CryptHandle
6667 = CH Word32
68+
69+
70+-- | Get random values from the hardward RNG or return Nothing if no
71+-- supported hardware RNG is available.
72+--
73+-- Supported hardware:
74+-- * RDRAND
75+-- * Patches welcome
76+hardwareRNG :: Int -> IO (Maybe B.ByteString)
6777#ifdef HAVE_RDRAND
68− | UseRdRand Word32
78+hardwareRNG n =
79+ do b <- cpuHasRdRand
80+ if b
81+ then Just <$> BI.create n (\ptr ->
82+ do r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
83+ when (r /= 0) (fail "RDRand failed to gather entropy"))
84+ else pure Nothing
85+#else
86+hardwareRNG _ = pure Nothing
6987#endif
7088
7189-- Define the constants we need from WinCrypt.h
@@ -110,30 +128,12 @@ cryptReleaseCtx h = do
110128
111129-- |Open a handle from which random data can be read
112130openHandle :: IO CryptHandle
113−openHandle = do
114−#ifdef HAVE_RDRAND
115− b <- cpuHasRdRand
116− if b then UseRdRand `fmap` cryptAcquireCtx
117− else do
118−#endif
119− CH `fmap` cryptAcquireCtx
131+openHandle = CH `fmap` cryptAcquireCtx
120132
121133-- |Close the `CryptHandle`
122134closeHandle :: CryptHandle -> IO ()
123135closeHandle (CH h) = cryptReleaseCtx h
124−#ifdef HAVE_RDRAND
125−closeHandle (UseRdRand h) = cryptReleaseCtx h
126−#endif
127136
128137-- |Read from `CryptHandle`
129138hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
130139hGetEntropy (CH h) n = cryptGenRandom h n
131−#ifdef HAVE_RDRAND
132−hGetEntropy (UseRdRand h) n =
133− do bsRDRAND <- BI.create n $ \ptr -> do
134− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
135− when (r /= 0)
136− (fail "RDRand failed to gather entropy")
137− bsWinCrypt <- cryptGenRandom h n
138− return $ B.pack $ B.zipWith xor bsRDRAND bsWinCrypt
139−#endif
System/EntropyXen.hs+12−2
@@ -4,7 +4,7 @@
44 Stability: beta
55 Portability: portable
66
7− Obtain entropy from system sources or x86 RDRAND when available.
7+ Obtain entropy from RDRAND when available.
88
99-}
1010
@@ -13,6 +13,7 @@ module System.EntropyXen
1313 , openHandle
1414 , hGetEntropy
1515 , closeHandle
16+ , hardwardRNG
1617 ) where
1718
1819import Control.Monad (liftM, when)
@@ -48,7 +49,16 @@ openHandle = do
4849closeHandle :: CryptHandle -> IO ()
4950closeHandle UseRdRand = return ()
5051
51−-- |Read random data from a `CryptHandle`
52+-- | Get random values from the hardward RNG or return Nothing if no
53+-- supported hardware RNG is available.
54+--
55+-- Supported hardware:
56+-- * RDRAND
57+-- * Patches welcome
58+hardwareRNG :: Int -> IO (Maybe B.ByteString)
59+hardwareRNG sz = Just <$> hGetEntropy UseRdRand sz
60+
61+-- |Read random data from a `CryptHandle`, which uses RDRAND (when on Xen)
5262hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
5363hGetEntropy UseRdRand = \n -> do
5464 B.create n $ \ptr -> do
entropy.cabal+3−3
@@ -1,5 +1,5 @@
11name: entropy
2−version: 0.3.8
2+version: 0.4
33description: A platform independent method to obtain cryptographically strong entropy
44 (RDRAND when available anywhere, urandom on nix, CryptAPI on Windows, patches welcome)
55 Users looking for cryptographically strong (number-theoretically
@@ -16,10 +16,10 @@ bug-reports: https://github.com/TomMD/entropy/issues
1616stability: stable
1717-- build-type: Simple
1818-- ^^ Used for HaLVM
19−build-type: Custom
19+build-type: Custom
2020-- ^^ Test for RDRAND support using 'ghc'
2121cabal-version: >=1.10
22−tested-with: GHC == 7.8.2
22+tested-with: GHC == 8.2.1
2323-- data-files:
2424extra-source-files: ./cbits/rdrand.c, ./cbits/rdrand.h, README.md
2525