如何在Python中实现与PostgreSQL pgp_sym_encrypt兼容的加密,使加密结果可被PostgreSQL解密?
如何在Python中实现与PostgreSQL pgp_sym_encrypt兼容的加密,使加密结果可被PostgreSQL解密?
我明白你的困扰了——你之前用PostgreSQL的pgcrypto函数加密数据,现在想在Python里复刻完全相同的逻辑,让加密后的数据能被PostgreSQL的pgp_sym_decrypt正常解密,但用gnupg库尝试后失败了,还碰到了[39000]: ERROR: Not text data的错误。我来帮你梳理问题原因和可行的解决办法。
先回顾你的原有操作
首先,你之前在PostgreSQL里用的加密SQL是这样的:
update test_encrypt set encrypted_data = encode(pgp_sym_encrypt(origin_data ::text, '123456', 'cipher-algo=aes256, compress-algo=0'), 'base64') where origin_data is not null and origin_data != '';
你尝试用Python的gnupg库模拟这个逻辑,但生成的加密数据无法被PostgreSQL识别,核心问题在于:gnupg的高层封装默认会生成包含额外元数据的完整PGP消息,而PostgreSQL的pgp_sym_encrypt生成的是严格符合OpenPGP特定子集的加密数据包,两者的结构细节存在差异。
推荐的解决方案:用pgpy库精确模拟pgcrypto的行为
gnupg的封装太“重”了,容易隐藏关键参数。推荐用专门处理OpenPGP的pgpy库,它能精确控制所有和pgcrypto对齐的参数,实现完全兼容的加密。
步骤1:安装pgpy库
pip install pgpy
步骤2:编写兼容的Python加密代码
import base64 from pgpy import PGPMessage, PGPKey from pgpy.constants import SymmetricKeyAlgorithm, CompressionAlgorithm, HashAlgorithm, S2KMode def pgp_sym_encrypt_compatible(data: str, passphrase: str) -> str: # 创建PGP消息,和PostgreSQL的text类型对齐,用UTF-8编码 msg = PGPMessage.new(data, encoding='utf-8') # 严格对齐PostgreSQL pgp_sym_encrypt的参数 # 对应你SQL里指定的cipher-algo=aes256, compress-algo=0(不压缩) # 同时匹配pgcrypto的默认S2K(字符串转密钥)参数 encryption_params = { 'cipher': SymmetricKeyAlgorithm.AES256, # 对应SQL的cipher-algo=aes256 'compress': CompressionAlgorithm.Uncompressed, # 对应compress-algo=0 's2k_mode': S2KMode.Iterated, # pgcrypto默认的S2K模式 's2k_hash': HashAlgorithm.SHA1, # pgcrypto默认的S2K哈希算法 's2k_count': 65536, # pgcrypto默认的S2K迭代次数(你SQL里没指定,用默认值) 's2k_cipher': SymmetricKeyAlgorithm.AES256 # 对应pgcrypto的S2K密码算法 } # 执行对称加密 encrypted_msg = msg.encrypt(passphrase, **encryption_params) # 把加密后的二进制数据转成Base64编码,和你SQL里的encode(..., 'base64')对齐 encrypted_bytes = bytes(encrypted_msg) return base64.b64encode(encrypted_bytes).decode('utf-8') # 测试用例 if __name__ == '__main__': original_message = "hello world, 你好世界" encrypted_base64 = pgp_sym_encrypt_compatible(original_message, "123456") print("加密后的Base64字符串:", encrypted_base64) # 把这个Base64字符串放到PostgreSQL里测试解密: # select pgp_sym_decrypt(decode('替换成上面的Base64字符串', 'base64'), '123456', 'cipher-algo=aes256') as decrypted;
为什么这个方案能解决问题?
PostgreSQL的pgp_sym_encrypt生成的是严格遵循OpenPGP标准的最小化对称加密消息,而pgpy库允许我们精确控制所有关键参数,完美匹配pgcrypto的行为:
- 加密算法、压缩设置完全和你SQL里指定的一致
- 字符串转密钥(S2K)的模式、哈希算法、迭代次数严格匹配pgcrypto的默认值
- 生成的加密数据包结构和pgcrypto输出的完全兼容,没有额外的元数据干扰
关于你之前的gnupg代码的问题
你用gnupg尝试的代码,问题出在gnupg的默认行为:
- 它默认会生成包含额外PGP数据包(比如版本信息、注释)的完整PGP消息,而pgcrypto只生成核心的加密数据包
- 可能使用了pgcrypto不支持的OpenPGP数据包类型(比如Tag18的带完整性保护的加密包,而pgcrypto用的是Tag9的普通加密包)
这些差异导致PostgreSQL无法识别加密数据的格式,从而抛出Not text data错误。
备注:内容来源于stack exchange,提问作者dtldyzb
相关产品推荐
相关产品推荐

