Table of Contents

EaxModeTransform Class

Definition

Namespace
Bodu.Security.Cryptography
Assembly
Bodu.Security.Cryptography.dll
Package
Bodu.Security.Cryptography 1.2.0
Source
EaxModeTransform.cs

Applies EAX mode to an underlying IBlockCipher, providing two-pass authenticated encryption with associated data (AEAD) per Bellare, Rogaway and Wagner (FSE 2004).

public sealed class EaxModeTransform : IAeadBlockCipherModeTransform, IAeadTransform, IDisposable
Inheritance
EaxModeTransform
Implements
Inherited Members
Extension Methods

Examples

using System.Security.Cryptography;
using Bodu.Security.Cryptography;
using Bodu.Security.Cryptography.Extensions;

using IBlockCipher cipher = new AesBlockCipher(key);
byte[] nonce = RandomNumberGenerator.GetBytes(cipher.BlockSize / 8); // unique per message
using IAeadBlockCipherModeTransform eax = new EaxModeTransform(cipher, nonce);
byte[] sealed_ = eax.Encrypt(plaintext, associatedData: header);
using IAeadBlockCipherModeTransform dec = new EaxModeTransform(cipher, nonce);
byte[] recovered = dec.Decrypt(sealed_, associatedData: header);

Remarks

Generic AEAD data flow - EAX instantiates the top pipeline as CTR mode and the bottom pipeline as three OMAC invocations over the nonce, associated data, and ciphertext whose outputs are XOR-combined to form the tag.

EAX is the CTR + OMAC(N ‖ A ‖ C) instantiation of the generic AEAD shape above. Three independent OMAC invocations are performed with a single-byte tweak t ∈ {0, 1, 2} selecting the input kind:

  • N' = OMAC_K^0(nonce) - authenticates the nonce and seeds the CTR counter.
  • H' = OMAC_K^1(associatedData) - authenticates the AAD.
  • C' = OMAC_K^2(ciphertext) - authenticates the ciphertext.

The authentication tag is T = N' ⊕ H' ⊕ C', and the keystream is generated by encrypting successive big-endian increments of N' with the underlying block cipher.

OMAC_K^t(M) is defined as CMAC_K([t]_n ‖ M), where [t]_n is the integer t encoded as a full BlockSize-byte big-endian block. All three invocations therefore share the same CMAC subkeys K₁ = dbl(E(0ⁿ)) and K₂ = dbl(K₁), derived from the cipher once per instance.

The tag size is fixed at 16 bytes (the full OMAC output). The IV is the raw nonce: the class computes N' internally. Ciphertext is output as C ‖ T (ciphertext then tag), consistent with the IAeadBlockCipherModeTransform convention.

When to use EAX. Pick EAX when an unencumbered, two-pass AEAD with a flexible nonce length (the OMAC-derived N' means EAX accepts nonces up to the cipher block size) is wanted - some embedded protocols and historical industry standards require it. EAX is roughly half the throughput of GcmModeTransform on commodity hardware but does not depend on Galois-field arithmetic and has no patent concerns. For new general-purpose AEAD prefer GCM; for nonce-misuse resistance prefer GcmSivModeTransform or SivModeTransform; for single-pass AEAD without GCM's catastrophic-on-reuse profile prefer OcbModeTransform.

Nonce uniqueness is required. EAX is not nonce-misuse resistant. Two messages encrypted under the same (key, nonce) share the same N' seed, so they share the same CTR keystream and an attacker can recover P1 XOR P2; the per-message OMAC tag inputs also overlap, weakening authentication. Callers must guarantee that every (key, nonce) pair is used at most once - either via a deterministic per-message counter or a fresh random nonce drawn from a CSPRNG. If nonce uniqueness cannot be guaranteed, prefer GcmSivModeTransform or SivModeTransform.

Constructors

EaxModeTransform(IBlockCipher, byte[])

Initializes a new instance of the EaxModeTransform class.

public EaxModeTransform(IBlockCipher cipher, byte[] iv)

Parameters

cipher IBlockCipher

The block cipher used for both OMAC and the CTR keystream.

iv byte[]

The nonce N. Must equal the cipher block size. A defensive copy is taken; the caller's array is not modified.

Exceptions

ArgumentNullException

cipher or iv is null.

ArgumentException

iv length does not equal the 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

ciphertextWithTag ReadOnlySpan<byte>

The ciphertext followed immediately by the TagSize / 8 byte authentication tag. Must be at least TagSize / 8 bytes long.

output Span<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 output first 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 mismatch output is 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

ciphertextWithTag is shorter than TagSize / 8 bytes, or output is 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 nonce and associated-data state from memory.

public void Dispose()

Remarks

The supplied IBlockCipher is 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

plaintext ReadOnlySpan<byte>

The data to encrypt.

output Span<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

output is 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

associatedData ReadOnlySpan<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

ProductVersions
.NET8, 10

See Also