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
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
cipherIBlockCipherThe block cipher used to perform the underlying block encryption operations.
ivbyte[]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
cipherorivis null.- ArgumentException
ivlength 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
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 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
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 |