Click here to Skip to main content
15,886,919 members
Articles / Programming Languages / C#
Article

Gnu Privacy Guard (GPG/PGP) for .NET [v1.0]

Rate me:
Please Sign up or sign in to vote.
4.94/5 (17 votes)
18 Sep 20033 min read 564.7K   8.7K   91   134
This article provides a C# wrapper class (GnuPGWrapper) that will enable use of GnuPG (the OpenPGP Internet encryption standard) within a .NET application.

Sample Image - GnuPGDotNet.jpg

Introduction

This article presents GnuPGWrapper v1.0, a wrapper class for GnuPG.

GnuPG stands for GNU Privacy Guard and is GNU's tool for secure communication and data storage. It can be used to encrypt data and to create digital signatures. It includes an advanced key management facility and is compliant with the proposed OpenPGP Internet standard as described in RFC 2440. As such, GnuPG is a complete and free replacement for PGP (Pretty Good Privacy).

This article provides a C# wrapper class (GnuPGWrapper) that will enable use of OpenPGP Internet encryption standard within a .NET world. It is shipped with a demo ASP.NET Web Form (GnuPG.aspx) which calls the wrapper class.

Installation

Prerequisites

  • Complete .NET Environment, e.g. Windows XP Professional + IIS 5.0 + .NET Framework SDK
  • GnuPG for Windows (more about GnuPG)

Procedure

Background

GnuPG ships as a command line program (gpg.exe) acting as a filter (reads from standard input and writes into standard output). Although suitable for scripting on UNIX systems (where calling a command line program from sh or bash is easy), it's pretty hard to integrate this in a production .NET environment.

The GnuPG Wrapper executes the command line program (gpg.exe) in a different process, redirects standard input (stdin), standard output (stdout) and standard error (stderr) streams, and monitors the streams to fetch the results of the encryption/signing operation.

Please note that you must have INSTALLED GnuPG AND generated/imported the appropriate keys before using this class. Refer to the GnuPG manual to do this...

Using the code

In order to use the wrapper class, you need to proceed as follows:

  1. Create an instance of the class
  2. Set the command property to the requested command (SignAndEncrypt, Encrypt, Decrypt, Sign, Verify)
  3. Optionally, set parameters for the command (home directory, originator, recipients, etc...)
  4. Call the ExecuteCommand method with input/output strings variables

The next sections show sample source code for the most command operation (SignAndEncrypt, Decrypt, Verify).

Encrypt and Sign

C#
// Reference My GnuPG wrapping class
using Emmanuel.Cryptography.GnuPG;

// Create GnuPG wrapping class
GnuPGWrapper gpg = new GnuPGWrapper();

// Set command
gpg.command = Commands.SignAndEncrypt;

// Set some parameters from on Web.Config file
gpg.homedirectory = Server.MapPath
       (ConfigurationSettings.AppSettings["homedirectory"]);
gpg.passphrase = ConfigurationSettings.AppSettings["passphrase"];

// Set other parameters from Web Controls
gpg.originator = FromTextBox.Text;
gpg.recipient = ToTextBox.Text;

// Declare input/output variables
// (input is also read from a Web control)
string inputText = MessageTextBox.Text;
string outputText = "";

// Execute GnuPG
gpg.ExecuteCommand(inputText, out outputText);

// Display output text
OutputTextBox.Text = outputText;
OutputTextBox.Visible = true;
ErrorMessage.Visible = false;
ExitCodeLabel.Text = gpg.exitcode.ToString();

Decrypt

C#
using Emmanuel.Cryptography.GnuPG;

GnuPGWrapper gpg = new GnuPGWrapper();

gpg.homedirectory = "C:\Inetpub\wwwroot\GnuPGDotNet\GnuPG"
gpg.passphrase = "My passphrase is so cool I can't remember it"
gpg.command = Commands.Decrypt;

// Execute GnuPG
string outputText = "";
gpg.ExecuteCommand("This is a test message.", out outputText);

// Display output text
[...].

Verify

C#
using Emmanuel.Cryptography.GnuPG;
GnuPGWrapper gpg = new GnuPGWrapper();

gpg.homedirectory = "C:\Inetpub\wwwroot\GnuPGDotNet\GnuPG"
gpg.passphrase = "My passphrase is so cool I can't remember it"
gpg.originator = "me@mycompany.com";
gpg.command = Commands.Verify;

// Execute GnuPG
string outputText = "";
gpg.ExecuteCommand("This is a test message.", out outputText);

// Display output text
[...].

Error handling

Error handling is done via a specific Exception class; method ExecuteCommand raises this exception whenever an error occurs. You calling application can handle this exception as follows:

C#
using Emmanuel.Cryptography.GnuPG;

    try 
    {

        GnuPGWrapper gpg = new GnuPGWrapper();

        gpg.homedirectory = "C:\Inetpub\wwwroot\GnuPGDotNet\GnuPG"
        gpg.passphrase = "My passphrase is so cool I can't remember it"
        gpg.originator = "me@mycompany.com";
        gpg.recipient = "you@yourcompany.com";
        gpg.command = Commands.SignAndEncrypt;

        // Execute GnuPG
        string outputText = "";
        gpg.ExecuteCommand("This is a test message.", out outputText);

        // Display output text
        [...]

    }
    catch (GnuPGException gpge)
    {
        // Display error message
        // Contains a clear text error message, 
        // either from the wrapper or from gpg.exe itself
        ErrorMessage.Text = gpge.Message; 
    }

Points of interest

The GnuPG wrapper:

  • Doesn't use any temporary files to store results; it directly uses streams/pipes.
  • Uses multiple threads to read data from standard input and standard error, preventing any deadlocks.
  • Uses configurable timeouts to prevent blocking calling applications in case of a system/program/process crash
  • Uses a configurable passphrase, which can be stored in a local configuration file (Web.Config) to prevent disclosure of the phrase

About GnuPG and PGP

This class has been developed and tested with GnuPG v1.2.0 (MingW32).

You can check the command line manual page for gpg.exe.

For more about GNU, please refer to http://www.gnu.org/. For more about GnuPG, please refer to http://www.gnupg.org/. For more about OpenPGP (RFC 2440), please refer to http://www.gnupg.org/rfc2440.html. For more about PGP, please refer to http://www.pgpi.org/.

History

  • Date posted: October 30th, 2002
  • Updated: September 19th, 2003

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
France France
Fell into computer software at the age of 11, founder of 3 startups, and now manager of an independent software vendor (ISV) labelled proSDK (www.prosdk.com)... And still a freeware writer and technical article author!

Comments and Discussions

 
QuestionError:gpg: test@abc.com: skipped: public key not found gpg: [stdin]: encryption failed: public key not found Pin
srikanth934113-Dec-17 20:50
srikanth934113-Dec-17 20:50 
QuestionPGP Encryption and Decryption Pin
Member 797647631-Jan-12 18:25
Member 797647631-Jan-12 18:25 
Questionsign and encrypt a file and deencrypt the same file Pin
kumaran_vr11-Nov-11 0:23
kumaran_vr11-Nov-11 0:23 
GeneralCan't encrypt message. Pin
abuswell21-Sep-10 11:32
abuswell21-Sep-10 11:32 
GeneralGot error on decrypting PGP file Pin
baiju@ispg.in30-Mar-10 20:12
baiju@ispg.in30-Mar-10 20:12 
Questionhow to solve Error - secret key not available Pin
SurajBRane198525-Mar-10 22:45
SurajBRane198525-Mar-10 22:45 
GeneralI've figure out many of the problems with this code Pin
Matthew Knapp31-Dec-09 5:36
Matthew Knapp31-Dec-09 5:36 
GeneralNew problem!!!ever seen!!!! Pin
satyasaradhi9-Nov-09 16:08
satyasaradhi9-Nov-09 16:08 
GeneralHome Directory Pin
Member 461822220-Oct-09 3:27
Member 461822220-Oct-09 3:27 
Questionzip file non existant? Pin
smhouston28-Sep-09 0:28
smhouston28-Sep-09 0:28 
GeneralSlight Tweak for Easier Use Pin
Member 343327815-Jul-09 14:27
Member 343327815-Jul-09 14:27 
QuestionHow to encrypt and decrypt a file? Pin
a8a9998-Jun-09 10:51
a8a9998-Jun-09 10:51 
AnswerRe: How to encrypt and decrypt a file? Pin
Ben Adler22-Jun-11 8:24
Ben Adler22-Jun-11 8:24 
GeneralError when calling the ExecuteCommand Pin
mpstrick@gmail.com30-Sep-08 5:29
mpstrick@gmail.com30-Sep-08 5:29 
GeneralRe: Error when calling the ExecuteCommand Pin
Member 448632230-Dec-08 2:39
Member 448632230-Dec-08 2:39 
Ranthomedirectory sets _bindirectory, which guarantees "System cannot find the file specified" error Pin
mcgmatt17-Sep-08 17:35
mcgmatt17-Sep-08 17:35 
GeneralRe: homedirectory sets _bindirectory, which guarantees "System cannot find the file specified" error Pin
Member 461822220-Oct-09 3:32
Member 461822220-Oct-09 3:32 
Generalgpg4win - doesn't encrypt a file over 900kb Pin
wbcintsol19-May-08 15:22
wbcintsol19-May-08 15:22 
GeneralRe: gpg4win - doesn't encrypt a file over 900kb Pin
Member 448632227-May-08 2:45
Member 448632227-May-08 2:45 
Generalpublic key not found: problem and solution [modified] Pin
Stephen Watson30-Jul-07 0:44
Stephen Watson30-Jul-07 0:44 
Prior to testing this wrapper, I installed gpg4win and used the WinPT desktop utility to create and import keys. But the wrapper always gave the error “public key not found”.

The cause turned out to be the location of the key files. With a little detective work I discovered that by default, pgp.exe keeps its key files under the user’s profile – in this folder:

C:\Documents and Settings\(user)\Application Data\gnupg

WinPT uses the default files, but GnuPGWrapper overrides this by supplying pgp.exe with a –homedir parameter taken from its “homedirectory” property. That meant that the wrapper was using a different set of key files from the WinPT tool. No wonder the public key was not found.

If you do not supply a home directory, then the wrapper cannot find the pgp.exe program, which it expects to find in the same folder as the keys. (This is not very tidy since one might well want to separate keys from executables.)

In fact, it turns out the wrapper does have a separate variable – bindirectory – for the pgp.exe path, but it is simply copies the homedirectory property into this variable (comment: “For now, let's assume the gpg.exe program is installed in the homedirectory too”). So we can improve things by removing the line below this comment, and adding an explict bindirectory property…

public string bindirectory
{
set
{
_bindirectory = value;
}
}

We can then supply this property with the path to pgp.exe, while leaving homedirectory unset. When called via the wrapper, pgp.exe then works OK using its default keys, as exposed by the WinPT GUI tool.

However, this solution means that the website or application that uses the wrapper must be running under the same user that ran WinPT to create the keys – or have administrator privileges – because the keys are saved in the users profile. Neither is particularly desirable. In fact you might want to run WinPT on your desktop while your application is on a production server.

An alternative solution would be to change the home directory used by WinPT. There is an option for this under Edt -> Preferences -> GPG preferences, but it’s greyed and cannot be changed. Gotya! Or maybe not…

Here’s my solution. Copy the key files from WinPT’s folder (C:\Documents and Settings\(user)\Application Data\gnupg ) to a folder that you know will be accessible to your application, and set homedirectory to point to that. The files to copy are secring.gpg, pubring.gpg and trustdb.gpg.

If you had the same problem, hope you find this useful.


-- modified at 6:56 Monday 30th July, 2007
GeneralRe: public key not found: problem and solution Pin
berghain7-Sep-07 3:28
berghain7-Sep-07 3:28 
QuestionRe: public key not found: problem and solution Pin
roopam_vishwam6-May-08 19:43
roopam_vishwam6-May-08 19:43 
AnswerRe: public key not found: problem and solution Pin
vikasprasad16-Nov-10 23:53
vikasprasad16-Nov-10 23:53 
GeneralRe: public key not found: problem and solution [modified] Pin
kapildhir 1-Aug-13 2:13
kapildhir 1-Aug-13 2:13 
GeneralRe: public key not found: problem and solution [modified] Pin
xxovariusxx2-Mar-16 4:16
xxovariusxx2-Mar-16 4:16 

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.