Hola johan.
Estando lejos de ser un experto en estas cosas, para la parte de la firma digital te sugiero echar un vistazo a este par de enlaces y valorar las recomendaciones que ahí se dan:
http://www.clubdelphi.com/foros/showthread.php?t=61897
http://www.clubdelphi.com/foros/show...376#post416376
Por si decides usar "
COM Interop", dejo aquí el código que escribí cuando necesité hacer algo muy parecido a lo que buscas (también en Delphi 7):
Código:
/* FirmaXML 1.0
Ensamblaje .NET para permitir el firmado XMLDSig de un documento fiscal mexicano de formato XML.
DLL compilada con la versión de prueba de Visual Studio. */
using System;
using System.IO;
using System.Xml;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
namespace FirmaXML
{
/* Permitimos que esta clase pueda ser exportada como interfaz COM, para ser utilizada en
entornos no .NET también. */
[ComVisible (true)]
[Guid ("4EA3AB36-9DD1-42C5-B57A-D0F89DC4711B")]
public class FirmaXML
{
public string Firmar (string XML, string RFC)
{
/* Método que recibe el texto de un documento XML y regresa ese mismo texto pero conteniendo
una firma digital XMLDSig envolvente.
Parámetro XML: Texto del documento a firmar.
Parámetro RFC: RFC del contribuyente cuyo certificado se usará para la firma. */
// Obtenemos el certificado correspondiente al RFC dado
X509Certificate2 Certificado = BuscarCertificado (RFC);
// Obtenemos el objeto de llave privada del certificado
RSACryptoServiceProvider Llave = Certificado.PrivateKey as RSACryptoServiceProvider;
// Creamos el objeto firmante (Firma) asignándole el texto XML y la llave del certificado
XmlDocument Documento = new XmlDocument ();
Documento.LoadXml (XML);
SignedXml Firma = new SignedXml (Documento);
Firma.SigningKey = Llave;
/* Creamos el nodo <Reference> con un subnodo <Transforms> conteniendo el elemento
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />, y lo
agregamos al objeto firmante */
Reference Referencia = new Reference ();
Referencia.Uri = ""; // Tomar ("digerir") todo el documento al crear la firma
Referencia.AddTransform (new XmlDsigEnvelopedSignatureTransform ());
Firma.AddReference (Referencia);
/* Creamos el nodo <KeyInfo> con el subnodo <X509Data>, poniendo dentro de éste el
certificado, su número de serie y la entidad emisora del mismo (primero estos dos últimos
como subnodo <X509IssuerSerial>), y agregando todo al objeto firmante. */
KeyInfoX509Data NodoX509Data = new KeyInfoX509Data ();
NodoX509Data.AddIssuerSerial (Certificado.Issuer, Certificado.GetSerialNumberString ());
NodoX509Data.AddCertificate (Certificado);
Firma.KeyInfo = new KeyInfo ();
Firma.KeyInfo.AddClause (NodoX509Data);
// Generamos la firma digital y la agregamos al objeto Documento
Firma.ComputeSignature ();
Documento.DocumentElement.AppendChild (Documento.ImportNode (Firma.GetXml (), true));
// Devolvemos el XML firmado
return Documento.OuterXml;
}
protected static X509Certificate2 BuscarCertificado (string RFC)
{
// Método para obtener el certificado que pertenece a un RFC
// Cargamos la lista de certificados personales instalados en Windows
X509Store Certificados = new X509Store (StoreName.My, StoreLocation.CurrentUser);
Certificados.Open (OpenFlags.ReadOnly);
// Buscamos el certificado del contribuyente
foreach (X509Certificate2 Resultado in Certificados.Certificates)
/* El sujeto (propiedad Subject) del certificado puede contener algo como:
"OU=Unidad 1, SERIALNUMBER=" / AAAA010101HDFRXX01", " (continúa)
"OID.2.5.4.45=AAA010101AAA / AAAA010101AAA, O=Matriz SA, " (continúa)
"OID.2.5.4.41=Matriz SA, CN=Matriz SA"
"AAA010101AAA / AAAA010101AAA" son el RFC del contribuyente (persona moral o física) y,
opcionalmente, el RFC de la persona física que representa a la persona moral
(posiblemente). El primero es el que nos interesa y debe ser igual al parámetro RFC para
dar por encontrado el certificado.
Revisaremos cada par "llave=valor" del sujeto. NOTA: Puede que convenga robustecer el
código de este ciclo anidado. */
foreach (string Dato in Resultado.Subject.Split (','))
{
string[] LlaveValor = Dato.Trim().Split ('=');
if ((LlaveValor.Length == 2) && LlaveValor [0].EndsWith ("2.5.4.45") &&
(LlaveValor [1].Split ('/') [0].Trim () == RFC))
return Resultado; // Encontrado
}
throw new Exception ("No hay un certificado instalado para el RFC que se indicó.");
}
}
}
Lo probé de la siguiente manera en Delphi:
Código Delphi
[-]unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, xmldom, XMLIntf, msxmldom, XMLDoc;
type
TForm1 = class(TForm)
Button1: TButton;
Doc: TXMLDocument;
mm1: TMemo;
mm2: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
Uses
FirmaXML_TLB;
procedure TForm1.FormCreate(Sender: TObject);
begin
Doc.Active := True;
mm1.Text := Doc.XML.Text;
end;
procedure TForm1.Button1Click(Sender: TObject);
Var
Firma :Variant;
Resultado :String;
begin
Firma := CoFirmaXML_.Create;
Resultado := Firma.Firmar (Doc.XML.Text, 'AAA010101AAA');
Doc.XML.Text := FormatXMLData (AnsiToUTF8 (Resultado));
Doc.Active := True;
Doc.SaveToFile ('XMLCancelacionResultado.xml');
mm2.Text := FormatXMLData (Resultado);
end;
end.
Lo mejor de todo es que funcionó, quedándome con una grata impresión de las bibliotecas nativas de .NET (lástima que su lenguaje puntero sea un derivado de C

).
Ojalá pueda servirte como base a ti o alguien más.
Saludos.
Al González.