Procedimiento para firmar documentos XML con firmas digitales
Puede usar las clases del espacio de nombres System.Security.Cryptography.Xml para firmar un documento XML o parte de un documento XML con una firma digital. Las firmas XML digitales (XMLDSIG) permiten comprobar que los datos no se modificaron después de firmarlos. Para obtener más información sobre el estándar XMLDSIG, vea la recomendación de World Wide Web Consortium (W3C) XML Signature Syntax and Processing.
Nota
El código de este artículo se aplica a Windows.
En el ejemplo de código de este procedimiento se muestra cómo firmar digitalmente un documento XML completo y adjuntar la firma al documento en un elemento <Signature
>. En el ejemplo se crea una clave de firma RSA, se agrega la clave a un contenedor de claves seguro y, a continuación, se usa la clave para firmar digitalmente un documento XML. La clave se puede recuperar para comprobar la firma digital XML, o bien se puede usar para firmar otro documento XML.
Para obtener información sobre cómo comprobar una firma digital XML creada mediante este procedimiento, vea Procedimiento para comprobar las firmas digitales de documentos XML.
Para firmar digitalmente un documento XML
Cree un objeto CspParameters y especifique el nombre del contenedor de claves.
CspParameters cspParams = new() { KeyContainerName = "XML_DSIG_RSA_KEY" };
Dim cspParams As New CspParameters With { .KeyContainerName = "XML_DSIG_RSA_KEY" }
Genere una clave asimétrica mediante la clase RSACryptoServiceProvider. La clave se guarda automáticamente en el contenedor de claves al pasar el objeto CspParameters al constructor de la clase RSACryptoServiceProvider. Esta clave se usará para firmar el documento XML.
RSACryptoServiceProvider rsaKey = new(cspParams);
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
Cree un objeto XmlDocument cargando un archivo XML del disco. El objeto XmlDocument contiene el elemento XML que se va a cifrar.
XmlDocument xmlDoc = new() { // Load an XML file into the XmlDocument object. PreserveWhitespace = true }; xmlDoc.Load("test.xml");
' Load an XML file into the XmlDocument object. Dim xmlDoc As New XmlDocument With { .PreserveWhitespace = True } xmlDoc.Load("test.xml")
Cree un nuevo objeto SignedXml y pásele el objeto XmlDocument.
SignedXml signedXml = new(xmlDoc) {
Dim signedXml As New SignedXml(xmlDoc)
Agregue la clave RSA de firma al objeto SignedXml.
SigningKey = rsaKey };
signedXml.SigningKey = rsaKey
Cree un objeto Reference que describa qué se va a firmar. Para firmar el documento completo, establezca la propiedad Uri en
""
.// Create a reference to be signed. Reference reference = new() { Uri = "" };
' Create a reference to be signed. Dim reference As New Reference() reference.Uri = ""
Agregue un objeto XmlDsigEnvelopedSignatureTransform al objeto Reference. Una transformación permite al comprobador representar los datos XML de un modo idéntico al que usó el firmante. Los datos XML se pueden representar de maneras diferentes, por lo que este paso es vital para la comprobación.
XmlDsigEnvelopedSignatureTransform env = new(); reference.AddTransform(env);
Dim env As New XmlDsigEnvelopedSignatureTransform() reference.AddTransform(env)
Agregue el objeto Reference al objeto SignedXml.
signedXml.AddReference(reference);
signedXml.AddReference(reference)
Calcule la firma llamando al método ComputeSignature.
signedXml.ComputeSignature();
signedXml.ComputeSignature()
Recupere la representación XML de la firma (un elemento <
Signature
>) y guárdela en un nuevo objeto XmlElement.XmlElement xmlDigitalSignature = signedXml.GetXml();
Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()
Anexe el elemento al objeto XmlDocument.
xmlDoc.DocumentElement?.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, True))
Guarde el documento.
xmlDoc.Save("test.xml");
xmlDoc.Save("test.xml")
Ejemplo
En este ejemplo se supone que un archivo llamado test.xml
se encuentra en el mismo directorio que el programa compilado. Puede colocar el siguiente código XML en un archivo llamado test.xml
y usarlo con este ejemplo.
<root>
<creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry>
</creditcard>
</root>
using System;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;
[SupportedOSPlatform("Windows")]
public class SignXML
{
public static void Main(String[] args)
{
try
{
// Create a new CspParameters object to specify
// a key container.
CspParameters cspParams = new()
{
KeyContainerName = "XML_DSIG_RSA_KEY"
};
// Create a new RSA signing key and save it in the container.
RSACryptoServiceProvider rsaKey = new(cspParams);
// Create a new XML document.
XmlDocument xmlDoc = new()
{
// Load an XML file into the XmlDocument object.
PreserveWhitespace = true
};
xmlDoc.Load("test.xml");
// Sign the XML document.
SignXml(xmlDoc, rsaKey);
Console.WriteLine("XML file signed.");
// Save the document.
xmlDoc.Save("test.xml");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
// Sign an XML file.
// This document cannot be verified unless the verifying
// code has the key with which it was signed.
public static void SignXml(XmlDocument xmlDoc, RSA rsaKey)
{
// Check arguments.
if (xmlDoc == null)
throw new ArgumentException(null, nameof(xmlDoc));
if (rsaKey == null)
throw new ArgumentException(null, nameof(rsaKey));
// Create a SignedXml object.
SignedXml signedXml = new(xmlDoc)
{
// Add the key to the SignedXml document.
SigningKey = rsaKey
};
// Create a reference to be signed.
Reference reference = new()
{
Uri = ""
};
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new();
reference.AddTransform(env);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
// Compute the signature.
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
// Append the element to the XML document.
xmlDoc.DocumentElement?.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
}
}
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Imports System.Xml
Module SignXML
Sub Main(ByVal args() As String)
Try
' Create a new CspParameters object to specify
' a key container.
Dim cspParams As New CspParameters With {
.KeyContainerName = "XML_DSIG_RSA_KEY"
}
' Create a new RSA signing key and save it in the container.
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
' Create a new XML document.
' Load an XML file into the XmlDocument object.
Dim xmlDoc As New XmlDocument With {
.PreserveWhitespace = True
}
xmlDoc.Load("test.xml")
' Sign the XML document.
SignXml(xmlDoc, rsaKey)
Console.WriteLine("XML file signed.")
' Save the document.
xmlDoc.Save("test.xml")
Catch e As Exception
Console.WriteLine(e.Message)
End Try
End Sub
' Sign an XML file.
' This document cannot be verified unless the verifying
' code has the key with which it was signed.
Sub SignXml(ByVal xmlDoc As XmlDocument, ByVal rsaKey As RSA)
' Check arguments.
If xmlDoc Is Nothing Then
Throw New ArgumentException(
"The XML doc cannot be nothing.", NameOf(xmlDoc))
End If
If rsaKey Is Nothing Then
Throw New ArgumentException(
"The RSA key cannot be nothing.", NameOf(rsaKey))
End If
' Create a SignedXml object.
Dim signedXml As New SignedXml(xmlDoc)
' Add the key to the SignedXml document.
signedXml.SigningKey = rsaKey
' Create a reference to be signed.
Dim reference As New Reference()
reference.Uri = ""
' Add an enveloped transformation to the reference.
Dim env As New XmlDsigEnvelopedSignatureTransform()
reference.AddTransform(env)
' Add the reference to the SignedXml object.
signedXml.AddReference(reference)
' Compute the signature.
signedXml.ComputeSignature()
' Get the XML representation of the signature and save
' it to an XmlElement object.
Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()
' Append the element to the XML document.
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, True))
End Sub
End Module
Compilar el código
En un proyecto destinado a .NET Framework, incluya una referencia a
System.Security.dll
.En un proyecto destinado a .NET Core o .NET 5, instale el paquete NuGet System.Security.Cryptography.Xml.
Incluya los siguientes espacios de nombres: System.Xml, System.Security.Cryptography y System.Security.Cryptography.Xml.
Seguridad de .NET
Nunca almacene ni transfiera la clave privada de un par de claves asimétricas en texto sin formato. Para más información sobre claves criptográficas simétricas y asimétricas, consulte Generar claves para cifrado y descifrado.
No inserte nunca una clave privada directamente en el código fuente. Las claves insertadas se pueden leer fácilmente desde un ensamblado con Ildasm.exe (desensamblador de IL) o si se abre el ensamblado en un editor de texto, como el Bloc de notas.