Возможно, вы находитесь не в той области иерархии классов BouncyCastle, что вы хотите сделать.(Я спотыкался в одном и том же месте, вероятно, по тем же причинам.) Если вы хотите внедрить ECDH, который должен быть совместимым, вы определенно не в том месте.
Почему он структурирован так неинтуитивно?Ну, причина в том, что абстракции в BouncyCastle - то, где они сосредотачивают свое внимание и обеспечивают свою ценность.Вместо того, чтобы готовить людей, говорящих «Я собираюсь использовать ключи шифрования ключей ECDH» и желающих иметь дело с низкоуровневыми криптографическими деталями, BC ожидает, что вы будете использовать абстракции уровня менеджера, такие как «открытый ключ», «закрытый ключ»,и «сертификат», и в середине его введите параметры безопасности, такие как «вид» и «битовая сила».
var _keypair = new ECKeyPairGenerator("EC").Init(
new KeyGenerationParameters(_SecureRandomSingleton, 256)).GenerateKeyPair();
// For the love of all that's holy don't do this in production, encrypt your keys!
var pkcs8gen = new Pkcs8Generator(_keypair.Private);
Stream pkcs8stream = new MemoryStream();
using(System.IO.TextWriter pkcs8writer = new StreamWriter(pkcs8stream))
{
var mywriter = new Org.BouncyCastle.OpenSsl.PemWriter(pkcs8writer);
mywriter.WriteObject(pkcs8gen.Generate());
mywriter.Writer.Flush();
}
BouncyCastle будет с удовольствием тратить время и электричество на пересчет открытого ключа при каждой загрузкеэто, если только вы не позаботитесь о сохранении _keypair.Public в чем-то вроде самоподписанного сертификата X509.
var _cgen = new X509V3CertificateGenerator();
_cgen.Reset();
_cgen.SetNotBefore(DateTime.Now);
_cgen.SetNotAfter(new DateTime(2999, 12, 31, 23, 59, 59, DateTimeKind.Utc));
var DN = new X509Name("CN=Self Signed Certificate");
_cgen.SetIssuerDN(DN);
_cgen.SetSubjectDN(DN);
_cgen.SetPublicKey(_keypair.Public);
_cgen.SetSignatureAlgorithm( // Can be anything ECDsaWith*
Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.ECDsaWithSha256.ToString());
_cgen.SetSerialNumber( // Serial number collisions suck
new Org.BouncyCastle.Math.BigInteger(
8 * 8 - 1, // number of bits to generate
_SecureRandomSingleton)); // source to generate from
var _cert = _cgen.Generate(_keypair.Private);
try
{
_cert.Verify(_keypair.Public);
} catch (Org.BouncyCastle.Security.Certificates.CertificateException E)
{
// error-handling code for Verify failure
// Ridiculous here because we know that _keypair is correct, but good practice
// to ensure that your keypair is correct and intact
}
Stream certStream = new MemoryStream();
TextWriter certWriter = new StreamWriter(certStream);
var pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(certWriter);
pemWriter.WriteObject(_cert);
pemWriter.Writer.Flush();
А вот как загрузить пару ключей из двух структур.
AsymmetricKeyParameter privateKey;
AsymmetricKeyParameter publicKey;
AsymmetricKeyPair reconstitutedPair;
certStream.Position = 0;
pkcs8Stream.Position = 0;
using (TextReader pkcs8reader = new StreamReader(pkcs8stream))
{
PemReader pemreader = new PemReader(pkcs8reader);
var privateKey = pemreader.ReadObject() as ECPrivateKeyParameters;
if (thisprivate == null)
throw new GeneralSecurityException("failed to read private key");
}
}
var certificate = new Org.BouncyCastle.X509.X509CertificateParser()
.ReadCertificate(certStream);
var publicKey = certificate.GetPublicKey();
reconstitutedPair = new AsymmetricKeyPair(publicKey,privateKey);
Теперь, после всего сказанного, вот ответ на ваш реальный вопрос.
.NET 4 предоставляет байт [], потому что он вызывает собственный код платформы OLE, который выполняет всю абстракцию за вас.Это наиболее эффективное представление для этой цели, потому что оно не анализирует то, что возвращается из CNG, выполняя наименьшее количество объектного бокса обратно в пространство объектов CLR и полагаясь на программиста, чтобы иметь дело с тем, что по сути является непрозрачным BLOB-объектом.
BouncyCastle использует свой класс BigInteger, потому что именно так он реализует вычисления bignum с 64-битными значениями long.Это наиболее эффективное представление для этой цели, поскольку накладные расходы на обработку 8-битного байта на 8-битный байт намного более чем в 8 раз превышают затраты на обработку 64-битного и 64-битного длинного.В любом случае, он требует итеративного вызова BitConverter для другого раздела входного байта [].Эти итерации и вызовы методов складываются, поэтому BigInteger является «внутренним представлением числа».
Это даже не дистанционно сопоставимые применения, так что это, вероятно, не то, что вы хотите делать.
Если вы хотите получить байт [] из BigInteger, используйте его метод ToByteArray ().Если вы хотите преобразовать byte [] в BigInteger, создайте новый объект BigInteger с байтом [], содержащим строку битов, с которой вы хотите вычислить.new BigInteger (oldBigInteger.ToByteArray ()) работает так, как вы ожидаете (новый объект BigInteger, который имеет то же значение, что и старый).Непосредственно работать с ними обычно нецелесообразно, поскольку открытые ключи EC состоят из двух чисел.Кроме того, ToByteArray () только сбрасывает значение целого числа, оно не включает никакой информации о кодировании DER, чтобы идентифицировать его как целое число любой длины.
(Кроме того, в C #, 'byte' и 'char'это разные вещи с разными размерами.' байт 'имеет длину 8 бит.' char 'является кодовой точкой Unicode, и они потенциально больше 8 бит.' char '(вместе с' string ', которая концептуально представляет собой последовательностьchars) требует кодирования / декодирования, прежде чем он уместится в куски размером в байт.)