    -- |
    -- Module      : Crypto.MAC.HMAC
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : unknown
    --
    -- provide the HMAC (Hash based Message Authentification Code) base algorithm.
    -- <http://en.wikipedia.org/wiki/HMAC>
    --
    module Crypto.MAC.HMAC
        ( hmac
        ) where

    import Data.ByteString (ByteString)
    import qualified Data.ByteString as B
    import Data.Bits (xor)

    -- | compute a MAC using the supplied hashing function
    --
    -- An incremental API can be found in the module "Crypto.Hash".
    --
    hmac :: (ByteString -> ByteString) -- ^ hash function
         -> Int -- ^ block size
         -> ByteString -- ^ secret
         -> ByteString -- ^ message
         -> ByteString
    hmac :: (ByteString -> ByteString)
    -> Int -> ByteString -> ByteString -> ByteString
    hmac hashF :: ByteString -> ByteString
    hashF blockSize :: Int
    blockSize secret :: ByteString
    secret msg :: ByteString
    msg = ByteString -> ByteString
    hashF (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ ByteString -> ByteString -> ByteString
    B.append ByteString
    opad (ByteString -> ByteString
    hashF (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ ByteString -> ByteString -> ByteString
    B.append ByteString
    ipad ByteString
    msg)
        where opad :: ByteString
    opad = (Word8 -> Word8) -> ByteString -> ByteString
    B.map (Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    xor 0x5c) ByteString
    k'
              ipad :: ByteString
    ipad = (Word8 -> Word8) -> ByteString -> ByteString
    B.map (Word8 -> Word8 -> Word8
    forall a. Bits a => a -> a -> a
    xor 0x36) ByteString
    k'

              k' :: ByteString
    k'  = ByteString -> ByteString -> ByteString
    B.append ByteString
    kt ByteString
    pad
              kt :: ByteString
    kt  = if ByteString -> Int
    B.length ByteString
    secret Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    blockSize then ByteString -> ByteString
    hashF ByteString
    secret else ByteString
    secret
              pad :: ByteString
    pad = Int -> Word8 -> ByteString
    B.replicate (Int -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    blockSize Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - ByteString -> Int
    B.length ByteString
    kt) 0