Bouncy Castle ECDH和.net4原生ECDiffieHellmanCNG之间的区别

时间:2011-04-15 20:40:29

标签: c# bouncycastle elliptic-curve diffie-hellman

我已经能够使用.net4中的ECDiffieHellmanCNG生成私钥,并且我还使用了Bouncy Castle C#库来成功生成私钥。我想知道为什么.net 4版本生成字符数组的字符,而Bouncy Castle的ECDHBasicAgreement生成一种BigInteger(手动实现)。我希望能够互换使用这些库。谢谢!

2 个答案:

答案 0 :(得分:3)

您可能在BouncyCastle类层次结构的错误区域中执行了您想要执行的操作。 (我在同一个地方偶然发现,原因可能相同。)如果你想要实现必须可互操作的ECDH,你肯定是在错误的地方。

为什么它的结构如此不直观?好吧,原因是BouncyCastle的抽象是他们关注并提供价值的地方。而不是为那些说“我将要使用ECDH密钥加密密钥”并且想要处理低级加密细节的人做准备,BC希望你使用管理员级别的抽象,如“公钥”,“私钥”,和“证书”,并填写中间的“kind”和“bitstrength”等安全参数。

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,如同自签名的X509Certificate。

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提供了一个byte [],因为它调用了OLE平台本机代码,它为您完成了所有的抽象。它是用于此目的的最有效表示,因为它不解析从CNG返回的内容,执行最少量的对象装回CLR对象空间并依赖程序员来处理基本上不透明的blob。

BouncyCastle使用其BigInteger类,因为它实现了64位长的bignum计算。它是用于此目的的最有效表示,因为8位字节处理8位字节的开销远远超过64位长64位长处理的成本的8倍。无论哪种方式,它都需要在输入字节[]的不同部分迭代地调用BitConverter。那些迭代和方法调用加起来,因此BigInteger是“数字的内部表示”。

这些甚至不具有远程可比性,因此这可能不是您想要做的。

如果要从BigInteger获取byte [],请使用其ToByteArray()方法。如果要将byte []转换为BigInteger,请构造一个新的BigInteger对象,其byte []包含要计算的位字符串。 new BigInteger(oldBigInteger.ToByteArray())按预期工作(一个新的BigInteger对象,它与旧的具有相同的值)。直接使用它们通常是不合适的,因为EC公钥由两个数字组成。此外,ToByteArray()仅转储整数的值,它不包含任何DER编码信息,以将其标识为任何长度的整数。

(另外,在C#中,'byte'和'char'是不同大小的不同东西。'byte'是8位长.'char'是一个Unicode代码点,那些可能大于8位。 char'(以及'string',在概念上是一系列字符)需要编码/解码才能适合字节大小的片段。)

答案 1 :(得分:2)

每个Diffie-Hellman实现使用唯一的常量集从公钥+私钥中派生共享密钥。因此,两种实现都不能从完全相同的密钥对中获得完全相同的共享秘密。你最好自己测试它,或者在BouncyCastle邮件列表上询问它。

注意:ECDiffieHellmanCNG仅适用于Windows Vista / Windows 7及更高版本。另一方面,您可以在.net 1.1及更高版本和旧版Windows(2000,XP等)上使用BouncyCastle。