Протокол WireGuard позволяет создать защищенный сетевой туннель на третьем уровне модели ВОС между двумя узлами с помощью протокола передачи сообщений UDP. Он использует криптографическое квитирование, пересылка сообщений или сигналов, выдаваемых в ответ на принятые сообщения для осуществления взаимной аутентификации, согласования ключей и обеспечения прямой секретности. Защита информации, передаваемой в инкапсулированных IP-пакетах через туннели WireGuard, осуществляется с использованием аутентифицированного шифрования с присоединенными данными (Authenticated Encryption with Associated Data, далее AEAD).

Каждый узел может начать сессию после отправки сообщения о квитировании и приема ответного сообщения. В этом протоколе не существует строго закрепленных ролей клиента и сервера как у других протоколов туннелирования. Узел, который намерен начать сессию, называют инициатором, а узел, с которым устанавливают соединение, – ответчиком.

Сессия WireGuard
Сессия WireGuard

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

Сетевой интерфейс WireGuard (далее wg0) может подключаться к множеству узлов. Для гарантирования того, что IP-трафик направлен в нужный узел, существует политика маршрутизации криптоключей. В ней узлы ассоциируются с определенным набором доступных ему IP-адресов. Локальный трафик, поступающий на wg0, будет отправлен только в том случае, если IP-адрес назначения доступен для данного узла. А входящий трафик будет принят, если IP-адрес источника расшифрованного IP-пакета, содержится в списке доступных IP-адресов у аутентифицированного узла.

Потоковые шифры семейства Salsa20

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

Отправитель и получатель шифруют сообщения с помощью функции преобразования, суть работы которой заключается в использовании длинной цепочки простых операций с 32-битными словами:

  • 32-битное суммирование, представленное в виде, где a и b – два 32-битных слова.

  • 32-битное исключающее ИЛИ, представленное в виде, где a и b – два 32-битных слова.

  • 32-битное смещение, представленное в виде, где a – 32-битное слов, а b – определенное количество бит, на которое происходит смещение.

Операции Salsa20/r:

где a, b, c, d – 32-битные слова.

Работа Salsa20 заключается в преобразовании 256-битного ключа и 64-битного одноразового кода в 270-байтный поток, с помощью которого будет происходить шифрование b-байтного открытого текста, путем сложения его по модулю 2 с первыми b байтами потока и отбрасывания оставшейся его части. Дешифрование происходит по тому же алгоритму.

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

Ядро Salsa20 представлено в виде матрицы, состоящей из 16 слов: константы 0x6170865, первых четырех ключевых слов, константы 0x3320646e, двух слов одноразового кода, двух слов блокового счетчика, константы 0x79622d32, оставшихся четырех ключевых слов и константы 0x6b206574.

Начальная матрица Salsa20
Начальная матрица Salsa20

Рассмотрим пример, где начальная матрица Salsa20 выглядит следующим образом:

Пример начальной матрицы
Пример начальной матрицы

Диагональные константы одинаковы для каждого блока, каждого одноразового кода и для каждого 32-байтного ключа. После получения данного массива происходит изменение каждого под-диагонального слова по следующему алгоритму: сложение диагонального и над-диагонального слов, смещение на 7 бит влево и сложение по модулю 2 с под-диагональными словами.

Пример (первый столбец):

1) 61707865 + 18171615 = 79878E7A = 01111001100001111000111001111010.

2) 11000011110001110011110100111100 = C3C73D3C.

3) C3C73D3C xor 100F030D = D3C83331.

Первый четверть-раунд
Первый четверть-раунд

Далее изменяются все под-под-диагональные слова следующим образом: суммирование диагональных и под-диагональных слов, смещение на 9 бит влево и сложение по модулю 2 с под-под-диагональными словами.

Пример (первый столбец):

1) D3C83331 + 61707865 = 3538AB96 = 00110101001110001010101110010110.

2) 01110001010101110010110001101010 = 71572C6A.

3) 71572C6A xor 00000007 = 71572C6D.

Второй четверть-раунд
Второй четверть-раунд

На следующем шаге происходит суммирование под-диагонального и под-под-диагонального слов, смещением влево на 13 бит и сложение по модулю 2 с над-диагональным словом.

Пример (второй столбец):

1) 71572C6D + D3C83331 = 451F5F9E = 01000101000111110101111110011110.

2) 11101011111100111100100010100011 = EBF3C8A3.

3) EBF3C8A3 xor 18171615 = F3E4DEB6.

Третий четверть-раунд
Третий четверть-раунд

Затем осуществляется суммирование над-диагонального и под-под-диагонального слова, смещением влево на 18 бит и сложение по модулю 2 с диагональным словом.

Пример (первый столбец):

1) F3E4DEB6 + 71572C6D = 653C0B23 = 01100101001111000000101100100011.

2) 00101100100011011001010011110000= 2C8D94F0.

3) 2C8D94F0 xor 61707865 = 4DFDEC95.

Четвертый четверть-раунд
Четвертый четверть-раунд

В конце первого раунда, после инверсии, матрица будет выглядеть следующим образом:

Конец первого раунда
Конец первого раунда

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

Массив в конце двадцатого раунда Salsa20
Массив в конце двадцатого раунда Salsa20
Пример гаммы ключа в алгоритме Salsa20/20
Пример гаммы ключа в алгоритме Salsa20/20

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

Алгоритм шифрования ChaCha20

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

Основой алгоритма ChaCha является четверть-раунд, работающий с четырьмя 32-битными числами:

Операции ChaChar:

где a, b, c, d – 32-битные слова.

Начальная матрица ChaCha20 включает:

  • Четыре константы, расположенные в первой строке: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574.

  • Ключ, длинной 256 бит, причем каждые 4 байта расположены в обратном порядке.

  • Блоковый счетчик, длинной 32 бита.

  • Одноразовый код (nonce), длинной 96 бит, который не следует повторять для одного и того же ключа. Каждые 4 байта расположены в обратном порядке.

Начальная матрица ChaCha20
Начальная матрица ChaCha20

В ChaCha20 для формирования гаммы ключа используется система раундов, из которых десять вертикальных раундов и десять диагональных. Каждый раунд состоит из 4 четверть-раундов, порядок прохождения которых представлен на рисунке 19. После двадцатого раунда происходит сложение начальной и конечной матрицы для формирования поточного ключа.

Вертикальные и диагональные раунды
Вертикальные и диагональные раунды

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

Комментарии (6)


  1. datacompboy
    03.08.2023 14:58
    +1

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

    "Мы берём два числа, складываем их. Таким образом, семейство алгоритмов сложения потенциально может претендовать на роль надежной и быстрой замены всех шифров мира."


  1. DGG
    03.08.2023 14:58

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

    В результате какой-нибудь более "тяжёлый" OpenVPN с AES в настройках, батарейку телефона жрет меньше чем WireGuard


    1. Number571
      03.08.2023 14:58

      Нужно также ещё понимать, что ChaCha20 - это представитель поточных алгоритмом шифрования в которых генерация гаммы оторвана от шифруемого сообщения, и проблемой которых всегда является необходимость учитывать неповторяемость гаммы за счёт неповторяемости Nonce или ключа (как в RC4). В это же время, блочные алгоритмы более гибки в своей настройке за счёт режимов шифрования, хоть и в большинстве случаев менее производительны. И за счёт режимов, как пример, CBC, CFB, отпадает необходимость учитывать Nonce. Вполне достаточным остаётся использование случайного вектора инициализации. И даже если таковой повторится, то проблема сведётся к режиму ECB (с определённо установленным IV), а не к полной дешифровке нескольких сообщений.


  1. domix32
    03.08.2023 14:58

    32-битное смещение, представленное в виде, где a – 32-битное слов, а b – определенное количество бит, на которое происходит смещение.

    Таки это смещение или поворот? Ибо обычно смещение обозначается << а у вас везде оно <<<


    1. RedBuilder81 Автор
      03.08.2023 14:58

      Данное обозначение было указано в RFC


      1. datacompboy
        03.08.2023 14:58

        То есть таки используется **циклическое смещение** aka поворот.