You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL加密数据后Python解密无输出问题求助

解决PostgreSQL AES加密后Python解密失败的问题

我帮你梳理下这个问题,大概率是加密和解密的逻辑没对齐,甚至加密函数的设计本身有坑,咱们一步步排查解决:

先搞清楚你的PostgreSQL加密函数逻辑

你给出的函数片段里,IV是用明文数据 + 'salt'做哈希生成的——这其实是个错误设计!IV不应该依赖明文,否则解密时必须知道明文才能生成IV,这完全矛盾,而且也不符合加密安全规范。不过先不管这个,先把加密函数的完整逻辑补全,才能对应写Python解密代码。

假设你的完整加密函数是这样的(大概率和实际情况一致):

CREATE OR REPLACE FUNCTION AESEncrypt(data TEXT, pass TEXT) RETURNS TEXT AS $crypted$ 
declare 
  crypted BYTEA; 
  key BYTEA; 
  iv BYTEA; 
BEGIN 
  -- 用SHA256生成32字节的AES-256密钥
  key := digest(convert_to(pass, 'utf-8'), 'sha256'); 
  -- 用明文+salt做MD5哈希,取前16字节当IV(这就是坑的来源)
  iv := substring(digest(convert_to(CONCAT(data , 'salt'), 'utf-8'), 'md5') from 1 for 16); 
  -- 用AES-CBC模式+PKCS7填充加密
  crypted := encrypt(convert_to(data, 'utf-8'), key, iv, 'aes-cbc/pkcs7'); 
  -- 把加密结果转成Base64字符串返回
  RETURN encode(crypted, 'base64'); 
END; 
$crypted$ LANGUAGE plpgsql;

为什么你的Python解密失败?

核心问题就是这个IV的生成逻辑——解密时你需要原始明文才能生成和加密时一样的IV,但你解密的目的就是得到明文啊!这就陷入死循环了。另外还有可能是以下细节没对齐:

  • 加密结果的编码(是Base64还是十六进制?)
  • AES的模式、填充方式和PG不一致
  • 密钥的哈希算法和PG不一样

解决方案:先修正加密逻辑(推荐)

首先得把加密函数改成安全合理的写法——用随机生成的IV,把IV和密文一起存储,这样解密时就能从密文中提取IV了:

修正后的PostgreSQL加密函数

CREATE OR REPLACE FUNCTION AESEncrypt(data TEXT, pass TEXT) RETURNS TEXT AS $crypted$ 
declare 
  crypted BYTEA; 
  key BYTEA; 
  iv BYTEA; 
BEGIN 
  key := digest(convert_to(pass, 'utf-8'), 'sha256');
  -- 生成随机16字节IV(符合AES-CBC要求)
  iv := gen_random_bytes(16); 
  crypted := encrypt(convert_to(data, 'utf-8'), key, iv, 'aes-cbc/pkcs7');
  -- 把IV拼在密文前面,一起转成Base64返回
  RETURN encode(iv || crypted, 'base64'); 
END; 
$crypted$ LANGUAGE plpgsql;

对应的Python解密代码

先安装依赖库:pip install pycryptodome pandas(pandas用来处理CSV)

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib
import pandas as pd

def aes_decrypt(crypted_str, password):
    # 1. 解码Base64字符串
    crypted_data = base64.b64decode(crypted_str)
    # 2. 拆分IV(前16字节)和密文(剩下的部分)
    iv = crypted_data[:16]
    ciphertext = crypted_data[16:]
    # 3. 生成和PG完全一致的密钥:SHA256哈希密码
    key = hashlib.sha256(password.encode('utf-8')).digest()
    # 4. 初始化AES-CBC解密器
    cipher = AES.new(key, AES.MODE_CBC, iv)
    # 5. 解密并去除PKCS7填充
    decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)
    # 6. 转成UTF-8字符串返回
    return decrypted_data.decode('utf-8')

# 处理CSV文件:解密指定列
if __name__ == "__main__":
    # 读取加密后的CSV
    df = pd.read_csv('encrypted_data.csv')
    # 替换成你要解密的列名和密码
    df['decrypted_column'] = df['encrypted_column'].apply(lambda x: aes_decrypt(x, '你的加密密码'))
    # 保存解密后的CSV
    df.to_csv('decrypted_data.csv', index=False)

如果必须兼容现有加密数据(不推荐)

如果你已经有大量加密数据不能重新加密,那只能硬着头皮按照原来的错误逻辑写解密代码——但前提是你得知道加密前的原始明文(这显然不合理,但没办法):

import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib
import pandas as pd

def aes_decrypt_old(crypted_str, password, original_plaintext):
    # 1. 解码Base64
    ciphertext = base64.b64decode(crypted_str)
    # 2. 生成和PG一致的IV:明文+salt做MD5哈希取前16字节
    iv = hashlib.md5(f"{original_plaintext}salt".encode('utf-8')).digest()[:16]
    # 3. 生成密钥
    key = hashlib.sha256(password.encode('utf-8')).digest()
    # 4. 解密
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)
    return decrypted_data.decode('utf-8')

你看,这个函数必须传入原始明文才能解密,完全失去了解密的意义,所以强烈建议你改用随机IV的加密逻辑。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:07:27