【问题标题】:BouncyCastle C# PublicKey different than GnuPGBouncyCastle C# PublicKey 不同于 GnuPG
【发布时间】:2014-10-17 13:45:03
【问题描述】:

我正在尝试从 GnuPG 使用 BouncyCastle C# 库创建的密钥环中获取公共 PGP 密钥。我已经通过使用以下代码使其半工作。问题是它输出的公钥大约是真实公钥长度的一半,最后几个字节也不同。我只是想得到真正的钥匙。

更新:有趣的是,我生成的密钥环只有一个公钥,但我从 bouncycastle 中得到了两个。我还发现,如果将第二个键插入到末尾的前几个字符中,它几乎会产生原始键。最后只有几个字符不同。那么为什么有两个键,为什么会发生这种情况呢?我错过了什么?

GnuPG 密钥环不兼容吗?

另请注意,此处显示的代码仅获取最后一个键。我现在将每个都添加到列表中。

这是我的代码:

public static string ReadKey(string pubkeyFile)
{
    string theKey;
    Stream fs = File.OpenRead(pubkeyFile);

    //
    // Read the public key rings
    //
    PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(fs));
    fs.Close();

    foreach (PgpPublicKeyRing pgpPub in pubRings.GetKeyRings())
    {
        pgpPub.GetPublicKey();

        foreach (PgpPublicKey pgpKey in pgpPub.GetPublicKeys())
        {
            //AsymmetricKeyParameter pubKey = pgpKey.GetKey();
            //SubjectPublicKeyInfo k = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
            //byte[] keyData = k.ToAsn1Object().GetDerEncoded();
            //byte[] keyData = k.GetEncoded();
            byte[] keyData = pgpKey.GetEncoded();
            theKey = Convert.ToBase64String(keyData);
        }
    }
    return theKey;
}

这是实际的公钥:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.20 (MingW32)

mQENBFP2z94BCADKfQT9DGHm4y/VEAYGL7XiUavbv+aE7D2OZ2jCbwnx7BYzQBu8
63v5qYe7oH0oBOiw67VaQSjS58fSBAE8vlTkKjvRAscHJNUX9qZrQoRtpMSnrK7N
Ca9N2ptvof7ykF1TAgbxDSSnhwysVznYc7mx76BO6Qx8KChqEd0Yp3w2U89YkUqN
qdzjB7ZIhj5hDM9f4eyHwsz0uZgyqLKK5VgNj6dHVmOHZt6+RIydRC2lGfocWKM8
loPkk6GiSX9sdEm6GXxi7gV/Q3Jr0G099AFg57cWyj1eO6NC8YHLgBHwrB1IkFwi
J0x5IHZssy/XleQ1i1izc3ntWiiH24powuAhABEBAAG0H3N5bmFwczMgPHN5bmFw
czNAc2FmZS1tYWlsLm5ldD6JATkEEwECACMFAlP2z94CGwMHCwkIBwMCAQYVCAIJ
CgsEFgIDAQIeAQIXgAAKCRD944Hz1MHUYP+AB/4roauazFR5lDrJBFB0YoH4VFKM
28IJtuy6OThg3cxhqI/N74sZoxtB90QQk4lcshdpwD7CIe9TCKrnhWokIdm4N91m
TGDmW7iIeM3kcPp3mj9/7hGOetESuz9JxhBQ0aHAXYk5LdHeDKyRg1KL3JvWrJ27
fioDoLLpxxdudSd2nJLhi0hAaHKnkLVl98r37AwxTigGj+J2rN47D+UepJraf8je
eZrY/RfwKJVleF1KYPIgduwX3jdiABrI4EsZP/CdbEWTvmmkFFtD4clSMsmqaXPT
a3VeaL/saScBPL93tDsjqCddcgW28hsnhzoJ7TM78j2zNcTXZjK8/tNCDnShuQEN
BFP2z94BCADmCAMIpOp518ywUlG5Pze5HdpgGiQF26XzwxUt3mPAMXBUQ7vqRMD/
zNagPXKthp/p4t0jRoFwFwF+7CqRrxkv2Rrj5OqDD7JqETY5nfRZ0Hvfi4cPkf2g
S17SVI4LSFQ/v/sISNNiI3Bo/xvpOeK+Af087j4BEe8vjFuyzf08HCglKoL6WAp8
5+Wc2vj+7EbH61YloKKNugq34AyuNh1QYml6LI04b2KR0b/qXTW8UqLvrh4YGaOp
k80l7DpBmKgGtXn8JFfU9V3sGCscSnfzDvKjqpmtKXiJFxO2pyPCN5jRKfGMOSyA
fZ21NIrBJER/WvuIAls8Tikk+wKRKXrpABEBAAGJAR8EGAECAAkFAlP2z94CGwwA
CgkQ/eOB89TB1GDDEAf+OA9hgb3FLbEtcNvkUl9wTtLaxr9nAsBowofNEITH96hV
w4i6em9Rjg29/+4JrnDhibuhsFr/F8uKoj+iZGFw2NpXHYI6yS+BLbuVj8jOkYAy
Gq34HMNWXuS1Nr4VHOxKbKmmLu8YhdYRk2KF9fPI2Qj376C69W90R/LHByCrcCg7
xmqAvO9a8Eac7Rk+Fc+5NKVw9D1rP7MqZGgIQQoh8jLiI2MblvEEahwNxA9AYs8U
PpMD0pdo93wxXIYuKc40MF4yFL9LfpPxDnf373dbYQjk3pNThQ5RagIgLNEhRow4
5x/1wcO6FMx5a/irQXnJ2o1XYRvznBeCsoyOAYbikA==
=r3Qj
-----END PGP PUBLIC KEY BLOCK-----

这是 BouncyCastle 制作的 NEW KEY(抱歉无法格式化):

mQENBFP2z94BCADKfQT9DGHm4y / VEAYGL7XiUavbv + aE7D2OZ2jCbwnx7BYzQBu863v5qYe7oH0oBOiw67VaQSjS58fSBAE8vlTkKjvRAscHJNUX9qZrQoRtpMSnrK7NCa9N2ptvof7ykF1TAgbxDSSnhwysVznYc7mx76BO6Qx8KChqEd0Yp3w2U89YkUqNqdzjB7ZIhj5hDM9f4eyHwsz0uZgyqLKK5VgNj6dHVmOHZt6 + RIydRC2lGfocWKM8loPkk6GiSX9sdEm6GXxi7gV / Q3Jr0G099AFg57cWyj1eO6NC8YHLgBHwrB1IkFwiJ0x5IHZssy / XleQ1i1izc3ntWiiH24powuAhABEBAAG0H3N5bmFwczMgPHN5bmFwczNAc2FmZS1tYWlsLm5ldD6JATkEEwECACMFAlP2z94CGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRD944Hz1MHUYP + AB / 4roauazFR5lDrJBFB0YoH4VFKM28IJtuy6OThg3cxhqI / N74sZoxtB90QQk4lcshdpwD7CIe9TCKrnhWokIdm4N91mTGDmW7iIeM3kcPp3mj9 / 7hGOetESuz9JxhBQ0aHAXYk5LdHeDKyRg1KL3JvWrJ27fioDoLLpxxdudSd2nJLhi0hAaHKnkLVl98r37AwxTigGj + J2rN47D + UepJraf8jeeZrY / RfwKJVleF1KYPIgduwX3jdiABrI4EsZP / CdbEWTvmmkFFtD4clSMsmqaXPTa3VeaL / saScBPL93tDsjqCddcgW28hsnhzoJ7TM78j2zNcTXZjK8 / tNCDnShsAIAA7kBDQRT9s / eAQgA5ggDCKTqedfMsFJRuT83uR3aYBokBdul88MVLd5jwDFwVEO76kTA / 8zWoD1yrYaf6eLdI0aBcBcBfuwqka8ZL9ka4 + Tqgw + yahE2OZ30WdB734uHD5H9oEte0lSOC0hUP7 / 7CEjTYiNwaP8b6Tniv gH9PO4 + ARHvL4xbss39PBwoJSqC + lgKfOflnNr4 / uxGx + tWJaCijboKt + AMrjYdUGJpeiyNOG9ikdG / 6l01vFKi764eGBmjqZPNJew6QZioBrV5 / CRX1PVd7BgrHEp38w7yo6qZrSl4iRcTtqcjwjeY0SnxjDksgH2dtTSKwSREf1r7iAJbPE4pJPsCkSl66QARAQABiQEfBBgBAgAJBQJT9s / eAhsMAAoJEP3jgfPUwdRgwxAH / jgPYYG9xS2xLXDb5FJfcE7S2sa / ZwLAaMKHzRCEx / eoVcOIunpvUY4Nvf / uCa5w4Ym7obBa / xfLiqI / omRhcNjaVx2COskvgS27lY / IzpGAMhqt + BzDVl7ktTa + FRzsSmyppi7vGIXWEZNihfXzyNkI9 ++ guvVvdEfyxwcgq3AoO8ZqgLzvWvBGnO0ZPhXPuTSlcPQ9az + zKmRoCEEKIfIy4iNjG5bxBGocDcQPQGLPFD6TA9KXaPd8MVyGLinONDBeMhS / S36T8Q539 + 93W2EI5N6TU4UOUWoCICzRIUaMOOcf9cHDuhTMeWv4q0F5ydqNV2Eb85wXgrKMjgGG4pCwAgAD P>

还是不一样。将这两个键放在记事本中并搜索“tNCDnS”,然后它们会发生变化。

谢谢你一直陪着我。我已经做到了这一点,我不想为了一些糟糕的加密而废弃整个代码。

【问题讨论】:

  • 您尝试过getPublicKeyPacket 吗?也许您丢失了一些数据,例如信任信息和/或密钥上的签名。
  • 请帮忙!!!该库的文档为零,并且尽可能不直观。我需要帮助。我需要完成这个项目。我什至找不到 getPublicKeyPacket。
  • 该死,通常 C# 库是 Java 库的副本......我必须自己建立一个完整的项目来帮助你;这有点太多了……试试 bouncy-dev 邮件列表!
  • 猜猜我的时间不够长。不知道邮件列表〜=论坛。谢谢你告诉我。

标签: c# encryption bouncycastle pgp openpgp


【解决方案1】:

您可能是 BouncyCastle 对“钥匙圈”一词的不常见用法的受害者。以下是 BouncyCastle 对三个相关术语的用法:

PgpPublicKey:这是单个数学密钥的公共部分,采用 PGP 格式。它不包含任何子键。

PgpPublicKeyRing:这是一个带有子密钥的加密密钥。其他程序通常将此称为 PGP 密钥。

PgpPublicKeyRingBundle:这是任意数量的 PgpPublicKeyRings(在 BouncyCastle 中定义)。其他程序通常将此称为公钥环(无捆绑包)。

您遍历密钥环以查找所有 PgpPublicKey 对象。您将它们解码并返回最后一个也是最后一个作为字符串。如果您将输入和输出字符串粘贴到 pgpdump.net(您必须将 BEGIN 和 END 标头添加到输出中),您会看到在此过程中丢失了子项。请改用 PgpPublicKeyRing 的 GetEncoded() 方法。这应该保留所有信息,也更容易:-)。

此外,PGP 的基数编码不仅仅是 Base64 编码。许多程序和库,包括 BC,都忽略了是否存在 PGP 页眉和页脚以及 Radix 编码包含的 CRC 校验和,而不是简单的 Base64。但是,GPG 更严格,似乎不接受没有 CRC 校验和的 ASCII 装甲。因此,您必须使用二进制密钥(即问题代码中的 byte[] keyData)或创建适当的 PGP ASCII 装甲。我已经根据您的代码编辑了以下代码,以使用 BC 的 ArmoredOutputStream 实现后者:

public static string ReadKey(string pubkeyFile)
{
    Stream fs = File.OpenRead(pubkeyFile);

    //
    // Read the public key rings
    //
    PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(fs));
    fs.Close();

    foreach (PgpPublicKeyRing pgpPub in pubRings.GetKeyRings())
    {
            using (MemoryStream ms = new MemoryStream())
            {
                using (ArmoredOutputStream aos = new ArmoredOutputStream(ms))
                    pgpPub.Encode(aos);
                return System.Text.Encoding.ASCII.GetString(ms.ToArray());
            }
    }
    return null;
}

EDIT:以下是一个没有外部依赖的完整程序。它对我有用,即输出“相同!”。请运行那个确切的程序并检查它是否输出“相同!”或“差异!”。如果它输出“Same!”,那么您可以使用它来更正您自己的程序代码:

using System;
using System.IO;
using Org.BouncyCastle.Bcpg.OpenPgp;

class Program
{
    private const string PGP_OVERFLOW_KEYBODY =
    "mQENBFP2z94BCADKfQT9DGHm4y/VEAYGL7XiUavbv+aE7D2OZ2jCbwnx7BYzQBu8\r\n" +
    "63v5qYe7oH0oBOiw67VaQSjS58fSBAE8vlTkKjvRAscHJNUX9qZrQoRtpMSnrK7N\r\n" +
    "Ca9N2ptvof7ykF1TAgbxDSSnhwysVznYc7mx76BO6Qx8KChqEd0Yp3w2U89YkUqN\r\n" +
    "qdzjB7ZIhj5hDM9f4eyHwsz0uZgyqLKK5VgNj6dHVmOHZt6+RIydRC2lGfocWKM8\r\n" +
    "loPkk6GiSX9sdEm6GXxi7gV/Q3Jr0G099AFg57cWyj1eO6NC8YHLgBHwrB1IkFwi\r\n" +
    "J0x5IHZssy/XleQ1i1izc3ntWiiH24powuAhABEBAAG0H3N5bmFwczMgPHN5bmFw\r\n" +
    "czNAc2FmZS1tYWlsLm5ldD6JATkEEwECACMFAlP2z94CGwMHCwkIBwMCAQYVCAIJ\r\n" +
    "CgsEFgIDAQIeAQIXgAAKCRD944Hz1MHUYP+AB/4roauazFR5lDrJBFB0YoH4VFKM\r\n" +
    "28IJtuy6OThg3cxhqI/N74sZoxtB90QQk4lcshdpwD7CIe9TCKrnhWokIdm4N91m\r\n" +
    "TGDmW7iIeM3kcPp3mj9/7hGOetESuz9JxhBQ0aHAXYk5LdHeDKyRg1KL3JvWrJ27\r\n" +
    "fioDoLLpxxdudSd2nJLhi0hAaHKnkLVl98r37AwxTigGj+J2rN47D+UepJraf8je\r\n" +
    "eZrY/RfwKJVleF1KYPIgduwX3jdiABrI4EsZP/CdbEWTvmmkFFtD4clSMsmqaXPT\r\n" +
    "a3VeaL/saScBPL93tDsjqCddcgW28hsnhzoJ7TM78j2zNcTXZjK8/tNCDnShuQEN\r\n" +
    "BFP2z94BCADmCAMIpOp518ywUlG5Pze5HdpgGiQF26XzwxUt3mPAMXBUQ7vqRMD/\r\n" +
    "zNagPXKthp/p4t0jRoFwFwF+7CqRrxkv2Rrj5OqDD7JqETY5nfRZ0Hvfi4cPkf2g\r\n" +
    "S17SVI4LSFQ/v/sISNNiI3Bo/xvpOeK+Af087j4BEe8vjFuyzf08HCglKoL6WAp8\r\n" +
    "5+Wc2vj+7EbH61YloKKNugq34AyuNh1QYml6LI04b2KR0b/qXTW8UqLvrh4YGaOp\r\n" +
    "k80l7DpBmKgGtXn8JFfU9V3sGCscSnfzDvKjqpmtKXiJFxO2pyPCN5jRKfGMOSyA\r\n" +
    "fZ21NIrBJER/WvuIAls8Tikk+wKRKXrpABEBAAGJAR8EGAECAAkFAlP2z94CGwwA\r\n" +
    "CgkQ/eOB89TB1GDDEAf+OA9hgb3FLbEtcNvkUl9wTtLaxr9nAsBowofNEITH96hV\r\n" +
    "w4i6em9Rjg29/+4JrnDhibuhsFr/F8uKoj+iZGFw2NpXHYI6yS+BLbuVj8jOkYAy\r\n" +
    "Gq34HMNWXuS1Nr4VHOxKbKmmLu8YhdYRk2KF9fPI2Qj376C69W90R/LHByCrcCg7\r\n" +
    "xmqAvO9a8Eac7Rk+Fc+5NKVw9D1rP7MqZGgIQQoh8jLiI2MblvEEahwNxA9AYs8U\r\n" +
    "PpMD0pdo93wxXIYuKc40MF4yFL9LfpPxDnf373dbYQjk3pNThQ5RagIgLNEhRow4\r\n" +
    "5x/1wcO6FMx5a/irQXnJ2o1XYRvznBeCsoyOAYbikA==";

    static void Main(string[] args)
    {
        string parsedKey = ReadKeyDirectly(PGP_OVERFLOW_KEYBODY);
        if (parsedKey != PGP_OVERFLOW_KEYBODY.Replace("\r\n",""))
            Console.WriteLine("Difference!");
        else
            Console.WriteLine("Same!");
    }

    public static string ReadKeyDirectly(string stringKeyData)
    {
        Stream fs = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(stringKeyData));
        fs.Seek(0, SeekOrigin.Begin);

        PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(fs));

        foreach (PgpPublicKeyRing pubRing in pubRings.GetKeyRings())
            return Convert.ToBase64String(pubRing.GetEncoded());
        return null;
    }
}

【讨论】:

  • 这只是返回了所有的key,但是上面的问题依然存在。
  • 好的,所以我误解了你的问题。我以为你已经发布了你的输入,但它只是输出。我相应地更正了我的答案。如果您仍有疑问,请发表您的意见。
  • 感谢您的描述。这段代码仍然不起作用。我只得到了上面发布的实际公钥的一半,其余的是其他的。
  • 如果我使用您作为“实际公钥”发布的密钥作为我的 ReadKey 函数的参数文件的内容,则返回值与“实际公钥”逐位相同" -- 除了页眉和页脚行以及五个校验和字符。这对你来说有什么不同吗?然后 .NET 框架版本或您的 BC 版本会导致问题。不过,我怀疑我仍然以某种方式误解了你。另外,您是否尝试过将您的密钥发布到 pgpdump.net 以查看其中包含哪些 PGP 数据包?您的“新密钥”输出包含额外的信任数据包。
  • 它对我有用,所以它不是一般的 bc 错误。一个 ASCII 铠装 PGP 密钥由一个标头 (-----BEGIN...)、可选的 cmets、一个空行、Base64 编码的密钥、一个校验和 (=ABCD) 和一个页脚 (-----结尾...)。我们的 BC 代码只输出 base64 编码的密钥,但大多数软件仍然接受它。如果您对输出进行 Base64 解码,则您有一个没有 ASCII 装甲的有效 PGP 密钥。
猜你喜欢
  • 2019-01-29
  • 2023-03-28
  • 2014-08-23
  • 1970-01-01
  • 2013-08-17
  • 2020-07-29
  • 2015-06-26
  • 2022-09-30
  • 1970-01-01
相关资源
最近更新 更多