Pues bien, hace tiempo estuve buscando la solución para la facturación electrónica con C#. Sí, ya todos sabemos que en la página del SAT no aparece la información como la esperamos, que no tienen personal calificado para responder nuestras dudas ni por chat, ni por teléfono y sin embargo la respuesta si está en su documentación. Es preciso leer detenidamente y buscar a detalle los puntos importantes para la generación del sello digital. No sólo en el Anexo 20 sino en otras ligas que proporcionan, así como bañarse en el tema de los algoritmos MD5, PKCS1, PKCS8, RSA, etc.
El tema de facturación electrónica es muy extenso y la cuestión principal es lo que no especifican a detalle en la página del SAT, "la generación del sello digital".
En primer lugar tenemos que se necesita decodificar la clave privada, para esto nuestros amigos de [URL="http://www.jensign.com/"]http://www.jensign.com/[/URL] nos proporcionan el código para decodificar la mentada clave privada en la siguiente liga: [URL="http://www.jensign.com/opensslkey/index.html"]http://www.jensign.com/opensslkey/index.html[/URL]
En la página de Microsoft nos explican un poco acerca de la seguridad que se recomienda tener con nuestras claves privadas utilizando Contenedores de Clave Privadas en la siguiente liga: [URL="http://msdn.microsoft.com/es-es/library/tswxhw92(VS.80).aspx"]http://msdn.microsoft.com/es-es/library/tswxhw92(VS.80).aspx[/URL]
Por mi parte, ya teniendo la clave privada a nuestro servicio lo que queda es tomar nuestro comprobante xml, generar la cadena original (que es lo más fácil utilizando la clase System.Xml.Xsl.XslCompiledTransform y nuestro archivo [URL="ftp://ftp2.sat.gob.mx/asistencia_servicio_ftp/publicaciones/solcedi/cadenaoriginal_3_0.xslt"]cadenaoriginal_3_0.xslt[/URL]).
Para efecto de pruebas generé el siguiente método que contiene los pasos importantes para la generación del sello digital. De acuerdo a la liga a la página de Microsoft que les mencioné, no es seguro mantener la clave privada en la PC como lo exige dicho método, pero repito, es sólo para pruebas y ya ustedes sabrán cómo lo aplican en sus sistemas.
/// <summary>
/// Sella digitalmente el comprobante fiscal digital.
/// </summary>
/// <param name="cadenaOriginalEnBytes">Arreglo de bytes que contiene a la Cadena Original del CFD.</param>
/// <param name="xmlClavePrivada">Clave Privada en formato XML (Sólo para efectos de prueba ya que es inseguro).</param>
/// <returns>Devuelve el sello digital en base64</returns>
private string SellarCFD(byte[] cadenaOriginalEnBytes, string xmlClavePrivada)
{
//Se especifica la ubicación de almacenamiento de nuestra clave privada.
//(Hay mejores formas de controlar esto).
CspParameters Parametros = new CspParameters();
Parametros.Flags = CspProviderFlags.UseMachineKeyStore;
//Se crea el objeto RSA y se carga la clave privada que se va a utilizar.
RSACryptoServiceProvider rsaClavePrivada;
rsaClavePrivada = new RSACryptoServiceProvider(1024, Parametros);
rsaClavePrivada.FromXmlString(xmlClavePrivada);
//Se crea el formateador de firma PKCS1 y se establece el algoritmo hash que se utiliza para crear la firma.
RSAPKCS1SignatureFormatter rsaPKCS1 = new RSAPKCS1SignatureFormatter(rsaClavePrivada);
rsaPKCS1.SetHashAlgorithm("MD5");
//Se genera el hash de la cadena original mediente el algoritmo MD5.
MD5CryptoServiceProvider md5CSP = new MD5CryptoServiceProvider();
byte[] cadenaHasMD5 = md5CSP.ComputeHash(cadenaOriginalEnBytes);
//Se sella el hash de la cadena original obteniendo el sello digital en un arreglo de bytes.
byte[] selloDigitalBytes = rsaPKCS1.CreateSignature(cadenaHasMD5);
//Se convierten los bytes en base64.
string selloDigitalB64 = Convert.ToBase64String(selloDigitalBytes);
//Sale nuestro sello digital como pan caliente!
return selloDigitalB64;
}
Pues ya teniendo esto, no queda más que decir. Los comentarios en el código lo explican todo.
Espero cualquier duda o sugerencia al respecto.
Suerte con sus aplicaciones Web y de escritorio.