.net4 で ECDiffieHellmanCNG を使用して秘密鍵を生成できました。また、Bouncy Castle C# ライブラリを使用して秘密鍵を正常に生成しました。.net 4 バージョンが char のバイト配列を生成し、Bouncy Castle の ECDHBasicAgreement が BigInteger (手動で実装) の型を生成する理由を知りたいです。これらのライブラリを互換的に使用できるようにしたいと考えています。ありがとう!
2 に答える
おそらく、やりたいことに対して、BouncyCastle クラス階層の間違った領域にいるのでしょう。(おそらく同じ理由で、同じ場所でつまずきました。) 相互運用可能でなければならない ECDH の実装を検討している場合、間違いなく間違った場所にいます。
なぜそれほど直感的に構造化されていないのですか?その理由は、BouncyCastle の抽象化が注目を集め、価値を提供する場所だからです。「私は ECDH キー暗号化キーを使用するつもりです」と言って低レベルの暗号化の詳細を処理したいという人々に対応する代わりに、BC は、「公開キー」、「秘密キー」などのマネージャーレベルの抽象化を使用することを期待しています。 「certificate」と「certificate」の中間に「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();
}
_keypair.Public を自己署名の X509Certificate のようなものに保存するように注意しない限り、BouncyCastle はこれをロードするたびに公開鍵を再計算するために時間と電力を無駄に浪費します。
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();
そして、2 つの構造体からキーペアをロードする方法は次のとおりです。
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 プラットフォーム ネイティブ コードを呼び出すため、byte[] を提供します。これは、CNG から返されたものを解析せず、CLR オブジェクト空間に戻すオブジェクト ボクシングを最小限に抑え、本質的に不透明な BLOB を処理するプログラマに依存するため、この目的では最も効率的な表現です。
BouncyCastle は BigInteger クラスを使用します。これは、64 ビット long で bignum 計算を実装する方法であるためです。8 ビット バイトを 8 ビット バイトごとに処理するオーバーヘッドは、64 ビット長を 64 ビット長で処理するコストの 8 倍をはるかに超えるため、これはこの目的には最も効率的な表現です。いずれにしても、入力 byte[] の別のセクションで BitConverter を繰り返し呼び出す必要があります。これらの反復とメソッド呼び出しが加算されるため、BigInteger は「数値の内部表現」です。
これらは遠く離れた比較可能な用途でさえないため、これはおそらくあなたがしたいことではありません.
BigInteger から byte[] を取得する場合は、その ToByteArray() メソッドを使用します。byte[] を BigInteger に変換する場合は、計算に使用するビット文字列を含む byte[] を使用して新しい BigInteger オブジェクトを作成します。new BigInteger(oldBigInteger.ToByteArray()) は期待どおりに機能します (古いものと同じ値を持つ新しい BigInteger オブジェクト)。EC 公開鍵は 2 つの数字で構成されているため、これらを直接操作することは通常不適切です。また、ToByteArray() は整数の値をダンプするだけで、任意の長さの整数として識別するための DER エンコード情報は含まれません。
(また、C# では、'byte' と 'char' はサイズが異なる別のものです。'byte' は 8 ビット長です。'char' は Unicode コード ポイントであり、8 ビットよりも大きい可能性があります。概念的には一連の文字である「文字列」と一緒に) バイトサイズの断片に収まる前に、エンコード/デコードが必要です。)
それぞれの Diffie-Hellman 実装は、固有の定数セットを使用して、公開鍵と秘密鍵から共有秘密鍵を導き出します。そのため、どちらの実装も、まったく同じ鍵ペアからまったく同じ共有秘密を導出することはできません。自分でテストするか、BouncyCastle メーリング リストで質問することをお勧めします。
注: ECDiffieHellmanCNG は、Windows Vista/Windows 7 以降でのみ使用できます。一方、BouncyCastle は .net 1.1 以降および古い Windows バージョン (2000、XP など) で使用できます。