Página 4 de 6

Re: Como validar "a mano" un sello digital

Publicado: Vie Feb 25, 2011 11:18 am
por danfred
Buenas

Estoy haciendo un validador que va a leer el CFD en formato XML, pero ando batallando en el utimo paso, el detalle es que no quiero utilizar openssl.exe lo quiero hacer completamente en c# (Visual Studio 2010), aqui les anexo el codigo que me 'genera' el sello digital completo en c# (no ocupa openssl.exe) y ya esta validado por el validador del SAT, a ver quien me echa la mano con el validador en c# de un XML que si contenga el certificado. Gracias

public byte[] hash_sha1_byte(byte[] Value)
{
System.Security.Cryptography.SHA1CryptoServiceProvider x =
new System.Security.Cryptography.SHA1CryptoServiceProvider();
byte[] data = x.ComputeHash(Value);
return data;
}

public string byte_to_string( byte[] data)
{
string ret = "";
for (int i = 0; i < data.Length; i++)
ret += data.ToString("x2").ToUpper();
return ret;
}

public string hash_sha1(string Value)
{
byte[] data = hash_sha1_byte(System.Text.Encoding.UTF8.GetBytes(Value));
return byte_to_string(data);
}


public string SelloDigital2(string _rutap12, string _passp12, string cadena)
{
try
{
// uso un archivo xxxx.P12 que incluye todo CERTIFICADO y LLAVES PUBLICAS Y PRIVADAS y _passp12 es el pasword de la PRIVATE KEY
X509Certificate2 certificado = new X509Certificate2( _rutap12, _passp12);
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)certificado.PrivateKey;
if (rsa == null)
{
throw new Exception("El certificado " + _rutap12 + " no es válido o su contraseña");
}

rsa.PersistKeyInCsp = false;

byte[] data = System.Text.Encoding.UTF8.GetBytes(cadena);
string hash_name;
hash_name = CryptoConfig.MapNameToOID("SHA1");
// Hash the data
data = hash_sha1_byte(data);
// Sign the hash
byte[] encriptado = rsa.SignHash(data, hash_name);
rsa.Clear();
return Convert.ToBase64String(encriptado);
}
catch (Exception ex)
{
return "Error al generar el sello digital " + ex.ToString();
}
}

Re: Como validar "a mano" un sello digital

Publicado: Vie Feb 25, 2011 11:24 am
por danfred
De acuerdo al post anterior esta funcion deberia de funcionar correctamente, pero no jala, ¿alguna idea del porque?, todo indica que la llave publica que se lee, es incorrecta, del archivo xxxx..P12 (ejemplo anterior) obtengo que la llave publica mide 162 bytes, pero los ejemplos que he visto esta llave mide 128 bytes, aunque la clase X509Certificate2 siempre marca 1024 en su elemento keysize.

public string ValidaSelloDigital2(string selloDigital, string cert, string cadena)
{
try
{
byte[] sello_byte = Convert.FromBase64String( selloDigital);
byte[] cert_byte = Convert.FromBase64String( cert);

X509Certificate2 certificado = new X509Certificate2( cert_byte);
//initialze the byte arrays to the public key information.
byte[] pk = certificado.GetPublicKey();

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.PersistKeyInCsp = false;
//Get an instance of RSAParameters from ExportParameters function.
RSAParameters RSAKeyInfo = rsa.ExportParameters(false);

//Set RSAKeyInfo to the public key values.
RSAKeyInfo.Modulus = pk;
//Import key parameters into RSA.
rsa.ImportParameters(RSAKeyInfo);

byte[] cadena_byte = System.Text.Encoding.UTF8.GetBytes(cadena);

System.Security.Cryptography.SHA1CryptoServiceProvider x =
new System.Security.Cryptography.SHA1CryptoServiceProvider();
byte[] data = x.ComputeHash(cadena_byte);

System.Security.Cryptography.MD5CryptoServiceProvider x2 =
new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] data2 = x2.ComputeHash(cadena_byte);

bool result = rsa.VerifyHash(data2, CryptoConfig.MapNameToOID("MD5"), sello_byte);
bool result2 = rsa.VerifyHash(data, CryptoConfig.MapNameToOID("SHA1"), sello_byte);
string smd5 = byte_to_string(data2);
string ssha1 = byte_to_string(data);

//MessageBox.Show("md5=" + smd5+ "\nsha1=" + ssha1+ "\nSello Digital="+ selloDigital);

string ret = "Sello inválido.";

if (result)
{
ret = "Sello válido con digestion MD5 " + hash_md5(cadena);
}
else
{
if (result2)
{
ret = "Sello válido con digestion SHA1 " + hash_sha1(cadena);
}
}
return ret;
}
catch (Exception ex)
{
return "Error al desencriptar el sello digital " + ex.ToString();
}
}

Re: Como validar "a mano" un sello digital

Publicado: Lun Feb 28, 2011 10:03 am
por danfred
Listo, validacion del sello digital en c#, aqui el codigo funcional, ya no ocupa openssl todo en punto NET, este codigo ya esta probado, se aceptan comentarios:

public string ValidaSelloDigital(string selloDigital, string cert, string cadena)
{
try
{
byte[] sello_byte = Convert.FromBase64String( selloDigital);
byte[] cert_byte = Convert.FromBase64String( cert);
X509Certificate2 certificado = new X509Certificate2( cert_byte);
string spk = certificado.PublicKey.Key.ToXmlString(false);
AsymmetricAlgorithm pk = AsymmetricAlgorithm.Create();
pk.FromXmlString(spk);
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider) pk;
rsa.PersistKeyInCsp = false;
byte[] cadena_byte = System.Text.Encoding.UTF8.GetBytes(cadena);
System.Security.Cryptography.SHA1CryptoServiceProvider x =
new System.Security.Cryptography.SHA1CryptoServiceProvider();
byte[] data = x.ComputeHash(cadena_byte);
System.Security.Cryptography.MD5CryptoServiceProvider x2 =
new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] data2 = x2.ComputeHash(cadena_byte);
bool result = rsa.VerifyHash(data2, CryptoConfig.MapNameToOID("MD5"), sello_byte);
bool result2 = rsa.VerifyHash(data, CryptoConfig.MapNameToOID("SHA1"), sello_byte);
string ret = "Sello inválido.";
if (result)
{
ret = "Sello válido con digestion MD5 " + hash_md5(cadena);
}
else
{
if (result2)
{
ret = "Sello válido con digestion SHA1 " + hash_sha1(cadena);
}
}
return ret;
}
catch (Exception ex)
{
return "Error al desencriptar el sello digital " + ex.ToString();
}
}

Re: Como validar "a mano" un sello digital

Publicado: Lun Mar 14, 2011 6:23 pm
por roda1984
Hola danfred!

Estoy desarrollando la nueva versión 2011 de la factura electrónica, con el PAC timbrefiscal, al enviar el archivo XML timbrado, el servidor me "responde sello no valido", por lo que quiero validar mi sello antes de enviarlo para ver si corresponde a mi cadena original, con tu codigo que posteaste se puede hacer esto cierto?

Solo tengo dudas, cuales son las entradas a la función:
string selloDigital, string cert, string cadena

Gracias por la ayuda y gran codigo! :)

Re: Como validar "a mano" un sello digital

Publicado: Lun Abr 04, 2011 9:13 pm
por elliot
Como genero el archivo xxxx.P12?, para que funcione el codigo de sellado

Saludos

Re: Como validar "a mano" un sello digital

Publicado: Mar Abr 05, 2011 9:56 am
por Dado
elliot escribió:Como genero el archivo xxxx.P12?, para que funcione el codigo de sellado

Saludos
P12 es lo mismo que pkcs12 y es lo mismo que pfx, busca pfx en el foro hay algunos mensajes al respecto.

Que codigo de sellado estas usando ya que aqui en este foro casi siempre usamos el PEM

Re: Como validar "a mano" un sello digital

Publicado: Mar Abr 05, 2011 7:13 pm
por elliot
Estoy usando el archivo de SAT en PKCS8, tendre que cambiarlo a pem y de ahi a pkcs12?

Saludos

Re: Como validar "a mano" un sello digital

Publicado: Mar Abr 05, 2011 7:42 pm
por elliot
Hice la conversion y todo funciono muy bien, gracias.

Re: Como validar "a mano" un sello digital

Publicado: Mar May 17, 2011 8:13 pm
por jgraterol
Hola!

Retomando este tema, estoy intentando aplicarlo con sha1.

El problema que tengo es con la digestión de la cadena original. Por alguna razón que no entiendo el resultado de hacerlo con

Código: Seleccionar todo

openssl dgst -sha1 "cadoriginal.txt" > sha1dgst.txt
es diferente a lo que reporta el SAT en su validador (https://www.consulta.sat.gob.mx/SICOFI_ ... idador.asp). La (inmediata) conclusión de que estoy construyendo mal la cadena original creo que no aplica, porque de hecho copio la cadena del resultado mismo de la página y lo pego en el archivo cadoriginal.txt, asegurándome de salvarlo como utf8 y sin caracteres extra. Anexo los archivos necesarios (MHI070814TL6F335.xml, cadoriginal.txt y sha1dgst.txt) a ver si puedes darme una mano con esto.

De antemano muchísimas gracias!

Re: Como validar "a mano" un sello digital

Publicado: Mar May 17, 2011 8:24 pm
por Dado
jgraterol escribió:Hola!

Retomando este tema, estoy intentando aplicarlo con sha1.

El problema que tengo es con la digestión de la cadena original. Por alguna razón que no entiendo el resultado de hacerlo con

Código: Seleccionar todo

openssl dgst -sha1 "cadoriginal.txt" > sha1dgst.txt
es diferente a lo que reporta el SAT en su validador (https://www.consulta.sat.gob.mx/SICOFI_ ... idador.asp). La (inmediata) conclusión de que estoy construyendo mal la cadena original creo que no aplica, porque de hecho copio la cadena del resultado mismo de la página y lo pego en el archivo cadoriginal.txt, asegurándome de salvarlo como utf8 y sin caracteres extra. Anexo los archivos necesarios (MHI070814TL6F335.xml, cadoriginal.txt y sha1dgst.txt) a ver si puedes darme una mano con esto.

De antemano muchísimas gracias!
Haz oido del "BOM" (byte order mark)....son 3 bytes que se le estan pegando a tu archivo, al inicio, la unica forma de verlos es con un editor hexadecimal

Busca BOM aqui en el foro, tambien busca un editor hexadecimal pa' quitarle esa mugre

Te anexo el archivo YA SIN EL MOLESTO BOM, haz tus pruebas, checa como el archivo que anexo es 3 BYTES MAS CHICO que el que subiste tu.