module Botan.MAC.CMAC
( CMAC(..)
, CMACKey(..)
, CMACAuth(..)
, cmac
, cmacLazy
, newCMACKey
) where

import Data.Maybe
import Data.Proxy

import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as Lazy
import qualified Data.Text as Text

import qualified Botan.BlockCipher as Botan
import qualified Botan.MAC as Botan
import qualified Botan.Utility as Botan

import Botan.BlockCipher.AES
import Botan.BlockCipher.Class
import Botan.MAC.Class
import Botan.Prelude

import Botan.RNG

-- CMAC type

data CMAC bc

newtype instance MACKey (CMAC bc) = CMACKey
    { forall bc. MACKey (CMAC bc) -> ByteString
getCMACKey :: ByteString {- ByteVector n -} }
    deriving newtype (MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
(MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool)
-> (MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool)
-> Eq (MACKey (CMAC bc))
forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
== :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
$c/= :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
/= :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
Eq, Eq (MACKey (CMAC bc))
Eq (MACKey (CMAC bc)) =>
(MACKey (CMAC bc) -> MACKey (CMAC bc) -> Ordering)
-> (MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool)
-> (MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool)
-> (MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool)
-> (MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool)
-> (MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc))
-> (MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc))
-> Ord (MACKey (CMAC bc))
MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
MACKey (CMAC bc) -> MACKey (CMAC bc) -> Ordering
MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc)
forall bc. Eq (MACKey (CMAC bc))
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Ordering
forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc)
$ccompare :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Ordering
compare :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> Ordering
$c< :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
< :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
$c<= :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
<= :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
$c> :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
> :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
$c>= :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
>= :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> Bool
$cmax :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc)
max :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc)
$cmin :: forall bc. MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc)
min :: MACKey (CMAC bc) -> MACKey (CMAC bc) -> MACKey (CMAC bc)
Ord)

instance Show (MACKey (CMAC bc)) where
    show :: MACKey (CMAC bc) -> String
    show :: MACKey (CMAC bc) -> String
show (CMACKey ByteString
bytes) = Text -> String
Text.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ ByteString -> HexCase -> Text
Botan.hexEncode ByteString
bytes HexCase
Botan.Lower

type CMACKey bc = MACKey (CMAC bc)

newtype instance MACAuth (CMAC bc) = CMACAuth
    { forall bc. MACAuth (CMAC bc) -> ByteString
getCMACAuth :: ByteString {- ByteVector n -} }
    deriving newtype (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
(MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool)
-> (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool)
-> Eq (MACAuth (CMAC bc))
forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
== :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
$c/= :: forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
/= :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
Eq, Eq (MACAuth (CMAC bc))
Eq (MACAuth (CMAC bc)) =>
(MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Ordering)
-> (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool)
-> (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool)
-> (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool)
-> (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool)
-> (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc))
-> (MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc))
-> Ord (MACAuth (CMAC bc))
MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Ordering
MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc)
forall bc. Eq (MACAuth (CMAC bc))
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Ordering
forall bc.
MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc)
$ccompare :: forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Ordering
compare :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Ordering
$c< :: forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
< :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
$c<= :: forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
<= :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
$c> :: forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
> :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
$c>= :: forall bc. MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
>= :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> Bool
$cmax :: forall bc.
MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc)
max :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc)
$cmin :: forall bc.
MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc)
min :: MACAuth (CMAC bc) -> MACAuth (CMAC bc) -> MACAuth (CMAC bc)
Ord)

instance Show (MACAuth (CMAC bc)) where
    show :: MACAuth (CMAC bc) -> String
    show :: MACAuth (CMAC bc) -> String
show (CMACAuth ByteString
bytes) = Text -> String
Text.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ ByteString -> HexCase -> Text
Botan.hexEncode ByteString
bytes HexCase
Botan.Lower

type CMACAuth bc = MACAuth (CMAC bc)

-- -- TODO: This can't support BlockCipher CLASS
-- -- IT NEEDS TO BE THE BlockCipher ENUM
-- instance (BlockCipher bc) => MAC (CMAC bc) where
--     mac :: MACKey (CMAC bc) -> ByteString -> MACAuth (CMAC bc)
--     mac k = CMACAuth . fromJust . Botan.mac (Botan.cmac (blockCipherWitness @bc)) (getCMACKeyByteString k)
--
-- -- TODO: This can't support BlockCipher CLASS
-- -- IT NEEDS TO BE THE BlockCipher ENUM
-- instance (BlockCipher bc) => IncrementalMAC (CMAC bc) where
--     macLazy :: MACKey (CMAC bc) -> Lazy.ByteString -> MACAuth (CMAC bc)
--     macLazy k = CMACAuth . fromJust . Botan.macLazy (Botan.cmac (blockCipherWitness @bc)) (getCMACKeyByteString k)

-- Can do per-algorithm instances - this works

-- instance MAC (CMAC AES128) where
--     mac :: MACKey (CMAC bc) -> ByteString -> MACAuth (CMAC bc)
--     mac (CMACKey k) = CMACAuth . fromJust . Botan.mac (Botan.cmac Botan.aes128) k
--
-- instance IncrementalMAC (CMAC AES128) where
--     macLazy :: MACKey (CMAC bc) -> Lazy.ByteString -> MACAuth (CMAC bc)
--     macLazy (CMACKey k) = CMACAuth . fromJust . Botan.macLazy (Botan.cmac Botan.aes128) k

-- ... but its tedious as it requires instances for each combination

-- Maybe I should allow / use proxy / witnesses
-- This requires either:
--  - abandoning use of empty data
--  - a witness data type
--  - classes to convert between crypto types and botan types

class BotanBlockCipher bc where
    botanBlockCipher :: Proxy bc -> Botan.BlockCipher
instance BotanBlockCipher AES128 where
    botanBlockCipher :: Proxy AES128 -> BlockCipher
botanBlockCipher Proxy AES128
_ = BlockCipher
Botan.aes128
class BotanMAC mac where
    botanMAC :: Proxy mac -> Botan.MAC
instance (BotanBlockCipher bc) => BotanMAC (CMAC bc) where
    botanMAC :: BotanBlockCipher bc => Proxy (CMAC bc) -> Botan.MAC
    botanMAC :: BotanBlockCipher bc => Proxy (CMAC bc) -> MAC
botanMAC Proxy (CMAC bc)
_ = BlockCipher -> MAC
Botan.cmac (Proxy bc -> BlockCipher
forall bc. BotanBlockCipher bc => Proxy bc -> BlockCipher
botanBlockCipher (Proxy bc -> BlockCipher) -> Proxy bc -> BlockCipher
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @bc)
instance (BotanBlockCipher bc) => MAC (CMAC bc) where
    mac :: MACKey (CMAC bc) -> ByteString -> MACAuth (CMAC bc)
    mac :: MACKey (CMAC bc) -> ByteString -> MACAuth (CMAC bc)
mac (CMACKey ByteString
k) = ByteString -> MACAuth (CMAC bc)
forall bc. ByteString -> MACAuth (CMAC bc)
CMACAuth (ByteString -> MACAuth (CMAC bc))
-> (ByteString -> ByteString) -> ByteString -> MACAuth (CMAC bc)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe ByteString -> ByteString
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe ByteString -> ByteString)
-> (ByteString -> Maybe ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MAC -> ByteString -> ByteString -> Maybe ByteString
Botan.mac (Proxy (CMAC bc) -> MAC
forall mac. BotanMAC mac => Proxy mac -> MAC
botanMAC (Proxy (CMAC bc) -> MAC) -> Proxy (CMAC bc) -> MAC
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @(CMAC bc)) ByteString
k

-- instance (IsBotanBlockCipher bc) => IncrementalMAC (CMAC AES128) where
--     macLazy :: MACKey (CMAC bc) -> Lazy.ByteString -> MACAuth (CMAC bc)
--     macLazy (CMACKey k) = CMACAuth . fromJust . Botan.macLazy (Botan.cmac Botan.aes128) k

-- CMAC mac

cmac :: (MAC (CMAC bc)) => MACKey (CMAC bc) -> ByteString -> CMACAuth bc
cmac :: forall bc.
MAC (CMAC bc) =>
MACKey (CMAC bc) -> ByteString -> CMACAuth bc
cmac = MACKey (CMAC bc) -> ByteString -> MACAuth (CMAC bc)
forall mac. MAC mac => MACKey mac -> ByteString -> MACAuth mac
mac

cmacLazy :: (IncrementalMAC (CMAC bc)) => MACKey (CMAC bc) -> Lazy.ByteString -> CMACAuth bc
cmacLazy :: forall bc.
IncrementalMAC (CMAC bc) =>
MACKey (CMAC bc) -> ByteString -> CMACAuth bc
cmacLazy = MACKey (CMAC bc) -> ByteString -> MACAuth (CMAC bc)
forall mac.
IncrementalMAC mac =>
MACKey mac -> ByteString -> MACAuth mac
macLazy

newCMACKey :: forall bc m . MonadRandomIO m => m (CMACKey bc)
newCMACKey :: forall bc (m :: * -> *). MonadRandomIO m => m (CMACKey bc)
newCMACKey = ByteString -> MACKey (CMAC bc)
forall bc. ByteString -> MACKey (CMAC bc)
CMACKey (ByteString -> MACKey (CMAC bc))
-> m ByteString -> m (MACKey (CMAC bc))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> m ByteString
forall (m :: * -> *). MonadRandomIO m => Int -> m ByteString
getRandomBytes Int
16