aboutsummaryrefslogtreecommitdiffstats
path: root/link/crypto-openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'link/crypto-openssl.c')
-rw-r--r--link/crypto-openssl.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/link/crypto-openssl.c b/link/crypto-openssl.c
index 6bdf6fb..96daa82 100644
--- a/link/crypto-openssl.c
+++ b/link/crypto-openssl.c
@@ -207,6 +207,32 @@ static bool link_secret(const PureSealKey *own, const unsigned char peer[PURE_SE
return ok && any;
}
+/* A pair made for once (X25519): an epoch's half, raw. */
+static bool link_ephemeral(unsigned char private_key[32], unsigned char public_key[PURE_SEAL_KEY]) {
+ EVP_PKEY *key = EVP_PKEY_Q_keygen(NULL, NULL, "X25519");
+ size_t a = 32, b = PURE_SEAL_KEY;
+ bool ok = key && EVP_PKEY_get_raw_private_key(key, private_key, &a) == 1 &&
+ EVP_PKEY_get_raw_public_key(key, public_key, &b) == 1 && a == 32 && b == PURE_SEAL_KEY;
+ EVP_PKEY_free(key);
+ return ok;
+}
+
+/* The secret a raw private half shares with a peer's public key. */
+static bool link_agree(const unsigned char private_key[32], const unsigned char peer[PURE_SEAL_KEY], unsigned char out[32]) {
+ EVP_PKEY *mine = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, private_key, 32);
+ EVP_PKEY *theirs = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, peer, PURE_SEAL_KEY);
+ EVP_PKEY_CTX *context = mine && theirs ? EVP_PKEY_CTX_new(mine, NULL) : NULL;
+ size_t length = 32;
+ bool ok = context && EVP_PKEY_derive_init(context) == 1 && EVP_PKEY_derive_set_peer(context, theirs) == 1 &&
+ EVP_PKEY_derive(context, out, &length) == 1 && length == 32;
+ EVP_PKEY_CTX_free(context);
+ EVP_PKEY_free(mine);
+ EVP_PKEY_free(theirs);
+ unsigned char any = 0; /* a small-order key makes zeros: no secret */
+ for (size_t i = 0; ok && i < 32; ++i) any |= out[i];
+ return ok && any;
+}
+
/* HKDF, fetched once. */
static EVP_KDF *hkdf(void) {
static EVP_KDF *kept;
@@ -281,4 +307,5 @@ static bool aead_open(PureAead *a, const unsigned char *key, const unsigned char
const PureCrypto pure_crypto = {PURE_CRYPTO_VERSION, tls_start, tls_open, tls_read, tls_write, tls_close,
seal_key, seal_key_free, sealer, seal, sealer_free, opener, unseal, opener_free,
- link_secret, link_derive, aead, aead_seal, aead_open, aead_free};
+ link_secret, link_ephemeral, link_agree, link_derive, aead, aead_seal, aead_open,
+ aead_free};