Unexport the Kyber implementation Kyber was the prestandard version of ML-KEM. Callers should be using ML-KEM now. For now, keep the implementation behind an internal header for libssl, but we expect to remove that soon too. Update-Note: <openssl/experimental/kyber.h> is gone. Use <openssl/mlkem.h> instead. Bug: 438787615 Change-Id: I02919e5d627dcbe863e70e433c79e360a556d462 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/81287 Reviewed-by: Lily Chen <chlily@google.com> Auto-Submit: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/build.json b/build.json index 4c56391..5e7c0f2 100644 --- a/build.json +++ b/build.json
@@ -449,7 +449,6 @@ "include/openssl/evp.h", "include/openssl/evp_errors.h", "include/openssl/ex_data.h", - "include/openssl/experimental/kyber.h", "include/openssl/hkdf.h", "include/openssl/hmac.h", "include/openssl/hpke.h",
diff --git a/crypto/kyber/internal.h b/crypto/kyber/internal.h index 59c80f7..89475a9 100644 --- a/crypto/kyber/internal.h +++ b/crypto/kyber/internal.h
@@ -16,13 +16,122 @@ #define OPENSSL_HEADER_CRYPTO_KYBER_INTERNAL_H #include <openssl/base.h> -#include <openssl/experimental/kyber.h> #if defined(__cplusplus) extern "C" { #endif +// Kyber is the pre-standard version of ML-KEM. This was once exported as public +// API, but is now internal and only used by libssl. It will be removed entirely +// in the future. +// +// This implements the round-3 specification of Kyber, defined at +// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf + +// KYBER_public_key contains a Kyber768 public key. The contents of this +// object should never leave the address space since the format is unstable. +struct KYBER_public_key { + union { + uint8_t bytes[512 * (3 + 9) + 32 + 32]; + uint16_t alignment; + } opaque; +}; + +// KYBER_private_key contains a Kyber768 private key. The contents of this +// object should never leave the address space since the format is unstable. +struct KYBER_private_key { + union { + uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; + uint16_t alignment; + } opaque; +}; + +// KYBER_PUBLIC_KEY_BYTES is the number of bytes in an encoded Kyber768 public +// key. +#define KYBER_PUBLIC_KEY_BYTES 1184 + +// KYBER_SHARED_SECRET_BYTES is the number of bytes in the Kyber768 shared +// secret. Although the round-3 specification has a variable-length output, the +// final ML-KEM construction is expected to use a fixed 32-byte output. To +// simplify the future transition, we apply the same restriction. +#define KYBER_SHARED_SECRET_BYTES 32 + +// KYBER_generate_key generates a random public/private key pair, writes the +// encoded public key to |out_encoded_public_key| and sets |out_private_key| to +// the private key. +OPENSSL_EXPORT void KYBER_generate_key( + uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], + struct KYBER_private_key *out_private_key); + +// KYBER_public_from_private sets |*out_public_key| to the public key that +// corresponds to |private_key|. (This is faster than parsing the output of +// |KYBER_generate_key| if, for some reason, you need to encapsulate to a key +// that was just generated.) +OPENSSL_EXPORT void KYBER_public_from_private( + struct KYBER_public_key *out_public_key, + const struct KYBER_private_key *private_key); + +// KYBER_CIPHERTEXT_BYTES is number of bytes in the Kyber768 ciphertext. +#define KYBER_CIPHERTEXT_BYTES 1088 + +// KYBER_encap encrypts a random shared secret for |public_key|, writes the +// ciphertext to |out_ciphertext|, and writes the random shared secret to +// |out_shared_secret|. +OPENSSL_EXPORT void KYBER_encap( + uint8_t out_ciphertext[KYBER_CIPHERTEXT_BYTES], + uint8_t out_shared_secret[KYBER_SHARED_SECRET_BYTES], + const struct KYBER_public_key *public_key); + +// KYBER_decap decrypts a shared secret from |ciphertext| using |private_key| +// and writes it to |out_shared_secret|. If |ciphertext| is invalid, +// |out_shared_secret| is filled with a key that will always be the same for the +// same |ciphertext| and |private_key|, but which appears to be random unless +// one has access to |private_key|. These alternatives occur in constant time. +// Any subsequent symmetric encryption using |out_shared_secret| must use an +// authenticated encryption scheme in order to discover the decapsulation +// failure. +OPENSSL_EXPORT void KYBER_decap( + uint8_t out_shared_secret[KYBER_SHARED_SECRET_BYTES], + const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES], + const struct KYBER_private_key *private_key); + + +// Serialisation of keys. + +// KYBER_marshal_public_key serializes |public_key| to |out| in the standard +// format for Kyber public keys. It returns one on success or zero on allocation +// error. +OPENSSL_EXPORT int KYBER_marshal_public_key( + CBB *out, const struct KYBER_public_key *public_key); + +// KYBER_parse_public_key parses a public key, in the format generated by +// |KYBER_marshal_public_key|, from |in| and writes the result to +// |out_public_key|. It returns one on success or zero on parse error or if +// there are trailing bytes in |in|. +OPENSSL_EXPORT int KYBER_parse_public_key( + struct KYBER_public_key *out_public_key, CBS *in); + +// KYBER_marshal_private_key serializes |private_key| to |out| in the standard +// format for Kyber private keys. It returns one on success or zero on +// allocation error. +OPENSSL_EXPORT int KYBER_marshal_private_key( + CBB *out, const struct KYBER_private_key *private_key); + +// KYBER_PRIVATE_KEY_BYTES is the length of the data produced by +// |KYBER_marshal_private_key|. +#define KYBER_PRIVATE_KEY_BYTES 2400 + +// KYBER_parse_private_key parses a private key, in the format generated by +// |KYBER_marshal_private_key|, from |in| and writes the result to +// |out_private_key|. It returns one on success or zero on parse error or if +// there are trailing bytes in |in|. +OPENSSL_EXPORT int KYBER_parse_private_key( + struct KYBER_private_key *out_private_key, CBS *in); + + +// Internal symbols. + // KYBER_ENCAP_ENTROPY is the number of bytes of uniformly random entropy // necessary to encapsulate a secret. The entropy will be leaked to the // decapsulating party.
diff --git a/crypto/kyber/kyber.cc b/crypto/kyber/kyber.cc index 15eb65f..bc67ae1 100644 --- a/crypto/kyber/kyber.cc +++ b/crypto/kyber/kyber.cc
@@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#define OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER -#include <openssl/experimental/kyber.h> - #include <assert.h> #include <stdlib.h>
diff --git a/crypto/kyber/kyber_test.cc b/crypto/kyber/kyber_test.cc index e5a772e..35f2d7a 100644 --- a/crypto/kyber/kyber_test.cc +++ b/crypto/kyber/kyber_test.cc
@@ -20,8 +20,6 @@ #include <openssl/bytestring.h> #include <openssl/ctrdrbg.h> -#define OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER -#include <openssl/experimental/kyber.h> #include "../fipsmodule/keccak/internal.h" #include "../test/file_test.h"
diff --git a/gen/sources.bzl b/gen/sources.bzl index ef789da..5d9520c 100644 --- a/gen/sources.bzl +++ b/gen/sources.bzl
@@ -550,7 +550,6 @@ "include/openssl/evp.h", "include/openssl/evp_errors.h", "include/openssl/ex_data.h", - "include/openssl/experimental/kyber.h", "include/openssl/hkdf.h", "include/openssl/hmac.h", "include/openssl/hpke.h",
diff --git a/gen/sources.cmake b/gen/sources.cmake index ec1f827..00ac47e 100644 --- a/gen/sources.cmake +++ b/gen/sources.cmake
@@ -566,7 +566,6 @@ include/openssl/evp.h include/openssl/evp_errors.h include/openssl/ex_data.h - include/openssl/experimental/kyber.h include/openssl/hkdf.h include/openssl/hmac.h include/openssl/hpke.h
diff --git a/gen/sources.gni b/gen/sources.gni index 9f4404d..3c5c6a4 100644 --- a/gen/sources.gni +++ b/gen/sources.gni
@@ -550,7 +550,6 @@ "include/openssl/evp.h", "include/openssl/evp_errors.h", "include/openssl/ex_data.h", - "include/openssl/experimental/kyber.h", "include/openssl/hkdf.h", "include/openssl/hmac.h", "include/openssl/hpke.h",
diff --git a/gen/sources.json b/gen/sources.json index d074bcb..5d74df8 100644 --- a/gen/sources.json +++ b/gen/sources.json
@@ -533,7 +533,6 @@ "include/openssl/evp.h", "include/openssl/evp_errors.h", "include/openssl/ex_data.h", - "include/openssl/experimental/kyber.h", "include/openssl/hkdf.h", "include/openssl/hmac.h", "include/openssl/hpke.h",
diff --git a/gen/sources.mk b/gen/sources.mk index baa2d06..85683b0 100644 --- a/gen/sources.mk +++ b/gen/sources.mk
@@ -543,7 +543,6 @@ include/openssl/evp.h \ include/openssl/evp_errors.h \ include/openssl/ex_data.h \ - include/openssl/experimental/kyber.h \ include/openssl/hkdf.h \ include/openssl/hmac.h \ include/openssl/hpke.h \
diff --git a/include/openssl/experimental/kyber.h b/include/openssl/experimental/kyber.h deleted file mode 100644 index 14ff973..0000000 --- a/include/openssl/experimental/kyber.h +++ /dev/null
@@ -1,146 +0,0 @@ -// Copyright 2023 The BoringSSL Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef OPENSSL_HEADER_KYBER_H -#define OPENSSL_HEADER_KYBER_H - -#include <openssl/base.h> // IWYU pragma: export - -#if defined(__cplusplus) -extern "C" { -#endif - - -#if defined(OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER) -// This header implements experimental, draft versions of not-yet-standardized -// primitives. When the standard is complete, these functions will be removed -// and replaced with the final, incompatible standard version. They are -// available now for short-lived experiments, but must not be deployed anywhere -// durable, such as a long-lived key store. To use these functions define -// OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER - -// Kyber768. -// -// This implements the round-3 specification of Kyber, defined at -// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf - - -// KYBER_public_key contains a Kyber768 public key. The contents of this -// object should never leave the address space since the format is unstable. -struct KYBER_public_key { - union { - uint8_t bytes[512 * (3 + 9) + 32 + 32]; - uint16_t alignment; - } opaque; -}; - -// KYBER_private_key contains a Kyber768 private key. The contents of this -// object should never leave the address space since the format is unstable. -struct KYBER_private_key { - union { - uint8_t bytes[512 * (3 + 3 + 9) + 32 + 32 + 32]; - uint16_t alignment; - } opaque; -}; - -// KYBER_PUBLIC_KEY_BYTES is the number of bytes in an encoded Kyber768 public -// key. -#define KYBER_PUBLIC_KEY_BYTES 1184 - -// KYBER_SHARED_SECRET_BYTES is the number of bytes in the Kyber768 shared -// secret. Although the round-3 specification has a variable-length output, the -// final ML-KEM construction is expected to use a fixed 32-byte output. To -// simplify the future transition, we apply the same restriction. -#define KYBER_SHARED_SECRET_BYTES 32 - -// KYBER_generate_key generates a random public/private key pair, writes the -// encoded public key to |out_encoded_public_key| and sets |out_private_key| to -// the private key. -OPENSSL_EXPORT void KYBER_generate_key( - uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], - struct KYBER_private_key *out_private_key); - -// KYBER_public_from_private sets |*out_public_key| to the public key that -// corresponds to |private_key|. (This is faster than parsing the output of -// |KYBER_generate_key| if, for some reason, you need to encapsulate to a key -// that was just generated.) -OPENSSL_EXPORT void KYBER_public_from_private( - struct KYBER_public_key *out_public_key, - const struct KYBER_private_key *private_key); - -// KYBER_CIPHERTEXT_BYTES is number of bytes in the Kyber768 ciphertext. -#define KYBER_CIPHERTEXT_BYTES 1088 - -// KYBER_encap encrypts a random shared secret for |public_key|, writes the -// ciphertext to |out_ciphertext|, and writes the random shared secret to -// |out_shared_secret|. -OPENSSL_EXPORT void KYBER_encap( - uint8_t out_ciphertext[KYBER_CIPHERTEXT_BYTES], - uint8_t out_shared_secret[KYBER_SHARED_SECRET_BYTES], - const struct KYBER_public_key *public_key); - -// KYBER_decap decrypts a shared secret from |ciphertext| using |private_key| -// and writes it to |out_shared_secret|. If |ciphertext| is invalid, -// |out_shared_secret| is filled with a key that will always be the same for the -// same |ciphertext| and |private_key|, but which appears to be random unless -// one has access to |private_key|. These alternatives occur in constant time. -// Any subsequent symmetric encryption using |out_shared_secret| must use an -// authenticated encryption scheme in order to discover the decapsulation -// failure. -OPENSSL_EXPORT void KYBER_decap( - uint8_t out_shared_secret[KYBER_SHARED_SECRET_BYTES], - const uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES], - const struct KYBER_private_key *private_key); - - -// Serialisation of keys. - -// KYBER_marshal_public_key serializes |public_key| to |out| in the standard -// format for Kyber public keys. It returns one on success or zero on allocation -// error. -OPENSSL_EXPORT int KYBER_marshal_public_key( - CBB *out, const struct KYBER_public_key *public_key); - -// KYBER_parse_public_key parses a public key, in the format generated by -// |KYBER_marshal_public_key|, from |in| and writes the result to -// |out_public_key|. It returns one on success or zero on parse error or if -// there are trailing bytes in |in|. -OPENSSL_EXPORT int KYBER_parse_public_key( - struct KYBER_public_key *out_public_key, CBS *in); - -// KYBER_marshal_private_key serializes |private_key| to |out| in the standard -// format for Kyber private keys. It returns one on success or zero on -// allocation error. -OPENSSL_EXPORT int KYBER_marshal_private_key( - CBB *out, const struct KYBER_private_key *private_key); - -// KYBER_PRIVATE_KEY_BYTES is the length of the data produced by -// |KYBER_marshal_private_key|. -#define KYBER_PRIVATE_KEY_BYTES 2400 - -// KYBER_parse_private_key parses a private key, in the format generated by -// |KYBER_marshal_private_key|, from |in| and writes the result to -// |out_private_key|. It returns one on success or zero on parse error or if -// there are trailing bytes in |in|. -OPENSSL_EXPORT int KYBER_parse_private_key( - struct KYBER_private_key *out_private_key, CBS *in); - -#endif // OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER - - -#if defined(__cplusplus) -} // extern C -#endif - -#endif // OPENSSL_HEADER_KYBER_H
diff --git a/ssl/ssl_key_share.cc b/ssl/ssl_key_share.cc index c2c01e6..411a6ab 100644 --- a/ssl/ssl_key_share.cc +++ b/ssl/ssl_key_share.cc
@@ -24,8 +24,6 @@ #include <openssl/curve25519.h> #include <openssl/ec.h> #include <openssl/err.h> -#define OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER -#include <openssl/experimental/kyber.h> #include <openssl/hrss.h> #include <openssl/mem.h> #include <openssl/mlkem.h> @@ -34,6 +32,7 @@ #include <openssl/span.h> #include "../crypto/internal.h" +#include "../crypto/kyber/internal.h" #include "internal.h" BSSL_NAMESPACE_BEGIN
diff --git a/tool/speed.cc b/tool/speed.cc index b9bca8e..a6e75e0 100644 --- a/tool/speed.cc +++ b/tool/speed.cc
@@ -38,8 +38,6 @@ #include <openssl/ecdsa.h> #include <openssl/err.h> #include <openssl/evp.h> -#define OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER -#include <openssl/experimental/kyber.h> #include <openssl/hrss.h> #include <openssl/mem.h> #include <openssl/mldsa.h> @@ -1079,55 +1077,6 @@ return true; } -static bool SpeedKyber(const std::string &selected) { - if (!selected.empty() && selected != "Kyber") { - return true; - } - - TimeResults results; - - uint8_t ciphertext[KYBER_CIPHERTEXT_BYTES]; - // This ciphertext is nonsense, but Kyber decap is constant-time so, for the - // purposes of timing, it's fine. - memset(ciphertext, 42, sizeof(ciphertext)); - if (!TimeFunctionParallel(&results, [&]() -> bool { - KYBER_private_key priv; - uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; - KYBER_generate_key(encoded_public_key, &priv); - uint8_t shared_secret[KYBER_SHARED_SECRET_BYTES]; - KYBER_decap(shared_secret, ciphertext, &priv); - return true; - })) { - fprintf(stderr, "Failed to time KYBER_generate_key + KYBER_decap.\n"); - return false; - } - - results.Print("Kyber generate + decap"); - - KYBER_private_key priv; - uint8_t encoded_public_key[KYBER_PUBLIC_KEY_BYTES]; - KYBER_generate_key(encoded_public_key, &priv); - KYBER_public_key pub; - if (!TimeFunctionParallel(&results, [&]() -> bool { - CBS encoded_public_key_cbs; - CBS_init(&encoded_public_key_cbs, encoded_public_key, - sizeof(encoded_public_key)); - if (!KYBER_parse_public_key(&pub, &encoded_public_key_cbs)) { - return false; - } - uint8_t shared_secret[KYBER_SHARED_SECRET_BYTES]; - KYBER_encap(ciphertext, shared_secret, &pub); - return true; - })) { - fprintf(stderr, "Failed to time KYBER_encap.\n"); - return false; - } - - results.Print("Kyber parse + encap"); - - return true; -} - static bool SpeedMLDSA(const std::string &selected) { if (!selected.empty() && selected != "ML-DSA") { return true; @@ -1857,7 +1806,6 @@ !SpeedScrypt(selected) || // !SpeedRSAKeyGen(selected) || // !SpeedHRSS(selected) || // - !SpeedKyber(selected) || // !SpeedMLDSA(selected) || // !SpeedMLKEM(selected) || // !SpeedMLKEM1024(selected) || //
diff --git a/util/doc.config b/util/doc.config index 9637c98..4903ee1 100644 --- a/util/doc.config +++ b/util/doc.config
@@ -61,11 +61,6 @@ "include/openssl/x509.h" ] },{ - "Name": "Experimental primitives. Will be removed and replaced when standardized!", - "Headers": [ - "include/openssl/experimental/kyber.h" - ] - },{ "Name": "SSL implementation", "Headers": [ "include/openssl/ssl.h"