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

Mohsen Heydari
  • 7,256
  • 4
  • 31
  • 46
Leo
  • 2,173
  • 6
  • 28
  • 37

5 Answers5

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

Leo
  • 2,173
  • 6
  • 28
  • 37
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);
                    }
                }
            }
        }
    }
azpc
  • 500
  • 9
  • 11
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#

Community
  • 1
  • 1
kyndigs
  • 3,074
  • 1
  • 18
  • 22
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);
malnosna
  • 164
  • 1
  • 5
  • A link to a solution is welcome, but please ensure your answer is useful without it: [add context around the link](//meta.stackexchange.com/a/8259) 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.](//stackoverflow.com/help/deleted-answers) – double-beep Jun 10 '20 at 13:37
  • 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. – Mark Rotteveel Jun 10 '20 at 18:20
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.

Naren
  • 797
  • 13
  • 12