如何在 Java 中使用 AAD 解密 AES-GCM 编码消息

发布于 2025-01-11 08:04:15 字数 1953 浏览 0 评论 0原文

我有一些现有的 C++ 代码,它们使用 openssl 发送加密消息。

我正在编写一个新的基于 Java 的客户端来接收此消息,但无法正确解密该消息。我收到 javax.crypto.AEADBadTagException: 标签不匹配 错误。

该消息的结构如下:

header info (21 bytes)
nonce (12 bytes)
tag data (16 bytes)
encrypted payload (n bytes)

标头和随机数字节作为附加验证数据输入。

要解密的Java代码:

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init( Cipher.DECRYPT_MODE,
                 aesKey,
                 new GCMParameterSpec( 96, packet.getNonce() ));

    cipher.updateAAD( packet.getHeaderAndNonce() );
    return cipher.doFinal( packet.getEncryptedData() );
    
    

我在https://stackoverflow.com/a/26370130/212589中看到了Java中的内容加密时在密文末尾添加标签数据。我尝试更改 packet.getEncryptedData() 以返回以下内容:

  1. 标记数据(16 字节)+ 加密有效负载(n 字节)
  2. 加密有效负载(n 字节)+ 标记数据(16 字节)

,但这两种情况因相同的错误标签异常而失败。

我做错了什么?

作为参考,这里是进行加密的 C++ 代码:

const unsigned int NONCE_LEN = 12;
const unsigned int TAG_DATA_LEN = 16;
const unsigned int DATA_PACKET_HEADER_LEN = 49;
const unsigned int DATA_NONCE_OFFSET = 21;
const unsigned int DATA_TAG_DATA_OFFSET = 33;

std::array<byte, NONCE_LEN> randomNonce = getRandomNonce();
std::copy(randomNonce.begin(), randomNonce.end(), _data.begin() + DATA_NONCE_OFFSET);

EVP_EncryptInit_ex(cipherContext, EVP_aes_256_gcm(), nullptr, encryptionKey.data(), randomNonce.data());

int outlen;
EVP_EncryptUpdate(cipherContext, nullptr, &outlen, _data.data(), DATA_PACKET_HEADER_LEN - TAG_DATA_LEN);    
EVP_EncryptUpdate(cipherContext, _data.data() + DATA_PACKET_HEADER_LEN, &outlen,
        _payloadPlaintext.data(), _payloadPlaintext.size() );

EVP_EncryptFinal_ex(cipherContext, nullptr, &outlen);
EVP_CIPHER_CTX_ctrl(cipherContext, EVP_CTRL_GCM_GET_TAG, TAG_DATA_LEN, &_data[DATA_TAG_DATA_OFFSET]);

I have some existing C++ code that uses openssl to send an encrypted message.

I'm writing a new Java based client to receive this message and cannot properly decrypt the message. I'm getting javax.crypto.AEADBadTagException: Tag mismatch errors.

The message is structured like this:

header info (21 bytes)
nonce (12 bytes)
tag data (16 bytes)
encrypted payload (n bytes)

The header and nonce bytes are input as Additional Authenticated Data.

The Java code to decrypt:

    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init( Cipher.DECRYPT_MODE,
                 aesKey,
                 new GCMParameterSpec( 96, packet.getNonce() ));

    cipher.updateAAD( packet.getHeaderAndNonce() );
    return cipher.doFinal( packet.getEncryptedData() );
    
    

I see mention in https://stackoverflow.com/a/26370130/212589 that in Java the tag data is added at the end of the cipher text when encrypting. I have tried changing packet.getEncryptedData() to return the following:

  1. tag data (16 bytes) + encrypted payload (n bytes)
  2. encrypted payload (n bytes) + tag data (16 bytes)

but both cases fail with the same bad tag exception.

What am I doing wrong?

For reference, here is the C++ code that is doing the encryption:

const unsigned int NONCE_LEN = 12;
const unsigned int TAG_DATA_LEN = 16;
const unsigned int DATA_PACKET_HEADER_LEN = 49;
const unsigned int DATA_NONCE_OFFSET = 21;
const unsigned int DATA_TAG_DATA_OFFSET = 33;

std::array<byte, NONCE_LEN> randomNonce = getRandomNonce();
std::copy(randomNonce.begin(), randomNonce.end(), _data.begin() + DATA_NONCE_OFFSET);

EVP_EncryptInit_ex(cipherContext, EVP_aes_256_gcm(), nullptr, encryptionKey.data(), randomNonce.data());

int outlen;
EVP_EncryptUpdate(cipherContext, nullptr, &outlen, _data.data(), DATA_PACKET_HEADER_LEN - TAG_DATA_LEN);    
EVP_EncryptUpdate(cipherContext, _data.data() + DATA_PACKET_HEADER_LEN, &outlen,
        _payloadPlaintext.data(), _payloadPlaintext.size() );

EVP_EncryptFinal_ex(cipherContext, nullptr, &outlen);
EVP_CIPHER_CTX_ctrl(cipherContext, EVP_CTRL_GCM_GET_TAG, TAG_DATA_LEN, &_data[DATA_TAG_DATA_OFFSET]);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

音盲 2025-01-18 08:04:15

我的解决方案有两个问题(请参阅@dave_thompson_085 的评论)

  1. 传递给 GCMParameterSpec 的标记长度参数是错误的。它应该是 128
  2. Java 解密假定标签数据位于密文的末尾,因此在我的例子中,我必须从开头移动标签数据字节。

There were two issues with my solution (see @dave_thompson_085's comment)

  1. The tag length parameter passed to GCMParameterSpec was wrong. It should be 128
  2. The Java decrypt assumes the tag data is at the end of the ciphertext, so in my case I had to move the tag data bytes from the beginning.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文