首页 > 解决方案 > AES/CCM 加密和明文长度超过最大消息长度

问题描述

我正在尝试使用具有 CCM 操作模式的 AES128 密码在 Crypto++ 库中执行加密和解密。当我尝试加密长度超过 16777215 字节的字符串时遇到问题。

我的代码:

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)
);

当我尝试加密/解密 CD 大小的纯文本 (737280000) 时,出现以下错误:

“在抛出 'CryptoPP::InvalidArgument' what() 的实例后调用终止:AES/CCM:消息长度 737280000 超过最大值 16777215”

我的问题是,如何加密/解密长度超过 16777215 字节的明文?

标签: c++encryptioncrypto++

解决方案


我的问题是,如何加密/解密长度超过 16777215 字节的明文?

CCM 模式在 NIST SP800-38c中指定。第 A.1 节,长度要求,讨论了安全上下文下的最大纯文本。安全上下文是{key, iv}组合(有些人放弃)。

我相信你有三个选择。首先,您可以增加 IV 的长度。iv 越大,可以加密的纯文本越多。最大 iv 长度为 13,因此它不会永远扩大。

其次,在达到上下文中的最大纯文本之前,您必须重新键入或更改 iv。您可以使用 找到最大纯文本长度MaxMessageLength()。Crypto++ 跟踪通过 处理的字节数m_totalMessageLength,但它不暴露给用户程序。您将不得不自己跟踪它。

第三,您可以更改算法。像ChaCha20Poly1305这样的算法允许您加密 2^38-1 个 64 字节块。这不到 2^44 字节或大约 256 GB。使用 ChaCha20Poly1305 应该是安全的。


Crypto++ 通过 告诉你最大字节数MaxMessageLength()。在 CCM 的情况下,它基于 iv 长度,并m_L在下面的代码中进行跟踪。

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

MaxMessageLength()用于authenc.cpp. ProcessData()达到限制时抛出异常:

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;

您的标签尺寸偏小。如果您的协议允许,您可能希望使用最大大小。


我建议你切换算法。CCM 是一种混蛋模式,在 2000 年初通过一些无线工作组进行了标准化。然后,NIST 采用了它,因为它已经标准化了。

在 CCM 标准化时,有更好的身份验证加密模式可用,如 CWC、OCB、EAX 和 GCM。不幸的是,损坏已经造成。现在你有了像 Bernstein 的 ChaChaPoly1305 这样的算法。

您可能还想查看Crypto++ wiki 上的AEAD 比较。比较表明,CCM 是最差的经过身份验证的加密模式。


推荐阅读