@@ -16,9 +16,11 @@ module System.Entropy
16 , closeHandle
16 , closeHandle
19−import Control.Monad (liftM, when)
19+import Control.Monad (liftM)
20import Data.ByteString as B
20import Data.ByteString as B
21−import System.IO (openFile, hClose, IOMode(..), Handle, withBinaryFile)
21+import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
22+import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
23+import Foreign (allocaBytes)
23#if defined(isWindows)
25#if defined(isWindows)
24{- C example for windows rng - taken from a blog, can't recall which one but thank you!
26{- C example for windows rng - taken from a blog, can't recall which one but thank you!
@@ -148,7 +150,6 @@ hGetEntropy UseRdRand =
150{- Not windows, assuming nix with a /dev/urandom -}
152{- Not windows, assuming nix with a /dev/urandom -}
151−import Foreign.C.Types
152import Foreign.Ptr
153import Foreign.Ptr
154source :: FilePath
155source :: FilePath
@@ -156,7 +157,7 @@ source = "/dev/urandom"
157-- |Handle for manual resource mangement
158-- |Handle for manual resource mangement
158data CryptHandle
159data CryptHandle
159− = CH Handle
160+ = CH Fd
160#ifdef HAVE_RDRAND
161#ifdef HAVE_RDRAND
161 | UseRdRand
162 | UseRdRand
@@ -169,18 +170,26 @@ openHandle = do
169 if b then return UseRdRand
170 if b then return UseRdRand
172− liftM CH (openFile source ReadMode)
173+ liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
174-- |Close the `CryptHandle`
175-- |Close the `CryptHandle`
175closeHandle :: CryptHandle -> IO ()
176closeHandle :: CryptHandle -> IO ()
176−closeHandle (CH h) = hClose h
177+closeHandle (CH h) = closeFd h
177#ifdef HAVE_RDRAND
178#ifdef HAVE_RDRAND
178closeHandle UseRdRand = return ()
179closeHandle UseRdRand = return ()
182+fdReadBS :: Fd -> Int -> IO B.ByteString
184+ allocaBytes n $ \buf -> do
185+ rc <- fdReadBuf fd buf (fromIntegral n)
187+ 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
188+ n' -> B.packCStringLen (castPtr buf, fromIntegral n')
181-- |Read random data from a `CryptHandle`
190-- |Read random data from a `CryptHandle`
182−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
191+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
183−hGetEntropy (CH h) = B.hGet h
192+hGetEntropy (CH h) = fdReadBS h
184#ifdef HAVE_RDRAND
193#ifdef HAVE_RDRAND
185hGetEntropy UseRdRand = \n -> do
194hGetEntropy UseRdRand = \n -> do
186 B.create n $ \ptr -> do
195 B.create n $ \ptr -> do
@@ -208,13 +217,9 @@ cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
208-- entropy.
217-- entropy.
209getEntropy :: Int -> IO B.ByteString
218getEntropy :: Int -> IO B.ByteString
210getEntropy n = do
219getEntropy n = do
211−#ifdef HAVE_RDRAND
220+ h <- openHandle
213− if b then hGetEntropy UseRdRand n
221+ e <- hGetEntropy h n
214− else do
222+ closeHandle h
217− withBinaryFile source ReadMode (`B.hGet` n)
219{- OS Test -}
225{- OS Test -}