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

How to decrypt AES-GCM encoded message using AAD in Java

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

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

消息结构如下:

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

header 和 nonce 字节作为附加验证数据输入。

解密的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() );
    
    

我在中看到提到在Java中加密时在密文末尾添加了标签数据。我尝试将 packet.getEncryptedData() 更改为 return 以下内容:

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

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

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