На этом шаге мы рассмотрим особенности выполнения этих операций.
Как объединить фиктивные данные с исходными данными, которые мы хотим зашифровать? В этом поможет операция XOR - логическая побитовая (работает на уровне битов) операция, которая возвращает true, если один из ее операндов равен True, и False, если оба оператора равны true или ни один из них не равен true. Как вы уже догадались, аббревиатура XOR означает exclusive or (исключающее ИЛИ).
В Python оператор XOR обозначается как ^. В контексте битов двоичных чисел XOR возвращает 1 для 0 ^ 1 и 1 ^ 0, но 0 для 0 ^ 0 и 1 ^ 1. Если объединить два числа, выполнив для каждого их бита XOR, то полезным свойством этой операции будет то, что при объединении результата с одним из операндов получим второй операнд:
А ^ B = С С ^ В = А С ^ А = В
Такое представление ключа лежит в основе шифрования с использованием одноразового шифра. Чтобы сформировать результат, мы просто выполняем XOR для значения int, представляющего байты исходной строки str, и случайно сгенерированного значения int той же битовой длины, полученного с помощью random_key(). Полученная пара ключей будет фиктивными данными и результатом шифрования.
def encrypt(original: str) -> Tuple[int, int]: original_bytes: bytes = original.encode() dummy: int = random_key(len(original_bytes)) original_key: int = int.from_bytes(original_bytes, "big") encrypted: int = original_key ^ dummy # XOR return dummy, encrypted
Расшифровка - это просто рекомбинация пары ключей, сгенерированной с помощью encrypt(). Она достигается посредством повторного выполнения операции XOR побитово для двух ключей. Окончательный результат должен быть преобразован обратно в тип str. Для этого сначала int преобразуется в bytes с помощью int.to_bytes(). Данный метод требует, чтобы число байтов было преобразовано из int. Чтобы получить это число, нужно разделить длину в битах на 8 (количество битов в байте). А затем метод bytes decode() возвращает str.
def decrypt(key1: int, key2: int) -> str: decrypted: int = key1 ^ key2 # XOR temp: bytes = decrypted.to_bytes((decrypted.bit_length() + 7) // 8, "big") return temp.decode()
Здесь также необходимо прибавить 7 к длине расшифрованных данных, прежде чем использовать целочисленное деление (//) на 8, чтобы гарантировать округление и избежать ошибки смещения на единицу. Если наше шифрование с одноразовыми ключами работает, то мы должны шифровать и дешифровать одну и ту же строку Unicode без проблем.
if __name__ == "__main__": key1, key2 = encrypt("One Time Pad!") result: str = decrypt(key1, key2) print(result)
Если в консоль выводится фраза "One Time Pad!", значит, все заработало.
На следующем шаге мы рассмотрим вычисление числа π.