我看过许多帖子,遵循了许多教程,但似乎都没有奏效。有时,它们会引用一些未找到的类。我可以指向一个地方,在那里我可以获得一个简单的教程,展示如何加密和解密文件。
我对 Pgp 很陌生,欢迎任何帮助。
我看过许多帖子,遵循了许多教程,但似乎都没有奏效。有时,它们会引用一些未找到的类。我可以指向一个地方,在那里我可以获得一个简单的教程,展示如何加密和解密文件。
我对 Pgp 很陌生,欢迎任何帮助。
我知道这个问题已经有好几年了,但它在 Google 中仍然是使用 Bouncy Castle 进行与 PGP 解密相关的搜索的第一或第二。由于似乎很难找到一个完整、简洁的示例,因此我想在这里分享我的工作解决方案来解密 PGP 文件。这只是其源文件中包含的 Bouncy Castle 示例的修改版本。
using System;
using System.IO;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Utilities.IO;
namespace PGPDecrypt
{
class Program
{
static void Main(string[] args)
{
DecryptFile(
@"path_to_encrypted_file.pgp",
@"path_to_secret_key.asc",
"your_password_here".ToCharArray(),
"output.txt"
);
}
private static void DecryptFile(
string inputFileName,
string keyFileName,
char[] passwd,
string defaultFileName)
{
using (Stream input = File.OpenRead(inputFileName),
keyIn = File.OpenRead(keyFileName))
{
DecryptFile(input, keyIn, passwd, defaultFileName);
}
}
private static void DecryptFile(
Stream inputStream,
Stream keyIn,
char[] passwd,
string defaultFileName)
{
inputStream = PgpUtilities.GetDecoderStream(inputStream);
try
{
PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
PgpEncryptedDataList enc;
PgpObject o = pgpF.NextPgpObject();
//
// the first object might be a PGP marker packet.
//
if (o is PgpEncryptedDataList)
{
enc = (PgpEncryptedDataList)o;
}
else
{
enc = (PgpEncryptedDataList)pgpF.NextPgpObject();
}
//
// find the secret key
//
PgpPrivateKey sKey = null;
PgpPublicKeyEncryptedData pbe = null;
PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(
PgpUtilities.GetDecoderStream(keyIn));
foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
{
sKey = FindSecretKey(pgpSec, pked.KeyId, passwd);
if (sKey != null)
{
pbe = pked;
break;
}
}
if (sKey == null)
{
throw new ArgumentException("secret key for message not found.");
}
Stream clear = pbe.GetDataStream(sKey);
PgpObjectFactory plainFact = new PgpObjectFactory(clear);
PgpObject message = plainFact.NextPgpObject();
if (message is PgpCompressedData)
{
PgpCompressedData cData = (PgpCompressedData)message;
PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream());
message = pgpFact.NextPgpObject();
}
if (message is PgpLiteralData)
{
PgpLiteralData ld = (PgpLiteralData)message;
string outFileName = ld.FileName;
if (outFileName.Length == 0)
{
outFileName = defaultFileName;
}
Stream fOut = File.Create(outFileName);
Stream unc = ld.GetInputStream();
Streams.PipeAll(unc, fOut);
fOut.Close();
}
else if (message is PgpOnePassSignatureList)
{
throw new PgpException("encrypted message contains a signed message - not literal data.");
}
else
{
throw new PgpException("message is not a simple encrypted file - type unknown.");
}
if (pbe.IsIntegrityProtected())
{
if (!pbe.Verify())
{
Console.Error.WriteLine("message failed integrity check");
}
else
{
Console.Error.WriteLine("message integrity check passed");
}
}
else
{
Console.Error.WriteLine("no message integrity check");
}
}
catch (PgpException e)
{
Console.Error.WriteLine(e);
Exception underlyingException = e.InnerException;
if (underlyingException != null)
{
Console.Error.WriteLine(underlyingException.Message);
Console.Error.WriteLine(underlyingException.StackTrace);
}
}
}
private static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyID, char[] pass)
{
PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyID);
if (pgpSecKey == null)
{
return null;
}
return pgpSecKey.ExtractPrivateKey(pass);
}
}
}
这个怎么样:
Bouncycastle PGP 解密期间的 PartialInputStream
此外,zip 包含此处的示例:
http://www.bouncycastle.org/csharp/
希望这可以帮助。如果您仍然卡住,请发布有关编译器抱怨哪些类的更多详细信息,社区将会查看。
现在,在 2021 年,Nikhil 的答案可能是最好的,因为它抽象出了直接使用 BouncyCastle 的需求。去给他点个赞吧。
如果您出于某种原因想直接使用 BouncyCastle,我有 Dan 的答案的现代实现,以及他正在使用的示例,它直接在 NET5 中使用 BouncyCastle。看一看:
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.IO;
安装的是 Nuget Package Portable.BouncyCastle 1.8.10。
public class EncryptionService
{
public static void EncryptPGPFile(FileInfo inFile, FileInfo keyFile, FileInfo outFile, bool withIntegrityCheck = false, bool withArmor = false)
{
PgpPublicKeyRingBundle keyRing = null;
using (var keyStream = keyFile.OpenRead())
{
keyRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyStream));
}
var publicKey = keyRing.GetKeyRings()
.Cast<PgpPublicKeyRing>()
.FirstOrDefault()
?.GetPublicKeys()
.Cast<PgpPublicKey>()
.FirstOrDefault(x => x.IsEncryptionKey);
using var outFileStream = outFile.Open(FileMode.Create);
using var armoredStream = new ArmoredOutputStream(outFileStream);
Stream outStream = withArmor ? armoredStream : outFileStream;
byte[] compressedBytes;
var compressor = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
using (var byteStream = new MemoryStream())
{
// Annoyingly, this is necessary. The compressorStream needs to be closed before the byteStream is read from, otherwise
// data will be left in the buffer and not written to the byteStream. It would be nice if compressorStream exposed a "Flush"
// method. - AJS
using (var compressorStream = compressor.Open(byteStream))
{
PgpUtilities.WriteFileToLiteralData(compressorStream, PgpLiteralData.Binary, inFile);
}
compressedBytes = byteStream.ToArray();
};
var encrypter = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
encrypter.AddMethod(publicKey);
using var finalOutputStream = encrypter.Open(outStream, compressedBytes.Length);
finalOutputStream.Write(compressedBytes, 0, compressedBytes.Length);
}
public static void DecryptPGPFile(FileInfo inFile, FileInfo keyFile, string password, FileInfo outFile)
{
using var inputFile = inFile.OpenRead();
using var input = PgpUtilities.GetDecoderStream(inputFile);
var pgpFactory = new PgpObjectFactory(input);
var firstObject = pgpFactory.NextPgpObject();
if (firstObject is not PgpEncryptedDataList)
{
firstObject = pgpFactory.NextPgpObject();
}
PgpPrivateKey keyToUse = null;
PgpSecretKeyRingBundle keyRing = null;
using (var keyStream = keyFile.OpenRead())
{
keyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(keyStream));
}
var encryptedData = ((PgpEncryptedDataList)firstObject).GetEncryptedDataObjects()
.Cast<PgpPublicKeyEncryptedData>()
.FirstOrDefault(x =>
{
var key = keyRing.GetSecretKey(x.KeyId);
if (key != null)
{
keyToUse = key.ExtractPrivateKey(password.ToCharArray());
return true;
}
return false;
});
if (keyToUse == null)
{
throw new PgpException("Cannot find secret key for message.");
}
Stream clearText = encryptedData.GetDataStream(keyToUse);
PgpObject message = new PgpObjectFactory(clearText).NextPgpObject();
if (message is PgpCompressedData data)
{
message = new PgpObjectFactory(inputStream: data.GetDataStream()).NextPgpObject();
}
if (message is PgpLiteralData literalData)
{
using var outputFileStream = outFile.Open(FileMode.Create);
Streams.PipeAll(literalData.GetInputStream(), outputFileStream);
}
else
{
throw new PgpException("message is not encoded correctly.");
}
if (encryptedData.IsIntegrityProtected() && !encryptedData.Verify())
{
throw new Exception("message failed integrity check!");
}
}
}