@@ -16,9 +16,11 @@ module System.Entropy
1616 , closeHandle
1717 ) where
1818
19−import Control.Monad (liftM, when)
19+import Control.Monad (liftM)
2020import 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)
2224
2325#if defined(isWindows)
2426{- C example for windows rng - taken from a blog, can't recall which one but thank you!
@@ -148,7 +150,6 @@ hGetEntropy UseRdRand =
148150
149151#else
150152{- Not windows, assuming nix with a /dev/urandom -}
151−import Foreign.C.Types
152153import Foreign.Ptr
153154
154155source :: FilePath
@@ -156,7 +157,7 @@ source = "/dev/urandom"
156157
157158-- |Handle for manual resource mangement
158159data CryptHandle
159− = CH Handle
160+ = CH Fd
160161#ifdef HAVE_RDRAND
161162 | UseRdRand
162163#endif
@@ -169,18 +170,26 @@ openHandle = do
169170 if b then return UseRdRand
170171 else do
171172#endif
172− liftM CH (openFile source ReadMode)
173+ liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
173174
174175-- |Close the `CryptHandle`
175176closeHandle :: CryptHandle -> IO ()
176−closeHandle (CH h) = hClose h
177+closeHandle (CH h) = closeFd h
177178#ifdef HAVE_RDRAND
178179closeHandle UseRdRand = return ()
179180#endif
180181
182+fdReadBS :: Fd -> Int -> IO B.ByteString
183+fdReadBS fd n = do
184+ allocaBytes n $ \buf -> do
185+ rc <- fdReadBuf fd buf (fromIntegral n)
186+ case rc of
187+ 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
188+ n' -> B.packCStringLen (castPtr buf, fromIntegral n')
189+
181190-- |Read random data from a `CryptHandle`
182−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
183−hGetEntropy (CH h) = B.hGet h
191+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
192+hGetEntropy (CH h) = fdReadBS h
184193#ifdef HAVE_RDRAND
185194hGetEntropy UseRdRand = \n -> do
186195 B.create n $ \ptr -> do
@@ -208,13 +217,9 @@ cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
208217-- entropy.
209218getEntropy :: Int -> IO B.ByteString
210219getEntropy n = do
211−#ifdef HAVE_RDRAND
212− b <- cpuHasRdRand
213− if b then hGetEntropy UseRdRand n
214− else do
215−#endif
216−{- arch_x86 -}
217− withBinaryFile source ReadMode (`B.hGet` n)
220+ h <- openHandle
221+ e <- hGetEntropy h n
222+ closeHandle h
223+ return e
218224#endif
219225{- OS Test -}
220−