Сообщить об ошибке.

Функции blake2b() и blake2s() модуля hashlib в Python

Криптографическая хеш-функция BLAKE2

BLAKE2 - это криптографическая хеш-функция, определенная в RFC 7693, которая поставляется в двух вариантах:

  • BLAKE2b, оптимизированный для 64-битных платформ и создающий хеши(дайджесты) любого размера от 1 до 64 байт,
  • BLAKE2s, оптимизированный для 8 и 32-битных платформ, создает хеши(дайджесты) любого размера от 1 до 32 байт.

BLAKE2 поддерживает режим ключей, более быстрая и простая замена HMAC. Поддерживает хеширование с добавлением соли, персонализацию хеша и хеширование дерева.

Предупреждение.
Хеширование с добавлением соли или простого хеширования с помощью BLAKE2 или любой другой криптографической хеш-функции общего назначения, такой как SHA-256, не подходит для хеширования паролей.

Синтаксис:

import hashlib

hashlib.blake2b(data=b'', *, digest_size=64, key=b'', salt=b'', 
                person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, 
                node_depth=0, inner_size=0, last_node=False, usedforsecurity=True)

hashlib.blake2s(data=b'', *, digest_size=32, key=b'', salt=b'', 
                person=b'', fanout=1, depth=1, leaf_size=0, node_offset=0, 
                node_depth=0, inner_size=0, last_node=False, usedforsecurity=True)

Возвращаемое значение:

Описание:

Функции hashlib.blake2b() и hashlib.blake2s() модуля hashlib возвращают соответствующие хеш-объекты для вычисления хешей BLAKE2b или BLAKE2s.

Они могут принимать следующие общие параметры:

  • data: начальный кусок данных для вычисления хеша, должен быть байтоподобным объектом. Аргумент data может быть передан только как позиционный аргумент.
  • digest_size: int размер выходного хеша(дайджеста) в байтах.
  • key: ключ, для хеширования по ключу, должна быть до 64 байтов для BLAKE2b, до 32 байтов для BLAKE2s.
  • salt: соль для рандомизированного хеширования, должна быть до 16 байт для BLAKE2b, до 8 байт для BLAKE2s.
  • person: строка персонализации выходного хеша, должна быть до 16 байтов для BLAKE2b, до 8 байтов для BLAKE2s.

В следующей таблице приведены ограничения для общих параметров, значения указаны в байтах:

Hashdigest_sizelen(key)len(salt)len(person)
BLAKE2b64641616
BLAKE2s323288

Примечание.
Спецификация BLAKE2 определяет постоянные длины для параметров соли salt и строки персонализации person, однако для удобства эта реализация принимает байтовые строки любого размера вплоть до указанной длины. Если длина параметра меньше указанной, она дополняется нулями, поэтому например b'salt' и b'salt\\x00' - это одно и то же значение, но это не так для ключа key.

Эти размеры доступны как константы модуля, описанные ниже.

Функции конструктора также принимают следующие параметры хеширования дерева:

  • fanout: разветвление (от 0 до 255, 0, если не ограничено, 1 в последовательном режиме).
  • depth: максимальная глубина дерева (от 1 до 255, 255 без ограничений, 1 в последовательном режиме).
  • leaf_size: максимальная длина байта листа (от 0 до 2**32-1, 0, если не ограничено или в последовательном режиме).
  • node_offset: смещение узла (от 0 до 2 ** 64-1 для BLAKE2b, от 0 до 2**48-1 для BLAKE2s, 0 для первого, крайнего левого, конечного или в последовательном режиме).
  • node_depth: глубина узла (от 0 до 255, 0 для листьев или в последовательном режиме).
  • inner_size: размер внутреннего хеша (от 0 до 64 для BLAKE2b, от 0 до 32 для BLAKE2s, 0 в последовательном режиме).
  • last_node: логическое значение, указывающее, является ли обработанный узел последним (False для последовательного режима).
  • usedforsecurity=True: запрещает использовать небезопасные и заблокированные алгоритмы хеширования (новое в Python 3.9).

Константы алгоритмов BLAKE2b и BLAKE2b.

blake2b.SALT_SIZE
blake2s.SALT_SIZE
:

Длина соли (максимальная длина, принятая конструкторами).

blake2b.PERSON_SIZE
blake2s.PERSON_SIZE
:

Длина строки персонализации (максимальная длина, принимаемая конструкторами).

blake2b.MAX_KEY_SIZE
blake2s.MAX_KEY_SIZE
:

Максимальный размер ключа.

blake2b.MAX_DIGEST_SIZE
blake2s.MAX_DIGEST_SIZE
:

Максимальный размер дайджеста, который может вывести хеш-функция.

Примеры:

Чтобы вычислить хеш некоторых данных, вы должны сначала создать хеш-объект, вызвав соответствующую функцию конструктора hashlib.blake2b() или hashlib.blake2s(), а затем обновить его данными, вызвав метод hash.update() для объекта и наконец получить хеш объекта путем вызова hash.digest() для [байтовой строки][t-bytes] илиhash.hexdigest() для строки в шестнадцатеричном коде.

>>> from hashlib import blake2b
>>> h = blake2b(digest_size=25)
>>> h.update(b'Hello world')
>>> h.hexdigest()
# '70ac97a738e8f0ccdecc277268516235e1ac687019af3f192b'

В качестве аргумента вы можете передать первый фрагмент данных для обновления непосредственно конструктору в качестве позиционного аргумента:

>>> from hashlib import blake2b
>>> blake2b(b'Hello world', digest_size=30).hexdigest()
# '5e9196a5ceaac41fa1c545c0b95df361856cee39b7a56235f11145d3affc'

Вы можете вызывать hash.update() столько раз, сколько нужно для итеративного обновления хеша:

>>> from hashlib import blake2b
>>> items = [b'Hello', b' ', b'world']
>>> h = blake2b(digest_size=30)
>>> for item in items:
...     h.update(item)
>>> h.hexdigest()
# '5e9196a5ceaac41fa1c545c0b95df361856cee39b7a56235f11145d3affc'

BLAKE2 имеет настраиваемый размер получаемого хеша до 64 байт для BLAKE2b и до 32 байт для BLAKE2s. Например, чтобы заменить SHA-1 на BLAKE2b без изменения размера вывода, мы можем указать BLAKE2b создать 20-байтовые дайджесты:

>>> from hashlib import blake2b
>>> h = blake2b(digest_size=20)
>>> h.update(b'Replacing SHA1 with the more secure function')
>>> h.hexdigest()
# 'd24f26cf8de66472d58d4e1b1774b4c9158b1f4c'
>>> h.digest_size
# 20
>>> len(h.digest())
# 20

Хеш-объекты с разным размером получаемого хеша имеют совершенно разные выходные данные. Более короткие хеши не являются префиксами более длинных хешей. BLAKE2b и BLAKE2s производят разные выходы, даже если длина вывода одинакова:

>>> from hashlib import blake2b, blake2s
>>> blake2b(digest_size=10).hexdigest()
# '6fa1d8fcfd719046d762'
>>> blake2b(digest_size=11).hexdigest()
# 'eb6ec15daf9546254f0809'
>>> blake2s(digest_size=10).hexdigest()
# '1bf21a98c78a1c376ae9'
>>> blake2s(digest_size=11).hexdigest()
# '567004bf96e4a25773ebf4'

Хеширование на основе ключа может использоваться для аутентификации в качестве более быстрой и простой замены кода аутентификации сообщений на основе хеша HMAC. BLAKE2 может безопасно использоваться в режиме префикса MAC благодаря свойству безразличия, унаследованному от BLAKE.

В этом примере показано, как получить (шестнадцатеричный) 128-битный код аутентификации для сообщения b'message data' с ключом b'pseudorandom key':

>>> from hashlib import blake2b
>>> h = blake2b(key=b'pseudorandom key', digest_size=16)
>>> h.update(b'message data')
>>> h.hexdigest()
# '3d363ff7401e02026f4a4687d4863ced'

В качестве практического примера веб-приложение может симметрично подписывать файлы cookie, отправляемые пользователям, а затем проверять их, чтобы убедиться, что они не были подделаны:

>>> from hashlib import blake2b
>>> from hmac import compare_digest
>>> SECRET_KEY = b'pseudorandomly generated server secret key'
>>> AUTH_SIZE = 16

>>> def sign(cookie):
...     h = blake2b(digest_size=AUTH_SIZE, key=SECRET_KEY)
...     h.update(cookie)
...     return h.hexdigest().encode('utf-8')

>>> def verify(cookie, sig):
...     good_sig = sign(cookie)
...     return compare_digest(good_sig, sig)

>>> cookie = b'user-alice'
>>> sig = sign(cookie)
>>> print("{0},{1}".format(cookie.decode('utf-8'), sig))
# user-alice,b'43b3c982cf697e0c5ab22172d1ca7421'
>>> verify(cookie, sig)
# True
>>> verify(b'user-bob', sig)
# False
>>> verify(cookie, b'0102030405060708090a0b0c0d0e0f00')
# False

Несмотря на то, что существует встроенный режим хеширования с ключом, BLAKE2, конечно же может использоваться в конструкции HMAC с модулем hmac:

>>> import hmac, hashlib
>>> m = hmac.new(b'secret key', digestmod=hashlib.blake2s)
>>> m.update(b'message')
>>> m.hexdigest()
# 'e3c8102868d28b5ff85fc35dda07329970d1a01e273c37481326fe0c861c8142'

Персонализация хешей.

Иногда полезно заставить хеш-функцию создавать разные дайджесты для одного и того же ввода для разных целей.

Цитируем авторов хеш-функции Скейна:

Мы рекомендуем всем дизайнерам приложений серьезно подумать об этом; Мы видели много протоколов, где хеш, который вычисляется в одной части протокола, может использоваться в совершенно другой части, потому что два вычисления хеша были выполнены для похожих или связанных данных, и злоумышленник может заставить приложение сделать один и тот же хеш-ввод. Персонализация каждой хеш-функции, используемой в протоколе, в целом останавливает этот тип атаки.

BLAKE2 можно персонализировать, передав байты аргументу person:

>>> from hashlib import blake2b
>>> FILES_HASH_PERSON = b'MyApp Files Hash'
>>> BLOCK_HASH_PERSON = b'MyApp Block Hash'
>>> h = blake2b(digest_size=32, person=FILES_HASH_PERSON)
>>> h.update(b'the same content')
>>> h.hexdigest()
# '20d9cd024d4fb086aae819a1432dd2466de12947831b75c5a30cf2676095d3b4'
>>> h = blake2b(digest_size=32, person=BLOCK_HASH_PERSON)
>>> h.update(b'the same content')
>>> h.hexdigest()
# 'cf68fb5761b9c44e7878bfb2c4c9aea52264a80b75005e65619778de59f383a3'

Персонализация вместе с режимом работы с ключами также может использоваться для получения разных ключей из одного и того же хеша.

>>> from hashlib import blake2s
>>> from base64 import b64decode, b64encode
>>> orig_key = b64decode(b'Rm5EPJai72qcK3RGBpW3vPNfZy5OZothY+kHY6h21KM=')
>>> enc_key = blake2s(key=orig_key, person=b'kEncrypt').digest()
>>> mac_key = blake2s(key=orig_key, person=b'kMAC').digest()
>>> print(b64encode(enc_key).decode('utf-8'))
# rbPb15S/Z9t+agffno5wuhB77VbRi6F9Iv2qIxU7WHw=
>>> print(b64encode(mac_key).decode('utf-8'))
# G9GtHFE1YluXY1zWPlYk1e/nWfu0WSEb0KRcjhDeP/o=

Хеширование с добавлением соли.

Добавив соли, пользователи могут ввести рандомизацию в хеш-функцию. Рандомизированное хеширование полезно для защиты от коллизионных атак на хеш-функцию, используемую в цифровых подписях.

В BLAKE2 - соль обрабатывается как одноразовый вход для хеш-функции во время инициализации, а не как вход для каждой функции сжатия.

>>> import os
>>> from hashlib import blake2b
>>> msg = b'some message'
# Вычислите первый хеш со случайной солью.
>>> salt1 = os.urandom(blake2b.SALT_SIZE)
>>> h1 = blake2b(salt=salt1)
>>> h1.update(msg)
# Вычислите второй хеш с другой случайной солью.
>>> salt2 = os.urandom(blake2b.SALT_SIZE)
>>> h2 = blake2b(salt=salt2)
>>> h2.update(msg)
# Хеши разные.
>>> h1.digest() != h2.digest()
# True