1{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables #-}
3 Maintainer: Thomas.DuBuisson@gmail.com
7 Obtain entropy from system sources.
8 Currently, windows and *nix systems with a @/dev/urandom@ are supported.
19import Control.Monad (liftM)
20import Data.ByteString as B
21import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
22import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
23import Foreign (allocaBytes)
26{- C example for windows rng - taken from a blog, can't recall which one but thank you!
31 // DISCLAIMER: Don't forget to check your error codes!!
32 // I am not checking as to make the example simple...
34 HCRYPTPROV hCryptCtx = NULL;
35 BYTE randomArray[128];
37 CryptAcquireContext(&hCryptCtx, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
38 CryptGenRandom(hCryptCtx, 128, randomArray);
39 CryptReleaseContext(hCryptCtx, 0);
42import Data.ByteString.Internal as BI
43import Data.Int (Int32)
44import Data.Word (Word32, Word8)
45import Foreign.C.String (CString, withCString)
47import Foreign.Ptr (Ptr, nullPtr, castPtr)
48import Foreign.Marshal.Alloc (alloca)
49import Foreign.Marshal.Utils (toBool)
50import Foreign.Storable (peek)
53foreign import ccall unsafe "cpu_has_rdrand"
54 c_cpu_has_rdrand :: IO CInt
56foreign import ccall unsafe "get_rand_bytes"
57 c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
59cpuHasRdRand :: IO Bool
60cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
69-- Define the constants we need from WinCrypt.h
71msDefProv = "Microsoft Base Cryptographic Provider v1.0"
73provRSAFull = fromIntegral 1
74cryptVerifyContext :: Word32
75cryptVerifyContext = fromIntegral 0xF0000000
77-- Declare the required CryptoAPI imports
78foreign import stdcall unsafe "CryptAcquireContextA"
79 c_cryptAcquireCtx :: Ptr Word32 -> CString -> CString -> Word32 -> Word32 -> IO Int32
80foreign import stdcall unsafe "CryptGenRandom"
81 c_cryptGenRandom :: Word32 -> Word32 -> Ptr Word8 -> IO Int32
82foreign import stdcall unsafe "CryptReleaseContext"
83 c_cryptReleaseCtx :: Word32 -> Word32 -> IO Int32
85cryptAcquireCtx :: IO Word32
87 alloca $ \handlePtr ->
88 withCString msDefProv $ \provName -> do
89 stat <- c_cryptAcquireCtx handlePtr nullPtr provName (fromIntegral 1) (fromIntegral cryptVerifyContext)
92 else fail "c_cryptAcquireCtx"
94cryptGenRandom :: Word32 -> Int -> IO B.ByteString
96 BI.create i $ \c_buffer -> do
97 stat <- c_cryptGenRandom (fromIntegral h) (fromIntegral i) c_buffer
100 else fail "c_cryptGenRandom"
102cryptReleaseCtx :: Word32 -> IO ()
103cryptReleaseCtx h = do
104 stat <- c_cryptReleaseCtx h 0
107 else fail "c_cryptReleaseCtx"
109-- |Inefficiently get a specific number of bytes of cryptographically
110-- secure random data using the system-specific facilities.
112-- This function will return zero bytes
113-- on platforms without a secure RNG!
114getEntropy :: Int -> IO B.ByteString
118 if b then hGetEntropy UseRdRand n
122 bs <- cryptGenRandom h n
127-- |Open a handle from which random data can be read
128openHandle :: IO CryptHandle
132 if b then return UseRdRand
135 liftM CH cryptAcquireCtx
137-- |Close the `CryptHandle`
138closeHandle (CH h) = cryptReleaseCtx h
140-- |Read from `CryptHandle`
141hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
142hGetEntropy (CH h) = cryptGenRandom h
144hGetEntropy UseRdRand =
145 B.create n $ \ptr -> do
146 r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
148 (fail "RDRand failed to gather entropy")
152{- Not windows, assuming nix with a /dev/urandom -}
156source = "/dev/urandom"
158-- |Handle for manual resource mangement
165-- |Open a `CryptHandle`
166openHandle :: IO CryptHandle
170 if b then return UseRdRand
173 liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
175-- |Close the `CryptHandle`
176closeHandle :: CryptHandle -> IO ()
177closeHandle (CH h) = closeFd h
179closeHandle UseRdRand = return ()
182fdReadBS :: Fd -> Int -> IO B.ByteString
184 allocaBytes n $ \buf -> do
185 rc <- fdReadBuf fd buf (fromIntegral n)
187 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
188 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
190-- |Read random data from a `CryptHandle`
191hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
192hGetEntropy (CH h) = fdReadBS h
194hGetEntropy UseRdRand = \n -> do
195 B.create n $ \ptr -> do
196 r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
198 (fail "RDRand failed to gather entropy")
202foreign import ccall unsafe "cpu_has_rdrand"
203 c_cpu_has_rdrand :: IO CInt
205foreign import ccall unsafe "get_rand_bytes"
206 c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
208cpuHasRdRand :: IO Bool
209cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
212-- |Inefficiently get a specific number of bytes of cryptographically
213-- secure random data using the system-specific facilities.
215-- Use '/dev/urandom' on *nix and CryptAPI when on Windows. In short,
216-- this entropy is considered "cryptographically secure" but not true
218getEntropy :: 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