@@ -4,22 +4,32 @@
44 Stability: beta
55 Portability: portable
66
7− Obtain entropy from system sources.
8− Currently, windows and *nix systems with a @/dev/urandom@ are supported.
7+ Obtain entropy from system sources or x86 RDRAND when available.
8+
9+ Currently supporting:
10+
11+ - Windows via CryptoAPO
12+ - *nix systems via @\/dev\/urandom@
13+ - QNX
14+ - Xen only when RDRAND is available.
915-}
1016
1117module System.Entropy
12− ( getEntropy
13− , CryptHandle
14− , openHandle
15− , hGetEntropy
16− , closeHandle
17− ) where
18−
19−import Control.Monad (liftM)
20−import Data.ByteString as B
18+ ( getEntropy
19+ , CryptHandle
20+ , openHandle
21+ , hGetEntropy
22+ , closeHandle
23+ ) where
24+
25+#ifndef XEN
26+import Control.Monad (liftM, when)
2127import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
2228import Foreign (allocaBytes)
29+#else
30+import Control.Monad (when)
31+#endif
32+import Data.ByteString as B
2333
2434#if defined(isWindows)
2535{- C example for windows rng - taken from a blog, can't recall which one but thank you!
@@ -149,8 +159,13 @@ hGetEntropy UseRdRand =
149159
150160#else
151161{- Not windows, assuming nix with a /dev/urandom -}
152−import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
153162import Foreign.Ptr
163+import Foreign.C.Types
164+import Data.ByteString.Internal as B
165+#ifdef XEN
166+data CryptHandle = UseRdRand -- or die trying
167+#else
168+import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
154169
155170source :: FilePath
156171source = "/dev/urandom"
@@ -161,6 +176,7 @@ data CryptHandle
161176#ifdef HAVE_RDRAND
162177 | UseRdRand
163178#endif
179+#endif
164180
165181-- |Open a `CryptHandle`
166182openHandle :: IO CryptHandle
@@ -170,15 +186,22 @@ openHandle = do
170186 if b then return UseRdRand
171187 else do
172188#endif
173− liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
189+#ifdef XEN
190+ error "entropy: On halvm there is no entropy other than RDRAND."
191+#else
192+ liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
193+#endif
174194
175195-- |Close the `CryptHandle`
176196closeHandle :: CryptHandle -> IO ()
197+#ifndef XEN
177198closeHandle (CH h) = closeFd h
199+#endif
178200#ifdef HAVE_RDRAND
179201closeHandle UseRdRand = return ()
180202#endif
181203
204+#ifndef XEN
182205fdReadBS :: Fd -> Int -> IO B.ByteString
183206fdReadBS fd n = do
184207 allocaBytes n $ \buf -> do
@@ -186,10 +209,13 @@ fdReadBS fd n = do
186209 case rc of
187210 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
188211 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
212+#endif
189213
190214-- |Read random data from a `CryptHandle`
191215hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
216+#ifndef XEN
192217hGetEntropy (CH h) = fdReadBS h
218+#else
193219#ifdef HAVE_RDRAND
194220hGetEntropy UseRdRand = \n -> do
195221 B.create n $ \ptr -> do
@@ -197,6 +223,8 @@ hGetEntropy UseRdRand = \n -> do
197223 when (r /= 0)
198224 (fail "RDRand failed to gather entropy")
199225#endif
226+#endif
227+{- XEN -}
200228
201229#ifdef HAVE_RDRAND
202230foreign import ccall unsafe "cpu_has_rdrand"
@@ -213,7 +241,7 @@ cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
213241-- secure random data using the system-specific facilities.
214242--
215243-- 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
217245-- entropy.
218246getEntropy :: Int -> IO B.ByteString
219247getEntropy n = do