    -- |
    -- Module      : Crypto.Cipher.TripleDES
    -- License     : BSD-style
    -- Stability   : experimental
    -- Portability : ???

    module Crypto.Cipher.TripleDES
        ( DES_EEE3
        , DES_EDE3
        , DES_EEE2
        , DES_EDE2
        ) where

    import           Data.Word
    import           Crypto.Error
    import           Crypto.Cipher.Types
    import           Crypto.Cipher.DES.Primitive
    import           Crypto.Internal.ByteArray (ByteArrayAccess)
    import qualified Crypto.Internal.ByteArray as B
    import           Data.Memory.Endian

    -- | 3DES with 3 different keys used all in the same direction
    data DES_EEE3 = DES_EEE3 Word64 Word64 Word64
        deriving (DES_EEE3 -> DES_EEE3 -> Bool
    (DES_EEE3 -> DES_EEE3 -> Bool)
    -> (DES_EEE3 -> DES_EEE3 -> Bool) -> Eq DES_EEE3
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DES_EEE3 -> DES_EEE3 -> Bool
    == :: DES_EEE3 -> DES_EEE3 -> Bool
    $c/= :: DES_EEE3 -> DES_EEE3 -> Bool
    /= :: DES_EEE3 -> DES_EEE3 -> Bool
    Eq)

    -- | 3DES with 3 different keys used in alternative direction
    data DES_EDE3 = DES_EDE3 Word64 Word64 Word64
        deriving (DES_EDE3 -> DES_EDE3 -> Bool
    (DES_EDE3 -> DES_EDE3 -> Bool)
    -> (DES_EDE3 -> DES_EDE3 -> Bool) -> Eq DES_EDE3
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DES_EDE3 -> DES_EDE3 -> Bool
    == :: DES_EDE3 -> DES_EDE3 -> Bool
    $c/= :: DES_EDE3 -> DES_EDE3 -> Bool
    /= :: DES_EDE3 -> DES_EDE3 -> Bool
    Eq)

    -- | 3DES where the first and third keys are equal, used in the same direction
    data DES_EEE2 = DES_EEE2 Word64 Word64 -- key1 and key3 are equal
        deriving (DES_EEE2 -> DES_EEE2 -> Bool
    (DES_EEE2 -> DES_EEE2 -> Bool)
    -> (DES_EEE2 -> DES_EEE2 -> Bool) -> Eq DES_EEE2
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DES_EEE2 -> DES_EEE2 -> Bool
    == :: DES_EEE2 -> DES_EEE2 -> Bool
    $c/= :: DES_EEE2 -> DES_EEE2 -> Bool
    /= :: DES_EEE2 -> DES_EEE2 -> Bool
    Eq)

    -- | 3DES where the first and third keys are equal, used in alternative direction
    data DES_EDE2 = DES_EDE2 Word64 Word64 -- key1 and key3 are equal
        deriving (DES_EDE2 -> DES_EDE2 -> Bool
    (DES_EDE2 -> DES_EDE2 -> Bool)
    -> (DES_EDE2 -> DES_EDE2 -> Bool) -> Eq DES_EDE2
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DES_EDE2 -> DES_EDE2 -> Bool
    == :: DES_EDE2 -> DES_EDE2 -> Bool
    $c/= :: DES_EDE2 -> DES_EDE2 -> Bool
    /= :: DES_EDE2 -> DES_EDE2 -> Bool
    Eq)

    instance Cipher DES_EEE3 where
        cipherName :: DES_EEE3 -> String
    cipherName    DES_EEE3
    _ = String
    "3DES_EEE"
        cipherKeySize :: DES_EEE3 -> KeySizeSpecifier
    cipherKeySize DES_EEE3
    _ = Int -> KeySizeSpecifier
    KeySizeFixed Int
    24
        cipherInit :: forall key. ByteArray key => key -> CryptoFailable DES_EEE3
    cipherInit key
    k    = (Word64 -> Word64 -> Word64 -> DES_EEE3)
    -> key -> CryptoFailable DES_EEE3
    forall key a.
    ByteArrayAccess key =>
    (Word64 -> Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init3DES Word64 -> Word64 -> Word64 -> DES_EEE3
    DES_EEE3 key
    k

    instance Cipher DES_EDE3 where
        cipherName :: DES_EDE3 -> String
    cipherName    DES_EDE3
    _ = String
    "3DES_EDE"
        cipherKeySize :: DES_EDE3 -> KeySizeSpecifier
    cipherKeySize DES_EDE3
    _ = Int -> KeySizeSpecifier
    KeySizeFixed Int
    24
        cipherInit :: forall key. ByteArray key => key -> CryptoFailable DES_EDE3
    cipherInit key
    k    = (Word64 -> Word64 -> Word64 -> DES_EDE3)
    -> key -> CryptoFailable DES_EDE3
    forall key a.
    ByteArrayAccess key =>
    (Word64 -> Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init3DES Word64 -> Word64 -> Word64 -> DES_EDE3
    DES_EDE3 key
    k

    instance Cipher DES_EDE2 where
        cipherName :: DES_EDE2 -> String
    cipherName    DES_EDE2
    _ = String
    "2DES_EDE"
        cipherKeySize :: DES_EDE2 -> KeySizeSpecifier
    cipherKeySize DES_EDE2
    _ = Int -> KeySizeSpecifier
    KeySizeFixed Int
    16
        cipherInit :: forall key. ByteArray key => key -> CryptoFailable DES_EDE2
    cipherInit key
    k    = (Word64 -> Word64 -> DES_EDE2) -> key -> CryptoFailable DES_EDE2
    forall key a.
    ByteArrayAccess key =>
    (Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init2DES Word64 -> Word64 -> DES_EDE2
    DES_EDE2 key
    k

    instance Cipher DES_EEE2 where
        cipherName :: DES_EEE2 -> String
    cipherName    DES_EEE2
    _ = String
    "2DES_EEE"
        cipherKeySize :: DES_EEE2 -> KeySizeSpecifier
    cipherKeySize DES_EEE2
    _ = Int -> KeySizeSpecifier
    KeySizeFixed Int
    16
        cipherInit :: forall key. ByteArray key => key -> CryptoFailable DES_EEE2
    cipherInit key
    k    = (Word64 -> Word64 -> DES_EEE2) -> key -> CryptoFailable DES_EEE2
    forall key a.
    ByteArrayAccess key =>
    (Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init2DES Word64 -> Word64 -> DES_EEE2
    DES_EEE2 key
    k

    instance BlockCipher DES_EEE3 where
        blockSize :: DES_EEE3 -> Int
    blockSize DES_EEE3
    _ = Int
    8
        ecbEncrypt :: forall ba. ByteArray ba => DES_EEE3 -> ba -> ba
    ecbEncrypt (DES_EEE3 Word64
    k1 Word64
    k2 Word64
    k3) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    encrypt Word64
    k3 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k1) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)
        ecbDecrypt :: forall ba. ByteArray ba => DES_EEE3 -> ba -> ba
    ecbDecrypt (DES_EEE3 Word64
    k1 Word64
    k2 Word64
    k3) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    decrypt Word64
    k1 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k3) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)

    instance BlockCipher DES_EDE3 where
        blockSize :: DES_EDE3 -> Int
    blockSize DES_EDE3
    _ = Int
    8
        ecbEncrypt :: forall ba. ByteArray ba => DES_EDE3 -> ba -> ba
    ecbEncrypt (DES_EDE3 Word64
    k1 Word64
    k2 Word64
    k3) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    encrypt Word64
    k3 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k1) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)
        ecbDecrypt :: forall ba. ByteArray ba => DES_EDE3 -> ba -> ba
    ecbDecrypt (DES_EDE3 Word64
    k1 Word64
    k2 Word64
    k3) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    decrypt Word64
    k1 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k3) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)

    instance BlockCipher DES_EEE2 where
        blockSize :: DES_EEE2 -> Int
    blockSize DES_EEE2
    _ = Int
    8
        ecbEncrypt :: forall ba. ByteArray ba => DES_EEE2 -> ba -> ba
    ecbEncrypt (DES_EEE2 Word64
    k1 Word64
    k2) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    encrypt Word64
    k1 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k1) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)
        ecbDecrypt :: forall ba. ByteArray ba => DES_EEE2 -> ba -> ba
    ecbDecrypt (DES_EEE2 Word64
    k1 Word64
    k2) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    decrypt Word64
    k1 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k1) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)

    instance BlockCipher DES_EDE2 where
        blockSize :: DES_EDE2 -> Int
    blockSize DES_EDE2
    _ = Int
    8
        ecbEncrypt :: forall ba. ByteArray ba => DES_EDE2 -> ba -> ba
    ecbEncrypt (DES_EDE2 Word64
    k1 Word64
    k2) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    encrypt Word64
    k1 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k1) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)
        ecbDecrypt :: forall ba. ByteArray ba => DES_EDE2 -> ba -> ba
    ecbDecrypt (DES_EDE2 Word64
    k1 Word64
    k2) = (Word64 -> Word64) -> ba -> ba
    forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
    B.mapAsWord64 (Block -> Word64
    unBlock (Block -> Word64) -> (Word64 -> Block) -> Word64 -> Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word64 -> Block -> Block
    decrypt Word64
    k1 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    encrypt Word64
    k2 (Block -> Block) -> (Block -> Block) -> Block -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block -> Block
    decrypt Word64
    k1) (Block -> Block) -> (Word64 -> Block) -> Word64 -> Block
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Word64 -> Block
    Block)

    init3DES :: ByteArrayAccess key => (Word64 -> Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init3DES :: forall key a.
    ByteArrayAccess key =>
    (Word64 -> Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init3DES Word64 -> Word64 -> Word64 -> a
    constr key
    k
        | Int
    len Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    24 = a -> CryptoFailable a
    forall a. a -> CryptoFailable a
    CryptoPassed (a -> CryptoFailable a) -> a -> CryptoFailable a
    forall a b. (a -> b) -> a -> b
    $ Word64 -> Word64 -> Word64 -> a
    constr Word64
    k1 Word64
    k2 Word64
    k3
        | Bool
    otherwise = CryptoError -> CryptoFailable a
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_KeySizeInvalid
      where len :: Int
    len = key -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length key
    k
            (Word64
    k1, Word64
    k2, Word64
    k3) = (BE Word64 -> Word64
    forall a. ByteSwap a => BE a -> a
    fromBE (BE Word64 -> Word64) -> BE Word64 -> Word64
    forall a b. (a -> b) -> a -> b
    $ key -> Int -> BE Word64
    forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
    B.toW64BE key
    k Int
    0, BE Word64 -> Word64
    forall a. ByteSwap a => BE a -> a
    fromBE (BE Word64 -> Word64) -> BE Word64 -> Word64
    forall a b. (a -> b) -> a -> b
    $ key -> Int -> BE Word64
    forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
    B.toW64BE key
    k Int
    8, BE Word64 -> Word64
    forall a. ByteSwap a => BE a -> a
    fromBE (BE Word64 -> Word64) -> BE Word64 -> Word64
    forall a b. (a -> b) -> a -> b
    $ key -> Int -> BE Word64
    forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
    B.toW64BE key
    k Int
    16)

    init2DES :: ByteArrayAccess key => (Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init2DES :: forall key a.
    ByteArrayAccess key =>
    (Word64 -> Word64 -> a) -> key -> CryptoFailable a
    init2DES Word64 -> Word64 -> a
    constr key
    k
        | Int
    len Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    16 = a -> CryptoFailable a
    forall a. a -> CryptoFailable a
    CryptoPassed (a -> CryptoFailable a) -> a -> CryptoFailable a
    forall a b. (a -> b) -> a -> b
    $ Word64 -> Word64 -> a
    constr Word64
    k1 Word64
    k2
        | Bool
    otherwise = CryptoError -> CryptoFailable a
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_KeySizeInvalid
      where len :: Int
    len = key -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length key
    k
            (Word64
    k1, Word64
    k2) = (BE Word64 -> Word64
    forall a. ByteSwap a => BE a -> a
    fromBE (BE Word64 -> Word64) -> BE Word64 -> Word64
    forall a b. (a -> b) -> a -> b
    $ key -> Int -> BE Word64
    forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
    B.toW64BE key
    k Int
    0, BE Word64 -> Word64
    forall a. ByteSwap a => BE a -> a
    fromBE (BE Word64 -> Word64) -> BE Word64 -> Word64
    forall a b. (a -> b) -> a -> b
    $ key -> Int -> BE Word64
    forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
    B.toW64BE key
    k Int
    8)