-- |
-- 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 Data.Byteable
import qualified Data.ByteString as B

import Crypto.Cipher.Types
import Crypto.Cipher.DES.Primitive
import Crypto.Cipher.DES.Serialization

-- | 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 DES_EEE3 -> DES_EEE3
cipherInit Key DES_EEE3
k    = (Word64 -> Word64 -> Word64 -> DES_EEE3)
-> Key DES_EEE3 -> DES_EEE3
forall b a.
Byteable b =>
(Word64 -> Word64 -> Word64 -> a) -> b -> a
init3DES Word64 -> Word64 -> Word64 -> DES_EEE3
DES_EEE3 Key DES_EEE3
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 DES_EDE3 -> DES_EDE3
cipherInit Key DES_EDE3
k    = (Word64 -> Word64 -> Word64 -> DES_EDE3)
-> Key DES_EDE3 -> DES_EDE3
forall b a.
Byteable b =>
(Word64 -> Word64 -> Word64 -> a) -> b -> a
init3DES Word64 -> Word64 -> Word64 -> DES_EDE3
DES_EDE3 Key DES_EDE3
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 DES_EDE2 -> DES_EDE2
cipherInit Key DES_EDE2
k    = (Word64 -> Word64 -> DES_EDE2) -> Key DES_EDE2 -> DES_EDE2
forall b a. Byteable b => (Word64 -> Word64 -> a) -> b -> a
init2DES Word64 -> Word64 -> DES_EDE2
DES_EDE2 Key DES_EDE2
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 DES_EEE2 -> DES_EEE2
cipherInit Key DES_EEE2
k    = (Word64 -> Word64 -> DES_EEE2) -> Key DES_EEE2 -> DES_EEE2
forall b a. Byteable b => (Word64 -> Word64 -> a) -> b -> a
init2DES Word64 -> Word64 -> DES_EEE2
DES_EEE2 Key DES_EEE2
k

instance BlockCipher DES_EEE3 where
    blockSize :: DES_EEE3 -> Int
blockSize DES_EEE3
_ = Int
8
    ecbEncrypt :: DES_EEE3 -> ByteString -> ByteString
ecbEncrypt (DES_EEE3 Word64
k1 Word64
k2 Word64
k3) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify
    ecbDecrypt :: DES_EEE3 -> ByteString -> ByteString
ecbDecrypt (DES_EEE3 Word64
k1 Word64
k2 Word64
k3) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify

instance BlockCipher DES_EDE3 where
    blockSize :: DES_EDE3 -> Int
blockSize DES_EDE3
_ = Int
8
    ecbEncrypt :: DES_EDE3 -> ByteString -> ByteString
ecbEncrypt (DES_EDE3 Word64
k1 Word64
k2 Word64
k3) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify
    ecbDecrypt :: DES_EDE3 -> ByteString -> ByteString
ecbDecrypt (DES_EDE3 Word64
k1 Word64
k2 Word64
k3) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify

instance BlockCipher DES_EEE2 where
    blockSize :: DES_EEE2 -> Int
blockSize DES_EEE2
_ = Int
8
    ecbEncrypt :: DES_EEE2 -> ByteString -> ByteString
ecbEncrypt (DES_EEE2 Word64
k1 Word64
k2) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify
    ecbDecrypt :: DES_EEE2 -> ByteString -> ByteString
ecbDecrypt (DES_EEE2 Word64
k1 Word64
k2) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify

instance BlockCipher DES_EDE2 where
    blockSize :: DES_EDE2 -> Int
blockSize DES_EDE2
_ = Int
8
    ecbEncrypt :: DES_EDE2 -> ByteString -> ByteString
ecbEncrypt (DES_EDE2 Word64
k1 Word64
k2) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify
    ecbDecrypt :: DES_EDE2 -> ByteString -> ByteString
ecbDecrypt (DES_EDE2 Word64
k1 Word64
k2) = [Block] -> ByteString
unblockify ([Block] -> ByteString)
-> (ByteString -> [Block]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Block -> Block) -> [Block] -> [Block]
forall a b. (a -> b) -> [a] -> [b]
map (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])
-> (ByteString -> [Block]) -> ByteString -> [Block]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Block]
blockify

init3DES :: Byteable b => (Word64 -> Word64 -> Word64 -> a) -> b -> a
init3DES :: forall b a.
Byteable b =>
(Word64 -> Word64 -> Word64 -> a) -> b -> a
init3DES Word64 -> Word64 -> Word64 -> a
constr b
k
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
24 = Word64 -> Word64 -> Word64 -> a
constr Word64
k1 Word64
k2 Word64
k3
    | Bool
otherwise = String -> a
forall a. HasCallStack => String -> a
error String
"3DES: not a valid key length (valid=24)"
  where len :: Int
len = b -> Int
forall a. Byteable a => a -> Int
byteableLength b
k
        (Block Word64
k1, Block Word64
k2, Block Word64
k3) =
            let (ByteString
b1, ByteString
k') = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
8 (b -> ByteString
forall a. Byteable a => a -> ByteString
toBytes b
k)
                (ByteString
b2, ByteString
b3) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
8 ByteString
k'
             in (ByteString -> Block
toW64 ByteString
b1, ByteString -> Block
toW64 ByteString
b2, ByteString -> Block
toW64 ByteString
b3)

init2DES :: Byteable b => (Word64 -> Word64 -> a) -> b -> a
init2DES :: forall b a. Byteable b => (Word64 -> Word64 -> a) -> b -> a
init2DES Word64 -> Word64 -> a
constr b
k
    | Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
16 = Word64 -> Word64 -> a
constr Word64
k1 Word64
k2
    | Bool
otherwise = String -> a
forall a. HasCallStack => String -> a
error String
"2DES: not a valid key length (valid=16)"
  where len :: Int
len = b -> Int
forall a. Byteable a => a -> Int
byteableLength b
k
        (Block Word64
k1, Block Word64
k2) =
            let (ByteString
b1, ByteString
b2) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
8 (b -> ByteString
forall a. Byteable a => a -> ByteString
toBytes b
k)
             in (ByteString -> Block
toW64 ByteString
b1, ByteString -> Block
toW64 ByteString
b2)