我看了很多帖子,跟了很多教程,但似乎都没用。有时候,他们提到一些找不到的类。请问能否指向一个可以获得简单教程的地方,展示如何加密和解密文件。
我对Pgp非常陌生,欢迎任何帮助。
我看了很多帖子,跟了很多教程,但似乎都没用。有时候,他们提到一些找不到的类。请问能否指向一个可以获得简单教程的地方,展示如何加密和解密文件。
我对Pgp非常陌生,欢迎任何帮助。
我知道这个问题已经有几年了,但是在与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的内容:
https://dev59.com/iVbTa4cB1Zd3GeqP8jV2
此外,里面还有一些示例文件:
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 包 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!");
}
}
}
plainFact.NextPgpObject();
,这将解决我的问题。非常感谢! - Mokh Akh