-- |
-- Module      : Crypto.Cipher.TripleDES
-- License     : BSD-style
-- Stability   : experimental
-- Portability : ???
module Crypto.Cipher.TripleDES (
    DES_EEE3,
    DES_EDE3,
    DES_EEE2,
    DES_EDE2,
) where

import Crypto.Cipher.DES.Primitive
import Crypto.Cipher.Types
import Crypto.Error
import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes)
import qualified Crypto.Internal.ByteArray as B

-- | 3DES with 3 different keys used all in the same direction
data DES_EEE3 = DES_EEE3 Schedule Schedule
    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 Schedule Schedule
    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 Schedule Schedule
    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 Schedule Schedule
    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 = (Schedule -> Schedule -> DES_EEE3)
-> Direction -> key -> CryptoFailable DES_EEE3
forall key a.
ByteArrayAccess key =>
(Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init3DES Schedule -> Schedule -> DES_EEE3
DES_EEE3 Direction
Encrypt 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 = (Schedule -> Schedule -> DES_EDE3)
-> Direction -> key -> CryptoFailable DES_EDE3
forall key a.
ByteArrayAccess key =>
(Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init3DES Schedule -> Schedule -> DES_EDE3
DES_EDE3 Direction
Decrypt 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 = (Schedule -> Schedule -> DES_EDE2)
-> Direction -> key -> CryptoFailable DES_EDE2
forall key a.
ByteArrayAccess key =>
(Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init2DES Schedule -> Schedule -> DES_EDE2
DES_EDE2 Direction
Decrypt 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 = (Schedule -> Schedule -> DES_EEE2)
-> Direction -> key -> CryptoFailable DES_EEE2
forall key a.
ByteArrayAccess key =>
(Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init2DES Schedule -> Schedule -> DES_EEE2
DES_EEE2 Direction
Encrypt 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 Schedule
enc Schedule
_) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
enc
    ecbDecrypt :: forall ba. ByteArray ba => DES_EEE3 -> ba -> ba
ecbDecrypt (DES_EEE3 Schedule
_ Schedule
dec) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
dec

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 Schedule
enc Schedule
_) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
enc
    ecbDecrypt :: forall ba. ByteArray ba => DES_EDE3 -> ba -> ba
ecbDecrypt (DES_EDE3 Schedule
_ Schedule
dec) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
dec

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 Schedule
enc Schedule
_) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
enc
    ecbDecrypt :: forall ba. ByteArray ba => DES_EEE2 -> ba -> ba
ecbDecrypt (DES_EEE2 Schedule
_ Schedule
dec) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
dec

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 Schedule
enc Schedule
_) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
enc
    ecbDecrypt :: forall ba. ByteArray ba => DES_EDE2 -> ba -> ba
ecbDecrypt (DES_EDE2 Schedule
_ Schedule
dec) = Schedule -> ba -> ba
forall ba. ByteArray ba => Schedule -> ba -> ba
ecb Schedule
dec

-- | The schedules of a three stage cipher, for both directions.
--
-- The outer stages encrypt and the middle one goes whichever way the
-- construction says; decrypting is the same three stages in the opposite
-- order, each the other way round.
stages
    :: ByteArrayAccess key
    => Direction
    -- ^ the direction of the middle stage when encrypting
    -> (key, key, key)
    -> (Schedule, Schedule)
stages :: forall key.
ByteArrayAccess key =>
Direction -> (key, key, key) -> (Schedule, Schedule)
stages Direction
mid (key
k1, key
k2, key
k3) =
    ( [(Direction, key)] -> Schedule
forall key. ByteArrayAccess key => [(Direction, key)] -> Schedule
schedule [(Direction
Encrypt, key
k1), (Direction
mid, key
k2), (Direction
Encrypt, key
k3)]
    , [(Direction, key)] -> Schedule
forall key. ByteArrayAccess key => [(Direction, key)] -> Schedule
schedule [(Direction
Decrypt, key
k3), (Direction -> Direction
opposite Direction
mid, key
k2), (Direction
Decrypt, key
k1)]
    )
  where
    opposite :: Direction -> Direction
opposite Direction
Encrypt = Direction
Decrypt
    opposite Direction
Decrypt = Direction
Encrypt

init3DES
    :: ByteArrayAccess key
    => (Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init3DES :: forall key a.
ByteArrayAccess key =>
(Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init3DES Schedule -> Schedule -> a
constr Direction
mid key
k
    | key -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length key
k 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
$ (Schedule -> Schedule -> a) -> (Schedule, Schedule) -> a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Schedule -> Schedule -> a
constr ((Schedule, Schedule) -> a) -> (Schedule, Schedule) -> a
forall a b. (a -> b) -> a -> b
$ Direction
-> (ScrubbedBytes, ScrubbedBytes, ScrubbedBytes)
-> (Schedule, Schedule)
forall key.
ByteArrayAccess key =>
Direction -> (key, key, key) -> (Schedule, Schedule)
stages Direction
mid (Int -> ScrubbedBytes
part Int
0, Int -> ScrubbedBytes
part Int
8, Int -> ScrubbedBytes
part Int
16)
    | Bool
otherwise = CryptoError -> CryptoFailable a
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_KeySizeInvalid
  where
    part :: Int -> ScrubbedBytes
part = key -> Int -> ScrubbedBytes
forall key. ByteArrayAccess key => key -> Int -> ScrubbedBytes
keyPart key
k

init2DES
    :: ByteArrayAccess key
    => (Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init2DES :: forall key a.
ByteArrayAccess key =>
(Schedule -> Schedule -> a) -> Direction -> key -> CryptoFailable a
init2DES Schedule -> Schedule -> a
constr Direction
mid key
k
    | key -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length key
k 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
$ (Schedule -> Schedule -> a) -> (Schedule, Schedule) -> a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Schedule -> Schedule -> a
constr ((Schedule, Schedule) -> a) -> (Schedule, Schedule) -> a
forall a b. (a -> b) -> a -> b
$ Direction
-> (ScrubbedBytes, ScrubbedBytes, ScrubbedBytes)
-> (Schedule, Schedule)
forall key.
ByteArrayAccess key =>
Direction -> (key, key, key) -> (Schedule, Schedule)
stages Direction
mid (Int -> ScrubbedBytes
part Int
0, Int -> ScrubbedBytes
part Int
8, Int -> ScrubbedBytes
part Int
0)
    | Bool
otherwise = CryptoError -> CryptoFailable a
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_KeySizeInvalid
  where
    part :: Int -> ScrubbedBytes
part = key -> Int -> ScrubbedBytes
forall key. ByteArrayAccess key => key -> Int -> ScrubbedBytes
keyPart key
k

-- | The eight bytes of a key that start at the given offset.
keyPart :: ByteArrayAccess key => key -> Int -> ScrubbedBytes
keyPart :: forall key. ByteArrayAccess key => key -> Int -> ScrubbedBytes
keyPart key
k Int
i = Int -> ScrubbedBytes -> ScrubbedBytes
forall bs. ByteArray bs => Int -> bs -> bs
B.take Int
8 (ScrubbedBytes -> ScrubbedBytes) -> ScrubbedBytes -> ScrubbedBytes
forall a b. (a -> b) -> a -> b
$ Int -> ScrubbedBytes -> ScrubbedBytes
forall bs. ByteArray bs => Int -> bs -> bs
B.drop Int
i (key -> ScrubbedBytes
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
B.convert key
k :: ScrubbedBytes)