@@ -16,9 +16,8 @@ module System.Entropy
1616 , closeHandle
1717 ) where
1818
19−import Control.Monad (liftM)
19+import Control.Monad (liftM, when)
2020import Data.ByteString as B
21−import Data.ByteString.Lazy as L
2221import System.IO (openFile, hClose, IOMode(..), Handle, withBinaryFile)
2322
2423#if defined(isWindows)
@@ -114,6 +113,12 @@ hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
114113hGetEntropy (CH h) = cryptGenRandom h
115114
116115#else
116+{- Not windows, assuming nix with a /dev/urandom -}
117+import Foreign.C.Types
118+import Foreign.Ptr
119+import Data.ByteString.Internal as B
120+
121+source :: FilePath
117122source = "/dev/urandom"
118123
119124-- |Handle for manual resource mangement
@@ -131,6 +136,17 @@ closeHandle (CH h) = hClose h
131136hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
132137hGetEntropy (CH h) = B.hGet h
133138
139+#ifdef arch_x86_64
140+foreign import ccall unsafe "cpu_has_rdrand"
141+ c_cpu_has_rdrand :: IO CInt
142+
143+foreign import ccall unsafe "get_rand_bytes"
144+ c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
145+
146+cpuHasRdRand :: IO Bool
147+cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
148+#endif
149+
134150-- |Inefficiently get a specific number of bytes of cryptographically
135151-- secure random data using the system-specific facilities.
136152--
@@ -138,6 +154,17 @@ hGetEntropy (CH h) = B.hGet h
138154-- this entropy is considered "cryptographically secure" but not true
139155-- entropy.
140156getEntropy :: Int -> IO B.ByteString
141−getEntropy n = withBinaryFile source ReadMode (`B.hGet` n)
157+getEntropy n = do
158+#if arch_x86_64
159+ b <- cpuHasRdRand
160+ if b then B.create n $ \ptr -> do
161+ r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
162+ when (r /= 0)
163+ (fail "RDRand failed to gather entropy")
164+ else do
165+#endif
166+{- arch_x86 -}
167+ withBinaryFile source ReadMode (`B.hGet` n)
142168#endif
169+{- OS Test -}
143170