如何在 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 以下内容:
- 标签数据(16 字节)+ 加密负载(n 字节)
- 加密有效载荷(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 的评论)
- 传递给
GCMParameterSpec
的标记长度参数错误。应该是128
- 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 以下内容:
- 标签数据(16 字节)+ 加密负载(n 字节)
- 加密有效载荷(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 的评论)
- 传递给
GCMParameterSpec
的标记长度参数错误。应该是128 - Java 解密假定标签数据位于密文的末尾,因此在我的情况下,我必须从开头移动标签数据字节。