You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让Python3的AES加密兼容含控制字符的PHP逻辑

解决Python3与PHP AES加密结果不一致的问题

我来帮你排查这个问题!其实核心不是Python忽略了控制字符,而是PHP和Python3在字符串与字节的处理逻辑上有本质差异——PHP是弱类型语言,字符串默认就是字节流;而Python3严格区分Unicode字符串(str)和字节序列(bytes),这是最容易踩坑的点。

问题根源分析

你的PKCS7填充函数看起来逻辑一致,但在Python里,chr(padding_size)返回的是Unicode字符,拼接后得到的是str类型;而PHP的chr()直接生成字节,填充后的结果是原生字节流。当你把Python的字符串传入AES加密函数时,Python会自动用默认编码(通常是UTF-8)把字符串转成字节,但如果你的加密流程中没有显式处理编码,或者参数类型不匹配,就会导致实际加密的字节和PHP不一致。

修正方案

1. 修正PKCS7填充函数,处理字节而非字符串

把填充函数改成直接操作字节,确保和PHP的字节流完全对齐:

def to_pkcs7(s):
    # 如果输入是字符串,先按UTF-8转成字节(和PHP默认编码一致)
    if isinstance(s, str):
        s = s.encode('utf-8')
    padding_size = 16 - (len(s) % 16)
    # 用bytes([padding_size])生成单字节,再重复填充
    return s + (bytes([padding_size]) * padding_size)

或者更省心的方式,直接用pycryptodome库自带的PKCS7填充工具(避免自己实现可能的疏漏):

from Crypto.Util.Padding import pad

# 先把字符串转成字节,再调用pad函数
padded_data = pad("12345678901".encode('utf-8'), 16, style='pkcs7')

2. 确保加密参数完全匹配PHP

加密时必须保证密钥、IV、加密模式、输出格式和PHP完全一致:
假设你的PHP加密代码是这样的:

$key = "your-16-byte-key"; // AES-128需要16字节密钥
$iv = "your-16-byte-iv";   // CBC模式必须16字节IV
$data = "12345678901";
$padded = toPkcs7($data);
// OPENSSL_RAW_DATA表示输出原始字节,不做base64编码
$encrypted = openssl_encrypt($padded, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);

对应的Python代码(使用pycryptodome)应该是:

from Crypto.Cipher import AES

# 密钥和IV必须是bytes类型,直接加b前缀转字节
key = b"your-16-byte-key"
iv = b"your-16-byte-iv"
data = "12345678901"

# 生成符合要求的填充字节
padded_data = to_pkcs7(data)
# 初始化AES加密器,模式和PHP一致为CBC
cipher = AES.new(key, AES.MODE_CBC, iv)
# 加密得到原始字节,和PHP的OPENSSL_RAW_DATA对应
encrypted = cipher.encrypt(padded_data)

3. 验证填充结果是否一致

在调试阶段,可以把填充后的结果转成十六进制对比,确保两者完全相同:

  • PHP:echo bin2hex($padded);
  • Python:print(padded_data.hex())
    如果十六进制字符串一致,说明填充没问题,加密结果也会一致。

关键注意事项

  • 密钥和IV的长度必须符合AES要求:AES-128对应16字节,AES-192对应24字节,AES-256对应32字节
  • 编码必须统一:PHP默认用UTF-8处理字符串,Python也要用encode('utf-8')转字节
  • 如果PHP的加密结果是base64编码的(没加OPENSSL_RAW_DATA参数),Python加密后也要用base64.b64encode(encrypted).decode('utf-8')转成字符串

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

火山引擎 最新活动