Introduction
Suppose you need to decrypt and process a PGP / GnuPG encrypted file. This brief how-to will hopefully help you do that.
Background
The set up: our client needed to provide us - securely - with an XML file made available via FTP, daily. Secure FTP was not an option, and they insisted on PGP. No problem, right? Well, actually quite a few problems, which I will attempt to help you avoid here.
Obviously, you need to install PGP or its open-source pal, GnuPG. You need to create a private and public key for yourself, and provide the public key to the "encryptor". All this stuff is well documented on various sites, so I'm not going into it here. There's a nice little Windows app called "GNU Privacy Assistant" (I used version v0.5.0) that will make this job fast and easy. Google it, or get it through www.gnupg.org.
End result: a human-unreadable / GPG-encrypted document that now needs to be decrypted and processed by an automated process.
Using the code
Here's the method we use. Basically, grab your encrypted file from the file system and get a reference to it through the FileInfo
class. Pass that to the method.
private string DecryptFile(FileInfo encryptedFile)
{
string outputFileName = this.GetDecryptedFileName(encryptedFile);
string path = encryptedFile.DirectoryName;
string outputFileNameFullPath = path + "\\" + outputFileName;
try {
System.Diagnostics.ProcessStartInfo psi =
new System.Diagnostics.ProcessStartInfo("cmd.exe");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WorkingDirectory = "C:\\Program Files\\GnuPP\\GnuPG";
System.Diagnostics.Process process = System.Diagnostics.Process.Start(psi);
string sCommandLine = "echo " + this._passphrase +
"| gpg.exe --passphrase-fd 0 -o \"" +
outputFileNameFullPath + "\" --decrypt \"" +
encryptedFile.FullName + "\"";
process.StandardInput.WriteLine(sCommandLine);
process.StandardInput.Flush();
process.StandardInput.Close();
process.WaitForExit();
process.Close();
}
catch (Exception ex)
{
this.HandleError(ex);
}
return outputFileName;
}
GetDecryptedFileName()
just provides a name for the resulting decrypted file - it's implementation is not important. Basically, just lop the ".gpg" extension off the end of the encrypted file. The method returns the decrypted file name for further processing; again, this isn't important, and simply suited the purpose at hand.
The interesting stuff: notice we call up the Windows Command EXE using System.Diagnostics.ProcessStartInfo
. The working directory is where the GnuPG application (EXE) and the public and private key files are stored.
The tricky part is passing the "secret" passphrase and options and commands to the gpg.exe process via cmd.exe. This is done through System.Diagnostics.Process.StandardInput
. Essentially, you are spawning a command window and feeding it something like:
C:\> echo my passphrase goes here| gpg.exe --passphrase-fd 0
-o "myDecryptedOutputFileName" --decrypt "myEncryptedFileName"
Problem solved! Note the security issues with having your private key passphrase used in an application like this - that's your issue! Not a big problem for our situation.
Points of interest
Notice the "-o" option? Don't use "-output", it won't work. Also notice how we build the whole command in "sCommandLine
" and pass this variable to WriteLine
? Also important. For some reason, building this directly in StandardInput.WriteLine()
doesn't work either - probably the escape characters in C#.
Hope that helps you avoid the frustrations we went through in coming up with this solution!