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

JEP 497: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm

Квантово-устойчивый алгоритм цифровой подписи на основе модульных решёток

ОтветственныйWeijun Wang
ТипFeature
ОбластьSE
СтатусClosed / Delivered
Выпуск24
Компонентsecurity-libs / java.security
Обсуждениеsecurity dash dev at openjdk dot org
ТрудоёмкостьM
ДлительностьM
РецензентыSean Mullan
ОдобренAlan Bateman, Sean Mullan
Создан2024/08/26 18:34
Обновлён2025/11/03 22:24
Задача8339010

Аннотация

Повысить безопасность Java-приложений за счёт реализации квантово-устойчивого алгоритма цифровой подписи на основе модульных решёток (Module-Lattice-Based Digital Signature Algorithm, ML-DSA). Цифровые подписи используются для обнаружения несанкционированных изменений данных и для подтверждения подлинности подписавших. ML-DSA спроектирован так, чтобы оставаться стойким к будущим атакам с использованием квантовых вычислений. Он стандартизован Национальным институтом стандартов и технологий США (NIST) в FIPS 204.

Цели

  • Предоставить реализации ML-DSA для API KeyPairGenerator, Signature и KeyFactory с поддержкой наборов параметров ML-DSA-44, ML-DSA-65 и ML-DSA-87, стандартизованных в FIPS 204.

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

  • Реализация алгоритма Dilithium, на основе которого создан ML-DSA, не является целью. Эти два алгоритма несовместимы между собой.

  • Добавление поддержки ML-DSA в те компоненты платформы Java, для которых ещё нет необходимых стандартов, не является целью. В частности, это относится к подписи JAR-файлов, а также к реализации протокола Transport Layer Security (TLS) в пакете javax.net.ssl. Мы добавим такую поддержку, когда стандарты появятся.

  • Поддержка Pre-Hash ML-DSA (FIPS 204 §5.4) и возможность задавать строки контекста, специфичные для приложения (FIPS 204 §5.2), не являются целью. Мы можем реализовать эти возможности в одном из будущих выпусков.

Мотивация

Область квантовых вычислений уже много лет стабильно развивается. Будущий крупномасштабный квантовый компьютер сможет с помощью алгоритма Шора, который способен раскладывать целые числа на множители и решать задачу дискретного логарифмирования, нарушить безопасность широко используемых алгоритмов с открытым ключом, включая Rivest-Shamir-Adleman (RSA) и Diffie-Hellman. Платформа Java использует такие алгоритмы, в частности, для цифровой подписи JAR-файлов и для установки защищённых сетевых соединений по протоколу Transport Layer Security (TLS). Атаку, на которую обычному суперкомпьютеру могли бы потребоваться от тысяч до миллионов лет, квантовый компьютер с алгоритмом Шора мог бы выполнить всего за несколько часов. В ответ на эту угрозу криптографы разработали квантово-устойчивые криптографические алгоритмы, которые невозможно взломать алгоритмом Шора.

Для квантово-устойчивой подписи данных и подтверждения подлинности NIST стандартизовал алгоритм цифровой подписи на основе модульных решёток (ML-DSA) в FIPS 204. В США государственные компьютерные системы, обрабатывающие конфиденциальную информацию, должны в течение следующего десятилетия перейти на использование ML-DSA. Поэтому платформе Java крайне важно предоставить реализацию этого алгоритма.

Описание

Мы предоставим реализации ML-DSA для API KeyPairGenerator — для генерации пар ключей ML-DSA, для API Signature — для создания и проверки подписей ML-DSA и для API KeyFactory — для преобразования ключей ML-DSA в их кодированное представление и обратно.

В Java Security Standard Algorithm Names Specification мы определим новое стандартное имя семейства алгоритмов "ML-DSA" для API KeyPairGenerator, Signature и KeyFactory.

FIPS 204 определяет три набора параметров для ML-DSA. В порядке возрастания криптостойкости и снижения производительности они называются "ML-DSA-44", "ML-DSA-65" и "ML-DSA-87". Эти имена наборов параметров также будут определены как стандартные имена алгоритмов для API KeyPairGenerator, Signature и KeyFactory, а кроме того, будут представлены новыми константами NamedParameterSpec: ML_DSA_44, ML_DSA_65 и ML_DSA_87.

Генерация пар ключей ML-DSA

Сгенерировать пару ключей ML-DSA можно одним из трёх способов:

  • Создать экземпляр KeyPairGenerator с именем семейства и инициализировать его именем набора параметров:

    KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA");
    g.initialize(NamedParameterSpec.ML_DSA_44);
    KeyPair kp = g.generateKeyPair(); // an ML-DSA-44 key pair
  • Если не инициализировать KeyPairGenerator набором параметров, реализация по умолчанию использует ML-DSA-65:

    KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA");
    KeyPair kp = g.generateKeyPair(); // an ML-DSA-65 key pair
  • Напрямую создать экземпляр KeyPairGenerator с именем набора параметров:

    KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA-87");
    KeyPair kp = g.generateKeyPair(); // an ML-DSA-87 key pair

API KeyPairGenerator позволяет указать при инициализации целочисленный размер ключа, но для пар ключей ML-DSA это не поддерживается и приведёт к выбросу InvalidParameterException.

Команда keytool будет поддерживать генерацию пар ключей и сертификатов ML-DSA. Например:

$ keytool -keystore ks -storepass changeit -genkeypair -alias mldsa \
          -keyalg ML-DSA -groupname ML-DSA-65 -dname CN=ML-DSA

Можно также указать имя набора параметров, ML-DSA-65, напрямую через параметр -keyalg:

$ keytool -keystore ks -storepass changeit -genkeypair -alias mldsa \
          -keyalg ML-DSA-65 -dname CN=ML-DSA2

Подпись ключами ML-DSA

Для создания и проверки подписей ML-DSA можно использовать реализацию Signature для ML-DSA.

Например, чтобы подписать сообщение закрытым ключом:

byte[] msg = ...;
Signature ss = Signature.getInstance("ML-DSA");
ss.initSign(privateKey);
ss.update(msg);
byte[] sig = ss.sign();

Чтобы проверить подпись открытым ключом:

byte[] msg = ...;
byte[] sig = ...;
Signature sv = Signature.getInstance("ML-DSA");
sv.initVerify(publicKey);
sv.update(msg);
boolean verified = sv.verify(sig);

Если объект Signature создан с именем семейства, он принимает ключи ML-DSA этого семейства с любым набором параметров. Если он создан с именем набора параметров, он принимает только ключи ML-DSA с этим набором параметров; в противном случае методы initSign и initVerify выбрасывают InvalidKeyException.

Кодирование и декодирование ключей ML-DSA

С помощью реализации KeyFactory для ML-DSA можно преобразовать закрытый ключ ML-DSA в кодировку PKCS #8 и обратно, а открытый ключ ML-DSA — в кодировку X.509 и обратно.

Например, чтобы преобразовать закрытый ключ ML-DSA в кодировку PKCS #8 и обратно:

KeyFactory f = KeyFactory.getInstance("ML-DSA");
PKCS8EncodedKeySpec p8spec = f.getKeySpec(kp.getPrivate(),
                                          PKCS8EncodedKeySpec.class);
PrivateKey sk2 = f.generatePrivate(p8spec);

Аналогично, чтобы преобразовать открытый ключ ML-DSA в кодировку X.509 и обратно:

X509EncodedKeySpec x509spec = f.getKeySpec(kp.getPublic(),
                                           X509EncodedKeySpec.class);
PublicKey pk2 = f.generatePublic(x509spec);

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

Метод getAlgorithm объекта Key, созданного реализацией KeyPairGenerator или KeyFactory для ML-DSA, всегда возвращает имя семейства "ML-DSA", независимо от того, был ли KeyPairGenerator или KeyFactory создан с именем семейства "ML-DSA" или с одним из имён наборов параметров. Метод getParams ключа ML-DSA возвращает объект NamedParameterSpec, соответствующий имени набора параметров ключа.

Если объект KeyFactory создан с именем семейства, он кодирует и декодирует ключи ML-DSA этого семейства с любым набором параметров. Если он создан с именем набора параметров, он кодирует и декодирует только ключи ML-DSA с этим набором параметров; в противном случае метод translateKey выбрасывает InvalidKeyException, а методы generatePrivate, generatePublic и getKeySpec выбрасывают InvalidKeySpecException.

Кодировка, которую использует KeyFactory для ML-DSA, определена в черновике IETF RFC. Мы будем отслеживать изменения этого черновика до его публикации.

Альтернативы

  • Проект Open Quantum Safe предоставляет JNI-обёртку для своей библиотеки liboqs на C, в которой реализован набор квантово-устойчивых алгоритмов, включая Dilithium и ML-DSA. Если Open Quantum Safe достигнет своей цели и станет основной реализацией квантово-устойчивой криптографии для крупных проектов, таких как OpenSSL, BoringSSL, OpenSSH и Mozilla, то благодаря широкому тестированию и использованию она значительно выиграет в производительности и надёжности.

    По сравнению с нативной реализацией, реализация ML-DSA на Java даёт ключевое преимущество: она встроена непосредственно в JDK. Поэтому она сразу доступна на всех платформах, на которые JDK уже портирован.

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

  • Модульные тесты подтвердят, что реализации соответствуют спецификациям API KeyGenerator, Signature и KeyFactory, в том числе в граничных случаях, таких как недопустимые входные параметры, граничные значения и неподдерживаемые операции.

  • Тесты с известными ответами (Known Answer Tests, KAT) охватят как корректные криптографические операции (позитивные случаи), так и некорректные операции или известные уязвимости (негативные случаи), что обеспечит всестороннюю проверку. В их число войдут, в частности:

  • Тесты совместимости с реализациями других поставщиков, включая, помимо прочего, liboqs, подтвердят, что наша реализация ML-DSA корректно работает с другими.