-- |
-- 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