Table of Contents

Skein Class

Definition

Namespace
Bodu.Security.Cryptography
Assembly
Bodu.Security.Cryptography.dll
Package
Bodu.Security.Cryptography 1.2.0
Source
Skein.Ubi.cs

Serves as the abstract base class for managed implementations of the Skein family of cryptographic hash functions, built by Bruce Schneier and co-authors on top of the ThreefishBlockCipher tweakable block cipher and submitted as a finalist to the NIST SHA-3 competition.

public abstract class Skein : KeyedBlockHashAlgorithm, ICryptoTransform, IDisposable
Inheritance
Skein
Implements
Derived
Inherited Members
Extension Methods

Remarks

Skein hashes a message by repeatedly applying the UBI (Unique Block Iteration) mode of operation. Each UBI call feeds the current chaining value and the next message block into Encrypt(ReadOnlySpan<byte>, Span<byte>) under a tweak that identifies the block's role (configuration, optional key, message, output) together with its position and its first / final flags. The new chaining value is the encryption output XORed with the block, giving the classic Matyas-Meyer-Oseas construction.

The base inherits from KeyedBlockHashAlgorithm so that the keyed Skein-MAC mode integrates with the shared keyed-hash test infrastructure. Unlike strict keyed-MAC algorithms such as SipHash , Skein accepts a variable-length optional key: an empty Key selects the canonical plain-hash profile (no KEY UBI phase), while any non-empty byte sequence enables Skein-MAC with a preliminary KEY UBI phase.

Three fixed state sizes are supported, each implemented by a sealed derived class that wires up the corresponding Threefish variant:

Only the sequential hashing profile of Skein is implemented. Tree hashing, personalization strings, public-key or key-derivation identifiers, and nonce modes are not exposed; the corresponding Skein tweak types are reserved for potential future extension (see Bodu.Security.Cryptography.SkeinTweakType).

When to choose Skein. Pick the Skein family for interop with code that has standardized on it (the SHA-3 finalist round attracted a long tail of adopters, and Skein remains common in research code). Skein-512 is the recommended default; Skein-256 is the narrower variant and Skein-1024 the widest. For new general-purpose cryptographic hashing without an interop requirement Blake2b is faster on commodity 64-bit hardware and SHA-2 / SHA-3 are more widely deployed. The Threefish primitive itself is also available standalone via Threefish.

Fields

MaxKeySize

Maximum accepted length for Key across every Skein variant is 8192 bits (1024 bytes). Keys longer than this bound are rejected to prevent unbounded memory usage; this value is far above any practical MAC key.

public const int MaxKeySize = 8192

Field Value

int

Properties

AlgorithmName

Gets the fully qualified algorithm name, including the state size and the configured output size.

public override string AlgorithmName { get; }

Property Value

string

A string of the form "Skein-s-h" - e.g. "Skein-512-256".

Exceptions

ObjectDisposedException

The instance has been disposed.

Key

Gets or sets the secret key used to switch Skein into its keyed Skein-MAC mode.

public override byte[] Key { get; set; }

Property Value

byte[]

A byte array holding the key material. An empty array - the default - produces a plain, unkeyed hash; a non-empty array triggers a preliminary KEY UBI phase whenever the algorithm is initialized. Both the getter and the setter operate on defensive copies so external callers cannot mutate the internal key.

Remarks

Unlike SipHash, Skein does not require a fixed key length: any byte sequence from zero up to MaxKeySize / 8 bytes is valid. Setting the key clears any cached initial chaining value so the next call to Initialize() rebuilds the state from the UBI pipeline KEY → CFG.

Exceptions

ObjectDisposedException

The instance has been disposed.

ArgumentNullException

The assigned value is null.

CryptographicException

The assigned key is longer than MaxKeySize / 8 bytes.

CryptographicUnexpectedOperationException

A hash computation has already started and the key may not be reassigned while the algorithm is in use.

Methods

Dispose(bool)

Releases the unmanaged resources used by the algorithm, securely clears all intermediate state, and disposes the underlying Threefish cipher.

protected override void Dispose(bool disposing)

Parameters

disposing bool

true to release both managed and unmanaged resources; false to release only unmanaged resources.

HashCore(byte[], int, int)

Validates the supplied byte-array slice and forwards it to the HashCore(ReadOnlySpan<byte>) overload that derived classes implement.

protected override void HashCore(byte[] array, int ibStart, int cbSize)

Parameters

array byte[]

The input byte array containing the data to hash.

ibStart int

The zero-based index in array at which to begin reading data.

cbSize int

The number of bytes to process from array.

Exceptions

ArgumentNullException

array is null.

ArgumentOutOfRangeException

ibStart is less than zero.

-or-

cbSize is less than zero.

ArgumentException

ibStart and cbSize specify a range that exceeds the length of array.

ObjectDisposedException

The algorithm instance has been disposed.

CryptographicUnexpectedOperationException

On target frameworks prior to .NET 6, the hash algorithm has already been finalized and cannot accept more input data.

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 Skein computation by flushing the residual message block and running the output UBI chain to produce the digest.

protected override byte[] HashFinal()

Returns

byte[]

A byte array containing the computed hash, of length HashSize / 8.

Exceptions

ObjectDisposedException

The instance has been disposed.

Initialize()

Resets the algorithm to its initial state, recomputing the chaining value from the configuration block (and the key, if one has been supplied) so that a fresh hash or MAC may be computed.

public override void Initialize()

Exceptions

ObjectDisposedException

The instance has been disposed.

CryptographicException

The internal key storage has been cleared (set to null) - the key must be reassigned before the instance can be reused.

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

Satisfies the PadBlock(ReadOnlySpan<byte>, ulong) contract, but is not used by the Skein implementation.

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

Parameters

block ReadOnlySpan<byte>

The final partial block supplied by the base pipeline. Skein does not consume this value here because final block processing is performed by the UBI chaining path.

messageLength ulong

The total message length supplied by the base pipeline. Skein does not consume this value here because UBI encodes position and final-block state in the tweak field.

destination Span<byte>

The span receiving the padded block or blocks; at least two blocks long.

Returns

int

This method never returns because Skein bypasses the base padding pipeline.

Exceptions

InvalidOperationException

Always thrown because Skein performs finalization through UBI rather than PadBlock(ReadOnlySpan<byte>, ulong).

ProcessBlock(ReadOnlySpan<byte>)

Pipeline contract marker - see the section comment above. Skein's UBI lookahead bypasses ProcessBlock entirely; this override exists only to fail loudly if the inherited Merkle-Damgård pipeline is ever wired up against a Skein instance.

protected override void ProcessBlock(ReadOnlySpan<byte> block)

Parameters

block ReadOnlySpan<byte>

Ignored.

Exceptions

InvalidOperationException

Always thrown - this method is not on the happy path.

ProcessFinalBlock()

Satisfies the base final-block processing contract, but is unreachable for Skein because hash finalization is performed by the OUTPUT UBI phase.

protected override byte[] ProcessFinalBlock()

Returns

byte[]

This method never returns because Skein bypasses the base final-block pipeline.

Exceptions

InvalidOperationException

Always thrown because Skein drives finalization from HashFinal() rather than ProcessFinalBlock().

Applies to

ProductVersions
.NET8, 10

See Also