Click here to Skip to main content
14,212,683 members
Click here to Skip to main content
Posted 2 Oct 2012

Tagged as


60 bookmarked

PGP Encryption with C#

Rate this:
4.91 (21 votes)
Please Sign up or sign in to vote.
4.91 (21 votes)
6 Jan 2013     CPOL    
Encrypting and Decrypting Files with GnuPG

What You'll Need

You will need to download the following two components for the encryption performed in this article:

  1. Gpg for Windows
  2. Starksoft OpenPGP component for .NET (see note at end of article regarding this component).


Where you need to encrypt data using PGP, GnuPG is an excellent choice to get the job done.  And with the Starksoft OpenPGP Component for .NET, we can write against an API which interacts with GnuPG to enable integration with your custom .NET apps.

Install GnuPG for Windows

The first step is to install GnuPG for Windows. Go to the GnuPG for Windows site, download the exe, and run the installer.  (Make it easier on yourself and accept the default location for where it will be installed.)

Before we write a line of code, we need to create a key for encryption/decryption.

Basic Step by Step Tutorial for GPG Usage

I am by no means an expert, so this is a very basic tutorial on usage of GPG. It’s just enough to get you up and running.

PGP encryption uses Public-key Cryptography. So, to truly test this out, you should have  two computers (either physical or virtual). The first computer (Computer A) should create a private key, then export it as a public key.  Then Computer B can use that public key to encrypt some data, which it can then transmit to Computer A. At that point, Computer A can use its private key to decrypt that data.

So, fire up Computer A first and create a private key. Do this by running the command:

gpg --gen-key

See the screenshot below for how I answered the questions that followed. You can accept defaults by pressing  Enter. A couple of questions prompt you to enter a letter.  In those cases, the default is in brackets.

Key Creation

Note the dialog box which is launched to capture the all-important pass-phrase. Do not forgot that pass-phrase. You will require it to decrypt anything which is encrypted with that key.

You can view your keys by entering the command:

gpg --list-keys

OK. Now that we have a private key on our key-ring, we can export it as a public key. You can do that by entering the following command,  using the comment which you input when you create your private key (you can see from the screenshot above that I used the comment "For private encrypted stuff"):

gpg --armor --output pubkey.txt --export 'For private encrypted stuff'

That will create a text file called pubkey.txt in the folder which has context vis-a-vis the Console in which you ran that command. (Or you could create it with a full  path - e.g., "D:\pubkey.txt".)

Now, on to the encryption. We will now move to Computer B. Computer B should also have GPG for Windows installed on it. To import the key (that we just exported above) onto Computer B, run:

gpg --import "D:\pubkey.txt"

And that's it. We can now move onto some code! We will use the imported key to encrypt some data. Then, at a later stage, we can take that encrypted data back to Computer A where we will decrypt it.

Create the Contract for the Encryption Service

First off, we will create a contract for our service to clearly delineate exactly what it will do. So, create a Visual Studio solution, add a  Class Library (name it "Contracts"),  and add the following interface to the class library:

public interface IEncryptionService
    FileInfo EncryptFile(string keyUserId, string sourceFile, string encryptedFile);

The EncryptFile method will return a FileInfo object representing the encrypted file that is created during the operation. Now, we will implement that interface.

Create the Encryption Service

Add another new project to your solution called "Service".

Create a new class called EncryptionService which will implement our interface. Add a reference to the Contracts project which contains the  IEncryptionService interface.  Then you will need to download the Starksoft OpenPGP component for .NET. (At the time of writing, this component is being migrated from SourceForge to CodePlex.  So, if you cannot find it on the Internet, just use the copy included with the download code for this article.)

Then, implement that IEncryptionService interface:

public class EncryptionService : IEncryptionService
    private GnuPG gpg = new GnuPG();
    private string appPath;

    public EncryptionService()

    public EncryptionService(string appPath)
        this.appPath = appPath;

    public FileInfo EncryptFile(string keyUserId, string sourceFile, string encryptedFile)
        // check parameters
        if (string.IsNullOrEmpty(keyUserId))
            throw new ArgumentException("keyUserId parameter is either empty or null", "keyUserId");
        if (string.IsNullOrEmpty(sourceFile))
            throw new ArgumentException("sourceFile parameter is either empty or null", "sourceFile");
        if (string.IsNullOrEmpty(encryptedFile))
            throw new ArgumentException("encryptedFile parameter is either empty or null", "encryptedFile");
        // Create streams - one for the unencrypted source file and one for the decrypted destination file
        using (Stream sourceFileStream = new FileStream(sourceFile, FileMode.Open))
            using (Stream encryptedFileStream = new FileStream(encryptedFile, FileMode.Create))
                //  Specify the directory containing gpg.exe (not sure why).
                gpg.BinaryPath = Path.GetDirectoryName(appPath);
                gpg.Recipient = keyUserId;
                //  Perform encryption
                gpg.Encrypt(sourceFileStream, encryptedFileStream);
                return new FileInfo(encryptedFile);

The constructor sets the path to the gpg2 executable. If you performed a vanilla install, that path will be something like  C:\Program Files\GNU\GnuPG\pub\gpg2.exe. The encryption operation simply uses the Starksoft component to encrypt the file from the source stream to the destination stream.

Note that when specifying the BinaryPath of the GnuPG object, you need to assign the directory which is the parent of  that of the executable. I'm not sure why that is the case; trial  and error is how I figured that out.

The Starksoft library does have a couple of custom Exception classes (GnuPGBadPassphraseExceptionGnuPGException), but they don’t add any special  custom members. That being the case, being mere wrappers of the System.Exception class, we’ll let them propagate to the caller as is in our service.

So, if we run that EncryptFile method on a file on Computer B, we will have an PGP-encrypted file which can only be decrypted by the party holding the private key. Now, we'll turn our minds to decryption.

Augment the Contract for the Encryption Service

The Encryption service so far, only contains the one method EncryptFile. We will now add a second method for decrypting the file:
public interface IEncryptionService
    FileInfo DecryptFile(string encryptedSourceFile, string decryptedFile);
    FileInfo EncryptFile(string keyUserId, string sourceFile, string encryptedFile);    

The DecryptFile method will return a FileInfo object representing the decrypted file that is created during the operation.

Augment the Encryption Service

In the EncryptionService we will implement the DecryptFile method as follows:

public FileInfo DecryptFile(string encryptedSourceFile, string decryptedFile)
    // check parameters
    if (string.IsNullOrEmpty(encryptedSourceFile))
        throw new ArgumentException("encryptedSourceFile parameter is either empty or null", "encryptedSourceFile");
    if (string.IsNullOrEmpty(decryptedFile))
        throw new ArgumentException("decryptedFile parameter is either empty or null", "decryptedFile");
    using (FileStream encryptedSourceFileStream = new FileStream(encryptedSourceFile, FileMode.Open))
        //  make sure the stream is at the start.
        encryptedSourceFileStream.Position = 0;
        using (FileStream decryptedFileStream = new FileStream(decryptedFile, FileMode.Create))
            //  Specify the directory containing gpg.exe (again, not sure why).
            gpg.BinaryPath = Path.GetDirectoryName(appPath);
            //  Decrypt
            gpg.Decrypt(encryptedSourceFileStream, decryptedFileStream);
    return new FileInfo(decryptedFile);

As you can see, we create a FileStream object for both the encrypted source file and the resulting decryted target file. With the help of the Starksoft OpenPGP component, we can pass the two streams into the Decrypt method of the gpg object and this will invoke the external Gpg for Windows executable which will open a dialog that requires us to enter the passphrase which we created for this key (note that the dialog may take a few seconds to display, as GnuPG for Windows is coming in to do its part).

So, if we take our encrypted file back to Computer A and run the DecryptFile method on it, once we enter the correct passphrase, the stream will be decrypted and our original file will now be decrypted.

Things to Consider

In this article, I have outlined an approach for implementing PGP encryption by invoking a 3rd party component through C#. This raises a few questions. Why didn't I implement PGP encryption myself? Why hand over control to a 3rd party component to perform the actual encryption/decryption operations?

This is always a cost/benefit analysis:

  • Ask yourself, "am I a cryptography expert". The good people who wrote GnuPG are. I am not.
  • There will be a significant decrease in development time if you do not have to implement PGP yourself. Encryption of non-text data also raises the difficulty level, which you will need to consider if you have to encrypt pdfs or some such. Definite benefit here.
  • However, you will be sacrificing control. When you invoke GnuPG, you are going out of process. Using Gpg for Windows, you don't even have control over the dialogs which the user needs to input data into. This will be important if you want to change the look and feel of those dialogs.

So, this approach will not be the right decision every time. But in many cases, it is a nice affordable solution to the encryption problem.


As noted, this is a very basic demonstration of the encryption capabilities of GnuPG and the .NET Starksoft component which enable us to interact with it.  And as mentioned earlier in the article, the Starksoft component is in the process of being migrated to CodePlex as part of the Biko project.  For the time being, the DLL in the download code for that component is fine.

I hope this article will serve as a helpful introduction to using C# for PGP encryption/decryption.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

David Rogers Dev
Software Developer
Australia Australia
A mid-level developer writing .NET code to provide business solutions to a wide range of customer requirements.

Comments and Discussions

QuestionBasic PGP Question Pin
Talal Zahid6-Sep-16 10:47
professionalTalal Zahid6-Sep-16 10:47 
Questionbinary path to GnuPG executable invalid or file permissions do not allow access Pin
Member 1249853324-Aug-16 15:28
memberMember 1249853324-Aug-16 15:28 
QuestionStarksoft.Aspen.GnuPG Pin
FaresDZ2515-Apr-16 4:19
memberFaresDZ2515-Apr-16 4:19 
QuestionStarksoft.Aspen.GnuPG not working Pin
Member 122459625-Jan-16 10:13
memberMember 122459625-Jan-16 10:13 
AnswerRe: Starksoft.Aspen.GnuPG not working Pin
FaresDZ2515-Apr-16 5:42
memberFaresDZ2515-Apr-16 5:42 
QuestionDoesn't find gpg.exe Pin
D Hartman28-Aug-15 4:43
memberD Hartman28-Aug-15 4:43 
AnswerRe: Doesn't find gpg.exe Pin
Member 116326164-Sep-15 1:13
memberMember 116326164-Sep-15 1:13 
SuggestionStarksoft Aspen GnuPG library / API Pin
CotBySloths28-Jul-15 6:51
memberCotBySloths28-Jul-15 6:51 
GeneralRe: Starksoft Aspen GnuPG library / API Pin
D Hartman28-Aug-15 5:22
memberD Hartman28-Aug-15 5:22 
GeneralThank you for the good sample Pin
meowling12-Jul-15 23:18
membermeowling12-Jul-15 23:18 
QuestionkeyUserID Pin
Member 1169883317-May-15 23:50
memberMember 1169883317-May-15 23:50 
QuestionGetting a blank file when decrypting Pin
Member 1160746114-Apr-15 10:11
memberMember 1160746114-Apr-15 10:11 
AnswerRe: Getting a blank file when decrypting Pin
David Rogers Dev13-May-15 20:29
memberDavid Rogers Dev13-May-15 20:29 
QuestionI have a question about form file type Pin
Member 1155853826-Mar-15 10:08
memberMember 1155853826-Mar-15 10:08 
QuestionAdding multiple key while Encrypting Pin
Tim8w29-Sep-14 8:27
memberTim8w29-Sep-14 8:27 
GeneralMy vote of 5 Pin
Member 1089064318-Jun-14 20:25
memberMember 1089064318-Jun-14 20:25 
GeneralRe: My vote of 5 Pin
David Rogers Dev19-Jun-14 15:10
memberDavid Rogers Dev19-Jun-14 15:10 
QuestionPassphrase not needed Pin
Carlos Mora A21-Nov-13 5:18
memberCarlos Mora A21-Nov-13 5:18 
AnswerRe: Passphrase not needed Pin
David Rogers Dev22-Nov-13 12:38
memberDavid Rogers Dev22-Nov-13 12:38 
AnswerRe: Passphrase not needed Pin
jfriedman31-Jan-14 6:03
professionaljfriedman31-Jan-14 6:03 
GeneralRe: Passphrase not needed Pin
David Rogers Dev31-Jan-14 15:26
memberDavid Rogers Dev31-Jan-14 15:26 
GeneralRe: Passphrase not needed Pin
jfriedman31-Jan-14 15:44
professionaljfriedman31-Jan-14 15:44 
GeneralRe: Passphrase not needed Pin
David Rogers Dev1-Feb-14 12:24
memberDavid Rogers Dev1-Feb-14 12:24 
GeneralRe: Passphrase not needed Pin
chigz_fj25-Nov-14 9:22
memberchigz_fj25-Nov-14 9:22 
GeneralRe: Passphrase not needed Pin
David Rogers Dev27-Nov-14 14:45
memberDavid Rogers Dev27-Nov-14 14:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Layout: fixed | fluid

Article Copyright 2012 by David Rogers Dev
Everything else Copyright © CodeProject, 1999-2019

Server Web01
Version 2.8.190619.2