@@ -15,223 +15,18 @@
17module System.Entropy
17module System.Entropy
18− ( getEntropy
18+ ( getEntropy,
25−import Control.Monad (liftM, when)
26−import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
27−import Foreign (allocaBytes)
28−import Data.ByteString as B
30#if defined(isWindows)
19#if defined(isWindows)
31−{- C example for windows rng - taken from a blog, can't recall which one but thank you!
20+ module System.EntropyWindows
32− #include <Windows.h>
21+ ) where
33− #include <Wincrypt.h>
22+import System.EntropyWindows
36− // DISCLAIMER: Don't forget to check your error codes!!
37− // I am not checking as to make the example simple...
39− HCRYPTPROV hCryptCtx = NULL;
40− BYTE randomArray[128];
42− CryptAcquireContext(&hCryptCtx, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
43− CryptGenRandom(hCryptCtx, 128, randomArray);
44− CryptReleaseContext(hCryptCtx, 0);
47−import Data.ByteString.Internal as BI
48−import Data.Int (Int32)
49−import Data.Word (Word32, Word8)
50−import Foreign.C.String (CString, withCString)
51−import Foreign.C.Types
52−import Foreign.Ptr (Ptr, nullPtr, castPtr)
53−import Foreign.Marshal.Alloc (alloca)
54−import Foreign.Marshal.Utils (toBool)
55−import Foreign.Storable (peek)
58−foreign import ccall unsafe "cpu_has_rdrand"
59− c_cpu_has_rdrand :: IO CInt
61−foreign import ccall unsafe "get_rand_bytes"
62− c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
64−cpuHasRdRand :: IO Bool
65−cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
74−-- Define the constants we need from WinCrypt.h
76−msDefProv = "Microsoft Base Cryptographic Provider v1.0"
78−provRSAFull = fromIntegral 1
79−cryptVerifyContext :: Word32
80−cryptVerifyContext = fromIntegral 0xF0000000
82−-- Declare the required CryptoAPI imports
83−foreign import stdcall unsafe "CryptAcquireContextA"
84− c_cryptAcquireCtx :: Ptr Word32 -> CString -> CString -> Word32 -> Word32 -> IO Int32
85−foreign import stdcall unsafe "CryptGenRandom"
86− c_cryptGenRandom :: Word32 -> Word32 -> Ptr Word8 -> IO Int32
87−foreign import stdcall unsafe "CryptReleaseContext"
88− c_cryptReleaseCtx :: Word32 -> Word32 -> IO Int32
90−cryptAcquireCtx :: IO Word32
92− alloca $ \handlePtr ->
93− withCString msDefProv $ \provName -> do
94− stat <- c_cryptAcquireCtx handlePtr nullPtr provName (fromIntegral 1) (fromIntegral cryptVerifyContext)
97− else fail "c_cryptAcquireCtx"
99−cryptGenRandom :: Word32 -> Int -> IO B.ByteString
101− BI.create i $ \c_buffer -> do
102− stat <- c_cryptGenRandom (fromIntegral h) (fromIntegral i) c_buffer
105− else fail "c_cryptGenRandom"
107−cryptReleaseCtx :: Word32 -> IO ()
108−cryptReleaseCtx h = do
109− stat <- c_cryptReleaseCtx h 0
112− else fail "c_cryptReleaseCtx"
114−-- |Inefficiently get a specific number of bytes of cryptographically
115−-- secure random data using the system-specific facilities.
117−-- This function will return zero bytes
118−-- on platforms without a secure RNG!
119−getEntropy :: Int -> IO B.ByteString
123− if b then hGetEntropy UseRdRand n
126− h <- cryptAcquireCtx
127− bs <- cryptGenRandom h n
132−-- |Open a handle from which random data can be read
133−openHandle :: IO CryptHandle
137− if b then return UseRdRand
140− liftM CH cryptAcquireCtx
142−-- |Close the `CryptHandle`
143−closeHandle (CH h) = cryptReleaseCtx h
145−-- |Read from `CryptHandle`
146−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
147−hGetEntropy (CH h) n = cryptGenRandom h n
149−hGetEntropy UseRdRand n =
150− B.create n $ \ptr -> do
151− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
153− (fail "RDRand failed to gather entropy")
157−{- Not windows, assuming nix with a /dev/urandom -}
159−import Foreign.C.Types
160−import Data.ByteString.Internal as B
162−data CryptHandle = UseRdRand -- or die trying
164−import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
167−source = "/dev/urandom"
169−-- |Handle for manual resource mangement
177−-- |Open a `CryptHandle`
178−openHandle :: IO CryptHandle
182− if b then return UseRdRand
186− error "entropy: On halvm there is no entropy other than RDRAND."
188− liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
191−-- |Close the `CryptHandle`
192−closeHandle :: CryptHandle -> IO ()
194−closeHandle (CH h) = closeFd h
197−closeHandle UseRdRand = return ()
201−fdReadBS :: Fd -> Int -> IO B.ByteString
203− allocaBytes n $ \buf -> do
204− rc <- fdReadBuf fd buf (fromIntegral n)
206− 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
207− n' -> B.packCStringLen (castPtr buf, fromIntegral n')
210−-- |Read random data from a `CryptHandle`
211−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
213−hGetEntropy (CH h) = fdReadBS h
215−#ifdef HAVE_RDRAND
24+ module System.EntropyNix
216−hGetEntropy UseRdRand = \n -> do
25+ ) where
217− B.create n $ \ptr -> do
26+import System.EntropyNix
218− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
220− (fail "RDRand failed to gather entropy")
226−foreign import ccall unsafe "cpu_has_rdrand"
227− c_cpu_has_rdrand :: IO CInt
229−foreign import ccall unsafe "get_rand_bytes"
29+import qualified Data.ByteString as B
230− c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
232−cpuHasRdRand :: IO Bool
233−cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
236-- |Inefficiently get a specific number of bytes of cryptographically
31-- |Inefficiently get a specific number of bytes of cryptographically
237-- secure random data using the system-specific facilities.
32-- secure random data using the system-specific facilities.
@@ -245,5 +40,3 @@ getEntropy n = do
245 e <- hGetEntropy h n
40 e <- hGetEntropy h n
246 closeHandle h
41 closeHandle h