-- | -- Module : Crypto.MAC -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : unknown -- -- Crypto hash generic MAC (Message Authentification Code) module -- {-# LANGUAGE BangPatterns #-} module Crypto.MAC ( -- * MAC algorithms HMAC(..) , hmac , hmacAlg -- ** Incremental MAC algorithms , HMACContext , hmacInit , hmacInitAlg , hmacUpdate , hmacFinalize ) where import Crypto.Hash import Data.ByteString (ByteString) import Data.Byteable import Data.Bits (xor) import qualified Data.ByteString as B -- -------------------------------------------------------------------------- -- -- Incremental HMAC -- | Represent an ongoing HMAC state, that can be appended with 'hmacUpdate' -- and finalize to an HMAC with 'hmacFinalize' data HMACContext hashalg = HMACContext !(Context hashalg) !(Context hashalg) -- | Initialize a new incremental HMAC context hmacInit :: HashAlgorithm a => ByteString -- ^ Secret key -> HMACContext a hmacInit secret = HMACContext octx ictx where ctxInit = hashInit ictx = hashUpdates ctxInit [ipad] octx = hashUpdates ctxInit [opad] ipad = B.map (xor 0x36) k' opad = B.map (xor 0x5c) k' k' = B.append kt pad kt = if B.length secret > fromIntegral blockSize then toBytes (hashF secret) else secret pad = B.replicate (fromIntegral blockSize - B.length kt) 0 hashF = hashFinalize . hashUpdate ctxInit blockSize = hashBlockSize ctxInit -- | Initialize a new incremental HMAC context with a given hash algorithm. hmacInitAlg :: HashAlgorithm a => a -- ^ the hash algorithm the actual value is unused. -> ByteString -- ^ Secret key -> HMACContext a hmacInitAlg _ secret = hmacInit secret -- | Incrementally update a HMAC context hmacUpdate :: HashAlgorithm a => HMACContext a -> ByteString -- ^ Message to Mac -> HMACContext a hmacUpdate (HMACContext octx ictx) msg = HMACContext octx (hashUpdate ictx msg) -- | Finalize a HMAC context and return the HMAC. hmacFinalize :: HashAlgorithm a => HMACContext a -> HMAC a hmacFinalize (HMACContext octx ictx) = HMAC $ hashFinalize $ hashUpdates octx [toBytes $ hashFinalize ictx]