    {-# OPTIONS_HADDOCK hide #-}
    {-# LANGUAGE ExistentialQuantification #-}
    -- |
    -- Module      : Network.TLS.Cipher
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : unknown
    --
    module Network.TLS.Cipher
            ( BulkFunctions(..)
            , CipherKeyExchangeType(..)
            , Bulk(..)
            , Hash(..)
            , Cipher(..)
            , CipherID
            , cipherKeyBlockSize
            , Key
            , IV
            , cipherExchangeNeedMoreData
            ) where

    import Network.TLS.Types (CipherID)
    import Network.TLS.Struct (Version(..))

    import qualified Data.ByteString as B

    -- FIXME convert to newtype
    type Key = B.ByteString
    type IV = B.ByteString

    data BulkFunctions =
              BulkBlockF (Key -> IV -> B.ByteString -> B.ByteString)
                         (Key -> IV -> B.ByteString -> B.ByteString)
            | BulkStreamF (Key -> IV)
                          (IV -> B.ByteString -> (B.ByteString, IV))
                          (IV -> B.ByteString -> (B.ByteString, IV))

    data CipherKeyExchangeType =
              CipherKeyExchange_RSA
            | CipherKeyExchange_DH_Anon
            | CipherKeyExchange_DHE_RSA
            | CipherKeyExchange_ECDHE_RSA
            | CipherKeyExchange_DHE_DSS
            | CipherKeyExchange_DH_DSS
            | CipherKeyExchange_DH_RSA
            | CipherKeyExchange_ECDH_ECDSA
            | CipherKeyExchange_ECDH_RSA
            | CipherKeyExchange_ECDHE_ECDSA
            deriving (Show,Eq)

    data Bulk = Bulk
            { bulkName         :: String
            , bulkKeySize      :: Int
            , bulkIVSize       :: Int
            , bulkBlockSize    :: Int
            , bulkF            :: BulkFunctions
            }

    data Hash = Hash
            { hashName         :: String
            , hashSize         :: Int
            , hashF            :: B.ByteString -> B.ByteString
            }

    -- | Cipher algorithm
    data Cipher = Cipher
            { cipherID           :: CipherID
            , cipherName         :: String
            , cipherHash         :: Hash
            , cipherBulk         :: Bulk
            , cipherKeyExchange  :: CipherKeyExchangeType
            , cipherMinVer       :: Maybe Version
            }

    cipherKeyBlockSize :: Cipher -> Int
    cipherKeyBlockSize cipher = 2 * (hashSize (cipherHash cipher) + bulkIVSize bulk + bulkKeySize bulk)
            where bulk = cipherBulk cipher

    instance Show Cipher where
            show c = cipherName c

    instance Eq Cipher where
            (==) c1 c2 = cipherID c1 == cipherID c2

    cipherExchangeNeedMoreData :: CipherKeyExchangeType -> Bool
    cipherExchangeNeedMoreData CipherKeyExchange_RSA         = False
    cipherExchangeNeedMoreData CipherKeyExchange_DH_Anon     = True
    cipherExchangeNeedMoreData CipherKeyExchange_DHE_RSA     = True
    cipherExchangeNeedMoreData CipherKeyExchange_ECDHE_RSA   = True
    cipherExchangeNeedMoreData CipherKeyExchange_DHE_DSS     = True
    cipherExchangeNeedMoreData CipherKeyExchange_DH_DSS      = False
    cipherExchangeNeedMoreData CipherKeyExchange_DH_RSA      = False
    cipherExchangeNeedMoreData CipherKeyExchange_ECDH_ECDSA  = True
    cipherExchangeNeedMoreData CipherKeyExchange_ECDH_RSA    = True
    cipherExchangeNeedMoreData CipherKeyExchange_ECDHE_ECDSA = True