Adding a C implementation of Kyber.

Passes test vectors, and should be constant time, but is currently
not optimized and neither the API nor the standard is stable.

Change-Id: I89b90877e023a43ee7238e11b86065444ab3bdec
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/57845
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_key_share.cc b/ssl/ssl_key_share.cc
index a81b917..5741c6b 100644
--- a/ssl/ssl_key_share.cc
+++ b/ssl/ssl_key_share.cc
@@ -24,6 +24,7 @@
 #include <openssl/curve25519.h>
 #include <openssl/ec.h>
 #include <openssl/err.h>
+#include <openssl/kyber.h>
 #include <openssl/hrss.h>
 #include <openssl/mem.h>
 #include <openssl/nid.h>
@@ -293,20 +294,86 @@
   uint16_t GroupID() const override { return SSL_CURVE_X25519KYBER768; }
 
   bool Generate(CBB *out) override {
-    // There is no implementation on Kyber in BoringSSL. BoringSSL must be
-    // patched for this KEM to be workable. It is not enabled by default.
-    return false;
+    uint8_t x25519_public_key[32];
+    X25519_keypair(x25519_public_key, x25519_private_key_);
+
+    uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES];
+    KYBER_generate_key(kyber_public_key, &kyber_private_key_);
+
+    if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
+        !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) {
+      return false;
+    }
+
+    return true;
   }
 
   bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
              uint8_t *out_alert, Span<const uint8_t> peer_key) override {
-    return false;
+    Array<uint8_t> secret;
+    if (!secret.Init(32 + 32)) {
+      return false;
+    }
+
+    uint8_t x25519_public_key[32];
+    X25519_keypair(x25519_public_key, x25519_private_key_);
+    KYBER_public_key peer_kyber_pub;
+    CBS peer_key_cbs;
+    CBS peer_x25519_cbs;
+    CBS peer_kyber_cbs;
+    CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size());
+    if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) ||
+        !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs,
+                       KYBER_PUBLIC_KEY_BYTES) ||
+        CBS_len(&peer_key_cbs) != 0 ||
+        !X25519(secret.data(), x25519_private_key_,
+                CBS_data(&peer_x25519_cbs)) ||
+        !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) {
+      *out_alert = SSL_AD_DECODE_ERROR;
+      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
+      return false;
+    }
+
+    uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES];
+    KYBER_encap(kyber_ciphertext, secret.data() + 32, secret.size() - 32,
+                &peer_kyber_pub);
+
+    if (!CBB_add_bytes(out_ciphertext, x25519_public_key,
+                       sizeof(x25519_public_key)) ||
+        !CBB_add_bytes(out_ciphertext, kyber_ciphertext,
+                       sizeof(kyber_ciphertext))) {
+      return false;
+    }
+
+    *out_secret = std::move(secret);
+    return true;
   }
 
   bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
              Span<const uint8_t> ciphertext) override {
-    return false;
+    *out_alert = SSL_AD_INTERNAL_ERROR;
+
+    Array<uint8_t> secret;
+    if (!secret.Init(32 + 32)) {
+      return false;
+    }
+
+    if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES ||
+        !X25519(secret.data(), x25519_private_key_, ciphertext.data())) {
+      *out_alert = SSL_AD_DECODE_ERROR;
+      OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
+      return false;
+    }
+
+    KYBER_decap(secret.data() + 32, secret.size() - 32, ciphertext.data() + 32,
+                &kyber_private_key_);
+    *out_secret = std::move(secret);
+    return true;
   }
+
+ private:
+  uint8_t x25519_private_key_[32];
+  KYBER_private_key kyber_private_key_;
 };
 
 class P256Kyber768KeyShare : public SSLKeyShare {