git.iko.soy/typeable/entropy
on main help sign in
Use RDRAND in addition to urandom.

Through some discussions it became apparent alternative security models are held by some rather motivated community members. Out of a desire to minimize community fragmentation this patch combines the entropy from RDRAND and urandom. Recall the intent of entropy is not speed but to seed fast and closely held DRBGs. Hence, securely combining N sources should be acceptable to user or they are actually looking for a slightly different package with different goals.

commitc33deced6877cb62e3ad07b51709f288b6bb2b50 authorThomas M. DuBuisson <tommd@galois.com> dateWed 16 Jul 2014, 13:18 (12 years ago) parent3622daf
4 files changed+99−47
System/Entropy.hs+10−4 System/EntropyNix.hs+15−39 System/EntropyXen.hs+66 entropy.cabal+8−4
System/Entropy.hs+10−4
@@ -8,10 +8,10 @@
88
99 Currently supporting:
1010
11− - Windows via CryptoAPO
11+ - Windows via CryptoAPI
1212 - *nix systems via @\/dev\/urandom@
13− - QNX
14− - Xen only when RDRAND is available.
13+ - Includes QNX
14+ - Xen (only when RDRAND is available)
1515-}
1616
1717module System.Entropy
@@ -20,18 +20,24 @@ module System.Entropy
2020 module System.EntropyWindows
2121 ) where
2222import System.EntropyWindows
23+#else
24+#ifdef XEN
25+ module System.EntropyXen
26+ ) where
27+import System.EntropyXen
2328#else
2429 module System.EntropyNix
2530 ) where
2631import System.EntropyNix
2732#endif
33+#endif
2834
2935import qualified Data.ByteString as B
3036
3137-- |Get a specific number of bytes of cryptographically
3238-- secure random data using the system-specific facilities.
3339--
34−-- Use RDRAND if available or '/dev/urandom' on *nix and CryptAPI when on
40+-- Use RDRAND if available and XOR with '/dev/urandom' on *nix and CryptAPI when on
3541-- Windows. In short, this entropy is considered cryptographically secure
3642-- but not true entropy.
3743getEntropy :: Int -> IO B.ByteString
System/EntropyNix.hs+15−39
@@ -18,6 +18,7 @@ module System.EntropyNix
1818import Control.Monad (liftM, when)
1919import Data.ByteString as B
2020import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
21+import Data.Bits (xor)
2122
2223import Foreign (allocaBytes)
2324import Foreign.Ptr
@@ -29,13 +30,6 @@ import Data.ByteString.Internal as B
2930#undef HAVE_RDRAND
3031#endif
3132
32−#ifdef XEN
33−#ifndef HAVE_RDRAND
34−#error "The entropy package requires RDRAND support when using the halvm/Xen"
35−#endif
36−data CryptHandle = UseRdRand -- or die trying
37−#else
38−
3933import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
4034
4135source :: FilePath
@@ -45,8 +39,7 @@ source = "/dev/urandom"
4539data CryptHandle
4640 = CH Fd
4741#ifdef HAVE_RDRAND
48− | UseRdRand
49−#endif
42+ | UseRdRand Fd
5043#endif
5144
5245-- |Open a `CryptHandle`
@@ -54,46 +47,31 @@ openHandle :: IO CryptHandle
5447openHandle = do
5548#ifdef HAVE_RDRAND
5649 b <- cpuHasRdRand
57− if b then return UseRdRand
58− else nonRDRandHandle
50+ if b then UseRdRand `fmap` nonRDRandHandle
51+ else CH `fmap` nonRDRandHandle
5952#else
60− nonRDRandHandle
53+ CH `fmap` nonRDRandHandle
6154#endif
6255 where
63−#ifdef XEN
64− nonRDRandHandle :: IO CryptHandle
65− nonRDRandHandle = error "entropy: On halvm there is no entropy other than RDRAND."
66−#else
67− nonRDRandHandle :: IO CryptHandle
68− nonRDRandHandle = liftM CH (openFd source ReadOnly Nothing defaultFileFlags)
69−#endif
56+ nonRDRandHandle :: IO Fd
57+ nonRDRandHandle = openFd source ReadOnly Nothing defaultFileFlags
7058
7159-- |Close the `CryptHandle`
7260closeHandle :: CryptHandle -> IO ()
73−#ifndef XEN
7461closeHandle (CH h) = closeFd h
75−#endif
76−#ifdef HAVE_RDRAND
77−closeHandle UseRdRand = return ()
78−#endif
62+closeHandle (UseRdRand h) = closeFd h
7963
8064-- |Read random data from a `CryptHandle`
81−#ifdef XEN
82−hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
83−hGetEntropy UseRdRand = \n -> do
84− B.create n $ \ptr -> do
85− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
86− when (r /= 0)
87− (fail "RDRand failed to gather entropy")
88−#else
8965hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
9066hGetEntropy (CH h) = fdReadBS h
9167#ifdef HAVE_RDRAND
92−hGetEntropy UseRdRand = \n -> do
93− B.create n $ \ptr -> do
94− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
95− when (r /= 0)
96− (fail "RDRand failed to gather entropy")
68+hGetEntropy (UseRdRand h) = \n ->
69+ do bsURandom <- fdReadBS h n
70+ bsRDRAND <- B.create n $ \ptr -> do
71+ r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
72+ when (r /= 0)
73+ (fail "RDRand failed to gather entropy")
74+ return $ B.pack $ B.zipWith xor bsURandom bsRDRAND
9775#endif
9876
9977fdReadBS :: Fd -> Int -> IO B.ByteString
@@ -103,8 +81,6 @@ fdReadBS fd n = do
10381 case rc of
10482 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
10583 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
106−#endif
107−
10884
10985#ifdef HAVE_RDRAND
11086foreign import ccall unsafe "cpu_has_rdrand"
System/EntropyXen.hsnew file+66
@@ -0,0 +1,66 @@
1+{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables #-}
2+{-|
3+ Maintainer: Thomas.DuBuisson@gmail.com
4+ Stability: beta
5+ Portability: portable
6+
7+ Obtain entropy from system sources or x86 RDRAND when available.
8+
9+-}
10+
11+module System.EntropyXen
12+ ( CryptHandle
13+ , openHandle
14+ , hGetEntropy
15+ , closeHandle
16+ ) where
17+
18+import Control.Monad (liftM, when)
19+import Data.ByteString as B
20+import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
21+
22+import Foreign (allocaBytes)
23+import Foreign.Ptr
24+import Foreign.C.Types
25+import Data.ByteString.Internal as B
26+
27+#ifdef arch_i386
28+-- See .cabal wrt GCC 4.8.2 asm compilation bug
29+#undef HAVE_RDRAND
30+#endif
31+
32+#ifndef HAVE_RDRAND
33+#error "The entropy package requires RDRAND support when using the halvm/Xen"
34+#endif
35+data CryptHandle = UseRdRand -- or die trying
36+
37+-- |Open a `CryptHandle`
38+openHandle :: IO CryptHandle
39+openHandle = do
40+ b <- cpuHasRdRand
41+ if b then return UseRdRand
42+ else nonRDRandHandle
43+ where
44+ nonRDRandHandle :: IO CryptHandle
45+ nonRDRandHandle = error "entropy: On halvm there is no entropy other than RDRAND."
46+
47+-- |Close the `CryptHandle`
48+closeHandle :: CryptHandle -> IO ()
49+closeHandle UseRdRand = return ()
50+
51+-- |Read random data from a `CryptHandle`
52+hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
53+hGetEntropy UseRdRand = \n -> do
54+ B.create n $ \ptr -> do
55+ r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
56+ when (r /= 0)
57+ (fail "RDRand failed to gather entropy")
58+
59+foreign import ccall unsafe "cpu_has_rdrand"
60+ c_cpu_has_rdrand :: IO CInt
61+
62+foreign import ccall unsafe "get_rand_bytes"
63+ c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
64+
65+cpuHasRdRand :: IO Bool
66+cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
entropy.cabal+8−4
@@ -35,12 +35,16 @@ library
3535 exposed-modules: System.Entropy
3636 if os(windows)
3737 other-modules: System.EntropyWindows
38− else
39− other-modules: System.EntropyNix
38+ else {
39+ if os(halvm)
40+ other-modules: System.EntropyXen
41+ else
42+ other-modules: System.EntropyNix
43+ }
4044 other-extensions: CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables
4145 build-depends: base == 4.*, bytestring
4246 default-language: Haskell2010
43− if(flag(halvm))
47+ if(os(halvm))
4448 cpp-options: -DXEN -DHAVE_RDRAND
4549 cc-options: -DXEN -DHAVE_RDRAND
4650 if arch(x86_64)
@@ -57,7 +61,7 @@ library
5761 cc-options: -DisWindows
5862 extra-libraries: advapi32
5963 else
60− if !flag(halvm)
64+ if !os(halvm)
6165 Build-Depends: unix
6266
6367source-repository head