SignedXml.CheckSignature возвращает true, только если я проверяю с помощью закрытого ключа

Я видел несколько похожих вопросов, но ни один из них не касается именно того, что я спрашиваю.

Я пытаюсь подписать XML, а затем проверить его с помощью открытого ключа с помощью С#.

Я подписываю XML ключом, а затем экспортирую ключ в XML. Затем перенесите ключ и подписанный XML на другой компьютер, импортируйте ключ с помощью rsa.FromXmlString(doc.InnerXml) и проверьте подпись XML.

Это работает, если я экспортирую как открытый, так и закрытый ключи в XML, используя rsa.ToXmlString(True). Однако я хочу экспортировать только свой открытый ключ, используя rsa.ToXmlString(False). Если я экспортирую только открытый ключ и импортирую его на второй компьютер и пытаюсь проверить подпись XML, он говорит, что подпись недействительна.

Во-первых, должен ли я иметь возможность проверять подписанный XML только с помощью открытого ключа?

Во-вторых, если это так, то почему моя функция проверки XML работает только с парой ключей pub/priv, а не только с открытым ключом?

Есть ли у вас какие-либо знания о том, как отладить эту проблему? Я не знаю, что еще делать, потому что signedXml.CheckSignature(Key); не предоставляет никакой информации о том, почему это не удалось.

Мой ключ импорта, ключ экспорта, подпись XML и функции проверки XML приведены ниже. Дайте мне знать, если вам нужна дополнительная информация.

    public static void ImportKeyFromFile(string ContainerName, string inputFile)
    {
        try
        {
            // Create new XmlDocument.
            XmlDocument doc = new XmlDocument();

            // Load XML Document.
            doc.Load(inputFile);

            // Create the CspParameters object and set the key container 
            // name used to store the RSA key pair.
            CspParameters cp = new CspParameters();
            cp.KeyContainerName = ContainerName;

            // Create a new instance of RSACryptoServiceProvider that accesses
            // the key container MyKeyContainerName.
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);

            // Get RSA Parameters from xml document.
            rsa.FromXmlString(doc.InnerXml);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
    public static void ExportKeyToFile(string ContainerName, string outputPath, bool private_key)
    {
        try
        {
            // Create the CspParameters object and set the key container 
            // name used to store the RSA key pair.
            CspParameters cp = new CspParameters();
            cp.KeyContainerName = ContainerName;

            // Create a new instance of RSACryptoServiceProvider that accesses
            // the key container MyKeyContainerName.
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);

            // Create new XmlDocument.
            XmlDocument doc = new XmlDocument();

            // Store rsa key.
            doc.InnerXml = rsa.ToXmlString(private_key);

            // Save Document.
            doc.Save(outputPath);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
    public static Boolean VerifyXml(XmlDocument Doc, RSA Key)
    {
        // Check arguments. 
        if (Doc == null)
            throw new ArgumentException("Doc");
        if (Key == null)
            throw new ArgumentException("Key");

        // Create a new SignedXml object and pass it 
        // the XML document class.
        SignedXml signedXml = new SignedXml(Doc);

        // Find the "Signature" node and create a new 
        // XmlNodeList object.
        XmlNodeList nodeList = Doc.GetElementsByTagName("Signature");

        // Throw an exception if no signature was found. 
        if (nodeList.Count <= 0)
        {
            throw new CryptographicException("Verification failed: No Signature was found in the document.");
        }

        // Load the first <signature> node.  
        signedXml.LoadXml((XmlElement)nodeList[0]);

        // Check the signature and return the result. 
        return signedXml.CheckSignature(Key);
    }
    public static void SignXml(XmlDocument xmlDoc, RSA Key)
    {
        // Check arguments. 
        if (xmlDoc == null)
            throw new ArgumentException("xmlDoc");
        if (Key == null)
            throw new ArgumentException("Key");

        // Create a SignedXml object.
        SignedXml signedXml = new SignedXml(xmlDoc);

        // Add the key to the SignedXml document.
        signedXml.SigningKey = Key;

        // Create a reference to be signed.
        Reference reference = new Reference();
        reference.Uri = "";

        // Add an enveloped transformation to the reference.
        XmlDsigEnvelopedSignatureTransform env = 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.
        XmlElement xmlDigitalSignature = signedXml.GetXml();

        // Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
    }

person user985637    schedule 08.01.2014    source источник


Ответы (1)


Проблема в том, что вы не можете хранить открытые ключи в контейнере ключей. Чтобы проверить подпись только с помощью открытого ключа, вы должны импортировать ключ из XML, используя rsa.FromXmlString, а затем передать rsa непосредственно в функцию проверки подписи. Если вы попытаетесь сохранить открытый ключ в контейнере ключей и получить его позже, вы просто создадите новый ключ. Как сохранить открытый ключ в контейнере ключей RSA на уровне компьютера

person user985637    schedule 09.01.2014
comment
Другим вариантом может быть включение ключа (или даже сертификата) в подписанный документ. Это не занимает много места, но освобождает потребителей от получения ключа по отдельному каналу. - person Wiktor Zychla; 09.01.2014
comment
Потребителям все равно нужно будет как-то проверить, что открытый ключ принадлежит тому, кому, по их мнению, он принадлежит. В моем случае у потребителя уже есть открытый ключ при получении xml. - person user985637; 09.01.2014
comment
Верно, но им нужен только отпечаток ключа (хэш ключа) для сравнения с полученным. - person Wiktor Zychla; 09.01.2014