Table of Contents

BufferedBlockHashAlgorithm Class

Definition

Namespace
Bodu.Security.Cryptography
Assembly
Bodu.Security.Cryptography.dll
Package
Bodu.Security.Cryptography 1.2.0
Source
BufferedBlockHashAlgorithm.cs

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

blockSize int

The 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 blockSize is 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

int

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

bool

true once disposal has begun; otherwise false.

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

disposing bool

true 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

array byte[]

The input byte array containing the data to hash.

ibStart int

The zero-based index in array at which to begin reading data.

cbSize int

The number of bytes to process from array.

Exceptions

ArgumentNullException

array is null.

ArgumentOutOfRangeException

ibStart is less than zero.

-or-

cbSize is less than zero.

ArgumentException

ibStart and cbSize specify a range that exceeds the length of array.

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

source ReadOnlySpan<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

ProductVersions
.NET8, 10