PostgreSQL解密函数无法输出明文:编码解码问题排查
我通过AES-ECB加密实现Python/Django与PostgreSQL间的数据加解密,已知CBC模式更优,但数据库已完成静态加密,本次操作仅用于对部分员工数据做模糊处理。
Python加密代码如下:
from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad import base64 enc_secret = AES.new(settings.AES_KEY.encode("utf-8"), AES.MODE_ECB) cipher_text = base64.b64encode(enc_secret.encrypt(pad(value.encode('utf-8'), AES.block_size)))
加密后的邮箱示例存储在PostgreSQL的bytea类型字段中(列头显示为Text)。直接执行以下SQL可正常获取明文:
select decrypt(decode('vqRkrhUW9ze4Id0qSYHg0g==','BASE64'),'key','aes-ecb')
但通过列名调用解密时出现错误:
select email, decrypt(decode(email::text,'base64')::bytea, 'key', 'aes-ecb') from table
报错信息:[22023] ERROR: invalid symbol "\" while decoding base64 sequence
请问编码解码环节哪里出现了问题?
核心原因
PostgreSQL将bytea类型转换为text时,会自动添加转义符(比如反斜杠),导致你拿到的text并非原始Base64字符串,而是带转义的格式,因此decode操作会识别到非法的反斜杠字符,触发报错。
解决方法
方法1:直接使用bytea字段进行解密
decrypt函数的第一个参数本身就接受bytea类型,而你的字段刚好是bytea类型,无需多余的encode/decode步骤,直接传入字段名即可:
select email, decrypt(email, 'key', 'aes-ecb') from table;
方法2:正确转换bytea为Base64字符串
如果确实需要先转Base64,不要用::text强制转换,改用encode(email, 'base64')直接从bytea生成标准Base64字符串:
select email, decrypt(decode(encode(email, 'base64'), 'base64'), 'key', 'aes-ecb') from table;
补充说明
你的Python代码中,base64.b64encode返回的是二进制bytes数据,存储到bytea字段时PostgreSQL会直接保存该二进制内容。但用email::text转换时,PostgreSQL会把bytea转为带转义的十六进制/文本表示(例如\x7671526b72685557397a6534496430715359486730673d3d),这显然不是原始的Base64字符串,才会导致解码失败。
内容的提问来源于stack exchange,提问作者Tyler

