module Network.TLS.Extra.CipherCBC (
    -- * TLS 1.2 CBC ciphers with PFS and SHA2
    ciphersuite_pfs_sha2_cbc,
    ciphersuite_ecdhe_sha2_cbc,
    ciphersuite_dhe_rsa_sha2_cbc,

    -- ** Individual CBC ciphers
    cipher_DHE_RSA_AES128_SHA256,
    cipher_DHE_RSA_AES256_SHA256,
    cipher_ECDHE_RSA_AES128CBC_SHA256,
    cipher_ECDHE_RSA_AES256CBC_SHA384,
    cipher_ECDHE_ECDSA_AES128CBC_SHA256,
) where

import Crypto.Cipher.AES
import Crypto.Cipher.Types hiding (Cipher, cipherName)
import Crypto.Error
-- import Crypto.System.CPU
import qualified Data.ByteString as B

import Network.TLS.Cipher
import Network.TLS.Imports
import Network.TLS.Types hiding (IV)

----------------------------------------------------------------

-- | TLS 1.2 AES CBC ciphers with DHE or ECDHE key exchange, ECDSA or RSA
-- authentication and a SHA256 or SHA2384 MAC.
-- For legacy applications only, deprecated in HTTPS.
ciphersuite_pfs_sha2_cbc :: [Cipher]
ciphersuite_pfs_sha2_cbc :: [Cipher]
ciphersuite_pfs_sha2_cbc =
    [ Cipher
cipher_ECDHE_ECDSA_AES128CBC_SHA256
    , Cipher
cipher_ECDHE_ECDSA_AES256CBC_SHA384
    , Cipher
cipher_ECDHE_RSA_AES128CBC_SHA256
    , Cipher
cipher_ECDHE_RSA_AES256CBC_SHA384
    , Cipher
cipher_DHE_RSA_AES128_SHA256
    , Cipher
cipher_DHE_RSA_AES256_SHA256
    ]

-- | TLS 1.2 AES CBC ciphers with ECDHE key exchange, ECDSA or RSA
-- authentication and a SHA256 or SHA2384 MAC.
-- For legacy applications only, deprecated in HTTPS.
ciphersuite_ecdhe_sha2_cbc :: [Cipher]
ciphersuite_ecdhe_sha2_cbc :: [Cipher]
ciphersuite_ecdhe_sha2_cbc =
    [ Cipher
cipher_ECDHE_ECDSA_AES128CBC_SHA256
    , Cipher
cipher_ECDHE_ECDSA_AES256CBC_SHA384
    , Cipher
cipher_ECDHE_RSA_AES128CBC_SHA256
    , Cipher
cipher_ECDHE_RSA_AES256CBC_SHA384
    ]

-- | TLS 1.2 AES CBC ciphers with DHE key exchange, RSA authentication and a
-- SHA256 MAC.
-- For legacy applications only, deprecated in HTTPS.
ciphersuite_dhe_rsa_sha2_cbc :: [Cipher]
ciphersuite_dhe_rsa_sha2_cbc :: [Cipher]
ciphersuite_dhe_rsa_sha2_cbc =
    [ Cipher
cipher_DHE_RSA_AES256_SHA256
    , Cipher
cipher_DHE_RSA_AES128_SHA256
    ]

----------------------------------------------------------------

-- | TLS 1.2 AES128 CBC, with DHE key exchange, RSA authentication and a SHA256 MAC.
-- For legacy applications only, deprecated in HTTPS.
cipher_DHE_RSA_AES128_SHA256 :: Cipher
cipher_DHE_RSA_AES128_SHA256 :: Cipher
cipher_DHE_RSA_AES128_SHA256 =
    Cipher
        { cipherID :: CipherID
cipherID = CipherID
0x0067
        , cipherName :: String
cipherName = String
"DHE-RSA-AES128-SHA256"
        , cipherBulk :: Bulk
cipherBulk = Bulk
bulk_aes128
        , cipherHash :: Hash
cipherHash = Hash
SHA256
        , cipherPRFHash :: Maybe Hash
cipherPRFHash = Hash -> Maybe Hash
forall a. a -> Maybe a
Just Hash
SHA256
        , cipherKeyExchange :: CipherKeyExchangeType
cipherKeyExchange = CipherKeyExchangeType
CipherKeyExchange_DHE_RSA
        , cipherMinVer :: Maybe Version
cipherMinVer = Version -> Maybe Version
forall a. a -> Maybe a
Just Version
TLS12 -- RFC 5288 Sec 4
        }

-- | TLS 1.2 AES256 CBC, with DHE key exchange, RSA authentication and a SHA256 MAC.
-- For legacy applications only, deprecated in HTTPS.
cipher_DHE_RSA_AES256_SHA256 :: Cipher
cipher_DHE_RSA_AES256_SHA256 :: Cipher
cipher_DHE_RSA_AES256_SHA256 =
    Cipher
cipher_DHE_RSA_AES128_SHA256
        { cipherID = 0x006B
        , cipherName = "DHE-RSA-AES256-SHA256"
        , cipherBulk = bulk_aes256
        }

-- | TLS 1.2 AES128 CBC, with ECDHE key exchange, RSA authentication and a SHA256 MAC.
-- For legacy applications only, deprecated in HTTPS.
cipher_ECDHE_RSA_AES128CBC_SHA256 :: Cipher
cipher_ECDHE_RSA_AES128CBC_SHA256 :: Cipher
cipher_ECDHE_RSA_AES128CBC_SHA256 =
    Cipher
        { cipherID :: CipherID
cipherID = CipherID
0xC027
        , cipherName :: String
cipherName = String
"ECDHE-RSA-AES128CBC-SHA256"
        , cipherBulk :: Bulk
cipherBulk = Bulk
bulk_aes128
        , cipherHash :: Hash
cipherHash = Hash
SHA256
        , cipherPRFHash :: Maybe Hash
cipherPRFHash = Hash -> Maybe Hash
forall a. a -> Maybe a
Just Hash
SHA256
        , cipherKeyExchange :: CipherKeyExchangeType
cipherKeyExchange = CipherKeyExchangeType
CipherKeyExchange_ECDHE_RSA
        , cipherMinVer :: Maybe Version
cipherMinVer = Version -> Maybe Version
forall a. a -> Maybe a
Just Version
TLS12 -- RFC 5288 Sec 4
        }

-- | TLS 1.2 AES256 CBC, with ECDHE key exchange, RSA authentication and a SHA384 MAC.
-- For legacy applications only, deprecated in HTTPS.
cipher_ECDHE_RSA_AES256CBC_SHA384 :: Cipher
cipher_ECDHE_RSA_AES256CBC_SHA384 :: Cipher
cipher_ECDHE_RSA_AES256CBC_SHA384 =
    Cipher
        { cipherID :: CipherID
cipherID = CipherID
0xC028
        , cipherName :: String
cipherName = String
"ECDHE-RSA-AES256CBC-SHA384"
        , cipherBulk :: Bulk
cipherBulk = Bulk
bulk_aes256
        , cipherHash :: Hash
cipherHash = Hash
SHA384
        , cipherPRFHash :: Maybe Hash
cipherPRFHash = Hash -> Maybe Hash
forall a. a -> Maybe a
Just Hash
SHA384
        , cipherKeyExchange :: CipherKeyExchangeType
cipherKeyExchange = CipherKeyExchangeType
CipherKeyExchange_ECDHE_RSA
        , cipherMinVer :: Maybe Version
cipherMinVer = Version -> Maybe Version
forall a. a -> Maybe a
Just Version
TLS12 -- RFC 5288 Sec 4
        }

-- | TLS 1.2 AES128 CBC, with ECDHE key exchange, ECDSA authentication and a SHA256 MAC.
-- For legacy applications only, deprecated in HTTPS.
cipher_ECDHE_ECDSA_AES128CBC_SHA256 :: Cipher
cipher_ECDHE_ECDSA_AES128CBC_SHA256 :: Cipher
cipher_ECDHE_ECDSA_AES128CBC_SHA256 =
    Cipher
        { cipherID :: CipherID
cipherID = CipherID
0xc023
        , cipherName :: String
cipherName = String
"ECDHE-ECDSA-AES128CBC-SHA256"
        , cipherBulk :: Bulk
cipherBulk = Bulk
bulk_aes128
        , cipherHash :: Hash
cipherHash = Hash
SHA256
        , cipherPRFHash :: Maybe Hash
cipherPRFHash = Hash -> Maybe Hash
forall a. a -> Maybe a
Just Hash
SHA256
        , cipherKeyExchange :: CipherKeyExchangeType
cipherKeyExchange = CipherKeyExchangeType
CipherKeyExchange_ECDHE_ECDSA
        , cipherMinVer :: Maybe Version
cipherMinVer = Version -> Maybe Version
forall a. a -> Maybe a
Just Version
TLS12 -- RFC 5289
        }

-- | TLS 1.2 AES256 CBC, with ECDHE key exchange, ECDSA authentication and a SHA384 MAC.
-- For legacy applications only, deprecated in HTTPS.
cipher_ECDHE_ECDSA_AES256CBC_SHA384 :: Cipher
cipher_ECDHE_ECDSA_AES256CBC_SHA384 :: Cipher
cipher_ECDHE_ECDSA_AES256CBC_SHA384 =
    Cipher
        { cipherID :: CipherID
cipherID = CipherID
0xC024
        , cipherName :: String
cipherName = String
"ECDHE-ECDSA-AES256CBC-SHA384"
        , cipherBulk :: Bulk
cipherBulk = Bulk
bulk_aes256
        , cipherHash :: Hash
cipherHash = Hash
SHA384
        , cipherPRFHash :: Maybe Hash
cipherPRFHash = Hash -> Maybe Hash
forall a. a -> Maybe a
Just Hash
SHA384
        , cipherKeyExchange :: CipherKeyExchangeType
cipherKeyExchange = CipherKeyExchangeType
CipherKeyExchange_ECDHE_ECDSA
        , cipherMinVer :: Maybe Version
cipherMinVer = Version -> Maybe Version
forall a. a -> Maybe a
Just Version
TLS12 -- RFC 5289
        }

----------------------------------------------------------------

aes128cbc :: BulkDirection -> BulkKey -> BulkBlock
aes128cbc :: BulkDirection -> BulkKey -> BulkBlock
aes128cbc BulkDirection
BulkEncrypt BulkKey
key =
    let ctx :: AES128
ctx = CryptoFailable AES128 -> AES128
forall a. CryptoFailable a -> a
noFail (BulkKey -> CryptoFailable AES128
forall key. ByteArray key => key -> CryptoFailable AES128
forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit BulkKey
key) :: AES128
     in ( \BulkIV
iv BulkIV
input ->
            let output :: BulkIV
output = AES128 -> IV AES128 -> BulkIV -> BulkIV
forall ba. ByteArray ba => AES128 -> IV AES128 -> ba -> ba
forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> IV cipher -> ba -> ba
cbcEncrypt AES128
ctx (BulkIV -> IV AES128
forall a. BlockCipher a => BulkIV -> IV a
makeIV_ BulkIV
iv) BulkIV
input in (BulkIV
output, Int -> BulkIV -> BulkIV
takelast Int
16 BulkIV
output)
        )
aes128cbc BulkDirection
BulkDecrypt BulkKey
key =
    let ctx :: AES128
ctx = CryptoFailable AES128 -> AES128
forall a. CryptoFailable a -> a
noFail (BulkKey -> CryptoFailable AES128
forall key. ByteArray key => key -> CryptoFailable AES128
forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit BulkKey
key) :: AES128
     in ( \BulkIV
iv BulkIV
input ->
            let output :: BulkIV
output = AES128 -> IV AES128 -> BulkIV -> BulkIV
forall ba. ByteArray ba => AES128 -> IV AES128 -> ba -> ba
forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> IV cipher -> ba -> ba
cbcDecrypt AES128
ctx (BulkIV -> IV AES128
forall a. BlockCipher a => BulkIV -> IV a
makeIV_ BulkIV
iv) BulkIV
input in (BulkIV
output, Int -> BulkIV -> BulkIV
takelast Int
16 BulkIV
input)
        )

aes256cbc :: BulkDirection -> BulkKey -> BulkBlock
aes256cbc :: BulkDirection -> BulkKey -> BulkBlock
aes256cbc BulkDirection
BulkEncrypt BulkKey
key =
    let ctx :: AES256
ctx = CryptoFailable AES256 -> AES256
forall a. CryptoFailable a -> a
noFail (BulkKey -> CryptoFailable AES256
forall key. ByteArray key => key -> CryptoFailable AES256
forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit BulkKey
key) :: AES256
     in ( \BulkIV
iv BulkIV
input ->
            let output :: BulkIV
output = AES256 -> IV AES256 -> BulkIV -> BulkIV
forall ba. ByteArray ba => AES256 -> IV AES256 -> ba -> ba
forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> IV cipher -> ba -> ba
cbcEncrypt AES256
ctx (BulkIV -> IV AES256
forall a. BlockCipher a => BulkIV -> IV a
makeIV_ BulkIV
iv) BulkIV
input in (BulkIV
output, Int -> BulkIV -> BulkIV
takelast Int
16 BulkIV
output)
        )
aes256cbc BulkDirection
BulkDecrypt BulkKey
key =
    let ctx :: AES256
ctx = CryptoFailable AES256 -> AES256
forall a. CryptoFailable a -> a
noFail (BulkKey -> CryptoFailable AES256
forall key. ByteArray key => key -> CryptoFailable AES256
forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
cipherInit BulkKey
key) :: AES256
     in ( \BulkIV
iv BulkIV
input ->
            let output :: BulkIV
output = AES256 -> IV AES256 -> BulkIV -> BulkIV
forall ba. ByteArray ba => AES256 -> IV AES256 -> ba -> ba
forall cipher ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> IV cipher -> ba -> ba
cbcDecrypt AES256
ctx (BulkIV -> IV AES256
forall a. BlockCipher a => BulkIV -> IV a
makeIV_ BulkIV
iv) BulkIV
input in (BulkIV
output, Int -> BulkIV -> BulkIV
takelast Int
16 BulkIV
input)
        )

makeIV_ :: BlockCipher a => B.ByteString -> IV a
makeIV_ :: forall a. BlockCipher a => BulkIV -> IV a
makeIV_ = IV a -> Maybe (IV a) -> IV a
forall a. a -> Maybe a -> a
fromMaybe (String -> IV a
forall a. HasCallStack => String -> a
error String
"makeIV_") (Maybe (IV a) -> IV a)
-> (BulkIV -> Maybe (IV a)) -> BulkIV -> IV a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BulkIV -> Maybe (IV a)
forall b c. (ByteArrayAccess b, BlockCipher c) => b -> Maybe (IV c)
makeIV

takelast :: Int -> B.ByteString -> B.ByteString
takelast :: Int -> BulkIV -> BulkIV
takelast Int
i BulkIV
b = Int -> BulkIV -> BulkIV
B.drop (BulkIV -> Int
B.length BulkIV
b Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i) BulkIV
b

noFail :: CryptoFailable a -> a
noFail :: forall a. CryptoFailable a -> a
noFail = CryptoFailable a -> a
forall a. CryptoFailable a -> a
throwCryptoError

----------------------------------------------------------------

bulk_aes128 :: Bulk
bulk_aes128 :: Bulk
bulk_aes128 =
    Bulk
        { bulkName :: String
bulkName = String
"AES128"
        , bulkKeySize :: Int
bulkKeySize = Int
16
        , bulkIVSize :: Int
bulkIVSize = Int
16
        , bulkExplicitIV :: Int
bulkExplicitIV = Int
0
        , bulkAuthTagLen :: Int
bulkAuthTagLen = Int
0
        , bulkBlockSize :: Int
bulkBlockSize = Int
16
        , bulkF :: BulkFunctions
bulkF = (BulkDirection -> BulkKey -> BulkBlock) -> BulkFunctions
BulkBlockF BulkDirection -> BulkKey -> BulkBlock
aes128cbc
        }

bulk_aes256 :: Bulk
bulk_aes256 :: Bulk
bulk_aes256 =
    Bulk
        { bulkName :: String
bulkName = String
"AES256"
        , bulkKeySize :: Int
bulkKeySize = Int
32
        , bulkIVSize :: Int
bulkIVSize = Int
16
        , bulkExplicitIV :: Int
bulkExplicitIV = Int
0
        , bulkAuthTagLen :: Int
bulkAuthTagLen = Int
0
        , bulkBlockSize :: Int
bulkBlockSize = Int
16
        , bulkF :: BulkFunctions
bulkF = (BulkDirection -> BulkKey -> BulkBlock) -> BulkFunctions
BulkBlockF BulkDirection -> BulkKey -> BulkBlock
aes256cbc
        }