using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace PGPSnippet.PGPDecryption
private const int BufferSize = 0x10000;
public static void EncryptFile(string inputFile, string outputFile, string publicKeyFile, bool armor, bool withIntegrityCheck)
using (Stream publicKeyStream = File.OpenRead(publicKeyFile))
PgpPublicKey encKey = ReadPublicKey(publicKeyStream);
using (MemoryStream bOut = new MemoryStream())
PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
PgpUtilities.WriteFileToLiteralData(comData.Open(bOut), PgpLiteralData.Binary, new FileInfo(inputFile));
PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
byte[] bytes = bOut.ToArray();
using (Stream outputStream = File.Create(outputFile))
using (ArmoredOutputStream armoredStream = new ArmoredOutputStream(outputStream))
using (Stream cOut = cPk.Open(armoredStream, bytes.Length))
cOut.Write(bytes, 0, bytes.Length);
using (Stream cOut = cPk.Open(outputStream, bytes.Length))
cOut.Write(bytes, 0, bytes.Length);
public static void EncryptAndSign(string inputFile, string outputFile, string publicKeyFile, string privateKeyFile, string passPhrase, bool armor)
PgpEncryptionKeys encryptionKeys = new PgpEncryptionKeys(publicKeyFile, privateKeyFile, passPhrase);
if (!File.Exists(inputFile))
throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFile));
if (!File.Exists(publicKeyFile))
throw new FileNotFoundException(String.Format("Public Key file [{0}] does not exist.", publicKeyFile));
if (!File.Exists(privateKeyFile))
throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFile));
if (String.IsNullOrEmpty(passPhrase))
throw new ArgumentNullException("Invalid Pass Phrase.");
if (encryptionKeys == null)
throw new ArgumentNullException("Encryption Key not found.");
using (Stream outputStream = File.Create(outputFile))
using (ArmoredOutputStream armoredOutputStream = new ArmoredOutputStream(outputStream))
OutputEncrypted(inputFile, armoredOutputStream, encryptionKeys);
OutputEncrypted(inputFile, outputStream, encryptionKeys);
private static void OutputEncrypted(string inputFile, Stream outputStream, PgpEncryptionKeys encryptionKeys)
using (Stream encryptedOut = ChainEncryptedOut(outputStream, encryptionKeys))
FileInfo unencryptedFileInfo = new FileInfo(inputFile);
using (Stream compressedOut = ChainCompressedOut(encryptedOut))
PgpSignatureGenerator signatureGenerator = InitSignatureGenerator(compressedOut, encryptionKeys);
using (Stream literalOut = ChainLiteralOut(compressedOut, unencryptedFileInfo))
using (FileStream inputFileStream = unencryptedFileInfo.OpenRead())
WriteOutputAndSign(compressedOut, literalOut, inputFileStream, signatureGenerator);
private static void WriteOutputAndSign(Stream compressedOut, Stream literalOut, FileStream inputFile, PgpSignatureGenerator signatureGenerator)
byte[] buf = new byte[BufferSize];
while ((length = inputFile.Read(buf, 0, buf.Length)) > 0)
literalOut.Write(buf, 0, length);
signatureGenerator.Update(buf, 0, length);
signatureGenerator.Generate().Encode(compressedOut);
private static Stream ChainEncryptedOut(Stream outputStream, PgpEncryptionKeys m_encryptionKeys)
PgpEncryptedDataGenerator encryptedDataGenerator;
encryptedDataGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.TripleDes, new SecureRandom());
encryptedDataGenerator.AddMethod(m_encryptionKeys.PublicKey);
return encryptedDataGenerator.Open(outputStream, new byte[BufferSize]);
private static Stream ChainCompressedOut(Stream encryptedOut)
PgpCompressedDataGenerator compressedDataGenerator = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
return compressedDataGenerator.Open(encryptedOut);
private static Stream ChainLiteralOut(Stream compressedOut, FileInfo file)
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
return pgpLiteralDataGenerator.Open(compressedOut, PgpLiteralData.Binary, file);
private static PgpSignatureGenerator InitSignatureGenerator(Stream compressedOut, PgpEncryptionKeys m_encryptionKeys)
const bool IsCritical = false;
const bool IsNested = false;
PublicKeyAlgorithmTag tag = m_encryptionKeys.SecretKey.PublicKey.Algorithm;
PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(tag, HashAlgorithmTag.Sha1);
pgpSignatureGenerator.InitSign(PgpSignature.BinaryDocument, m_encryptionKeys.PrivateKey);
foreach (string userId in m_encryptionKeys.SecretKey.PublicKey.GetUserIds())
PgpSignatureSubpacketGenerator subPacketGenerator = new PgpSignatureSubpacketGenerator();
subPacketGenerator.SetSignerUserId(IsCritical, userId);
pgpSignatureGenerator.SetHashedSubpackets(subPacketGenerator.Generate());
pgpSignatureGenerator.GenerateOnePassVersion(IsNested).Encode(compressedOut);
return pgpSignatureGenerator;
#endregion Encrypt and Sign
public static void Decrypt(string inputfile, string privateKeyFile, string passPhrase, string outputFile)
if (!File.Exists(inputfile))
throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputfile));
if (!File.Exists(privateKeyFile))
throw new FileNotFoundException(String.Format("Private Key File [{0}] not found.", privateKeyFile));
if (String.IsNullOrEmpty(outputFile))
throw new ArgumentNullException("Invalid Output file path.");
using (Stream inputStream = File.OpenRead(inputfile))
using (Stream keyIn = File.OpenRead(privateKeyFile))
Decrypt(inputStream, keyIn, passPhrase, outputFile);
public static void Decrypt(Stream inputStream, Stream privateKeyStream, string passPhrase, string outputFile)
PgpObjectFactory pgpF = null;
PgpEncryptedDataList enc = null;
PgpPrivateKey sKey = null;
PgpPublicKeyEncryptedData pbe = null;
PgpSecretKeyRingBundle pgpSec = null;
pgpF = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream));
pgpSec = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream));
o = pgpF.NextPgpObject();
if (o is PgpEncryptedDataList)
enc = (PgpEncryptedDataList)o;
enc = (PgpEncryptedDataList)pgpF.NextPgpObject();
foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
sKey = FindSecretKey(pgpSec, pked.KeyId, passPhrase.ToCharArray());
throw new ArgumentException("Secret key for message not found.");
PgpObjectFactory plainFact = null;
using (Stream clear = pbe.GetDataStream(sKey))
plainFact = new PgpObjectFactory(clear);
PgpObject message = plainFact.NextPgpObject();
if (message is PgpCompressedData)
PgpCompressedData cData = (PgpCompressedData)message;
PgpObjectFactory of = null;
using (Stream compDataIn = cData.GetDataStream())
of = new PgpObjectFactory(compDataIn);
message = of.NextPgpObject();
if (message is PgpOnePassSignatureList)
message = of.NextPgpObject();
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
using (Stream output = File.Create(outputFile))
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, output);
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
using (Stream output = File.Create(outputFile))
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, output);
else if (message is PgpLiteralData)
PgpLiteralData ld = (PgpLiteralData)message;
string outFileName = ld.FileName;
using (Stream fOut = File.Create(outputFile))
Stream unc = ld.GetInputStream();
Streams.PipeAll(unc, fOut);
else if (message is PgpOnePassSignatureList)
throw new PgpException("Encrypted message contains a signed message - not literal data.");
throw new PgpException("Message is not a simple encrypted file - type unknown.");
#endregion commented code
private static PgpPublicKey ReadPublicKey(Stream inputStream)
inputStream = PgpUtilities.GetDecoderStream(inputStream);
PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(inputStream);
foreach (PgpPublicKeyRing kRing in pgpPub.GetKeyRings())
foreach (PgpPublicKey k in kRing.GetPublicKeys())
throw new ArgumentException("Can't find encryption key in key ring.");
private static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyId, char[] pass)
PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId);
return pgpSecKey.ExtractPrivateKey(pass);
#endregion Private helpers