关于使用python/php实现mysql aes_encrypt(str,pass)超长密文加密解解决方案
开发环境:
mysql 5.7
python 3.8
php 7
centos7.9
使用 mysql的aes_encrypt 进行数据加密,使用 hex(aes_encrypt(原文, 密钥)) 加密生成密文,并使用 aes_decrypt(unhex(密文), 密钥) 进行解密。
--注意,当密钥长度超过16位时,mysql会对密钥进行处理,生成16位长度的新密钥。这点需要特别注意。这也是php python实现方法中“模拟mysql的密钥生成逻辑”存在的目的 --例如 密钥='fdsar23sv3qrgasdfasdfh34gsdv' 该密钥在php 或者python实现中,不可简单的截取前16位,而是要模拟 mysql 越长密钥的生成逻辑进行处理 -- 加密 SELECT HEX(AES_ENCRYPT('0123456789', '密钥')); -- 解密 SELECT AES_DECRYPT(HEX('密文'), '密钥');
下面是使用php进行该功能的实现
1 function mysql_aes_key($passphrase) {// 模拟MySQL的密钥生成逻辑(循环异或处理超长密钥) 2 $key = str_repeat("\0", 16); // 初始化16字节缓冲区 3 $passBytes = $passphrase; // 原始密钥字节流 4 for ($i = 0; $i < strlen($passBytes); $i++) { 5 $key[$i % 16] = $key[$i % 16] ^ $passBytes[$i]; // 循环异或 6 } 7 return $key; 8 } 9 function mysql_aes_decrypt($hex_data,$passphrase){ 10 try{ 11 if(!ctype_xdigit($hex_data) || strlen($hex_data)%2!=0){ 12 throw new Exception('Invalid hex data'); 13 } 14 // 将十六进制表示转换为二进制数据 15 $encrypted_binary= hex2bin($hex_data); 16 // 2. 处理密钥 17 $key = mysql_aes_key($passphrase); 18 // 使用openssl_decrypt函数解密数据 19 // 加密算法为AES-128-ECB,这是MySQL中默认的AES加密算法 20 // 指定了OPENSSL_RAW_DATA选项,以确保解密后的数据不进行任何格式转换 21 $decrypted_data = openssl_decrypt($encrypted_binary,'AES-128-ECB',$key,OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING); 22 23 // 4. 安全去除PKCS7填充(PHP需手动处理) 24 $pad = ord($decrypted_data[strlen($decrypted_data) - 1]); 25 $unpadded_data = substr($decrypted_data, 0, -$pad); 26 27 // 5. 编码转换与过滤(兼容Python的decode('utf-8')) 28 $decrypted_data = mb_convert_encoding($unpadded_data, 'UTF-8', 'UTF-8,GBK,ISO-8859-1'); 29 // $decrypted_data = iconv('UTF-8', 'UTF-8//IGNORE', $decrypted_data); 30 return $decrypted_data; 31 } catch (Exception $e) { 32 error_log("Decryption failed: " . $e->getMessage()); 33 return $hex_data; 34 } catch (Throwable $t) { 35 // 处理二进制解码异常 36 error_log("Unicode error: " . $t->getMessage()); 37 return ''; 38 } 39 } 40 /** 41 * mysql HEX(AES_ENCRYPT('原文','密钥')) 42 * @param string $data 要加密的数据 43 * @param string $passhprase 加密密钥 44 * @param string $cipher_algo 加密算法 45 * @param int $options 加密选项 46 * @return string 加密后的十六进制字符串 47 */ 48 function mysql_aes_encrypt($data,$passphrase){ 49 try{ 50 51 // 使用openssl_encrypt函数进行AES加密 52 // 加密算法为AES-128-ECB,这是MySQL中默认的AES加密算法 53 // 指定了OPENSSL_RAW_DATA选项,以确保加密后的数据不进行任何格式转换 54 // $encrypted = openssl_encrypt($data,$cipher_algo,$passphrase,$options); 55 56 // 模拟 mysql 处理超长密钥 57 $key = mysql_aes_key($passphrase); 58 $encrypted = openssl_encrypt($data,'AES-128-ECB',$key,OPENSSL_RAW_DATA); 59 60 // 将加密结果转换为十六进制字符串 61 $hex_encrypted= bin2hex($encrypted); 62 return $hex_encrypted; 63 }catch(\Exception $e){ 64 return $data; 65 } 66 }
下面是使用python进行实现:
1 from Crypto.Cipher import AES 2 from Crypto.Util.Padding import pad, unpad 3 4 5 # import hashlib 6 7 def mysql_aes_key(passphrase: str) -> bytes: 8 """模拟MySQL的密钥生成逻辑(循环异或处理超长密钥)""" 9 key = bytearray(16) # 初始化16字节缓冲区 10 pass_bytes = passphrase.encode('utf-8') 11 for i in range(len(pass_bytes)): 12 key[i % 16] ^= pass_bytes[i] # 循环异或操作 13 return bytes(key) 14 15 def mysql_aes_encrypt(data: str, passphrase: str) -> str: 16 """ 17 字符串加密 18 :param data: 待加密字符串 19 :param passphrase: 密钥 20 """ 21 try: 22 # 1. 密钥处理:MD5哈希生成16字节密钥(MySQL兼容性) 23 # key = hashlib.md5(passphrase.encode()).digest() 24 # key = passphrase.encode('utf-8')[:16].ljust(16, b'\0') # 直接截取前16字节,不足补零 25 key = mysql_aes_key(passphrase) 26 27 # 2. PKCS7填充(PHP/MySQL默认填充方式) 28 padded_data = pad(data.encode('utf-8'), AES.block_size, style='pkcs7') 29 30 # 3. AES-128-ECB加密(无IV,兼容MySQL) 31 cipher = AES.new(key, AES.MODE_ECB) 32 encrypted_data = cipher.encrypt(padded_data) 33 34 # 4. 转为HEX字符串(大写,兼容MySQL的HEX()) 35 return encrypted_data.hex().upper() 36 except Exception as e: 37 # 异常时返回原始数据(与PHP行为一致) 38 return data 39 40 41 def mysql_aes_decrypt(hex_data: str, passphrase: str) -> str: 42 """ 43 字符串加密 44 :param hex_data: 待解密字符串 45 :param passphrase: 密钥 46 """ 47 try: 48 # 1. 检查HEX格式并转换 49 encrypted_data = bytes.fromhex(hex_data) 50 51 # 2. 生成MD5哈希密钥(16字节) 52 # key = hashlib.md5(passphrase.encode()).digest() 53 # key = passphrase.encode('utf-8')[:16].ljust(16, b'\0') # 直接截取前16字节,不足补零 54 key = mysql_aes_key(passphrase) 55 56 # 3. ECB模式解密 57 cipher = AES.new(key, AES.MODE_ECB) 58 decrypted_data = cipher.decrypt(encrypted_data) 59 60 # 4. 安全去除PKCS7填充 61 unpadded_data = unpad(decrypted_data, AES.block_size, style='pkcs7') 62 63 return unpadded_data.decode('utf-8') 64 except (ValueError, TypeError) as e: 65 print(f"解密失败: {str(e)}") 66 return hex_data # 或抛出异常 67 except UnicodeDecodeError: 68 # return "解密成功但编码异常" # 处理非文本数据 69 print("解密成功但编码异常") 70 return ''

浙公网安备 33010602011771号