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:
- Skein256 - 256-bit state, 32-byte blocks, over Threefish256Cipher.
- Skein512 - 512-bit state, 64-byte blocks, over Threefish512Cipher.
- Skein1024 - 1024-bit state, 128-byte blocks, over Threefish1024Cipher.
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
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
KEYUBI 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
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
arraybyte[]The input byte array containing the data to hash.
ibStartintThe zero-based index in
arrayat which to begin reading data.cbSizeintThe number of bytes to process from
array.
Exceptions
- ArgumentNullException
arrayis null.- ArgumentOutOfRangeException
ibStartis less than zero.-or-
cbSizeis less than zero.- ArgumentException
ibStartandcbSizespecify a range that exceeds the length ofarray.- 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
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 Skein computation by flushing the residual message block and running the output UBI chain to produce the digest.
protected override byte[] HashFinal()
Returns
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
blockReadOnlySpan<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.
messageLengthulongThe 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.
destinationSpan<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
blockReadOnlySpan<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
| Product | Versions |
|---|---|
| .NET | 8, 10 |