Skip to main content

Module ccm

Module ccm 

Source
Expand description

AES-CCM AEAD (NIST SP 800-38C, RFC 3610).

CCM = Counter with CBC-MAC. It is the second AES AEAD shipped by arcana alongside AES-GCM, and the older of the two. CCM is the AEAD used by Bluetooth Low Energy, ZigBee, IPsec ESP-CCM, TLS 1.2 ciphersuites of the form *_CCM*, 802.15.4 mesh networks, and IETF protocols that need a small / portable AEAD with no GHASH dependency.

Compared to GCM:

  • Pro: only needs encrypt_block. Decryption never invokes AES decrypt – it XORs the same CTR keystream and recomputes the MAC over the plaintext. Smaller code, smaller embedded footprint, no GHASH state.
  • Pro: no soft-failure modes – the construction is a straightforward MAC-then-encrypt with explicit length fields.
  • Con: two-pass over the data (one for MAC, one for CTR), so it’s slower than GCM on hardware that has carry-less multiply.
  • Con: tag length and the unusual (N, L) parameter trade are easy to misconfigure – see the parameter validation below.

§Parameters

CCM is parameterised by (M, L) where:

  • M is the tag length in bytes. Allowed: {4, 6, 8, 10, 12, 14, 16}. Smaller M = faster but lower forgery resistance. Most protocols use M = 8 (Bluetooth, ZigBee) or M = 16 (TLS, ESP).

  • L is the length-of-length field in bytes. Allowed: {2, 3, 4, 5, 6, 7, 8}. The maximum payload length is 2^(8*L) - 1 bytes; the nonce length is 15 - L bytes. L = 2 gives a 13-byte nonce and a max payload of ~64 KB, which is the choice in RFC 3610 and almost every modern protocol that uses CCM. The convenience constructors below pin L = 2.

§Construction (NIST SP 800-38C / RFC 3610)

  1. Format the first MAC block B0:

     +-----+----------+----------+
     | flg | nonce N  | length Q |
     +-----+----------+----------+
       1B    15 - L      L

    where flg = (Adata << 6) | ((M-2)/2 << 3) | (L-1), Adata = 1 iff AAD is non-empty, and Q is the big-endian payload length encoded in L bytes.

  2. Format the AAD blocks: prepend length(AAD) encoded as 2 bytes (BE) for 0 < len < 2^16 - 2^8, or 6 bytes for the larger ranges (we only support the 2-byte form: caller AAD must fit in the canonical IETF range), then the AAD bytes, then zero-pad to a multiple of 16.

  3. Format the payload blocks: just the plaintext bytes, zero- padded to a multiple of 16.

  4. CBC-MAC all of the above (B0 || formatted_aad || formatted_payload) with AES under the key. The CBC-MAC output is the unencrypted tag T (taking the first M bytes of the final 16-byte CBC state).

  5. Counter blocks A_i: format

     +-----+----------+--------+
     | flg | nonce N  | i (BE) |
     +-----+----------+--------+
       1B    15 - L      L

    where flg = L - 1. S_i = AES_K(A_i) is the keystream block.

  6. Encrypt T by XOR with the first M bytes of S_0. The result is the on-the-wire tag.

  7. Encrypt the payload by XOR with S_1, S_2, ... (counter starts at 1).

Decryption reverses steps 6-7 to recover the plaintext, then recomputes T via steps 1-4 and compares in constant time.

Structs§

AesCcm
AES-CCM with the RFC 3610 default parameters: L = 2, so the nonce is 13 bytes and the maximum payload is 2^16 - 1 bytes. The tag length M is configurable per call.

Functions§

ccm_decrypt
AES-CCM decrypt with the generic (M, L) parameters.
ccm_encrypt
AES-CCM encrypt with the generic (M, L) parameters.