openjdk.ruOpenJDK на русском

JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms

Криптографические алгоритмы ChaCha20 и Poly1305

ОтветственныйJamil Nimeh
ТипFeature
ОбластьSE
СтатусClosed / Delivered
Выпуск11
Компонентsecurity-libs / javax.crypto
Обсуждениеsecurity dash dev at openjdk dot java dot net
ТрудоёмкостьS
ДлительностьS
РецензентыBrian Goetz, Sean Mullan
ОдобренBrian Goetz
Создан2016/03/29 20:15
Обновлён2026/07/29 18:59
Задача8153028

Аннотация

Реализовать шифры ChaCha20 и ChaCha20-Poly1305 в соответствии со спецификацией RFC 7539. ChaCha20 — сравнительно новый потоковый шифр, который может заменить старый и небезопасный потоковый шифр RC4.

Цели

  • Предоставить реализации Cipher для ChaCha20 и ChaCha20-Poly1305. Эти алгоритмы будут реализованы в провайдере SunJCE.
  • Предоставить реализацию KeyGenerator, которая создаёт ключи, подходящие для алгоритмов ChaCha20 и ChaCha20-Poly1305.
  • Предоставить реализацию AlgorithmParameters для использования с алгоритмом ChaCha20-Poly1305.

Что не является целью

Поддержка наборов шифров TLS не входит в этот JEP. Поддержка этих шифров в TLS появится в последующем улучшении.

Мотивация

Единственный другой широко распространённый потоковый шифр, RC4, давно признан небезопасным. В отрасли сложился консенсус, что на данный момент ChaCha20-Poly1305 безопасен, и он довольно широко применяется в реализациях TLS, а также в других криптографических протоколах. JDK должен быть на одном уровне с другими криптографическими инструментариями и реализациями TLS.

Кроме того, TLS 1.3 допускает только наборы шифров на основе AEAD. Реализация алгоритма ChaCha20-Poly1305 — первый шаг к реализации различных наборов шифров, работающих в режиме AEAD, на случай, если в AES или GCM когда-либо будут найдены уязвимости.

Описание

Алгоритмы ChaCha20 и ChaCha20-Poly1305 будут реализовывать API javax.crypto.CipherSpi в провайдере SunJCE. Экземпляры шифров будут создаваться так же, как и других шифров, с помощью метода Cipher.getInstance(). Для обоих шифров допускаются два варианта строки преобразования. Предпочтителен вариант из одного имени: "ChaCha20" для ChaCha20 как простого потокового шифра без аутентификации и "ChaCha20-Poly1305" для ChaCha20 как AEAD-шифра с Poly1305 в качестве аутентификатора. Строки преобразования "ChaCha20/None/NoPadding" и "ChaCha20-Poly1305/None/NoPadding" тоже допустимы, но никакие другие значения режима или дополнения, кроме "None" и "NoPadding", приниматься не будут. Использование других значений режима или дополнения приведёт к выбросу исключения.

При инициализации шифр ChaCha20 будет принимать новую реализацию AlgorithmParameterSpecjavax.crypto.spec.ChaCha20ParameterSpec:

ChaCha20ParameterSpec(byte[] nonce, int counter);     // Constructor
public byte[] getNonce();     // Obtains a copy of the nonce value
public int getCounter();     // Obtains the initial counter value

Длина nonce должна составлять 96 бит (12 байт). Любая другая длина приведёт к выбросу исключения. Целочисленное значение счётчика может быть любым целым числом, даже отрицательным, чтобы можно было использовать весь диапазон беззнаковых 32-битных значений.

Если этот алгоритм инициализирован без ChaCha20ParameterSpec, шифр сам сгенерирует 12-байтовый nonce и установит значение счётчика равным 1. Байты счётчика можно получить, вызвав метод Cipher.getIV().

ChaCha20-Poly1305 можно инициализировать, передав экземпляр существующего класса javax.crypto.spec.IvParameterSpec, содержащий 12-байтовый nonce. Выбор IvParameterSpec вместо ChaCha20ParameterSpec позволяет перенести ChaCha20-Poly1305 в более ранние выпуски без каких-либо изменений API. Поскольку IvParameterSpec не накладывает требований на длину хранимых байтов, сам объект шифра будет проверять требование к длине в 12 байт при инициализации.

Как и ChaCha20, ChaCha20-Poly1305 можно инициализировать без IvParameterSpec. В этом случае nonce будет сгенерирован случайно, и его можно будет получить с помощью Cipher.getIV().

Объекты ключей, передаваемые в любой из методов init, должны иметь тип алгоритма «ChaCha20». Для этого будет создана новая реализация KeyGenerator. Как и существующие реализации KeyGenerator для других алгоритмов, таких как AES, RC2, ARCFOUR и семейство HmacSHA2, этот KeyGenerator нельзя инициализировать с помощью AlgorithmParameterSpec. Если вызываются формы метода init, позволяющие задать длину ключа, этот параметр должен быть равен 256, иначе будет выброшено InvalidParameterException.

Алгоритм ChaCha20 используется через существующий API Cipher, как и другие потоковые шифры. Простое шифрование за одну операцию можно записать так:

// Get a Cipher instance and set up the parameters
// Assume SecretKey "key", 12-byte nonce "nonceBytes" and plaintext "pText"
// are coming from outside this code snippet
Cipher mambo = Cipher.getInstance("ChaCha20");
ChaCha20ParameterSpec mamboSpec
    = new ChaCha20ParameterSpec(nonceBytes, 7);   // Use a starting counter value of "7"
// Encrypt our input
mambo.init(Cipher.ENCRYPT_MODE, key, mamboSpec);
byte[] encryptedResult = mambo.doFinal(pText);

Для ChaCha20 в режиме AEAD с аутентификатором Poly1305 требуется только nonce, поскольку RFC 7539 определяет, что начальное значение счётчика для данных равно 1. Чтобы эту реализацию Cipher можно было переносить в более ранние выпуски и чтобы упростить её использование в нашем провайдере JSSE, nonce будет передаваться через javax.crypto.spec.IvParameterSpec.

В режиме AEAD размер выходных данных может отличаться от размера входных из-за добавления тега аутентификации (при шифровании) или из-за чтения и проверки тега (при расшифровке). Если выходной буфер нужно выделить до шифрования или расшифровки, следует использовать метод getOutputSize(). Пример шифрования за одну операцию:

// Get a Cipher instance and set up the parameters
// Assume SecretKey "key", 12-byte nonce "nonceBytes" and plaintext "pText"
// are coming from outside this code snippet
Cipher mambo = Cipher.getInstance("ChaCha20-Poly1305");
AlgorithmParameterSpec mamboSpec = new IvParameterSpec(nonceBytes);

// Encrypt our input
mambo.init(Cipher.ENCRYPT_MODE, key, mamboSpec);
byte[] encryptedResult = new byte[mambo.getOutputSize(pText.length)];
mambo.doFinal(pText, 0, pText.length, encryptedResult);

Важное требование к обоим шифрам, ChaCha20 и ChaCha20-Poly1305: после вызова doFinal() необходимо вызвать init() с nonce, отличным от текущего. Это похоже на требование к шифрованию в AES-GCM, но для этих двух шифров повторная инициализация обязательна после операций как шифрования, так и расшифровки. Последующие вызовы Cipher.update(), Cipher.updateAAD() или Cipher.doFinal() после предыдущего doFinal() без вызова init() между ними приведут к выбросу IllegalStateException.

Тестирование

Тестирование будет охватывать следующие области:

  • Проверить, что шифры ChaCha20 и ChaCha20-Poly1305 проходят все тесты с известными ответами
  • Проверить, что генератор ключей ChaCha20 принимает правильные формы инициализации и генерирует ключи нужного размера
  • Проверить, что шифры соблюдают ограничения при инициализации (запрет повторного использования nonce и т. д.)
  • Проверить, что шифры выполняют требования к повторной инициализации между завершёнными операциями шифрования и расшифровки
  • Проверить, что наша реализация совместима хотя бы с одной другой реализацией
  • Проверить, что реализация AlgorithmParameters для ChaCha20-Poly1305 принимает данные nonce в правильном формате.

Зависимости

Единственная существенная зависимость — API математических операций с постоянным временем выполнения. Они будут предоставлены в рамках JEP 324.