    {-# LANGUAGE CPP                      #-}
    {-# LANGUAGE ForeignFunctionInterface #-}
    {-# LANGUAGE CApiFFI                  #-}
    -- |Asymmetric cipher decryption using encrypted symmetric key. This
    -- is an opposite of "OpenSSL.EVP.Seal".
    module OpenSSL.EVP.Open
        ( open
        , openBS
        , openLBS
        )
        where
    import qualified Data.ByteString.Char8 as B8
    import qualified Data.ByteString.Lazy.Char8 as L8
    import qualified Data.ByteString.Unsafe as B8
    import Foreign.C.String (CString)
    #if MIN_VERSION_base(4,5,0)
    import Foreign.C.Types (CChar(..), CInt(..))
    #else
    import Foreign.C.Types (CChar, CInt)
    #endif
    import Foreign.Ptr (Ptr)
    import OpenSSL.EVP.Cipher hiding (cipher)
    import OpenSSL.EVP.PKey
    import OpenSSL.EVP.Internal
    import OpenSSL.Utils
    import System.IO.Unsafe (unsafePerformIO)

    foreign import capi unsafe "openssl/evp.h EVP_OpenInit"
            _OpenInit :: Ptr EVP_CIPHER_CTX
                      -> Cipher
                      -> Ptr CChar
                      -> CInt
                      -> CString
                      -> Ptr EVP_PKEY
                      -> IO CInt

    openInit :: KeyPair key =>
                Cipher
             -> B8.ByteString
             -> B8.ByteString
             -> key
             -> IO CipherCtx
    openInit :: forall key.
    KeyPair key =>
    Cipher -> ByteString -> ByteString -> key -> IO CipherCtx
    openInit Cipher
    cipher ByteString
    encKey ByteString
    iv key
    pkey
        = do ctx <- IO CipherCtx
    newCipherCtx
             withCipherCtxPtr ctx $ \ Ptr EVP_CIPHER_CTX
    ctxPtr ->
                 ByteString -> (CStringLen -> IO ()) -> IO ()
    forall a. ByteString -> (CStringLen -> IO a) -> IO a
    B8.unsafeUseAsCStringLen ByteString
    encKey ((CStringLen -> IO ()) -> IO ()) -> (CStringLen -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \ (Ptr CChar
    encKeyPtr, Int
    encKeyLen) ->
                     ByteString -> (Ptr CChar -> IO ()) -> IO ()
    forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
    B8.unsafeUseAsCString ByteString
    iv ((Ptr CChar -> IO ()) -> IO ()) -> (Ptr CChar -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \ Ptr CChar
    ivPtr ->
                         key -> (Ptr EVP_PKEY -> IO ()) -> IO ()
    forall k a. PKey k => k -> (Ptr EVP_PKEY -> IO a) -> IO a
    withPKeyPtr' key
    pkey ((Ptr EVP_PKEY -> IO ()) -> IO ())
    -> (Ptr EVP_PKEY -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \ Ptr EVP_PKEY
    pkeyPtr ->
                             Ptr EVP_CIPHER_CTX
    -> Cipher
    -> Ptr CChar
    -> CInt
    -> Ptr CChar
    -> Ptr EVP_PKEY
    -> IO CInt
    _OpenInit Ptr EVP_CIPHER_CTX
    ctxPtr Cipher
    cipher Ptr CChar
    encKeyPtr (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    encKeyLen) Ptr CChar
    ivPtr Ptr EVP_PKEY
    pkeyPtr
                                  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
    0)
             return ctx

    -- |@'open'@ lazilly decrypts a stream of data. The input string
    -- doesn't necessarily have to be finite.
    open :: KeyPair key =>
            Cipher -- ^ symmetric cipher algorithm to use
         -> String -- ^ encrypted symmetric key to decrypt the input string
         -> String -- ^ IV
         -> key    -- ^ private key to decrypt the symmetric key
         -> String -- ^ input string to decrypt
         -> String -- ^ decrypted string
    {-# DEPRECATED open "Use openBS or openLBS instead." #-}
    open :: forall key.
    KeyPair key =>
    Cipher -> String -> String -> key -> String -> String
    open Cipher
    cipher String
    encKey String
    iv key
    pkey String
    input
        = ByteString -> String
    L8.unpack (ByteString -> String) -> ByteString -> String
    forall a b. (a -> b) -> a -> b
    $ Cipher
    -> ByteString -> ByteString -> key -> ByteString -> ByteString
    forall key.
    KeyPair key =>
    Cipher
    -> ByteString -> ByteString -> key -> ByteString -> ByteString
    openLBS Cipher
    cipher (String -> ByteString
    B8.pack String
    encKey) (String -> ByteString
    B8.pack String
    iv) key
    pkey (String -> ByteString
    L8.pack String
    input)

    -- |@'openBS'@ decrypts a chunk of data.
    openBS :: KeyPair key =>
              Cipher        -- ^ symmetric cipher algorithm to use
           -> B8.ByteString -- ^ encrypted symmetric key to decrypt the input string
           -> B8.ByteString -- ^ IV
           -> key           -- ^ private key to decrypt the symmetric key
           -> B8.ByteString -- ^ input string to decrypt
           -> B8.ByteString -- ^ decrypted string
    openBS :: forall key.
    KeyPair key =>
    Cipher
    -> ByteString -> ByteString -> key -> ByteString -> ByteString
    openBS Cipher
    cipher ByteString
    encKey ByteString
    iv key
    pkey ByteString
    input
        = IO ByteString -> ByteString
    forall a. IO a -> a
    unsafePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $
          do ctx <- Cipher -> ByteString -> ByteString -> key -> IO CipherCtx
    forall key.
    KeyPair key =>
    Cipher -> ByteString -> ByteString -> key -> IO CipherCtx
    openInit Cipher
    cipher ByteString
    encKey ByteString
    iv key
    pkey
             cipherStrictly ctx input

    -- |@'openLBS'@ lazilly decrypts a stream of data. The input string
    -- doesn't necessarily have to be finite.
    openLBS :: KeyPair key =>
               Cipher        -- ^ symmetric cipher algorithm to use
            -> B8.ByteString -- ^ encrypted symmetric key to decrypt the input string
            -> B8.ByteString -- ^ IV
            -> key           -- ^ private key to decrypt the symmetric key
            -> L8.ByteString -- ^ input string to decrypt
            -> L8.ByteString -- ^ decrypted string
    openLBS :: forall key.
    KeyPair key =>
    Cipher
    -> ByteString -> ByteString -> key -> ByteString -> ByteString
    openLBS Cipher
    cipher ByteString
    encKey ByteString
    iv key
    pkey ByteString
    input
        = IO ByteString -> ByteString
    forall a. IO a -> a
    unsafePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $
          do ctx <- Cipher -> ByteString -> ByteString -> key -> IO CipherCtx
    forall key.
    KeyPair key =>
    Cipher -> ByteString -> ByteString -> key -> IO CipherCtx
    openInit Cipher
    cipher ByteString
    encKey ByteString
    iv key
    pkey
             cipherLazily ctx input