Введение

Тип структуры данных

В криптографии и информатике хеш-дерево, или дерево Меркла, — это дерево, в котором каждый "листовой" узел помечен криптографическим хешем блока данных, а каждый узел, который не является листом (называемый ветвью, внутренним узлом или inode), помечен криптографическим хешем меток его дочерних узлов. Хеш-дерево обеспечивает эффективную и безопасную проверку содержимого большой структуры данных. Хеш-дерево является обобщением хеш-списка и хеш-цепи. Для демонстрации того, что листовой узел является частью заданного двоичного хеш-дерева, требуется вычислить количество хешей, пропорциональное логарифму числа листовых узлов в дереве. В отличие от этого, в хеш-списке это число пропорционально количеству листовых узлов. Таким образом, дерево Меркла является эффективным примером схемы криптографического подтверждения, в которой корень дерева рассматривается как подтверждение, а листовые узлы могут быть раскрыты и доказаны как часть исходного подтверждения. Концепция хеш-дерева названа в честь Ральфа Меркла, который запатентовал её в 1979 году.

Обзор

Хаширующее дерево — это дерево хэшей, в котором листья (т. е. листовые узлы, иногда также называемые «листьями») являются хэшами блоков данных, например, файла или набора файлов. Узлы, расположенные выше в дереве, являются хэшами их соответствующих дочерних узлов. Например, на приведенном выше рисунке хэш 0 является результатом хеширования конкатенации хэша 0 0 и хэша 0 1. То есть, хэш 0 = хэш(хэш 0 0 + хэш 0 1), где "+" обозначает конкатенацию. Большинство реализаций хэш-деревьев являются бинарными (с двумя дочерними узлами под каждым узлом), но они могут также использовать гораздо больше дочерних узлов под каждым узлом. Обычно для хеширования используется криптографическая хеш-функция, такая как SHA 2. Если хэш-дерево должно защищать только от случайных повреждений, можно использовать незащищённые контрольные суммы, такие как CRC. В верхней части хэш-дерева находится верхний хэш (или корневой хэш, или мастер-хэш). Перед загрузкой файла в P2P-сети в большинстве случаев верхний хэш получают из доверенного источника, например, от друга или веб-сайта, который известен хорошими рекомендациями по файлам для загрузки. Когда верхний хэш доступен, хэш-дерево можно получить из любого недоверенного источника, например, от любого участника P2P-сети. Затем полученное хэш-дерево проверяется на соответствие доверенному верхнему хэшу, и если хэш-дерево повреждено или подделано, будет опробовано другое хэш-дерево из другого источника, пока программа не найдёт то, которое соответствует верхнему хэшу. Основное отличие от хэш-списка заключается в том, что одну ветвь хэш-дерева можно загрузить за один раз, и целостность каждой ветви можно проверить немедленно, даже если всё дерево ещё не доступно. Например, на рисунке целостность блока данных L2 можно проверить немедленно, если дерево уже содержит хэш 0 0 и хэш 1, путём хеширования блока данных и последовательного объединения результата с хэшем 0 0, а затем с хэшем 1 и, наконец, сравнения результата с верхним хэшем. Аналогично, целостность блока данных L3 можно проверить, если дерево уже содержит хэш 1 1 и хэш 0. Это может быть преимуществом, поскольку эффективно разбивать файлы на очень маленькие блоки данных, так что только небольшие блоки нужно будет повторно загружать в случае повреждения. Если хешируемый файл большой, такой хэш-список или хэш-цепочка становится довольно объёмным. Но если это дерево, то можно быстро загрузить одну небольшую ветвь, проверить целостность ветви, а затем начать загрузку блоков данных.

Вторая атака на преимущество

Хэш-дерево Меркла не указывает глубину дерева, что делает возможной атаку второго прообраза, при которой злоумышленник создает документ, отличный от исходного, но имеющий тот же корневой хэш Меркла. В приведенном выше примере злоумышленник может создать новый документ, содержащий два блока данных, где первый является суммой хэшей 0 0 и 0 1, а второй – суммой хэшей 1 0 и 1 1. Простое решение описано в спецификации Certificate Transparency: при вычислении хэшей листовых узлов к данным хэша добавляется префикс 0x00, а при вычислении хэшей внутренних узлов – префикс 0x01. Хэширование в виде дерева Тигра используется в протоколах P2P обмена файлами Gnutella, Gnutella2 и Direct Connect, а также в приложениях для обмена файлами, таких как Phex, BearShare, LimeWire, Shareaza, DC++ и gtk gnutella.