    {-# LANGUAGE ForeignFunctionInterface #-}
    {-# LANGUAGE CApiFFI                  #-}
    -- | PRNG services
    --   See <http://www.openssl.org/docs/crypto/rand.html>
    --   For random Integer generation, see "OpenSSL.BN"
    module OpenSSL.Random
        ( -- * Random byte generation
          randBytes
        , prandBytes
        , add
        ) where
    import           Foreign
    import           Foreign.C.Types
    import qualified Data.ByteString as BS
    import           OpenSSL.Utils

    foreign import capi unsafe "openssl/rand.h RAND_bytes"
            _RAND_bytes :: Ptr CChar -> CInt -> IO CInt

    foreign import capi unsafe "openssl/rand.h RAND_pseudo_bytes"
            _RAND_pseudo_bytes :: Ptr CChar -> CInt -> IO ()

    foreign import capi unsafe "openssl/rand.h RAND_add"
            _RAND_add :: Ptr CChar -> CInt -> CInt -> IO ()

    -- | Return a bytestring consisting of the given number of strongly random
    --   bytes
    randBytes :: Int  -- ^ the number of bytes requested
              -> IO BS.ByteString
    randBytes :: Int -> IO ByteString
    randBytes Int
    n =
      Int -> (Ptr CChar -> IO ByteString) -> IO ByteString
    forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
    allocaArray Int
    n ((Ptr CChar -> IO ByteString) -> IO ByteString)
    -> (Ptr CChar -> IO ByteString) -> IO ByteString
    forall a b. (a -> b) -> a -> b
    $ \Ptr CChar
    bufPtr ->
      do Ptr CChar -> CInt -> IO CInt
    _RAND_bytes Ptr CChar
    bufPtr (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    n) IO CInt -> (CInt -> IO ()) -> IO ()
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= (CInt -> Bool) -> CInt -> IO ()
    forall a. (a -> Bool) -> a -> IO ()
    failIf_ (CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    /= CInt
    1)
         CStringLen -> IO ByteString
    BS.packCStringLen (Ptr CChar
    bufPtr, Int
    n)

    -- | Return a bytestring consisting of the given number of pseudo random
    --   bytes
    prandBytes :: Int  -- ^ the number of bytes requested
               -> IO BS.ByteString
    prandBytes :: Int -> IO ByteString
    prandBytes Int
    n =
      Int -> (Ptr CChar -> IO ByteString) -> IO ByteString
    forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
    allocaArray Int
    n ((Ptr CChar -> IO ByteString) -> IO ByteString)
    -> (Ptr CChar -> IO ByteString) -> IO ByteString
    forall a b. (a -> b) -> a -> b
    $ \Ptr CChar
    bufPtr ->
      do Ptr CChar -> CInt -> IO ()
    _RAND_pseudo_bytes Ptr CChar
    bufPtr (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    n)
         CStringLen -> IO ByteString
    BS.packCStringLen (Ptr CChar
    bufPtr, Int
    n)

    -- | Add data to the entropy pool. It's safe to add sensitive information
    --   (e.g. user passwords etc) to the pool. Also, adding data with an entropy
    --   of 0 can never hurt.
    add :: BS.ByteString  -- ^ random data to be added to the pool
        -> Int  -- ^ the number of bits of entropy in the first argument
        -> IO ()
    add :: ByteString -> Int -> IO ()
    add ByteString
    bs Int
    entropy =
      ByteString -> (CStringLen -> IO ()) -> IO ()
    forall a. ByteString -> (CStringLen -> IO a) -> IO a
    BS.useAsCStringLen ByteString
    bs ((CStringLen -> IO ()) -> IO ()) -> (CStringLen -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \(Ptr CChar
    ptr, Int
    len) ->
      Ptr CChar -> CInt -> CInt -> IO ()
    _RAND_add Ptr CChar
    ptr (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    len) (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    entropy)