{-# LINE 1 "OpenSSL/EVP/Open.hsc" #-}
{- -*- haskell -*- -}
{-# LINE 2 "OpenSSL/EVP/Open.hsc" #-}

-- |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           Foreign
import           Foreign.C
import           OpenSSL.EVP.Cipher hiding (cipher)
import           OpenSSL.EVP.PKey
import           OpenSSL.EVP.Internal
import           OpenSSL.Utils


foreign import ccall unsafe "EVP_OpenInit"
        _OpenInit :: Ptr EVP_CIPHER_CTX
                  -> Cipher
                  -> Ptr CChar
                  -> CInt
                  -> CString
                  -> Ptr EVP_PKEY
                  -> IO CInt


openInit :: KeyPair key => Cipher -> String -> String -> key -> IO CipherCtx
openInit cipher encKey iv pkey
    = do ctx <- newCipherCtx
         withCipherCtxPtr ctx $ \ ctxPtr ->
             withCStringLen encKey $ \ (encKeyPtr, encKeyLen) ->
                 withCString iv $ \ ivPtr ->
                     withPKeyPtr' pkey $ \ pkeyPtr ->
                         _OpenInit ctxPtr cipher encKeyPtr (fromIntegral encKeyLen) ivPtr pkeyPtr
                              >>= failIf_ (== 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
open cipher encKey iv pkey input
    = L8.unpack $ openLBS cipher encKey iv pkey $ L8.pack input

-- |@'openBS'@ decrypts a chunk of data.
openBS :: 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
       -> B8.ByteString -- ^ input string to decrypt
       -> B8.ByteString -- ^ decrypted string
openBS cipher encKey iv pkey input
    = unsafePerformIO $
      do ctx <- openInit cipher encKey iv 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
        -> String         -- ^ encrypted symmetric key to decrypt the input string
        -> String         -- ^ IV
        -> key            -- ^ private key to decrypt the symmetric key
        -> L8.ByteString -- ^ input string to decrypt
        -> L8.ByteString -- ^ decrypted string
openLBS cipher encKey iv pkey input
    = unsafePerformIO $
      do ctx <- openInit cipher encKey iv pkey
         cipherLazily ctx input