hmac-drbg

Pure Haskell HMAC-DRBG (docs.ppad.tech/hmac-drbg).
git clone git://git.ppad.tech/hmac-drbg.git
Log | Files | Refs | README | LICENSE

commit 47b445a1684f93a6822f416f02aba19c3d229cc7
parent 3c329bb29be708da78c8c3940bf4ef19e7e1747a
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat, 10 Jan 2026 16:12:26 +0400

lib: handle new MAC types

.. that, for ergonomic reasons, I'm sort of regretting.

Diffstat:
Mbench/Main.hs | 17+++++++++++++----
Mflake.lock | 16++++++++--------
Mlib/Crypto/DRBG/HMAC.hs | 13+++++++------
Mtest/Main.hs | 12++++++++++--
4 files changed, 38 insertions(+), 20 deletions(-)

diff --git a/bench/Main.hs b/bench/Main.hs @@ -8,11 +8,20 @@ import Criterion.Main import qualified Crypto.DRBG.HMAC as DRBG import qualified Crypto.Hash.SHA256 as SHA256 import qualified Crypto.Hash.SHA512 as SHA512 +import qualified Data.ByteString as BS + +hmac_sha256 :: BS.ByteString -> BS.ByteString -> BS.ByteString +hmac_sha256 k b = case SHA256.hmac k b of + SHA256.MAC m -> m + +hmac_sha512 :: BS.ByteString -> BS.ByteString -> BS.ByteString +hmac_sha512 k b = case SHA512.hmac k b of + SHA512.MAC m -> m main :: IO () main = do - !drbg256 <- DRBG.new SHA256.hmac mempty mempty mempty -- no NFData - !drbg512 <- DRBG.new SHA512.hmac mempty mempty mempty -- no NFData + !drbg256 <- DRBG.new hmac_sha256 mempty mempty mempty -- no NFData + !drbg512 <- DRBG.new hmac_sha512 mempty mempty mempty -- no NFData defaultMain [ suite drbg256 drbg512 ] @@ -20,13 +29,13 @@ main = do suite drbg256 drbg512 = bgroup "ppad-hmac-drbg" [ bgroup "HMAC-SHA256" [ - bench "new" $ whnfAppIO (DRBG.new SHA256.hmac mempty mempty) mempty + bench "new" $ whnfAppIO (DRBG.new hmac_sha256 mempty mempty) mempty , bench "reseed" $ whnfAppIO (DRBG.reseed mempty mempty) drbg256 , bench "gen (32B)" $ whnfAppIO (DRBG.gen mempty 32) drbg256 , bench "gen (256B)" $ whnfAppIO (DRBG.gen mempty 256) drbg256 ] , bgroup "HMAC-SHA512" [ - bench "new" $ whnfAppIO (DRBG.new SHA512.hmac mempty mempty) mempty + bench "new" $ whnfAppIO (DRBG.new hmac_sha512 mempty mempty) mempty , bench "reseed" $ whnfAppIO (DRBG.reseed mempty mempty) drbg512 , bench "gen (32B)" $ whnfAppIO (DRBG.gen mempty 32) drbg512 , bench "gen (256B)" $ whnfAppIO (DRBG.gen mempty 256) drbg512 diff --git a/flake.lock b/flake.lock @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1767897559, - "narHash": "sha256-UabcPqE4O+h1HHv02LjanjuorRS91OODqk0ek55VrmQ=", + "lastModified": 1768045644, + "narHash": "sha256-8+jLaYRN8iX6NmyotE7DvjfjUIT8I0KOchgcP7uq7Vo=", "ref": "master", - "rev": "528d9cf07ca756fb5422cab174849fe0708620d0", - "revCount": 111, + "rev": "4716cd5b4e673e9cb66e4e5e427e5464a7c10977", + "revCount": 116, "type": "git", "url": "git://git.ppad.tech/sha256.git" }, @@ -139,11 +139,11 @@ ] }, "locked": { - "lastModified": 1767897585, - "narHash": "sha256-QxLlHu8+tGKZ9aOKFnVOqNwEn+LCuNF27kY2dxOCYxo=", + "lastModified": 1768045869, + "narHash": "sha256-ySqv5fQRz+/9X54yXCuck2QnGyuIqRLpRzanh+Ehl88=", "ref": "master", - "rev": "428e2e09c345a0cb255d9aab432606308872c014", - "revCount": 38, + "rev": "0fbaba3c091692622744d30016e36ca6b726a819", + "revCount": 42, "type": "git", "url": "git://git.ppad.tech/sha512.git" }, diff --git a/lib/Crypto/DRBG/HMAC.hs b/lib/Crypto/DRBG/HMAC.hs @@ -69,8 +69,7 @@ _RESEED_COUNTER = (2 :: Word64) ^ (48 :: Word64) -- Create a DRBG with 'new', and then use and reuse it to generate -- bytes as needed. -- --- >>> import qualified Crypto.Hash.SHA256 as SHA256 --- >>> drbg <- new SHA256.hmac entropy nonce personalization_string +-- >>> drbg <- new hmac entropy nonce personalization_string -- >>> bytes0 <- gen addl_bytes 16 drbg -- >>> bytes1 <- gen addl_bytes 16 drbg -- >>> drbg @@ -94,8 +93,9 @@ data DRBGState = DRBGState -- value as the second, producing a MAC digest. -- -- >>> import qualified Crypto.Hash.SHA256 as SHA256 --- >>> :t SHA256.hmac --- SHA256.hmac :: BS.ByteString -> BS.ByteString -> BS.ByteString +-- >>> let hmac k b = let SHA256.MAC m = SHA256.hmac k b in m +-- >>> :t hmac +-- hmac :: BS.ByteString -> BS.ByteString -> BS.ByteString type HMAC = BS.ByteString -> BS.ByteString -> BS.ByteString -- HMAC function and its associated outlength @@ -133,7 +133,8 @@ _read_k (DRBG mut) = do -- The DRBG is returned in any 'PrimMonad', e.g. 'ST' or 'IO'. -- -- >>> import qualified Crypto.Hash.SHA256 as SHA256 --- >>> new SHA256.hmac entropy nonce personalization_string +-- >>> let hmac k b = let SHA256.MAC m = SHA256.hmac k b in m +-- >>> new hmac entropy nonce personalization_string -- "<drbg>" new :: PrimMonad m @@ -155,7 +156,7 @@ new hmac entropy nonce ps = do -- 'MaxBytesExceeded'. -- -- >>> import qualified Data.ByteString.Base16 as B16 --- >>> drbg <- new SHA256.hmac entropy nonce personalization_string +-- >>> drbg <- new hmac entropy nonce personalization_string -- >>> Right bytes0 <- gen addl_bytes 16 drbg -- >>> Right bytes1 <- gen addl_bytes 16 drbg -- >>> B16.encode bytes0 diff --git a/test/Main.hs b/test/Main.hs @@ -37,10 +37,18 @@ main = do defaultMain (cavp_14_3 sha256_cases sha512_cases) +hmac_sha256 :: BS.ByteString -> BS.ByteString -> BS.ByteString +hmac_sha256 k b = case SHA256.hmac k b of + SHA256.MAC m -> m + +hmac_sha512 :: BS.ByteString -> BS.ByteString -> BS.ByteString +hmac_sha512 k b = case SHA512.hmac k b of + SHA512.MAC m -> m + cavp_14_3 :: [CaseBlock] -> [CaseBlock] -> TestTree cavp_14_3 cs ds = testGroup "CAVP 14.3" [ - testGroup "HMAC-SHA256" (fmap (execute_caseblock SHA256.hmac) cs) - , testGroup "HMAC-SHA512" (fmap (execute_caseblock SHA512.hmac) ds) + testGroup "HMAC-SHA256" (fmap (execute_caseblock hmac_sha256) cs) + , testGroup "HMAC-SHA512" (fmap (execute_caseblock hmac_sha512) ds) ] data CaseBlock = CaseBlock {