Python与PHP中AES-256-CBC加密结果不一致,求解决方案
AES-256-CBC加密:Python与PHP输出不一致的解决方法
问题重现
Python代码与输出
from Crypto.Random import get_random_bytes from Crypto.Cipher import AES from Crypto.Util.Padding import pad import base64 def encrypt_string(input_string, key_base64, str_iv): try: key = key_base64.encode('utf-8') if str_iv: iv = base64.b64decode(str_iv) else: iv = get_random_bytes(16) cipher = AES.new(key, AES.MODE_CBC, iv) padded_data = pad(input_string.encode(), AES.block_size) cipher_data = cipher.encrypt(padded_data) combined_data = iv + cipher_data return base64.b64encode(combined_data).decode() except Exception as e: print(e) if __name__ == "__main__": key = "1bd393e7a457f9023d9ba95fffb5a2e1" iv = "1oTOhV9xGyu1mppmWZWa5w==" input_string = "AAAAAAA" encrypted_data = encrypt_string(input_string, key, iv) print("Encrypted string:", encrypted_data)
输出:
Encrypted string: 1oTOhV9xGyu1mppmWZWa5+kzveiTRzRH+gRVHx+7Ad0=
PHP代码与输出
<?php function encrypt_string($input_string, $key_base64, $str_iv) { try { $key = base64_decode($key_base64); if ($str_iv) { $iv = base64_decode($str_iv); } else { $iv = openssl_random_pseudo_bytes(16); } $ciphertext = openssl_encrypt($input_string, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); $combined_data = $iv . $ciphertext; return base64_encode($combined_data); } catch (Exception $e) { echo $e->getMessage(); } } $key = "1bd393e7a457f9023d9ba95fffb5a2e1"; $iv = "1oTOhV9xGyu1mppmWZWa5w=="; $input_string = "AAAAAAA"; $encrypted_data = encrypt_string($input_string, $key, $iv); echo "Encrypted string: " . $encrypted_data . "\n"; ?>
输出:
Encrypted string: 1oTOhV9xGyu1mppmWZWa53Nc8rxWTultBWLvWitUICQ=
核心差异原因
两段代码的密钥处理逻辑完全不一致:
- Python直接将传入的
key字符串编码为UTF-8字节作为AES密钥(长度32字节,符合AES-256的密钥要求)。 - PHP对传入的
key字符串执行base64_decode操作,得到24字节数据,不符合AES-256的32字节密钥要求,openssl会自动用零填充补全至32字节,最终导致两边使用的密钥完全不同,加密结果自然不一致。
注:两边填充逻辑一致,均默认使用PKCS7填充,无差异。
修正方案
方案1:修改PHP代码(推荐)
将PHP密钥处理逻辑改为与Python一致,直接使用key的UTF-8字节作为密钥:
<?php function encrypt_string($input_string, $key_base64, $str_iv) { try { // 替换base64_decode为直接使用字符串(PHP字符串默认是字节串) $key = $key_base64; if ($str_iv) { $iv = base64_decode($str_iv); } else { $iv = openssl_random_pseudo_bytes(16); } $ciphertext = openssl_encrypt($input_string, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv); $combined_data = $iv . $ciphertext; return base64_encode($combined_data); } catch (Exception $e) { echo $e->getMessage(); } } $key = "1bd393e7a457f9023d9ba95fffb5a2e1"; $iv = "1oTOhV9xGyu1mppmWZWa5w=="; $input_string = "AAAAAAA"; $encrypted_data = encrypt_string($input_string, $key, $iv); echo "Encrypted string: " . $encrypted_data . "\n"; ?>
修正后输出:
Encrypted string: 1oTOhV9xGyu1mppmWZWa5+kzveiTRzRH+gRVHx+7Ad0=
与Python代码输出完全一致。
方案2:修改Python代码(若需保持PHP原密钥逻辑)
若必须使用base64_decode后的密钥,需手动补全至32字节(模拟openssl的零填充行为):
from Crypto.Random import get_random_bytes from Crypto.Cipher import AES from Crypto.Util.Padding import pad import base64 def encrypt_string(input_string, key_base64, str_iv): try: # 模拟PHP的密钥处理:base64解码后补零至32字节 key = base64.b64decode(key_base64) if len(key) < 32: key += b'\x00' * (32 - len(key)) if str_iv: iv = base64.b64decode(str_iv) else: iv = get_random_bytes(16) cipher = AES.new(key, AES.MODE_CBC, iv) padded_data = pad(input_string.encode(), AES.block_size) cipher_data = cipher.encrypt(padded_data) combined_data = iv + cipher_data return base64.b64encode(combined_data).decode() except Exception as e: print(e) if __name__ == "__main__": key = "1bd393e7a457f9023d9ba95fffb5a2e1" iv = "1oTOhV9xGyu1mppmWZWa5w==" input_string = "AAAAAAA" encrypted_data = encrypt_string(input_string, key, iv) print("Encrypted string:", encrypted_data)
修正后输出:
Encrypted string: 1oTOhV9xGyu1mppmWZWa53Nc8rxWTultBWLvWitUICQ=
与原PHP代码输出完全一致。
内容的提问来源于stack exchange,提问作者Dafahan
相关产品推荐
相关产品推荐

