![]() |
![]()
| ![]() |
![]()
NAME
SYNOPSIS
void
void
void
void
void
void
DESCRIPTION
raw_shared_secret and your_secret_key may overlap if your secret is no longer required. Some protocols, such as some
password-authenticated key exchange (PAKE) protocols and oblivious
pseudo-random functions (OPRF), may require “contributory”
behaviour, which ensures that no untrusted party forces the shared secret to
a known constant. If a protocol requires contributory behaviour, compare the
output of
Do not use the same secret key for
both key exchanges and signatures. The public keys are different and
revealing both may leak information. If there really is no room to store or
derive two different secret keys, consider generating a key pair for
signatures and then converting the private half with
crypto_blake2b(3monocypher)
or
crypto_sha512(3monocypher),
and the public half with
crypto_eddsa_to_x25519(3monocypher).
Or go the other way and implement XEdDSA with the help of
RETURN VALUES
EXAMPLESThe following example assumes the existence of
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 your_pk [32]; /* Your public key */ uint8_t shared_secret[32]; /* Shared secret (NOT a key) */ arc4random_buf(your_sk, 32); crypto_x25519_public_key(your_pk, your_sk); 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_ctx ctx; crypto_blake2b_init (&ctx, 64); crypto_blake2b_update(&ctx, shared_secret, 32); crypto_blake2b_update(&ctx, your_pk , 32); crypto_blake2b_update(&ctx, their_pk , 32); crypto_blake2b_final (&ctx, shared_keys); 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); INVERSE SCALAR MULTIPLICATIONThe
uint8_t b [32]; /* Random scalar */ uint8_t base [32]; /* Point on the prime order subgroup */ crypto_x25519_public_key(base, b); uint8_t private_key[32]; /* Random secret key */ uint8_t curve_point[32]; /* Point on the prime order subgroup */ uint8_t blind_salt [32]; crypto_x25519(curve_point, private_key, base); crypto_x25519_inverse(blind_salt, private_key, curve_point); assert(memcmp(blind_salt, base, 32) == 0); /* blind_salt == base */ We can think of it as a scalar division that also clears the cofactor. The arguments are:
DIRTY PUBLIC KEY GENERATION
Both functions do the same with
different code size and memory characteristics:
CONVERSION TO EDDSAThe SEE ALSOSTANDARDSThis function implements X25519, described in RFC 7748. HISTORYThe CAVEATSMonocypher does not perform any input validation. Any deviation from the specified input and output length ranges results in undefined behaviour. Make sure your inputs are correct. SECURITY CONSIDERATIONSIf 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. Many (private, public) key pairs produce the same shared secret. Therefore, not including the public keys in the key derivation can lead to subtle vulnerabilities. This can be avoided by hashing the shared secret concatenated with both public keys. For example, BLAKE2b(shared_secret || your_pk || their_pk)
using
crypto_blake2b(3monocypher).
IMPLEMENTATION DETAILSThe 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).
|