entropy-0.4: System/EntropyXen.hs
{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables #-}
{-|
Maintainer: Thomas.DuBuisson@gmail.com
Stability: beta
Portability: portable
Obtain entropy from RDRAND when available.
-}
module System.EntropyXen
( CryptHandle
, openHandle
, hGetEntropy
, closeHandle
, hardwardRNG
) where
import Control.Monad (liftM, when)
import Data.ByteString as B
import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
import Foreign (allocaBytes)
import Foreign.Ptr
import Foreign.C.Types
import Data.ByteString.Internal as B
#ifdef arch_i386
-- See .cabal wrt GCC 4.8.2 asm compilation bug
#undef HAVE_RDRAND
#endif
#ifndef HAVE_RDRAND
#error "The entropy package requires RDRAND support when using the halvm/Xen"
#endif
data CryptHandle = UseRdRand -- or die trying
-- |Open a `CryptHandle`
openHandle :: IO CryptHandle
openHandle = do
b <- cpuHasRdRand
if b then return UseRdRand
else nonRDRandHandle
where
nonRDRandHandle :: IO CryptHandle
nonRDRandHandle = error "entropy: On halvm there is no entropy other than RDRAND."
-- |Close the `CryptHandle`
closeHandle :: CryptHandle -> IO ()
closeHandle UseRdRand = return ()
-- | Get random values from the hardward RNG or return Nothing if no
-- supported hardware RNG is available.
--
-- Supported hardware:
-- * RDRAND
-- * Patches welcome
hardwareRandom :: Int -> IO (Maybe B.ByteString)
hardwareRandom sz = Just <$> hGetEntropy UseRdRand sz
-- |Read random data from a `CryptHandle`, which uses RDRAND (when on Xen)
hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
hGetEntropy UseRdRand = \n -> do
B.create n $ \ptr -> do
r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
when (r /= 0)
(fail "RDRand failed to gather entropy")
foreign import ccall unsafe "cpu_has_rdrand"
c_cpu_has_rdrand :: IO CInt
foreign import ccall unsafe "get_rand_bytes"
c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
cpuHasRdRand :: IO Bool
cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand