@@ -41,12 +41,28 @@ import Data.ByteString.Internal as BI
41import Data.Int (Int32)
41import Data.Int (Int32)
42import Data.Word (Word32, Word8)
42import Data.Word (Word32, Word8)
43import Foreign.C.String (CString, withCString)
43import Foreign.C.String (CString, withCString)
44−import Foreign.Ptr (Ptr, nullPtr)
44+import Foreign.C.Types
45+import Foreign.Ptr (Ptr, nullPtr, castPtr)
45import Foreign.Marshal.Alloc (alloca)
46import Foreign.Marshal.Alloc (alloca)
46import Foreign.Marshal.Utils (toBool)
47import Foreign.Marshal.Utils (toBool)
47import Foreign.Storable (peek)
48import Foreign.Storable (peek)
51+foreign import ccall unsafe "cpu_has_rdrand"
52+ c_cpu_has_rdrand :: IO CInt
54+foreign import ccall unsafe "get_rand_bytes"
55+ c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
57+cpuHasRdRand :: IO Bool
58+cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
49−newtype CryptHandle = CH Word32
61+newtype CryptHandle
51-- Define the constants we need from WinCrypt.h
67-- Define the constants we need from WinCrypt.h
52msDefProv :: String
68msDefProv :: String
@@ -95,6 +111,11 @@ cryptReleaseCtx h = do
95-- on platforms without a secure RNG!
111-- on platforms without a secure RNG!
96getEntropy :: Int -> IO B.ByteString
112getEntropy :: Int -> IO B.ByteString
97getEntropy n = do
113getEntropy n = do
116+ if b then hGetEntropy UseRdRand n
98 h <- cryptAcquireCtx
119 h <- cryptAcquireCtx
99 bs <- cryptGenRandom h n
120 bs <- cryptGenRandom h n
100 let !bs' = bs
121 let !bs' = bs
@@ -103,7 +124,13 @@ getEntropy n = do
104-- |Open a handle from which random data can be read
125-- |Open a handle from which random data can be read
105openHandle :: IO CryptHandle
126openHandle :: IO CryptHandle
130+ if b then return UseRdRand
106−openHandle = liftM CH cryptAcquireCtx
133+ liftM CH cryptAcquireCtx
108-- |Close the `CryptHandle`
135-- |Close the `CryptHandle`
109closeHandle (CH h) = cryptReleaseCtx h
136closeHandle (CH h) = cryptReleaseCtx h
@@ -111,6 +138,13 @@ closeHandle (CH h) = cryptReleaseCtx h
111-- |Read from `CryptHandle`
138-- |Read from `CryptHandle`
112hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
139hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
113hGetEntropy (CH h) = cryptGenRandom h
140hGetEntropy (CH h) = cryptGenRandom h
142+hGetEntropy UseRdRand =
143+ B.create n $ \ptr -> do
144+ r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
146+ (fail "RDRand failed to gather entropy")
116{- Not windows, assuming nix with a /dev/urandom -}
150{- Not windows, assuming nix with a /dev/urandom -}
@@ -122,7 +156,11 @@ source :: FilePath
122source = "/dev/urandom"
156source = "/dev/urandom"
124-- |Handle for manual resource mangement
158-- |Handle for manual resource mangement
125−data CryptHandle = CH Handle | UseRdRand
159+data CryptHandle
127-- |Open a `CryptHandle`
165-- |Open a `CryptHandle`
128openHandle :: IO CryptHandle
166openHandle :: IO CryptHandle
@@ -173,10 +211,7 @@ getEntropy :: Int -> IO B.ByteString
173getEntropy n = do
211getEntropy n = do
174#if arch_x86_64
212#if arch_x86_64
175 b <- cpuHasRdRand
213 b <- cpuHasRdRand
176− if b then B.create n $ \ptr -> do
214+ if b then hGetEntropy UseRdRand n
177− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
179− (fail "RDRand failed to gather entropy")
182{- arch_x86 -}
217{- arch_x86 -}