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:
- ProcessBlock(ReadOnlySpan<byte>) processes a single complete block of input data.
- PadBlock(ReadOnlySpan<byte>, ulong, Span<byte>) (or the array-returning PadBlock(ReadOnlySpan<byte>, ulong)) pads the final input segment and encodes the total message length.
- ProcessFinalBlock() finalizes the hash computation and returns the resulting digest.
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
blockSizeintThe 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
blockSizeis 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
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
sourceReadOnlySpan<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
blockReadOnlySpan<byte>The final block of unprocessed input, typically containing 0 to BlockSize-1 bytes.
messageLengthulongThe 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
blockReadOnlySpan<byte>The final block of unprocessed input, typically containing 0 to BlockSize-1 bytes.
messageLengthulongThe 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.destinationSpan<byte>The span receiving the padded block or blocks; at least two blocks (
2 × BlockSize / 8bytes) 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
blockReadOnlySpan<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
blockis 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
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
| Product | Versions |
|---|---|
| .NET | 8, 10 |