Asynchronous I/O
Hashing APIs use asynchronous operations for file and stream processing, making them suitable for modern .NET applications and longer-running workloads.
A focused .NET library for calculating cryptographic hashes from files and streams with asynchronous I/O, multiple algorithms in a single read operation, cancellation, progress reporting, and memory-efficient streaming.
KZ.FileHash provides a focused API for calculating cryptographic hashes from files and streams in modern .NET applications.
The library processes data incrementally instead of loading the entire file into memory. It uses buffered asynchronous I/O, pooled memory, and incremental hashing to keep memory usage controlled during file-processing operations.
Multiple hashing algorithms can be calculated during a single read operation, avoiding unnecessary repeated reads of the same data. The library also supports both seekable and non-seekable streams.
Hashing operations can optionally report progress and observe cancellation requests, while buffer size can be customized for different environments and workloads.
Loading an entire file into memory before hashing is unnecessary for large inputs and can create avoidable memory pressure.
Calculating several hashes independently can require reading the same data multiple times. A single-pass approach can calculate multiple algorithms while the data is already being read.
Hashing large files can take time. Applications may need progress reporting and cancellation instead of treating the operation as an opaque synchronous call.
Hashing APIs use asynchronous operations for file and stream processing, making them suitable for modern .NET applications and longer-running workloads.
Multiple hashing algorithms can process the same input during a single read operation instead of repeatedly reading the source data.
Files and streams are processed incrementally without loading the complete input into memory, including support for non-seekable streams.
Internal buffering uses ArrayPool<byte> to reduce unnecessary allocations during repeated data-processing operations.
Consumers can observe hashing progress and cancel operations that are no longer required.
IncrementalHash is used for streaming hash calculation, with a dedicated IncrementalHashEngine for processing data chunks directly.
Input data is processed in chunks rather than materializing the complete file in memory. The implementation uses buffered asynchronous I/O and incremental hash calculation.
FileHashEngine can be configured with multiple hashing algorithms using the flags-based HashAlgorithmType API. The selected algorithms are calculated while the source data is read once.
The library uses ArrayPool<byte> for internal buffering to reduce allocations. The default buffer size is 64 KB and can be customized when required.
IncrementalHashEngine supports calculating hashes from data chunks using ReadOnlySpan<byte> and can be reused after retrieving and resetting hash results.
using KZ.FileHash.Engine;
using KZ.FileHash.Enums;
var engine =
new FileHashEngine(
HashAlgorithmType.SHA256
);
var hashes =
await engine.CalculateHashAsync(
"example.zip"
);
Console.WriteLine(
hashes[HashAlgorithmType.SHA256]
);
KZ.FileHash supports combining hashing algorithms with the flags-based HashAlgorithmType API.
This allows applications to calculate several hashes from the same file without independently reading the source for each algorithm.
var engine =
new FileHashEngine(
HashAlgorithmType.MD5 |
HashAlgorithmType.SHA256 |
HashAlgorithmType.SHA512
);
var hashes =
await engine.CalculateHashAsync(
"example.zip"
);
Console.WriteLine(
hashes[HashAlgorithmType.MD5]
);
Console.WriteLine(
hashes[HashAlgorithmType.SHA256]
);
Console.WriteLine(
hashes[HashAlgorithmType.SHA512]
);
The default internal buffer is 64 KB and can be customized for different environments and workloads.
Hashing does not require every input stream to support seeking, making the API suitable for forward-only streaming sources.
Hash results can be retrieved as hexadecimal strings or raw byte arrays depending on the consuming application's needs.
Applications can provide a custom buffer size instead of being restricted to the default configuration.
IncrementalHashEngine can be reused after retrieving and resetting hash results.
The project includes BenchmarkDotNet benchmarks and GitHub Actions for continuously monitoring execution performance and memory allocations.
MD5 and SHA-1 are included primarily for compatibility and non-security-critical integrity checking. They should not be used for security-sensitive applications.
For modern security-sensitive applications, SHA-256, SHA-384, SHA-512, or SHA-3 variants are recommended.
Data-processing APIs should account for memory, allocations, I/O, and execution characteristics instead of assuming that inputs are always small.
When several algorithms operate on the same input, calculating them during one read can avoid unnecessary repeated reads of the source data.
Long-running operations should give consuming applications a clear way to stop work that is no longer required.
A reusable library becomes easier to integrate when its responsibilities remain narrow and explicit.
Read the implementation, documentation, benchmarks, tests, and project history on GitHub.
I work on backend systems, APIs, SQL Server, ERP software, and performance-focused engineering problems.
Let’s talk