packages feed

entropy 0.2.2.4 → 0.3

raw patch · 6 files changed

+279/−207 lines, 6 filesdep ~basesetup-changed

Dependency ranges changed: base

Files

README.md view
@@ -3,3 +3,5 @@ This package allows Haskell users to easily acquire entropy for use in critical security applications by calling out to either windows crypto api, unix/linux's `/dev/urandom`, or the RDRAND instruction.++This package supports Windows, {li,u}nix, QNX, and has preliminary support for HaLVM.
Setup.hs view
@@ -29,7 +29,7 @@ cArgs = ["-DHAVE_RDRAND"]  cArgsHC :: [String]-cArgsHC = map ("-optc" ++) cArgs+cArgsHC = cArgs ++ map ("-optc" ++) cArgs  canUseRDRAND :: FilePath -> IO Bool canUseRDRAND cc = do
System/Entropy.hs view
@@ -4,216 +4,35 @@  Stability: beta  Portability: portable - Obtain entropy from system sources.- Currently, windows and *nix systems with a @/dev/urandom@ are supported.--}--module System.Entropy-	( getEntropy-	, CryptHandle-	, openHandle-	, hGetEntropy-	, closeHandle-	) where--import Control.Monad (liftM)-import Data.ByteString as B-import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)-import Foreign (allocaBytes)+ Obtain entropy from system sources or x86 RDRAND when available. -#if defined(isWindows)-{- C example for windows rng - taken from a blog, can't recall which one but thank you!-        #include <Windows.h>-        #include <Wincrypt.h>-        ...-        //-        // DISCLAIMER: Don't forget to check your error codes!!-        // I am not checking as to make the example simple...-        //-        HCRYPTPROV hCryptCtx = NULL;-        BYTE randomArray[128];+ Currently supporting: -        CryptAcquireContext(&hCryptCtx, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);-        CryptGenRandom(hCryptCtx, 128, randomArray);-        CryptReleaseContext(hCryptCtx, 0);+    - Windows via CryptoAPO+    - *nix systems via @\/dev\/urandom@+    - QNX+    - Xen only when RDRAND is available. -} -import Data.ByteString.Internal as BI-import Data.Int (Int32)-import Data.Word (Word32, Word8)-import Foreign.C.String (CString, withCString)-import Foreign.C.Types-import Foreign.Ptr (Ptr, nullPtr, castPtr)-import Foreign.Marshal.Alloc (alloca)-import Foreign.Marshal.Utils (toBool)-import Foreign.Storable (peek)--#ifdef HAVE_RDRAND-foreign import ccall unsafe "cpu_has_rdrand"-   c_cpu_has_rdrand :: IO CInt--foreign import ccall unsafe "get_rand_bytes"-  c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt--cpuHasRdRand :: IO Bool-cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand-#endif--data CryptHandle-    = CH Word32-#ifdef HAVE_RDRAND-    | UseRdRand-#endif---- Define the constants we need from WinCrypt.h -msDefProv :: String-msDefProv = "Microsoft Base Cryptographic Provider v1.0"-provRSAFull :: Word32-provRSAFull = fromIntegral 1-cryptVerifyContext :: Word32-cryptVerifyContext = fromIntegral 0xF0000000---- Declare the required CryptoAPI imports -foreign import stdcall unsafe "CryptAcquireContextA"-   c_cryptAcquireCtx :: Ptr Word32 -> CString -> CString -> Word32 -> Word32 -> IO Int32-foreign import stdcall unsafe "CryptGenRandom"-   c_cryptGenRandom :: Word32 -> Word32 -> Ptr Word8 -> IO Int32-foreign import stdcall unsafe "CryptReleaseContext"-   c_cryptReleaseCtx :: Word32 -> Word32 -> IO Int32--cryptAcquireCtx :: IO Word32-cryptAcquireCtx = -   alloca $ \handlePtr -> -      withCString msDefProv $ \provName -> do-         stat <- c_cryptAcquireCtx handlePtr nullPtr provName (fromIntegral 1) (fromIntegral cryptVerifyContext)-         if (toBool stat)-            then peek handlePtr-            else fail "c_cryptAcquireCtx"--cryptGenRandom :: Word32 -> Int -> IO B.ByteString-cryptGenRandom h i = -   BI.create i $ \c_buffer -> do-      stat <- c_cryptGenRandom (fromIntegral h) (fromIntegral i) c_buffer-      if (toBool stat)-         then return ()-         else fail "c_cryptGenRandom"--cryptReleaseCtx :: Word32 -> IO ()-cryptReleaseCtx h = do-   stat <- c_cryptReleaseCtx h 0-   if (toBool stat)-      then return ()-      else fail "c_cryptReleaseCtx"---- |Inefficiently get a specific number of bytes of cryptographically--- secure random data using the system-specific facilities.------ This function will return zero bytes--- on platforms without a secure RNG!-getEntropy :: Int -> IO B.ByteString-getEntropy n = do-#ifdef HAVE_RDRAND-    b <- cpuHasRdRand-    if b then hGetEntropy UseRdRand n-         else do-#endif-   h <- cryptAcquireCtx-   bs <- cryptGenRandom h n-   let !bs' = bs-   cryptReleaseCtx h-   return bs'---- |Open a handle from which random data can be read-openHandle :: IO CryptHandle-openHandle = do-#ifdef HAVE_RDRAND-    b <- cpuHasRdRand-    if b then return UseRdRand-         else do-#endif-    liftM CH cryptAcquireCtx---- |Close the `CryptHandle`-closeHandle (CH h) = cryptReleaseCtx h---- |Read from `CryptHandle`-hGetEntropy :: CryptHandle -> Int -> IO B.ByteString -hGetEntropy (CH h) = cryptGenRandom h-#ifdef HAVE_RDRAND-hGetEntropy UseRdRand =-    B.create n $ \ptr ->  do-                r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)-                when (r /= 0)-                     (fail "RDRand failed to gather entropy")-#endif-+module System.Entropy+        ( getEntropy,+#if defined(isWindows)+         module System.EntropyWindows+        ) where+import System.EntropyWindows #else-{- Not windows, assuming nix with a /dev/urandom -}-import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)-import Foreign.Ptr--source :: FilePath-source = "/dev/urandom"---- |Handle for manual resource mangement-data CryptHandle-    = CH Fd-#ifdef HAVE_RDRAND-    | UseRdRand-#endif---- |Open a `CryptHandle`-openHandle :: IO CryptHandle-openHandle = do-#ifdef HAVE_RDRAND-    b <- cpuHasRdRand-    if b then return UseRdRand-         else do-#endif-    liftM CH (openFd source ReadOnly Nothing defaultFileFlags)---- |Close the `CryptHandle`-closeHandle :: CryptHandle -> IO ()-closeHandle (CH h) = closeFd h-#ifdef HAVE_RDRAND-closeHandle UseRdRand = return ()-#endif--fdReadBS :: Fd -> Int -> IO B.ByteString-fdReadBS fd n = do-    allocaBytes n $ \buf -> do-        rc <- fdReadBuf fd buf (fromIntegral n)-        case rc of-            0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")-            n' -> B.packCStringLen (castPtr buf, fromIntegral n')---- |Read random data from a `CryptHandle`-hGetEntropy :: CryptHandle -> Int -> IO B.ByteString-hGetEntropy (CH h) = fdReadBS h-#ifdef HAVE_RDRAND-hGetEntropy UseRdRand = \n -> do-    B.create n $ \ptr ->  do-                r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)-                when (r /= 0)-                     (fail "RDRand failed to gather entropy")+         module System.EntropyNix+        ) where+import System.EntropyNix #endif -#ifdef HAVE_RDRAND-foreign import ccall unsafe "cpu_has_rdrand"-   c_cpu_has_rdrand :: IO CInt--foreign import ccall unsafe "get_rand_bytes"-  c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt--cpuHasRdRand :: IO Bool-cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand-#endif+import qualified Data.ByteString as B  -- |Inefficiently get a specific number of bytes of cryptographically -- secure random data using the system-specific facilities. -- -- Use '/dev/urandom' on *nix and CryptAPI when on Windows.  In short,--- this entropy is considered "cryptographically secure" but not true+-- this entropy is considered cryptographically secure but not true -- entropy. getEntropy :: Int -> IO B.ByteString getEntropy n = do@@ -221,5 +40,3 @@     e <- hGetEntropy h n     closeHandle h     return e-#endif-{- OS Test -}
+ System/EntropyNix.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables #-}+{-|+ Maintainer: Thomas.DuBuisson@gmail.com+ Stability: beta+ Portability: portable++ Obtain entropy from system sources or x86 RDRAND when available.++-}++module System.EntropyNix+        ( CryptHandle+        , openHandle+        , hGetEntropy+        , closeHandle+        ) where++import Control.Monad (liftM, when)+import Data.ByteString as B+import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)++import Foreign (allocaBytes)+import Foreign.Ptr+import Foreign.C.Types+import Data.ByteString.Internal as B++#ifdef XEN+data CryptHandle = UseRdRand -- or die trying+#else++import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)++source :: FilePath+source = "/dev/urandom"++-- |Handle for manual resource mangement+data CryptHandle+    = CH Fd+#ifdef HAVE_RDRAND+    | UseRdRand+#endif+#endif++-- |Open a `CryptHandle`+openHandle :: IO CryptHandle+openHandle = do+#ifdef HAVE_RDRAND+    b <- cpuHasRdRand+    if b then return UseRdRand+         else nonRDRandHandle+#else+              nonRDRandHandle+#endif+ where+#ifdef XEN+  nonRDRandHandle :: IO CryptHandle+  nonRDRandHandle = error "entropy: On halvm there is no entropy other than RDRAND."+#else+  nonRDRandHandle :: IO CryptHandle+  nonRDRandHandle = liftM CH (openFd source ReadOnly Nothing defaultFileFlags)+#endif++-- |Close the `CryptHandle`+closeHandle :: CryptHandle -> IO ()+#ifndef XEN+closeHandle (CH h) = closeFd h+#endif+#ifdef HAVE_RDRAND+closeHandle UseRdRand = return ()+#endif++-- |Read random data from a `CryptHandle`+#ifdef XEN+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString+hGetEntropy UseRdRand = \n -> do+    B.create n $ \ptr ->  do+                r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)+                when (r /= 0)+                     (fail "RDRand failed to gather entropy")+#else+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString+hGetEntropy (CH h) = fdReadBS h+#ifdef HAVE_RDRAND+hGetEntropy UseRdRand = \n -> do+    B.create n $ \ptr ->  do+                r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)+                when (r /= 0)+                     (fail "RDRand failed to gather entropy")+#endif++fdReadBS :: Fd -> Int -> IO B.ByteString+fdReadBS fd n = do+    allocaBytes n $ \buf -> do+        rc <- fdReadBuf fd buf (fromIntegral n)+        case rc of+            0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")+            n' -> B.packCStringLen (castPtr buf, fromIntegral n')+#endif+++#ifdef HAVE_RDRAND+foreign import ccall unsafe "cpu_has_rdrand"+   c_cpu_has_rdrand :: IO CInt++foreign import ccall unsafe "get_rand_bytes"+  c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt++cpuHasRdRand :: IO Bool+cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand+#endif+
+ System/EntropyWindows.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables #-}+{-|+ Maintainer: Thomas.DuBuisson@gmail.com+ Stability: beta+ Portability: portable++ Obtain entropy from system sources or x86 RDRAND when available.+-}++module System.EntropyWindows+        ( CryptHandle+        , openHandle+        , hGetEntropy+        , closeHandle+        ) where++import Control.Monad (liftM, when)+import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)+import Foreign (allocaBytes)+import Data.ByteString as B+import Data.ByteString.Internal as BI+import Data.Int (Int32)+import Data.Word (Word32, Word8)+import Foreign.C.String (CString, withCString)+import Foreign.C.Types+import Foreign.Ptr (Ptr, nullPtr, castPtr)+import Foreign.Marshal.Alloc (alloca)+import Foreign.Marshal.Utils (toBool)+import Foreign.Storable (peek)++{- C example for windows rng - taken from a blog, can't recall which one but thank you!+        #include <Windows.h>+        #include <Wincrypt.h>+        ...+        //+        // DISCLAIMER: Don't forget to check your error codes!!+        // I am not checking as to make the example simple...+        //+        HCRYPTPROV hCryptCtx = NULL;+        BYTE randomArray[128];++        CryptAcquireContext(&hCryptCtx, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);+        CryptGenRandom(hCryptCtx, 128, randomArray);+        CryptReleaseContext(hCryptCtx, 0);+-}+++#ifdef HAVE_RDRAND+foreign import ccall unsafe "cpu_has_rdrand"+   c_cpu_has_rdrand :: IO CInt++foreign import ccall unsafe "get_rand_bytes"+  c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt++cpuHasRdRand :: IO Bool+cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand+#endif++data CryptHandle+    = CH Word32+#ifdef HAVE_RDRAND+    | UseRdRand+#endif++-- Define the constants we need from WinCrypt.h +msDefProv :: String+msDefProv = "Microsoft Base Cryptographic Provider v1.0"+provRSAFull :: Word32+provRSAFull = 1+cryptVerifyContext :: Word32+cryptVerifyContext = fromIntegral 0xF0000000++-- Declare the required CryptoAPI imports +foreign import stdcall unsafe "CryptAcquireContextA"+   c_cryptAcquireCtx :: Ptr Word32 -> CString -> CString -> Word32 -> Word32 -> IO Int32+foreign import stdcall unsafe "CryptGenRandom"+   c_cryptGenRandom :: Word32 -> Word32 -> Ptr Word8 -> IO Int32+foreign import stdcall unsafe "CryptReleaseContext"+   c_cryptReleaseCtx :: Word32 -> Word32 -> IO Int32++cryptAcquireCtx :: IO Word32+cryptAcquireCtx =+   alloca $ \handlePtr -> +      withCString msDefProv $ \provName -> do+         stat <- c_cryptAcquireCtx handlePtr nullPtr provName provRSAFull cryptVerifyContext+         if (toBool stat)+            then peek handlePtr+            else fail "c_cryptAcquireCtx"++cryptGenRandom :: Word32 -> Int -> IO B.ByteString+cryptGenRandom h i = +   BI.create i $ \c_buffer -> do+      stat <- c_cryptGenRandom h (fromIntegral i) c_buffer+      if (toBool stat)+         then return ()+         else fail "c_cryptGenRandom"++cryptReleaseCtx :: Word32 -> IO ()+cryptReleaseCtx h = do+   stat <- c_cryptReleaseCtx h 0+   if (toBool stat)+      then return ()+      else fail "c_cryptReleaseCtx"++-- |Open a handle from which random data can be read+openHandle :: IO CryptHandle+openHandle = do+#ifdef HAVE_RDRAND+    b <- cpuHasRdRand+    if b then return UseRdRand+         else do+#endif+                  liftM CH cryptAcquireCtx++-- |Close the `CryptHandle`+closeHandle :: CryptHandle -> IO ()+closeHandle (CH h) = cryptReleaseCtx h++-- |Read from `CryptHandle`+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString +hGetEntropy (CH h) n = cryptGenRandom h n+#ifdef HAVE_RDRAND+hGetEntropy UseRdRand n =+    BI.create n $ \ptr ->  do+                r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)+                when (r /= 0)+                     (fail "RDRand failed to gather entropy")+#endif
entropy.cabal view
@@ -1,5 +1,5 @@ name:           entropy-version:        0.2.2.4+version:        0.3 description:    A platform independent method to obtain cryptographically strong entropy                  (urandom on Linux, CryptAPI on Windows, patches welcome).                  Users looking for cryptographically strong (number-theoretically@@ -14,20 +14,33 @@ homepage:       https://github.com/TomMD/entropy bug-reports:    https://github.com/TomMD/entropy/issues stability:      stable+-- build-type:  Simple+-- ^^ Used for HaLVM build-type:        Custom-cabal-version:     >=1.10+-- ^^ Test for RDRAND support using 'ghc'+cabal-version:  >=1.10 tested-with:    GHC == 7.6.3 -- data-files: extra-source-files:   ./cbits/rdrand.c, ./cbits/rdrand.h, README.md +-- Notice to compile  with HaLVM the above 'build-type' must be changed+-- to 'Simple' instead of 'Custom'.  The current build system naively+-- runs GHC to determine if the compiler supports RDRAND before proceeding.+flag halvm+    description:        Build for the HaLVM+    default:            False library-  ghc-options:  -Wall -O2+  ghc-options:  -O2   exposed-modules: System.Entropy+  if os(windows)+    other-modules: System.EntropyWindows+  else+    other-modules: System.EntropyNix   other-extensions:    CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables   build-depends: base == 4.*, bytestring-  -- hs-source-dirs:-  -- other-modules:   default-language:    Haskell2010+  if(flag(halvm))+    cpp-options: -DXEN -DHAVE_RDRAND   if arch(x86_64)     cpp-options: -Darch_x86_64     c-sources:    cbits/rdrand.c@@ -36,7 +49,8 @@     cpp-options: -DisWindows     extra-libraries: advapi32   else-    Build-Depends: unix+    if !flag(halvm)+       Build-Depends: unix  source-repository head     type:       git