Pycryptodome AES-GCM加密后Java解密报Tag mismatch问题求助
Fixing AES-GCM Tag Mismatch Between Pycryptodome and Java
Let's break down why you're hitting that AEADBadTagException and fix it step by step:
Root Causes
- Missing Authentication Tag: AES-GCM is an AEAD (Authenticated Encryption with Associated Data) algorithm, which requires three components for decryption: the nonce, the ciphertext, and the authentication tag. Your Python code only sends the ciphertext to Java, but doesn't include the tag generated during encryption.
- Java Code Variable Mix-Up: In your original Java snippet, you reference an undefined
ivvariable inGCMParameterSpec, and create anIvParameterSpecthat's never used (GCM doesn't need this—GCMParameterSpechandles the nonce directly).
Fixed Python Encryption Code
You need to capture the tag after encryption and bundle it with the ciphertext (appending it works perfectly since you set mac_len=16 for a fixed-length tag):
import os from Crypto.Cipher import AES message = b"your target plaintext here" cek = os.urandom(16) nonce = os.urandom(12) cipher = AES.new(cek, AES.MODE_GCM, nonce=nonce, mac_len=16) ciphertext = cipher.encrypt(message) # Capture the authentication tag generated during encryption tag = cipher.digest() # Bundle nonce + ciphertext + tag to send to Java (concatenation is a simple approach) data_to_send = nonce + ciphertext + tag
Fixed Java Decryption Code
On the Java side, split the received data into its three components, then initialize the GCM cipher correctly:
import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Arrays; public class GCMDecrypt { public static void main(String[] args) throws Exception { byte[] receivedData = /* Your combined data from Python: nonce + ciphertext + tag */; byte[] cek = /* The same CEK bytes used in Python encryption */; // Split the received data into components byte[] nonce = Arrays.copyOfRange(receivedData, 0, 12); byte[] tag = Arrays.copyOfRange(receivedData, receivedData.length - 16, receivedData.length); byte[] ciphertext = Arrays.copyOfRange(receivedData, 12, receivedData.length - 16); // Initialize AES-GCM cipher Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec gcmSpec = new GCMParameterSpec(128, nonce); // 128 bits = 16-byte tag SecretKeySpec secretKeySpec = new SecretKeySpec(cek, "AES"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmSpec); // Combine ciphertext and tag before decryption byte[] ciphertextWithTag = new byte[ciphertext.length + tag.length]; System.arraycopy(ciphertext, 0, ciphertextWithTag, 0, ciphertext.length); System.arraycopy(tag, 0, ciphertextWithTag, ciphertext.length, tag.length); byte[] decryptedBytes = cipher.doFinal(ciphertextWithTag); String decryptedMessage = new String(decryptedBytes); System.out.println("Decrypted content: " + decryptedMessage); } }
Key Notes
- Tag Handling: Pycryptodome generates the tag separately via
cipher.digest()—never skip sending this to Java. Java'sdoFinal()expects the ciphertext followed by the tag (you can also useupdate()for ciphertext anddoFinal()for the tag, but concatenation is simpler). - Nonce Best Practice: You're using the recommended 12-byte nonce for GCM, which avoids security risks associated with shorter nonces—keep that up!
- Variable Consistency: Double-check all variable references (like fixing the
iv/noncemix-up in your original Java code) to avoid accidental mismatches.
内容的提问来源于stack exchange,提问作者Alastair McCormack
相关产品推荐
相关产品推荐

