C# How to simply encrypt a text file with a PGP Public Key?
I found a tutorial here but it requires both Secret Key and Public Key to encrypt data. However I've modified the codes a bit to only require public key (no signing, no compress) and thought I should publish it here in case anyone also looking for a solution for this question. Belows is the modified codes, all the credits for the author - Mr. Kim.
public class PgpEncrypt
{
private PgpEncryptionKeys m_encryptionKeys;
private const int BufferSize = 0x10000;
/// <summary>
/// Instantiate a new PgpEncrypt class with initialized PgpEncryptionKeys.
/// </summary>
/// <param name="encryptionKeys"></param>
/// <exception cref="ArgumentNullException">encryptionKeys is null</exception>
public PgpEncrypt(PgpEncryptionKeys encryptionKeys)
{
if (encryptionKeys == null)
{
throw new ArgumentNullException("encryptionKeys", "encryptionKeys 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 Encrypt(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 literalOut = ChainLiteralOut(encryptedOut, unencryptedFileInfo))
using (FileStream inputFile = unencryptedFileInfo.OpenRead())
{
WriteOutput(literalOut, inputFile);
}
}
}
private static void WriteOutput(Stream literalOut,
FileStream inputFile)
{
int length = 0;
byte[] buf = new byte[BufferSize];
while ((length = inputFile.Read(buf, 0, buf.Length)) > 0)
{
literalOut.Write(buf, 0, length);
}
}
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 ChainLiteralOut(Stream encryptedOut, FileInfo file)
{
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
return pgpLiteralDataGenerator.Open(encryptedOut, PgpLiteralData.Binary,
file);
}
}
Of course to run these codes you have to include BouncyCastle library in your project.
I've tested encrypting and then decrypting and it runs fine :)
Here is perhaps a cleaner approach:
var pkr = asciiPublicKeyToRing(ascfilein);
if (pkr != null)
{
try
{
EncryptFile(
tbUnencryptedFile.Text, tbEncryptedFile.Text, getFirstPublicEncryptionKeyFromRing(pkr), true, true);
MessageBox.Show("File Encrypted.");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
else
{
MessageBox.Show(ascfilein + " is not a public key.");
}
private PgpPublicKeyRing asciiPublicKeyToRing(string ascfilein)
{
using (Stream pubFis = File.OpenRead(ascfilein))
{
var pubArmoredStream = new ArmoredInputStream(pubFis);
PgpObjectFactory pgpFact = new PgpObjectFactory(pubArmoredStream);
Object opgp = pgpFact.NextPgpObject();
var pkr = opgp as PgpPublicKeyRing;
return pkr;
}
}
private PgpPublicKey getFirstPublicEncryptionKeyFromRing(PgpPublicKeyRing pkr)
{
foreach (PgpPublicKey k in pkr.GetPublicKeys())
{
if (k.IsEncryptionKey)
return k;
}
throw new ArgumentException("Can't find encryption key in key ring.");
}
public static void EncryptFile(string inputFile, string outputFile, PgpPublicKey encKey, bool armor,
bool withIntegrityCheck)
{
using (MemoryStream bOut = new MemoryStream())
{
PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
PgpUtilities.WriteFileToLiteralData(comData.Open(bOut), PgpLiteralData.Binary,
new FileInfo(inputFile));
comData.Close();
PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Aes256,
withIntegrityCheck, new SecureRandom());
cPk.AddMethod(encKey);
byte[] bytes = bOut.ToArray();
using (Stream outputStream = File.Create(outputFile))
{
if (armor)
{
using (ArmoredOutputStream armoredStream = new ArmoredOutputStream(outputStream))
using (Stream cOut = cPk.Open(armoredStream, bytes.Length))
{
cOut.Write(bytes, 0, bytes.Length);
}
}
else
{
using (Stream cOut = cPk.Open(outputStream, bytes.Length))
{
cOut.Write(bytes, 0, bytes.Length);
}
}
}
}
}
Did you take a look at the bouncycastle pgp? http://www.bouncycastle.org/
There is a source example here of enrypting a file taken from the BouncyCastle site: Need example for BouncyCastle PGP File encryption in C#