1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
{-# LANGUAGE CPP, ForeignFunctionInterface, BangPatterns, ScopedTypeVariables #-}
{-|
Maintainer: Thomas.DuBuisson@gmail.com
Stability: beta
Portability: portable
Obtain entropy from system sources or x86 RDRAND when available.
Currently supporting:
- Windows via CryptoAPI
- *nix systems via @\/dev\/urandom@
- Includes QNX
- ghcjs/browser via JavaScript crypto API.
-}
module System.Entropy
( getEntropy,
getHardwareEntropy,
CryptHandle,
openHandle,
hGetEntropy,
closeHandle
) where
#ifdef ghcjs_HOST_OS
import System.EntropyGhcjs
#elif defined(isWindows)
import System.EntropyWindows
#else
import System.EntropyNix
#endif
import qualified Data.ByteString as B
import Control.Exception (bracket)
-- |Get a specific number of bytes of cryptographically
-- secure random data using the *system-specific* sources.
-- (As of 0.4. Versions <0.4 mixed system and hardware sources)
--
-- The returned random value is considered cryptographically secure but not true entropy.
--
-- On some platforms this requires 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
|