PGP Decryption with C#

PGP Decryption Pictogram

PGP Decryption Pictogram

One of my recent projects was to create a Windows desktop application that would allow a user to select a PGP encrypted file, select and output destination and click a button to have that file decrypted. There were a few other things the application needed to do, like verify the information in the file, but that was the easy part.

The real challenge was to load up the public and private key rings and decrypt the source file. I have a pretty good understanding of the concepts behind PGP (symmetric key) encryption, so it seemed like a fairly straight forward project. However, as most software developers know, perception and reality rarely align.

I started out looking for a .Net library that would encapsulate all of the PGP processes for me. Turns out, there are several, but most of them are commercial products and there just wasn’t any money in the project budget for that. So I keep looking and eventually, I came across the Legion of the Bouncy Castle, which provides an extensive encryption library. It was originally for Java, but has been ported to C#. Perfect!

This thing's got class(es)!

This thing's got class(es)!

I downloaded the non-IDEA library, referenced it in my project and voila! Except, not so much. There was a ton classes, but nothing referencing OpenPGP directly, and that’s what I needed.

I read through a ton of information on the Bouncy Castle site, and it looks like there should be a .OpenPgp class included. So I spent a bit more time searching through Google to find an example or two of others that were already using Bouncy Castle in C#.

If you’ve been trying to do the same thing, you already know that there aren’t very many good samples out there. I did find an excellent piece on how to encrypt files using PGP and the Bouncy Castle library by the .Net Geek. If you’re looking to encrypt files, this is a great place to start. I’ve incorporated this code into my crypto library that is below. I’ve also included links to a number of sites and articles that I read while working on this project. I hope you will find this information useful as well.

With a good example in hand, I started working out how to make the decryption side of things work. Again, its fairly straightforward, you just need to know what sort of stream you’re looking for at each stage of the process. Similar to the .Net Geek, I like to figure out how I’m going to consume the provider before I write it. That helps to make sure that the classes are easy to use and work like I’m expecting. I’ve provided a sample application and a crypto wrapper library at the bottom of this entry. Feel free to jump ahead.

All I wanted to do from my application was call the decryption routine and pass in the path to the encrypted file.

?View Code CSHARP
1
2
3
4
public bool DecryptFile(string encryptedFilePath)
{
    return decryptInputFile(encryptedFilePath);
}

The next step is setup the crypto wrapper and actually decode the file. I decided that I would simply remove the .gpg from the end of my encrypted file and use that as the destination file. In my case, I also had to process this intermediate file to ensure that all of the information was valid.

?View Code CSHARP
1
2
3
4
5
6
string outputFile = extractOutputFileName(encryptedFileName);
 
private string extractOutputFileName(string encryptedFileName)
{
      return encryptedFileName.Substring(0, encryptedFileName.LastIndexOf('.'));
}

Now I need to get everything ready to call the decrypt and verify method in the cryptography library. In my particular implementation, I wanted to be able to say that the decryption failed, but it wasn’t important to the end user exactly why, so it’s just true or false.

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private bool decryptInputFile(string encryptedFileName)
{
     bool returnCode;
     string outputFile = extractOutputFileName(encryptedFileName);
     try
     {
          SPL.Crypto.PgpEncryptionKeys keys = new PgpEncryptionKeys(publicKeyRingPath, secretKeyRingPath, passPhrase);
          PgpDecrypt decryptor = new PgpDecrypt(keys);
          Stream encryptedStream = new StreamReader(encryptedFileName).BaseStream;
          decryptor.DecryptAndVerify(encryptedStream, outputFile);
          returnCode = true;
     }
     catch (Exception)
     {
          // If there was an error, we're going to eat it and just let the user know we failed.
          returnCode = false;
     }
     return returnCode;
}

Once the decryption object had been setup, it was just a matter of invoking DecryptAndVerify. This method works through all of the different streams and transforms each into the next, finally resulting in the clear text document that we write out to the file system. None of the streams used in the decryption process are saved any where, they’re just kept in memory while they’re being used.

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void decryptAndVerify(Stream inputStream, string outputFilePath)
{
     PgpPublicKeyEncryptedData publicKeyED = extractPublicKeyEncryptedData(inputStream);
     PgpObject message = getClearCompressedMessage(publicKeyED);
 
     if (message is PgpCompressedData)
     {
         message = processCompressedMessage(message);
         PgpLiteralData literalData = (PgpLiteralData)message;
         using (Stream outputFile = File.Create(outputFilePath))
         {
            using (Stream literalDataStream = literalData.GetInputStream())
            {
                Streams.PipeAll(literalDataStream, outputFile);
            }
         }
     }
 
     return;
}

I’ll leave the details of how it all works to the samples and the cryptography library below. All of the source is included for your reference.

9/23/2009 UPDATE

I added the sample files from this post to GitHub. Feel free to access the sample files there too.

More Information:

  • Bouncy Castle – http://www.bouncycastle.org/
  • Karmin’s Blog – http://karym6.blogspot.com/2009/06/pgp-decryption-with-c.html
  • .Net Geek – http://blogs.microsoft.co.il/blogs/kim/archive/2009/01/23/pgp-zip-encrypted-files-with-c.aspx
  • Jesse’s Blog – http://elian.co.uk/post/2009/07/29/Bouncy-Castle-CSharp.aspx
  • Aaron Johnson – http://cephas.net/blog/2004/09/03/pgp-decryption-using-c/

Sample Files:

Be Sociable, Share!

Other awsome works, possibly related: