Skip to content

Instantly share code, notes, and snippets.

@tekmaven
Forked from dieseltravis/CryptoHelper.cs
Created July 26, 2016 16:28
Show Gist options
  • Save tekmaven/03fddd1b156f0149f28e66a7c675d94e to your computer and use it in GitHub Desktop.
Save tekmaven/03fddd1b156f0149f28e66a7c675d94e to your computer and use it in GitHub Desktop.
sample app that uses PGP Encryption using Bouncy Castle's C# API
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<add key="Password" value="ThisIsNotARealPassword" />
<add key="PublicKey" value="PgpPublicKey.asc" />
<add key="PrivateKeyOnly" value="PgpPrivateKeyOnly.asc" />
</configuration>
using System;
using System.Configuration;
using System.IO;
using System.Security.Cryptography;
// using Bouncy Castle library: http://www.bouncycastle.org/csharp/
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace EncryptionSample
{
public static class CryptoHelper
{
private static readonly string Password = ConfigurationManager.AppSettings["Password"];
public static readonly string PublicKey = ConfigurationManager.AppSettings["PublicKey"];
public static readonly string PublicKeyPath = IoHelper.BasePath + @"\" + PublicKey;
// note: this should be changed if the private key is not located in the current executables path
private static readonly string PrivateKeyOnly = ConfigurationManager.AppSettings["PrivateKeyOnly"];
private static readonly string PrivateKeyOnlyPath = IoHelper.BasePath + @"\" + PrivateKeyOnly;
// The majority of the functionality encrypting/decrypting came from this answer: http://stackoverflow.com/a/10210465
private static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyId, char[] pass)
{
PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId);
if (pgpSecKey == null)
{
return null;
}
return pgpSecKey.ExtractPrivateKey(pass);
}
public static string DecryptPgpData(string inputData)
{
string output;
using (Stream inputStream = IoHelper.GetStream(inputData))
{
using (Stream keyIn = File.OpenRead(PrivateKeyOnlyPath))
{
output = DecryptPgpData(inputStream, keyIn, Password);
}
}
return output;
}
public static string DecryptPgpData(Stream inputStream, Stream privateKeyStream, string passPhrase)
{
string output;
PgpObjectFactory pgpFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream));
// find secret key
PgpSecretKeyRingBundle pgpKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream));
PgpObject pgp = null;
if (pgpFactory != null)
{
pgp = pgpFactory.NextPgpObject();
}
// the first object might be a PGP marker packet.
PgpEncryptedDataList encryptedData = null;
if (pgp is PgpEncryptedDataList)
{
encryptedData = (PgpEncryptedDataList)pgp;
}
else
{
encryptedData = (PgpEncryptedDataList)pgpFactory.NextPgpObject();
}
// decrypt
PgpPrivateKey privateKey = null;
PgpPublicKeyEncryptedData pubKeyData = null;
foreach (PgpPublicKeyEncryptedData pubKeyDataItem in encryptedData.GetEncryptedDataObjects())
{
privateKey = FindSecretKey(pgpKeyRing, pubKeyDataItem.KeyId, passPhrase.ToCharArray());
if (privateKey != null)
{
pubKeyData = pubKeyDataItem;
break;
}
}
if (privateKey == null)
{
throw new ArgumentException("Secret key for message not found.");
}
PgpObjectFactory plainFact = null;
using (Stream clear = pubKeyData.GetDataStream(privateKey))
{
plainFact = new PgpObjectFactory(clear);
}
PgpObject message = plainFact.NextPgpObject();
if (message is PgpCompressedData)
{
PgpCompressedData compressedData = (PgpCompressedData)message;
PgpObjectFactory pgpCompressedFactory = null;
using (Stream compDataIn = compressedData.GetDataStream())
{
pgpCompressedFactory = new PgpObjectFactory(compDataIn);
}
message = pgpCompressedFactory.NextPgpObject();
PgpLiteralData literalData = null;
if (message is PgpOnePassSignatureList)
{
message = pgpCompressedFactory.NextPgpObject();
}
literalData = (PgpLiteralData)message;
using (Stream unc = literalData.GetInputStream())
{
output = IoHelper.GetString(unc);
}
}
else if (message is PgpLiteralData)
{
PgpLiteralData literalData = (PgpLiteralData)message;
using (Stream unc = literalData.GetInputStream())
{
output = IoHelper.GetString(unc);
}
}
else if (message is PgpOnePassSignatureList)
{
throw new PgpException("Encrypted message contains a signed message - not literal data.");
}
else
{
throw new PgpException("Message is not a simple encrypted file - type unknown.");
}
return output;
}
private static PgpPublicKey ReadPublicKey(Stream inputStream)
{
inputStream = PgpUtilities.GetDecoderStream(inputStream);
PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(inputStream);
foreach (PgpPublicKeyRing keyRing in pgpPub.GetKeyRings())
{
foreach (PgpPublicKey key in keyRing.GetPublicKeys())
{
if (key.IsEncryptionKey)
{
return key;
}
}
}
throw new ArgumentException("Can't find encryption key in key ring.");
}
public static void EncryptPgpFile(string inputFile, string outputFile)
{
// use armor: yes, use integrity check? yes?
EncryptPgpFile(inputFile, outputFile, PublicKeyPath, true, true);
}
public static void EncryptPgpFile(string inputFile, string outputFile, string publicKeyFile, bool armor, bool withIntegrityCheck)
{
using (Stream publicKeyStream = File.OpenRead(publicKeyFile))
{
PgpPublicKey pubKey = ReadPublicKey(publicKeyStream);
using (MemoryStream outputBytes = new MemoryStream())
{
PgpCompressedDataGenerator dataCompressor = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
PgpUtilities.WriteFileToLiteralData(dataCompressor.Open(outputBytes), PgpLiteralData.Binary, new FileInfo(inputFile));
dataCompressor.Close();
PgpEncryptedDataGenerator dataGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
dataGenerator.AddMethod(pubKey);
byte[] dataBytes = outputBytes.ToArray();
using (Stream outputStream = File.Create(outputFile))
{
if (armor)
{
using (ArmoredOutputStream armoredStream = new ArmoredOutputStream(outputStream))
{
IoHelper.WriteStream(dataGenerator.Open(armoredStream, dataBytes.Length), ref dataBytes);
}
}
else
{
IoHelper.WriteStream(dataGenerator.Open(outputStream, dataBytes.Length), ref dataBytes);
}
}
}
}
}
// Note: I was able to extract the private key into xml format .Net expecs with this
public static string GetPrivateKeyXml(string inputData)
{
Stream inputStream = IoHelper.GetStream(inputData);
PgpObjectFactory pgpFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream));
PgpObject pgp = null;
if (pgpFactory != null)
{
pgp = pgpFactory.NextPgpObject();
}
PgpEncryptedDataList encryptedData = null;
if (pgp is PgpEncryptedDataList)
{
encryptedData = (PgpEncryptedDataList)pgp;
}
else
{
encryptedData = (PgpEncryptedDataList)pgpFactory.NextPgpObject();
}
Stream privateKeyStream = File.OpenRead(PrivateKeyOnlyPath);
// find secret key
PgpSecretKeyRingBundle pgpKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream));
PgpPrivateKey privateKey = null;
foreach (PgpPublicKeyEncryptedData pked in encryptedData.GetEncryptedDataObjects())
{
privateKey = FindSecretKey(pgpKeyRing, pked.KeyId, Password.ToCharArray());
if (privateKey != null)
{
//pubKeyData = pked;
break;
}
}
// get xml:
RsaPrivateCrtKeyParameters rpckp = ((RsaPrivateCrtKeyParameters)privateKey.Key);
RSAParameters dotNetParams = DotNetUtilities.ToRSAParameters(rpckp);
RSA rsa = RSA.Create();
rsa.ImportParameters(dotNetParams);
string xmlPrivate = rsa.ToXmlString(true);
return xmlPrivate;
}
}
}
using System.IO;
using System.Reflection;
namespace EncryptionSample
{
public static class IoHelper
{
public static readonly string BasePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public static Stream GetStream(string stringData)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(stringData);
writer.Flush();
stream.Position = 0;
return stream;
}
public static string GetString(Stream inputStream)
{
string output;
using (StreamReader reader = new StreamReader(inputStream))
{
output = reader.ReadToEnd();
}
return output;
}
public static void WriteStream(Stream inputStream, ref byte[] dataBytes)
{
using (Stream outputStream = inputStream)
{
outputStream.Write(dataBytes, 0, dataBytes.Length);
}
}
}
}
namespace EncryptionSample
{
class Program
{
static void Main(string[] args)
{
// note: all key info is in app.config
// pass in a string encrypted data to decrypt
string decrypted = CryptoHelper.DecryptPgpData("-----BEGIN PGP MESSAGE----- some pgp-wrapped encrypted string that the private key and password will open");
// pass in 2 file paths to generate the encrypted file
// (IoHelper.BasePath is just the path where the executable is running)
CryptoHelper.EncryptPgpFile(IoHelper.BasePath + @"\plain-text.txt", IoHelper.BasePath + @"\pgp-encrypted.asc");
// if you need to convert a private key from a pgp to xml format:
string xmlPPrivateKey = CryptoHelper.GetPrivateKeyXml("-----BEGIN PGP PRIVATE KEY BLOCK----- a pgp private key");
}
}
}
@saintofdreams
Copy link

I have an error .
encryptedData.GetEncryptedDataObjects() is null ?

Why ?

image

@insigmaprashant
Copy link

How to convert the .gpg file in excel. can you give me solution?

@jamesshaw99
Copy link

I have an error .
encryptedData.GetEncryptedDataObjects() is null ?

Why ?

image

did you find a solution to this?

@susilpadhi
Copy link

Where can i get the Public Key & Private Key files.

@sonamdhabria
Copy link

Hi

I have a requirement to Encrypt using Private key , can anyone help. Above code gives error as I dont have Public key, client has just provided private key and wants us to encrypt file using that.

@ahadjithoma
Copy link

@siva1254
Copy link

Hi i've copied your code but seems to be pgputilities doesn't have "WriteFileToLiteralData" method FYR i'm attaching screen shot please check and help

pgpuitlity1
pgputility2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment