6

C# で DSA 署名を検証するにはどうすればよいですか?

与えられた:

  • メッセージテキスト、
  • 署名付きダイジェスト (通常は ASN.1 DER 形式)、
  • 公開鍵 (署名付き X.509 証明書、PEM または DER 形式)

いくつかのアプローチを試しましたが、成功しませんでした:

  • OpenSSL.NET :ライブラリに関するさまざまな奇妙なエラー。SourceForge で作成者と一緒に開いているスレッドを実行していますが、まだ解決できていません。

  • Microsoft .NET API:比較のために DER 署名を解凍できません。DSA 署名は 40 バイト (2 つの 20 バイト整数) ですが、DER でエンコードされた 2 つの整数のシーケンスとして提示されるため、合計の長さは 46 から 48 バイトの範囲になります (簡単な概要については、この投稿を参照してください)。 NET には、ASN.1/DER を解析するためのコードが含まれています (証明書を DER 形式で読み取ることができるため)。コードは深く埋もれており、アクセスする方法がないため、ASN.1/DER でエンコードされた sig から 40 バイトを正しく取得できます。 . この問題は私を次の選択肢に導きました...

  • BouncyCastle:関数を使用してOrg.BouncyCastle.Asn1、ASN.1 署名を解析し、それをコンポーネントの R および S 整数値に取り込むことができます。しかし、これらを署名検証ルーチンに渡すと、説明がなく失敗します。C# API は完全に文書化されておらず、Java のバージョンはほとんど文書化されていないため、私が何か間違ったことをしているのかどうかはわかりません (しかし、私が見つけることができる例や HOWTO 情報はありません)。

私は約1週間、この問題に身を投じてきました。誰かが以前にそれをやったに違いないことは知っていますが、完全な/実用的な例は見つかりませんでした.

ここには 3 つの C# プロジェクトがあり、それぞれ 95% 完了していますが、失敗の原因となる重大な欠陥が 1 つあります。動作するサンプルコードは非常に高く評価されます。

編集:これは、私が検証しようとしている署名の例で、Base64 と ASCII 16 進数に変換して投稿可能にしています。この特定のものは 47 バイトですが、適切なパーサーはそれを受け入れる必要があります。詳細については、DER 仕様を参照してください (BER/DER は、MSB が 1 の場合に符号を確認するために先頭に 00 を追加します)。

Base64: MC0CFQCUgq2DEHWzp3O4nOdo38mDu8mStwIUadZmbin7BvXxpeoJh7dhquD2CTM=

ASCII Hex: 302d0215009482ad831075b3a773b89ce768dfc983bbc992b7021469d6666e29fb06f5f1a5ea0987b761aae0f60933

構造は DER 仕様に準拠しています。次のように解析します。

30 2d: sequence, length 45 (may vary from 44 to 46)
 02 15: integer, length 21 (first byte is 00 to confirm sign)
  009482ad831075b3a773b89ce768dfc983bbc992b7
 02 14: integer, length 20 (leading 00 not necessary for this one)
  69d6666e29fb06f5f1a5ea0987b761aae0f60933

独自の DER パーサーを作成することは実際にはオプションではありません。エラーの余地が多すぎるため、これを適切に行う方法が必要です。

4

5 に答える 5

2

これを見てください: http://www.codeproject.com/KB/security/CryptoInteropSign.aspxこれは、私が抱えていた問題を解決しました。

于 2009-11-11T20:08:30.560 に答える
1

BouncyCastle (v1.7) を使用して、これを行うことができます (もちろん、エラー チェックを忘れないでください)。

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Asn1;

byte[] signature = ReadFile("signature.bin");
byte[] dataToVerify = ReadFile("data.bin");
byte[] rawPublicKey = KeyResources.publickey; // My public key is in a resource

var x509 = new X509Certificate2(rawPublicKey);
var dsa = x509.PublicKey.Key as DSACryptoServiceProvider;

// extract signature components from ASN1 formatted signature
DSASignatureDeformatter DSADeformatter = new DSASignatureDeformatter(dsa);
DSADeformatter.SetHashAlgorithm("SHA1");

Asn1InputStream bIn = new Asn1InputStream(new MemoryStream(signature));
DerSequence seq = bIn.ReadObject() as DerSequence;

var r11 = seq[0].GetEncoded();
var r21 = seq[1].GetEncoded();

byte[] p1363 = new byte[40];
Array.Copy(r11, r11.Length - 20, p1363, 0, 20);
Array.Copy(r21, r21.Length - 20, p1363, 20, 20);

// and finally we can verify
if (!DSADeformatter.VerifySignature(new SHA1CryptoServiceProvider().ComputeHash(dataToVerify), p1363))
{
    // Noo, mismatch!
}

私の signature.bin は OpenSSL を使用して生成されます。openssl dgst -sha1 -sign private.key data.bin > signature.bin

于 2013-10-04T14:15:08.173 に答える
1

DSA 署名を検証するコードは、NSshプロジェクトにあります。公開鍵は X.509 証明書から取得されないため、正確なニーズには合いませんが、出発点になる可能性があります。

于 2009-10-27T01:46:01.763 に答える
1

もう 1 つの良い例は、DotNetAutoUpdateコードです。RSA を使用していますが、DSA に切り替えるのは非常に簡単です。特に、次のファイルを見てください。

http://code.google.com/p/dotnetautoupdate/source/browse/trunk/source/DotNetAutoUpdate/UpdateKeys.cs


編集:基本的に、これに似たものが必要です:

var sha1 = new SHA1Managed();
var hash = sha1.ComputeHash(inputStream);

var signatureFormatter = new DSASignatureDeformatter(dsa);
signatureFormatter.SetHashAlgorithm("SHA1");
bool valid = signatureFormatter.VerifySignature(hash, signature); 

詳細については、MSDNを参照してください。


編集:別のオプションは Mono.Security ライブラリです:

  • ASN1を読むためのクラスがあります
  • X.509 証明書を読み取るためのアセンブリもあります。

それが役立つかどうかはわかりません...

于 2009-10-27T01:51:50.987 に答える
0

JFYI: OpenSSL コマンド ライン ツールによって生成された、有効な 45 バイトの DER DSA 署名 (INTEGERS の 1 つが 20 バイトではなく 19 バイトでした) が表示されることがあります。また、44 バイト (両方とも 19 バイト) が存在する可能性があるため、46 から 48 バイトよりも 6 から 48 バイトを期待するほうがよいでしょう。;-)

于 2013-09-19T09:14:27.753 に答える