git.iko.soy/typeable/entropy
on main help sign in
Add RDRAND instruction support.
750063eThomas M. DuBuisson
System/Entropy.hs+30−3
@@ -16,9 +16,8 @@ module System.Entropy
16 , closeHandle
16 , closeHandle
17 ) where
17 ) where
18
18
19−import Control.Monad (liftM)
19+import Control.Monad (liftM, when)
20import Data.ByteString as B
20import Data.ByteString as B
21−import Data.ByteString.Lazy as L
22import System.IO (openFile, hClose, IOMode(..), Handle, withBinaryFile)
21import System.IO (openFile, hClose, IOMode(..), Handle, withBinaryFile)
23
22
24#if defined(isWindows)
23#if defined(isWindows)
@@ -114,6 +113,12 @@ hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
114hGetEntropy (CH h) = cryptGenRandom h
113hGetEntropy (CH h) = cryptGenRandom h
115
114
116#else
115#else
116+{- Not windows, assuming nix with a /dev/urandom -}
117+import Foreign.C.Types
118+import Foreign.Ptr
119+import Data.ByteString.Internal as B
120+
121+source :: FilePath
117source = "/dev/urandom"
122source = "/dev/urandom"
118
123
119-- |Handle for manual resource mangement
124-- |Handle for manual resource mangement
@@ -131,6 +136,17 @@ closeHandle (CH h) = hClose h
131hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
136hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
132hGetEntropy (CH h) = B.hGet h
137hGetEntropy (CH h) = B.hGet h
133
138
139+#ifdef arch_x86_64
140+foreign import ccall unsafe "cpu_has_rdrand"
141+ c_cpu_has_rdrand :: IO CInt
142+
143+foreign import ccall unsafe "get_rand_bytes"
144+ c_get_rand_bytes :: Ptr CUChar -> CSize -> IO CInt
145+
146+cpuHasRdRand :: IO Bool
147+cpuHasRdRand = (/= 0) `fmap` c_cpu_has_rdrand
148+#endif
149+
134-- |Inefficiently get a specific number of bytes of cryptographically
150-- |Inefficiently get a specific number of bytes of cryptographically
135-- secure random data using the system-specific facilities.
151-- secure random data using the system-specific facilities.
136--
152--
@@ -138,6 +154,17 @@ hGetEntropy (CH h) = B.hGet h
138-- this entropy is considered "cryptographically secure" but not true
154-- this entropy is considered "cryptographically secure" but not true
139-- entropy.
155-- entropy.
140getEntropy :: Int -> IO B.ByteString
156getEntropy :: Int -> IO B.ByteString
157+getEntropy n = do
158+#if arch_x86_64
159+ b <- cpuHasRdRand
160+ if b then B.create n $ \ptr -> do
161+ r <- c_get_rand_bytes (castPtr ptr) (fromIntegral n)
162+ when (r /= 0)
163+ (fail "RDRand failed to gather entropy")
164+ else do
165+#endif
166+{- arch_x86 -}
141−getEntropy n = withBinaryFile source ReadMode (`B.hGet` n)
167+ withBinaryFile source ReadMode (`B.hGet` n)
142#endif
168#endif
169+{- OS Test -}
143
170
cbits/rdrand.cnew file+51
@@ -0,0 +1,51 @@
1+#include <stdint.h>
2+#include <stdlib.h>
3+
4+int cpu_has_rdrand()
5+{
6+ uint32_t ax,bx,cx,dx,func=1;
7+ __asm__ volatile ("cpuid":\
8+ "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
9+ return (cx & 0x40000000);
10+}
11+
12+// Returns 1 on success
13+inline int _rdrand64_step(uint64_t *therand)
14+{
15+ unsigned char err;
16+ asm volatile("rdrand %0 ; setc %1"
17+ : "=r" (*therand), "=qm" (err));
18+ return (int) err;
19+}
20+
21+// Returns 0 on success, non-zero on failure.
22+int get_rand_bytes(uint8_t *therand, size_t len)
23+{
24+ int cnt;
25+ int fail=0;
26+ uint8_t *p = therand;
27+ uint8_t *end = therand + len;
28+ if((uint64_t)p%8 != 0) {
29+ uint64_t tmp;
30+ fail |= !_rdrand64_step(&tmp);
31+ while((uint64_t)p%8 != 0 && p != end) {
32+ *p = (uint8_t)(tmp & 0xFF);
33+ tmp = tmp >> 8;
34+ p++;
35+ }
36+ }
37+ for(; p <= end - sizeof(uint64_t); p+=sizeof(uint64_t)) {
38+ fail |= !_rdrand64_step((uint64_t *)p);
39+ }
40+ if(p != end) {
41+ uint64_t tmp;
42+ int cnt;
43+ fail |= !_rdrand64_step(&tmp);
44+ while(p != end) {
45+ *p = (uint8_t)(tmp & 0xFF);
46+ tmp = tmp >> 8;
47+ p++;
48+ }
49+ }
50+ return fail;
51+}
cbits/rdrand.hnew file+10
@@ -0,0 +1,10 @@
1+#ifndef rdrand_h
2+#include <stdint.h>
3+
4+#ifdef arch_x86_64
5+int cpu_has_rdrand()
6+
7+// Returns 0 on success, non-zero on failure.
8+int get_rand_bytes(uint8_t *therand, size_t len)
9+#endif /* arch_x86_64 */
10+#endif // rdrand_h
entropy.cabal+8−3
@@ -1,5 +1,5 @@
1name: entropy
1name: entropy
2−version: 0.2.1
2+version: 0.2.2
3license: BSD3
3license: BSD3
4license-file: LICENSE
4license-file: LICENSE
5copyright: Thomas DuBuisson <thomas.dubuisson@gmail.com>
5copyright: Thomas DuBuisson <thomas.dubuisson@gmail.com>
@@ -18,14 +18,19 @@ build-type: Simple
18cabal-version: >= 1.6
18cabal-version: >= 1.6
19tested-with: GHC == 6.12.1
19tested-with: GHC == 6.12.1
20data-files:
20data-files:
21−extra-source-files:
21+extra-source-files: ./cbits/rdrand.c
22+ , ./cbits/rdrand.h
22
23
23Library
24Library
24 Build-Depends: base == 4.*, bytestring
25 Build-Depends: base == 4.*, bytestring
25− ghc-options:
26+ ghc-options: -Wall -O2
26 hs-source-dirs:
27 hs-source-dirs:
27 exposed-modules: System.Entropy
28 exposed-modules: System.Entropy
28 other-modules:
29 other-modules:
30+ if arch(x86_64)
31+ cpp-options: -Darch_x86_64
32+ c-sources: cbits/rdrand.c
33+ include-dirs: cbits
29 if os(windows)
34 if os(windows)
30 cpp-options: -DisWindows
35 cpp-options: -DisWindows
31 extra-libraries: advapi32
36 extra-libraries: advapi32