{-# LANGUAGE BangPatterns #-}
module Crypto.MAC
(
HMAC(..)
, hmac
, hmacAlg
, 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
data HMACContext hashalg = HMACContext !(Context hashalg) !(Context hashalg)
hmacInit :: HashAlgorithm a
=> ByteString
-> HMACContext a
hmacInit :: forall a. HashAlgorithm a => ByteString -> HMACContext a
hmacInit ByteString
secret = forall hashalg.
Context hashalg -> Context hashalg -> HMACContext hashalg
HMACContext Context a
octx Context a
ictx
where ctxInit :: Context a
ctxInit = forall a. HashAlgorithm a => Context a
hashInit
ictx :: Context a
ictx = forall a. HashAlgorithm a => Context a -> [ByteString] -> Context a
hashUpdates Context a
ctxInit [ByteString
ipad]
octx :: Context a
octx = forall a. HashAlgorithm a => Context a -> [ByteString] -> Context a
hashUpdates Context a
ctxInit [ByteString
opad]
ipad :: ByteString
ipad = (Word8 -> Word8) -> ByteString -> ByteString
B.map (forall a. Bits a => a -> a -> a
xor Word8
0x36) ByteString
k'
opad :: ByteString
opad = (Word8 -> Word8) -> ByteString -> ByteString
B.map (forall a. Bits a => a -> a -> a
xor Word8
0x5c) ByteString
k'
k' :: ByteString
k' = ByteString -> ByteString -> ByteString
B.append ByteString
kt ByteString
pad
kt :: ByteString
kt = if ByteString -> Int
B.length ByteString
secret forall a. Ord a => a -> a -> Bool
> forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
blockSize then forall a. Byteable a => a -> ByteString
toBytes (ByteString -> Digest a
hashF ByteString
secret) else ByteString
secret
pad :: ByteString
pad = Int -> Word8 -> ByteString
B.replicate (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
blockSize forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
kt) Word8
0
hashF :: ByteString -> Digest a
hashF = forall a. HashAlgorithm a => Context a -> Digest a
hashFinalize forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. HashAlgorithm a => Context a -> ByteString -> Context a
hashUpdate Context a
ctxInit
blockSize :: Int
blockSize = forall a. HashAlgorithm a => Context a -> Int
hashBlockSize Context a
ctxInit
hmacInitAlg :: HashAlgorithm a
=> a
-> ByteString
-> HMACContext a
hmacInitAlg :: forall a. HashAlgorithm a => a -> ByteString -> HMACContext a
hmacInitAlg a
_ ByteString
secret = forall a. HashAlgorithm a => ByteString -> HMACContext a
hmacInit ByteString
secret
hmacUpdate :: HashAlgorithm a
=> HMACContext a
-> ByteString
-> HMACContext a
hmacUpdate :: forall a.
HashAlgorithm a =>
HMACContext a -> ByteString -> HMACContext a
hmacUpdate (HMACContext Context a
octx Context a
ictx) ByteString
msg =
forall hashalg.
Context hashalg -> Context hashalg -> HMACContext hashalg
HMACContext Context a
octx (forall a. HashAlgorithm a => Context a -> ByteString -> Context a
hashUpdate Context a
ictx ByteString
msg)
hmacFinalize :: HashAlgorithm a
=> HMACContext a
-> HMAC a
hmacFinalize :: forall a. HashAlgorithm a => HMACContext a -> HMAC a
hmacFinalize (HMACContext Context a
octx Context a
ictx) =
forall a. Digest a -> HMAC a
HMAC forall a b. (a -> b) -> a -> b
$ forall a. HashAlgorithm a => Context a -> Digest a
hashFinalize forall a b. (a -> b) -> a -> b
$ forall a. HashAlgorithm a => Context a -> [ByteString] -> Context a
hashUpdates Context a
octx [forall a. Byteable a => a -> ByteString
toBytes forall a b. (a -> b) -> a -> b
$ forall a. HashAlgorithm a => Context a -> Digest a
hashFinalize Context a
ictx]