@@ -4,22 +4,32 @@
4 Stability: beta
4 Stability: beta
5 Portability: portable
5 Portability: portable
7− Obtain entropy from system sources.
7+ Obtain entropy from system sources or x86 RDRAND when available.
11+ - Windows via CryptoAPO
8− Currently, windows and *nix systems with a @/dev/urandom@ are supported.
12+ - *nix systems via @\/dev\/urandom@
14+ - Xen only when RDRAND is available.
11module System.Entropy
17module System.Entropy
12− ( getEntropy
18+ ( getEntropy
13− , CryptHandle
19+ , CryptHandle
14− , openHandle
20+ , openHandle
15− , hGetEntropy
21+ , hGetEntropy
16− , closeHandle
22+ , closeHandle
19−import Control.Monad (liftM)
26+import Control.Monad (liftM, when)
20−import Data.ByteString as B
21import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
27import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
22import Foreign (allocaBytes)
28import Foreign (allocaBytes)
30+import Control.Monad (when)
32+import Data.ByteString as B
24#if defined(isWindows)
34#if defined(isWindows)
25{- C example for windows rng - taken from a blog, can't recall which one but thank you!
35{- C example for windows rng - taken from a blog, can't recall which one but thank you!
@@ -149,8 +159,13 @@ hGetEntropy UseRdRand =
151{- Not windows, assuming nix with a /dev/urandom -}
161{- Not windows, assuming nix with a /dev/urandom -}
152−import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
153import Foreign.Ptr
162import Foreign.Ptr
163+import Foreign.C.Types
164+import Data.ByteString.Internal as B
166+data CryptHandle = UseRdRand -- or die trying
168+import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
155source :: FilePath
170source :: FilePath
156source = "/dev/urandom"
171source = "/dev/urandom"
@@ -161,6 +176,7 @@ data CryptHandle
161#ifdef HAVE_RDRAND
176#ifdef HAVE_RDRAND
162 | UseRdRand
177 | UseRdRand
165-- |Open a `CryptHandle`
181-- |Open a `CryptHandle`
166openHandle :: IO CryptHandle
182openHandle :: IO CryptHandle
@@ -170,15 +186,22 @@ openHandle = do
170 if b then return UseRdRand
186 if b then return UseRdRand
190+ error "entropy: On halvm there is no entropy other than RDRAND."
173− liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
192+ liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
175-- |Close the `CryptHandle`
195-- |Close the `CryptHandle`
176closeHandle :: CryptHandle -> IO ()
196closeHandle :: CryptHandle -> IO ()
177closeHandle (CH h) = closeFd h
198closeHandle (CH h) = closeFd h
178#ifdef HAVE_RDRAND
200#ifdef HAVE_RDRAND
179closeHandle UseRdRand = return ()
201closeHandle UseRdRand = return ()
182fdReadBS :: Fd -> Int -> IO B.ByteString
205fdReadBS :: Fd -> Int -> IO B.ByteString
183fdReadBS fd n = do
206fdReadBS fd n = do
184 allocaBytes n $ \buf -> do
207 allocaBytes n $ \buf -> do
@@ -186,10 +209,13 @@ fdReadBS fd n = do
186 case rc of
209 case rc of
187 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
210 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
188 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
211 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
190-- |Read random data from a `CryptHandle`
214-- |Read random data from a `CryptHandle`
191hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
215hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
192hGetEntropy (CH h) = fdReadBS h
217hGetEntropy (CH h) = fdReadBS h
193#ifdef HAVE_RDRAND
219#ifdef HAVE_RDRAND
194hGetEntropy UseRdRand = \n -> do
220hGetEntropy UseRdRand = \n -> do
195 B.create n $ \ptr -> do
221 B.create n $ \ptr -> do
@@ -197,6 +223,8 @@ hGetEntropy UseRdRand = \n -> do
197 when (r /= 0)
223 when (r /= 0)
198 (fail "RDRand failed to gather entropy")
224 (fail "RDRand failed to gather entropy")
201#ifdef HAVE_RDRAND
229#ifdef HAVE_RDRAND
202foreign import ccall unsafe "cpu_has_rdrand"
230foreign import ccall unsafe "cpu_has_rdrand"
@@ -213,7 +241,7 @@ cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
213-- secure random data using the system-specific facilities.
241-- secure random data using the system-specific facilities.
215-- Use '/dev/urandom' on *nix and CryptAPI when on Windows. In short,
243-- Use '/dev/urandom' on *nix and CryptAPI when on Windows. In short,
216−-- this entropy is considered "cryptographically secure" but not true
244+-- this entropy is considered cryptographically secure but not true
217-- entropy.
245-- entropy.
218getEntropy :: Int -> IO B.ByteString
246getEntropy :: Int -> IO B.ByteString
219getEntropy n = do
247getEntropy n = do