Skip to content

LibTomCrypt ccm_memory silently truncates nonces longer than 13 bytes #775

Description

@LLian7

Summary

LibTomCrypt ccm_memory accepts AES-CCM encryption when noncelen is 14 bytes. The calls return CRYPT_OK, although CCM permits nonce lengths only from 7 to 13 octets.

On the generic implementation path, nonce lengths greater than 13 are silently clamped to 13. Consequently, two 14-byte nonce values that share the same first 13 bytes but differ in the final byte produce the same ciphertext and authentication tag.

This report is intentionally narrow. It is about the remaining high-nonce case observed on current develop, reproduced locally on 2026-07-14 using the clean commit recorded below. It is not claiming that older invalid tag-length, short-nonce, or message-length-at-L=1 cases are still present.

Tested version

LibTomCrypt develop commit: a68fa19bc2b532f66a6f18ca457daec53054a312

This is the upstream develop commit checked on 2026-07-14. The local source tree used for the run had no uncommitted changes.

Minimal reproducer

A minimal standalone reproducer is attached:

  • repro.cpp
  • build.sh
  • run.sh

build.sh
repro.cpp
run.sh

It runs three cases:

valid_control:
  noncelen = 13
  expected = CRYPT_OK

invalid_high_nonce_a:
  noncelen = 14
  final nonce byte = 0x01
  expected = CRYPT_INVALID_ARG

invalid_high_nonce_b:
  noncelen = 14
  final nonce byte = 0x02
  expected = CRYPT_INVALID_ARG

The 13-byte control is exactly the common prefix of the two 14-byte nonce values. A conforming call should reject both 14-byte inputs before processing them. If the implementation instead clamps noncelen to 13, all three calls use the same effective nonce and produce identical ciphertext and authentication-tag outputs. The reproducer checks these comparisons explicitly and bounds-checks the returned tag length before comparing tag bytes.

An application that treats the complete 14-byte values as distinct may therefore unknowingly reuse the same effective CCM nonce.

The key, nonce, AAD, plaintext, and tag buffer are fixed test values. The reproducer does not use a fuzzing harness, adapter layer, private API, or undefined behavior.

Build and run

The checked repro can be built and run with:

export LIBTOMCRYPT_ROOT=/path/to/libtomcrypt-develop
./build.sh
./run.sh

build.sh accepts LIBTOMCRYPT_ROOT when a different local LibTomCrypt tree is needed and writes the temporary executable under ${TMPDIR:-/tmp}.
For the checked run, LIBTOMCRYPT_ROOT pointed to a clean checkout of a68fa19bc2b532f66a6f18ca457daec53054a312.

Observed behavior

Reproduced on LibTomCrypt current develop, checked locally on 2026-07-14.

Output from the attached reproducer:

case,nonce_len,return,error,expected
valid_control,13,0,CRYPT_OK,CRYPT_OK
invalid_high_nonce_a,14,0,CRYPT_OK,CRYPT_INVALID_ARG
invalid_high_nonce_b,14,0,CRYPT_OK,CRYPT_INVALID_ARG
silent_truncation_check,nonce14_tail_a,0x01
silent_truncation_check,nonce14_tail_b,0x02
silent_truncation_check,nonce13_matches_nonce14_a,true
silent_truncation_check,nonce13_matches_nonce14_b,true
silent_truncation_check,ciphertexts_equal,true
silent_truncation_check,tags_equal,true
result,silent_nonce_truncation_reproduced

Expected behavior

ccm_memory(..., nonce, noncelen > 13, ...) should reject the input, preferably with CRYPT_INVALID_ARG, because AES-CCM permits nonce lengths only from 7 to 13 bytes. It should not silently treat a caller-provided 14-byte nonce as a different, shorter nonce. NIST SP 800-38C section 5.1.1 defines the CCM nonce length domain as 7 through 13 octets.

Related issue

Issue #536 demonstrated the lower-bound case using a one-byte nonce. The current develop implementation rejects noncelen < 7, but the opposite upper-bound case remains: noncelen > 13 is accepted and clamped to 13. This report covers that remaining upper-bound validation gap.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions