ppad-hmac-drbg 0.3.1 → 0.3.2
raw patch · 5 files changed
+58/−11 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG +6/−1
- lib/Crypto/DRBG/HMAC/Internal.hs +37/−1
- lib/Crypto/DRBG/HMAC/SHA256.hs +7/−4
- lib/Crypto/DRBG/HMAC/SHA512.hs +7/−4
- ppad-hmac-drbg.cabal +1/−1
CHANGELOG view
@@ -1,6 +1,11 @@ # Changelog -- 0.3.1 (2026-02-01)+- 0.3.2 (2026-11-14)+ * 'new' and 'reseed' combine their seed material in a pinned buffer+ that is zeroed after use, rather than concatenating it into+ ordinary heap bytestrings that could outlive 'wipe'.++- 0.3.1 (2026-02-04) * Adds SPECIALIZE pragmas for IO and ST to improve the generated Core. - 0.3.0 (2026-02-01)
lib/Crypto/DRBG/HMAC/Internal.hs view
@@ -1,4 +1,5 @@ {-# OPTIONS_HADDOCK hide #-}+{-# LANGUAGE BangPatterns #-} -- | -- Module: Crypto.DRBG.HMAC.Internal@@ -12,9 +13,18 @@ Error(..) , _RESEED_COUNTER , _MAX_BYTES+ , _with_concat ) where -import Data.Word (Word64)+import Control.Monad.Primitive (PrimMonad)+import qualified Control.Monad.Primitive as Prim (unsafeIOToPrim)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BI+import qualified Data.ByteString.Unsafe as BU+import Data.Word (Word8, Word64)+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Marshal.Utils (copyBytes, fillBytes)+import Foreign.Ptr (Ptr, castPtr, plusPtr) -- | A DRBG error. data Error =@@ -31,3 +41,29 @@ _MAX_BYTES :: Word64 _MAX_BYTES = 0x10000 {-# INLINE _MAX_BYTES #-}++-- | Run an action on the concatenation of the given strings, held in a+-- pinned buffer that is zeroed once the action completes, so that+-- (secret) seed material leaves no copy of the library's making+-- behind. The action must not retain its argument.+_with_concat+ :: PrimMonad m+ => [BS.ByteString]+ -> (BS.ByteString -> m a)+ -> m a+_with_concat bss act = do+ let !n = sum (fmap BS.length bss)+ fp <- Prim.unsafeIOToPrim $ do+ fp <- BI.mallocByteString n+ withForeignPtr fp $ \dst -> copy_all dst bss+ pure fp+ !r <- act (BI.BS fp n)+ Prim.unsafeIOToPrim $ withForeignPtr fp $ \p -> fillBytes p 0 n+ pure r+ where+ copy_all :: Ptr Word8 -> [BS.ByteString] -> IO ()+ copy_all _ [] = pure ()+ copy_all dst (b@(BI.PS _ _ l) : bs) = do+ BU.unsafeUseAsCString b $ \src -> copyBytes dst (castPtr src) l+ copy_all (dst `plusPtr` l) bs+{-# INLINE _with_concat #-}
lib/Crypto/DRBG/HMAC/SHA256.hs view
@@ -29,7 +29,8 @@ , _read_k ) where -import Crypto.DRBG.HMAC.Internal (Error(..), _RESEED_COUNTER, _MAX_BYTES)+import Crypto.DRBG.HMAC.Internal+ (Error(..), _RESEED_COUNTER, _MAX_BYTES, _with_concat) import qualified Crypto.Hash.SHA256 as SHA256 import Crypto.Hash.SHA256.Internal (Registers(..)) import qualified Crypto.Hash.SHA256.Internal as SHA256 (cat)@@ -87,7 +88,7 @@ PA.setPrimArray drbg 02 08 (0x00000000 :: Word32) -- init k PA.setPrimArray drbg 10 08 (0x01010101 :: Word32) -- init v PA.setPrimArray drbg 18 16 (0x00000000 :: Word32) -- scratch- update drbg (entropy <> nonce <> ps)+ _with_concat [entropy, nonce, ps] (update drbg) pure $! DRBG drbg {-# INLINABLE new #-} {-# SPECIALIZE new@@ -118,7 +119,7 @@ -> BS.ByteString -> m () reseed (DRBG drbg) entr addl = do- update drbg (entr <> addl)+ _with_concat [entr, addl] (update drbg) init_counter drbg {-# INLINE reseed #-} @@ -184,7 +185,9 @@ -- | Wipe the state of a DRBG. -- -- You should call this when you're finished with a DRBG to ensure that its--- state is wiped from memory.+-- state is wiped from memory. A wiped DRBG must not be used afterwards:+-- its state is reset to the publicly known initial one, so it would+-- produce predictable output. -- -- >>> drbg <- new mempty mempty mempty -- >>> Right bytes <- gen drbg addl_bytes 16
lib/Crypto/DRBG/HMAC/SHA512.hs view
@@ -29,7 +29,8 @@ , _read_k ) where -import Crypto.DRBG.HMAC.Internal (Error(..), _RESEED_COUNTER, _MAX_BYTES)+import Crypto.DRBG.HMAC.Internal+ (Error(..), _RESEED_COUNTER, _MAX_BYTES, _with_concat) import qualified Crypto.Hash.SHA512 as SHA512 import Crypto.Hash.SHA512.Internal (Registers(..)) import qualified Crypto.Hash.SHA512.Internal as SHA512 (cat)@@ -87,7 +88,7 @@ PA.setPrimArray drbg 01 08 (0x0000000000000000 :: Word64) -- init k PA.setPrimArray drbg 09 08 (0x0101010101010101 :: Word64) -- init v PA.setPrimArray drbg 17 16 (0x0000000000000000 :: Word64) -- scratch- update drbg (entropy <> nonce <> ps)+ _with_concat [entropy, nonce, ps] (update drbg) pure $! DRBG drbg {-# INLINABLE new #-} {-# SPECIALIZE new@@ -118,7 +119,7 @@ -> BS.ByteString -> m () reseed (DRBG drbg) entr addl = do- update drbg (entr <> addl)+ _with_concat [entr, addl] (update drbg) init_counter drbg {-# INLINE reseed #-} @@ -184,7 +185,9 @@ -- | Wipe the state of a DRBG. -- -- You should call this when you're finished with a DRBG to ensure that its--- state is wiped from memory.+-- state is wiped from memory. A wiped DRBG must not be used afterwards:+-- its state is reset to the publicly known initial one, so it would+-- produce predictable output. -- -- >>> drbg <- new mempty mempty mempty -- >>> Right bytes <- gen drbg addl_bytes 16
ppad-hmac-drbg.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: ppad-hmac-drbg-version: 0.3.1+version: 0.3.2 synopsis: HMAC-based deterministic random bit generator license: MIT license-file: LICENSE