Вступление
Статья частично является продолжениям идеи создания своего алгоритма шифрования на основе хеш функций из первой части. И так, продолжим. Большинство практических схем шифрования строятся вокруг проверенных стандартов вроде AES или RSA. В этом материале мы разберем альтернативный, исследовательский подход: шифрование, где для каждого байта сообщения подбирается собственное значение salt на основе SHA-256. Главная особенность алгоритма в том, что для шифрования используется хеш функция. Цель статьи — интуитивно и пошагово объяснить механику новой версии алгоритма, чтобы вы могли оценить его сильные и слабые стороны.
Идея алгоритма
Алгоритм обрабатывает сообщение как последовательность байтов. Для каждого байта используется текущее состояние ключа. Из ключа вычисляется хэш, а его первый байт играет роль маски XOR. Дальше происходит ключевой шаг, алгоритм подбирает число salt. Перебор продолжается, пока первый байт полученного хэша не совпадет с целевым значением, которое было рассчитано из исходного байта и маски XOR. Найденный salt и сохраняется в шифротекст. После этого ключ обновляется (снова через SHA-256), и следующий байт обрабатывается уже с новым ключом. Каждый шаг зависит от предыдущего состояния.
Шифрования
Шаг 1. Из секретной фразы получаем стартовый ключ
Берем любую секретную фразу произвольной длины (лучше конечно не меньше 16 символов) и хэшируем ее через SHA-256. Результат всегда 32 байта — это и есть стартовый ключ алгоритма.
import hashlib secret_phrase = "my very secret passphrase" secret_seed = secret_phrase.encode("utf-8") initial_key = hashlib.sha256(secret_seed).digest()
Шаг 2. Готовим данные для шифрования
Алгоритм работает с байтами, поэтому сообщение тоже переводим в bytes.
message = "Hello!" message_bytes = message.encode("utf-8")
Шаг 3. Шифруем один байт
Для каждого байта:
берем маску из текущего ключа (первый байт SHA-256 от ключа);
считаем целевое значение через XOR;
подбираем
saltперебором, пока первый байт SHA-256 отkey + saltне совпадет с целью, другими словами, не будет равноxor_target(single_byte ^ mask_byte).
def encrypt_byte(single_byte: int, current_key: bytes) -> tuple[int, bytes]: mask = hashlib.sha256(current_key).digest() mask_byte = mask[0] xor_target = single_byte ^ mask_byte salt = 0 while True: salt_bytes = salt.to_bytes(4, byteorder="big") attempt_hash = hashlib.sha256(current_key + salt_bytes).digest() if attempt_hash[0] == xor_target: break salt += 1 next_key = hashlib.sha256(current_key).digest() return salt, next_key
Шаг 4. Шифруем все сообщение
Повторяем шаг для каждого байта. В результате получаем массив salt — это и есть шифротекст.
salts = [] current_key = initial_key for b in message_bytes: salt, current_key = encrypt_byte(b, current_key) salts.append(salt) print("Ciphertext (salts):", salts)
Расшифрования
Шаг 1. Расшифровываем один байт
На расшифровке перебора уже нет. Мы знаем salt, поэтому сразу восстанавливаем байт.
def decrypt_byte(salt: int, current_key: bytes) -> tuple[int, bytes]: mask = hashlib.sha256(current_key).digest() mask_byte = mask[0] salt_bytes = salt.to_bytes(4, byteorder="big") attempt_hash = hashlib.sha256(current_key + salt_bytes).digest() xor_target = attempt_hash[0] single_byte = xor_target ^ mask_byte next_key = hashlib.sha256(current_key).digest() return single_byte, next_key
Шаг 2. Расшифровываем все сообщение
Идем по всему массиву salts, восстанавливаем байты, собираем обратно строку.
decrypted_bytes = bytearray() current_key = initial_key for salt in salts: single_byte, current_key = decrypt_byte(salt, current_key) decrypted_bytes.append(single_byte) decrypted_message = decrypted_bytes.decode("utf-8") print("Decrypted:", decrypted_message)
Итоги
Этот алгоритм — интересный пример того, как можно построить обратимое преобразование вокруг SHA-256 или другой хеш функции и использовать это для шифрования данных. Алгоритм конечно можно модифицировать и улучшать, здесь показана только идея и принцип работы. Полный код можно найти на GitHub. Спасибо за внимание и комментарии.
