diff --git a/Codec/Digest/SHA.hs b/Codec/Digest/SHA.hs
--- a/Codec/Digest/SHA.hs
+++ b/Codec/Digest/SHA.hs
@@ -1,12 +1,13 @@
 -- | A pure interface to SHA
 module Codec.Digest.SHA(
-  Length(..), hash, hash',
+  Length(..), hash, hash', hmac,
   showBSasHex
 ) where
 
 import Codec.Digest.SHA.Monad
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as BL
+import Data.Bits(xor)
 
 -- | Hashing lazy bytestrings
 hash :: Length -> BL.ByteString -> B.ByteString
@@ -15,3 +16,29 @@
 -- | Hashing strict bytestrings
 hash' :: Length -> B.ByteString -> B.ByteString
 hash' len bs = snd $ runSHA len (update bs)
+
+lenBytes :: Num a => Length -> a
+lenBytes SHA256 = 32
+lenBytes SHA384 = 48
+lenBytes SHA512 = 64
+
+fixkey :: B.ByteString -> Length -> B.ByteString
+fixkey k (lenBytes -> len) = if B.length k >= len
+                            then B.take len k
+                            else B.concat [k,(B.replicate (len - B.length k) 0)]
+
+-- | SHA-based HMAC, see http://en.wikipedia.org/wiki/HMAC
+--
+-- If you're doing encryption and want to prevent attackers from
+-- changing your messages, you probably want this.
+hmac :: Hashable a 
+       => Length -- ^ Desired size of the HMAC
+       -> B.ByteString -- ^ The shared secret key to use
+       -> a -- ^ Message to hash
+       -> B.ByteString
+hmac len key' msg = hash' len $ B.concat [opad,ihash]
+  where
+    ihash = snd $ runSHA len $ update ipad >> update msg
+    opad = B.map (xor 0x5c) key
+    ipad = B.map (xor 0x36) key
+    key = fixkey key' len
diff --git a/SHA2.cabal b/SHA2.cabal
--- a/SHA2.cabal
+++ b/SHA2.cabal
@@ -1,7 +1,7 @@
 Name: SHA2
 Synopsis: Fast, incremental SHA hashing for bytestrings
 Description: A zero-copy binding to Aaron Gifford's SHA implementation, including a copy of that implementation
-Version: 0.0.1
+Version: 0.1.0
 License: BSD3
 License-file: COPYING
 Copyright: Copyright (c) 2009 University of Tromsø
