entropy 0.3.8 → 0.4
raw patch · 6 files changed
+121/−64 lines, 6 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
+ System.Entropy: getHardwareEntropy :: Int -> IO (Maybe ByteString)
Files
- README.md +19/−3
- System/Entropy.hs +43/−11
- System/EntropyNix.hs +19/−21
- System/EntropyWindows.hs +22/−22
- System/EntropyXen.hs +12/−2
- entropy.cabal +6/−5
README.md view
@@ -1,9 +1,25 @@ # Introduction -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 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`. Hardware RNGs (currently RDRAND, patches welcome) are supported+via the `hardwareRNG` function. +If you wish to obtain an XOR of the hardware and system RNG consider:++```+import Data.Bits (xor)+import qualified Data.ByteString as B+import qualified Control.Exception as X++xorRNG sz = do hw <- hardwareRNG sz+ h <- openHandle+ sys <- hGetEntropy h `X.finally` closeHandle h+ pure $ B.pack $ B.zipWith xor hw sys+```+ This package supports Windows, {li,u}nix, QNX, and has preliminary support for HaLVM.++Typically tested on Linux and OSX - testers are as welcome as patches. [](https://travis-ci.org/TomMD/entropy)
System/Entropy.hs view
@@ -16,18 +16,18 @@ module System.Entropy ( getEntropy,-#if defined(isWindows)- module System.EntropyWindows+ getHardwareEntropy,+ CryptHandle,+ openHandle,+ hGetEntropy,+ closeHandle ) where+#if defined(isWindows) import System.EntropyWindows #else #ifdef XEN- module System.EntropyXen- ) where import System.EntropyXen #else- module System.EntropyNix- ) where import System.EntropyNix #endif #endif@@ -36,10 +36,42 @@ import Control.Exception (bracket) -- |Get a specific number of bytes of cryptographically--- secure random data using the system-specific facilities.+-- secure random data using the *system-specific* sources. +-- (As of 0.4. Verions <0.4 mixed system and hardware sources) ----- Use RDRAND if available and XOR with '/dev/urandom' on *nix and CryptAPI when on--- Windows. In short, this entropy is considered cryptographically secure--- but not true entropy.-getEntropy :: Int -> IO B.ByteString+-- The returned random value is considered cryptographically secure but not true entropy.+--+-- On some platforms this requies a file handle which can lead to resource+-- exhaustion in some situations.+getEntropy :: Int -- ^ Number of bytes+ -> IO B.ByteString getEntropy = bracket openHandle closeHandle . flip hGetEntropy++-- |Get a specific number of bytes of cryptographically+-- secure random data using a supported *hardware* random bit generator.+--+-- If there is no hardware random number generator then @Nothing@ is returned.+-- If any call returns non-Nothing then it should never be @Nothing@ unless+-- there has been a hardware failure.+--+-- If trust of the CPU allows it and no context switching is important,+-- a bias to the hardware rng with system rng as fall back is trivial:+--+-- @+-- let fastRandom nr = maybe (getEntropy nr) pure =<< getHardwareEntropy nr+-- @+--+-- The old, @<0.4@, behavior is possible using @xor@ from 'Data.Bits':+--+-- @+-- let oldRandom nr =+-- do hwRnd <- maybe (replicate nr 0) BS.unpack <$> getHardwareEntropy nr+-- sysRnd <- BS.unpack <$> getEntropy nr+-- pure $ BS.pack $ zipWith xor sysRnd hwRnd+-- @+--+-- A less maliable mixing can be accomplished by replacing `xor` with a+-- composition of concat and cryptographic hash.+getHardwareEntropy :: Int -- ^ Number of bytes+ -> IO (Maybe B.ByteString)+getHardwareEntropy = hardwareRandom
System/EntropyNix.hs view
@@ -13,6 +13,7 @@ , openHandle , hGetEntropy , closeHandle+ , hardwareRandom ) where import Control.Monad (liftM, when)@@ -38,20 +39,29 @@ -- |Handle for manual resource management data CryptHandle = CH Fd++-- | Get random values from the hardward RNG or return Nothing if no+-- supported hardware RNG is available.+--+-- Supported hardware:+-- * RDRAND+-- * Patches welcome+hardwareRandom :: Int -> IO (Maybe B.ByteString) #ifdef HAVE_RDRAND- | UseRdRand Fd+hardwareRandom n =+ do b <- cpuHasRdRand+ if b+ then Just <$> B.create n (\ptr ->+ do r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)+ when (r /= 0) (fail "RDRand failed to gather entropy"))+ else pure Nothing+#else+hardwareRandom _ = pure Nothing #endif -- |Open a `CryptHandle` openHandle :: IO CryptHandle-openHandle = do-#ifdef HAVE_RDRAND- b <- cpuHasRdRand- if b then UseRdRand `fmap` nonRDRandHandle- else CH `fmap` nonRDRandHandle-#else- CH `fmap` nonRDRandHandle-#endif+openHandle = do CH `fmap` nonRDRandHandle where nonRDRandHandle :: IO Fd nonRDRandHandle = openFd source ReadOnly Nothing defaultFileFlags@@ -59,22 +69,10 @@ -- |Close the `CryptHandle` closeHandle :: CryptHandle -> IO () closeHandle (CH h) = closeFd h-#ifdef HAVE_RDRAND-closeHandle (UseRdRand h) = closeFd h-#endif -- |Read random data from a `CryptHandle` hGetEntropy :: CryptHandle -> Int -> IO B.ByteString hGetEntropy (CH h) = fdReadBS h-#ifdef HAVE_RDRAND-hGetEntropy (UseRdRand h) = \n ->- do bsURandom <- fdReadBS h n- bsRDRAND <- B.create n $ \ptr -> do- r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)- when (r /= 0)- (fail "RDRand failed to gather entropy")- return $ B.pack $ B.zipWith xor bsURandom bsRDRAND-#endif fdReadBS :: Fd -> Int -> IO B.ByteString fdReadBS fd n =
System/EntropyWindows.hs view
@@ -4,7 +4,7 @@ Stability: beta Portability: portable - Obtain entropy from system sources or x86 RDRAND when available.+ Obtain entropy from system sources. -} module System.EntropyWindows@@ -12,6 +12,7 @@ , openHandle , hGetEntropy , closeHandle+ , hardwareRandom ) where import Control.Monad (liftM, when)@@ -64,8 +65,25 @@ data CryptHandle = CH Word32+++-- | Get random values from the hardward RNG or return Nothing if no+-- supported hardware RNG is available.+--+-- Supported hardware:+-- * RDRAND+-- * Patches welcome+hardwareRandom :: Int -> IO (Maybe B.ByteString) #ifdef HAVE_RDRAND- | UseRdRand Word32+hardwareRandom n =+ do b <- cpuHasRdRand+ if b+ then Just <$> BI.create n (\ptr ->+ do r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)+ when (r /= 0) (fail "RDRand failed to gather entropy"))+ else pure Nothing+#else+hardwareRandom _ = pure Nothing #endif -- Define the constants we need from WinCrypt.h @@ -110,30 +128,12 @@ -- |Open a handle from which random data can be read openHandle :: IO CryptHandle-openHandle = do-#ifdef HAVE_RDRAND- b <- cpuHasRdRand- if b then UseRdRand `fmap` cryptAcquireCtx- else do-#endif- CH `fmap` cryptAcquireCtx+openHandle = CH `fmap` cryptAcquireCtx -- |Close the `CryptHandle` closeHandle :: CryptHandle -> IO () closeHandle (CH h) = cryptReleaseCtx h-#ifdef HAVE_RDRAND-closeHandle (UseRdRand h) = cryptReleaseCtx h-#endif -- |Read from `CryptHandle`-hGetEntropy :: CryptHandle -> Int -> IO B.ByteString +hGetEntropy :: CryptHandle -> Int -> IO B.ByteString hGetEntropy (CH h) n = cryptGenRandom h n-#ifdef HAVE_RDRAND-hGetEntropy (UseRdRand h) n =- do bsRDRAND <- BI.create n $ \ptr -> do- r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)- when (r /= 0)- (fail "RDRand failed to gather entropy")- bsWinCrypt <- cryptGenRandom h n- return $ B.pack $ B.zipWith xor bsRDRAND bsWinCrypt-#endif
System/EntropyXen.hs view
@@ -4,7 +4,7 @@ Stability: beta Portability: portable - Obtain entropy from system sources or x86 RDRAND when available.+ Obtain entropy from RDRAND when available. -} @@ -13,6 +13,7 @@ , openHandle , hGetEntropy , closeHandle+ , hardwardRNG ) where import Control.Monad (liftM, when)@@ -48,7 +49,16 @@ closeHandle :: CryptHandle -> IO () closeHandle UseRdRand = return () --- |Read random data from a `CryptHandle`+-- | Get random values from the hardward RNG or return Nothing if no+-- supported hardware RNG is available.+--+-- Supported hardware:+-- * RDRAND+-- * Patches welcome+hardwareRandom :: Int -> IO (Maybe B.ByteString)+hardwareRandom sz = Just <$> hGetEntropy UseRdRand sz++-- |Read random data from a `CryptHandle`, which uses RDRAND (when on Xen) hGetEntropy :: CryptHandle -> Int -> IO B.ByteString hGetEntropy UseRdRand = \n -> do B.create n $ \ptr -> do
entropy.cabal view
@@ -1,7 +1,7 @@ name: entropy-version: 0.3.8+version: 0.4 description: A platform independent method to obtain cryptographically strong entropy- (RDRAND when available anywhere, urandom on nix, CryptAPI on Windows, patches welcome)+ (RDRAND, urandom, CryptAPI, and patches welcome) Users looking for cryptographically strong (number-theoretically sound) PRNGs should see the 'DRBG' package too. synopsis: A platform independent entropy source@@ -16,10 +16,10 @@ stability: stable -- build-type: Simple -- ^^ Used for HaLVM-build-type: Custom+build-type: Custom -- ^^ Test for RDRAND support using 'ghc' cabal-version: >=1.10-tested-with: GHC == 7.8.2+tested-with: GHC == 8.2.2 -- data-files: extra-source-files: ./cbits/rdrand.c, ./cbits/rdrand.h, README.md @@ -49,7 +49,8 @@ else other-modules: System.EntropyNix }- other-extensions: CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables+ other-extensions: CPP, ForeignFunctionInterface, BangPatterns,+ ScopedTypeVariables build-depends: base >= 4.3 && < 5, bytestring default-language: Haskell2010 if(os(halvm))