Table of Contents

BlockHashAlgorithm Class

Definition

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

Base class for hash algorithms that consume input in fixed-size blocks and pad the final partial block before processing it (the Merkle–Damgård shape). Handles block alignment and final-block padding orchestration on behalf of derived implementations; the residual buffer, running byte total, and disposal latch are inherited from BufferedBlockHashAlgorithm.

public abstract class BlockHashAlgorithm : BufferedBlockHashAlgorithm, ICryptoTransform, IDisposable
Inheritance
BlockHashAlgorithm
Implements
Derived
Inherited Members
Extension Methods

Examples

// Consume through a concrete derivative - the base class drives buffering and finalization.
using HashAlgorithm hash = new Tiger();      // 512-bit block, 192-bit digest
byte[] digest = hash.ComputeHash("hello"u8.ToArray());

// Or feed input incrementally via the standard streaming surface.
using HashAlgorithm streaming = new Tiger();
streaming.TransformBlock(buffer1, 0, buffer1.Length, null, 0);
streaming.TransformBlock(buffer2, 0, buffer2.Length, null, 0);
streaming.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
byte[] result = streaming.Hash!;

Remarks

Input data is accumulated into the inherited residual buffer until a complete block of BlockSize is available, at which point it is passed to ProcessBlock(ReadOnlySpan<byte>). Any residual bytes left over at HashFinal() are padded via PadBlock(ReadOnlySpan<byte>, ulong, Span<byte>) before a final call to ProcessFinalBlock() produces the digest.

Derived classes must implement the following:

Derived classes must also expose a public parameterless constructor to satisfy the base class's new() constraint.

When to derive from this class. Pick BlockHashAlgorithm for any classic Merkle-Damgård cryptographic hash - the family includes the SHA-2 hashes, Tiger, Whirlpool, Snefru, and similar designs that finalize by appending a length-encoding pad to the last partial block. For the BLAKE-family pattern (final-block flag, no length-encoding pad) derive from DeferredFinalBlockHashAlgorithm instead. For a keyed Merkle-Damgård hash (Poly1305, SipHash) derive from KeyedBlockHashAlgorithm, which adds key handling on top of this base. For non-cryptographic block hashes (Fletcher, CRC) the parallel BlockNonCryptographicHashAlgorithm<T> base in Bodu.IO.Hashing is the right pick - it integrates with NonCryptographicHashAlgorithm rather than HashAlgorithm.

Constructors

BlockHashAlgorithm(int)

Initializes a new instance of the BlockHashAlgorithm class using the specified input block size.

protected BlockHashAlgorithm(int blockSize)

Parameters

blockSize int

The block size, in bits, that the algorithm uses to process input data. Must be a positive multiple of 8. This value determines how data is buffered and segmented during hashing operations; the equivalent byte length is available via the inherited BlockSize field.

Remarks

The specified blockSize defines the size of each complete block passed to the ProcessBlock(ReadOnlySpan<byte>) method during hashing. Any input data not aligned to this size is temporarily stored in a residual buffer until enough bytes are accumulated for a full block.

This constructor delegates to BufferedBlockHashAlgorithm, which allocates the residual buffer used to accumulate and align partial input segments across multiple calls to TransformBlock(byte[], int, int, byte[], int) and TransformFinalBlock(byte[], int, int).

The specified block size must match the expectations of the underlying algorithm implementation. For example, a SHA-like construction may expect 64 or 128 bytes per block.

Exceptions

ArgumentOutOfRangeException

Thrown if blockSize is less than or equal to zero.

Properties

AllowUnalignedFinalBlock

Gets a value indicating whether the final padded block must be sliced into aligned blocks, or whether the full padded result may be passed as a single block (e.g., Poly1305-style).

protected virtual bool AllowUnalignedFinalBlock { get; }

Property Value

bool

Methods

HashCore(ReadOnlySpan<byte>)

Processes the entirety of the input source and feeds it into the computation pipeline. This method updates the internal hash state accordingly by consuming the entire input span.

protected override void HashCore(ReadOnlySpan<byte> source)

Parameters

source ReadOnlySpan<byte>

The input byte span containing the data to hash.

Remarks

This method is part of the core hashing process and is automatically invoked by methods such as TransformBlock(byte[], int, int, byte[], int) and ComputeHash(byte[]). It handles processing of raw byte array input and ensures the hash algorithm receives data in properly sized blocks.

This method internally buffers incomplete blocks between calls to ensure proper alignment. Full blocks are immediately processed; any remaining bytes are stored until more data arrives or finalization occurs.

Exceptions

CryptographicUnexpectedOperationException

The hash algorithm has already been finalized and cannot accept more input data.

HashFinal()

Finalizes the hash computation by padding and processing any residual data, and returns the resulting digest.

protected override byte[] HashFinal()

Returns

byte[]

A byte array containing the final computed hash value.

Exceptions

ObjectDisposedException

The algorithm instance has been disposed.

CryptographicUnexpectedOperationException

On target frameworks prior to .NET 6, the hash computation has already been finalized.

PadBlock(ReadOnlySpan<byte>, ulong)

Pads the final partial block of input data and appends the encoded total message length. This ensures that all input is padded and aligned to the block size required by the algorithm, often with trailing zeroes and encoded length information.

protected virtual byte[] PadBlock(ReadOnlySpan<byte> block, ulong messageLength)

Parameters

block ReadOnlySpan<byte>

The final block of unprocessed input, typically containing 0 to BlockSize-1 bytes.

messageLength ulong

The total number of message bytes consumed by the algorithm, including the bytes in block. This is the value most Merkle-Damgård length encodings append.

Returns

byte[]

A padded byte array consisting of one or more full blocks that include the input data and message length encoding, ready to be passed to ProcessBlock(ReadOnlySpan<byte>).

Remarks

The returned array must be aligned to the algorithm’s block size. Padding schemes often include a leading '1' bit, followed by zero bytes, and end with a length field (e.g., as in Merkle-Damgård construction).

This overload and the span-writing PadBlock(ReadOnlySpan<byte>, ulong, Span<byte>) overload default to delegating to each other, so a derived class must override exactly one of them - preferably the span-writing form, which avoids a heap allocation per finalization.

PadBlock(ReadOnlySpan<byte>, ulong, Span<byte>)

Pads the final partial block of input data into destination and appends the encoded total message length, without allocating a padded copy on the heap.

protected virtual int PadBlock(ReadOnlySpan<byte> block, ulong messageLength, Span<byte> destination)

Parameters

block ReadOnlySpan<byte>

The final block of unprocessed input, typically containing 0 to BlockSize-1 bytes.

messageLength ulong

The total number of message bytes consumed by the algorithm, including the bytes in block. This is the value most Merkle-Damgård length encodings append.

destination Span<byte>

The span receiving the padded block or blocks; at least two blocks (2 × BlockSize / 8 bytes) long. The caller clears the span after processing.

Returns

int

The number of bytes written - one or two whole blocks, ready for ProcessBlock(ReadOnlySpan<byte>).

Remarks

The default implementation delegates to the array-returning PadBlock(ReadOnlySpan<byte>, ulong) overload and clears the intermediate array; see that overload's remarks for the override contract.

ProcessBlock(ReadOnlySpan<byte>)

Transforms a complete block of input data and updates the internal hash state.

protected abstract void ProcessBlock(ReadOnlySpan<byte> block)

Parameters

block ReadOnlySpan<byte>

The input block to process. Its length must match the algorithm's configured block size.

Remarks

This method performs the core transformation logic of the hash algorithm. It is called repeatedly with aligned input blocks and is not responsible for padding or finalization steps.

Exceptions

ArgumentException

Thrown if the block is not the expected size.

ProcessFinalBlock()

Finalizes the hash computation and produces the final hash output.

protected abstract byte[] ProcessFinalBlock()

Returns

byte[]

A byte array containing the final computed hash value.

Remarks

This method is invoked after all input has been processed and padded. It reads from the internal hash state and serializes the result to a byte array in the format expected by consumers of the algorithm (e.g., big-endian or little-endian).

ShouldPadFinalBlock()

Determines whether the final block of input data should be padded before processing.

protected virtual bool ShouldPadFinalBlock()

Returns

bool

true if the final block should be padded; otherwise, false.

Remarks

This method is used to decide whether padding is required for the final block of input data. Derived classes can override this method to implement their own logic for padding behavior. By default, this method returns true, indicating that padding is required.

Applies to

ProductVersions
.NET8, 10

See Also