I have been looking all day yesterday, and I can't seem to find a working example of PGP decryption using Bouncy Castle in c#
Asked
Active
Viewed 1.9k times
7
-
take a look at http://blog.mrjaredpowell.com/2010/Automate_decryption_Bouncy_Castle.htm or at the other so question with links to examples http://stackoverflow.com/questions/6987699/pgp-encryption-and-decryption-using-bouncycastle-c-sharp – Brian Jun 12 '12 at 15:14
-
The blog post seems to be Java. not C#. I am trying to port the code though – Ron Harlev Jun 12 '12 at 15:34
2 Answers
9
Finally got it to work. The main issue I had with other samples was the fact that the private key ring I had included a key for signing which was coming up first when trying to load the key for decryption. This is why why I had to add a check for the ElGamalPrivateKeyParameters
type on the key.
Below is my code. Not very clean, but it works.
private static PgpPrivateKey GetPrivateKey(string privateKeyPath)
{
using (Stream keyIn = File.OpenRead(privateKeyPath))
using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
{
PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream);
PgpSecretKey key = null;
foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings())
{
foreach (PgpSecretKey secretKey in kRing.GetSecretKeys())
{
PgpPrivateKey privKey = secretKey.ExtractPrivateKey("1234567890".ToCharArray());
if (privKey.Key.GetType() ==
typeof (Org.BouncyCastle.Crypto.Parameters.ElGamalPrivateKeyParameters))
//Org.BouncyCastle.Crypto.Parameters.ElGamalPrivateKeyParameters
{
return privKey;
}
}
}
}
return null;
}
public static void Decrypt(Stream input, string outputpath, String privateKeyPath)
{
input = PgpUtilities.GetDecoderStream(input);
try
{
PgpObjectFactory pgpObjF = new PgpObjectFactory(input);
PgpEncryptedDataList enc;
PgpObject obj = pgpObjF.NextPgpObject();
if (obj is PgpEncryptedDataList)
{
enc = (PgpEncryptedDataList)obj;
}
else
{
enc = (PgpEncryptedDataList)pgpObjF.NextPgpObject();
}
PgpPrivateKey privKey = GetPrivateKey(privateKeyPath);
PgpPublicKeyEncryptedData pbe = enc.GetEncryptedDataObjects().Cast<PgpPublicKeyEncryptedData>().First();
Stream clear;
clear = pbe.GetDataStream(privKey);
PgpObjectFactory plainFact = new PgpObjectFactory(clear);
PgpObject message = plainFact.NextPgpObject();
if (message is PgpCompressedData)
{
PgpCompressedData cData = (PgpCompressedData)message;
Stream compDataIn = cData.GetDataStream();
PgpObjectFactory o = new PgpObjectFactory(compDataIn);
message = o.NextPgpObject();
if (message is PgpOnePassSignatureList)
{
message = o.NextPgpObject();
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
Stream output = File.Create(outputpath + "\\" + Ld.FileName);
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, output);
}
else
{
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
//Stream output = File.Create(outputpath + "\\" + Ld.FileName);
Stream output = File.Create(outputpath);
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, output);
}
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}

Ron Harlev
- 16,227
- 24
- 89
- 132
-
@GeorgePligor: Hi, I am very new to PGP have have to encrypt my csv in pgp format for some requirment, I have found code to implement that but still struggling to undersatand keystore and Keys. Could you suggest from where i can get keys? Public and private. – 14578446 Apr 26 '13 at 08:28
-
-
1My 'message is PgpCompressedData' is true but then 'message = o.NextPgpObject();' is always null, any idea about it? Also I do not get ElGamalKeyParameters key type but keys of type - RsaPrivateCrtKeyParameters only... – Manik Arora Jul 13 '17 at 07:12
-
I realize this was awhile ago, but the line `var akp = new AsymmetricKeyParameter(true);` gives the error: Cannot create an instance of the abstract class or interface ( Furthermore, why is it there in the first place, you are not even using the variable akp in that block). – joedotnot Mar 11 '21 at 13:26
6
I was running into issues with Ron Harlev's Decrypt function holding the output file until the program was terminated. I added a few using statements around the Stream's to overcome this issue. I also replaced the hard coded passphrase in favor of an input argument. I hope somebody finds this useful.
private static bool DecryptFile(Stream inputStream, string outputDir, char[] passPhrase, string privateKeyLoc)
{
try
{
using (var newStream = PgpUtilities.GetDecoderStream(inputStream))
{
PgpObjectFactory pgpObjF = new PgpObjectFactory(newStream);
PgpEncryptedDataList enc;
PgpObject obj = pgpObjF.NextPgpObject();
if (obj is PgpEncryptedDataList)
{
enc = (PgpEncryptedDataList)obj;
}
else
{
enc = (PgpEncryptedDataList)pgpObjF.NextPgpObject();
}
PgpPrivateKey privKey = GetPrivateKey(privateKeyLoc, passPhrase, logger);
PgpPublicKeyEncryptedData pbe = enc.GetEncryptedDataObjects().Cast<PgpPublicKeyEncryptedData>().First();
using (Stream clear = pbe.GetDataStream(privKey))
{
PgpObjectFactory plainFact = new PgpObjectFactory(clear);
PgpObject message = plainFact.NextPgpObject();
if (message is PgpCompressedData)
{
PgpCompressedData cData = (PgpCompressedData)message;
Stream compDataIn = cData.GetDataStream();
PgpObjectFactory o = new PgpObjectFactory(compDataIn);
message = o.NextPgpObject();
if (message is PgpOnePassSignatureList)
{
message = o.NextPgpObject();
}
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
using (Stream output = File.Create(outputDir + "\\" + Ld.FileName))
{
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, output);
}
}
}
}
return true;
}
catch (Exception e)
{
throw new Exception(e.Message);
return false;
}
}

Ron Harlev
- 16,227
- 24
- 89
- 132

coshea34
- 63
- 2
- 6