1{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables #-}
3 Maintainer: Thomas.DuBuisson@gmail.com
7 Obtain entropy from system sources or x86 RDRAND when available.
11 - Windows via CryptoAPO
12 - *nix systems via @\/dev\/urandom@
14 - Xen only when RDRAND is available.
26import Control.Monad (liftM, when)
27import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
28import Foreign (allocaBytes)
30import Control.Monad (when)
32import Data.ByteString as B
35{- C example for windows rng - taken from a blog, can't recall which one but thank you!
40 // DISCLAIMER: Don't forget to check your error codes!!
41 // I am not checking as to make the example simple...
43 HCRYPTPROV hCryptCtx = NULL;
44 BYTE randomArray[128];
46 CryptAcquireContext(&hCryptCtx, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
47 CryptGenRandom(hCryptCtx, 128, randomArray);
48 CryptReleaseContext(hCryptCtx, 0);
51import Data.ByteString.Internal as BI
52import Data.Int (Int32)
53import Data.Word (Word32, Word8)
54import Foreign.C.String (CString, withCString)
56import Foreign.Ptr (Ptr, nullPtr, castPtr)
57import Foreign.Marshal.Alloc (alloca)
58import Foreign.Marshal.Utils (toBool)
59import Foreign.Storable (peek)
62foreign import ccall unsafe "cpu_has_rdrand"
63 c_cpu_has_rdrand :: IO CInt
65foreign import ccall unsafe "get_rand_bytes"
66 c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
68cpuHasRdRand :: IO Bool
69cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
78-- Define the constants we need from WinCrypt.h
80msDefProv = "Microsoft Base Cryptographic Provider v1.0"
82provRSAFull = fromIntegral 1
83cryptVerifyContext :: Word32
84cryptVerifyContext = fromIntegral 0xF0000000
86-- Declare the required CryptoAPI imports
87foreign import stdcall unsafe "CryptAcquireContextA"
88 c_cryptAcquireCtx :: Ptr Word32 -> CString -> CString -> Word32 -> Word32 -> IO Int32
89foreign import stdcall unsafe "CryptGenRandom"
90 c_cryptGenRandom :: Word32 -> Word32 -> Ptr Word8 -> IO Int32
91foreign import stdcall unsafe "CryptReleaseContext"
92 c_cryptReleaseCtx :: Word32 -> Word32 -> IO Int32
94cryptAcquireCtx :: IO Word32
96 alloca $ \handlePtr ->
97 withCString msDefProv $ \provName -> do
98 stat <- c_cryptAcquireCtx handlePtr nullPtr provName (fromIntegral 1) (fromIntegral cryptVerifyContext)
101 else fail "c_cryptAcquireCtx"
103cryptGenRandom :: Word32 -> Int -> IO B.ByteString
105 BI.create i $ \c_buffer -> do
106 stat <- c_cryptGenRandom (fromIntegral h) (fromIntegral i) c_buffer
109 else fail "c_cryptGenRandom"
111cryptReleaseCtx :: Word32 -> IO ()
112cryptReleaseCtx h = do
113 stat <- c_cryptReleaseCtx h 0
116 else fail "c_cryptReleaseCtx"
118-- |Inefficiently get a specific number of bytes of cryptographically
119-- secure random data using the system-specific facilities.
121-- This function will return zero bytes
122-- on platforms without a secure RNG!
123getEntropy :: Int -> IO B.ByteString
127 if b then hGetEntropy UseRdRand n
131 bs <- cryptGenRandom h n
136-- |Open a handle from which random data can be read
137openHandle :: IO CryptHandle
141 if b then return UseRdRand
144 liftM CH cryptAcquireCtx
146-- |Close the `CryptHandle`
147closeHandle (CH h) = cryptReleaseCtx h
149-- |Read from `CryptHandle`
150hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
151hGetEntropy (CH h) = cryptGenRandom h
153hGetEntropy UseRdRand =
154 B.create n $ \ptr -> do
155 r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
157 (fail "RDRand failed to gather entropy")
161{- Not windows, assuming nix with a /dev/urandom -}
163import Foreign.C.Types
164import Data.ByteString.Internal as B
166data CryptHandle = UseRdRand -- or die trying
168import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
171source = "/dev/urandom"
173-- |Handle for manual resource mangement
181-- |Open a `CryptHandle`
182openHandle :: IO CryptHandle
186 if b then return UseRdRand
190 error "entropy: On halvm there is no entropy other than RDRAND."
192 liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
195-- |Close the `CryptHandle`
196closeHandle :: CryptHandle -> IO ()
198closeHandle (CH h) = closeFd h
201closeHandle UseRdRand = return ()
205fdReadBS :: Fd -> Int -> IO B.ByteString
207 allocaBytes n $ \buf -> do
208 rc <- fdReadBuf fd buf (fromIntegral n)
210 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
211 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
214-- |Read random data from a `CryptHandle`
215hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
217hGetEntropy (CH h) = fdReadBS h
220hGetEntropy UseRdRand = \n -> do
221 B.create n $ \ptr -> do
222 r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
224 (fail "RDRand failed to gather entropy")
230foreign import ccall unsafe "cpu_has_rdrand"
231 c_cpu_has_rdrand :: IO CInt
233foreign import ccall unsafe "get_rand_bytes"
234 c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
236cpuHasRdRand :: IO Bool
237cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
240-- |Inefficiently get a specific number of bytes of cryptographically
241-- secure random data using the system-specific facilities.
243-- Use '/dev/urandom' on *nix and CryptAPI when on Windows. In short,
244-- this entropy is considered cryptographically secure but not true
246getEntropy :: Int -> IO B.ByteString
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list