Bouncy Castle is a great open source resource. However, the off-the-shelf PGP functionality is severely lacking in real-world-usabaility. Most of what you need is easy enough to code up yourself (and I would love to contribute what I’ve done if I could). One thing that you really need that doesn’t come built-in and is actually quite hard to do right is PGP Single Pass Sign and Encrypt. Here’s a class in the style of csharp\crypto\test\src\openpgp\examples\KeyBasedFileProcessor.cs that does exactly that.
using System;
using System.IO;
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
namespace PgpCrypto
{
public class PgpProcessor
{
public void SignAndEncryptFile(string actualFileName, string embeddedFileName,
Stream keyIn, long keyId, Stream outputStream,
char[] password, bool armor, bool withIntegrityCheck, PgpPublicKey encKey)
{
const int BUFFER_SIZE = 1 << 16; // should always be power of 2
if (armor)
outputStream = new ArmoredOutputStream(outputStream);
// Init encrypted data generator
PgpEncryptedDataGenerator encryptedDataGenerator =
new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
encryptedDataGenerator.AddMethod(encKey);
Stream encryptedOut = encryptedDataGenerator.Open(outputStream, new byte[BUFFER_SIZE]);
// Init compression
PgpCompressedDataGenerator compressedDataGenerator = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
Stream compressedOut = compressedDataGenerator.Open(encryptedOut);
// Init signature
PgpSecretKeyRingBundle pgpSecBundle = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn));
PgpSecretKey pgpSecKey = pgpSecBundle.GetSecretKey(keyId);
if (pgpSecKey == null)
throw new ArgumentException(keyId.ToString("X") + " could not be found in specified key ring bundle.", "keyId");
PgpPrivateKey pgpPrivKey = pgpSecKey.ExtractPrivateKey(password);
PgpSignatureGenerator signatureGenerator = new PgpSignatureGenerator(pgpSecKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
signatureGenerator.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
foreach (string userId in pgpSecKey.PublicKey.GetUserIds())
{
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
spGen.SetSignerUserId(false, userId);
signatureGenerator.SetHashedSubpackets(spGen.Generate());
// Just the first one!
break;
}
signatureGenerator.GenerateOnePassVersion(false).Encode(compressedOut);
// Create the Literal Data generator output stream
PgpLiteralDataGenerator literalDataGenerator = new PgpLiteralDataGenerator();
FileInfo embeddedFile = new FileInfo(embeddedFileName);
FileInfo actualFile = new FileInfo(actualFileName);
// TODO: Use lastwritetime from source file
Stream literalOut = literalDataGenerator.Open(compressedOut, PgpLiteralData.Binary,
embeddedFile.Name, actualFile.LastWriteTime, new byte[BUFFER_SIZE]);
// Open the input file
FileStream inputStream = actualFile.OpenRead();
byte[] buf = new byte[BUFFER_SIZE];
int len;
while ((len = inputStream.Read(buf, 0, buf.Length)) > 0)
{
literalOut.Write(buf, 0, len);
signatureGenerator.Update(buf, 0, len);
}
literalOut.Close();
literalDataGenerator.Close();
signatureGenerator.Generate().Encode(compressedOut);
compressedOut.Close();
compressedDataGenerator.Close();
encryptedOut.Close();
encryptedDataGenerator.Close();
inputStream.Close();
if (armor)
outputStream.Close();
}
}
}

Subscribe
June 23, 2008 at 1:15 pm
[...] Files Method in C# Unit Testing May 6, 2008 — jopincar I’ve been working on a class that wraps the low-level PGP crypto capabilities of Bouncy Castle and presents a higher-level, [...]
September 9, 2008 at 8:38 am
This example doesn’t work.
Signer SHA1WITHELGAMAL not recognised.
September 9, 2008 at 8:45 am
Nevermind. I got the keys mixed up. It should have been a DSA key sorry.
December 12, 2008 at 10:45 am
[...] – bookmarked by 6 members originally found by ndb3dgj on 2008-11-06 PGP Single Pass Sign and Encrypt with Bouncy Castle http://jopinblog.wordpress.com/2008/06/23/pgp-single-pass-sign-and-encrypt-with-bouncy-castle/ – [...]
January 23, 2009 at 4:20 am
[...] We found a few samples online, but nothing I felt comfortable to use in our codebase. Credits to John Opincar who published a post on single pass encryption and signing. We used the blog post of his, the [...]
February 26, 2009 at 9:00 pm
Thanks for sharing your code, Do you have a single pass decryption for a signed and encrypted file.
Thanks,
March 3, 2009 at 9:00 am
That’s already built in to Bouncey Castle.
October 30, 2009 at 7:29 am
Thank you. I ported this for a Java project I was working on. It solved my problem.