{-# 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 :: Int -> IO ByteString getEntropy = IO CryptHandle -> (CryptHandle -> IO ()) -> (CryptHandle -> IO ByteString) -> IO ByteString forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c bracket IO CryptHandle openHandle CryptHandle -> IO () closeHandle ((CryptHandle -> IO ByteString) -> IO ByteString) -> (Int -> CryptHandle -> IO ByteString) -> Int -> IO ByteString forall b c a. (b -> c) -> (a -> b) -> a -> c . (CryptHandle -> Int -> IO ByteString) -> Int -> CryptHandle -> IO ByteString forall a b c. (a -> b -> c) -> b -> a -> c flip CryptHandle -> Int -> IO ByteString 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 :: Int -> IO (Maybe ByteString) getHardwareEntropy = Int -> IO (Maybe ByteString) hardwareRandom