@@ -13,6 +13,7 @@ module System.EntropyNix
13 , openHandle
13 , openHandle
14 , hGetEntropy
14 , hGetEntropy
15 , closeHandle
15 , closeHandle
18import Control.Monad (liftM, when)
19import Control.Monad (liftM, when)
@@ -38,20 +39,29 @@ source = "/dev/urandom"
38-- |Handle for manual resource management
39-- |Handle for manual resource management
39data CryptHandle
40data CryptHandle
43+-- | Get random values from the hardward RNG or return Nothing if no
44+-- supported hardware RNG is available.
46+-- Supported hardware:
49+hardwareRNG :: Int -> IO (Maybe B.ByteString)
41#ifdef HAVE_RDRAND
50#ifdef HAVE_RDRAND
42− | UseRdRand Fd
51+hardwareRNG n =
54+ then Just <$> B.create n (\ptr ->
55+ do r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
56+ when (r /= 0) (fail "RDRand failed to gather entropy"))
59+hardwareRNG _ = pure Nothing
45-- |Open a `CryptHandle`
62-- |Open a `CryptHandle`
46openHandle :: IO CryptHandle
63openHandle :: IO CryptHandle
50− if b then UseRdRand `fmap` nonRDRandHandle
51− else CH `fmap` nonRDRandHandle
53− CH `fmap` nonRDRandHandle
64+openHandle = do CH `fmap` nonRDRandHandle
56 nonRDRandHandle :: IO Fd
66 nonRDRandHandle :: IO Fd
57 nonRDRandHandle = openFd source ReadOnly Nothing defaultFileFlags
67 nonRDRandHandle = openFd source ReadOnly Nothing defaultFileFlags
@@ -59,22 +69,10 @@ openHandle = do
59-- |Close the `CryptHandle`
69-- |Close the `CryptHandle`
60closeHandle :: CryptHandle -> IO ()
70closeHandle :: CryptHandle -> IO ()
61closeHandle (CH h) = closeFd h
71closeHandle (CH h) = closeFd h
63−closeHandle (UseRdRand h) = closeFd h
66-- |Read random data from a `CryptHandle`
73-- |Read random data from a `CryptHandle`
67hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
74hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
68hGetEntropy (CH h) = fdReadBS h
75hGetEntropy (CH h) = fdReadBS h
70−hGetEntropy (UseRdRand h) = \n ->
71− do bsURandom <- fdReadBS h n
72− bsRDRAND <- B.create n $ \ptr -> do
73− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
75− (fail "RDRand failed to gather entropy")
76− return $ B.pack $ B.zipWith xor bsURandom bsRDRAND
79fdReadBS :: Fd -> Int -> IO B.ByteString
77fdReadBS :: Fd -> Int -> IO B.ByteString
80fdReadBS fd n =
78fdReadBS fd n =