Алгоритм канонизации XML дает два разных результата при непосредственном вызове, чем при вызове как часть цифровой подписи xml?

StackOverflow https://stackoverflow.com/questions/1026432

Вопрос

Я получаю два разных хэша одного и того же XML-документа, когда я напрямую канонизирую некоторый XML-файл, чем когда я выполняю цифровую подпись на нем, который также выполняет тот же алгоритм канонизации для XML-кода перед его хэшированием? Я выяснил, что канонизация цифровой подписи включает символы новой строки '\ n' и символы пробела при канонизации, а прямой алгоритм - нет.

Включение символов новой строки + пробелов не входит в спецификацию канонизации? Я специально смотрю на эту версию http://www.w3.org / TR / 2001 / REC-XML-c14n-20010315

Кто-нибудь знает, что происходит? Я включил документ xml и обе реализации кода, чтобы вы могли видеть.

Это действительно озадачивает меня, и я хотел бы знать почему, я что-то упускаю из виду?

<root>
  <child1>some text</child1>
  <child2 attr="1" />
</root>

Код прямой канонизации

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography;
using System.IO;
using System.ComponentModel;

namespace XML_SignatureGenerator
{
    class XML_C14N
    {
        private String _filename;
        private Boolean isCommented = false;
        private XmlDocument xmlDoc = null;

        public XML_C14N(String filename)
        {
            _filename = filename;
            xmlDoc = new XmlDocument();
            xmlDoc.Load(_filename);
        }

        //implement this spec http://www.w3.org/TR/2001/REC-xml-c14n-20010315
        public String XML_Canonalize(System.Windows.Forms.RichTextBox tb)
        {
            //create c14n instance and load in xml file
            XmlDsigC14NTransform c14n = new XmlDsigC14NTransform(isCommented);

            c14n.LoadInput(xmlDoc);

            //get canonalised stream
            Stream s1 = (Stream)c14n.GetOutput(typeof(Stream));
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            Byte[] output = sha1.ComputeHash(s1);

            tb.Text = Convert.ToBase64String(output);

            //create new xmldocument and save
            String newFilename = _filename.Substring(0, _filename.Length - 4) + "C14N.xml";
            XmlDocument xmldoc2 = new XmlDocument();
            xmldoc2.Load(s1);
            xmldoc2.Save(newFilename);

            return newFilename;
        }

        public void set_isCommented(Boolean value)
        {
            isCommented = value;
        }

        public Boolean get_isCommented()
        {
            return isCommented;
        }
    }
}

XML-код цифровой подписи

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;

namespace XML_SignatureGenerator
{
class xmlSignature
    {
        public xmlSignature(String filename)
        {
            _filename = filename;
        }

        public Boolean SignXML()
        {
            RSACryptoServiceProvider rsa =  new RSACryptoServiceProvider();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.PreserveWhitespace = true;
            String fname = _filename; //"C:\\SigTest.xml";
            xmlDoc.Load(fname);

            SignedXml xmlSig = new SignedXml(xmlDoc);
            xmlSig.SigningKey = rsa;

            Reference reference = new Reference();
            reference.Uri = "";

            XmlDsigC14NTransform env = new XmlDsigC14NTransform(false);
            reference.AddTransform(env);

            xmlSig.AddReference(reference);
            xmlSig.ComputeSignature();

            XmlElement xmlDigitalSignature = xmlSig.GetXml();
            xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

            xmlDoc.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/SignedXML.xml");

            return true;
        }
        private String _filename;
    }
}

Любая идея была бы отличной! Кстати, это весь код C #.

Заранее спасибо

Джон

Это было полезно?

Решение

Способ, которым XML Sig обрабатывает пробелы, на мой взгляд, нарушен. Это, конечно, не соответствует тому, что большинство здравомыслящих людей назвали бы канонизацией. Изменение пробела должно не влиять на дайджест, но в xmlsig это влияет.

Один из возможных обходных путей - пропустить документ через процедуру canonicalizer перед передачей его в код генерации подписи. Это должно сделать вещи намного более предсказуемыми.

Эта статья может помочь уточнить вещи.

Другие советы

Похоже, у вас есть второй фрагмент кода

xmlDoc.PreserveWhitespace = true;

пока в первом у тебя нет.

Насколько я понимаю, спецификация канонизации требует сохранения пробела между элементами, поэтому я предлагаю вам включить эту строку в оба.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top