Skip to content

Instantly share code, notes, and snippets.

@bergquist
Forked from dieseltravis/CryptoHelper.cs
Last active August 29, 2015 14:10
Show Gist options
  • Save bergquist/3d4e9a5549921b0913b6 to your computer and use it in GitHub Desktop.
Save bergquist/3d4e9a5549921b0913b6 to your computer and use it in GitHub Desktop.
<?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");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment