Вы здесь

Объяснение протокола Диффи-Хеллмана (Python) для обмена ключами

Протокол для обмена ключами Диффи-Хеллмана (ДХ) – это метод безопасного обмена криптографическими ключами по общедоступному каналу; он был одним из первых протоколов с открытым ключом, первоначально концептуализированный Ральфом Мерклом и названный в честь Уитфилда Диффи и Мартина Хеллмана. ДХ является одним из первых практических примеров обмена открытыми ключами, реализованных в области криптографии.

Объяснение протокола Диффи-Хеллмана (Python) для обмена ключами

Сегодня ДХ используется для всех видов приложений, таких как Proton Mail и SSH. Бесплатным программным обеспечением для шифрования файлов, в котором используется ДХ, является GPG (для получения дополнительной информации прочтите статью Майкла Галарника «(Ассиметричная) криптография с открытым ключом при использовании GPG»).

Проблема сквозного шифрования

Давайте рассмотрим крайне простую ситуацию. Представьте, что мы с Майклом решили обменяться информацией. Теперь, скажем, хакер по имени господин Робот пытается перехватить наше сообщение.

Логичный способ не дать господину Роботу прочитать наше сообщение – это зашифровать его. При шифровании предполагается, что даже если система шифрования известна, сообщение не может быть расшифровано без ключа шифрования. Поэтому, пока мы с Майклом используем один и тот же метод шифрования и имеем один и тот же ключ, у нас все в порядке! Однако есть одна проблема…

Чтобы расшифровать зашифрованное сообщение Майкла, мне нужно, чтобы он отправил мне ключ по сети. Беда в том, что господин Робот ищет ключ. Если он получит доступ к ключу, он легко расшифрует все наши сообщения! Эта проблема обмена ключами решается алгоритмом Диффи-Хеллмана.

Как протокол Диффи-Хеллмана решает проблему?

Принцип работы протокола Диффи-Хеллмана заключается в том, чтобы не делиться полностью ключом шифрования по сети. Вместо этого у каждой стороны имеется открытый ключ (который может видеть каждый, включая господина Робота) и закрытый ключ (его может видеть только пользователь в конечной точке). У меня нет доступа к закрытому ключу Майкла. Майкл также не имеет доступа к моему закрытому ключу.

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

Создание базового класса

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

class DH_Endpoint(object):
    def __init__(self, public_key1, public_key2, private_key):
        self.public_key1 = public_key1
        self.public_key2 = public_key2
        self.private_key = private_key
        self.full_key = None
    def generate_partial_key(self):
        partial_key = self.public_key1**self.private_key
        partial_key = partial_key%self.public_key2
        return partial_key
    def generate_full_key(self, partial_key_r):
        full_key = partial_key_r**self.private_key
        full_key = full_key%self.public_key2
        self.full_key = full_key
        return full_key
    def encrypt_message(self, message):
        encrypted_message = ""
        key = self.full_key
        for c in message:
            encrypted_message += chr(ord(c)+key)
        return encrypted_message
    def decrypt_message(self, encrypted_message):
        decrypted_message = ""
        key = self.full_key
        for c in encrypted_message:
            decrypted_message += chr(ord(c)-key)
        return decrypted_message

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

message="This is a very secret message!!!"
s_public=197
s_private=199
m_public=151
m_private=157
Sadat = DH_Endpoint(s_public, m_public, s_private)
Michael = DH_Endpoint(s_public, m_public, m_private)

Частичный обмен ключами

Предположим, что мы ничего не видим внутри сервера Майкла (включая его закрытый ключ).

Теперь мне нужно создать частичный шифровальный ключ, используя 3 доступных информации: мой закрытый и открытый ключи.. и открытый ключ Майкла. Алгоритмически мы согласились использовать мой открытый ключ в качестве основы, а его открытый ключ – в качестве расчета «по модулю».

Если мы посмотрим на нашу функцию для генерации частичного ключа, то вот конкретно, что мы делаем:

        def generate_partial_key(self):
        partial_key = self.public_key1**self.private_key
        partial_key = partial_key%self.public_key2
        return partial_key

Теперь давайте сгенерируем этот частичный ключ и отправим его Майклу по сети.

s_partial=Sadat.generate_partial_key()
print(s_partial) #147

Таким же образом Майкл посылает мне свои частичные ключи и передает их мне через сеть.

m_partial=Michael.generate_partial_key()
print(m_partial)

Сравнение двух расчетов частичных ключей:

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

Все, что знает господин Робот, это частичные ключи и соответствующие открытые ключи, включая формулу, используемую для получения частичных ключей. Идея расчета «по модулю» заключается в том, что функция вызывает цикл значения. Если у вас по модулю 151, то значение будет от 0 до 151-1.

Существует бесконечное число возможных значений, расчет «по модулю» которых может быть 66 или 147. В результате информации будет недостаточно для установления закрытых ключей конечных пользователей (за исключением грубого форсирования безумно большого количества возможных вариаций). Кроме того, не забывайте, что я использую небольшие числа для закрытых и открытых ключей. В реальной жизни они будут огромными!

Создание полного ключа

Теперь, когда мы успешно обменялись частичными ключами, давайте снова применим оператор «возведения в степень» и «деления по модулю» (power и modulo) к частичному ключу другого человека, используя наши собственные закрытые ключи следующим образом:

Реализация этого на языке Python:

        def generate_full_key(self, partial_key_r):
        full_key = partial_key_r**self.private_key
        full_key = full_key%self.public_key2
        self.full_key = full_key
        return full_key

Вот мой код:

s_full=Sadat.generate_full_key(m_partial)
print(s_full) #75

А вот код Майкла, полученный с использованием моего частичного ключа:

m_full=Michael.generate_full_key(s_partial)
print(m_full) #75

Сравним их:

Заметили кое-то интересное? Мы оба получили полные ключи с 75 в конце! Причина, по которой это произошло, связана со следующим математическим уравнением:

Здесь a и b являются закрытыми ключами, а g и p – открытыми ключами. Важная деталь заключается в том, что нам удалось обменяться друг с другом по сети достаточной информацией для создания общего ключа шифрования без ущерба для наших закрытых ключей.

Время Шифрования!

Теперь, когда у нас есть общий ключ шифрования, пришло время начать обмен сообщениями! Как было объяснено в начале этого раздела, Майкл хочет отправить мне зашифрованное сообщение. Вот простой алгоритм шифрования, который я написал, чтобы зашифровать сообщение Майкла:

        def encrypt_message(self, message):
        encrypted_message = ""
        key = self.full_key
        for c in message:
            encrypted_message += chr(ord(c)+key)
        return encrypted_message

Ничего особенного. Каждый символ кодируется в целое число, добавляется значение ключа, а затем целое число преобразуется обратно в символ. Этот процесс повторяется для каждого символа в сообщении. Первоначальное сообщение, которым Майкл хотел поделиться, звучало как «Это очень секретное сообщение!!!». Давайте включим это в алгоритм с нашим новым ключом шифрования.

m_encrypted=Michael.encrypt_message(message)
print(m_encrypted) #'\x9f³´¾k´¾k¬kÁ°½Äk¾°®½°¿k¸°¾¾¬²°lll'

Зашифрованным сообщением является «\x9f3½kkká ° ½ փ k°¾2 ° lll», что представляет собой полную неразбериху для чтения. Господин Робот понятия не имеет, чем Майкл делится со мной.

Я получил нечитабельное сообщение по сети. Теперь пришло время расшифровать сообщение с моей стороны.

        def decrypt_message(self, encrypted_message):
        decrypted_message = ""
        key = self.full_key
        for c in encrypted_message:
            decrypted_message += chr(ord(c)-key)
        return decrypted_message

Эта функция делает обратное. В то время как шаг шифрования добавляет значение ключа, шаг расшифровки вычитает то же значение ключа.

message = Sadat.decrypt_message(m_encrypted)
print(message) #'This is a very secret message!!!'

Сообщение получено! Уважаемый господин Робот, нам удалось обменяться зашифрованными сообщениями без ущерба для наших ключей шифрования.

Удачи с Evil Corp!

Ограничения

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

  • В зависимости от того, что вы думаете о правительственной слежке, это может быть отличным решением. Обычно, когда данные хранятся в базе данных (например, в центре обработки данных), можно получить ордер на раскрытие данных. Хотя это можно рассматривать в качестве аргумента в пользу соблюдения правопорядка и безопасности, защитники конфиденциальности могут заявить, что хакер или тоталитарное правительство могут без труда воспользоваться в своих корыстных целях ценной информацией, хранимой в этом центре обработки данных. Смысл шифрования по протоколу ДХ заключается в том, что данные, хранимые в центре обработки данных, являются полным мусором, пока не будут расшифрованы на соответствующих серверах конечного пользователя. Такова идея, лежащая в основе Proton Mail. Если речь идет об обеспечении правопорядка, данные могут быть просто извлечены из устройства конечного пользователя (например, поиск смартфона с ордером).
  • Другое предположение, которое мы сделали, касается небезопасности в конечной точке. По определению, правильное взаимодействие с пользователем требует скрытия всего шифрования, которое происходит за сценой. Например, когда вы отправляете электронное письмо через WhatsApp или Proton Mail, данные в конечном итоге должны быть расшифрованы для просмотра сообщения. Следовательно, если конечная система скомпрометирована, данные все еще могут быть получены в незашифрованном виде.
Категория: 
Безопасность
4
Ваша оценка: Нет Средняя: 3.5 (2 оценок)
36039 / 0
Аватар пользователя Daritas
Публикацию добавил: Daritas
Дата публикации: пт, 04/12/2019 - 12:57

Что еще почитать: