Question

EDIT: This code works. The key text is different every time, but the key material is the same. I have updated the code below to collect the data for key creation from the console, without echo.

I would like to generate a Pgp keypair from a livecd with a pass phrase, distribute the public key and use it to encrypt personal data before I store it at Google drive, but never write the private key to disk.

I realize I could just use the RSA key directly, but I would prefer to have a pgp key for ease of use and flexibility.

When I need to decrypt data I would boot from a livecd again and reproduce the private key.

This is the code I am using... It produces the rsa key the same every time, but the pgp keys come out different. What am I missing?

Thanks in advance,

Code follows:

using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;

namespace PgpKeyFromPassphrase
{
    class Program
    {
        static void Main()
        {
            string identity = ReadIdentityFromConsole();
            DateTime keyDate = ReadDateFromConsole();
            string passPhrase = ReadPassphraseFromConsole();
            Console.WriteLine("Generating seed and keys.  This will take some time");
            //Hash the passphrasse 50,000 times
            var seed = GenerateSeed(passPhrase);
            //Create the RSA keypair from the seed
            var keys = GenerateRsaKeys(seed);
            //Create PGP secret key from keypair
            var secretKey = GeneratePgpKeys(keyDate, identity, keys);
            //Write armored secret key
            PrintSecretKey(secretKey);
            //Write armored public key
            PrintPublicKey(secretKey);
            Console.WriteLine("Copy the key and press enter to exit the program");
            Console.ReadLine();
        }


        private static string ReadIdentityFromConsole()
        {
            string retVal = null;
            while (retVal == null || retVal.Equals(string.Empty))
            {
                Console.WriteLine("Type a name to be associated with the Key");
                retVal = Console.ReadLine();
            }
            return retVal;
        }

        private static DateTime ReadDateFromConsole()
        {
            DateTime retVal = DateTime.Today;
            while (true)
            {
                Console.WriteLine("Enter the key creation date.  Press enter for today");
                var line = Console.ReadLine();
                if (line == null || line.Equals(string.Empty) || DateTime.TryParse(line, out retVal)) break;
                else Console.WriteLine("Failed to parse date, try again");
            }
            return retVal;
        }

        static string ReadPassphraseFromConsole()
        {
            var pass1 = new StringBuilder();
            var pass2 = new StringBuilder();
            while (pass1.Length == 0 || !pass1.Equals(pass2))
            {
                if (pass1.Length > 0 && pass2.Length > 0 && !pass1.Equals(pass2))
                {
                    pass1 = new StringBuilder();
                    pass2 = new StringBuilder();
                    Console.WriteLine("Passphrases don't match! Try again.");
                }
                Console.WriteLine("type a strong passphrase and hit enter");
                var key = Console.ReadKey(true);
                while (!key.Key.Equals(ConsoleKey.Enter))
                {
                    if (key.Key.Equals(ConsoleKey.Backspace))
                    {
                        if (pass1.Length > 0) pass1.Remove(pass1.Length - 1, 1);
                    }
                    else pass1.Append(key.KeyChar);
                    key = Console.ReadKey(true);
                }
                Console.WriteLine("repeat passphrase and hit enter");
                key = Console.ReadKey(true);
                while (!key.Key.Equals(ConsoleKey.Enter))
                {
                    if (key.Key.Equals(ConsoleKey.Backspace))
                    {
                        if (pass2.Length > 0) pass2.Remove(pass2.Length - 1, 1);
                    }
                    else pass2.Append(key.KeyChar);
                    key = Console.ReadKey(true);
                }
            }
            return pass1.ToString();
        }

        static byte[] GenerateSeed(string passPhrase)
        {
            //Hash the passphrasse 50,000 times
            var passPhraseBytes = new byte[passPhrase.Length * sizeof(char)];
            Buffer.BlockCopy(passPhrase.ToCharArray(), 0, passPhraseBytes, 0, passPhraseBytes.Length);
            var digester = new Sha256Digest();
            var seed = new byte[digester.GetDigestSize()];
            digester.BlockUpdate(seed, 0, seed.Length);
            digester.DoFinal(seed, 0);
            for (var i = 0; i < 49999; i++)
            {
                digester = new Sha256Digest();
                digester.BlockUpdate(seed, 0, seed.Length);
                digester.DoFinal(seed, 0);
            }
            return seed;
        }

        static AsymmetricCipherKeyPair GenerateRsaKeys(byte[] seed)
        {
            var kpg = new RsaKeyPairGenerator();
            kpg.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(0x13), new SecureRandom(seed), 4096, 8));
            AsymmetricCipherKeyPair keys = kpg.GenerateKeyPair();
            return keys;
        }

        static PgpSecretKey GeneratePgpKeys(DateTime keyDate, string identity, AsymmetricCipherKeyPair keys)
        {
            var secretKey = new PgpSecretKey(PgpSignature.DefaultCertification, PublicKeyAlgorithmTag.RsaGeneral, keys.Public, keys.Private, keyDate, identity, SymmetricKeyAlgorithmTag.Cast5, null, null, null, new SecureRandom());
            return secretKey;
        }

        static void PrintSecretKey(PgpSecretKey secretKey)
        {
            var secretMemStream = new MemoryStream();
            var secretArmoredStream = new ArmoredOutputStream(secretMemStream);
            secretKey.Encode(secretArmoredStream);
            secretArmoredStream.Close();
            var ascPgpSecretKey = Encoding.ASCII.GetString(secretMemStream.ToArray());
            Console.WriteLine(ascPgpSecretKey);
        }

        static void PrintPublicKey(PgpSecretKey secretKey)
        {
            var pubMemStream = new MemoryStream();
            var pubArmoredStream = new ArmoredOutputStream(pubMemStream);
            secretKey.PublicKey.Encode(pubArmoredStream);
            pubArmoredStream.Close();
            var ascPgpPublicKey = Encoding.ASCII.GetString(pubMemStream.ToArray());
            Console.WriteLine(ascPgpPublicKey);
        }

    }
}
Was it helpful?

Solution

Thanks Duncan!

It worked.

The ASCII armored text that comes out for the PGP keys are different every time even though the underlying RSA keys are the same.

However I was able generate a keypair use the public key to encrypt a file then generate a new keypair and use that new private key to decrypt the file.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top