phkdf-0.0.0.0: lib/Crypto/PHKDF/HMAC/Subtle.hs
{- |
"Internal" data structures representing precomputed HMAC keys and partial HMAC
contexts, supporting incremental computation and backtracking.
-}
module Crypto.PHKDF.HMAC.Subtle
( HmacCtx(..)
, HmacKey(..)
, hmacKey_ipad
, hmacKey_opad
) where
import qualified Crypto.Hash.SHA256 as SHA256
-- | Fixed-size context representing the state of a partial HMAC computation
-- with a complete HMAC key and a partial message parameter.
data HmacCtx = HmacCtx
{ hmacCtx_ipad :: !SHA256.Ctx
, hmacCtx_opad :: !SHA256.Ctx
} deriving (Eq)
-- | A precomputed HMAC key. Computing an HMAC key costs two SHA256 blocks.
--
-- No additional blocks are incurred for keys that are 64 bytes or less in
-- length. Keys that are longer than 64 bytes long must be first hashed
-- with SHA256 before the key can be derived, incurring extra blocks.
--
-- It is not uncommon that implementations of PBKDF2, HKDF, etc unnecessarily
-- redo this computation even though a single HMAC key is used repeatedly.
--
-- TODO: FIXME: this data structure is way larger than it should be. We can
-- pack this into a single 64-byte bytestring, but right now it's 208 bytes
-- of data plus extra overhead.
--
-- On the other hand, this approach may actually be more efficient for the
-- core PHKDF algorithm as currently implemented. Reducing the size of this
-- data structure while maintaining tight code involves some additional work
-- on cryptohash-sha256
newtype HmacKey = HmacKey { hmacKey_run :: HmacCtx } deriving (Eq)
hmacKey_ipad :: HmacKey -> SHA256.Ctx
hmacKey_ipad (HmacKey ctx) = hmacCtx_ipad ctx
hmacKey_opad :: HmacKey -> SHA256.Ctx
hmacKey_opad (HmacKey ctx) = hmacCtx_opad ctx