如何在C#中解密PostgreSQL的PGP_SYM_ENCRYPT加密数据?
解决PostgreSQL PGP_SYM_ENCRYPT加密数据的C#解密方案
核心逻辑
PostgreSQL的PGP_SYM_ENCRYPT基于OpenPGP标准实现,不是单纯的AES对称加密,所以直接用AES库解密必然失败。正确的思路是用支持OpenPGP的工具库(比如BouncyCastle),按OpenPGP的解密流程处理。
具体步骤
1. 十六进制字符串转字节数组
PostgreSQL返回的加密结果是带\x前缀的十六进制字符串,第一步要把它转换成字节数组:
- 去掉开头的
\x前缀 - 用
.NET 5+内置的Convert.FromHexString完成转换,低版本可以用自定义十六进制转字节方法
2. 用BouncyCastle完成OpenPGP解密
先安装NuGet包:Org.BouncyCastle和Org.BouncyCastle.Bcpg,然后按照OpenPGP的解密流程处理字节流:
完整解密代码
using Org.BouncyCastle.Bcpg.OpenPgp; using Org.BouncyCastle.Security; using System; using System.IO; public static string DecryptPgpEncryptedData(string hexEncryptedString, string passphrase) { // 清理十六进制字符串,去掉\x前缀 var cleanedHex = hexEncryptedString.StartsWith("\\x") ? hexEncryptedString.Substring(2) : hexEncryptedString; byte[] encryptedBytes = Convert.FromHexString(cleanedHex); // 解析PGP加密数据结构 using var inputStream = new MemoryStream(encryptedBytes); inputStream.Position = 0; var pgpFactory = new PgpObjectFactory(inputStream); PgpEncryptedDataList encryptedDataList = null; var firstObj = pgpFactory.NextPgpObject(); encryptedDataList = firstObj is PgpEncryptedDataList list ? list : (PgpEncryptedDataList)pgpFactory.NextPgpObject(); // 定位对称加密数据块 PgpSymmetricKeyEncryptedData symmetricData = null; foreach (var obj in encryptedDataList.GetEncryptedDataObjects()) { symmetricData = obj as PgpSymmetricKeyEncryptedData; if (symmetricData != null) break; } if (symmetricData == null) throw new InvalidOperationException("未找到有效的PGP对称加密数据块"); // 解密获取明文流 using var clearStream = symmetricData.GetDataStream(PbeParametersGenerator.Pkcs5, passphrase.ToCharArray()); var clearFactory = new PgpObjectFactory(clearStream); var literalData = clearFactory.NextPgpObject() as PgpLiteralData; // 读取明文内容 using var contentStream = literalData.GetInputStream(); using var reader = new StreamReader(contentStream); return reader.ReadToEnd(); }
3. EF Core中的两种使用方式
方式一:在C#代码中解密(已查询出加密数据后)
var encryptedRecord = await dbContext.YourTable.FirstAsync(t => t.Id == 1); string decryptedContent = DecryptPgpEncryptedData(encryptedRecord.EncryptedColumn, "KEY");
方式二:直接在EF Core查询中调用PostgreSQL解密函数
如果不想在C#中处理解密逻辑,可以直接让数据库完成解密,避免字节流传输:
var result = await dbContext.YourTable .Select(t => new { t.Id, DecryptedContent = EF.Functions.SqlQuery<string>( "SELECT PGP_SYM_DECRYPT({0}::bytea, 'KEY')", t.EncryptedColumn) }) .ToListAsync();
注意事项
- 密钥安全:绝对不要硬编码密钥,改用配置文件、环境变量或密钥管理服务存储
- 字符编码:
PGP_SYM_ENCRYPT默认使用UTF-8,解密时保持编码一致 - BouncyCastle版本:使用最新稳定版,避免API兼容问题
内容的提问来源于stack exchange,提问作者Leonardo Artuso
相关产品推荐
相关产品推荐

