Saludos Compañeros.
No conozco de C# y hacienda efectuo este ejemplo para firmar xml de facturacion electronica.
Me pueden ayudar a pasarlo a Delphi ?
Desde ya muchas gracias.
Cita:
(El siguiente ejemplo es una aplicación de consola desarrollada utilizando Visual Studio express 2013 for desktop.
En su método Main, carga el archivo xml a cifrar y el certificado desde el archivo del almacén de certificados,
suponiendo que ambos se encuentran en el directorio de la aplicación.
La ejecución sigue de la siguiente manera:
Se selecciona el elemento del documento que se va a cifrar
Se cifra el elemento y se guarda el xml obtenido
Se vuelve a cargar el documento cifrado desde el archivo recientemente guardado.
Se descifra el documento y se guarda con un nuevo nombre. Este documento debería ser
igual al documento inicial.
Para poder ejecutar el ejemplo se debe crear una nueva aplicación de consola y agregar una
referencia (Add Reference…) y seleccionamos el “assembly” System.Security.
Sustituir el contenido del archivo Program.cs por el siguiente código (recordar que se debe cambiar el
nombre del archivo xml original, el del almacén de certificados y la contraseña, por los correspondientes en su ambiente, el xpath del nodo a
cifrar podría ser diferente según el documento utilizado).
Se debe utilizar como algoritmo asimétrico rsa-pkcs1 (http://www.w3.org/2001/04/xmlenc#rsa-1_5) y como algoritmo simétrico: 3DES-CBC (http://www.w3.org/2001/04/xmlenc#tripledes-cbc).
Finalmente como nombre de clave (KeyName) se debe utilizar CERT_DGI_EFACTURA.)
|
Código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Security.Cryptography;
namespace DgiEncriptarXml {
class Program {
/ <summary>
/ Lee y escribe todos los archivos desde el directorio de la aplicación.
/ </summary>
/ <param name="args"></param>
static void Main(string[] args) {
const string NOMBRE_CLAVE = "CERT_DGI_EFACTURA";
/ Se carga el documento a cifrar
var xmlDoc = CargarXml(@"EnvioCfe_net_sin_encriptar.xml");
/ Se carga el certificado que se va a utilizar.
/ Se utiliza la clave pública para cifrar y la clave privada para descifrar
var cert = CargarCertificado("client.p12", "secreto");
/ Se selecciona el nodo del documento que se cifrará
var xmlNM = new XmlNamespaceManager(xmlDoc.NameTable);
xmlNM.AddNamespace("ns0", "http://cfe.dgi.gub.uy");
var elm =
xmlDoc.SelectSingleNode("/ns0:EnvioCFE/ns0:CFE/ns0:eFact/ns0:Compl_Fiscal/ns0:Compl_Fiscal_Data", xmlNM) as XmlElement;
/Encriptamos
EncriptarXml(elm, cert, NOMBRE_CLAVE);
/Guardo el documento cifrado
xmlDoc.Save("EnvioCfe_net_encriptado.xml");
/Cargo nuevamente el documento cifrado
xmlDoc = CargarXml("EnvioCfe_net_sin_encriptar.xml");
/ Se descifra el documento
DesencriptarDocumento(xmlDoc, cert, NOMBRE_CLAVE);
/Guardo el documento descifrado
xmlDoc.Save("EnvioCfe_net_desencriptado.xml");
}
/ <summary>
/ Carga un certificado desde un almacén tipo #PKCS12
/ El certificado podría cargarse desde otros lugares,
/ por ejemplo, el almacén de windows
/ </summary>
/ <param name="path">Camino al archivo</param>
/ <param name="contrasenia">Contraseña del almacén</param>
/ <returns></returns>
private static X509Certificate2 CargarCertificado(string path, string contrasenia) {
return new X509Certificate2(path, contrasenia, X509KeyStorageFlags.Exportable);
}
/ <summary>
/ Carga el documento xml que contiene el nodo a cifrar
/ </summary>
/ <param name="path">Camino al archivo</param>
/ <returns></returns>
private static XmlDocument CargarXml(string path) {
var xmldoc = new XmlDocument();
xmldoc.PreserveWhitespace = false;
xmldoc.Load(path);
return xmldoc;
}
/ <summary>
/ Cifra el nodo utilizando la clave pública del certificado suministrado.
/ </summary>
/ <param name="nodoParaEncriptar">Elemento para cifrar</param>
/ <param name="cert">Certificado </param>
/ <param name="nombreClave">Nombre para la clave</param>
private static void EncriptarXml(XmlElement nodoParaEncriptar, X509Certificate2 cert, string
nombreClave) {
/ Se crea una nueva clave TripleDES.
TripleDESCryptoServiceProvider tDESkey = new TripleDESCryptoServiceProvider();
/ Se crea una nueva instancia de EncryptedXml y la uso para encriptar el elemento con la clave simétrica.
EncryptedXml eXml = new EncryptedXml();
byte[] encryptedElement = eXml.EncryptData(nodoParaEncriptar, tDESkey, false);
/ Se construye el objeto EncryptedData y se carga la información de cifrado deseada
EncryptedData edElement = new EncryptedData();
edElement.Type = EncryptedXml.XmlEncElementUrl;
edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncTripleDESUrl);
var alg = (RSACryptoServiceProvider)cert.PublicKey.Key;
/ Se cifra la clave simétrica.
EncryptedKey ek = new EncryptedKey();
byte[] encryptedKey = EncryptedXml.EncryptKey(tDESkey.Key, alg, false);
ek.CipherData = new CipherData(encryptedKey);
ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
/Agrega la clave cifrada al objeto EncriptedData
edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
/ Asigna el Elemento KeyInfoName para especificar el nombre de la clave RSA
KeyInfoName kin = new KeyInfoName();
kin.Value = nombreClave;
/ Agrega el KeyInfoName al objeto encriptado
ek.KeyInfo.AddClause(kin);
edElement.CipherData.CipherValue = encryptedElement;
EncryptedXml.ReplaceElement(nodoParaEncriptar, edElement, false);
}
/ <summary>
/ Descifra el documento utilizando la clave privada del certificado suministrado
/ </summary>
/ <param name="xmlDoc">Documento a descifrar</param>
/ <param name="cert">Certificado a utilizar</param>
/ <param name="nombreClave">Nombre de la clave simétrica</param>
private static void DesencriptarDocumento(XmlDocument xmlDoc, X509Certificate2 cert, string
nombreClave) {
EncryptedXml exml = new EncryptedXml(xmlDoc);
/ Agrega el diccionario clave-nombre
/ Este método sólo puede descifrar documentos
/ que contengan la clave especificada
var privateKey =(RSACryptoServiceProvider)cert.PrivateKey;
exml.AddKeyNameMapping(nombreClave, privateKey);
/ Descifrar el elemento.
exml.DecryptDocument();
}
}
}