c++ - 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 字节的明文?
解决方案
我的问题是,如何加密/解密长度超过 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 是最差的经过身份验证的加密模式。
推荐阅读
- django - Django rest-auth 自定义登录表单 - 无法识别输入的电子邮件:“必须包括 \"email\" 和 \"password\"。”
- android - Android 8.1 上的 ADB wifi 永久
- docker - 如何使用 docker-compose 在 Openshift Container Platform 中部署?
- design-patterns - 复合设计模式 - 如何创建计算器
- django - 在 Django 中实现 PostgreSQL HStore
- php - 如何更改php中的打印变量?
- linux - 循环遍历 CSV 文件中的每一列并将不同的值导出到文件中
- javascript - 如何在 webdriverIO 的屏幕截图名称中获取测试套件/测试用例名称?
- javascript - 函数未定义 javascript onclick
- python - 如何在数据框末尾添加某些列的总和