module Botan.Cipher.Class
( Cipher(..)
, SecretKey(..)
, Nonce(..)
, Ciphertext(..)
, LazyCiphertext(..)
, cipherEncryptProxy
, cipherDecryptProxy
, cipherEncryptFile
, cipherDecryptFile
, IncrementalCipher(..)
, cipherEncryptFileLazy
, cipherDecryptFileLazy
-- , MutableCipher(..)
-- , MutableCtx(..)
) where

import Botan.Prelude hiding (Ciphertext, LazyCiphertext)

import Data.Proxy (Proxy(..))

import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as Lazy

import Botan.Types.Class
import Botan.RNG

-- NOTE: I think that CBC NoPadding is the only cipher that doesn't accept arbitrary length input
-- So we can drop the Maybe from cipherEncrypt
class (HasSecretKey c, HasNonce c, HasCiphertext c) => Cipher c where

    cipherEncrypt :: SecretKey c -> Nonce c -> ByteString -> Ciphertext c
    default cipherEncrypt :: (IncrementalCipher c) => SecretKey c -> Nonce c -> ByteString -> Ciphertext c
    cipherEncrypt SecretKey c
k Nonce c
n = LazyCiphertext c -> Ciphertext c
forall alg.
HasLazyCiphertext alg =>
LazyCiphertext alg -> Ciphertext alg
toStrictCiphertext (LazyCiphertext c -> Ciphertext c)
-> (ByteString -> LazyCiphertext c) -> ByteString -> Ciphertext c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecretKey c -> Nonce c -> ByteString -> LazyCiphertext c
forall c.
IncrementalCipher c =>
SecretKey c -> Nonce c -> ByteString -> LazyCiphertext c
cipherEncryptLazy SecretKey c
k Nonce c
n (ByteString -> LazyCiphertext c)
-> (ByteString -> ByteString) -> ByteString -> LazyCiphertext c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
ByteString.fromStrict

    cipherDecrypt :: SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
    default cipherDecrypt :: (IncrementalCipher c) => SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
    cipherDecrypt SecretKey c
k Nonce c
n = (ByteString -> ByteString) -> Maybe ByteString -> Maybe ByteString
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> ByteString
ByteString.toStrict (Maybe ByteString -> Maybe ByteString)
-> (Ciphertext c -> Maybe ByteString)
-> Ciphertext c
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SecretKey c -> Nonce c -> LazyCiphertext c -> Maybe ByteString
forall c.
IncrementalCipher c =>
SecretKey c -> Nonce c -> LazyCiphertext c -> Maybe ByteString
cipherDecryptLazy SecretKey c
k Nonce c
n (LazyCiphertext c -> Maybe ByteString)
-> (Ciphertext c -> LazyCiphertext c)
-> Ciphertext c
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ciphertext c -> LazyCiphertext c
forall alg.
HasLazyCiphertext alg =>
Ciphertext alg -> LazyCiphertext alg
fromStrictCiphertext

cipherEncryptProxy :: (Cipher c) => Proxy c -> SecretKey c -> Nonce c -> ByteString -> Ciphertext c
cipherEncryptProxy :: forall c.
Cipher c =>
Proxy c -> SecretKey c -> Nonce c -> ByteString -> Ciphertext c
cipherEncryptProxy Proxy c
_ = SecretKey c -> Nonce c -> ByteString -> Ciphertext c
forall c.
Cipher c =>
SecretKey c -> Nonce c -> ByteString -> Ciphertext c
cipherEncrypt

cipherDecryptProxy :: Cipher c => Proxy c -> SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
cipherDecryptProxy :: forall c.
Cipher c =>
Proxy c
-> SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
cipherDecryptProxy Proxy c
_ = SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
forall c.
Cipher c =>
SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
cipherDecrypt

cipherEncryptFile :: (Cipher c, MonadIO m) => SecretKey c -> Nonce c -> FilePath -> m (Ciphertext c)
cipherEncryptFile :: forall c (m :: * -> *).
(Cipher c, MonadIO m) =>
SecretKey c -> Nonce c -> FilePath -> m (Ciphertext c)
cipherEncryptFile SecretKey c
k Nonce c
n FilePath
fp = SecretKey c -> Nonce c -> ByteString -> Ciphertext c
forall c.
Cipher c =>
SecretKey c -> Nonce c -> ByteString -> Ciphertext c
cipherEncrypt SecretKey c
k Nonce c
n (ByteString -> Ciphertext c) -> m ByteString -> m (Ciphertext c)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO ByteString -> m ByteString
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (FilePath -> IO ByteString
ByteString.readFile FilePath
fp)

cipherDecryptFile :: (Cipher c, MonadIO m) => SecretKey c -> Nonce c -> FilePath -> m (Maybe ByteString)
cipherDecryptFile :: forall c (m :: * -> *).
(Cipher c, MonadIO m) =>
SecretKey c -> Nonce c -> FilePath -> m (Maybe ByteString)
cipherDecryptFile SecretKey c
k Nonce c
n FilePath
fp = SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
forall c.
Cipher c =>
SecretKey c -> Nonce c -> Ciphertext c -> Maybe ByteString
cipherDecrypt SecretKey c
k Nonce c
n (Ciphertext c -> Maybe ByteString)
-> (ByteString -> Ciphertext c) -> ByteString -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Ciphertext c
forall a. Encodable a => ByteString -> a
unsafeDecode (ByteString -> Maybe ByteString)
-> m ByteString -> m (Maybe ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO ByteString -> m ByteString
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (FilePath -> IO ByteString
ByteString.readFile FilePath
fp)

class (Cipher c, HasLazyCiphertext c) => IncrementalCipher c where

    cipherEncryptLazy :: SecretKey c -> Nonce c -> Lazy.ByteString -> LazyCiphertext c
    cipherDecryptLazy :: SecretKey c -> Nonce c -> LazyCiphertext c -> Maybe Lazy.ByteString

cipherEncryptFileLazy :: (IncrementalCipher c, MonadIO m) => SecretKey c -> Nonce c -> FilePath -> m (LazyCiphertext c)
cipherEncryptFileLazy :: forall c (m :: * -> *).
(IncrementalCipher c, MonadIO m) =>
SecretKey c -> Nonce c -> FilePath -> m (LazyCiphertext c)
cipherEncryptFileLazy SecretKey c
k Nonce c
n FilePath
fp = do
    ByteString
bs <- IO ByteString -> m ByteString
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString) -> IO ByteString -> m ByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> IO ByteString
Lazy.readFile FilePath
fp
    -- Seq is probably unnecessary
    let d :: LazyCiphertext c
d = SecretKey c -> Nonce c -> ByteString -> LazyCiphertext c
forall c.
IncrementalCipher c =>
SecretKey c -> Nonce c -> ByteString -> LazyCiphertext c
cipherEncryptLazy SecretKey c
k Nonce c
n ByteString
bs
        in LazyCiphertext c
d LazyCiphertext c -> m (LazyCiphertext c) -> m (LazyCiphertext c)
forall a b. a -> b -> b
`seq` LazyCiphertext c -> m (LazyCiphertext c)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return LazyCiphertext c
d

cipherDecryptFileLazy :: (IncrementalCipher c, MonadIO m) => SecretKey c -> Nonce c -> FilePath -> m (Maybe Lazy.ByteString)
cipherDecryptFileLazy :: forall c (m :: * -> *).
(IncrementalCipher c, MonadIO m) =>
SecretKey c -> Nonce c -> FilePath -> m (Maybe ByteString)
cipherDecryptFileLazy SecretKey c
k Nonce c
n FilePath
fp = do
    ByteString
bs <- IO ByteString -> m ByteString
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString) -> IO ByteString -> m ByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> IO ByteString
Lazy.readFile FilePath
fp
    -- Seq is probably unnecessary
    let d :: Maybe ByteString
d = SecretKey c -> Nonce c -> LazyCiphertext c -> Maybe ByteString
forall c.
IncrementalCipher c =>
SecretKey c -> Nonce c -> LazyCiphertext c -> Maybe ByteString
cipherDecryptLazy SecretKey c
k Nonce c
n (ByteString -> LazyCiphertext c
forall a. LazyEncodable a => ByteString -> a
unsafeDecodeLazy ByteString
bs)
        in Maybe ByteString
d Maybe ByteString -> m (Maybe ByteString) -> m (Maybe ByteString)
forall a b. a -> b -> b
`seq` Maybe ByteString -> m (Maybe ByteString)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ByteString
d