Добрый день. Разобрались частично, это уже маленькая победа, поздравляю.
Автор: Philarete Правильно ли я пониманию, что DigestValue это хеш подписываемых данных, полученный по алгоритму, к примеру CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256?
Верно. Фрагмент выбирается в Reference атрибут URI, далее смотрятся подчиненные Reference теги. Точный алгоритм должен быть указан в теге DigestMethod атрибут Algorithm, например
Код:<ds:DigestMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256"/>
, то есть если нужна универсальность, то надо сделать некую свою табличку соответствий значений атрибута и констант CADESCOM_HASH_ALGORITHM_*
Если напомнить процедуру точнее, нужно взять подписываемый фрагмент (с учетом контекста предков, но если у Вас весь документ подписывается, то контекст предков пустой, просто берете все). Если берете фрагмент не XML парсером, то следует учесть, что в норме парсер выполняет нормализацию переводов строк (символы 13+10 заменяются на 10, потом одиночные символы 13 заменяются на 10), то есть во взятом фрагменте не должно быть символов с кодом 13. К взятому фрагменту применяются все указанные в <Transforms> трансформы. В случае каноникализации стоит учитывать, что кодировка должна быть UTF-8 если <?xml ?> нет (либо корректно указана в <?xml ?>, в этом случае будет автоматом преобразована к UTF-8). Результат трансформов как поток октетов (то есть текст "лишается прав текста" и трактуется как "байты") идет на хэширование.
В случае плагина рекомендуется указать DataEncoding = ...BASE64_TO_BINARY (оно же 1) и закодировать текст в Base64 перед передачей методу Hash во избежание искажения при передаче в плагин.
Автор: Philarete Если захешировать подписываемые данные через HashedData и взять просчитанный хеш по алгоритму, перегнать в кодировку Base64, то он не совпадает с DigestValue из подписи. Но если самим подписать данные через SignedXML с использованием того же алгоритма и вытащить оттуда DigestValue, то он совпадёт. Можно ли как-то получить такой DigestValue, но без подписывания данных? В чём различие хеширований в двух описанных способах по одному алгоритму?
Если алгоритм совпадает, то никаких различий самого процесса хэширования нет. У алгоритма гост-94 были еще наборы параметров (внутренних констант для вычисления хэша), нужно было следить за оидом параметров. У алгоритма гост-2012 все константы прописаны в самом стандарте, так что попытки изменить оид параметров возвращают ошибку.
Другой вопрос в том, что стандарты гост обычно не регламентируют формат представления результата хэширования программными реализациями. Совсем. В самом стандарте константы и примеры записаны как числа в позиционной системе счисления, то есть наиболее значимый бит (и байт) первым (BIG ENDIAN). В стандарте XMLDSIG аналогичный порядок байт. Модули гост для openssl аналогично.
Однако как отвечали выше КриптоПро CSP на самом нижнем уровне возвращает данные как LITTLE ENDIAN. Некоторые интерфейсы уровнем повыше уже это учитывают и корректируют порядок байт, некоторые нет. Если нет, нужно будет в своем коде "отзеркалить" результат (как описано в моем ответе выше). Для гост-2012 чаще всего приходится "отзеркалить" значение подписи, а вот "отзеркалить" хэш обычно не требуется.
С представлением длинных чисел в XMLDSIG есть дополнительные нюансы. С хэшем и подписью гост такого практически никогда не случается (регламентировано количество бит в начале, которые могут быть нулевые, целого нулевого байта не получается), но знать не помешает.
Если идущий в начале байт нулевой (иногда еще требуется чтобы следующий ненулевой был менее 128, так как первый байт более 128 может означать отрицательное число и если число неотрицательное впереди сохраняется/добавляется нулевой байт), то нулевой байт исключается из представления (до кодирования в Base64).
Следовательно, надо внимательно читать что именно возвращается через тот или иной интерфейс. В частности, из плагина результат по умолчанию возвращается
в шестнадцатиричном виде, то есть надо результат декодировать в "бинарный" вид (и при необходимости "отзеркалить") перед кодированием Base64. Если же закодируете прямо шестнадцатиричный в Base64, то результат будет
в 2 раза длиннее.
Отредактировано пользователем 16 мая 2022 г. 6:55:03(UTC)
| Причина: Не указана