File: Entropy.hs

package info (click to toggle)
haskell-entropy 0.4.1.11-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 100 kB
  • sloc: haskell: 358; ansic: 182; makefile: 2
file content (76 lines) | stat: -rw-r--r-- 2,454 bytes parent folder | download | duplicates (3)
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