2009-10-27 96 views
5

Làm cách nào để xác minh chữ ký DSA trong C#?Xác minh chữ ký DSA trong C# đang sử dụng định dạng ASN.1 được mã hóa BER/DER

Given:

  • nội dung tin nhắn,
  • một digest ký (thường là ASN.1 định dạng DER),
  • khóa công khai (trong một chứng chỉ X.509 ký, PEM hoặc DER định dạng)

tôi đã thử một số phương pháp, nhưng đã không có bất kỳ thành công:

  • OpenSSL.NET: nhiều lỗi lạ khác nhau với thư viện; Tôi đã có một số open thread running with the author over on SourceForge nhưng chưa thể giải quyết vấn đề này.

  • Microsoft .NET API: không thể giải nén chữ ký DER để so sánh. Chữ ký DSA là 40 byte (hai số nguyên 20 byte), nhưng được trình bày dưới dạng chuỗi DER được mã hóa gồm hai số nguyên, do đó tổng chiều dài có thể nằm trong khoảng từ 46 đến 48 byte (xem this post để có tổng quan nhanh). bao gồm mã để phân tích ASN.1/DER (vì nó có thể đọc chứng chỉ ở định dạng DER), nó được chôn sâu và không có cách nào để truy cập nó để bạn có thể truy xuất chính xác 40 byte từ sig được mã hóa ASN.1/DER. Vấn đề này dẫn tôi đến tùy chọn tiếp theo ...

  • BouncyCastle: thông qua việc sử dụng các Org.BouncyCastle.Asn1 chức năng, tôi có thể phân tích chữ ký ASN.1 và kéo nó vào đó là thành phần R và các giá trị số nguyên S. Nhưng khi tôi vượt qua những thói quen xác minh chữ ký, nó không thành công mà không có lời giải thích nào được đưa ra. Tôi không chắc chắn nếu tôi đang làm điều gì sai trái, bởi vì C# API là hoàn toàn không có giấy tờ, và phiên bản Java là hầu như không ghi nhận (nhưng không có ví dụ hoặc HOWTO thông tin mà tôi có thể tìm thấy.)

Tôi đã ném bản thân mình vào vấn đề này trong khoảng một tuần nay. Tôi biết ai đó phải làm điều đó trước đây, nhưng tôi đã không tìm thấy bất kỳ ví dụ hoàn chỉnh/làm việc nào.

Tôi có ba dự án C# đang ngồi ở đây, mỗi 95% hoàn thành nhưng có một lỗ hổng quan trọng gây ra lỗi. Bất kỳ mã ví dụ làm việc nào cũng sẽ được đánh giá cao.

chỉnh sửa: đây là ví dụ về chữ ký tôi đang cố gắng xác minh, được chuyển đổi thành Base64 và ASCII hex để làm cho nó có thể đăng. cái này là 47 byte nhưng một phân tích cú pháp thích hợp vẫn phải chấp nhận nó, đọc lên trên spec DER để biết thêm (BER/DER thêm một lãnh đạo 00 để xác nhận dấu hiệu nếu MSB là 1)

Base64: MC0CFQCUgq2DEHWzp3O4nOdo38mDu8mStwIUadZmbin7BvXxpeoJh7dhquD2CTM= 

ASCII Hex: 302d0215009482ad831075b3a773b89ce768dfc983bbc992b7021469d6666e29fb06f5f1a5ea0987b761aae0f60933 

Structure theo thông số DER; nó phân tích như sau:

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 

Viết phân tích cú pháp DER của riêng tôi thực sự không phải là một lựa chọn, quá nhiều chỗ cho sai sót và có nhận được một cách để làm điều này đúng.

+0

Tôi đã tự hỏi nếu bạn có thể làm cho tôi một ưu tiên và thay đổi tiêu đề từ "Xác minh chữ ký DSA trong C#" để "Xác minh chữ ký DSA trong C# với định dạng ASN.1" hoặc một cái gì đó tương tự. Có thể giúp tìm kiếm người một chút. – Greg

+0

Giống như một bình luận; Tôi đang đi theo cách khác (xác minh một chữ ký trong Java đã được tạo ra trong .NET); Tôi đã phải viết một trình chuyển đổi từ định dạng .NET DSA (chỉ là r || s trong 40 byte) sang định dạng DER. Theo những gì tôi tìm thấy ở đây (http://www.mombu.com/microsoft/security-crypto/t-dsa-signature-format-674106.html) định dạng DER dự kiến ​​r và s là big-endian nhưng điều đó đã không 't làm việc ở tất cả vì vậy tôi để nó như là một chút nhỏ và nó hoạt động ... Tôi đã không tìm thấy bất cứ điều gì rất rõ ràng về điều này; có nên là người lớn hay nhỏ ... nếu có ai biết thì hãy kêu vang! – SonarJetLens

Trả lời

1

Một đoạn mã xác minh chữ ký DSA có thể được tìm thấy trong dự án NSsh. Nó không phù hợp với nhu cầu chính xác của bạn vì khóa công khai không được lấy từ một X.509 giấy chứng nhận nhưng nó có thể cung cấp cho bạn một điểm khởi đầu.

+0

Theo như tôi thấy, nó tạo chữ ký trong nội bộ: SignatureOfH = hostKey.Sign (H); Tôi cần phải đọc một chữ ký được tạo bên ngoài, dẫn đến vấn đề ASN.1 (được mô tả một chút trong bài đăng cập nhật.) – andersop

1

Một ví dụ khác là mã DotNetAutoUpdate. Nó sử dụng RSA nhưng nó khá đơn giản để chuyển sang DSA. Đặc biệt có một cái nhìn tại tập tin này:

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


Edit: về cơ bản bạn muốn một cái gì đó tương tự như sau:

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

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

tin chi tiết về MSDN.


Edit: lựa chọn khác là các thư viện Mono.Security:

  • Có một lớp học cho việc đọc ASN1
  • Ngoài ra còn một assembly là để đọc cerficiates X.509.

Tôi không chắc chắn nếu điều đó giúp ...

+0

Vấn đề với việc triển khai .NET là nó không thể phân tích cú pháp định dạng ASN.1 của chữ ký - Tôi không thể tạo đối tượng "chữ ký" trong ví dụ trên. – andersop

+0

@andersop bạn có thể đăng một ví dụ về chữ ký ASN.1 không? –

+0

@Luke Quinane: Chắc chắn, tôi đã chỉnh sửa nó vào OP vì các bình luận không hỗ trợ định dạng. – andersop

0

JFYI: Đôi khi tôi thấy các chữ ký DER DSA 45 byte hợp lệ (một trong INTEGERS là 19 byte không phải 20), được tạo bởi công cụ dòng lệnh OpenSSL. Và có vẻ như có thể có 44 byte (cả hai đều là 19 byte), vì vậy bạn nên mong đợi mọi thứ từ 6 đến 48 byte thay vì từ 46 đến 48. ;-)

1

Sử dụng BouncyCastle (v1.7), tôi có thể làm điều này (đừng quên kiểm tra lỗi, tất nhiên):

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! 
} 

Chữ ký của tôi.bin được tạo bằng OpenSSL, ví dụ: openssl dgst -sha1 -sign private.key data.bin > signature.bin

Các vấn đề liên quan