如何从Python加密适配PHP的MCRYPT_RIJNDAEL_256解密逻辑?
解决Python与PHP mcrypt_decrypt(MCRYPT_RIJNDAEL_256, ECB)的加密适配问题
你的问题核心在于算法参数不匹配和填充逻辑错误,下面一步步拆解并给出修正方案:
1. 关键差异点分析
PHP端用的是MCRYPT_RIJNDAEL_256,这是块大小为256位(32字节)的Rijndael算法;而你Python里用的AES类是标准AES,它的块大小固定为128位(16字节)——即使你手动设置aes.block_size = 256也无效,因为标准AES不支持256位块大小,这是导致解密乱码的首要原因。
另外,PHP的mcrypt_decrypt在ECB模式下,当明文长度不是块大小的整数倍时,会自动用**NULL字节(\x00)**填充到块大小的整数倍;你之前按16字节填充,和PHP的32字节块大小不匹配,这是第二个问题。
2. 修正后的Python加密代码
首先安装支持完整Rijndael算法的库(推荐pycryptodome,因为pycrypto已停止维护):
pip install pycryptodome
然后修改加密逻辑,适配PHP的参数:
from Cryptodome.Cipher import Rijndael import json # 替换成你的实际密钥,确保是字节类型,和PHP的密钥编码一致(比如UTF-8) __KEY__ = b"your_secret_key_here" action = json.dumps({'test': 'value'}) block_size = 32 # RIJNDAEL_256的块大小是256位=32字节 # 实现和PHP mcrypt一致的NULL填充 padding_length = block_size - len(action) % block_size # Python的'\0'等价于\x00,和PHP的NULL填充逻辑完全一致 action_padded = action + ('\0' * padding_length) # 初始化Rijndael加密器,ECB模式,指定32字节块大小 cipher = Rijndael.new(__KEY__, Rijndael.MODE_ECB, block_size=block_size) # 将填充后的字符串转成字节再执行加密 encrypted = cipher.encrypt(action_padded.encode('utf-8'))
3. 额外注意事项
- 密钥处理:PHP的
mcrypt_decrypt会自动将密钥截断/补NULL到算法支持的长度(RIJNDAEL_256支持128/192/256位密钥),Python里要确保密钥的字节长度和PHP端完全一致,比如如果PHP密钥是20字节,Python里也要用同样的20字节密钥(不要额外补全或截断)。 - PHP解密后的处理:
mcrypt_decrypt解密后不会自动去除末尾的NULL填充,所以PHP端需要手动清理:$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, __KEY__, $encrypted_data, MCRYPT_MODE_ECB); $json_str = rtrim($decrypted, "\x00"); // 去除末尾的NULL字节 $value_object = json_decode($json_str);
这样调整后,Python加密的数据就能被PHP端正确解密了。
内容的提问来源于stack exchange,提问作者Reigo Hein
相关产品推荐
相关产品推荐

