{-# LANGUAGE CPP #-}
{-|
 Maintainer: Thomas.DuBuisson@gmail.com
 Stability: beta
 Portability: portable
-}
module Crypto.Modes (
        -- * Initialization Vector Type, Modifiers (for all ciphers, all modes that use IVs)
          dblIV
        -- * Authentication modes
        , cbcMac', cbcMac, cMac, cMac'
        , cMacStar, cMacStar'
        -- Combined modes (nothing here yet)
        -- , gmc
        -- , xts
        -- , ccm
        ) where

import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.Serialize
import qualified Data.Serialize.Put as SP
import qualified Data.Serialize.Get as SG
import Data.Bits (xor, shift, (.&.), (.|.), testBit, setBit, clearBit, Bits, complementBit)
import Data.Tagged
import Crypto.Classes (BlockCipher(..), for, blockSizeBytes, incIV, zeroIV, chunkFor, chunkFor')
import Crypto.Random
import Crypto.Util
import Crypto.CPoly
import Crypto.Types
import System.Entropy (getEntropy)
import Control.Monad (liftM, forM_)
import Data.List (genericDrop)
import Data.Word (Word8)
import Data.List (genericDrop,genericReplicate,genericLength)

#if MIN_VERSION_tagged(0,2,0)
import Data.Proxy
#endif

-- |Cipher block chaining message authentication
cbcMac' :: BlockCipher k => k -> B.ByteString -> B.ByteString
cbcMac' :: k -> ByteString -> ByteString
cbcMac' k :: k
k pt :: ByteString
pt = IV k -> ByteString
forall a. Serialize a => a -> ByteString
encode (IV k -> ByteString) -> IV k -> ByteString
forall a b. (a -> b) -> a -> b
$ (ByteString, IV k) -> IV k
forall a b. (a, b) -> b
snd ((ByteString, IV k) -> IV k) -> (ByteString, IV k) -> IV k
forall a b. (a -> b) -> a -> b
$ k -> IV k -> ByteString -> (ByteString, IV k)
forall k.
BlockCipher k =>
k -> IV k -> ByteString -> (ByteString, IV k)
cbc k
k IV k
forall k. BlockCipher k => IV k
zeroIV ByteString
pt
{-# INLINEABLE cbcMac' #-}

-- |Cipher block chaining message authentication
cbcMac :: BlockCipher k => k -> L.ByteString -> L.ByteString
cbcMac :: k -> ByteString -> ByteString
cbcMac k :: k
k pt :: ByteString
pt = [ByteString] -> ByteString
L.fromChunks [IV k -> ByteString
forall a. Serialize a => a -> ByteString
encode (IV k -> ByteString) -> IV k -> ByteString
forall a b. (a -> b) -> a -> b
$ (ByteString, IV k) -> IV k
forall a b. (a, b) -> b
snd ((ByteString, IV k) -> IV k) -> (ByteString, IV k) -> IV k
forall a b. (a -> b) -> a -> b
$ k -> IV k -> ByteString -> (ByteString, IV k)
forall k.
BlockCipher k =>
k -> IV k -> ByteString -> (ByteString, IV k)
cbcLazy k
k IV k
forall k. BlockCipher k => IV k
zeroIV ByteString
pt]
{-# INLINEABLE cbcMac #-}

-- |Generate cmac subkeys.
cMacSubk :: BlockCipher k => k -> (IV k, IV k)
cMacSubk :: k -> (IV k, IV k)
cMacSubk k :: k
k = (IV k
k1, IV k
k2) (IV k, IV k) -> (IV k, IV k) -> (IV k, IV k)
forall a b. a -> b -> b
`seq` (IV k
k1, IV k
k2)
  where
       bSize :: ByteLength
bSize = Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSizeBytes Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
       k1 :: IV k
k1 = IV k -> IV k
forall k. BlockCipher k => IV k -> IV k
dblIV (IV k -> IV k) -> IV k -> IV k
forall a b. (a -> b) -> a -> b
$ ByteString -> IV k
forall k. ByteString -> IV k
IV (ByteString -> IV k) -> ByteString -> IV k
forall a b. (a -> b) -> a -> b
$ k -> ByteString -> ByteString
forall k. BlockCipher k => k -> ByteString -> ByteString
encryptBlock k
k (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteLength -> Word8 -> ByteString
B.replicate ByteLength
bSize 0
       k2 :: IV k
k2 = IV k -> IV k
forall k. BlockCipher k => IV k -> IV k
dblIV (IV k -> IV k) -> IV k -> IV k
forall a b. (a -> b) -> a -> b
$ IV k
k1

-- |Pad the string as required by the cmac algorithm. In theory this
--  should work at bit level but since the API works at byte level we
--  do the same
cMacPad :: ([Word8], Bool, Int) -> Maybe (Word8,([Word8], Bool, Int))
cMacPad :: ([Word8], Bool, ByteLength)
-> Maybe (Word8, ([Word8], Bool, ByteLength))
cMacPad (_, _, 0) = Maybe (Word8, ([Word8], Bool, ByteLength))
forall a. Maybe a
Nothing
cMacPad ([], False, n :: ByteLength
n) = (Word8, ([Word8], Bool, ByteLength))
-> Maybe (Word8, ([Word8], Bool, ByteLength))
forall a. a -> Maybe a
Just (0,([], Bool
False, ByteLength
nByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
-1))
cMacPad ([], True, n :: ByteLength
n) = (Word8, ([Word8], Bool, ByteLength))
-> Maybe (Word8, ([Word8], Bool, ByteLength))
forall a. a -> Maybe a
Just (128,([], Bool
False, ByteLength
nByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
-1))
cMacPad (x :: Word8
x:xs :: [Word8]
xs, b :: Bool
b, n :: ByteLength
n) =  (Word8, ([Word8], Bool, ByteLength))
-> Maybe (Word8, ([Word8], Bool, ByteLength))
forall a. a -> Maybe a
Just (Word8
x,([Word8]
xs, Bool
b, ByteLength
nByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
-1))

-- |Obtain the cmac with the specified subkey for lazy bytestrings
cMacWithSubK :: BlockCipher k => k -> (IV k, IV k) -> L.ByteString -> L.ByteString
cMacWithSubK :: k -> (IV k, IV k) -> ByteString -> ByteString
cMacWithSubK k :: k
k (IV k1 :: ByteString
k1, IV k2 :: ByteString
k2) l :: ByteString
l = [ByteString] -> ByteString
L.fromChunks ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ [[ByteString] -> ByteString -> ByteString
go (k -> ByteString -> [ByteString]
forall k. BlockCipher k => k -> ByteString -> [ByteString]
chunkFor k
k ByteString
t) (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteLength -> Word8 -> ByteString
B.replicate ByteLength
bSize1 0]
  where
       bSize1 :: ByteLength
bSize1 = ByteLength -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> ByteLength) -> ByteLength -> ByteLength
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSizeBytes Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
       bSize2 :: Int64
bSize2 = ByteLength -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> Int64) -> ByteLength -> Int64
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSizeBytes Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
       (t :: ByteString
t,e :: ByteString
e) = Int64 -> ByteString -> (ByteString, ByteString)
L.splitAt (((ByteString -> Int64
L.length ByteString
lInt64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
-1)Int64 -> Int64 -> Int64
forall a. Integral a => a -> a -> a
`div` Int64
bSize2)Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
*Int64
bSize2) ByteString
l
       pe :: ByteString
pe =  (ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString)
-> (ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteLength
-> (([Word8], Bool, ByteLength)
    -> Maybe (Word8, ([Word8], Bool, ByteLength)))
-> ([Word8], Bool, ByteLength)
-> (ByteString, Maybe ([Word8], Bool, ByteLength))
forall a.
ByteLength -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
B.unfoldrN (ByteLength
bSize1) ([Word8], Bool, ByteLength)
-> Maybe (Word8, ([Word8], Bool, ByteLength))
cMacPad (ByteString -> [Word8]
L.unpack ByteString
e,Bool
True,ByteLength
bSize1)
       fe :: ByteString
fe | Int64
bSize2 Int64 -> Int64 -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString -> Int64
L.length ByteString
e = ByteString -> ByteString -> ByteString
zwp' ByteString
k1 ByteString
pe
          | Bool
otherwise =  ByteString -> ByteString -> ByteString
zwp' ByteString
k2 ByteString
pe
       go :: [ByteString] -> ByteString -> ByteString
go [] c :: ByteString
c = k -> ByteString -> ByteString
forall k. BlockCipher k => k -> ByteString -> ByteString
encryptBlock k
k (ByteString -> ByteString -> ByteString
zwp' ByteString
c ByteString
fe)
       go (x :: ByteString
x:xs :: [ByteString]
xs) c :: ByteString
c = [ByteString] -> ByteString -> ByteString
go [ByteString]
xs (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ k -> ByteString -> ByteString
forall k. BlockCipher k => k -> ByteString -> ByteString
encryptBlock k
k (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
zwp' ByteString
c ByteString
x

-- |Obtain the cmac for lazy bytestrings
cMac :: BlockCipher k => k -> L.ByteString -> L.ByteString
cMac :: k -> ByteString -> ByteString
cMac k :: k
k = k -> (IV k, IV k) -> ByteString -> ByteString
forall k.
BlockCipher k =>
k -> (IV k, IV k) -> ByteString -> ByteString
cMacWithSubK k
k (k -> (IV k, IV k)
forall k. BlockCipher k => k -> (IV k, IV k)
cMacSubk k
k)

-- |Obtain the cmac with the specified subkey for strict bytestrings
cMacWithSubK' :: BlockCipher k => k -> (IV k, IV k) -> B.ByteString -> B.ByteString
cMacWithSubK' :: k -> (IV k, IV k) -> ByteString -> ByteString
cMacWithSubK' k :: k
k (IV k1 :: ByteString
k1, IV k2 :: ByteString
k2) b :: ByteString
b = [ByteString] -> ByteString -> ByteString
go (k -> ByteString -> [ByteString]
forall k. BlockCipher k => k -> ByteString -> [ByteString]
chunkFor' k
k ByteString
t) (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteLength -> Word8 -> ByteString
B.replicate ByteLength
bSize1 0
  where
       bSize1 :: ByteLength
bSize1 = ByteLength -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> ByteLength) -> ByteLength -> ByteLength
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSizeBytes Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
       bSize2 :: ByteLength
bSize2 = ByteLength -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> ByteLength) -> ByteLength -> ByteLength
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSizeBytes Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
       (t :: ByteString
t,e :: ByteString
e) = ByteLength -> ByteString -> (ByteString, ByteString)
B.splitAt (((ByteString -> ByteLength
B.length ByteString
bByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
-1)ByteLength -> ByteLength -> ByteLength
forall a. Integral a => a -> a -> a
`div` ByteLength
bSize2)ByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
*ByteLength
bSize2) ByteString
b
       pe :: ByteString
pe =  (ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString)
-> (ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteLength
-> (([Word8], Bool, ByteLength)
    -> Maybe (Word8, ([Word8], Bool, ByteLength)))
-> ([Word8], Bool, ByteLength)
-> (ByteString, Maybe ([Word8], Bool, ByteLength))
forall a.
ByteLength -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
B.unfoldrN (ByteLength
bSize1) ([Word8], Bool, ByteLength)
-> Maybe (Word8, ([Word8], Bool, ByteLength))
cMacPad (ByteString -> [Word8]
B.unpack ByteString
e,Bool
True,ByteLength
bSize1)
       fe :: ByteString
fe | ByteLength
bSize2 ByteLength -> ByteLength -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString -> ByteLength
B.length ByteString
e = ByteString -> ByteString -> ByteString
zwp' ByteString
k1 ByteString
pe
          | Bool
otherwise =  ByteString -> ByteString -> ByteString
zwp' ByteString
k2 ByteString
pe
       go :: [ByteString] -> ByteString -> ByteString
go [] c :: ByteString
c = k -> ByteString -> ByteString
forall k. BlockCipher k => k -> ByteString -> ByteString
encryptBlock k
k (ByteString -> ByteString -> ByteString
zwp' ByteString
c ByteString
fe)
       go (x :: ByteString
x:xs :: [ByteString]
xs) c :: ByteString
c = [ByteString] -> ByteString -> ByteString
go [ByteString]
xs (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ k -> ByteString -> ByteString
forall k. BlockCipher k => k -> ByteString -> ByteString
encryptBlock k
k (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
zwp' ByteString
c ByteString
x

-- |Obtain the cmac for strict bytestrings
cMac' :: BlockCipher k => k -> B.ByteString -> B.ByteString
cMac' :: k -> ByteString -> ByteString
cMac' k :: k
k = k -> (IV k, IV k) -> ByteString -> ByteString
forall k.
BlockCipher k =>
k -> (IV k, IV k) -> ByteString -> ByteString
cMacWithSubK' k
k (k -> (IV k, IV k)
forall k. BlockCipher k => k -> (IV k, IV k)
cMacSubk k
k)

cMacStar :: BlockCipher k => k -> [L.ByteString] -> L.ByteString
cMacStar :: k -> [ByteString] -> ByteString
cMacStar k :: k
k l :: [ByteString]
l = ByteString -> [ByteString] -> ByteString
go (ByteString -> ByteString
lcmac (Int64 -> Word8 -> ByteString
L.replicate Int64
bSize 0)) [ByteString]
l
  where
        bSize :: Int64
bSize = ByteLength -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> Int64) -> ByteLength -> Int64
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSizeBytes Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
        bSizeb :: Integer
bSizeb = ByteLength -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> Integer) -> ByteLength -> Integer
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSize Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
        lcmac :: ByteString -> ByteString
lcmac = k -> (IV k, IV k) -> ByteString -> ByteString
forall k.
BlockCipher k =>
k -> (IV k, IV k) -> ByteString -> ByteString
cMacWithSubK k
k (k -> (IV k, IV k)
forall k. BlockCipher k => k -> (IV k, IV k)
cMacSubk k
k)
        go :: ByteString -> [ByteString] -> ByteString
go s :: ByteString
s [] = ByteString
s
        go s :: ByteString
s [x :: ByteString
x] | (ByteString -> Int64
L.length ByteString
x) Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int64
bSize = ByteString -> ByteString
lcmac (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
zwp ByteString
x (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ((ByteLength, [Word8]) -> Maybe (Word8, (ByteLength, [Word8])))
-> (ByteLength, [Word8]) -> ByteString
forall a. (a -> Maybe (Word8, a)) -> a -> ByteString
L.unfoldr (ByteLength
-> (ByteLength, [Word8]) -> Maybe (Word8, (ByteLength, [Word8]))
xorend (ByteLength
 -> (ByteLength, [Word8]) -> Maybe (Word8, (ByteLength, [Word8])))
-> ByteLength
-> (ByteLength, [Word8])
-> Maybe (Word8, (ByteLength, [Word8]))
forall a b. (a -> b) -> a -> b
$ Int64 -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
bSize) (Int64 -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> ByteLength) -> Int64 -> ByteLength
forall a b. (a -> b) -> a -> b
$ ByteString -> Int64
L.length ByteString
x,ByteString -> [Word8]
L.unpack ByteString
s)
                 | Bool
otherwise = ByteString -> ByteString
lcmac (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
zwp (ByteString -> ByteString
dblL ByteString
s) ((([Word8], Bool, ByteLength)
 -> Maybe (Word8, ([Word8], Bool, ByteLength)))
-> ([Word8], Bool, ByteLength) -> ByteString
forall a. (a -> Maybe (Word8, a)) -> a -> ByteString
L.unfoldr ([Word8], Bool, ByteLength)
-> Maybe (Word8, ([Word8], Bool, ByteLength))
cMacPad (ByteString -> [Word8]
L.unpack ByteString
x,Bool
True,Int64 -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
bSize))
        go s :: ByteString
s (x :: ByteString
x:xs :: [ByteString]
xs) = ByteString -> [ByteString] -> ByteString
go (ByteString -> ByteString -> ByteString
zwp (ByteString -> ByteString
dblL ByteString
s) (ByteString -> ByteString
lcmac ByteString
x)) [ByteString]
xs

-- |Obtain the CMAC* on strict bytestrings
cMacStar' :: BlockCipher k => k -> [B.ByteString] -> B.ByteString
cMacStar' :: k -> [ByteString] -> ByteString
cMacStar' k :: k
k s :: [ByteString]
s = ByteString -> [ByteString] -> ByteString
go (ByteString -> ByteString
lcmac (ByteLength -> Word8 -> ByteString
B.replicate ByteLength
bSize 0)) [ByteString]
s
  where
       bSize :: ByteLength
bSize = ByteLength -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> ByteLength) -> ByteLength -> ByteLength
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSizeBytes Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
       bSizeb :: Integer
bSizeb = ByteLength -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> Integer) -> ByteLength -> Integer
forall a b. (a -> b) -> a -> b
$ Tagged k ByteLength
forall k. BlockCipher k => Tagged k ByteLength
blockSize Tagged k ByteLength -> k -> ByteLength
forall a b. Tagged a b -> a -> b
`for` k
k
       lcmac :: ByteString -> ByteString
lcmac = k -> (IV k, IV k) -> ByteString -> ByteString
forall k.
BlockCipher k =>
k -> (IV k, IV k) -> ByteString -> ByteString
cMacWithSubK' k
k (k -> (IV k, IV k)
forall k. BlockCipher k => k -> (IV k, IV k)
cMacSubk k
k)
       go :: ByteString -> [ByteString] -> ByteString
go s :: ByteString
s [] = ByteString
s
       go s :: ByteString
s [x :: ByteString
x] | (ByteString -> ByteLength
B.length ByteString
x) ByteLength -> ByteLength -> Bool
forall a. Ord a => a -> a -> Bool
>= ByteLength
bSize = ByteString -> ByteString
lcmac (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
zwp' ByteString
x (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ (ByteString, Maybe (ByteLength, [Word8])) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, Maybe (ByteLength, [Word8])) -> ByteString)
-> (ByteString, Maybe (ByteLength, [Word8])) -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteLength
-> ((ByteLength, [Word8]) -> Maybe (Word8, (ByteLength, [Word8])))
-> (ByteLength, [Word8])
-> (ByteString, Maybe (ByteLength, [Word8]))
forall a.
ByteLength -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
B.unfoldrN (ByteString -> ByteLength
B.length ByteString
x) (ByteLength
-> (ByteLength, [Word8]) -> Maybe (Word8, (ByteLength, [Word8]))
xorend ByteLength
bSize) (ByteLength -> ByteLength
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteLength -> ByteLength) -> ByteLength -> ByteLength
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteLength
B.length ByteString
x,ByteString -> [Word8]
B.unpack ByteString
s)
                | Bool
otherwise = ByteString -> ByteString
lcmac (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
zwp' (ByteString -> ByteString
dblB ByteString
s) ((ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString
forall a b. (a, b) -> a
fst ((ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString)
-> (ByteString, Maybe ([Word8], Bool, ByteLength)) -> ByteString
forall a b. (a -> b) -> a -> b
$ ByteLength
-> (([Word8], Bool, ByteLength)
    -> Maybe (Word8, ([Word8], Bool, ByteLength)))
-> ([Word8], Bool, ByteLength)
-> (ByteString, Maybe ([Word8], Bool, ByteLength))
forall a.
ByteLength -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
B.unfoldrN ByteLength
bSize ([Word8], Bool, ByteLength)
-> Maybe (Word8, ([Word8], Bool, ByteLength))
cMacPad (ByteString -> [Word8]
B.unpack ByteString
x,Bool
True,ByteLength
bSize))
       go s :: ByteString
s (x :: ByteString
x:xs :: [ByteString]
xs) = ByteString -> [ByteString] -> ByteString
go (ByteString -> ByteString -> ByteString
zwp' (ByteString -> ByteString
dblB ByteString
s) (ByteString -> ByteString
lcmac ByteString
x)) [ByteString]
xs 

-- |Generate the xor stream for the last step of the CMAC* algorithm
xorend  :: Int -> (Int,[Word8]) -> Maybe (Word8,(Int,[Word8]))
xorend :: ByteLength
-> (ByteLength, [Word8]) -> Maybe (Word8, (ByteLength, [Word8]))
xorend bsize :: ByteLength
bsize (0, []) = Maybe (Word8, (ByteLength, [Word8]))
forall a. Maybe a
Nothing
xorend bsize :: ByteLength
bsize (n :: ByteLength
n, x :: Word8
x:xs :: [Word8]
xs) | ByteLength
n ByteLength -> ByteLength -> Bool
forall a. Ord a => a -> a -> Bool
<= ByteLength
bsize = (Word8, (ByteLength, [Word8]))
-> Maybe (Word8, (ByteLength, [Word8]))
forall a. a -> Maybe a
Just (Word8
x,((ByteLength
nByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
-1),[Word8]
xs))
                       | Bool
otherwise = (Word8, (ByteLength, [Word8]))
-> Maybe (Word8, (ByteLength, [Word8]))
forall a. a -> Maybe a
Just (0,((ByteLength
nByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
-1),(Word8
xWord8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
:[Word8]
xs)))

-- |Accumulator based double operation
dblw :: Bool -> (Int,[Int],Bool) -> Word8 -> ((Int,[Int],Bool), Word8)
dblw :: Bool
-> (ByteLength, [ByteLength], Bool)
-> Word8
-> ((ByteLength, [ByteLength], Bool), Word8)
dblw hb :: Bool
hb (i :: ByteLength
i,xs :: [ByteLength]
xs,b :: Bool
b) w :: Word8
w = Bool -> ((ByteLength, [ByteLength], Bool), Word8)
dblw' Bool
hb
  where
       slw :: Bool -> a -> a
slw True w :: a
w = (a -> ByteLength -> a
forall a. Bits a => a -> ByteLength -> a
setBit (a -> ByteLength -> a
forall a. Bits a => a -> ByteLength -> a
shift a
w 1) 0)
       slw False w :: a
w = (a -> ByteLength -> a
forall a. Bits a => a -> ByteLength -> a
clearBit (a -> ByteLength -> a
forall a. Bits a => a -> ByteLength -> a
shift a
w 1) 0)
       cpolyw :: ByteLength -> [ByteLength] -> t -> ((ByteLength, [ByteLength]), t)
cpolyw i :: ByteLength
i [] w :: t
w = ((ByteLength
iByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
+8,[]),t
w)
       cpolyw i :: ByteLength
i (x :: ByteLength
x:xs :: [ByteLength]
xs) w :: t
w
         | ByteLength
x ByteLength -> ByteLength -> Bool
forall a. Ord a => a -> a -> Bool
< ByteLength
i ByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
+8 = (\(a :: (ByteLength, [ByteLength])
a,b :: t
b) -> ((ByteLength, [ByteLength])
a,t -> ByteLength -> t
forall a. Bits a => a -> ByteLength -> a
complementBit t
b (ByteLength
xByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
-ByteLength
i))) (((ByteLength, [ByteLength]), t)
 -> ((ByteLength, [ByteLength]), t))
-> ((ByteLength, [ByteLength]), t)
-> ((ByteLength, [ByteLength]), t)
forall a b. (a -> b) -> a -> b
$ ByteLength -> [ByteLength] -> t -> ((ByteLength, [ByteLength]), t)
cpolyw ByteLength
i [ByteLength]
xs t
w
         |Bool
otherwise = ((ByteLength
iByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
+8,(ByteLength
xByteLength -> [ByteLength] -> [ByteLength]
forall a. a -> [a] -> [a]
:[ByteLength]
xs)),t
w)
       b' :: Bool
b' = Word8 -> ByteLength -> Bool
forall a. Bits a => a -> ByteLength -> Bool
testBit Word8
w 7
       w' :: Word8
w' = Bool -> Word8 -> Word8
forall a. Bits a => Bool -> a -> a
slw Bool
b Word8
w
       ((i' :: ByteLength
i',xs' :: [ByteLength]
xs'),w'' :: Word8
w'') = ByteLength
-> [ByteLength] -> Word8 -> ((ByteLength, [ByteLength]), Word8)
forall t.
Bits t =>
ByteLength -> [ByteLength] -> t -> ((ByteLength, [ByteLength]), t)
cpolyw ByteLength
i [ByteLength]
xs Word8
w'
       dblw' :: Bool -> ((ByteLength, [ByteLength], Bool), Word8)
dblw' False = ByteLength
i'ByteLength
-> ((ByteLength, [ByteLength], Bool), Word8)
-> ((ByteLength, [ByteLength], Bool), Word8)
forall a b. a -> b -> b
`seq`[ByteLength]
xs'[ByteLength]
-> ((ByteLength, [ByteLength], Bool), Word8)
-> ((ByteLength, [ByteLength], Bool), Word8)
forall a b. a -> b -> b
`seq`Word8
w''Word8
-> ((ByteLength, [ByteLength], Bool), Word8)
-> ((ByteLength, [ByteLength], Bool), Word8)
forall a b. a -> b -> b
`seq`((ByteLength
i,[ByteLength]
xs,Bool
b'),Word8
w')
       dblw' True  = ((ByteLength
i',[ByteLength]
xs',Bool
b'),Word8
w'')

-- |Perform doubling as defined by the CMAC and SIV papers
dblIV :: BlockCipher k => IV k -> IV k
dblIV :: IV k -> IV k
dblIV (IV b :: ByteString
b) = ByteString -> IV k
forall k. ByteString -> IV k
IV (ByteString -> IV k) -> ByteString -> IV k
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
dblB ByteString
b

-- |Perform doubling as defined by the CMAC and SIV papers
dblB :: B.ByteString -> B.ByteString
dblB :: ByteString -> ByteString
dblB b :: ByteString
b | ByteString -> Bool
B.null ByteString
b = ByteString
b
       | Bool
otherwise = ((ByteLength, [ByteLength], Bool), ByteString) -> ByteString
forall a b. (a, b) -> b
snd (((ByteLength, [ByteLength], Bool), ByteString) -> ByteString)
-> ((ByteLength, [ByteLength], Bool), ByteString) -> ByteString
forall a b. (a -> b) -> a -> b
$ ((ByteLength, [ByteLength], Bool)
 -> Word8 -> ((ByteLength, [ByteLength], Bool), Word8))
-> (ByteLength, [ByteLength], Bool)
-> ByteString
-> ((ByteLength, [ByteLength], Bool), ByteString)
forall acc.
(acc -> Word8 -> (acc, Word8))
-> acc -> ByteString -> (acc, ByteString)
B.mapAccumR (Bool
-> (ByteLength, [ByteLength], Bool)
-> Word8
-> ((ByteLength, [ByteLength], Bool), Word8)
dblw (Word8 -> ByteLength -> Bool
forall a. Bits a => a -> ByteLength -> Bool
testBit (ByteString -> Word8
B.head ByteString
b) 7)) (0,ByteLength -> [ByteLength]
forall a b. (Integral a, Integral b) => a -> [b]
cpoly2revlist (ByteString -> ByteLength
B.length ByteString
b ByteLength -> ByteLength -> ByteLength
forall a. Num a => a -> a -> a
* 8),Bool
False) ByteString
b

-- |Perform doubling as defined by the CMAC and SIV papers
dblL :: L.ByteString -> L.ByteString
dblL :: ByteString -> ByteString
dblL b :: ByteString
b | ByteString -> Bool
L.null ByteString
b = ByteString
b
       | Bool
otherwise = ((ByteLength, [ByteLength], Bool), ByteString) -> ByteString
forall a b. (a, b) -> b
snd (((ByteLength, [ByteLength], Bool), ByteString) -> ByteString)
-> ((ByteLength, [ByteLength], Bool), ByteString) -> ByteString
forall a b. (a -> b) -> a -> b
$ ((ByteLength, [ByteLength], Bool)
 -> Word8 -> ((ByteLength, [ByteLength], Bool), Word8))
-> (ByteLength, [ByteLength], Bool)
-> ByteString
-> ((ByteLength, [ByteLength], Bool), ByteString)
forall acc.
(acc -> Word8 -> (acc, Word8))
-> acc -> ByteString -> (acc, ByteString)
L.mapAccumR (Bool
-> (ByteLength, [ByteLength], Bool)
-> Word8
-> ((ByteLength, [ByteLength], Bool), Word8)
dblw (Word8 -> ByteLength -> Bool
forall a. Bits a => a -> ByteLength -> Bool
testBit (ByteString -> Word8
L.head ByteString
b) 7)) (0,Int64 -> [ByteLength]
forall a b. (Integral a, Integral b) => a -> [b]
cpoly2revlist (ByteString -> Int64
L.length ByteString
b Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
* 8),Bool
False) ByteString
b
 
-- |Cast a bigEndian ByteString into an Integer
decodeB :: B.ByteString -> Integer
decodeB :: ByteString -> Integer
decodeB = (Integer -> Word8 -> Integer) -> Integer -> ByteString -> Integer
forall a. (a -> Word8 -> a) -> a -> ByteString -> a
B.foldl' (\acc :: Integer
acc w :: Word8
w -> (Integer -> ByteLength -> Integer
forall a. Bits a => a -> ByteLength -> a
shift Integer
acc 8) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Word8 -> Integer
forall a. Integral a => a -> Integer
toInteger(Word8
w)) 0

-- |Cast an Integer into a bigEndian ByteString of size k.  It will
-- drop the MSBs in case the number is bigger than k and add 00s if it
-- is smaller.
encodeB :: (Ord a,Num a) => a -> Integer -> B.ByteString
encodeB :: a -> Integer -> ByteString
encodeB k :: a
k n :: Integer
n = [Word8] -> ByteString
B.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ if a
lr a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
k then a -> [Word8] -> [Word8]
forall t a. (Eq t, Num t) => t -> [a] -> [a]
takel (a
lr a -> a -> a
forall a. Num a => a -> a -> a
- a
k) [Word8]
r else a -> [Word8] -> [Word8]
forall t a. (Eq t, Num t, Num a) => t -> [a] -> [a]
pad (a
k a -> a -> a
forall a. Num a => a -> a -> a
- a
lr) [Word8]
r
  where
       go :: Integer -> [a] -> [a]
go 0 xs :: [a]
xs = [a]
xs 
       go n :: Integer
n xs :: [a]
xs = Integer -> [a] -> [a]
go (Integer -> ByteLength -> Integer
forall a. Bits a => a -> ByteLength -> a
shift Integer
n (-8)) (Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer
n Integer -> Integer -> Integer
forall a. Bits a => a -> a -> a
.&. 255) a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
xs)
       pad :: t -> [a] -> [a]
pad 0 xs :: [a]
xs = [a]
xs
       pad n :: t
n xs :: [a]
xs = 0 a -> [a] -> [a]
forall a. a -> [a] -> [a]
: t -> [a] -> [a]
pad (t
nt -> t -> t
forall a. Num a => a -> a -> a
-1) [a]
xs
       takel :: t -> [a] -> [a]
takel 0 xs :: [a]
xs = [a]
xs
       takel n :: t
n (_:xs :: [a]
xs) = t -> [a] -> [a]
takel (t
nt -> t -> t
forall a. Num a => a -> a -> a
-1) [a]
xs
       r :: [Word8]
r = Integer -> [Word8] -> [Word8]
forall a. Num a => Integer -> [a] -> [a]
go Integer
n []
       lr :: a
lr = [Word8] -> a
forall i a. Num i => [a] -> i
genericLength [Word8]
r

-- |Cast a bigEndian ByteString into an Integer
decodeL :: L.ByteString -> Integer
decodeL :: ByteString -> Integer
decodeL = (Integer -> Word8 -> Integer) -> Integer -> ByteString -> Integer
forall a. (a -> Word8 -> a) -> a -> ByteString -> a
L.foldl' (\acc :: Integer
acc w :: Word8
w -> (Integer -> ByteLength -> Integer
forall a. Bits a => a -> ByteLength -> a
shift Integer
acc 8) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Word8 -> Integer
forall a. Integral a => a -> Integer
toInteger(Word8
w)) 0

-- |Cast an Integer into a bigEndian ByteString of size k.  It will
-- drop the MSBs in case the number is bigger than k and add 00s if it
-- is smaller.
encodeL :: (Ord a,Num a) => a -> Integer -> L.ByteString
encodeL :: a -> Integer -> ByteString
encodeL k :: a
k n :: Integer
n = [Word8] -> ByteString
L.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ if a
lr a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
k then a -> [Word8] -> [Word8]
forall t a. (Eq t, Num t) => t -> [a] -> [a]
takel (a
lr a -> a -> a
forall a. Num a => a -> a -> a
- a
k) [Word8]
r else a -> [Word8] -> [Word8]
forall t a. (Eq t, Num t, Num a) => t -> [a] -> [a]
pad (a
k a -> a -> a
forall a. Num a => a -> a -> a
- a
lr) [Word8]
r
  where go :: Integer -> [a] -> [a]
go 0 xs :: [a]
xs = [a]
xs 
        go n :: Integer
n xs :: [a]
xs = Integer -> [a] -> [a]
go (Integer -> ByteLength -> Integer
forall a. Bits a => a -> ByteLength -> a
shift Integer
n (-8)) (Integer -> a
forall a. Num a => Integer -> a
fromInteger (Integer
n Integer -> Integer -> Integer
forall a. Bits a => a -> a -> a
.&. 255) a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
xs)
        pad :: t -> [a] -> [a]
pad 0 xs :: [a]
xs = [a]
xs
        pad n :: t
n xs :: [a]
xs = 0 a -> [a] -> [a]
forall a. a -> [a] -> [a]
: t -> [a] -> [a]
pad (t
nt -> t -> t
forall a. Num a => a -> a -> a
-1) [a]
xs
        takel :: t -> [a] -> [a]
takel 0 xs :: [a]
xs = [a]
xs
        takel n :: t
n (_:xs :: [a]
xs) = t -> [a] -> [a]
takel (t
nt -> t -> t
forall a. Num a => a -> a -> a
-1) [a]
xs
        r :: [Word8]
r = Integer -> [Word8] -> [Word8]
forall a. Num a => Integer -> [a] -> [a]
go Integer
n []
        lr :: a
lr = [Word8] -> a
forall i a. Num i => [a] -> i
genericLength [Word8]
r

-- TODO: GCM, GMAC
-- Consider the AES-only modes of XTS, CCM