2009-10-27 12 views
5

Come posso verificare una firma DSA in C#?Verificare una firma DSA in C# che utilizza il formato ASN.1 codificato BER/DER

Data:

  • il testo del messaggio,
  • un digest firmato (in genere ASN.1 formato DER),
  • la chiave pubblica (in un certificato X.509 firmato, PEM o DER formato)

ho provato una serie di approcci, ma non hanno avuto alcun successo:

  • OpenSSL.NET: vari errori strani con la libreria; Ho uno open thread running with the author over on SourceForge ma non sono ancora riuscito a risolverlo.

  • API Microsoft .NET: Impossibile decomprimere la firma DER per il confronto. Una firma DSA è 40 byte (due interi a 20 byte), ma viene presentata come una sequenza codificata DER di due numeri interi, quindi la lunghezza totale può variare da 46 a 48 byte (vedere this post per una rapida panoramica.) While .NET include il codice per analizzare ASN.1/DER (perché può leggere i certificati in formato DER), è sepolto in profondità e non c'è modo di accedervi in ​​modo da poter recuperare correttamente i 40 byte dal sig codificato ASN.1/DER. Questo problema mi ha portato alla successiva opzione ...

  • BouncyCastle: attraverso l'uso delle funzioni Org.BouncyCastle.Asn1, posso analizzare la firma ASN.1 e tirarlo in esso è componente valori interi S R e. Ma quando li passo alle routine di verifica della firma, non funziona senza alcuna spiegazione fornita. Non sono sicuro se sto facendo qualcosa di sbagliato, perché il C# API è completamente privi di documenti, e la versione di Java è a malapena documentato (ma non c'è alcun esempio o HOWTO informazioni che posso trovare.)

Mi sono lanciato questo problema per circa una settimana. So che qualcuno deve averlo fatto prima, ma non ho trovato nessun esempio completo/funzionante.

Ho tre progetti C# qui seduti, ciascuno completo al 95% ma con un difetto critico che causa il fallimento. Qualsiasi codice di esempio funzionante sarebbe enormemente apprezzato.

modifica: ecco un esempio di firma che sto cercando di verificare, convertito in Base64 e hex ASCII per renderlo postabile. Questa in particolare è di 47 byte, ma un parser corretta deve ancora accettare, leggere sulle specifiche DER per maggiori informazioni (BER/DER aggiunge un importante 00 per confermare il segno se il MSB è 1)

Base64: MC0CFQCUgq2DEHWzp3O4nOdo38mDu8mStwIUadZmbin7BvXxpeoJh7dhquD2CTM= 

ASCII Hex: 302d0215009482ad831075b3a773b89ce768dfc983bbc992b7021469d6666e29fb06f5f1a5ea0987b761aae0f60933 

Struttura è secondo le specifiche DER; analizza come segue:

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 

scrivere il mio parser DER è davvero non è un'opzione, troppo spazio per l'errore e ci deve essere un modo per farlo correttamente.

+0

Mi chiedevo se potevi farmi un favore e cambiare il titolo da "Verifica firma DSA in C#" a "Verifica firma DSA in C# con formato ASN.1" o qualcosa del genere. Potrebbe aiutare a cercare un po 'le persone. – Greg

+0

Proprio come un commento; Sto andando nella direzione opposta (verifica una firma in Java creata in .NET); Ho dovuto scrivere un convertitore dal formato .NET DSA (che è solo r ||s in 40 byte) nel formato DER. Secondo quanto ho trovato qui (http://www.mombu.com/microsoft/security-crypto/t-dsa-signature-format-674106.html) il formato DER si aspetta che r e s siano big-endian ma ciò non ha Non lavoro affatto, quindi l'ho lasciato come little-endian e funziona ... Non ho trovato nulla di molto chiaro su questo; dovrebbe essere grande o piccolo -endiano ... se qualcuno lo sa, per favore suonate! – SonarJetLens

risposta

1

Un pezzo di codice che verifica una firma DSA può essere trovato nel progetto NSsh. Non soddisfa i tuoi bisogni esatti poiché la chiave pubblica non viene estratta da una X.Certificato 509 ma potrebbe darti un punto di partenza.

+0

Per quanto posso vedere, sta generando la firma internamente: SignatureOfH = hostKey.Sign (H); Ho bisogno di leggere una firma generata esternamente, che porta al problema ASN.1 (descritto un po 'di più nel post aggiornato.) – andersop

1

Un altro buon esempio è il codice DotNetAutoUpdate. Usa RSA ma dovrebbe essere abbastanza semplice passare a DSA. In particolare, dare un'occhiata a questo file:

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


Edit: fondamentalmente si desidera qualcosa di simile a questo:

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

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

Maggiori dettagli su MSDN.


Edit: Un'altra opzione è le librerie Mono.Security:

  • C'è una classe per la lettura ASN1
  • C'è anche un assembly per la lettura cerficiates X.509.

non sono sicuro se questo aiuta ...

+0

Il problema con l'implementazione .NET è che non è in grado di analizzare il formato ASN.1 del firme - Non riesco a generare l'oggetto "firma" nell'esempio sopra. – andersop

+0

@andersop puoi pubblicare un esempio della firma ASN.1? –

+0

@Luke Quinane: Certo, l'ho modificato nell'OP poiché i commenti non supportano la formattazione. – andersop

0

JFYI: A volte vedo firme DER DSA da 45 byte valide (uno di INTEGERS era 19 byte non 20), generato dallo strumento da riga di comando OpenSSL. E sembra che ci possano essere 44 byte (entrambi sono 19 byte), quindi è meglio aspettarsi qualcosa da 6 a 48 byte anziché da 46 a 48. ;-)

1

Utilizzando BouncyCastle (v1.7), posso fare questo (non dimenticate il controllo degli errori, naturalmente):

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

mio signature.bin viene generato utilizzando OpenSSL, ad esempio, openssl dgst -sha1 -sign private.key data.bin > signature.bin

Problemi correlati