SivModeTransform Class
Definition
- Namespace
- Bodu.Security.Cryptography
- Assembly
- Bodu.Security.Cryptography.dll
- Package
- Bodu.Security.Cryptography 1.2.0
- Source
- SivModeTransform.cs
Applies Synthetic Initialization Vector (SIV) mode to two underlying IBlockCipher instances, providing deterministic authenticated encryption per RFC 5297 (AES-SIV).
public sealed class SivModeTransform : IAeadBlockCipherModeTransform, IAeadTransform, IDisposable
- Inheritance
-
SivModeTransform
- Implements
- Inherited Members
- Extension Methods
Examples
using System.Security.Cryptography;
using Bodu.Security.Cryptography;
using Bodu.Security.Cryptography.Extensions;
// SIV uses a doubled key: first half drives the MAC, second half drives CTR encryption.
using IBlockCipher s2v = new AesBlockCipher(macKey);
using IBlockCipher ctr = new AesBlockCipher(encKey);
byte[] iv = new byte[s2v.BlockSize / 8]; // ignored by SIV - present for interface compatibility
using IAeadBlockCipherModeTransform siv = new SivModeTransform(s2v, ctr, iv);
byte[] sealed_ = siv.Encrypt(plaintext, associatedData: header);
Remarks
SIV inverts the order shown in the generic AEAD diagram: the bottom pipeline runs first - S2V/CMAC over the associated data and plaintext produces the synthetic IV, which is both the tag and the CTR counter base - and only then does the top pipeline encrypt the plaintext under that derived counter. That reversal is what makes SIV misuse-resistant: re-encrypting the same message yields the same ciphertext, but confidentiality is not lost beyond confirming message equality.
SIV requires two independent ciphers keyed with different material:
s2vCipher(K₁) - used by CMAC and S2V to derive the synthetic IV.ctrCipher(K₂) - used by AES-CTR to encrypt the plaintext.
The S2V algorithm (RFC 5297 Section 2.4) accumulates all associated data blocks and the plaintext into a single 128-bit tag using CMAC:
D ← CMAC(K₁, 0^128)
for each AD block Sᵢ (i < n): D ← dbl(D) ⊕ CMAC(K₁, Sᵢ)
if |Sₙ| ≥ 128: T ← CMAC(K₁, xorend(Sₙ, D))
else: T ← CMAC(K₁, dbl(D) ⊕ pad(Sₙ))
SIV ← T
Ciphertext is output as C || SIV (ciphertext then tag), consistent with the
IAeadBlockCipherModeTransform convention.
When to use SIV. Pick AES-SIV when deterministic authenticated encryption is wanted - key wrapping
(RFC 5297 §6 / RFC 5649), envelope encryption schemes that need stable ciphertext for deduplication, or any context
that cannot maintain a per-message nonce. SIV is two-pass and slower than GcmModeTransform on
commodity hardware, but it has the strongest misuse-resistance profile in this library: re-encrypting the same
(plaintext, AAD) tuple produces the same ciphertext, but distinct messages remain confidential and authentic.
GcmSivModeTransform is the RFC 8452 alternative - same misuse-resistance category, different MAC
(POLYVAL) and key schedule, typically faster on AES-NI/PCLMULQDQ hardware.
Constructors
SivModeTransform(IBlockCipher, IBlockCipher, byte[])
Initializes a new instance of the SivModeTransform class.
public SivModeTransform(IBlockCipher s2vCipher, IBlockCipher ctrCipher, byte[] iv)
Parameters
s2vCipherIBlockCipherThe cipher keyed with K₁, used for CMAC and S2V computation.
ctrCipherIBlockCipherThe cipher keyed with K₂, used for CTR encryption.
ivbyte[]Accepted for interface compatibility; not used by SIV because the synthetic IV is derived from the data.
Exceptions
- ArgumentNullException
s2vCipher,ctrCipher, orivis null.- ArgumentException
Either cipher does not have a 16-byte block size, or
ivlength does not equal the S2V cipher block size.
Properties
TagSize
Gets the authentication-tag size, in bits.
public int TagSize { get; }
Property Value
- int
The authentication-tag size, in bits.
Methods
Decrypt(ReadOnlySpan<byte>, Span<byte>)
Decrypts ciphertextWithTag and verifies the authentication tag.
public int Decrypt(ReadOnlySpan<byte> ciphertextWithTag, Span<byte> output)
Parameters
ciphertextWithTagReadOnlySpan<byte>The ciphertext followed immediately by the TagSize / 8 byte authentication tag. Must be at least TagSize / 8 bytes long.
outputSpan<byte>Receives the decrypted plaintext. Must be at least
ciphertextWithTag.Length - (TagSize / 8)bytes long.
Returns
- int
Bytes written:
ciphertextWithTag.Length - (TagSize / 8).
Remarks
Authentication failure contract. All implementations honour the same observable guarantee on tag mismatch: CryptographicException is thrown and no plaintext is released to the caller. Implementations achieve this in one of two ways:
-
Verify-before-release. The tag is compared in constant time before any plaintext byte is written to
output. Used by GCM, CCM, EAX, and OCB. -
Write-then-clear. The candidate plaintext is streamed into
outputfirst because the algorithm's structure requires the transform to complete before the tag can be computed. The tag is then compared in constant time; on mismatchoutputis zeroed via ZeroMemory(Span<byte>) before the exception is thrown. Used by Ascon-AEAD-128 and GCM-SIV.
In both cases the API is strictly one-shot: a failed decryption invalidates the instance, and subsequent calls throw InvalidOperationException. Construct a fresh instance per message.
Exceptions
- CryptographicException
The authentication tag did not match.
- ArgumentException
ciphertextWithTagis shorter than TagSize / 8 bytes, oroutputis too small.- InvalidOperationException
The instance has already encrypted or decrypted a message, including after a previous tag-mismatch failure. AEAD transforms are single-use per message - construct a fresh instance.
Dispose()
Releases the resources used by this instance and clears retained associated-data state from memory.
public void Dispose()
Remarks
The supplied IBlockCipher instances are not disposed by this type. Ownership remains with the caller.
Encrypt(ReadOnlySpan<byte>, Span<byte>)
Encrypts plaintext and appends the authentication tag to output.
public int Encrypt(ReadOnlySpan<byte> plaintext, Span<byte> output)
Parameters
plaintextReadOnlySpan<byte>The data to encrypt.
outputSpan<byte>Receives the ciphertext followed immediately by the TagSize / 8 byte tag. Must be at least
plaintext.Length + (TagSize / 8)bytes long.
Returns
- int
Total bytes written:
plaintext.Length + (TagSize / 8).
Exceptions
- ArgumentException
outputis too small.- InvalidOperationException
The instance has already encrypted or decrypted a message. AEAD transforms are single-use per message - construct a fresh instance.
ProcessAssociatedData(ReadOnlySpan<byte>)
Processes associated data (AAD) that will be authenticated but not encrypted. Must be called before Encrypt(ReadOnlySpan<byte>, Span<byte>) or Decrypt(ReadOnlySpan<byte>, Span<byte>).
public void ProcessAssociatedData(ReadOnlySpan<byte> associatedData)
Parameters
associatedDataReadOnlySpan<byte>The bytes to authenticate. May be empty to indicate no associated data.
Exceptions
- InvalidOperationException
Associated data has already been processed on this instance, or the instance has already completed an Encrypt(ReadOnlySpan<byte>, Span<byte>) or Decrypt(ReadOnlySpan<byte>, Span<byte>) operation.
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |