1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
-- |
-- Module : Crypto.Random.Entropy.Unix
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : Good
--
{-# LANGUAGE ScopedTypeVariables #-}
module Crypto.Random.Entropy.Unix
( DevRandom
, DevURandom
) where
import Foreign.Ptr
import Data.Word (Word8)
import Crypto.Random.Entropy.Source
import Control.Exception as E
import System.Posix.Types (Fd)
import System.Posix.IO
type H = Fd
type DeviceName = String
-- | Entropy device /dev/random on unix system
newtype DevRandom = DevRandom DeviceName
-- | Entropy device /dev/urandom on unix system
newtype DevURandom = DevURandom DeviceName
instance EntropySource DevRandom where
entropyOpen = fmap DevRandom `fmap` testOpen "/dev/random"
entropyGather (DevRandom name) ptr n =
withDev name $ \h -> gatherDevEntropy h ptr n
entropyClose (DevRandom _) = return ()
instance EntropySource DevURandom where
entropyOpen = fmap DevURandom `fmap` testOpen "/dev/urandom"
entropyGather (DevURandom name) ptr n =
withDev name $ \h -> gatherDevEntropy h ptr n
entropyClose (DevURandom _) = return ()
testOpen :: DeviceName -> IO (Maybe DeviceName)
testOpen filepath = do
d <- openDev filepath
case d of
Nothing -> return Nothing
Just h -> closeDev h >> return (Just filepath)
openDev :: String -> IO (Maybe H)
openDev filepath = (Just `fmap` openFd filepath ReadOnly Nothing fileFlags)
`E.catch` \(_ :: IOException) -> return Nothing
where fileFlags = defaultFileFlags { nonBlock = True }
withDev :: String -> (H -> IO a) -> IO a
withDev filepath f = openDev filepath >>= \h ->
case h of
Nothing -> error ("device " ++ filepath ++ " cannot be grabbed")
Just fd -> f fd >>= \r -> (closeDev fd >> return r)
closeDev :: H -> IO ()
closeDev h = closeFd h
gatherDevEntropy :: H -> Ptr Word8 -> Int -> IO Int
gatherDevEntropy h ptr sz =
(fromIntegral `fmap` fdReadBuf h ptr (fromIntegral sz))
`E.catch` \(_ :: IOException) -> return 0
|