You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在C#中实现PostgreSQL pgp_sym_encrypt加密数据的解密?

如何用C#解密PostgreSQL pgp_sym_encrypt加密的数据

你遇到的问题核心在于:PostgreSQL的pgp_sym_encrypt()生成的是OpenPGP标准的加密数据,而不是裸的AES密文。你直接用.NET自带的AES类解密,相当于跳过了OpenPGP格式的封装层,自然无法得到正确的明文。

为什么你的现有代码无效?

  • pgp_sym_encrypt()会把明文、加密算法参数(比如自动生成的IV)、校验信息等打包成OpenPGP格式的二进制数据,不是单纯的AES加密结果。
  • 你把数据库返回的加密二进制数据用Encoding.UTF8.GetBytes(data)转换,这本身就是错误的——加密后的二进制数据不是合法的UTF8字符串,转字节时会丢失信息。
  • OpenPGP的AES加密不会使用固定的全0 IV,它会自动生成随机IV,所以你手动设置aes.IV = new byte[16]也不符合实际加密逻辑。

正确的解决方案:使用OpenPGP库解密

.NET自带的加密库不支持OpenPGP,我们可以用BouncyCastle这个成熟的密码学库来处理。

步骤1:安装BouncyCastle NuGet包

在你的项目中安装最新的BouncyCastle.Cryptography包:

Install-Package BouncyCastle.Cryptography

或者通过NuGet包管理器搜索安装。

步骤2:编写解密代码

下面是等价的C#解密方法,注意要直接从数据库获取byte[]类型的加密数据(不要转成字符串再转字节):

using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
using System.IO;

public static string DecryptPgpSymmetric(byte[] encryptedData, string passphrase)
{
    using (var inputStream = new MemoryStream(encryptedData))
    {
        // 读取OpenPGP加密数据
        var pgpObjectFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream));
        var pgpEncryptedDataList = (PgpEncryptedDataList)pgpObjectFactory.NextPgpObject();

        // 找到对称加密的数据对象
        PgpSymmetricEncryptedData pgpEncryptedData = null;
        foreach (PgpEncryptedData encryptedDataObj in pgpEncryptedDataList)
        {
            if (encryptedDataObj is PgpSymmetricEncryptedData symmetricData)
            {
                pgpEncryptedData = symmetricData;
                break;
            }
        }

        if (pgpEncryptedData == null)
        {
            throw new InvalidDataException("未找到对称加密的OpenPGP数据");
        }

        // 用密码解密,获取明文流
        using (var clearStream = pgpEncryptedData.GetDataStream(PbeParametersGenerator.Pkcs5PasswordToBytes(passphrase.ToCharArray())))
        {
            var plainTextFactory = new PgpObjectFactory(clearStream);
            var pgpLiteralData = (PgpLiteralData)plainTextFactory.NextPgpObject();

            // 读取明文内容
            using (var literalStream = pgpLiteralData.GetInputStream())
            using (var reader = new StreamReader(literalStream))
            {
                return reader.ReadToEnd();
            }
        }
    }
}

如何使用这个方法?

假设你从数据库查询到的加密name字段是byte[]类型(比如用Npgsql获取bytea数据),调用方式如下:

// 从数据库获取加密后的byte[]数据
byte[] encryptedName = ...; // 例如从DataReader.GetBytes()获取
string decryptedName = DecryptPgpSymmetric(encryptedName, "AES_KEY");

额外注意事项

  • 确保你使用的BouncyCastle版本是最新的,旧版本的API可能略有不同。
  • 不要把加密后的二进制数据转换成字符串存储或传递,直接用byte[]处理,避免编码错误。
  • PostgreSQL的pgp_sym_encrypt()默认使用的加密算法可以通过参数指定,如果你修改过默认算法,需要在解密时确保BouncyCastle支持对应的算法。

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

火山引擎 最新活动