@@ -0,0 +1,143 @@
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.
19+import Control.Monad (liftM)
20+import Data.ByteString as B
21+import Data.ByteString.Lazy as L
22+import System.IO (openFile, hClose, IOMode(..), Handle, withBinaryFile)
24+#if defined(isWindows)
25+{- C example for windows rng - taken from a blog, can't recall which one but thank you!
27+ #include <Wincrypt.h>
30+ // DISCLAIMER: Don't forget to check your error codes!!
31+ // I am not checking as to make the example simple...
33+ HCRYPTPROV hCryptCtx = NULL;
34+ BYTE randomArray[128];
36+ CryptAcquireContext(&hCryptCtx, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
37+ CryptGenRandom(hCryptCtx, 128, randomArray);
38+ CryptReleaseContext(hCryptCtx, 0);
41+import Data.ByteString.Internal as BI
42+import Data.Int (Int32)
43+import Data.Word (Word32, Word8)
44+import Foreign.C.String (CString, withCString)
45+import Foreign.Ptr (Ptr, nullPtr)
46+import Foreign.Marshal.Alloc (alloca)
47+import Foreign.Marshal.Utils (toBool)
48+import Foreign.Storable (peek)
50+newtype CryptHandle = CH Word32
52+-- Define the constants we need from WinCrypt.h
54+msDefProv = "Microsoft Base Cryptographic Provider v1.0"
56+provRSAFull = fromIntegral 1
57+cryptVerifyContext :: Word32
58+cryptVerifyContext = fromIntegral 0xF0000000
60+-- Declare the required CryptoAPI imports
61+foreign import stdcall unsafe "CryptAcquireContextA"
62+ c_cryptAcquireCtx :: Ptr Word32 -> CString -> CString -> Word32 -> Word32 -> IO Int32
63+foreign import stdcall unsafe "CryptGenRandom"
64+ c_cryptGenRandom :: Word32 -> Word32 -> Ptr Word8 -> IO Int32
65+foreign import stdcall unsafe "CryptReleaseContext"
66+ c_cryptReleaseCtx :: Word32 -> Word32 -> IO Int32
68+cryptAcquireCtx :: IO Word32
70+ alloca $ \handlePtr ->
71+ withCString msDefProv $ \provName -> do
72+ stat <- c_cryptAcquireCtx handlePtr nullPtr provName (fromIntegral 1) (fromIntegral cryptVerifyContext)
75+ else fail "c_cryptAcquireCtx"
77+cryptGenRandom :: Word32 -> Int -> IO B.ByteString
79+ BI.create i $ \c_buffer -> do
80+ stat <- c_cryptGenRandom (fromIntegral h) (fromIntegral i) c_buffer
83+ else fail "c_cryptGenRandom"
85+cryptReleaseCtx :: Word32 -> IO ()
86+cryptReleaseCtx h = do
87+ stat <- c_cryptReleaseCtx h 0
90+ else fail "c_cryptReleaseCtx"
92+-- |Inefficiently get a specific number of bytes of cryptographically
93+-- secure random data using the system-specific facilities.
95+-- This function will return zero bytes
96+-- on platforms without a secure RNG!
97+getEntropy :: Int -> IO B.ByteString
100+ bs <- cryptGenRandom h n
105+-- |Open a handle from which random data can be read
106+openHandle :: IO CryptHandle
107+openHandle = liftM CH cryptAcquireCtx
109+-- |Close the `CryptHandle`
110+closeHandle (CH h) = cryptReleaseCtx h
112+-- |Read from `CryptHandle`
113+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
114+hGetEntropy (CH h) = cryptGenRandom h
117+source = "/dev/urandom"
119+-- |Handle for manual resource mangement
120+newtype CryptHandle = CH Handle
122+-- |Open a `CryptHandle`
123+openHandle :: IO CryptHandle
124+openHandle = liftM CH (openFile source ReadMode)
126+-- |Close the `CryptHandle`
127+closeHandle :: CryptHandle -> IO ()
128+closeHandle (CH h) = hClose h
130+-- |Read random data from a `CryptHandle`
131+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
132+hGetEntropy (CH h) = B.hGet h
134+-- |Inefficiently get a specific number of bytes of cryptographically
135+-- secure random data using the system-specific facilities.
137+-- Use '/dev/urandom' on *nix and CryptAPI when on Windows. In short,
138+-- this entropy is considered "cryptographically secure" but not true
140+getEntropy :: Int -> IO B.ByteString
141+getEntropy n = withBinaryFile source ReadMode (`B.hGet` n)