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"