← Back to projects
.NET Library Open Source

KZ.FileHash Asynchronous hashing for files and streams.

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.

A focused library for file and stream hashing.

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.

Language C#
Runtime .NET 8 / 9 / 10
Distribution NuGet
License MIT

Hashing is straightforward. Efficient hashing requires more consideration.

01

Memory usage

Loading an entire file into memory before hashing is unnecessary for large inputs and can create avoidable memory pressure.

02

Repeated I/O

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.

03

Long-running operations

Hashing large files can take time. Applications may need progress reporting and cancellation instead of treating the operation as an opaque synchronous call.

A small API. Deliberate implementation choices.

01

Asynchronous I/O

Hashing APIs use asynchronous operations for file and stream processing, making them suitable for modern .NET applications and longer-running workloads.

02

Single-read Multi-hashing

Multiple hashing algorithms can process the same input during a single read operation instead of repeatedly reading the source data.

03

Streaming

Files and streams are processed incrementally without loading the complete input into memory, including support for non-seekable streams.

04

Pooled Memory

Internal buffering uses ArrayPool<byte> to reduce unnecessary allocations during repeated data-processing operations.

05

Cancellation & Progress

Consumers can observe hashing progress and cancel operations that are no longer required.

06

Incremental Hashing

IncrementalHash is used for streaming hash calculation, with a dedicated IncrementalHashEngine for processing data chunks directly.

Designed around streaming and controlled resource usage.

Incremental stream processing

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.

Multiple algorithms in one pass

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.

Pooled buffering

The library uses ArrayPool<byte> for internal buffering to reduce allocations. The default buffer size is 64 KB and can be customized when required.

Reusable incremental hashing

IncrementalHashEngine supports calculating hashes from data chunks using ReadOnlySpan<byte> and can be reused after retrieving and resetting hash results.

usage.cs
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]
);

Calculate multiple hashes during a single read.

One input, multiple algorithms

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.

multiple-hashes.cs
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]
);

Built with a focused .NET stack.

Language
C#
Runtime
.NET 8 .NET 9 .NET 10
Core APIs
Streams Async/Await CancellationToken IncrementalHash ArrayPool
Hashing
MD5 SHA-1 SHA-256 SHA-384 SHA-512 SHA3-256 SHA3-384 SHA3-512
Tooling
NuGet BenchmarkDotNet GitHub Actions

Small implementation details that matter at scale.

01

64 KB default buffer

The default internal buffer is 64 KB and can be customized for different environments and workloads.

02

Non-seekable streams

Hashing does not require every input stream to support seeking, making the API suitable for forward-only streaming sources.

03

Raw or hexadecimal results

Hash results can be retrieved as hexadecimal strings or raw byte arrays depending on the consuming application's needs.

04

Configurable buffering

Applications can provide a custom buffer size instead of being restricted to the default configuration.

05

Reusable incremental engine

IncrementalHashEngine can be reused after retrieving and resetting hash results.

06

Performance monitoring

The project includes BenchmarkDotNet benchmarks and GitHub Actions for continuously monitoring execution performance and memory allocations.

Standard algorithms for compatibility and modern applications.

Legacy / Compatibility
MD5 SHA-1
SHA-2
SHA-256 SHA-384 SHA-512
SHA-3
SHA3-256 SHA3-384 SHA3-512

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.

What this project actually demonstrates.

01

Resource awareness

Data-processing APIs should account for memory, allocations, I/O, and execution characteristics instead of assuming that inputs are always small.

02

Avoid redundant I/O

When several algorithms operate on the same input, calculating them during one read can avoid unnecessary repeated reads of the source data.

03

Cancellation is part of the API

Long-running operations should give consuming applications a clear way to stop work that is no longer required.

04

Keep libraries focused

A reusable library becomes easier to integrate when its responsibilities remain narrow and explicit.

Have a backend problem worth solving?

I work on backend systems, APIs, SQL Server, ERP software, and performance-focused engineering problems.

Let’s talk