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 note 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:/keyPublic.txt” , “d:/keyPrivate.txt”.
We will now move to the c# code. For encryption we will create two classes called “PgpEncrypt.cs” and “PgpEncryptionKeys.cs“.
PgpEncrypt.cs class will hold hte code for encryotion and PgpEncryptionKeys class 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 /// /// Instantiate a new PgpEncrypt class with initialized PgpEncryptionKeys. /// /// /// encryptionKeys is null public PgpEncrypt(PgpEncryptionKeys encryptionKeys) { if (encryptionKeys == null) throw new ArgumentNullException("encryptionKeys", "encryptionKeys is null."); m_encryptionKeys = encryptionKeys; } /// /// Encrypt and sign the file pointed to by unencryptedFileInfo and /// write the encrypted content to outputStream. /// /// The stream that will contain the /// encrypted data when this method returns. /// FileInfo of the file to encrypt public void EncryptAndSign(Stream outputStream, FileInfo unencryptedFileInfo) { if (outputStream == null) throw new ArgumentNullException("outputStream", "outputStream is null."); if (unencryptedFileInfo == null) throw new ArgumentNullException("unencryptedFileInfo", "unencryptedFileInfo 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 = InitSignatureGenerator(compressedOut); using (Stream literalOut = ChainLiteralOut(compressedOut, unencryptedFileInfo)) using (FileStream inputFile = unencryptedFileInfo.OpenRead()) { WriteOutputAndSign(compressedOut, literalOut, inputFile, signatureGenerator); } } } 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 file) { PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator(); return pgpLiteralDataGenerator.Open(compressedOut, PgpLiteralData.Binary, file); } private PgpSignatureGenerator InitSignatureGenerator(Stream compressedOut) { const bool IsCritical = false; const bool IsNested = false; PublicKeyAlgorithmTag tag = m_encryptionKeys.SecretKey.PublicKey.Algorithm; PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(tag, HashAlgorithmTag.Sha1); pgpSignatureGenerator.InitSign(PgpSignature.BinaryDocument, m_encryptionKeys.PrivateKey); foreach (string userId in m_encryptionKeys.SecretKey.PublicKey.GetUserIds()) { PgpSignatureSubpacketGenerator subPacketGenerator = new PgpSignatureSubpacketGenerator(); subPacketGenerator.SetSignerUserId(IsCritical, userId); pgpSignatureGenerator.SetHashedSubpackets(subPacketGenerator.Generate()); // Just the first one! break; } pgpSignatureGenerator.GenerateOnePassVersion(IsNested).Encode(compressedOut); return pgpSignatureGenerator; } } }
PgpEncryptionKeys.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using 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; } /// /// 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. /// /// The key used to encrypt the data /// The key used to sign the data. /// The (your) password required to access the private key /// Public key not found. Private key not found. Missing password public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase) { if (!File.Exists(publicKeyPath)) throw new ArgumentException("Public key file not found", "publicKeyPath"); if (!File.Exists(privateKeyPath)) throw new ArgumentException("Private key file not found", "privateKeyPath"); if (String.IsNullOrEmpty(passPhrase)) throw new ArgumentException("passPhrase is null or empty.", "passPhrase"); 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 PgpSecretKeyRingBundle(inputStream); PgpSecretKey foundKey = GetFirstSecretKey(secretKeyRingBundle); if (foundKey != null) return foundKey; } throw new ArgumentException("Can't find signing key in key ring."); } /// /// Return the first key we can use to encrypt. /// Note: A file can contain multiple keys (stored in "key rings") /// private PgpSecretKey GetFirstSecretKey(PgpSecretKeyRingBundle secretKeyRingBundle) { foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings()) { PgpSecretKey key = kRing.GetSecretKeys().Cast().Where(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 PgpPublicKeyRingBundle(inputStream); PgpPublicKey foundKey = GetFirstPublicKey(publicKeyRingBundle); if (foundKey != null) return foundKey; } throw new ArgumentException("No encryption key found in public key ring."); } private PgpPublicKey GetFirstPublicKey(PgpPublicKeyRingBundle publicKeyRingBundle) { foreach (PgpPublicKeyRing kRing in publicKeyRingBundle.GetKeyRings()) { PgpPublicKey key = kRing.GetPublicKeys() .Cast() .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.ToCharArray()); 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 are 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.txt", @"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 Org.BouncyCastle.Bcpg.OpenPgp; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.IO; using 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 password, 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.GetEncryptedDataObjects()) { 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.FileName); Stream unc = Ld.GetInputStream(); Streams.PipeAll(unc, output); } else { PgpLiteralData Ld = null; Ld = (PgpLiteralData)message; Stream output = File.Create(outputpath + "\\" + Ld.FileName); 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 the 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:”, @”d:/keyPublic.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/)