-- |
-- 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
/= :: 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
(DES_EDE3 -> DES_EDE3 -> Bool)
-> (DES_EDE3 -> DES_EDE3 -> Bool) -> Eq DES_EDE3
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
(DES_EEE2 -> DES_EEE2 -> Bool)
-> (DES_EEE2 -> DES_EEE2 -> Bool) -> Eq DES_EEE2
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
(DES_EDE2 -> DES_EDE2 -> Bool)
-> (DES_EDE2 -> DES_EDE2 -> Bool) -> Eq DES_EDE2
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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: 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 :: (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 :: (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)