Tomi Jerenko
Tomi Jerenko

Reputation: 45

AES/CCM Encryption and Plaintext Length Exceeds Maximum Message Length

I am trying to perform an encryption and decryption in Crypto++ library using AES128 cipher with CCM mode of operation. I have a problem when I try to encrypt string longer than 16777215 bytes.

My code:

const int TAG_SIZE = 8;
CCM< AES, TAG_SIZE >::Encryption e;
CCM< AES, TAG_SIZE >::Decryption d;

e.SetKeyWithIV( key, sizeof(key), iv, sizeof(iv) );
e.SpecifyDataLengths( 0, plain.size(), 0 );

//Encryption
StringSource ss1(
  plain,
  true,
  new AuthenticatedEncryptionFilter(
    e,
    new StringSink(cipher)
   )
);

d.SetKeyWithIV( key, sizeof(key), iv, sizeof(iv) );
d.SpecifyDataLengths( 0, plain.size(), 0 );

//Decryption
AuthenticatedDecryptionFilter df( d,
  new StringSink(recovered)
);
StringSource ss2(
  cipher,
  true,
  new Redirector(df)
);

When I try to encrypt/decrypt a plaintext which is size of a CD (737280000), I get the following error:

"terminate called after throwing an instance of 'CryptoPP::InvalidArgument' what(): AES/CCM: message length 737280000 exceeds the maximum of 16777215"

My question is, how do I encrypt/decrypt a plaintext which is longer than 16777215 bytes?

Upvotes: 3

Views: 1386

Answers (1)

jww
jww

Reputation: 102376

My question is, how do I encrypt/decrypt a plaintext which is longer than 16777215 bytes?

CCM mode is specified in NIST SP800-38c. Section A.1, Length Requirements, discusses maximum plain text under a security context. A security context is the {key, iv} combination (with some hand waiving).

I believe you have three choices. First, you can increase the length of the IV. The larger the iv, the more plain text you can encrypt. The max iv length is 13 so it does not scale up forever.

Second, you have to re-key or change the iv before you hit the maximum plain text under the context. You can find the maximum plain text length using MaxMessageLength(). Crypto++ tracks the number of bytes processed via m_totalMessageLength, but it is not exposed to user programs. You will have to track it yourself.

Third, you can change algorithms. An algorithm like ChaCha20Poly1305 allows you to encrypt 2^38-1 64-byte blocks. That is just under 2^44 bytes or about 256 GB. You should be safe with ChaCha20Poly1305.


Crypto++ tells you the maximum number of bytes via MaxMessageLength(). In the case of CCM it is based on the iv length, and tracked through m_L in the code below.

lword MaxMessageLength() const
    {return m_L<8 ? (W64LIT(1)<<(8*m_L))-1 : W64LIT(0)-1;}

MaxMessageLength() is used in authenc.cpp. ProcessData() throws an exception when the limit is hit:

if (m_state >= State_IVSet && length > MaxMessageLength()-m_totalMessageLength)
    throw InvalidArgument(AlgorithmName() + ": message length exceeds maximum");
m_totalMessageLength += length;

const int TAG_SIZE = 8;
CCM< AES, TAG_SIZE >::Encryption e;
CCM< AES, TAG_SIZE >::Decryption d;

Your tag size is a tad bit on the small side. You might want to use the maximum size, if your protocol allows it.


I recommend you switch algorithms. CCM is a bastard mode that got standardized in the early 2000's through some Wireless Working Group. Then, NIST adopted it because it was already standardized.

At the time CCM was standardized there were better Authenticated Encryption modes available, like CWC, OCB, EAX and GCM. Unfortunately the damage was done. And now you have algorithms like Bernstein's ChaChaPoly1305.

You might also want to checkout AEAD Comparison on the Crypto++ wiki. The comparison shows CCM is about the worst of the authenticated encryption modes.

Upvotes: 4

Related Questions