Table of Contents

CcmModeTransform Class

Definition

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

Applies Counter with CBC-MAC (CCM) mode to an underlying IBlockCipher, providing authenticated encryption with associated data (AEAD) per NIST SP 800-38C.

public sealed class CcmModeTransform : IAeadBlockCipherModeTransform, IAeadTransform, IDisposable
Inheritance
CcmModeTransform
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[] iv = BuildCcmIv(nonce); // 12-byte nonce in the first 12 bytes of the IV
using IAeadBlockCipherModeTransform ccm = new CcmModeTransform(cipher, iv);
byte[] sealed_ = ccm.Encrypt(plaintext, associatedData: header);
using IAeadBlockCipherModeTransform dec = new CcmModeTransform(cipher, iv);
byte[] recovered = dec.Decrypt(sealed_, associatedData: header);

Remarks

Generic AEAD data flow - a CTR-style keystream produces ciphertext and a MAC over nonce, associated data, and ciphertext produces the tag. In CCM the MAC is CBC-MAC.

CCM is the CTR + CBC-MAC instantiation of the generic AEAD shape above: the top pipeline is the plain CTR keystream generator (panel labeled Keystream Generator (CTR)), and the bottom pipeline is a CBC-MAC chain over the formatted nonce, associated data, and ciphertext that produces the tag.

Fixed parameters (matching the most common deployment profile):

  • Nonce (Nlen): 12 bytes - first 12 bytes of the IV.
  • Length field (q): 3 bytes - messages up to 2^24 − 1 bytes.
  • Tag (T): 16 bytes.

Formatting follows NIST SP 800-38C Section 6.3. Flag byte B0: bit 6 = Adata, bits 5-3 = M' = (T−2)/2 = 7, bits 2-0 = L' = q−1 = 2. Counter block A_i: byte 0 = 0x02, bytes 1-12 = nonce, bytes 13-15 = counter (big-endian). AAD length is encoded as a 2-byte big-endian prefix (supports up to 65 279 bytes).

When to use CCM. Pick CCM when interoperability with constrained-environment standards is required - IEEE 802.15.4 / Zigbee, Bluetooth Mesh, IPsec ESP, and TLS 1.2 with the AES-CCM cipher suites all use it. CCM is two-pass over the message (CBC-MAC then CTR), so it is slower than GcmModeTransform on commodity hardware, but it has no Galois-field arithmetic and is easier to implement correctly on minimal microcontrollers. For new general-purpose AEAD on x86/ARM hosts prefer GCM; for nonce-misuse resistance prefer GcmSivModeTransform or SivModeTransform.

Nonce uniqueness is required. CCM is not nonce-misuse resistant. Reusing a (key, nonce) pair across two messages reuses the CTR keystream and lets an attacker XOR the two ciphertexts to recover P1 XOR P2; CBC-MAC chains from the same starting state are also exposed, which weakens authentication. Callers must guarantee that every (key, nonce) pair is used at most once - typically via a per-message counter or a fresh random 96-bit value drawn from a CSPRNG. If nonce uniqueness cannot be guaranteed prefer GcmSivModeTransform or SivModeTransform.

Constructors

CcmModeTransform(IBlockCipher, byte[])

Initializes a new instance of the CcmModeTransform class. The first 12 bytes of iv are used as the CCM nonce.

public CcmModeTransform(IBlockCipher cipher, byte[] iv)

Parameters

cipher IBlockCipher

The block cipher used to perform the underlying block encryption operations.

iv byte[]

The initialization vector from which the CCM nonce is derived. The value must be exactly one cipher block in length; only the first 12 bytes are copied and used as the nonce.

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