2009-10-27 7 views
5

¿Cómo puedo verificar una firma de DSA en C#?Verificar una firma de DSA en C# que está usando formato ASR.1 codificado en BER/DER

Dado:

  • el texto del mensaje,
  • un compendio firmado (típicamente formato DER ASN.1),
  • la clave pública (en un certificado X.509 firmado, PEM o DER formato)

he intentado una serie de enfoques, pero no han tenido ningún éxito:

  • OpenSSL.NET: varios errores extraños con la biblioteca; Tengo un open thread running with the author over on SourceForge pero aún no he podido resolverlo.

  • Microsoft .NET API: no se puede descomprimir la firma DER para fines de comparación. Una firma DSA tiene 40 bytes (dos enteros de 20 bytes), pero se presenta como una secuencia codificada DER de dos enteros, por lo que la longitud total puede variar de 46 a 48 bytes (consulte this post para obtener una descripción general rápida). Mientras .NET incluye código para analizar ASN.1/DER (porque puede leer certificados en formato DER), está enterrado profundamente, y no hay forma de acceder a él para que pueda recuperar correctamente los 40 bytes de la señal codificada ASN.1/DER. Este problema me llevó a la siguiente opción ...

  • BouncyCastle: a través del uso de las funciones Org.BouncyCastle.Asn1, puedo analizar la firma ASN.1 y tire de ella en que es valores enteros S componente R y. Pero cuando paso estos a las rutinas de verificación de la firma, está fallando sin explicación dada. No estoy seguro de si estoy haciendo algo mal, debido a que el C# API es completamente indocumentado, y la versión de Java está poco documentado (pero no hay ningún ejemplo o COMO información que puedo encontrar.)

Me he estado lanzando sobre este problema desde hace una semana. Sé que alguien debe haberlo hecho antes, pero no he encontrado ningún ejemplo completo/de trabajo.

Tengo aquí tres proyectos de C#, cada uno de los cuales está completo al 95% pero con un error crítico que hace que falle. Cualquier código de ejemplo de trabajo sería tremendamente apreciado.

editar: aquí hay un ejemplo de una firma que estoy tratando de verificar, convertida a Base64 y hexadecimal ASCII para que sea postable. Esta en particular es de 47 bytes, aunque con un analizador adecuado todavía tiene que aceptarlo, leer sobre la especificación DER para obtener más información (BER/DER agrega un líder de 00 para confirmar la señal si el MSB es 1)

Base64: MC0CFQCUgq2DEHWzp3O4nOdo38mDu8mStwIUadZmbin7BvXxpeoJh7dhquD2CTM= 

ASCII Hex: 302d0215009482ad831075b3a773b89ce768dfc983bbc992b7021469d6666e29fb06f5f1a5ea0987b761aae0f60933 

Estructura es por la especificación DER; se analiza de la siguiente manera:

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 

escribir mi propio analizador DER es realmente no es una opción, demasiado margen para el error y no tiene que haber una manera de hacer esto correctamente.

+0

Me preguntaba si podría hacerme un favor y cambiar el título de "Verificar firma DSA en C#" a "Verificar firma DSA en C# con formato ASN.1" o algo por el estilo. Podría ayudar a buscar personas un poco. – Greg

+0

Solo como un comentario; Voy por el otro camino (verifique una firma en Java que fue creada en .NET); Tuve que escribir un convertidor del formato .NET DSA (que es simplemente r || s en 40 bytes) al formato DER. De acuerdo con lo que encontré aquí (http://www.mombu.com/microsoft/security-crypto/t-dsa-signature-format-674106.html), el formato DER espera que r y s sean big-endian pero que no lo hicieron No funciona en absoluto así que lo dejé como pequeño endian y funciona ... No he encontrado nada muy claro en esto; debería ser grande o poco indio ... si alguien sabe, por favor, toque el timbre! – SonarJetLens

Respuesta

1

Se puede encontrar un código que verifica la firma de un DSA en el proyecto NSsh. No se ajusta a sus necesidades exactas ya que la clave pública no se extrae de una X.Certificado 509 pero puede darle un punto de partida.

+0

Por lo que puedo ver, está generando la firma internamente: SignatureOfH = hostKey.Sign (H); Necesito leer una firma generada externamente, lo que lleva al problema ASN.1 (descrito un poco más en la publicación actualizada). – andersop

1

Otro buen ejemplo es el código DotNetAutoUpdate. Utiliza RSA pero debería ser bastante simple cambiar a DSA. En particular, echar un vistazo a este archivo:

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


Editar: básicamente quieres algo similar a esto:

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

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

Más detalles sobre MSDN.


Editar: Otra opción es las bibliotecas Mono.Security:

  • Hay una clase de lectura ASN1
  • También hay un assembly para leer cerficiates X.509.

No estoy seguro de si eso ayuda ...

+0

El problema con la implementación .NET es que no puede analizar el formato ASN.1 del firmas: no puedo generar el objeto "firma" en el ejemplo anterior. – andersop

+0

@andersop ¿puedes publicar un ejemplo de la firma ASN.1? –

+0

@Luke Quinane: Claro, lo edité en el PO ya que los comentarios no admiten el formateo. – andersop

0

JFYI: A veces veo firmas válidas de DER DSA de 45 bytes (una de INTEGER era de 19 bytes, no 20), generada por la herramienta de línea de comandos de OpenSSL. Y parece que puede haber 44 bytes (ambos son 19 bytes), por lo que es mejor esperar de 6 a 48 bytes en lugar de 46 a 48. ;-)

1

Utilizando BouncyCastle (v1.7), puedo hacer esto (no se olvide de comprobación de errores, por supuesto): se genera

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

Mi signature.bin usando OpenSSL, por ejemplo, openssl dgst -sha1 -sign private.key data.bin > signature.bin

Cuestiones relacionadas