c++ - 如何使用 openssl 获取 AES-CCM 解密的标签信息
问题描述
我正在开发使用 AES-CCM 模式的安全应用程序。应用要求如图所示。
我对解密感到震惊,因为我的应用程序在解密时也需要一个 TAG。
根据 openssl EVP Authenticated Encryption and Decryption,我们应该提供 TAG 以及 TAG 长度,如下所示。
/* Set expected tag value. */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, tag))
handleErrors();
如果我没有设置标签信息,结果将全为零。我在e_aes.c 的第 3835 行浏览了 AES-CCM 的实现细节,发现如果预期的标签与生成的标签匹配,那么只会更新结果。(这是我的理解)
你能否建议我如何处理这个问题。
编辑 我已经根据要求创建了图像。实际上,在客户端代码中,它们存储了加密的 TAG 值,并与描述时生成的 TAG 进行比较。即,比较发生在客户端代码处。所以我需要将解密中生成的 TAG 还原为客户端代码。
解决方案
CCM(带有 CBC-MAC 的计数器)在RFC3610中定义。EVP_Authenticated_Encryption_and_Decryption中描述的带有 EVP 的 CCM 实现如下:
加密:在加密期间生成标签:
int ccm_encrypt(...){ ... /* Set tag length */ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, NULL); ... /* Get the tag */ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, 14, tag); // tag is generated here ... }
然后,标签连同密文一起传送给接收者。
解密:在解密期间,接收到的标签用于身份验证:
int ccm_decrypt(...){ ... /* Set expected tag value. */ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, 14, tag); // tag is provided here ... /* ...obtain the plaintext output...*/ ret = EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len); // tag is verified here ... }
仅当解密中使用的标签与加密期间创建的标签相同时,解密才有效。否则EVP_DecryptUpdate
返回 0 并为解密数据提供一个零值数组。
我不知道图像来自哪里,但是 IMO 使用的 AES-CCM 解密EVP_aes_256_ccm()
没有正确描述。
编辑:
使用 时EVP_aes_256_ccm()
,必须知道加密标签才能进行解密(如上所述),因为解密和身份验证是一步完成的。
当然,解密和认证也可以分两步进行:第一步,使用AES-CTR进行解密,即确定明文和标签(CBC-MAC 1)。在第二步中,使用 CBC-MAC 从明文再次计算标签(CBC-MAC 2)(就像在加密过程中所做的那样)。如果两个标签(CBC-MAC 1 和 CBC-MAC 2)相同,则验证成功。
然而,据我所知,没有直接支持这种方法的 EVP 方法。但是,CCM 只是 AES-CTR 和 CBC-MAC 的组合,它们是根据RFC3610组合的。为此,您也可以通过这种方式实现 CCM,并使用 AES-CTR 和 CBC-MAC 所需的 EVP_methods:
- 对于 AES-256-CTR,有
EVP_aes_256_ctr()
. - 对于 CBC-MAC,需要 AES-256-CBC。为此,有
EVP_aes_256_cbc()
. - 以下是使用 EVP 方法的CBC 加密和CBC 解密的示例。当
EVP_aes_256_cbc()
替换为时,CTR 结果的相应 EVP 方法EVP_aes_256_ctr()
。 - CBC-MAC 的确定本质上是一种 CBC 加密,因此
EVP_aes_256_cbc()
这里不需要其他 EVP 方法。
由于 AES-CTR 和 AES-CBC 已经在各自的 EVP 方法中实现,因此两种机制的输入格式都需要付出最大的努力。NIST 特别出版物 800-38C中有很好的描述。应该注意的是,今天AES-GCM已成为最流行的 AE(AD) 模式,请参见例如这篇文章。
推荐阅读
- function - 将参数传递给函数——推送或注册
- python - 在文件夹中使用 WSGI 运行 Gunicorn
- html - 无法在css中应用自定义字体
- java - 哪个对数组列表更有效:collections.swap() 还是使用临时变量进行交换?
- java - Java - 字数对错
- python-3.x - 合并 GDML 文件
- python - pytorch DataLoader 第一个时期极慢
- typescript - 是否可以为多类型参数类/函数的多个参数创建类型别名?
- seaborn - 如何在 seaborn pairplot 中添加细节
- java - 需要有关 Java 中通配符泛型类型的帮助