Android ChaCha20-Poly1305加密后Python解密出现尾部乱码问题
问题原因与解决方案
核心问题
ChaCha20-Poly1305是AEAD(带关联数据的认证加密)算法,Java的Cipher.doFinal()返回的是密文 + 16字节Poly1305认证标签的拼接结果。但你的Python代码直接把这个拼接后的完整字节流当成纯密文解密,导致末尾的16字节标签被当作密文内容解密,产生乱码。
修正方案
方案1:Python端拆分密文与标签
在解密时,将收到的Base64解码后的字节流拆分为两部分:前N-16字节是密文,最后16字节是认证标签,然后用decrypt_and_verify方法解密并验证:
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 import base64 # 替换为Java端输出的ct值 ciphertext_b64 = "你的Base64编码密文" ciphertext_with_tag = base64.b64decode(ciphertext_b64) # 拆分密文和标签:最后16字节是Poly1305标签 ciphertext = ciphertext_with_tag[:-16] tag = ciphertext_with_tag[-16:] chacha_key = '11111111111111111111111111111111'.encode() nonce = 'nnnnnnnnnnnn'.encode() chacha_cipher = ChaCha20Poly1305.new(key=chacha_key, nonce=nonce) # 解密并验证标签合法性 plain_text = chacha_cipher.decrypt_and_verify(ciphertext, tag) print(plain_text.decode('utf-8'))
方案2:Java端分离密文与标签(可选)
如果希望Java端直接输出分离的密文和标签,可以修改Java代码,单独获取密文和标签:
byte[] plainText = "This is a sample test".getBytes(StandardCharsets.UTF_8); byte[] key = "11111111111111111111111111111111".getBytes(); byte[] nonce = "nnnnnnnnnnnn".getBytes(); IvParameterSpec ivSpec = new IvParameterSpec(nonce); SecretKeySpec secretKeySpec = new SecretKeySpec(key, "ChaCha20"); Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec); // 生成密文 byte[] ciphertext = cipher.update(plainText); // 完成加密流程,获取认证标签 byte[] tag = cipher.doFinal(); // 分别对密文和标签做Base64编码 String ct = java.util.Base64.getEncoder().encodeToString(ciphertext); String tagStr = java.util.Base64.getEncoder().encodeToString(tag);
此时Python端只需分别解码密文和标签,再调用decrypt_and_verify即可。
额外注意事项
- 确保Java和Python端的key、nonce完全一致:你的代码中key是32字节(符合ChaCha20要求),nonce是12字节(标准长度),这部分没问题。
- 禁止重复使用同一组key和nonce:这会严重破坏加密安全性,实际业务中建议每次加密生成随机nonce,并随密文一起传输。
内容的提问来源于stack exchange,提问作者KTB
相关产品推荐
相关产品推荐

