C#中使用Bouncy Castle实现PGP一键签名加密示例求助
使用Bouncy Castle实现文件签名+加密
依赖准备
先安装对应的NuGet包:
Install-Package Org.BouncyCastle Install-Package Org.BouncyCastle.Bcpg
核心实现代码
签名需要发送方的私钥(带密码),加密需要接收方的公钥,以下是一次完成签名+加密的完整实现:
using System.IO; using Org.BouncyCastle.Bcpg.OpenPgp; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.IO; public static class PgpFileHandler { /// <summary> /// 对目标文件执行签名+加密操作 /// </summary> /// <param name="inputPath">待处理文件路径</param> /// <param name="outputPath">生成的签名加密文件路径</param> /// <param name="senderPrivKeyPath">发送方PGP私钥文件路径</param> /// <param name="privKeyPassword">私钥解锁密码</param> /// <param name="recipientPubKeyPath">接收方PGP公钥文件路径</param> public static void SignAndEncrypt(string inputPath, string outputPath, string senderPrivKeyPath, string privKeyPassword, string recipientPubKeyPath) { using var inputStream = File.OpenRead(inputPath); using var outputStream = File.Create(outputPath); // 加载接收方加密公钥 var recipientPubKey = LoadPublicKey(recipientPubKeyPath); // 加载发送方签名私钥 var senderPrivKey = LoadPrivateKey(senderPrivKeyPath, privKeyPassword); // 初始化加密生成器,采用CAST-5对称加密算法 var encryptGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, true, new SecureRandom()); encryptGenerator.AddMethod(recipientPubKey); // 创建加密输出流 var encryptedStream = encryptGenerator.Open(outputStream, new byte[4096]); // 初始化签名生成器,采用SHA-256哈希算法 var signatureGenerator = new PgpSignatureGenerator(senderPrivKey.PublicKey.Algorithm, HashAlgorithmTag.Sha256); signatureGenerator.InitSign(PgpSignature.BinaryDocument, senderPrivKey); // 设置签名者用户信息 foreach (var userId in senderPrivKey.PublicKey.GetUserIds()) { var subpacketGen = new PgpSignatureSubpacketGenerator(); subpacketGen.SetSignerUserId(false, userId.ToString()); signatureGenerator.SetHashedSubpackets(subpacketGen.Generate()); break; // 取第一个用户ID即可 } // 创建带签名的输出流(如果不需要ASCII装甲,可替换为BufferedStream) var signedStream = new ArmoredOutputStream(encryptedStream); // 写入一次性签名头 signatureGenerator.GenerateOnePassVersion(false).Encode(signedStream); // 读取文件内容,同时更新签名并写入加密流 var buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0) { signedStream.Write(buffer, 0, bytesRead); signatureGenerator.Update(buffer, 0, bytesRead); } // 写入最终签名 signatureGenerator.Generate().Encode(signedStream); // 依次关闭流 signedStream.Close(); encryptedStream.Close(); } /// <summary> /// 加载PGP公钥 /// </summary> private static PgpPublicKey LoadPublicKey(string pubKeyPath) { using var keyStream = File.OpenRead(pubKeyPath); var pubRingBundle = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyStream)); foreach (PgpPublicKeyRing ring in pubRingBundle.GetKeyRings()) { foreach (PgpPublicKey key in ring.GetPublicKeys()) { if (key.IsEncryptionKey) { return key; } } } throw new InvalidDataException("未找到可用的加密公钥"); } /// <summary> /// 加载PGP私钥 /// </summary> private static PgpPrivateKey LoadPrivateKey(string privKeyPath, string password) { using var keyStream = File.OpenRead(privKeyPath); var privRingBundle = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(keyStream)); foreach (PgpSecretKeyRing ring in privRingBundle.GetKeyRings()) { foreach (PgpSecretKey key in ring.GetSecretKeys()) { if (key.IsSigningKey) { return key.ExtractPrivateKey(password.ToCharArray()); } } } throw new InvalidDataException("未找到可用的签名私钥"); } }
使用示例
// 调用示例 PgpFileHandler.SignAndEncrypt( inputPath: @"D:\docs\raw_file.pdf", outputPath: @"D:\docs\signed_encrypted_file.pgp", senderPrivKeyPath: @"D:\keys\my_private_key.asc", privKeyPassword: "my_secure_password", recipientPubKeyPath: @"D:\keys\recipient_public_key.asc" );
注意事项
- 确保私钥、公钥文件为标准PGP格式(通常是.asc或.gpg后缀)。
- 如果不需要生成ASCII装甲格式的文件,可将
ArmoredOutputStream替换为BufferedStream。 - 签名私钥需妥善保管,泄露后可能导致签名被伪造。
内容的提问来源于stack exchange,提问作者gordana
相关产品推荐
相关产品推荐

