BouncyCastle C# PublicKey отличается от GnuPG
Я пытаюсь получить открытый ключ PGP из набора ключей, созданного GnuPG с использованием библиотеки BouncyCastle C#. Я получил его на половину работы с помощью следующего кода. Проблема в том, что открытый ключ, который он выводит, составляет примерно половину длины реального, а последние несколько байтов также различаются. Я просто пытаюсь получить настоящий ключ.
ОБНОВЛЕНИЕ: кое-что интересное, чтобы заметить, - то, что у сгенерированного мной набора ключей был только один открытый ключ, все же я получаю два из 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 (извините, не могу не отформатировать):
mQENBFP2z94BCADKfQT9DGHm4y / VEAYGL7XiUavbv + aE7D2OZ2jCbwnx7BYzQBu863v5qYe7oH0oBOiw67VaQSjS58fSBAE8vlTkKjvRAscHJNUX9qZrQoRtpMSnrK7NCa9N2ptvof7ykF1TAgbxDSSnhwysVznYc7mx76BO6Qx8KChqEd0Yp3w2U89YkUqNqdzjB7ZIhj5hDM9f4eyHwsz0uZgyqLKK5VgNj6dHVmOHZt6 + RIydRC2lGfocWKM8loPkk6GiSX9sdEm6GXxi7gV / Q3Jr0G099AFg57cWyj1eO6NC8YHLgBHwrB1IkFwiJ0x5IHZssy / XleQ1i1izc3ntWiiH24powuAhABEBAAG0H3N5bmFwczMgPHN5bmFwczNAc2FmZS1tYWlsLm5ldD6JATkEEwECACMFAlP2z94CGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRD944Hz1MHUYP + АВ /4roauazFR5lDrJBFB0YoH4VFKM28IJtuy6OThg3cxhqI/N74sZoxtB90QQk4lcshdpwD7CIe9TCKrnhWokIdm4N91mTGDmW7iIeM3kcPp3mj9/7hGOetESuz9JxhBQ0aHAXYk5LdHeDKyRg1KL3JvWrJ27fioDoLLpxxdudSd2nJLhi0hAaHKnkLVl98r37AwxTigGj+J2rN47D+UepJraf8jeeZrY/RfwKJVleF1KYPIgduwX3jdiABrI4EsZP/CdbEWTvmmkFFtD4clSMsmqaXPTa3VeaL/saScBPL93tDsjqCddcgW28hsnhzoJ7TM78j2zNcTXZjK8/tNCDnShsAIAA7kBDQRT9s/eAQgA5ggDCKTqedfMsFJRuT83uR3aYBokBdul88MVLd5jwDFwVEO76kTA/8zWoD1yrYaf6eLdI0aBcBcBfuwqka8ZL9ka4+Tqgw+yahE2OZ30WdB734uHD5H9oEte0lSOC0hUP7/7CEjTYiNwaP8b6TnivgH9 РО4+ARHvL4xbss39PBwoJSqC+lgKfOflnNr4/uxGx+tWJaCijboKt+AMrjYdUGJpeiyNOG9ikdG/6l01vFKi764eGBmjqZPNJew6QZioBrV5/CRX1PVd7BgrHEp38w7yo6qZrSl4iRcTtqcjwjeY0SnxjDksgH2dtTSKwSREf1r7iAJbPE4pJPsCkSl66QARAQABiQEfBBgBAgAJBQJT9s/eAhsMAAoJEP3jgfPUwdRgwxAH/jgPYYG9xS2xLXDb5FJfcE7S2sa/ZwLAaMKHzRCEx/eoVcOIunpvUY4Nvf/uCa5w4Ym7obBa/xfLiqI/omRhcNjaVx2COskvgS27lY/IzpGAMhqt+BzDVl7ktTa+FRzsSmyppi7vGIXWEZNihfXzyNkI9++guvVvdEfyxwcgq3AoO8ZqgLzvWvBGnO0ZPhXPuTSlcPQ9az+zKmRoCEEKIfIy4iNjG5bxBGocDcQPQGLPFD6TA9KXaPd8MVyGLinONDBeMhS/S36T8Q539+93W2EI5N6TU4UOUWoCICzRIUaMOOcf9cHDuhTMeWv4q0F5ydqNV2Eb85wXgrKMjgGG4pCwAgAD
Все еще не то же самое. Поместите обе клавиши в блокнот и найдите "tNCDnS", после чего они меняются.
Спасибо, что остались со мной. Я получил достаточно далеко с этим, что я не хочу отбросить весь код для некоторого дерьмового шифрования.
1 ответ
Возможно, вы стали жертвой несколько необычного использования BouncyCastle термина "связка ключей". Вот использование BouncyCastle трех связанных терминов:
PgpPublicKey: это открытая часть одного математического ключа в формате PGP. Он не содержит никаких подразделов.
PgpPublicKeyRing: это криптографический ключ со своими подразделами. Другие программы обычно называют это ключом PGP.
PgpPublicKeyRingBundle: Это любое количество PgpPublicKeyRings (как определено в BouncyCastle). Другие программы обычно называют это открытым кольцом ключей (без пакета).
Вы перебрали список ключей, чтобы найти все объекты PgpPublicKey. Вы декодируете их и возвращаете последний и только последний из них в виде строки. Если вы вставите входные и выходные строки в pgpdump.net (вам нужно добавить заголовки BEGIN и END к выходным данным), вы увидите, что в этой процедуре вы потеряли подраздел. Вместо этого используйте метод GetEncoded() PgpPublicKeyRing. Это должно сохранить всю информацию, а также проще:-).
Кроме того, кодирование PGP Radix- это нечто большее, чем просто кодирование Base64. Многие программы и библиотеки, включая BC, игнорируют наличие заголовков и нижних колонтитулов PGP, а также контрольной суммы CRC, которую включает в себя кодирование Radix, в отличие от простого Base64. Тем не менее, GPG является более строгим и, похоже, не принимает ASCII-доспехи без контрольной суммы CRC. Поэтому вы должны использовать двоичный ключ (который является keyData byte[] в вашем коде проблемы) или создать соответствующую броню 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;
}
РЕДАКТИРОВАТЬ: Ниже приведена полная программа без внешних зависимостей. У меня это работает, т.е. выводит "То же самое!". Пожалуйста, запустите эту точную программу и проверьте, выводит ли она "Same!" или "Разница!" Если он выводит "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;
}
}