Расчет хэш-суммы по ГОСТ
Нужно посчитать хэш значение по алгоритму ГОСТ 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="
Ответы (1 шт):
Я так и не понял, по какому алгоритму нужно получить хэш-сумму(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=...>
выдавал не тэг целиком, а только его содержимое.