diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -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.
 
 [![Build Status](https://travis-ci.org/TomMD/entropy.svg?branch=master)](https://travis-ci.org/TomMD/entropy)
diff --git a/System/Entropy.hs b/System/Entropy.hs
--- a/System/Entropy.hs
+++ b/System/Entropy.hs
@@ -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
diff --git a/System/EntropyNix.hs b/System/EntropyNix.hs
--- a/System/EntropyNix.hs
+++ b/System/EntropyNix.hs
@@ -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 =
diff --git a/System/EntropyWindows.hs b/System/EntropyWindows.hs
--- a/System/EntropyWindows.hs
+++ b/System/EntropyWindows.hs
@@ -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
diff --git a/System/EntropyXen.hs b/System/EntropyXen.hs
--- a/System/EntropyXen.hs
+++ b/System/EntropyXen.hs
@@ -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
diff --git a/entropy.cabal b/entropy.cabal
--- a/entropy.cabal
+++ b/entropy.cabal
@@ -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))
