{-# 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 :: ByteString -> HMACContext a
hmacInit secret :: ByteString
secret = Context a -> Context a -> HMACContext a
forall hashalg.
Context hashalg -> Context hashalg -> HMACContext hashalg
HMACContext Context a
octx Context a
ictx
where ctxInit :: Context a
ctxInit = Context a
forall a. HashAlgorithm a => Context a
hashInit
ictx :: Context a
ictx = Context a -> [ByteString] -> Context a
forall a. HashAlgorithm a => Context a -> [ByteString] -> Context a
hashUpdates Context a
ctxInit [ByteString
ipad]
octx :: Context a
octx = Context a -> [ByteString] -> Context a
forall a. HashAlgorithm a => Context a -> [ByteString] -> Context a
hashUpdates Context a
ctxInit [ByteString
opad]
ipad :: ByteString
ipad = (Word8 -> Word8) -> ByteString -> ByteString
B.map (Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
xor 0x36) ByteString
k'
opad :: ByteString
opad = (Word8 -> Word8) -> ByteString -> ByteString
B.map (Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
xor 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 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 Digest a -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (ByteString -> Digest a
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
hashF :: ByteString -> Digest a
hashF = Context a -> Digest a
forall a. HashAlgorithm a => Context a -> Digest a
hashFinalize (Context a -> Digest a)
-> (ByteString -> Context a) -> ByteString -> Digest a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Context a -> ByteString -> Context a
forall a. HashAlgorithm a => Context a -> ByteString -> Context a
hashUpdate Context a
ctxInit
blockSize :: Int
blockSize = Context a -> Int
forall a. HashAlgorithm a => Context a -> Int
hashBlockSize Context a
ctxInit
hmacInitAlg :: HashAlgorithm a
=> a
-> ByteString
-> HMACContext a
hmacInitAlg :: a -> ByteString -> HMACContext a
hmacInitAlg _ secret :: ByteString
secret = ByteString -> HMACContext a
forall a. HashAlgorithm a => ByteString -> HMACContext a
hmacInit ByteString
secret
hmacUpdate :: HashAlgorithm a
=> HMACContext a
-> ByteString
-> HMACContext a
hmacUpdate :: HMACContext a -> ByteString -> HMACContext a
hmacUpdate (HMACContext octx :: Context a
octx ictx :: Context a
ictx) msg :: ByteString
msg =
Context a -> Context a -> HMACContext a
forall hashalg.
Context hashalg -> Context hashalg -> HMACContext hashalg
HMACContext Context a
octx (Context a -> ByteString -> Context a
forall a. HashAlgorithm a => Context a -> ByteString -> Context a
hashUpdate Context a
ictx ByteString
msg)
hmacFinalize :: HashAlgorithm a
=> HMACContext a
-> HMAC a
hmacFinalize :: HMACContext a -> HMAC a
hmacFinalize (HMACContext octx :: Context a
octx ictx :: Context a
ictx) =
Digest a -> HMAC a
forall a. Digest a -> HMAC a
HMAC (Digest a -> HMAC a) -> Digest a -> HMAC a
forall a b. (a -> b) -> a -> b
$ Context a -> Digest a
forall a. HashAlgorithm a => Context a -> Digest a
hashFinalize (Context a -> Digest a) -> Context a -> Digest a
forall a b. (a -> b) -> a -> b
$ Context a -> [ByteString] -> Context a
forall a. HashAlgorithm a => Context a -> [ByteString] -> Context a
hashUpdates Context a
octx [Digest a -> ByteString
forall a. Byteable a => a -> ByteString
toBytes (Digest a -> ByteString) -> Digest a -> ByteString
forall a b. (a -> b) -> a -> b
$ Context a -> Digest a
forall a. HashAlgorithm a => Context a -> Digest a
hashFinalize Context a
ictx]