Поделиться через


Практическое руководство. Подписывать XML-документы с помощью цифровых подписей

Классы в System.Security.Cryptography.Xml пространстве имен можно использовать для подписи XML-документа или части XML-документа с цифровой подписью. Цифровые подписи XML (XMLDSIG) позволяют убедиться, что данные не были изменены после подписания. Дополнительные сведения о стандарте XMLDSIG см. в рекомендации консорциума W3C (W3C) по синтаксису и обработке сигнатур XML.

Замечание

Код, приведенный в этой статье, применяется к Windows.

В примере кода в этой процедуре показано, как цифрово подписать весь XML-документ и присоединить подпись к документу в элементе <Signature> . В примере создается ключ подписывания RSA, добавляется ключ в контейнер безопасного ключа, а затем используется ключ для цифровой подписи XML-документа. Затем ключ можно получить, чтобы проверить цифровую подпись XML или использовать для подписи другого XML-документа.

Сведения о том, как проверить цифровую подпись XML, созданную с помощью этой процедуры, см. в разделе "Практическое руководство. Проверка цифровых подписей XML-документов".

Цифровая подпись XML-документа

  1. CspParameters Создайте объект и укажите имя контейнера ключей.

    CspParameters cspParams = new()
    {
        KeyContainerName = "XML_DSIG_RSA_KEY"
    };
    
    Dim cspParams As New CspParameters With {
        .KeyContainerName = "XML_DSIG_RSA_KEY"
    }
    
  2. Создайте асимметричный ключ с помощью RSACryptoServiceProvider класса. Ключ автоматически сохраняется в контейнере ключей при передаче CspParameters объекта конструктору RSACryptoServiceProvider класса. Этот ключ будет использоваться для подписи XML-документа.

    RSACryptoServiceProvider rsaKey = new(cspParams);
    
    Dim rsaKey As New RSACryptoServiceProvider(cspParams)
    
  3. XmlDocument Создайте объект, загрузив XML-файл с диска. Объект XmlDocument содержит XML-элемент для шифрования.

    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")
    
  4. Создайте новый SignedXml объект и передайте XmlDocument объект в него.

    SignedXml signedXml = new(xmlDoc)
    {
    
    Dim signedXml As New SignedXml(xmlDoc)
    
  5. Добавьте ключ RSA подписывания в SignedXml объект.

        SigningKey = rsaKey
    };
    
    signedXml.SigningKey = rsaKey
    
  6. Reference Создайте объект, описывающий, что нужно подписать. Чтобы подписать весь документ, установите для свойства Uri значение "".

    // Create a reference to be signed.
    Reference reference = new()
    {
        Uri = ""
    };
    
    ' Create a reference to be signed.
    Dim reference As New Reference()
    reference.Uri = ""
    
  7. Добавьте объект XmlDsigEnvelopedSignatureTransform к объекту Reference. Преобразование позволяет проверяющим представлять XML-данные таким же образом, как используется подписыватель. XML-данные могут быть представлены разными способами, поэтому этот шаг жизненно важен для проверки.

    XmlDsigEnvelopedSignatureTransform env = new();
    reference.AddTransform(env);
    
    Dim env As New XmlDsigEnvelopedSignatureTransform()
    reference.AddTransform(env)
    
  8. Добавьте объект Reference в объект SignedXml.

    signedXml.AddReference(reference);
    
    signedXml.AddReference(reference)
    
  9. Вычислить сигнатуру ComputeSignature путем вызова метода.

    signedXml.ComputeSignature();
    
    signedXml.ComputeSignature()
    
  10. Извлеките XML-представление сигнатуры ( <Signature> элемента) и сохраните его в новом XmlElement объекте.

    XmlElement xmlDigitalSignature = signedXml.GetXml();
    
    Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()
    
  11. Добавьте элемент в XmlDocument объект.

    xmlDoc.DocumentElement?.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
    
    xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, True))
    
  12. Сохраните документ.

    xmlDoc.Save("test.xml");
    
    xmlDoc.Save("test.xml")
    

Пример

В этом примере предполагается, что файл с именем test.xml существует в том же каталоге, что и скомпилированная программа. Можно поместить следующий XML в файл под названием test.xml и использовать его с этим примером.

<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

Компиляция кода

Безопасность .NET

Никогда не храните или не передавайте приватный ключ пары асимметричных ключей в виде незашифрованного текста. Дополнительные сведения о симметричных и асимметричных криптографических ключах см. в разделе "Создание ключей для шифрования и расшифровки".

Никогда не внедряйте закрытый ключ непосредственно в исходный код. Внедренные ключи можно легко считывать из сборки с помощью Ildasm.exe (IL Disassembler) или открытия сборки в текстовом редакторе, например Блокнот.

См. также