Monocypher

Boring crypto that simply works
CRYPTO_X25519(3MONOCYPHER) 3MONOCYPHER CRYPTO_X25519(3MONOCYPHER)

NAME

X25519 key exchange #include <monocypher.h>
void
crypto_x25519(uint8_t raw_shared_secret[32], const uint8_t your_secret_key[32], const uint8_t their_public_key[32]);
void
crypto_x25519_public_key(uint8_t your_public_key[32], const uint8_t your_secret_key[32]);

DESCRIPTION

crypto_x25519() computes a shared secret with your_secret_key and their_public_key. It is a low-level primitive. Use crypto_key_exchange() unless you have a specific reason not to.
crypto_x25519_public_key() is the same as crypto_key_exchange_public_key(). It deterministically computes the public key from a random secret key.
The arguments are:
raw_shared_secret
The shared secret, known only to those who know a relevant secret key (yours or theirs). It is not cryptographically random. Do not use it directly as a key. Hash it with crypto_chacha20_H() or crypto_blake2b() first.
your_secret_key
A 32-byte secret random number. See intro() for advice about generating random bytes (use the operating system's random number generator).
their_public_key
The public key of the other party.

RETURN VALUES

crypto_x25519() and crypto_x25519_public_key() return nothing.
Some poorly designed protocols require to test for “contributory” behaviour, which ensures that no untrusted party forces the shared secret to a known constant. Protocols should instead be designed in such a way that no such check is necessary, namely by authenticating the other party or exchanging keys over a trusted channel.

EXAMPLES

Generate a pair of shared keys with your secret key and their public key. (This can help nonce management for full duplex communications.)
const uint8_t their_pk     [32]; /* Their public key          */ 
uint8_t       your_sk      [32]; /* Your secret key           */ 
uint8_t       shared_secret[32]; /* Shared secret (NOT a key) */ 
crypto_x25519(shared_secret, your_sk, their_pk); 
/* Wipe secrets if they are no longer needed */ 
crypto_wipe(your_sk, 32); 
 
uint8_t shared_keys[64]; /* Two shared session keys */ 
crypto_blake2b(shared_keys, shared_secret, 32); 
const uint8_t *key_1 = shared_keys;      /* Shared key 1 */ 
const uint8_t *key_2 = shared_keys + 32; /* Shared key 2 */ 
/* Wipe secrets if they are no longer needed */ 
crypto_wipe(shared_secret, 32);

SEE ALSO

crypto_key_exchange(), intro()

STANDARDS

This function implements X25519, described in RFC 7748.

HISTORY

The crypto_x25519(), and crypto_x25519_public_key() functions first appeared in Monocypher 0.1.

SECURITY CONSIDERATIONS

If either of the long term secret keys leaks, it may compromise all past messages. This can be avoided by using protocols that provide forward secrecy, such as the X3DH key agreement protocol.

IMPLEMENTATION DETAILS

The most significant bit of the public key is systematically ignored. It is not needed because every public key should be smaller than 2^255-19, which fits in 255 bits. If another implementation of X25519 gives you a key that is not fully reduced and has its high bit set, the computation will fail. On the other hand, it also means you may use this bit for other purposes (such as parity flipping for Ed25519 compatibility).
December 12, 2019 Linux 4.15.0-88-generic