C# How to simply encrypt a text file with a PGP Public Key?
Asked Answered
E

5

31

I've researched a bit about how to achieve what I said in the question and found several APIs but most of them look very complicated and since I'm just a noobie in this area I just want a simple method like:

public String Encrypt(String message, PublicKey publicKey)

Don't know if this can be done? If not then please someone enlighten me another way to achieve this :)

Thank you.

UPDATE:

So far I have only seen that all of the library for OpenPGP encryption require both the public key and private key to do the encrypt while I only want to encrypt with the public key (because I don't have the private key to use it)!

Erectile answered 16/11, 2010 at 8:33 Comment(0)
E
15

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 :)

Erectile answered 17/11, 2010 at 6:41 Comment(5)
Why is this the answer? This looks like symmetric encryption with a preshared key, not asymmetric encryption with a public/ private key.Xiphoid
This is asymmetric encryption, it works on the public/private key.Trisaccharide
The part with "SymmetricKeyAlgorithmTag.TripleDes" might be.. well.. a tiny bit outdated.Perreault
where does PgpEncryptionKeys class come from?Naca
How to encrypt a string, not FileInfo?Kenyatta
S
11

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);
                    }
                }
            }
        }
    }
Southland answered 28/12, 2014 at 20:16 Comment(0)
G
7

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#

Guiltless answered 16/11, 2010 at 9:43 Comment(2)
What is the armor and integrityCheck? also the passphrase?Erectile
Armor is a fancy way of saying "ASCII encoded binary data", which means you can encrypt pictures and word documents.Definiendum
P
6

If you want to do both encryption and decryption in dotnet core, this is the article I followed: https://nightbaker.github.io/pgp/cryptography/.net/core/2019/02/08/pgp-encryption/

The encryption part does not require the private key.

All credits go to the original author NightBaker.

Install-Package  BouncyCastle.NetCore
Install-Package  BouncyCastle.NetCoreSdk
public class Pgp
{
    public static void EncryptFile(
        string outputFileName,
        string inputFileName,
        string encKeyFileName,
        bool armor,
        bool withIntegrityCheck)
    {
        PgpPublicKey encKey = PgpExampleUtilities.ReadPublicKey(encKeyFileName);

        using (Stream output = File.Create(outputFileName))
        {
            EncryptFile(output, inputFileName, encKey, armor, withIntegrityCheck);
        }
    }

    private static void EncryptFile(
        Stream outputStream,
        string fileName,
        PgpPublicKey encKey,
        bool armor,
        bool withIntegrityCheck)
    {
        if (armor)
        {
            outputStream = new ArmoredOutputStream(outputStream);
        }

        try
        {
            byte[] bytes = PgpExampleUtilities.CompressFile(fileName, CompressionAlgorithmTag.Zip);

            PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(
                SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
            encGen.AddMethod(encKey);

            Stream cOut = encGen.Open(outputStream, bytes.Length);

            cOut.Write(bytes, 0, bytes.Length);
            cOut.Close();

            if (armor)
            {
                outputStream.Close();
            }
        }
        catch (PgpException e)
        {
            Console.Error.WriteLine(e);

            Exception underlyingException = e.InnerException;
            if (underlyingException != null)
            {
                Console.Error.WriteLine(underlyingException.Message);
                Console.Error.WriteLine(underlyingException.StackTrace);
            }
        }
    }
}

public class PgpExampleUtilities
{
    internal static PgpPublicKey ReadPublicKey(string fileName)
    {
        using (Stream keyIn = File.OpenRead(fileName))
        {
            return ReadPublicKey(keyIn);
        }
    }

    internal static PgpPublicKey ReadPublicKey(Stream input)
    {
        PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(
            PgpUtilities.GetDecoderStream(input));

        //
        // we just loop through the collection till we find a key suitable for encryption, in the real
        // world you would probably want to be a bit smarter about this.
        //

        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.");
    }


    internal static byte[] CompressFile(string fileName, CompressionAlgorithmTag algorithm)
    {
        MemoryStream bOut = new MemoryStream();
        PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(algorithm);
        PgpUtilities.WriteFileToLiteralData(comData.Open(bOut), PgpLiteralData.Binary,
            new FileInfo(fileName));
        comData.Close();
        return bOut.ToArray();
    }
}

Usage:

Pgp.EncryptFile("Resources/output.txt", "Resources/input.txt", "Resources/publicKey.txt", true, true);
Plainsman answered 10/6, 2020 at 13:35 Comment(2)
A link to a solution is welcome, but please ensure your answer is useful without it: add context around the link so your fellow users will have some idea what it is and why it’s there, then quote the most relevant part of the page you're linking to in case the target page is unavailable. Answers that are little more than a link may be deleted.Affricative
You can't just copy code from a third-party article and present it as your own answer. The answers you write should be your own. Selectively quoting from attributed sources is allowed, as long as you make clear it is a quote, and as long as it is not the majority of your answer.Mach
F
3

If you are looking for a simple dotnet library to do pgp encryption take a look at PgpCore. Its a wrapper around Bouncy Castle - just making it a little bit easier than needing to know the internals of Bouncy Castle.

Foreglimpse answered 26/5, 2020 at 18:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.