当前位置: 首页 > 知识库问答 >
问题:

我可以使用Bouncycastle for C#创建一个带有密码短语的可复制PGP小键盘吗?

贺宏逸
2023-03-14

代码如下:

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

    }
}

共有1个答案

漆雕疏珂
2023-03-14

谢谢邓肯!

奏效了。

尽管底层的RSA密钥相同,但PGP密钥的ASCII装甲文本每次都不同。

 类似资料:
  • 我想用自签名证书连接到TLS服务器,所以我需要一个自定义信任存储。似乎绝对需要密码才能导入证书,但我真的不需要密码保护信任存储区。使用标准密码“changeit”可以工作,但我更希望没有密码。 请注意,这是一个“信任存储”,而不是“密钥存储”,因此信任存储中根本没有秘密材料:只有服务器的证书,因此客户机可以验证服务器是可信的。 使用可以吗?是否有其他工具可以从信任存储区中移除密码?了解到身份验证信

  • 我想创建一个简单的Java类文件,并从我的所有项目访问它。 我知道我可以通过复制/粘贴方法来完成,但在这种情况下,类文件将独立于其原始源。我在原始类文件中所做的任何更改都不会影响已经复制到其他项目中的类文件。 在Android Studio中有链接类文件的方法吗?

  • 我正在使用JPA QueryDSL从DB查询数据,这很管用。现在,我有一个用JPA QueryDSL编写的复杂的select查询,我需要使用它创建一个临时表,如下所示(POSTGRES)。 有没有人可以帮助使用JPA QueryDSL定义上面的查询。有可能用JPA查询处理DDL吗? 您对我的问题提出的建议将不胜感激。

  • 从文档中可以看出,这在spring-boot-maven-plugin中是不可能的。 所以现在我正在尝试创建一个测试JAR,但是当我运行应用程序类时,我得到了 有没有关于如何在没有maven插件的情况下打包SpringBoot应用程序的文档?

  • 嗨,我只是想知道有没有可能创建一个通用类来确认ObserveObject协议,它可以被多个ContentView使用。 如果我能做到这一点,那么我将能够使我的ContentView和Model类完全通用和可重用。 我希望实现的一个例子: 如果我能做到这一点,任何类都可以实现ContentViewModelType,并成为ContentView的模型,使其通用且可重用。举个例子 但是当我尝试初始化C

  • 假设我有一个记录品牌之间相关性值的集合(别管如何生成或解释这种相关性。)那么这个集合中的字段将包括:'Brand1'、'Brand2'和'correlation'。 为了举例起见,假设品牌可以承担“Google”、“Microsoft”等字符串值,这样每个文档就记录了各种品牌名称之间的相关性。 我想在'Brand1'和'Brand2'字段上创建一个唯一的索引,以便每个文档在集合中只记录一对品牌之间