@@ -18,6 +18,7 @@ module System.EntropyNix
1818import Control.Monad (liftM, when)
1919import Data.ByteString as B
2020import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
21+import Data.Bits (xor)
2122
2223import Foreign (allocaBytes)
2324import Foreign.Ptr
@@ -29,13 +30,6 @@ import Data.ByteString.Internal as B
2930#undef HAVE_RDRAND
3031#endif
3132
32−#ifdef XEN
33−#ifndef HAVE_RDRAND
34−#error "The entropy package requires RDRAND support when using the halvm/Xen"
35−#endif
36−data CryptHandle = UseRdRand -- or die trying
37−#else
38−
3933import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
4034
4135source :: FilePath
@@ -45,8 +39,7 @@ source = "/dev/urandom"
4539data CryptHandle
4640 = CH Fd
4741#ifdef HAVE_RDRAND
48− | UseRdRand
49−#endif
42+ | UseRdRand Fd
5043#endif
5144
5245-- |Open a `CryptHandle`
@@ -54,46 +47,31 @@ openHandle :: IO CryptHandle
5447openHandle = do
5548#ifdef HAVE_RDRAND
5649 b <- cpuHasRdRand
57− if b then return UseRdRand
58− else nonRDRandHandle
50+ if b then UseRdRand `fmap` nonRDRandHandle
51+ else CH `fmap` nonRDRandHandle
5952#else
60− nonRDRandHandle
53+ CH `fmap` nonRDRandHandle
6154#endif
6255 where
63−#ifdef XEN
64− nonRDRandHandle :: IO CryptHandle
65− nonRDRandHandle = error "entropy: On halvm there is no entropy other than RDRAND."
66−#else
67− nonRDRandHandle :: IO CryptHandle
68− nonRDRandHandle = liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
69−#endif
56+ nonRDRandHandle :: IO Fd
57+ nonRDRandHandle = openFd source ReadOnly Nothing defaultFileFlags
7058
7159-- |Close the `CryptHandle`
7260closeHandle :: CryptHandle -> IO ()
73−#ifndef XEN
7461closeHandle (CH h) = closeFd h
75−#endif
76−#ifdef HAVE_RDRAND
77−closeHandle UseRdRand = return ()
78−#endif
62+closeHandle (UseRdRand h) = closeFd h
7963
8064-- |Read random data from a `CryptHandle`
81−#ifdef XEN
82−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
83−hGetEntropy UseRdRand = \n -> do
84− B.create n $ \ptr -> do
85− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
86− when (r /= 0)
87− (fail "RDRand failed to gather entropy")
88−#else
8965hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
9066hGetEntropy (CH h) = fdReadBS h
9167#ifdef HAVE_RDRAND
92−hGetEntropy UseRdRand = \n -> do
93− B.create n $ \ptr -> do
94− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
95− when (r /= 0)
96− (fail "RDRand failed to gather entropy")
68+hGetEntropy (UseRdRand h) = \n ->
69+ do bsURandom <- fdReadBS h n
70+ bsRDRAND <- B.create n $ \ptr -> do
71+ r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
72+ when (r /= 0)
73+ (fail "RDRand failed to gather entropy")
74+ return $ B.pack $ B.zipWith xor bsURandom bsRDRAND
9775#endif
9876
9977fdReadBS :: Fd -> Int -> IO B.ByteString
@@ -103,8 +81,6 @@ fdReadBS fd n = do
10381 case rc of
10482 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
10583 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
106−#endif
107−
10884
10985#ifdef HAVE_RDRAND
11086foreign import ccall unsafe "cpu_has_rdrand"