git.iko.soy/typeable/entropy
on main help sign in
Use RDRAND in addition to urandom.
c33deceThomas M. DuBuisson
System/Entropy.hs+10−4
@@ -8,10 +8,10 @@
8
8
9 Currently supporting:
9 Currently supporting:
10
10
11− - Windows via CryptoAPO
11+ - Windows via CryptoAPI
12 - *nix systems via @\/dev\/urandom@
12 - *nix systems via @\/dev\/urandom@
13− - QNX
13+ - Includes QNX
14− - Xen only when RDRAND is available.
14+ - Xen (only when RDRAND is available)
15-}
15-}
16
16
17module System.Entropy
17module System.Entropy
@@ -20,18 +20,24 @@ module System.Entropy
20 module System.EntropyWindows
20 module System.EntropyWindows
21 ) where
21 ) where
22import System.EntropyWindows
22import System.EntropyWindows
23+#else
24+#ifdef XEN
25+ module System.EntropyXen
26+ ) where
27+import System.EntropyXen
23#else
28#else
24 module System.EntropyNix
29 module System.EntropyNix
25 ) where
30 ) where
26import System.EntropyNix
31import System.EntropyNix
27#endif
32#endif
33+#endif
28
34
29import qualified Data.ByteString as B
35import qualified Data.ByteString as B
30
36
31-- |Get a specific number of bytes of cryptographically
37-- |Get a specific number of bytes of cryptographically
32-- secure random data using the system-specific facilities.
38-- secure random data using the system-specific facilities.
33--
39--
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
35-- Windows. In short, this entropy is considered cryptographically secure
41-- Windows. In short, this entropy is considered cryptographically secure
36-- but not true entropy.
42-- but not true entropy.
37getEntropy :: Int -> IO B.ByteString
43getEntropy :: Int -> IO B.ByteString
System/EntropyNix.hs+15−39
@@ -18,6 +18,7 @@ module System.EntropyNix
18import Control.Monad (liftM, when)
18import Control.Monad (liftM, when)
19import Data.ByteString as B
19import Data.ByteString as B
20import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
20import System.IO.Error (mkIOError, eofErrorType, ioeSetErrorString)
21+import Data.Bits (xor)
21
22
22import Foreign (allocaBytes)
23import Foreign (allocaBytes)
23import Foreign.Ptr
24import Foreign.Ptr
@@ -29,13 +30,6 @@ import Data.ByteString.Internal as B
29#undef HAVE_RDRAND
30#undef HAVE_RDRAND
30#endif
31#endif
31
32
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−
39import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
33import System.Posix (openFd, closeFd, fdReadBuf, OpenMode(..), defaultFileFlags, Fd)
40
34
41source :: FilePath
35source :: FilePath
@@ -45,8 +39,7 @@ source = "/dev/urandom"
45data CryptHandle
39data CryptHandle
46 = CH Fd
40 = CH Fd
47#ifdef HAVE_RDRAND
41#ifdef HAVE_RDRAND
48− | UseRdRand
42+ | UseRdRand Fd
49−#endif
50#endif
43#endif
51
44
52-- |Open a `CryptHandle`
45-- |Open a `CryptHandle`
@@ -54,46 +47,31 @@ openHandle :: IO CryptHandle
54openHandle = do
47openHandle = do
55#ifdef HAVE_RDRAND
48#ifdef HAVE_RDRAND
56 b <- cpuHasRdRand
49 b <- cpuHasRdRand
57− if b then return UseRdRand
50+ if b then UseRdRand `fmap` nonRDRandHandle
58− else nonRDRandHandle
51+ else CH `fmap` nonRDRandHandle
59#else
52#else
60− nonRDRandHandle
53+ CH `fmap` nonRDRandHandle
61#endif
54#endif
62 where
55 where
63−#ifdef XEN
64− nonRDRandHandle :: IO CryptHandle
56+ nonRDRandHandle :: IO Fd
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)
57+ nonRDRandHandle = openFd source ReadOnly Nothing defaultFileFlags
69−#endif
70
58
71-- |Close the `CryptHandle`
59-- |Close the `CryptHandle`
72closeHandle :: CryptHandle -> IO ()
60closeHandle :: CryptHandle -> IO ()
73−#ifndef XEN
74closeHandle (CH h) = closeFd h
61closeHandle (CH h) = closeFd h
75−#endif
76−#ifdef HAVE_RDRAND
77−closeHandle UseRdRand = return ()
62+closeHandle (UseRdRand h) = closeFd h
78−#endif
79
63
80-- |Read random data from a `CryptHandle`
64-- |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
89hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
65hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
90hGetEntropy (CH h) = fdReadBS h
66hGetEntropy (CH h) = fdReadBS h
91#ifdef HAVE_RDRAND
67#ifdef HAVE_RDRAND
92−hGetEntropy UseRdRand = \n -> do
68+hGetEntropy (UseRdRand h) = \n ->
69+ do bsURandom <- fdReadBS h n
93− B.create n $ \ptr -> do
70+ bsRDRAND <- B.create n $ \ptr -> do
94− r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
71+ r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
95− when (r /= 0)
72+ when (r /= 0)
96− (fail "RDRand failed to gather entropy")
73+ (fail "RDRand failed to gather entropy")
74+ return $ B.pack $ B.zipWith xor bsURandom bsRDRAND
97#endif
75#endif
98
76
99fdReadBS :: Fd -> Int -> IO B.ByteString
77fdReadBS :: Fd -> Int -> IO B.ByteString
@@ -103,8 +81,6 @@ fdReadBS fd n = do
103 case rc of
81 case rc of
104 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
82 0 -> ioError (ioeSetErrorString (mkIOError eofErrorType "fdRead" Nothing Nothing) "EOF")
105 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
83 n' -> B.packCStringLen (castPtr buf, fromIntegral n')
106−#endif
107−
108
84
109#ifdef HAVE_RDRAND
85#ifdef HAVE_RDRAND
110foreign import ccall unsafe "cpu_has_rdrand"
86foreign 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
35 exposed-modules: System.Entropy
35 exposed-modules: System.Entropy
36 if os(windows)
36 if os(windows)
37 other-modules: System.EntropyWindows
37 other-modules: System.EntropyWindows
38− else
38+ else {
39+ if os(halvm)
40+ other-modules: System.EntropyXen
41+ else
39− other-modules: System.EntropyNix
42+ other-modules: System.EntropyNix
43+ }
40 other-extensions: CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables
44 other-extensions: CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables
41 build-depends: base == 4.*, bytestring
45 build-depends: base == 4.*, bytestring
42 default-language: Haskell2010
46 default-language: Haskell2010
43− if(flag(halvm))
47+ if(os(halvm))
44 cpp-options: -DXEN -DHAVE_RDRAND
48 cpp-options: -DXEN -DHAVE_RDRAND
45 cc-options: -DXEN -DHAVE_RDRAND
49 cc-options: -DXEN -DHAVE_RDRAND
46 if arch(x86_64)
50 if arch(x86_64)
@@ -57,7 +61,7 @@ library
57 cc-options: -DisWindows
61 cc-options: -DisWindows
58 extra-libraries: advapi32
62 extra-libraries: advapi32
59 else
63 else
60− if !flag(halvm)
64+ if !os(halvm)
61 Build-Depends: unix
65 Build-Depends: unix
62
66
63source-repository head
67source-repository head