Расчет хэш-суммы по ГОСТ

Рейтинг: 0Ответов: 1Опубликовано: 13.02.2025

Нужно посчитать хэш значение по алгоритму ГОСТ 34.11 Есть документация где рассчитан пример:

<ds:Reference URI="#id-9a89bcea-eb0d-41f2-a8e8-405ad5ea0d62">
              <ds:Transforms>
                 <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
              </ds:Transforms>
              <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/>
              <ds:DigestValue>STvOHkqaWjQbVCkB7mnG++RLLdGmjryqTqS+BcZx4Cg=</ds:DigestValue>
           </ds:Reference>

Область документа, на которую ссылается:

<a:To wsu:Id="id-9a89bcea-eb0d-41f2-a8e8-405ad5ea0d62" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">https://ips.test.egisz.rosminzdrav.ru/57234d87b0838</a:To>

Я так и не понял, по какому алгоритму нужно получить хэш-сумму(34.11-2012 или 34.11-1994) Вот код для 34.11-2012(библиотека pygost: https://github.com/ilyaTT/pygost_0_15/tree/master):

from lxml import etree
from pygost.gost3411_12 import GOST341112
import base64

data = '''<a:To wsu:Id="id-9a89bcea-eb0d-41f2-a8e8-405ad5ea0d62" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:a="http://www.w3.org/2005/08/addressing">https://ips.test.egisz.rosminzdrav.ru/57234d87b0838</a:To>'''

parser = etree.XMLParser(remove_blank_text=True)
xml_tree = etree.fromstring(data.encode("utf-8"), parser)

canonical_xml = etree.tostring(xml_tree, method="c14n", exclusive=True).decode("utf-8")

canonical_base64 = base64.b64encode(canonical_xml.encode("utf-8")).decode("utf-8")
data_bytes = canonical_base64.encode("utf-8")[::-1]

# Хэшируем
gost_hash = GOST341112(digest_size=256)
gost_hash.update(data_bytes)
signature_hash = gost_hash.digest()[::-1]

# Хэш в шестнадцатеричной строке
hex_string = signature_hash.hex()
print("HEX:", hex_string)

new_value = base64.b64encode(signature_hash).decode()
print("BASE64:", new_value)

Хэш-сумма, получаемая в программе, не совпадает с той что в образце.

Реализация для ГОСТ 34.11-1994:

from lxml import etree
from pygost.gost3411_94 import GOST341194
import base64

# Исходный XML-документ
xml_data = '''<a:To wsu:Id="id-9a89bcea-eb0d-41f2-a8e8-405ad5ea0d62" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">https://ips.test.egisz.rosminzdrav.ru/57234d87b0838</a:To>'''

root = etree.fromstring(xml_data)

# Канонизируем (c14n)
data_to_hash = etree.tostring(root, method="c14n", exclusive=True, with_comments=False)

print(type(data_to_hash))

print(data_to_hash)

# Вычисляем хэш (ГОСТ Р 34.11-94)
gost_hash = GOST341194(data_to_hash)
digest_value = gost_hash.digest()

digest_base64 = base64.b64encode(digest_value).decode()
print("DigestValue:", digest_base64)

Получил хэш: "ost9NriBuOVw2DKHUiKThCpIVkk2HITA0v6cMWv16mU=" А должно получится: "STvOHkqaWjQbVCkB7mnG++RLLdGmjryqTqS+BcZx4Cg="

Ответы

▲ 0Принят

Я так и не понял, по какому алгоритму нужно получить хэш-сумму(34.11-2012 или 34.11-1994)

http://www.w3.org/2001/04/xmldsig-more#gostr3411 идентифицирует ГОСТ Р 34.11-94, смотрите, например: https://datatracker.ietf.org/doc/html/draft-chudov-cryptopro-cpxmldsig-00 (Примечание, это устаревший идентификатор, несколько менее устаревшего алгоритма. Однако, если кто-то где-то его таки ещё использует, то, наверное, по возможности, стоит использовать urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr3411)

У ГОСТ Р 34.11-2012 идентификаторы urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256 и urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-512, смотрите, например: https://datatracker.ietf.org/doc/html/draft-smirnov-xmldsig-05

P.S.

... (библиотека pygost: https://github.com/ilyaTT/pygost_0_15/tree/master):

DEFAULT_SBOX = "GostR3411_94_TestParamSet"
...
class GOST341194(object):
   ...
   def __init__(self, data=b'', sbox=DEFAULT_SBOX):
       ... 

Что весьма странно, я бы сказал даже ошибочно, т.к. тестовые параметры предназначены только для тестирования (о чём везде написано, начиная с самого ГОСТ Р 34.11-94) и не должны использоваться без явного запроса.

Впрочем, возможно, не смертельно, если в этой библиотеке нет других серьёзных ошибок, но в вашем коде:

# Вычисляем хэш (ГОСТ Р 34.11-94)
gost_hash = GOST341194(data_to_hash)

А в спецификациях указано:

The ds:DigestMethod element MAY include a descendant element named cpxmlsec:NamedParameters to specify hash algorithm parameters.

If present, hash algorithm parameters MUST be included in the "URI" attribute of the cpxmlsec:NamedParameters element. Parameters are indicated by OIDs and MUST be formatted in accordance with [RFC3061]. OIDs defined in section 8.2 of [RFC4357] MAY be used.

If the cpxmlsec:NamedParameters element is not included, id-GostR3411-94-CryptoProParamSet (see [RFC4357]) MUST be presumed

P.P.S.

Хэш значения pygost выдаёт перевёрнутые, можно сравнить, например, с контрольными примерами OpenSSL: github.com/gost-engine/engine/blob/v3.0.3/test/01-digest.t

Я так понял, подтвердилось, что код в вопросе, при обработке <Reference URI=...> выдавал не тэг целиком, а только его содержимое.