BufferedBlockHashAlgorithm Class
Definition
- Namespace
- Bodu.Security.Cryptography
- Assembly
- Bodu.Security.Cryptography.dll
- Package
- Bodu.Security.Cryptography 1.2.0
Provides the shared infrastructure for hash algorithms that consume input in fixed-size blocks. Owns the residual buffer, the running total of bytes consumed, the disposal latch, and the HashCore(byte[], int, int) to HashCore(ReadOnlySpan<byte>) delegation.
public abstract class BufferedBlockHashAlgorithm : HashAlgorithm, ICryptoTransform, IDisposable
- Inheritance
-
BufferedBlockHashAlgorithm
- Implements
- Derived
- Inherited Members
- Extension Methods
Examples
// Consume a concrete derivative through the standard HashAlgorithm contract - the base
// class drives the residual buffer and the block-aligned compression loop for you.
using HashAlgorithm hash = new Blake2b(); // DeferredFinalBlockHashAlgorithm<T>
byte[] digest1 = hash.ComputeHash("hello"u8.ToArray());
using HashAlgorithm tiger = new Tiger(); // BlockHashAlgorithm<T>
byte[] digest2 = tiger.ComputeHash("hello"u8.ToArray());
Remarks
This class is the common ancestor for both block-buffered patterns offered by the library: BlockHashAlgorithm (Merkle–Damgård-style; pads the final partial block before processing) and the Blake-family-style sibling that defers the final full block until HashFinal() so that a finalization flag may be raised on the last compression call.
The grandparent intentionally does not implement HashCore(ReadOnlySpan<byte>) or HashFinal(), because the buffering loops and finalization shapes of the two derived patterns genuinely differ. Each derived base owns its own HashCore(ReadOnlySpan<byte>) override and reads BlockSize, Bodu.Security.Cryptography.BufferedBlockHashAlgorithm._residualBlock, Bodu.Security.Cryptography.BufferedBlockHashAlgorithm._residualBytes and Bodu.Security.Cryptography.BufferedBlockHashAlgorithm._totalBytes directly.
Derived classes must implement the following:
-
Initialize() resets any algorithm-specific state (chaining variables, IV, schedule).
Override and call
base.Initialize()first. - HashCore(ReadOnlySpan<byte>) consumes the input span using the buffering shape required by the algorithm family.
- HashFinal() finalizes the computation and returns the digest.
Don't derive from this class directly. Use one of the four pattern-specific bases that extend it - the buffering loops and finalization shapes differ enough that the right derivation point depends on which family the algorithm belongs to:
- Merkle-Damgård, unkeyed BlockHashAlgorithm - Tiger, Whirlpool, Snefru, the SHA-2 family, classic block-padding hashes that finalize by padding the last partial block.
- Merkle-Damgård, keyed KeyedBlockHashAlgorithm - Poly1305, SipHash, and any keyed hash whose finalization is "pad then compress".
- Blake-style, unkeyed DeferredFinalBlockHashAlgorithm - BLAKE3 and other algorithms that need to defer the last full block so a finalization flag can be set.
- Blake-style, optionally keyed KeyedDeferredFinalBlockHashAlgorithm - BLAKE2b, BLAKE2s, and the RFC 7693 keyed-MAC variants of BLAKE-family hashes.
Derive from BufferedBlockHashAlgorithm directly only when implementing a new buffering pattern that doesn't fit either family - e.g. a sponge construction with a non-Merkle-Damgård finalization step.
Constructors
BufferedBlockHashAlgorithm(int)
Initializes a new instance of the BufferedBlockHashAlgorithm class with the specified input block size.
protected BufferedBlockHashAlgorithm(int blockSize)
Parameters
blockSizeintThe fixed size, in bits, of each block consumed by the algorithm. Must be greater than zero and a positive multiple of 8.
Remarks
Stores blockSize directly in the protected BlockSize field and allocates the
residual buffer at blockSize / 8 bytes. Derived classes compute the byte length inline as
BlockSize / 8 for span sizing and byte-aligned iteration. Derived classes are expected to override
Initialize(), call base.Initialize() first to clear the inherited buffer and counters, then
reset their own algorithm-specific state so the two halves stay in sync.
Exceptions
- ArgumentOutOfRangeException
Thrown when
blockSizeis less than or equal to zero.
Fields
BlockSize
The fixed size, in bits, of each block consumed by the algorithm. Multiply or divide by 8 at the use site to convert to bytes for buffer allocation, span sizing, or block-aligned iteration.
protected readonly int BlockSize
Field Value
Properties
AlgorithmName
Gets the canonical, fully-qualified algorithm name for this instance, including any size or variant qualifiers
(for example, "Tiger/192", "Skein-512-256", "BLAKE2b-512", "ASCON-HASH256",
"SipHash-2-4-64").
public abstract string AlgorithmName { get; }
Property Value
- string
A string identifying the algorithm and its current configuration.
Remarks
Derived classes implement this property to expose a stable, consumer-facing identifier suitable for logging, telemetry, registry keys, or interop with hash-name catalogues. Implementations should be pure and side-effect-free - the value may be queried before any input has been consumed and after disposal as part of error reporting.
IsDisposed
Gets a value indicating whether this instance has been disposed. Read-only and updated exactly once by Dispose(bool) after the residual buffer and counters have been cleared.
protected bool IsDisposed { get; }
Property Value
Remarks
Derived classes follow the canonical dispose pattern - guard the body of their own Dispose(bool)
override with if (IsDisposed) return;, clear their own state when disposing is
true, and call base.Dispose(disposing) last. Derived classes must not declare a
private _disposed field of their own - the latch is owned exclusively by this base class.
Methods
Dispose(bool)
Releases the resources used by the algorithm and zeros the residual buffer.
protected override void Dispose(bool disposing)
Parameters
disposingbooltrue to release both managed and unmanaged resources; false to release only unmanaged resources.
Remarks
The dispose latch ensures that subsequent calls are no-ops and that the residual buffer is cleared at most once.
Derived classes that hold algorithm-specific state, buffers, keys, or other secret material should override
Dispose(bool), clear their own state when disposing is
true, and then call the base implementation.
HashCore(byte[], int, int)
Validates the supplied byte-array slice and forwards it to the HashCore(ReadOnlySpan<byte>) overload that derived classes implement.
protected override void HashCore(byte[] array, int ibStart, int cbSize)
Parameters
arraybyte[]The input byte array containing the data to hash.
ibStartintThe zero-based index in
arrayat which to begin reading data.cbSizeintThe number of bytes to process from
array.
Exceptions
- ArgumentNullException
arrayis null.- ArgumentOutOfRangeException
ibStartis less than zero.-or-
cbSizeis less than zero.- ArgumentException
ibStartandcbSizespecify a range that exceeds the length ofarray.- ObjectDisposedException
The algorithm instance has been disposed.
- CryptographicUnexpectedOperationException
On target frameworks prior to .NET 6, the hash algorithm has already been finalized and cannot accept more input data.
HashCore(ReadOnlySpan<byte>)
Consumes the supplied input span and updates the algorithm state. Derived classes implement the buffering loop appropriate to their family (immediate-fire-on-full-block for Merkle–Damgård hashes, defer-on-full-block for Blake-family hashes).
protected override abstract void HashCore(ReadOnlySpan<byte> source)
Parameters
sourceReadOnlySpan<byte>The input bytes to consume. May be empty, partial, exact-block, or multi-block in length.
Remarks
This overload is re-marked abstract by the grandparent to force every derived base to provide an explicit
implementation. Without this, the default HashCore(ReadOnlySpan<byte>)
implementation would allocate a temporary byte array and call back into
HashCore(byte[], int, int), producing infinite recursion through the grandparent's forwarding
override.
Initialize()
Resets the algorithm to its initial state by clearing the residual buffer and the running byte total. Derived
classes override this method, call base.Initialize() first, and then reset their own algorithm-specific
state (chaining variables, IV, key-derived schedule).
public override void Initialize()
Remarks
This method does not reset the State property explicitly on .NET 6+ targets —
the framework manages that transition. On earlier targets, derived classes that need the already-finalized guard
should reset their _finalized backing field from their own Initialize override.
Derived classes that need to validate state before the reset (for example, a keyed MAC that refuses to be
re-initialized when no key has been set) should perform that validation before calling base.Initialize().
Once the base call returns, the residual buffer is empty, Bodu.Security.Cryptography.BufferedBlockHashAlgorithm._residualBytes is 0, and
Bodu.Security.Cryptography.BufferedBlockHashAlgorithm._totalBytes is 0.
Exceptions
- ObjectDisposedException
The instance has been disposed.
ThrowIfDisposed()
Throws an ObjectDisposedException if the algorithm instance has been disposed.
protected void ThrowIfDisposed()
Exceptions
- ObjectDisposedException
Thrown when any public method or property is accessed after the instance has been disposed.
ThrowIfInvalidState()
Throws if the algorithm has begun processing and can no longer be reconfigured.
protected void ThrowIfInvalidState()
Exceptions
- CryptographicUnexpectedOperationException
Thrown if an attempt is made to change configuration after the algorithm has started.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |