Salsa20 и тесно связанный с ним ChaCha — это потоковые шифры , разработанные Дэниелом Дж. Бернстайном . Salsa20, оригинальный шифр, был разработан в 2005 году, а затем представлен Бернстайном в процесс криптографической проверки Европейского союза eSTREAM . ChaCha — это модификация Salsa20, опубликованная в 2008 году. Она использует новую функцию раунда, которая увеличивает диффузию и повышает производительность на некоторых архитектурах. [4]
Оба шифра построены на псевдослучайной функции , основанной на операциях add–rotate–XOR (ARX) — 32-битное сложение, побитовое сложение (XOR) и операции вращения . Основная функция сопоставляет 256-битный ключ , 64-битный nonce и 64-битный счетчик с 512-битным блоком ключевого потока (также существует версия Salsa с 128-битным ключом). Это дает Salsa20 и ChaCha необычное преимущество, заключающееся в том, что пользователь может эффективно искать любую позицию в ключевом потоке за постоянное время. Salsa20 предлагает скорость около 4–14 циклов на байт в программном обеспечении на современных процессорах x86 [5] и разумную производительность оборудования. Он не запатентован, и Бернстайн написал несколько реализаций в открытом доступе, оптимизированных для распространенных архитектур. [6]
Внутри шифр использует побитовое сложение ⊕ ( исключающее ИЛИ ), 32-битное сложение mod 2 32 ⊞ и операции вращения с постоянным расстоянием <<< на внутреннем состоянии шестнадцати 32-битных слов. Использование только операций add-rotate-xor позволяет избежать возможности атак по времени в программных реализациях. Внутреннее состояние состоит из шестнадцати 32-битных слов, организованных в матрицу 4×4.
Начальное состояние состоит из восьми ключевых слов ( ), два слова позиции потока ( ), два слова nonce (по сути, дополнительные биты позиции потока) ( ), и четыре фиксированных слова ( ):
Константные слова образуют "expand 32-byte k" в ASCII (т.е. 4 слова - "expa", "nd 3", "2-by" и "te k"). Это пример числа " ничего-в-рукаве " . Основная операция в Salsa20 - это четверть-раунд QR(a, b, c, d)
, который принимает входные данные из четырех слов и производит выходные данные из четырех слов:
б ^= (а + г) <<< 7;с ^= (б + а) <<< 9;г ^= (с + б) <<< 13;а ^= (d + c) <<< 18;
Нечетные раунды применяются QR(a, b, c, d)
к каждому из четырех столбцов в матрице 4×4, а четные раунды применяют его к каждой из четырех строк. Два последовательных раунда (столбцовый раунд и строковый раунд) вместе называются двойным раундом:
// Нечетный раундQR( 0, 4, 8, 12) // столбец 1QR( 5, 9, 13, 1) // столбец 2QR(10, 14, 2, 6) // столбец 3QR(15, 3, 7, 11) // столбец 4// Ровный раундQR( 0, 1, 2, 3) // строка 1QR( 5, 6, 7, 4) // строка 2QR(10, 11, 8, 9) // строка 3QR(15, 12, 13, 14) // строка 4
Реализация на языке C/C++ представлена ниже.
#include <stdint.h> #define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) #define QR(a, b, c, d)( \ b ^= ROTL(a + d, 7), \ c ^= ROTL(b + a, 9), \ d ^= ROTL(c + b,13), \ a ^= ROTL(d + c,18)) #define ROUNDS 20 void salsa20_block ( uint32_t out [ 16 ], uint32_t const in [ 16 ]) { int i ; uint32_t x [ 16 ]; for ( i = 0 ; i < 16 ; ++ i ) x [ i ] = in [ i ]; // 10 циклов × 2 цикла/цикл = 20 циклов for ( i = 0 ; i < ROUNDS ; i += 2 ) { // Нечетный цикл QR ( x [ 0 ], x [ 4 ], x [ 8 ], x [ 12 ]); // столбец 1 QR ( x [ 5 ], x [ 9 ], x [ 13 ], x [ 1 ]); // столбец 2 QR ( x [ 10 ], x [ 14 ], x [ 2 ], x [ 6 ]); // столбец 3 QR ( x [ 15 ], x [ 3 ], x [ 7 ], x [ 11 ]); // столбец 4 // Четный раунд QR ( x [ 0 ], x [ 1 ], x [ 2 ], x [ 3 ]); // строка 1 QR ( x [ 5 ], x [ 6 ], x [ 7 ], x [ 4 ]); // строка 2 QR ( x [ 10 ], x [ 11 ], x [ 8 ], x [ 9 ]); // строка 3 QR ( x [ 15 ], x [ 12 ], x [ 13 ], x [ 14 ]); // строка 4 } for ( i = 0 ; я < 16 ; ++ я ) вых [ я ] = х [ я ] + вх [ я ]; }
В последней строке смешанный массив добавляется слово за словом к исходному массиву для получения его 64-байтового блока потока ключей. Это важно, поскольку сами по себе раунды смешивания являются обратимыми . Другими словами, применение обратных операций даст исходную матрицу 4×4, включая ключ. Добавление смешанного массива к исходному делает невозможным восстановление входных данных. (Эта же техника широко используется в хэш-функциях от MD4 до SHA-2 .)
Salsa20 выполняет 20 раундов смешивания на своем входе. [1] Однако также были введены сокращенные варианты Salsa20/8 и Salsa20/12, использующие 8 и 12 раундов соответственно. Эти варианты были введены в дополнение к оригинальному Salsa20, а не для его замены, и работают лучше [примечание 1] в тестах eSTREAM, чем Salsa20, хотя и с соответственно меньшим запасом безопасности.
В 2008 году Бернстайн предложил вариант Salsa20 с 192-битными одноразовыми числами под названием XSalsa20. [7] [8] [9] XSalsa20 доказуемо безопасен , если Salsa20 безопасен, но больше подходит для приложений, где желательны более длинные одноразовые числа. XSalsa20 подает ключ и первые 128 бит одноразового числа в один блок Salsa20 (без последнего сложения, которое может быть либо опущено, либо вычтено после стандартного блока Salsa20) и использует 256 бит выходных данных в качестве ключа для стандартного Salsa20, используя последние 64 бита одноразового числа и позицию потока. В частности, используемые 256 бит выходных данных соответствуют несекретным частям входных данных: индексы 0, 5, 10, 15, 6, 7, 8 и 9.
Salsa20/12 был выбран в качестве проекта Фазы 3 для Профиля 1 (программное обеспечение) проектом eSTREAM , получив наивысший взвешенный балл голосования среди всех алгоритмов Профиля 1 в конце Фазы 2. [10] Ранее Salsa20 был выбран в качестве проекта Фазы 2 для Профиля 1 (программное обеспечение) и в качестве проекта Фазы 2 для Профиля 2 (аппаратное обеспечение) проектом eSTREAM, [11] но не был продвинут в Фазу 3 для Профиля 2, поскольку eSTREAM посчитал, что он, вероятно, не является хорошим кандидатом для аппаратных сред с крайне ограниченными ресурсами. [12]
Комитет eSTREAM рекомендует использовать Salsa20/12, 12-раундовый вариант, «сочетающий очень хорошую производительность с комфортным запасом безопасности». [13]
По состоянию на 2015 год [обновлять]не было опубликовано ни одного нападения на Salsa20/12 или на полную Salsa20/20; лучшая известная атака [3] нарушает 8 из 12 или 20 раундов.
В 2005 году Пол Кроули сообщил об атаке на Salsa20/5 с оценочной временной сложностью 2 165 и выиграл премию Бернстайна в размере 1000 долларов США за «самый интересный криптоанализ Salsa20». [14] Эта атака и все последующие атаки основаны на усеченном дифференциальном криптоанализе . В 2006 году Фишер, Мейер, Бербейн, Биасс и Робшоу сообщили об атаке на Salsa20/6 с оценочной временной сложностью 2 177 и атаке с использованием связанного ключа на Salsa20/7 с оценочной временной сложностью 2 217. [15 ]
В 2007 году Цуноо и др. объявили о криптоанализе Salsa20, который взламывает 8 из 20 раундов, чтобы восстановить 256-битный секретный ключ за 2 255 операций, используя 2 пары ключевых потоков по 11,37 . [16] Однако эта атака, похоже, не может конкурировать с атакой методом перебора.
В 2008 году Аумассон, Фишер, Хазаи, Мейер и Рехбергер сообщили о криптоаналитической атаке против Salsa20/7 с временной сложностью 2 151 , а также об атаке против Salsa20/8 с предполагаемой временной сложностью 2 251 . Эта атака использует новую концепцию вероятностных нейтральных ключевых битов для вероятностного обнаружения усеченного дифференциала. Атаку можно адаптировать для взлома Salsa20/7 с помощью 128-битного ключа. [3]
В 2012 году атака Аумассона и др. была улучшена Ши и др. против Salsa20/7 (128-битный ключ) до временной сложности 2 109 и Salsa20/8 (256-битный ключ) до 2 250. [17 ]
В 2013 году Муха и Пренель опубликовали доказательство [18] , что 15 раундов Salsa20 были 128-битными и защищены от дифференциального криптоанализа . (В частности, у него нет дифференциальной характеристики с более высокой вероятностью, чем 2−130 , поэтому дифференциальный криптоанализ был бы сложнее, чем исчерпание 128-битного ключа.)
В 2008 году Бернстайн опубликовал близкородственное семейство шифров ChaCha , целью которого является увеличение диффузии за раунд при достижении той же или немного лучшей производительности. [19] Статья Аумассона и др. также атакует ChaCha, добиваясь на один раунд меньше (для 256-битного ChaCha6 со сложностью 2 139 , ChaCha7 со сложностью 2 248 и 128-битного ChaCha6 в пределах 2 107 ), но утверждает, что атака не может взломать 128-битный ChaCha7. [3]
Как и в Salsa20, начальное состояние ChaCha включает 128-битную константу, 256-битный ключ, 64-битный счетчик и 64-битный одноразовый номер (в оригинальной версии; как описано ниже, версия ChaCha из RFC 7539 немного отличается), организованные в виде матрицы 4×4 из 32-битных слов. [19] Но ChaCha переупорядочивает некоторые слова в начальном состоянии:
Константа та же, что и у Salsa20 («расширить 32-байтовый k»). ChaCha заменяет четверть круга Salsa20 QR(a, b, c, d)
на:
а += б; д ^= а; д <<<= 16;с += д; б ^= с; б <<<= 12;а += б; д ^= а; д <<<= 8;с += д; б ^= с; б <<<= 7;
Обратите внимание, что эта версия обновляет каждое слово дважды, тогда как четверть круга Salsa20 обновляет каждое слово только один раз. Кроме того, четверть круга ChaCha рассеивает изменения быстрее. В среднем после изменения 1 входного бита четверть круга Salsa20 изменит 8 выходных битов, тогда как ChaCha изменит 12,5 выходных битов. [4]
Четверть раунда ChaCha имеет то же количество сложений, исключающих операций и битовых ротаций, что и четверть раунда Salsa20, но тот факт, что две ротации кратны 8, позволяет провести небольшую оптимизацию на некоторых архитектурах, включая x86. [20] Кроме того, форматирование входных данных было перестроено для поддержки эффективной оптимизации реализации SSE , обнаруженной для Salsa20. Вместо того, чтобы чередовать округления вниз по столбцам и по строкам, они выполняются вниз по столбцам и по диагоналям. [4] : 4 Подобно Salsa20, ChaCha размещает шестнадцать 32-битных слов в матрице 4×4. Если мы индексируем элементы матрицы от 0 до 15
тогда двойной раунд в ChaCha это:
// Нечетный раундQR(0, 4, 8, 12) // столбец 1QR(1, 5, 9, 13) // столбец 2QR(2, 6, 10, 14) // столбец 3QR(3, 7, 11, 15) // столбец 4// Ровный раундQR(0, 5, 10, 15) // диагональ 1 (главная диагональ)QR(1, 6, 11, 12) // диагональ 2QR(2, 7, 8, 13) // диагональ 3QR(3, 4, 9, 14) // диагональ 4
ChaCha20 использует 10 итераций двойного раунда. [21] Реализация на C/C++ представлена ниже.
#include <stdint.h> #define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) #define QR(a, b, c, d) ( \ a += b, d ^= a, d = ROTL(d, 16), \ c += d, b ^= c, b = ROTL(b, 12), \ a += b, d ^= a, d = ROTL(d, 8), \ c += d, b ^= c, b = ROTL(b, 7)) #define ROUNDS 20 void chacha_block ( uint32_t out [ 16 ], uint32_t const in [ 16 ]) { int i ; uint32_t x [ 16 ]; for ( i = 0 ; i < 16 ; ++ i ) x [ i ] = in [ i ]; // 10 циклов × 2 цикла/цикл = 20 циклов for ( i = 0 ; i < ROUNDS ; i += 2 ) { // Нечетный цикл QR ( x [ 0 ], x [ 4 ], x [ 8 ], x [ 12 ]); // столбец 1 QR ( x [ 1 ], x [ 5 ], x [ 9 ], x [ 13 ]); // столбец 2 QR ( x [ 2 ], x [ 6 ], x [ 10 ], x [ 14 ]); // столбец 3 QR ( x [ 3 ], x [ 7 ], x [ 11 ], x [ 15 ]); // столбец 4 // Четный раунд QR ( x [ 0 ], x [ 5 ], x [ 10 ], x [ 15 ]); // диагональ 1 (главная диагональ) QR ( x [ 1 ], x [ 6 ], x [ 11 ], x [ 12 ]); // диагональ 2 QR ( x [ 2 ], x [ 7 ], x [ 8 ], x [ 13 ]); // диагональ 3 QR ( x [ 3 ], x [ 4 ], x [ 9 ], x [ 14 ]); // диагональ 4 } for ( i = 0 ; я < 16 ; ++ я ) вых [ я ] = х [ я ] + вх [ я ]; }
ChaCha является основой хэш-функции BLAKE , финалиста конкурса хэш-функций NIST , и ее более быстрых последователей BLAKE2 и BLAKE3. Он также определяет вариант, использующий шестнадцать 64-битных слов (1024 бита состояния) с соответствующим образом скорректированными константами вращения.
Хотя это и не было объявлено Бернштейном, доказательство безопасности XSalsa20 напрямую распространяется на аналогичный шифр XChaCha . Используйте ключ и первые 128 бит одноразового номера (во входных словах с 12 по 15) для формирования входного блока ChaCha, затем выполните операцию блока (пропуская последнее сложение). Выходные слова 0–3 и 12–15 (те слова, которые соответствуют неключевым словам входных данных), затем сформируйте ключ, используемый для обычного ChaCha (с последними 64 битами одноразового номера и 64 битами счетчика блоков). [22]
В 2020 году Аумассон утверждал, что 8 раундов ChaCha (ChaCha8), вероятно, обеспечивают достаточную устойчивость к будущему криптоанализу для того же уровня безопасности , что дает ускорение в 2,5 раза. [23] Компромиссный ChaCha12 (основанный на рекомендации eSTREAM 12-раундового Salsa) [24] также находит некоторое применение. [25] Набор для бенчмаркинга eSTREAM включает ChaCha8 и ChaCha12. [19]
Google выбрал ChaCha20 вместе с кодом аутентификации сообщений Poly1305 Бернстайна в SPDY , который был задуман как замена TLS через TCP . [26] В процессе они предложили новую конструкцию аутентифицированного шифрования , объединяющую оба алгоритма, которая называется ChaCha20-Poly1305 . ChaCha20 и Poly1305 теперь используются в протоколе QUIC , который заменяет SPDY и используется HTTP/3 . [27] [28]
Вскоре после принятия Google TLS, алгоритмы ChaCha20 и Poly1305 также использовались для нового [email protected]
шифра в OpenSSH . [29] [30] Впоследствии это позволило OpenSSH избежать любой зависимости от OpenSSL с помощью опции времени компиляции. [31]
ChaCha20 также используется для arc4random
генератора случайных чисел в операционных системах FreeBSD [32] , OpenBSD [33] и NetBSD [ 34] вместо сломанного RC4 , а в DragonFly BSD [35] для подпрограммы CSPRNG ядра. [36] [37] Начиная с версии 4.8, ядро Linux использует алгоритм ChaCha20 для генерации данных для неблокируемого устройства /dev/urandom . [38] [39] [40] ChaCha8 используется для PRNG по умолчанию в Golang . [41] CSPRNG Rust использует ChaCha12. [24]
ChaCha20 обычно обеспечивает лучшую производительность, чем более распространенный алгоритм Advanced Encryption Standard (AES) в системах, где ЦП не поддерживает ускорение AES (например, набор инструкций AES для процессоров x86). В результате ChaCha20 иногда предпочтительнее AES в определенных случаях использования, связанных с мобильными устройствами , которые в основном используют процессоры на базе ARM . [42] [43] Специализированные аппаратные ускорители для ChaCha20 также менее сложны по сравнению с ускорителями AES. [44]
ChaCha20-Poly1305 (версия IETF; см. ниже) — эксклюзивный алгоритм, используемый системой WireGuard VPN, начиная с версии протокола 1. [45]
Ссылка на реализацию ChaCha20 была опубликована в RFC 7539. Реализация IETF изменила опубликованный алгоритм Бернштейна, изменив 64-битный одноразовый номер и 64-битный счетчик блоков на 96-битный одноразовый номер и 32-битный счетчик блоков. [46] Название не было изменено при изменении алгоритма, поскольку оно криптографически незначимо (оба формируют то, что криптограф распознал бы как 128-битный одноразовый номер), но изменение интерфейса может стать источником путаницы для разработчиков. Из-за уменьшенного счетчика блоков максимальная длина сообщения, которое может быть безопасно зашифровано вариантом IETF, составляет 2 32 блока по 64 байта (256 ГиБ ). Для приложений, где этого недостаточно, таких как шифрование файлов или дисков, RFC 7539 предлагает использовать исходный алгоритм с 64-битным одноразовым номером.
Использование ChaCha20 в IKE и IPsec стандартизировано в RFC 7634. Стандартизация его использования в TLS опубликована в RFC 7905.
В 2018 году RFC 7539 был заменен RFC 8439. RFC 8439 объединяет некоторые исправления и добавляет дополнительные соображения по безопасности. [47]
две из этих констант кратны 8; это позволяет выполнять ротацию инструкций на 1 в процессорах Core2 и более поздних процессорах Intel с помощью
инструкции
pshufb
Заменить алгоритм RC4 для генерации безопасных случайных чисел в ядре на Chacha20
Генератор случайных чисел на основе ChaCha для OpenBSD.
Устаревший API arc4random(3) из OpenBSD, переписанный с использованием ChaCha20 PRF, с состоянием каждого потока.
chacha_encrypt_bytes
random: заменить неблокирующий пул на CRNG на основе Chacha20
Отличия от обычного ChaCha. Разделение порядкового номера блока nonce было изменено с 64:64 на 96:32 [...] Состояние ChaCha20 инициализируется следующим образом: