{-# 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 hiding (unsafePerformIO)
import           System.IO.Unsafe (unsafePerformIO)
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