You are on page 1of 8

PGP Encryption & Decryption in C#

http://burnignorance.com/c-coding-tips/pgp-encryption-decryption-in-c/
inShare
To start with PGP encryption we nead to download assembly of BouncyCastle (bccrypto
-net-1.7-bin.zip) from the following link http://www.bouncycastle.org/csharp/.
Add this assembly to your applicaiton.
PGP Encryption
We will first discuss about PGP Encryption. In PGP encryption we need to create
public & private keys. Public key is used to encrypt the file and Private key is
used to decrypt the encrypted file at clients end.
To generate the keys we need to write algorithim, but we have sites which gives
us private & public keys instant. To generate keys go through the following site
https://www.igolder.com/pgp/generate-key/. While generating the keys please not
e down the password which you have provided during the key generation.
Now its time to keep the public & private keys in separate files like Ex: d:/keyP
ublic.txt , d:/keyPrivate.txt .
We will now move to the c# code. For encryption we will create two classes calle
d PgpEncrypt.cs and PgpEncryptionKeys.cs .
PgpEncrypt.cs class will hold hte code for encryotion and PgpEncryptionKeys clas
s will upload the keys. Following are the codes.
PgpEncrypt.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
using System.IO;
namespace PGPEncryption
{
public class PgpEncrypt
{
private PgpEncryptionKeys m_encryptionKeys;
private const int BufferSize = 0x10000; // should always be power of 2
/// <summary>
/// Instantiate a new PgpEncrypt class with initialized PgpEncryptionKey
s.
/// </summary>
/// <param name="encryptionKeys"></param>
/// <exception cref="ArgumentNullException">encryptionKeys is null</exce
ption>
public PgpEncrypt(PgpEncryptionKeys encryptionKeys)
{
if (encryptionKeys == null)
throw new ArgumentNullException("encryptionKeys", "encryptionKey
s is null.");
m_encryptionKeys = encryptionKeys;
}
/// <summary>
/// Encrypt and sign the file pointed to by unencryptedFileInfo and
/// write the encrypted content to outputStream.
/// </summary>

/// <param name="outputStream">The stream that will contain the


/// encrypted data when this method returns.</param>
/// <param name="fileName">FileInfo of the file to encrypt</param>
public void EncryptAndSign(Stream outputStream, FileInfo unencryptedFile
Info)
{
if (outputStream == null)
throw new ArgumentNullException("outputStream", "outputStream is
null.");
if (unencryptedFileInfo == null)
throw new ArgumentNullException("unencryptedFileInfo", "unencryp
tedFileInfo is null.");
if (!File.Exists(unencryptedFileInfo.FullName))
throw new ArgumentException("File to encrypt not found.");
using (Stream encryptedOut = ChainEncryptedOut(outputStream))
using (Stream compressedOut = ChainCompressedOut(encryptedOut))
{
PgpSignatureGenerator signatureGenerator = InitSignatureGenerato
r(compressedOut);
using (Stream literalOut = ChainLiteralOut(compressedOut, unencr
yptedFileInfo))
using (FileStream inputFile = unencryptedFileInfo.OpenRead())
{
WriteOutputAndSign(compressedOut, literalOut, inputFile, sig
natureGenerator);
}
}
}
private static void WriteOutputAndSign(Stream compressedOut,
Stream literalOut,
FileStream inputFile,
PgpSignatureGenerator signatureGenerator)
{
int length = 0;
byte[] buf = new byte[BufferSize];
while ((length = inputFile.Read(buf, 0, buf.Length)) > 0)
{
literalOut.Write(buf, 0, length);
signatureGenerator.Update(buf, 0, length);
}
signatureGenerator.Generate().Encode(compressedOut);
}
private Stream ChainEncryptedOut(Stream outputStream)
{
PgpEncryptedDataGenerator encryptedDataGenerator;
encryptedDataGenerator =
new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.TripleDes
,
new SecureRandom());
encryptedDataGenerator.AddMethod(m_encryptionKeys.PublicKey);
return encryptedDataGenerator.Open(outputStream, new byte[BufferSize
]);
}
private static Stream ChainCompressedOut(Stream encryptedOut)
{
PgpCompressedDataGenerator compressedDataGenerator =
new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
return compressedDataGenerator.Open(encryptedOut);
}
private static Stream ChainLiteralOut(Stream compressedOut, FileInfo fil

e)
{
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralData
Generator();
return pgpLiteralDataGenerator.Open(compressedOut, PgpLiteralData.Bi
nary, file);
}
private PgpSignatureGenerator InitSignatureGenerator(Stream compressedOu
t)
{
const bool IsCritical = false;
const bool IsNested = false;
PublicKeyAlgorithmTag tag = m_encryptionKeys.SecretKey.PublicKey.Alg
orithm;
PgpSignatureGenerator pgpSignatureGenerator =
new PgpSignatureGenerator(tag, HashAlgorithmTag.Sha1);
pgpSignatureGenerator.InitSign(PgpSignature.BinaryDocument, m_encryp
tionKeys.PrivateKey);
foreach (string userId in m_encryptionKeys.SecretKey.PublicKey.GetUs
erIds())
{
PgpSignatureSubpacketGenerator subPacketGenerator =
new PgpSignatureSubpacketGenerator();
subPacketGenerator.SetSignerUserId(IsCritical, userId);
pgpSignatureGenerator.SetHashedSubpackets(subPacketGenerator.Gen
erate());
// Just the first one!
break;
}
pgpSignatureGenerator.GenerateOnePassVersion(IsNested).Encode(compre
ssedOut);
return pgpSignatureGenerator;
}
}
}
PgpEncryptionKeys.cs
using
using
using
using
using
using

System;
System.Collections.Generic;
System.Linq;
System.Text;
System.IO;
Org.BouncyCastle.Bcpg.OpenPgp;

namespace PGPEncryption
{
public class PgpEncryptionKeys
{
public PgpPublicKey PublicKey { get; private set; }
public PgpPrivateKey PrivateKey { get; private set; }
public PgpSecretKey SecretKey { get; private set; }
/// <summary>
/// Initializes a new instance of the EncryptionKeys class.
/// Two keys are required to encrypt and sign data. Your private key and
the recipients public key.
/// The data is encrypted with the recipients public key and signed with
your private key.
/// </summary>

/// <param name="publicKeyPath">The key used to encrypt the data</param>


/// <param name="privateKeyPath">The key used to sign the data.</param>
/// <param name="passPhrase">The (your) password required to access the
private key</param>
/// <exception cref="ArgumentException">Public key not found. Private ke
y not found. Missing password</exception>
public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, st
ring passPhrase)
{
if (!File.Exists(publicKeyPath))
throw new ArgumentException("Public key file not found", "public
KeyPath");
if (!File.Exists(privateKeyPath))
throw new ArgumentException("Private key file not found", "priva
teKeyPath");
if (String.IsNullOrEmpty(passPhrase))
throw new ArgumentException("passPhrase is null or empty.", "pas
sPhrase");
PublicKey = ReadPublicKey(publicKeyPath);
SecretKey = ReadSecretKey(privateKeyPath);
PrivateKey = ReadPrivateKey(passPhrase);
}
#region Secret Key
private PgpSecretKey ReadSecretKey(string privateKeyPath)
{
using (Stream keyIn = File.OpenRead(privateKeyPath))
using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
{
PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRin
gBundle(inputStream);
PgpSecretKey foundKey = GetFirstSecretKey(secretKeyRingBundle);
if (foundKey != null)
return foundKey;
}
throw new ArgumentException("Can't find signing key in key ring.");
}
/// <summary>
/// Return the first key we can use to encrypt.
/// Note: A file can contain multiple keys (stored in "key rings")
/// </summary>
private PgpSecretKey GetFirstSecretKey(PgpSecretKeyRingBundle secretKeyR
ingBundle)
{
foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings()
)
{
PgpSecretKey key = kRing.GetSecretKeys().Cast<PgpSecretKey>().Wh
ere(k => k.IsSigningKey).FirstOrDefault();
if (key != null)
return key;

}
return null;
}
#endregion
#region Public Key
private PgpPublicKey ReadPublicKey(string publicKeyPath)
{
using (Stream keyIn = File.OpenRead(publicKeyPath))
using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
{
PgpPublicKeyRingBundle publicKeyRingBundle = new PgpPublicKeyRin
gBundle(inputStream);
PgpPublicKey foundKey = GetFirstPublicKey(publicKeyRingBundle);
if (foundKey != null)
return foundKey;
}
throw new ArgumentException("No encryption key found in public key r
ing.");
}
private PgpPublicKey GetFirstPublicKey(PgpPublicKeyRingBundle publicKeyR
ingBundle)
{
foreach (PgpPublicKeyRing kRing in publicKeyRingBundle.GetKeyRings()
)
{
PgpPublicKey key = kRing.GetPublicKeys()
.Cast<PgpPublicKey>()
.Where(k => k.IsEncryptionKey)
.FirstOrDefault();
if (key != null)
return key;
}
return null;
}
#endregion
#region Private Key
private PgpPrivateKey ReadPrivateKey(string passPhrase)
{
PgpPrivateKey privateKey = SecretKey.ExtractPrivateKey(passPhrase.To
CharArray());
if (privateKey != null)
return privateKey;
throw new ArgumentException("No private key found in secret key.");
}
#endregion
}
}

create a form & take button control to fire the encryption process. following ar
e the code in Form1.cs
Form1.cs
private void button1_Click(object sender, EventArgs e)
{
string path1 = @"d:\unEncryptedFile.txt";
FileInfo fi = new FileInfo(path1);
//GetFile();
string path = @"d:\MyTest.txt";
// Delete the file if it exists.
if (File.Exists(path))
{
File.Delete(path);
}
//Create the file.
using (FileStream fs = fi.Create())
{
Byte[] info = new UTF8Encoding(true).GetBytes("This is some text
in the file.");
// Add some information to the file.
fs.Write(info, 0, info.Length);
fs.Flush();
fs.Close();
FileStream str=new FileStream(@"d:\MyTest.txt",FileMode.Create);
PgpEncryptionKeys objPgpEncryptionKeys = new PgpEncryptionKeys(@
"d:/keyPublic.txt",
@"d:/keyPrivate.txt", "password");
PgpEncrypt objPgpEncrypt = new PgpEncrypt(objPgpEncryptionKeys);
objPgpEncrypt.EncryptAndSign(str, fi);
}
The above code will create a file called MyTest.txt in folder @d:/. The content
will be in encrypted format.
Now we will move towards PGP Decryption. We will decrypt the same file which we
have encrypted just now.
Note: In this click event the following line
PgpEncryptionKeys objPgpEncryptionKeys = new PgpEncryptionKeys(@"d:/keyPublic.tx
t", @"d:/keyPrivate.txt", "password");
for Password you have to give the same as you have given during the key generation
in the tool (https://www.igolder.com/pgp/generate-key/)
PGP Decryption
For PGP Decryption we need only one class which will contain the source code for
decrypting the file. we call it as PGPDecrypt.cs
PGPDecrypt.cs
using
using
using
using
using

Org.BouncyCastle.Bcpg.OpenPgp;
Org.BouncyCastle.Crypto;
Org.BouncyCastle.Security;
Org.BouncyCastle.Utilities.IO;
Org.BouncyCastle.Bcpg;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
//using Tools.PGP.Crypto;
namespace PGPEncryption
{
public class PGPDecrypt
{
public string _encryptedFilePath;
public string _privKeyPath;
public char[] _password;
public string _outputPath;
public PgpEncryptionKeys pgpKeys;
public PGPDecrypt(string encryptedFilePath, string privKeyPath, string p
assword, string outputPath, string pubKeyPath)
{
_encryptedFilePath = encryptedFilePath;
_outputPath = outputPath;
_password = password.ToCharArray();
_privKeyPath = privKeyPath;
pgpKeys = new PgpEncryptionKeys(pubKeyPath, privKeyPath, password);
}
public void decrypt(Stream input, string outputpath)
{
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 = pgpKeys.PrivateKey;
PgpPublicKeyEncryptedData pbe = null;
foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataO
bjects())
{
if (privKey != null)
{
pbe = pked;
break;
}
}
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;
Stream output = File.Create(outputpath + "\\" + Ld.FileN
ame);
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, output);
}
else
{
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
Stream output = File.Create(outputpath + "\\" + Ld.FileN
ame);
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, output);
}
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
}
}
For decryption key we will use the same PgpEncryptionKeys class. Now we will use t
he decrypt method to decrypt the file. Create another button ib the same form as
Decrypt . In the button click even write the below code.
private void button2_Click(object sender, EventArgs e)
{
PGPDecrypt test = new PGPDecrypt(@"d:\MyTest.txt",
@"d:/keyPrivate.txt",
"password",
@"d:",
@"d:/keyPublic.txt");
FileStream fs = File.Open(@"d:\MyTest.txt", FileMode.Open);
test.decrypt(fs, @"d:");
}

Note: In this click event this line


PGPDecrypt test = new PGPDecrypt(@ d:\MyTest.txt , @ d:/keyPrivate.txt , password , @ d: , @
eyPublic.txt );
for Password you have to give the same as you have given during the key generation
in the tool (https://www.igolder.com/pgp/generate-key/)

You might also like