diff options
Diffstat (limited to 'link')
| -rw-r--r-- | link/crypto-openssl.c | 29 | ||||
| -rw-r--r-- | link/crypto.c | 10 | ||||
| -rw-r--r-- | link/crypto.h | 4 | ||||
| -rw-r--r-- | link/seal.h | 7 |
4 files changed, 48 insertions, 2 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}; diff --git a/link/crypto.c b/link/crypto.c index 2fa7d44..c8fb9bd 100644 --- a/link/crypto.c +++ b/link/crypto.c @@ -141,6 +141,16 @@ bool pure_link_secret(const PureSealKey *own, const unsigned char peer[PURE_SEAL return c && own && c->link_secret(own, peer, out); } +bool pure_link_ephemeral(unsigned char private_key[32], unsigned char public_key[PURE_SEAL_KEY]) { + const PureCrypto *c = loaded(NULL, 0); + return c && c->link_ephemeral(private_key, public_key); +} + +bool pure_link_agree(const unsigned char private_key[32], const unsigned char peer[PURE_SEAL_KEY], unsigned char out[32]) { + const PureCrypto *c = loaded(NULL, 0); + return c && c->link_agree(private_key, peer, out); +} + bool pure_link_derive(const unsigned char secret[32], const unsigned char *info, size_t info_size, unsigned char *out, size_t out_size) { const PureCrypto *c = loaded(NULL, 0); diff --git a/link/crypto.h b/link/crypto.h index 53ac785..ede5fb9 100644 --- a/link/crypto.h +++ b/link/crypto.h @@ -8,7 +8,7 @@ * first time a server seals, opens a seal or connects to an https receiver * (link/crypto.c): one that does none of these maps no OpenSSL, 2.3 MiB * less resident and 0.6 MiB less of its own. */ -enum { PURE_CRYPTO_VERSION = 4 }; +enum { PURE_CRYPTO_VERSION = 5 }; typedef struct { unsigned version; @@ -35,6 +35,8 @@ typedef struct { void (*opener_free)(PureOpener *); /* Links, as link/seal.h says. */ bool (*link_secret)(const PureSealKey *, const unsigned char peer[PURE_SEAL_KEY], unsigned char out[32]); + bool (*link_ephemeral)(unsigned char private_key[32], unsigned char public_key[PURE_SEAL_KEY]); + bool (*link_agree)(const unsigned char private_key[32], const unsigned char peer[PURE_SEAL_KEY], unsigned char out[32]); bool (*link_derive)(const unsigned char secret[32], const unsigned char *info, size_t info_size, unsigned char *out, size_t out_size); PureAead *(*aead)(const unsigned char key[PURE_AEAD_KEY]); diff --git a/link/seal.h b/link/seal.h index 9245f25..de1e7a5 100644 --- a/link/seal.h +++ b/link/seal.h @@ -65,6 +65,13 @@ void pure_opener_free(PureOpener *); typedef struct PureAead PureAead; enum { PURE_AEAD_KEY = 16, PURE_AEAD_NONCE = 12, PURE_AEAD_TAG = 16 }; bool pure_link_secret(const PureSealKey *own, const unsigned char peer[PURE_SEAL_KEY], unsigned char out[32]); +/* An epoch's keys (link/link-protocol.h): a key pair made for once, raw (its + * holder clears the private half as soon as it has agreed: a link may hold + * one for long, and a node many, so they are not kept in the secure heap), + * and the secret it shares with another's public half (never all zeros). + * On a Raspberry Pi 5 the pair costs 57 µs and the secret 220. */ +bool pure_link_ephemeral(unsigned char private_key[32], unsigned char public_key[PURE_SEAL_KEY]); +bool pure_link_agree(const unsigned char private_key[32], const unsigned char peer[PURE_SEAL_KEY], unsigned char out[32]); bool pure_link_derive(const unsigned char secret[32], const unsigned char *info, size_t info_size, unsigned char *out, size_t out_size); PureAead *pure_aead(const unsigned char key[PURE_AEAD_KEY]); |
