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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 08:33:29