{-# LANGUAGE CPP                      #-}
{-# LANGUAGE ForeignFunctionInterface #-}
-- |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 ccall unsafe "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 :: Cipher -> ByteString -> ByteString -> key -> IO CipherCtx
openInit Cipher
cipher ByteString
encKey ByteString
iv key
pkey
    = do CipherCtx
ctx <- IO CipherCtx
newCipherCtx
         CipherCtx -> (Ptr EVP_CIPHER_CTX -> IO ()) -> IO ()
forall a. CipherCtx -> (Ptr EVP_CIPHER_CTX -> IO a) -> IO a
withCipherCtxPtr CipherCtx
ctx ((Ptr EVP_CIPHER_CTX -> IO ()) -> IO ())
-> (Ptr EVP_CIPHER_CTX -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ 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 (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)
         CipherCtx -> IO CipherCtx
forall (m :: * -> *) a. Monad m => a -> m a
return CipherCtx
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 :: 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 :: 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 CipherCtx
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
         CipherCtx -> ByteString -> IO ByteString
cipherStrictly CipherCtx
ctx ByteString
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 :: 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 CipherCtx
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
         CipherCtx -> ByteString -> IO ByteString
cipherLazily CipherCtx
ctx ByteString
input