-- |
-- 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
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DES_EEE3 -> DES_EEE3 -> Bool
$c/= :: DES_EEE3 -> DES_EEE3 -> Bool
== :: DES_EEE3 -> DES_EEE3 -> Bool
$c== :: 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
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DES_EDE3 -> DES_EDE3 -> Bool
$c/= :: DES_EDE3 -> DES_EDE3 -> Bool
== :: DES_EDE3 -> DES_EDE3 -> Bool
$c== :: 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
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DES_EEE2 -> DES_EEE2 -> Bool
$c/= :: DES_EEE2 -> DES_EEE2 -> Bool
== :: DES_EEE2 -> DES_EEE2 -> Bool
$c== :: 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
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DES_EDE2 -> DES_EDE2 -> Bool
$c/= :: DES_EDE2 -> DES_EDE2 -> Bool
== :: DES_EDE2 -> DES_EDE2 -> Bool
$c== :: 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    = 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    = 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    = 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    = 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
encrypt Word64
k3 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k1) 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
decrypt Word64
k1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k3) 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
encrypt Word64
k3 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k1) 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
decrypt Word64
k1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k3) 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
encrypt Word64
k1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k1) 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
decrypt Word64
k1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k1) 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
encrypt Word64
k1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k1) 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) = forall bs. ByteArray bs => (Word64 -> Word64) -> bs -> bs
B.mapAsWord64 (Block -> Word64
unBlock forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Word64 -> Block -> Block
decrypt Word64
k1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
encrypt Word64
k2 forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Block -> Block
decrypt Word64
k1) 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 forall a. Eq a => a -> a -> Bool
== Int
24 = forall a. a -> CryptoFailable a
CryptoPassed forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> Word64 -> a
constr Word64
k1 Word64
k2 Word64
k3
    | Bool
otherwise = forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_KeySizeInvalid
  where len :: Int
len = forall ba. ByteArrayAccess ba => ba -> Int
B.length key
k
        (Word64
k1, Word64
k2, Word64
k3) = (forall a. ByteSwap a => BE a -> a
fromBE forall a b. (a -> b) -> a -> b
$ forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
B.toW64BE key
k Int
0, forall a. ByteSwap a => BE a -> a
fromBE forall a b. (a -> b) -> a -> b
$ forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
B.toW64BE key
k Int
8, forall a. ByteSwap a => BE a -> a
fromBE forall a b. (a -> b) -> a -> b
$ 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 forall a. Eq a => a -> a -> Bool
== Int
16 = forall a. a -> CryptoFailable a
CryptoPassed forall a b. (a -> b) -> a -> b
$ Word64 -> Word64 -> a
constr Word64
k1 Word64
k2
    | Bool
otherwise = forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_KeySizeInvalid
  where len :: Int
len = forall ba. ByteArrayAccess ba => ba -> Int
B.length key
k
        (Word64
k1, Word64
k2) = (forall a. ByteSwap a => BE a -> a
fromBE forall a b. (a -> b) -> a -> b
$ forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
B.toW64BE key
k Int
0, forall a. ByteSwap a => BE a -> a
fromBE forall a b. (a -> b) -> a -> b
$ forall bs. ByteArrayAccess bs => bs -> Int -> BE Word64
B.toW64BE key
k Int
8)