Шифрование, расшифровка, контрольная сумма и многое другое

Хеширование - ключевая часть большинства языков программирования. Большие объемы данных могут быть представлены в фиксированном буфере. В структурах "ключ-значение" для хранения ссылок используются хэши.

Хеши используются для защиты. Хэши могут быть детерминированными или недетерминированными. Хеши могут значительно отличаться при небольших изменениях данных или очень похожи.

В этой статье будут рассмотрены наиболее распространенные способы хеширования данных в Python.

1. Встроенное хеширование

Python предоставляет встроенную функцию .hash(), как показано ниже.

>>> hash("test")
2314058222102390712

Вышеупомянутое было запущено в Python 2.7, давайте попробуем Python 3.7.

>>> hash("test")
5946494221830395164

Результат будет другим и будет отличаться для каждого нового вызова Python. Python никогда не гарантировал, что .hash() детерминирован.

В Python 2.x он будет детерминированным большую часть времени, но не всегда. Python 3.x добавил в .hash() случайность для повышения безопасности. Порядок сортировки словарей, наборов и списков по умолчанию поддерживается встроенным хешированием.

У меня есть целый проект, посвященный хешированию Python 2.x в Python 3.x. Как правило, .hash() не следует полагаться ни на что при вызовах Python.

2. Контрольные суммы

Контрольные суммы используются для проверки данных в файле. В файлах ZIP используются контрольные суммы, чтобы гарантировать, что файл не будет поврежден при распаковке. В отличие от встроенного хеширования Python, он детерминирован. Одни и те же данные будут возвращать каждый раз один и тот же результат.

Ниже приведен пример использования alder32 и crc32 zlib. Alder32 обычно является лучшим выбором, поскольку он намного быстрее и почти так же надежен, как crc32.

>>> import zlib
>>> zlib.adler32(b"test")
73204161
>>> zlib.crc32(b"test")
3632233996

Для небольшой базы данных adler32 можно использовать как простой хэш идентификатора. Но по мере роста объемов данных коллизии быстро станут проблемой.

3. Безопасное хеширование

Безопасные хэши и дайджесты сообщений развивались с годами. От MD5 до SHA1, от SHA256 до SHA512.

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

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

Посмотрите, насколько отличаются два хэша MD5 после изменения одного символа.

>>> import hashlib
>>> hashlib.md5(b"test1").hexdigest()
'5a105e8b9d40e1329780d62ea2265d8a'
>>> hashlib.md5(b"test2").hexdigest()
'ad0234829205b9033196ba818f7a872b'

Давайте посмотрим на некоторые распространенные алгоритмы безопасного хеширования.

MD5– 16 байт / 128 бит

Хэши MD5 имеют длину 16 байтов или 128 бит. См. Пример ниже, обратите внимание, что шестнадцатеричный дайджест представляет каждый байт как шестнадцатеричную строку (т.е. ведущий 09 - это один байт). Хеши MD5 больше не используются.

>>> import hashlib
>>> hashlib.md5(b"test").hexdigest()
'098f6bcd4621d373cade4e832627b4f6'
>>> len(hashlib.md5(b"test").digest())
16

SHA1–20 байт / 160 бит

Хэши SHA1 имеют длину 20 байтов или 160 бит. Хэши SHA1 также больше не используются.

>>> import hashlib
>>> hashlib.sha1(b"test").hexdigest()
'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'
>>> len(hashlib.sha1(b"test").digest())
20

SHA256–32 байта / 256 бит

Хэши SHA256 имеют длину 32 байта или 256 бит. Обычно используются хеши SHA256.

>>> import hashlib
>>> hashlib.sha256(b"test").hexdigest()
'9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'
>>> len(hashlib.sha256(b"test").digest())
32

SHA512–64 байта / 512 бит

Хэши SHA512 имеют длину 64 байта или 512 бит. Обычно используются хеши SHA512.

>>> import hashlib
>>> hashlib.sha512(b"test").hexdigest()
'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff'
>>> len(hashlib.sha512(b"test").digest())
64

4. Обнаружение почти повторяющихся данных

До этого момента все вышеперечисленные методы генерируют существенно разные хэши при изменении данных.

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

Но что, если цель - найти похожий контент. Обнаружение дубликатов или почти дубликатов помогает уменьшить объем хранимых данных.

Некоторые варианты использования требуют выявления тонких различий в данных, таких как обнаружение плагиата. В приведенном ниже примере для демонстрации будет установлена ​​библиотека Python Simhash.

pip install simhash

После завершения установки запускается следующий код.

Обратите внимание, насколько похожи хэши для близких данных. Но для других данных дело обстоит гораздо дальше.

5. Перцептивное хеширование

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

Одним из примеров этого может быть обнаружение почти повторяющихся кадров в видео. Можно использовать алгоритмы, чтобы исключить дублирование контента в видео или определить, что изображение достаточно близко, чтобы считать его дубликатом, что позволяет сэкономить место.

В приведенном ниже примере показаны два почти идентичных изображения и насколько близки их перцептивные хэши. Для демонстрации используется библиотека Python ImageHash.

pip install ImageHash

Используются следующие изображения:

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

Как и ожидалось, хеши совершенно разные. Теперь попробуем ImageHash.

Хеши разные, но очень близкие. Только один байт в конце отличается. ImageHash позволяет вычесть два хэша, чтобы получить разницу.

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

Заключение

В этой статье было рассмотрено несколько различных способов хеширования данных в Python. В зависимости от варианта использования эти методы предоставляют несколько вариантов построения хэшей. Надеюсь, это поможет в текущем или будущем проекте.