{-# LANGUAGE MagicHash #-}

-- |
-- Module      : Crypto.Cipher.Camellia.Primitive
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : Good
--
-- This only cover Camellia 128 bits for now. The API will change once
-- 192 and 256 mode are implemented too.
module Crypto.Cipher.Camellia.Primitive (
    Camellia,
    initCamellia,
    encrypt,
    decrypt,
) where

import Data.Bits
import Data.Word

import Crypto.Error
import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.WordArray
import Crypto.Internal.Words
import Data.Memory.Endian

data Mode = Decrypt | Encrypt

w64tow128 :: (Word64, Word64) -> Word128
w64tow128 :: (Word64, Word64) -> Word128
w64tow128 (Word64
x1, Word64
x2) = Word64 -> Word64 -> Word128
Word128 Word64
x1 Word64
x2

w64tow8 :: Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
w64tow8 :: Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
w64tow8 Word64
x = (Word8
t1, Word8
t2, Word8
t3, Word8
t4, Word8
t5, Word8
t6, Word8
t7, Word8
t8)
  where
    t1 :: Word8
t1 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
56)
    t2 :: Word8
t2 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
48)
    t3 :: Word8
t3 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
40)
    t4 :: Word8
t4 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
32)
    t5 :: Word8
t5 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
24)
    t6 :: Word8
t6 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
16)
    t7 :: Word8
t7 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
8)
    t8 :: Word8
t8 = Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
x)

w8tow64 :: (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8) -> Word64
w8tow64 :: (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8) -> Word64
w8tow64 (Word8
t1, Word8
t2, Word8
t3, Word8
t4, Word8
t5, Word8
t6, Word8
t7, Word8
t8) =
    (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
56)
        Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
48)
        Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t3 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
40)
        Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t4 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
32)
        Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t5 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
24)
        Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t6 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
16)
        Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t7 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
8)
        Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word8 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
t8)

sbox :: Int -> Word8
sbox :: Int -> Word8
sbox = Array8 -> Int -> Word8
arrayRead8 Array8
t
  where
    t :: Array8
t =
        Addr# -> Array8
array8
            Addr#
"\x70\x82\x2c\xec\xb3\x27\xc0\xe5\xe4\x85\x57\x35\xea\x0c\xae\x41\
            \\x23\xef\x6b\x93\x45\x19\xa5\x21\xed\x0e\x4f\x4e\x1d\x65\x92\xbd\
            \\x86\xb8\xaf\x8f\x7c\xeb\x1f\xce\x3e\x30\xdc\x5f\x5e\xc5\x0b\x1a\
            \\xa6\xe1\x39\xca\xd5\x47\x5d\x3d\xd9\x01\x5a\xd6\x51\x56\x6c\x4d\
            \\x8b\x0d\x9a\x66\xfb\xcc\xb0\x2d\x74\x12\x2b\x20\xf0\xb1\x84\x99\
            \\xdf\x4c\xcb\xc2\x34\x7e\x76\x05\x6d\xb7\xa9\x31\xd1\x17\x04\xd7\
            \\x14\x58\x3a\x61\xde\x1b\x11\x1c\x32\x0f\x9c\x16\x53\x18\xf2\x22\
            \\xfe\x44\xcf\xb2\xc3\xb5\x7a\x91\x24\x08\xe8\xa8\x60\xfc\x69\x50\
            \\xaa\xd0\xa0\x7d\xa1\x89\x62\x97\x54\x5b\x1e\x95\xe0\xff\x64\xd2\
            \\x10\xc4\x00\x48\xa3\xf7\x75\xdb\x8a\x03\xe6\xda\x09\x3f\xdd\x94\
            \\x87\x5c\x83\x02\xcd\x4a\x90\x33\x73\x67\xf6\xf3\x9d\x7f\xbf\xe2\
            \\x52\x9b\xd8\x26\xc8\x37\xc6\x3b\x81\x96\x6f\x4b\x13\xbe\x63\x2e\
            \\xe9\x79\xa7\x8c\x9f\x6e\xbc\x8e\x29\xf5\xf9\xb6\x2f\xfd\xb4\x59\
            \\x78\x98\x06\x6a\xe7\x46\x71\xba\xd4\x25\xab\x42\x88\xa2\x8d\xfa\
            \\x72\x07\xb9\x55\xf8\xee\xac\x0a\x36\x49\x2a\x68\x3c\x38\xf1\xa4\
            \\x40\x28\xd3\x7b\xbb\xc9\x43\xc1\x15\xe3\xad\xf4\x77\xc7\x80\x9e"#

sbox1 :: Word8 -> Word8
sbox1 :: Word8 -> Word8
sbox1 Word8
x = Int -> Word8
sbox (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
x)

sbox2 :: Word8 -> Word8
sbox2 :: Word8 -> Word8
sbox2 Word8
x = Word8 -> Word8
sbox1 Word8
x Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`rotateL` Int
1

sbox3 :: Word8 -> Word8
sbox3 :: Word8 -> Word8
sbox3 Word8
x = Word8 -> Word8
sbox1 Word8
x Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`rotateL` Int
7

sbox4 :: Word8 -> Word8
sbox4 :: Word8 -> Word8
sbox4 Word8
x = Word8 -> Word8
sbox1 (Word8
x Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
`rotateL` Int
1)

sigma1, sigma2, sigma3, sigma4, sigma5, sigma6 :: Word64
sigma1 :: Word64
sigma1 = Word64
0xA09E667F3BCC908B
sigma2 :: Word64
sigma2 = Word64
0xB67AE8584CAA73B2
sigma3 :: Word64
sigma3 = Word64
0xC6EF372FE94F82BE
sigma4 :: Word64
sigma4 = Word64
0x54FF53A5F1D36F1C
sigma5 :: Word64
sigma5 = Word64
0x10E527FADE682D1D
sigma6 :: Word64
sigma6 = Word64
0xB05688C2B3E6C1FD

rotl128 :: Word128 -> Int -> Word128
rotl128 :: Word128 -> Int -> Word128
rotl128 Word128
v Int
0 = Word128
v
rotl128 (Word128 Word64
x1 Word64
x2) Int
64 = Word64 -> Word64 -> Word128
Word128 Word64
x2 Word64
x1
rotl128 v :: Word128
v@(Word128 Word64
x1 Word64
x2) Int
w
    | Int
w Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
64 = (Word128
v Word128 -> Int -> Word128
`rotl128` Int
64) Word128 -> Int -> Word128
`rotl128` (Int
w Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
64)
    | Bool
otherwise = Word64 -> Word64 -> Word128
Word128 (Word64
x1high Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word64
x2low) (Word64
x2high Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word64
x1low)
  where
    splitBits :: b -> (b, b)
splitBits b
i = (b
i b -> b -> b
forall a. Bits a => a -> a -> a
.&. b -> b
forall a. Bits a => a -> a
complement b
x, b
i b -> b -> b
forall a. Bits a => a -> a -> a
.&. b
x)
      where
        x :: b
x = b
2 b -> Int -> b
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
w b -> b -> b
forall a. Num a => a -> a -> a
- b
1
    (Word64
x1high, Word64
x1low) = Word64 -> (Word64, Word64)
forall {b}. (Bits b, Num b) => b -> (b, b)
splitBits (Word64
x1 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`rotateL` Int
w)
    (Word64
x2high, Word64
x2low) = Word64 -> (Word64, Word64)
forall {b}. (Bits b, Num b) => b -> (b, b)
splitBits (Word64
x2 Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`rotateL` Int
w)

-- | Camellia context
data Camellia = Camellia
    { Camellia -> Array64
k :: Array64
    , Camellia -> Array64
kw :: Array64
    , Camellia -> Array64
ke :: Array64
    }

setKeyInterim
    :: ByteArrayAccess key => key -> (Word128, Word128, Word128, Word128)
setKeyInterim :: forall key.
ByteArrayAccess key =>
key -> (Word128, Word128, Word128, Word128)
setKeyInterim key
keyseed = ((Word64, Word64) -> Word128
w64tow128 (Word64, Word64)
kL, (Word64, Word64) -> Word128
w64tow128 (Word64, Word64)
kR, (Word64, Word64) -> Word128
w64tow128 (Word64, Word64)
kA, (Word64, Word64) -> Word128
w64tow128 (Word64, Word64)
kB)
  where
    kL :: (Word64, Word64)
kL = (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
keyseed 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
keyseed Int
8)
    kR :: (Word64, Word64)
kR = (Word64
0, Word64
0)

    kA :: (Word64, Word64)
kA =
        let d1 :: Word64
d1 = ((Word64, Word64) -> Word64
forall a b. (a, b) -> a
fst (Word64, Word64)
kL Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64, Word64) -> Word64
forall a b. (a, b) -> a
fst (Word64, Word64)
kR)
            d2 :: Word64
d2 = ((Word64, Word64) -> Word64
forall a b. (a, b) -> b
snd (Word64, Word64)
kL Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64, Word64) -> Word64
forall a b. (a, b) -> b
snd (Word64, Word64)
kR)
            d3 :: Word64
d3 = Word64
d2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
d1 Word64
sigma1
            d4 :: Word64
d4 = Word64
d1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
d3 Word64
sigma2
            d5 :: Word64
d5 = Word64
d4 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` ((Word64, Word64) -> Word64
forall a b. (a, b) -> a
fst (Word64, Word64)
kL)
            d6 :: Word64
d6 = Word64
d3 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` ((Word64, Word64) -> Word64
forall a b. (a, b) -> b
snd (Word64, Word64)
kL)
            d7 :: Word64
d7 = Word64
d6 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
d5 Word64
sigma3
            d8 :: Word64
d8 = Word64
d5 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
d7 Word64
sigma4
         in (Word64
d8, Word64
d7)

    kB :: (Word64, Word64)
kB =
        let d1 :: Word64
d1 = ((Word64, Word64) -> Word64
forall a b. (a, b) -> a
fst (Word64, Word64)
kA Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64, Word64) -> Word64
forall a b. (a, b) -> a
fst (Word64, Word64)
kR)
            d2 :: Word64
d2 = ((Word64, Word64) -> Word64
forall a b. (a, b) -> b
snd (Word64, Word64)
kA Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Word64, Word64) -> Word64
forall a b. (a, b) -> b
snd (Word64, Word64)
kR)
            d3 :: Word64
d3 = Word64
d2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
d1 Word64
sigma5
            d4 :: Word64
d4 = Word64
d1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
d3 Word64
sigma6
         in (Word64
d4, Word64
d3)

-- | Initialize a 128-bit key
--
-- Return the initialized key or a error message if the given
-- keyseed was not 16-bytes in length.
initCamellia
    :: ByteArray key
    => key
    -- ^ The key to create the camellia context
    -> CryptoFailable Camellia
initCamellia :: forall key. ByteArray key => key -> CryptoFailable Camellia
initCamellia key
key
    | key -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length key
key Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
16 = CryptoError -> CryptoFailable Camellia
forall a. CryptoError -> CryptoFailable a
CryptoFailed (CryptoError -> CryptoFailable Camellia)
-> CryptoError -> CryptoFailable Camellia
forall a b. (a -> b) -> a -> b
$ CryptoError
CryptoError_KeySizeInvalid
    | Bool
otherwise =
        let (Word128
kL, Word128
_, Word128
kA, Word128
_) = key -> (Word128, Word128, Word128, Word128)
forall key.
ByteArrayAccess key =>
key -> (Word128, Word128, Word128, Word128)
setKeyInterim key
key
         in let (Word128 Word64
kw1 Word64
kw2) = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
0)
             in let (Word128 Word64
k1 Word64
k2) = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
0)
                 in let (Word128 Word64
k3 Word64
k4) = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
15)
                     in let (Word128 Word64
k5 Word64
k6) = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
15)
                         in let (Word128 Word64
ke1 Word64
ke2) = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
30) -- ke1 = (KA <<<  30) >> 64; ke2 = (KA <<<  30) & MASK64;
                             in let (Word128 Word64
k7 Word64
k8) = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
45) -- k7  = (KL <<<  45) >> 64; k8  = (KL <<<  45) & MASK64;
                                 in let (Word128 Word64
k9 Word64
_) = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
45) -- k9  = (KA <<<  45) >> 64;
                                     in let (Word128 Word64
_ Word64
k10) = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
60)
                                         in let (Word128 Word64
k11 Word64
k12) = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
60)
                                             in let (Word128 Word64
ke3 Word64
ke4) = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
77)
                                                 in let (Word128 Word64
k13 Word64
k14) = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
94)
                                                     in let (Word128 Word64
k15 Word64
k16) = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
94)
                                                         in let (Word128 Word64
k17 Word64
k18) = (Word128
kL Word128 -> Int -> Word128
`rotl128` Int
111)
                                                             in let (Word128 Word64
kw3 Word64
kw4) = (Word128
kA Word128 -> Int -> Word128
`rotl128` Int
111)
                                                                 in Camellia -> CryptoFailable Camellia
forall a. a -> CryptoFailable a
CryptoPassed (Camellia -> CryptoFailable Camellia)
-> Camellia -> CryptoFailable Camellia
forall a b. (a -> b) -> a -> b
$
                                                                        Camellia
                                                                            { kw :: Array64
kw = Int -> [Word64] -> Array64
array64 Int
4 [Word64
kw1, Word64
kw2, Word64
kw3, Word64
kw4]
                                                                            , ke :: Array64
ke = Int -> [Word64] -> Array64
array64 Int
4 [Word64
ke1, Word64
ke2, Word64
ke3, Word64
ke4]
                                                                            , k :: Array64
k =
                                                                                Int -> [Word64] -> Array64
array64
                                                                                    Int
18
                                                                                    [ Word64
k1
                                                                                    , Word64
k2
                                                                                    , Word64
k3
                                                                                    , Word64
k4
                                                                                    , Word64
k5
                                                                                    , Word64
k6
                                                                                    , Word64
k7
                                                                                    , Word64
k8
                                                                                    , Word64
k9
                                                                                    , Word64
k10
                                                                                    , Word64
k11
                                                                                    , Word64
k12
                                                                                    , Word64
k13
                                                                                    , Word64
k14
                                                                                    , Word64
k15
                                                                                    , Word64
k16
                                                                                    , Word64
k17
                                                                                    , Word64
k18
                                                                                    ]
                                                                            }

feistel :: Word64 -> Word64 -> Word64
feistel :: Word64 -> Word64 -> Word64
feistel Word64
fin Word64
sk =
    let x :: Word64
x = Word64
fin Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64
sk
     in let (Word8
t1, Word8
t2, Word8
t3, Word8
t4, Word8
t5, Word8
t6, Word8
t7, Word8
t8) = Word64 -> (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8)
w64tow8 Word64
x
         in let t1' :: Word8
t1' = Word8 -> Word8
sbox1 Word8
t1
             in let t2' :: Word8
t2' = Word8 -> Word8
sbox2 Word8
t2
                 in let t3' :: Word8
t3' = Word8 -> Word8
sbox3 Word8
t3
                     in let t4' :: Word8
t4' = Word8 -> Word8
sbox4 Word8
t4
                         in let t5' :: Word8
t5' = Word8 -> Word8
sbox2 Word8
t5
                             in let t6' :: Word8
t6' = Word8 -> Word8
sbox3 Word8
t6
                                 in let t7' :: Word8
t7' = Word8 -> Word8
sbox4 Word8
t7
                                     in let t8' :: Word8
t8' = Word8 -> Word8
sbox1 Word8
t8
                                         in let y1 :: Word8
y1 = Word8
t1' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t3' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t4' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t6' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t7' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t8'
                                             in let y2 :: Word8
y2 = Word8
t1' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t2' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t4' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t5' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t7' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t8'
                                                 in let y3 :: Word8
y3 = Word8
t1' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t2' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t3' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t5' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t6' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t8'
                                                     in let y4 :: Word8
y4 = Word8
t2' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t3' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t4' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t5' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t6' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t7'
                                                         in let y5 :: Word8
y5 = Word8
t1' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t2' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t6' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t7' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t8'
                                                             in let y6 :: Word8
y6 = Word8
t2' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t3' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t5' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t7' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t8'
                                                                 in let y7 :: Word8
y7 = Word8
t3' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t4' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t5' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t6' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t8'
                                                                     in let y8 :: Word8
y8 = Word8
t1' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t4' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t5' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t6' Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
`xor` Word8
t7'
                                                                         in (Word8, Word8, Word8, Word8, Word8, Word8, Word8, Word8) -> Word64
w8tow64 (Word8
y1, Word8
y2, Word8
y3, Word8
y4, Word8
y5, Word8
y6, Word8
y7, Word8
y8)

fl :: Word64 -> Word64 -> Word64
fl :: Word64 -> Word64 -> Word64
fl Word64
fin Word64
sk =
    let (Word32
x1, Word32
x2) = Word64 -> (Word32, Word32)
w64to32 Word64
fin
     in let (Word32
k1, Word32
k2) = Word64 -> (Word32, Word32)
w64to32 Word64
sk
         in let y2 :: Word32
y2 = Word32
x2 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
`xor` ((Word32
x1 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
k1) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`rotateL` Int
1)
             in let y1 :: Word32
y1 = Word32
x1 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
`xor` (Word32
y2 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
k2)
                 in (Word32, Word32) -> Word64
w32to64 (Word32
y1, Word32
y2)

flinv :: Word64 -> Word64 -> Word64
flinv :: Word64 -> Word64 -> Word64
flinv Word64
fin Word64
sk =
    let (Word32
y1, Word32
y2) = Word64 -> (Word32, Word32)
w64to32 Word64
fin
     in let (Word32
k1, Word32
k2) = Word64 -> (Word32, Word32)
w64to32 Word64
sk
         in let x1 :: Word32
x1 = Word32
y1 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
`xor` (Word32
y2 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Word32
k2)
             in let x2 :: Word32
x2 = Word32
y2 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
`xor` ((Word32
x1 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
k1) Word32 -> Int -> Word32
forall a. Bits a => a -> Int -> a
`rotateL` Int
1)
                 in (Word32, Word32) -> Word64
w32to64 (Word32
x1, Word32
x2)

{- in decrypt mode 0->17 1->16 ... -}
getKeyK :: Mode -> Camellia -> Int -> Word64
getKeyK :: Mode -> Camellia -> Int -> Word64
getKeyK Mode
Encrypt Camellia
key Int
i = Camellia -> Array64
k Camellia
key Array64 -> Int -> Word64
`arrayRead64` Int
i
getKeyK Mode
Decrypt Camellia
key Int
i = Camellia -> Array64
k Camellia
key Array64 -> Int -> Word64
`arrayRead64` (Int
17 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i)

{- in decrypt mode 0->3 1->2 2->1 3->0 -}
getKeyKe :: Mode -> Camellia -> Int -> Word64
getKeyKe :: Mode -> Camellia -> Int -> Word64
getKeyKe Mode
Encrypt Camellia
key Int
i = Camellia -> Array64
ke Camellia
key Array64 -> Int -> Word64
`arrayRead64` Int
i
getKeyKe Mode
Decrypt Camellia
key Int
i = Camellia -> Array64
ke Camellia
key Array64 -> Int -> Word64
`arrayRead64` (Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i)

{- in decrypt mode 0->2 1->3 2->0 3->1 -}
getKeyKw :: Mode -> Camellia -> Int -> Word64
getKeyKw :: Mode -> Camellia -> Int -> Word64
getKeyKw Mode
Encrypt Camellia
key Int
i = (Camellia -> Array64
kw Camellia
key) Array64 -> Int -> Word64
`arrayRead64` Int
i
getKeyKw Mode
Decrypt Camellia
key Int
i = (Camellia -> Array64
kw Camellia
key) Array64 -> Int -> Word64
`arrayRead64` ((Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
4)

{- perform the following
    D2 = D2 ^ F(D1, k1);     // Round 1
    D1 = D1 ^ F(D2, k2);     // Round 2
    D2 = D2 ^ F(D1, k3);     // Round 3
    D1 = D1 ^ F(D2, k4);     // Round 4
    D2 = D2 ^ F(D1, k5);     // Round 5
    D1 = D1 ^ F(D2, k6);     // Round 6
 -}
doBlockRound :: Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
doBlockRound :: Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
doBlockRound Mode
mode Camellia
key Word64
d1 Word64
d2 Int
i =
    let r1 :: Word64
r1 = Word64
d2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
d1 (Mode -> Camellia -> Int -> Word64
getKeyK Mode
mode Camellia
key (Int
0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i {- Round 1+i -}))
     in let r2 :: Word64
r2 = Word64
d1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
r1 (Mode -> Camellia -> Int -> Word64
getKeyK Mode
mode Camellia
key (Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i {- Round 2+i -}))
         in let r3 :: Word64
r3 = Word64
r1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
r2 (Mode -> Camellia -> Int -> Word64
getKeyK Mode
mode Camellia
key (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i {- Round 3+i -}))
             in let r4 :: Word64
r4 = Word64
r2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
r3 (Mode -> Camellia -> Int -> Word64
getKeyK Mode
mode Camellia
key (Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i {- Round 4+i -}))
                 in let r5 :: Word64
r5 = Word64
r3 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
r4 (Mode -> Camellia -> Int -> Word64
getKeyK Mode
mode Camellia
key (Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i {- Round 5+i -}))
                     in let r6 :: Word64
r6 = Word64
r4 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` Word64 -> Word64 -> Word64
feistel Word64
r5 (Mode -> Camellia -> Int -> Word64
getKeyK Mode
mode Camellia
key (Int
5 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i {- Round 6+i -}))
                         in (Word64
r6, Word64
r5)

doBlock :: Mode -> Camellia -> Word128 -> Word128
doBlock :: Mode -> Camellia -> Word128 -> Word128
doBlock Mode
mode Camellia
key (Word128 Word64
d1 Word64
d2) =
    let d1a :: Word64
d1a = Word64
d1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Mode -> Camellia -> Int -> Word64
getKeyKw Mode
mode Camellia
key Int
0 {- Prewhitening -})
     in let d2a :: Word64
d2a = Word64
d2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Mode -> Camellia -> Int -> Word64
getKeyKw Mode
mode Camellia
key Int
1)
         in let (Word64
d1b, Word64
d2b) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
doBlockRound Mode
mode Camellia
key Word64
d1a Word64
d2a Int
0
             in let d1c :: Word64
d1c = Word64 -> Word64 -> Word64
fl Word64
d1b (Mode -> Camellia -> Int -> Word64
getKeyKe Mode
mode Camellia
key Int
0 {- FL -})
                 in let d2c :: Word64
d2c = Word64 -> Word64 -> Word64
flinv Word64
d2b (Mode -> Camellia -> Int -> Word64
getKeyKe Mode
mode Camellia
key Int
1 {- FLINV -})
                     in let (Word64
d1d, Word64
d2d) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
doBlockRound Mode
mode Camellia
key Word64
d1c Word64
d2c Int
6
                         in let d1e :: Word64
d1e = Word64 -> Word64 -> Word64
fl Word64
d1d (Mode -> Camellia -> Int -> Word64
getKeyKe Mode
mode Camellia
key Int
2 {- FL -})
                             in let d2e :: Word64
d2e = Word64 -> Word64 -> Word64
flinv Word64
d2d (Mode -> Camellia -> Int -> Word64
getKeyKe Mode
mode Camellia
key Int
3 {- FLINV -})
                                 in let (Word64
d1f, Word64
d2f) = Mode -> Camellia -> Word64 -> Word64 -> Int -> (Word64, Word64)
doBlockRound Mode
mode Camellia
key Word64
d1e Word64
d2e Int
12
                                     in let d2g :: Word64
d2g = Word64
d2f Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Mode -> Camellia -> Int -> Word64
getKeyKw Mode
mode Camellia
key Int
2 {- Postwhitening -})
                                         in let d1g :: Word64
d1g = Word64
d1f Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`xor` (Mode -> Camellia -> Int -> Word64
getKeyKw Mode
mode Camellia
key Int
3)
                                             in (Word64, Word64) -> Word128
w64tow128 (Word64
d2g, Word64
d1g)

{- encryption for 128 bits blocks -}
encryptBlock :: Camellia -> Word128 -> Word128
encryptBlock :: Camellia -> Word128 -> Word128
encryptBlock = Mode -> Camellia -> Word128 -> Word128
doBlock Mode
Encrypt

{- decryption for 128 bits blocks -}
decryptBlock :: Camellia -> Word128 -> Word128
decryptBlock :: Camellia -> Word128 -> Word128
decryptBlock = Mode -> Camellia -> Word128 -> Word128
doBlock Mode
Decrypt

-- | Encrypts the given ByteString using the given Key
encrypt
    :: ByteArray ba
    => Camellia
    -- ^ The key to use
    -> ba
    -- ^ The data to encrypt
    -> ba
encrypt :: forall ba. ByteArray ba => Camellia -> ba -> ba
encrypt Camellia
key = (Word128 -> Word128) -> ba -> ba
forall bs. ByteArray bs => (Word128 -> Word128) -> bs -> bs
B.mapAsWord128 (Camellia -> Word128 -> Word128
encryptBlock Camellia
key)

-- | Decrypts the given ByteString using the given Key
decrypt
    :: ByteArray ba
    => Camellia
    -- ^ The key to use
    -> ba
    -- ^ The data to decrypt
    -> ba
decrypt :: forall ba. ByteArray ba => Camellia -> ba -> ba
decrypt Camellia
key = (Word128 -> Word128) -> ba -> ba
forall bs. ByteArray bs => (Word128 -> Word128) -> bs -> bs
B.mapAsWord128 (Camellia -> Word128 -> Word128
decryptBlock Camellia
key)