Подпись XML: как рассчитать значение дайджеста? - PullRequest
22 голосов
/ 11 февраля 2010

У меня есть такой XML

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar>
    <value>A</value>
  </bar>
  <bar>
    <value>B</value>
  </bar>
  <baz>
    <value>C</value>
  </baz><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue>WqpRWHxXA0YgH+p3Sxy6hRo1XIk=</DigestValue></Reference></SignedInfo><SignatureValue>EoRk/GhR4UA4D+8AzGPPkeim1dZrlSy88eF73n/T9Lpeq9IxoGRHNUA8FEwuDNJuz3IugC0n2RHQQpQajiYvhlY3XG+z742pgsdMfFE4Pddk4gF1T8CVS1rsF7bjX+FKT/c8B2/C8FNgmfkxDlB/ochtbRvuAGPQGtgJ3h/wjSg=</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIB8zCCAVygAwIBAgIQgfzbrIjhLL9FobStI2ub3zANBgkqhkiG9w0BAQQFADATMREwDwYDVQQDEwhUZXN0ZUFjbjAeFw0wMDAxMDEwMDAwMDBaFw0zNjAxMDEwMDAwMDBaMBMxETAPBgNVBAMTCFRlc3RlQWNuMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO+yAZ8/qJbhSVH/+2wMmzix3jM/CExb6sTgaiPwe6ylcHgF45zeQDq06OSJZCSns34em/ULINZddDf8z0b9uk/2sOGr1pYqsunLLBvw2FkvWJQDkhx2SzCm8v4xGX2kyXNbjiY/K56oPOMjpayKoAFnnvk7p2iFAxNZK/6lpZ7wIDAQABo0gwRjBEBgNVHQEEPTA7gBCOOHcajwnATYZ0t6w7LVU0oRUwEzERMA8GA1UEAxMIVGVzdGVBY26CEIH826yI4Sy/RaG0rSNrm98wDQYJKoZIhvcNAQEEBQADgYEABL9Qhi6f1Z+/t8oKXBQFx3UUsNF9N2o4k6q1c3CKZYqx2E/in+nARIYRdh5kbeLfomi6GIyVFeXExp8crob3MAzOQMvXf9+ByuezimMPIHDvv0u3kmmeITXfoZrHCDxLoWWlESN1owBfKPqe7JKAuu9ORDC0pUiUfCHWxCoqNos=</X509Certificate></X509Data></KeyInfo></Signature>
</foo>

Как создается значение дайджеста (WqpRWHxXA0YgH + p3Sxy6hRo1XIk =) в ссылке? Я имею в виду, как я могу вычислить это значение вручную?

Ответы [ 5 ]

21 голосов
/ 29 сентября 2011

Я сталкивался с этим вопросом, пытаясь выяснить точно то же самое. Позже я разобрался, как это сделать, поэтому решил опубликовать ответ здесь.

Вещи, которые должны произойти:

  • канонизации
  • создать дайджест-значение, обычно SHA1 (но может быть и SHA256 среди прочих)
  • base64 кодировать его

Часть канонизации была довольно простой, поскольку библиотеки Java сделали это для меня. То, с чем я боролся, было следующим битом, созданием дайджеста, потому что я допустил фатальную ошибку в том, что сгенерированный дайджест SHA1 был SHA1 в HEX-форме. SHA1 составляет 160 бит, то есть 20 байтов, но если вы выведите эти 160 бит в HEX, вы получите 40 символов. Если вы затем закодируете это base64, вы получите совершенно неправильное значение по сравнению с тем, что должно быть в DigestValue.

Вместо этого вы должны сгенерировать дайджест SHA1, а base64 закодировать 20-байтовый вывод. Не пытайтесь выводить 20 байтов в STDOUT, поскольку маловероятно, что он будет читабелен (именно поэтому люди часто выводят эквивалент HEX, так как он является читаемым). Вместо этого просто base64 кодирует 20 байтов, и это ваше DigestValue.

3 голосов
/ 05 февраля 2014

Очень просто, используйте openssl в консоли:

openssl dgst -binary -sha1 file | openssl enc -base64

Готово

3 голосов
/ 12 февраля 2010

Я сам столкнулся именно с этой проблемой: я генерировал подпись XML в Java и проверял в .NET, и проверка всегда заканчивалась неудачей. В моем случае причиной была функция «напечатать XML в файл» XMLWrite.m (да, в MATLAB *), которая «красиво печатала» XML, вставляя табуляцию, пробелы и переводы строк по своему усмотрению. Поскольку они являются частью документа, естественно, проверка не удалась (в Java она тоже не прошла). Глядя на ваш источник, это может происходить с вами. Используйте Transformer (javax.xml.transform. *) Для правильной сериализации DOM без изменения содержимого.

* Вы знали, что MATLAB также понимает Java? Вы можете просто ввести операторы Java в консоль интерпретатора, и они будут выполняться как собственный m-код.

2 голосов
/ 05 мая 2017

Это решение JAVA, для которого требуются следующие jar-файлы:

  • commons-logging-1.2.jar
  • commons-codec-1.6.jar
  • Saxon-HE-9.4.jar
  • xmlsec-1.3.0.jar

Это решение использует http://www.w3.org/2001/10/xml-exc-c14n# в качестве алгоритма канонизации и использует SHA256 в качестве алгоритма хеширования и кодирования base64.

Примечание: document представляет документ XML в виде объекта DOM в JAVA.

Пример кода:

        // create the transformer in order to transform the document from
        // DOM Source as a JAVA document class, into a character stream (StreamResult) of
        // type String writer, in order to be converted to a string later on
        TransformerFactory tf = new net.sf.saxon.TransformerFactoryImpl();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

        // create the string writer and transform the document to a character stream
        StringWriter sw = new StringWriter();
        transformer.transform(new DOMSource(document), new StreamResult(sw));

        String documentAsString = sw.toString();

        // initialize the XML security object, which is necessary to run the apache canonicalization
        com.sun.org.apache.xml.internal.security.Init.init();

        // canonicalize the document to a byte array and convert it to string
        Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
        byte canonXmlBytes[] = canon.canonicalize(documentAsString.getBytes());
        String canonXmlString = new String(canonXmlBytes);

        // get instance of the message digest based on the SHA-256 hashing algorithm
        MessageDigest digest = MessageDigest.getInstance("SHA-256");

        // call the digest method passing the byte stream on the text, this directly updates the message
        // being digested and perform the hashing
        byte[] hash = digest.digest(canonXmlString.getBytes(StandardCharsets.UTF_8));

        // encode the endresult byte hash
        byte[] encodedBytes = Base64.encodeBase64(hash);

        return new String(encodedBytes);
0 голосов
/ 11 февраля 2010

Этот документ должен содержать способ вычисления значения дайджеста.

Надеюсь, это поможет!

...