jaytwo.HashSiphon 0.1.0-beta-20250915083103

This is a prerelease version of jaytwo.HashSiphon.
dotnet add package jaytwo.HashSiphon --version 0.1.0-beta-20250915083103
                    
NuGet\Install-Package jaytwo.HashSiphon -Version 0.1.0-beta-20250915083103
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="jaytwo.HashSiphon" Version="0.1.0-beta-20250915083103" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="jaytwo.HashSiphon" Version="0.1.0-beta-20250915083103" />
                    
Directory.Packages.props
<PackageReference Include="jaytwo.HashSiphon" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add jaytwo.HashSiphon --version 0.1.0-beta-20250915083103
                    
#r "nuget: jaytwo.HashSiphon, 0.1.0-beta-20250915083103"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package jaytwo.HashSiphon@0.1.0-beta-20250915083103
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=jaytwo.HashSiphon&version=0.1.0-beta-20250915083103&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=jaytwo.HashSiphon&version=0.1.0-beta-20250915083103&prerelease
                    
Install as a Cake Tool

jaytwo.HashSiphon

NuGet Version NuGet Downloads License: MIT

jaytwo.HashSiphon is a .NET stream wrapper that computes a hash (SHA256, SHA1, MD5, or custom) while reading from or writing to a stream — without needing to buffer or read the stream twice.

View source on GitHub

Features

  • Hash streams in real time (read or write)
  • SHA256, SHA1, MD5, or custom algorithm support
  • Works with Stream APIs like CopyToAsync, WriteAsync, etc.
  • Async and cancellation token support
  • Does not buffer or re-read the stream
  • Hash available after stream is fully consumed

Background

Once or twice, I've accepted user uploads to an API which I then stream to an object store. Sometimes I want a hash of that file—whether for deduplication, verification, or future audit. Usually, however, the file isn't supplied with a hash up front.

This package provides a way to hash the content as it's being read from or written to the underlying stream.

Since we don't have the full hash until the stream is consumed (referring to the use case above), this doesn't allow us to set the Content-MD5 header (for example) before sending to the object store. It does, however, allow us to persist the final hash to a database or log it for tracking, all without reading the stream twice.

Installation

Add the NuGet package:

PM> Install-Package jaytwo.HashSiphon

Usage

Wrap the input stream with a HashSiphonStream, then read it as usual. The hash becomes available after the stream is fully consumed.

Examples

// Example: Hashing While Reading

using var input = File.OpenRead("myfile.txt");
using var hashStream = HashSiphonStream.CreateSHA256Read(input);

using var output = File.Create("copy.txt");
await hashStream.CopyToAsync(output);

// Final hash is now available
Console.WriteLine(hashStream.HashHex);
// Example: Hashing While Writing

using var output = File.Create("output.txt");
using var hashStream = HashSiphonStream.CreateSHA256Write(output);

var buffer = Encoding.UTF8.GetBytes("hello world");
await hashStream.WriteAsync(buffer, 0, buffer.Length);

// finalize the hash without disposing
await hashStream.FlushAsync(finalizeHash: true);

Console.WriteLine(hashStream.HashHex);

Factory Methods

Method Description
CreateSHA256Read() Creates a SHA256 stream in read mode
CreateSHA1Read() Creates a SHA1 stream in read mode
CreateMD5Read() Creates a MD5 stream in read mode
CreateSHA256Write() Creates a SHA256 stream in write mode
CreateSHA1Write() Creates a SHA1 stream in write mode
CreateMD5Write() Creates a MD5 stream in write mode
CreateRead() Custom algorithm, read mode
CreateWrite() Custom algorithm, write mode

Custom Algorithms

If you want to use a custom HashAlgorithm:

// I used this approach to write multiple generated XML documents into a ZIP package (which requires a CRC32 checksum for each entry) when streaming an XLSX file to a write-only output.

using (var hashSiphonStream = HashSiphonStream.CreateWrite(_outputStream, () => new Crc32Algorithm(isBigEndian: false), leaveOpen: true))
{
    await WriteXml(hashSiphon);
    await hashSiphonStream.FlushAsync(finalizeHash: true);
    crc32 = BitConverter.ToUInt32(hashSiphon.Hash);
}

All constructor overloads accept leaveOpen = true if you don't want the wrapped stream disposed when HashSiphonStream is disposed.

Notes

  • Hash computation is finalized automatically when a read stream hits EOF or when a write stream is flushed with finalizeHash = true or disposed.
  • Hash (and HashHex / HashBase64) will return null until the hash computation is finalized.
  • You can use any of the TryGetHash() variants to check for hash availability and retrieve the value in a single line. These are mostly useful for scenarios where you're uncertain whether the hash has been finalized yet (e.g., mid-stream inspection).
  • Supports DisposeAsync() on .NET 5+.
  • Seek and SetLength are not supported.

Made with ♥ by Jake — Licensed under the MIT License

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 is compatible.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.6.2

    • No dependencies.
  • .NETStandard 2.0

    • No dependencies.
  • net6.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-beta-20250915083103 266 9/15/2025
0.1.0-beta-20250512175120 284 5/12/2025
0.1.0-beta-20250509102925 111 5/9/2025
0.1.0-beta-20250505183914 183 5/6/2025
0.1.0-beta-20250502190539 97 5/3/2025