git.iko.soy/typeable/entropy
on main help sign in
Add RDRAND instruction support.
commit750063ec25b4c36769c9c2562f948d5747d660e3 authorThomas M. DuBuisson <tommd@galois.com> dateSun 12 May 2013, 15:31 (13 years ago) parentf72a11f
4 files changed+99−6
System/Entropy.hs+30−3 cbits/rdrand.c+51 cbits/rdrand.h+10 entropy.cabal+8−3
System/Entropy.hs+30−3
@@ -16,9 +16,8 @@ module System.Entropy
1616 , closeHandle
1717 ) where
1818
19−import Control.Monad (liftM)
19+import Control.Monad (liftM, when)
2020import Data.ByteString as B
21−import Data.ByteString.Lazy as L
2221import System.IO (openFile, hClose, IOMode(..), Handle, withBinaryFile)
2322
2423#if defined(isWindows)
@@ -114,6 +113,12 @@ hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
114113hGetEntropy (CH h) = cryptGenRandom h
115114
116115#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
117122source = "/dev/urandom"
118123
119124-- |Handle for manual resource mangement
@@ -131,6 +136,17 @@ closeHandle (CH h) = hClose h
131136hGetEntropy :: CryptHandle -> Int -> IO B.ByteString
132137hGetEntropy (CH h) = B.hGet h
133138
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+
134150-- |Inefficiently get a specific number of bytes of cryptographically
135151-- secure random data using the system-specific facilities.
136152--
@@ -138,6 +154,17 @@ hGetEntropy (CH h) = B.hGet h
138154-- this entropy is considered "cryptographically secure" but not true
139155-- entropy.
140156getEntropy :: Int -> IO B.ByteString
141−getEntropy n = withBinaryFile source ReadMode (`B.hGet` n)
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 -}
167+ withBinaryFile source ReadMode (`B.hGet` n)
142168#endif
169+{- OS Test -}
143170
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 @@
11name: entropy
2−version: 0.2.1
2+version: 0.2.2
33license: BSD3
44license-file: LICENSE
55copyright: Thomas DuBuisson <thomas.dubuisson@gmail.com>
@@ -18,14 +18,19 @@ build-type: Simple
1818cabal-version: >= 1.6
1919tested-with: GHC == 6.12.1
2020data-files:
21−extra-source-files:
21+extra-source-files: ./cbits/rdrand.c
22+ , ./cbits/rdrand.h
2223
2324Library
2425 Build-Depends: base == 4.*, bytestring
25− ghc-options:
26+ ghc-options: -Wall -O2
2627 hs-source-dirs:
2728 exposed-modules: System.Entropy
2829 other-modules:
30+ if arch(x86_64)
31+ cpp-options: -Darch_x86_64
32+ c-sources: cbits/rdrand.c
33+ include-dirs: cbits
2934 if os(windows)
3035 cpp-options: -DisWindows
3136 extra-libraries: advapi32