You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现PHP的openssl_decrypt(AES-256-GCM)解密遇MAC校验失败求助

Python中实现PHP openssl_decrypt(AES-256-GCM)解密的问题

原PHP解密代码

需要将这段PHP的AES-256-GCM解密逻辑转换成Python实现:

openssl_decrypt( $acipher, "aes-256-gcm", $secret, OPENSSL_RAW_DATA, $bnonce, $tag);

初始Python代码(参数传递困惑)

我写了一段Python代码,但不知道该如何传入$bnonce和$tag参数:

from crypto.Cipher import AES
cipher = AES.new(acipher, AES.MODE_GCM, acipher)
plaintext = cipher.decrypt(secret)
# 我不知道该把$bnonce和$tag放在哪里,哈哈。

尝试后的错误代码(MAC check failed)

我尝试了以下代码,但一直出现“MAC check failed”错误:

secret              = "b34f09fc80e7974a918b50cfda6f48ce" # 这是我对某个字符串使用OpenSSL后得到的内容,仅作补充信息。
content             = "EZrjXFQ4o3oCVzy28q/IWYLgg9aP+VlmhQZ+wKs4C20D7k+lZMKlmi9UgZgINz6t/ucWmOzRFLo5DAZ3b6dYrMOz1lV2gJs9v9K6MDFeweREKRDupnTDKgx8AS7OaimofNK8wKxNp5QDnYBZNpY6BQ02mU5586LXGfwJJrAc3S7D85cZZofnUBpNcUztrHYOjCEtvB24p6j8W9ju3ALkAfd1Dk+UdKMVzp9sLa/qbzxPqQeZhPPS43A5b9Wa10DeKvMnMl4Z46M6j+AeudKmS46xCOM84zMbOonxIkCA+kS0BCPaDlpwOyiL31yeJqHw/dKhHuY0qVyHWgrlf3mdHizGKakeAoYsy4Wo1WjeTteSRnw713s="

# Content
bcontent                            = str( base64.b64decode(content) )
bcontent_total_characters           = len(bcontent)
bcontent_total_characters_minus_12  = bcontent_total_characters - 12
bnonce                              = bcontent[ bcontent_total_characters_minus_12 : bcontent_total_characters - 12 + bcontent_total_characters ]
bcipher                             = bcontent[ 0 : 0 + bcontent_total_characters_minus_12 ]
# default tag
bcipher_total_characters            = len(bcipher)
taglength                           = 16
tag                                 = bcipher[ bcipher_total_characters - taglength : bcipher_total_characters - taglength + bcipher_total_characters ]
acipher                             = bcipher[ 0 : 0 + bcipher_total_characters - taglength]

cipher = AES.new(str.encode(secret), AES.MODE_GCM,  str.encode(bnonce) )
decrypted = cipher.decrypt_and_verify(str.encode(content), str.encode(tag))

问题分析与解决方法

核心错误点

  1. 二进制数据处理错误:把base64解码后的字节流转成字符串,导致二进制数据损坏,应该直接保留字节类型。
  2. Nonce和Tag截取逻辑错误:
    • AES-GCM标准Nonce是12字节,你当前的切片范围完全错误,应该从内容末尾取对应长度的字节。
    • Tag是16字节,同样切片范围错误,且错误地从密文里截取,而非整体内容的对应位置。
  3. 解密传入内容错误:传入了原始base64编码字符串,而非截取后的纯密文部分。

正确的Python实现代码

from Crypto.Cipher import AES
import base64

secret = "b34f09fc80e7974a918b50cfda6f48ce"
content = "EZrjXFQ4o3oCVzy28q/IWYLgg9aP+VlmhQZ+wKs4C20D7k+lZMKlmi9UgZgINz6t/ucWmOzRFLo5DAZ3b6dYrMOz1lV2gJs9v9K6MDFeweREKRDupnTDKgx8AS7OaimofNK8wKxNp5QDnYBZNpY6BQ02mU5586LXGfwJJrAc3S7D85cZZofnUBpNcUztrHYOjCEtvB24p6j8W9ju3ALkAfd1Dk+UdKMVzp9sLa/qbzxPqQeZhPPS43A5b9Wa10DeKvMnMl4Z46M6j+AeudKmS46xCOM84zMbOonxIkCA+kS0BCPaDlpwOyiL31yeJqHw/dKhHuY0qVyHWgrlf3mdHizGKakeAoYsy4Wo1WjeTteSRnw713s="

# 解码base64内容,保留字节类型,不要转字符串
bcontent = base64.b64decode(content)

# 拆分密文、Tag、Nonce:PHP openssl加密后的常见格式为 [密文][Tag(16字节)][Nonce(12字节)]
tag_length = 16
nonce_length = 12

nonce = bcontent[-nonce_length:]  # 最后12字节是Nonce
tag = bcontent[-nonce_length - tag_length : -nonce_length]  # Nonce之前的16字节是Tag
ciphertext = bcontent[:-nonce_length - tag_length]  # 前面的所有字节是纯密文

# 初始化AES-GCM解密器:密钥、模式、Nonce对应PHP的$secret、aes-256-gcm、$bnonce
cipher = AES.new(secret.encode('utf-8'), AES.MODE_GCM, nonce=nonce)
# 解密并验证Tag:对应PHP的$acipher和$tag
plaintext = cipher.decrypt_and_verify(ciphertext, tag)

# 输出明文(根据实际编码调整decode的参数)
print(plaintext.decode('utf-8'))

关键说明

  • 字节类型必须贯穿全程:所有加密解密相关的操作都要用bytes类型,绝对不能转成字符串,否则会破坏二进制数据。
  • 参数对应关系:
    • PHP的$secret → Python AES.new()的第一个参数(密钥)
    • PHP的$bnonce → Python AES.new()的nonce参数
    • PHP的$tag → Python decrypt_and_verify()的第二个参数
  • 格式适配:如果上述代码仍报错,可能是加密时的内容拼接顺序不同(比如Nonce在最前面),可尝试调整拆分逻辑:nonce = bcontent[:12],然后Tag和密文对应调整范围。

内容的提问来源于stack exchange,提问作者Raymond Seger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 18:45:40