Разница между Bouncy Castle ECDH и родным .net4 ECDiffieHellmanCNG - PullRequest
3 голосов
/ 16 апреля 2011

Мне удалось сгенерировать закрытый ключ, используя ECDiffieHellmanCNG в .net4, и я также использовал библиотеку Bouncy Castle C # для успешной генерации закрытых ключей.Я хочу знать, почему версия .net 4 генерирует байтовый массив символов, а ECDHBasicAgreement из Bouncy Castle генерирует тип BigInteger (реализуется вручную).Я хотел бы иметь возможность использовать эти библиотеки взаимозаменяемо.Спасибо!

Ответы [ 2 ]

3 голосов
/ 02 февраля 2012

Возможно, вы находитесь не в той области иерархии классов 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) требует кодирования / декодирования, прежде чем он уместится в куски размером в байт.)

2 голосов
/ 16 апреля 2011

Каждая реализация Диффи-Хеллмана использует уникальный набор констант для получения общего секрета из открытого + закрытого ключа. Таким образом, ни одна из реализаций не может получить один и тот же общий секрет из одних и тех же пар ключей. Вам лучше протестировать его самостоятельно или задать вопрос в списках рассылки BouncyCastle.

Примечание: ECDiffieHellmanCNG доступен только в Windows Vista / Windows 7 и выше. С другой стороны, вы можете использовать BouncyCastle на .net 1.1 и выше и более старых версиях Windows (2000, XP и т. Д.)

...