1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- |
-- Module : Crypto.MAC.KeyedBlake2
-- License : BSD-style
-- Maintainer : Matthias Valvekens <dev@mvalvekens.be>
-- Stability : experimental
-- Portability : unknown
--
-- Expose a MAC interface to the keyed Blake2 algorithms
-- defined in RFC 7693.
module Crypto.MAC.KeyedBlake2 (
HashBlake2,
KeyedBlake2 (..),
keyedBlake2,
keyedBlake2Lazy,
-- * Incremental
Context,
initialize,
update,
updates,
finalize,
) where
import qualified Crypto.Hash as H
import Crypto.Hash.Blake2
import qualified Crypto.Hash.Types as H
import Crypto.Internal.DeepSeq (NFData)
import Data.ByteArray (ByteArrayAccess)
import qualified Data.ByteArray as B
import qualified Data.ByteString.Lazy as L
import Foreign.Ptr (Ptr)
-- Keyed Blake2b
-- | Represent a Blake2b MAC that is a phantom type with the hash used to produce the
-- MAC.
--
-- The Eq instance is constant time. No Show instance is provided, to avoid
-- printing by mistake.
newtype KeyedBlake2 a = KeyedBlake2 {keyedBlake2GetDigest :: H.Digest a}
deriving (ByteArrayAccess, NFData)
instance Eq (KeyedBlake2 a) where
KeyedBlake2 x == KeyedBlake2 y = B.constEq x y
-- | Represent an ongoing Blake2 state, that can be appended with 'update' and
-- finalized to a 'KeyedBlake2' with 'finalize'.
newtype Context a = Context (H.Context a)
-- | Initialize a new incremental keyed Blake2 context with the supplied key.
initialize
:: forall a key
. (HashBlake2 a, ByteArrayAccess key)
=> key -> Context a
initialize k = Context $ H.Context $ B.allocAndFreeze ctxSz performInit
where
ctxSz = H.hashInternalContextSize (undefined :: a)
digestSz = H.hashDigestSize (undefined :: a)
-- cap the number of key bytes at digestSz,
-- since that's the maximal key size
keyByteLen = min (B.length k) digestSz
performInit :: Ptr (H.Context a) -> IO ()
performInit ptr = B.withByteArray k $
\keyPtr -> blake2InternalKeyedInit ptr keyPtr (fromIntegral keyByteLen)
-- | Incrementally update a keyed Blake2 context.
update :: (HashBlake2 a, ByteArrayAccess ba) => Context a -> ba -> Context a
update (Context ctx) = Context . H.hashUpdate ctx
-- | Incrementally update a keyed Blake2 context with multiple inputs.
updates :: (HashBlake2 a, ByteArrayAccess ba) => Context a -> [ba] -> Context a
updates (Context ctx) = Context . H.hashUpdates ctx
-- | Finalize a keyed Blake2 context and return the computed MAC.
finalize :: HashBlake2 a => Context a -> KeyedBlake2 a
finalize (Context ctx) = KeyedBlake2 $ H.hashFinalize ctx
-- | Compute a Blake2 MAC using the supplied key.
keyedBlake2
:: (HashBlake2 a, ByteArrayAccess key, ByteArrayAccess ba)
=> key -> ba -> KeyedBlake2 a
keyedBlake2 key msg = finalize $ update (initialize key) msg
-- | Compute a Blake2 MAC using the supplied key, for a lazy input.
keyedBlake2Lazy
:: (HashBlake2 a, ByteArrayAccess key)
=> key -> L.ByteString -> KeyedBlake2 a
keyedBlake2Lazy key msg = finalize $ updates (initialize key) (L.toChunks msg)
|