]> git.codecow.com Git - Monocypher.git/commitdiff
Manual review: key exchange
authorLoup Vaillant <loup@loup-vaillant.fr>
Wed, 1 Nov 2017 11:01:48 +0000 (12:01 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Wed, 1 Nov 2017 11:01:48 +0000 (12:01 +0100)
doc/man/man3/crypto_key_exchange.3monocypher

index 97a3151252c82328adf822adce9055b6626e6d8d..1de90b3d3f5bcca9ae55048ddbdcde75aa3905da 100644 (file)
 .Fa "const uint8_t their_public_key[32]"
 .Fc
 .Sh DESCRIPTION
-Key exchange works thus: Alice and Bob each have a key pair (a secret
-key and a public key).
-They know each other's public key, but they keep their own secret key
-secret.
-If Eve (an attacker) learns Alice's secret key, she could compute the
-shared secret between Alice and anyone else (including Bob), allowing
-her to read and forge correspondence.
-Protect your secret key.
-.Pp
-Furthermore, Alice and Bob must know each other's public keys
-.Em beforehand .
-If they do not, and try to communicate those keys over an insecure
-channel, Eve might intercept their communications (Man-in-the-middle
-attack) and provide false public keys.
-There are various ways to learn of each other's public keys (crypto
-parties, certificate authorities, web of trust…), each with their own
-advantages and drawbacks.
-.Pp
 The
 .Fn crypto_key_exchange
 function computes a shared key with your secret key and their public
 key, suitable for the
-.Xr crypto_lock 3monocypher ,
-.Xr crypto_unlock 3monocypher ,
-.Xr crypto_aead_lock 3monocypher ,
-and
-.Xr crypto_aead_unlock 3monocypher
-functions.
-It performs an X25519 key exchange, then hashes the shared secret (with
-HChacha20) to get a suitably random shared key.
-.Pp
-Keep in mind that if either of the long term secret keys leaks, it
-may compromise
-.Em all past messages !
-If you want forward secrecy, you will need to exchange temporary public
-keys, then compute your shared secret with
-.Em them .
+.Xr crypto_lock 3monocypher
+family of functions.
+It performs an X25519 key exchange, then hashes the shared secret with
+HChacha20 to get a suitably random shared key.
 .Pp
 The
 .Fn crypto_x25519_public_key
-function eterministically computes the public key from
+function eterministically computes the public key from a random
 .Fa secret_key .
-Make sure the secret key is random.
 See
 .Xr intro 3monocypher
-for advice about generating random bytes (basically, use your operating
-system's random number generator).
+about generating random bytes (use the operating system's random
+number generator).
 .Pp
 The
 .Fn crypto_x25519
-function allows doing a raw X25519 key exchange.
-This is a low-level function.
-Unless you
-.Em really
-know what you are doing, you should use
-.Fn crypto_key_exchange
-instead.
-This function computes a shared secret with your secret key
+function computes a shared secret with
 .Fa your_secret_key
-and the other party's public key
+and
 .Fa their_public_key .
 .Sy Warning: the shared secret is not cryptographically random .
 Do not use it directly as a session key.
-You need to hash it first.
-Any cryptographically secure hash will do.
-The
-.Fn crypto_key_exchange
-function uses HChacha20 via
-.Xr crypto_chacha20_H 3monocypher ,
-which is not a general purpose hash, but here it works just fine.
+Hash it first with
+.Xr crypto_chacha20_H
+or
+.Xr crypto_blake2b .
 .Sh RETURN VALUES
 The
 .Fn crypto_key_exchange
 and
 .Fn crypto_x25519
-functions return zero on success.
-The return value serves as a security check: there are public keys that
-force the shared key to a known constant (the HChacha20 of zero in the
-case of
-.Fn crypto_key_exchange
-or all-zero in the case of
-.Fn crypto_x25519 ) .
+functions return zero on success, or -1 on failure.
+The return value serves as a security check: some public keys force
+the shared key to a known constant.
 This never happens with legitimate public keys, but if the ones you
 process are not known to be trustworthy, check the return value.
 .Pp
@@ -116,53 +72,71 @@ The
 function returns nothing.
 It cannot fail.
 .Sh EXAMPLES
-This example outlines how to generate a private key and a public key,
-then perform a key exchange.
+Generate a public key from a randomly generated secret key:
 .Bd -literal -offset indent
-uint8_t sk[32], pk[32];
-uint8_t theirpk[32];
-uint8_t shared_key[32];
-
-/* ...randomly generate sk here... */
+const uint8_t sk[32]; /* Random secret key */
+uint8_t       pk[32]; /* Public key        */
 crypto_x25519_public_key(pk, sk);
-
-/* ...read their public key... */
-
-if (crypto_key_exchange(shared_key, sk, theirpk) != 0) {
-        /* ...handle weak key (see RETURN VALUES)...
-         * You probably want to stop processing now.
-         */
+/* Wipe secrets if they are no longer needed */
+crypto_wipe(sk, 32);
+.Ed
+.Pp
+Generate a shared, symmetric key with your secret key and their public
+key.
+(The other party will generate the same shared key with your public
+key and their secret key.)
+.Bd -literal -offset indent
+const uint8_t their_pk  [32]; /* Their public key   */
+const uint8_t your_sk   [32]; /* Your secret key    */
+uint8_t       shared_key[32]; /* Shared session key */
+if (crypto_key_exchange(shared_key, your_sk, their_pk) != 0) {
+    /* Their public key is evil.     */
+    /* The exchange must be aborted. */
 }
+/* Wipe secrets if they are no longer needed */
+crypto_wipe(your_sk, 32);
+.Ed
+.Pp
+Generate
+.Em two
+shared keys with your secret key and their public key.
+(This can help nonce management for full duplex communications.)
+.Bd -literal -offset indent
+const uint8_t their_pk     [32]; /* Their public key          */
+const uint8_t your_sk      [32]; /* Your secret key           */
+uint8_t       shared_secret[32]; /* Shared secret (NOT a key) */
+if (crypto_x25519(shared_secret, your_sk, their_pk) != 0) {
+    /* Their public key is evil.     */
+    /* The exchange must be aborted. */
+}
+/* Wipe secrets if they are no longer needed */
+crypto_wipe(your_sk, 32);
 
-/* You will want to wipe the secret key unless you specifically need
- * it for another key exchange.
- */
-crypto_wipe(sk, sizeof(sk));
-
-/* shared_key can now be used as key, for example in
- * crypto_lock/crypto_unlock.
- */
+uint8_t shared_keys[64];           /* Two shared session keys  */
+uint8_t *key_1 = shared_keys;      /* Shared key 1             */
+uint8_t *key_2 = shared_keys + 32; /* Shared key 2             */
+crypto_blake2b(shared_keys, shared_secret, 32);
+crypto_wipe(shared_secret, 32);    /* wipe the unneeded secret */
 .Ed
 .Sh SEE ALSO
 .Xr crypto_lock 3monocypher ,
 .Xr intro 3monocypher
-.Sh CAVEATS
-No implementation advice can be given for implementing forward secrecy
-using temporary public/private key pairs due to unfamiliarity of the
-author with that matter.
-.Pp
-X25519 generally encodes all numbers in little endian.
-This may require special attention when interoperating with other
-cryptographic libraries that expose an ECDH interface consuming only
-big integers in big endian representation, notably mbedTLS.
-.Sh IMPLEMENTATION DETAILS
-These functions implement X25519.
+.Sh STANDARDS
+These functions implement X25519, described in RFC 7748.
 The
 .Fn crypto_key_exchange
-function utilizes HChacha20 as well.
-.Pp
-Note that the most significant bit of the public key is systematically
-ignored.
+function uses HChacha20 as well.
+.Sh SECURITY CONSIDERATIONS
+If either of the long term secret keys leaks, it
+may compromise
+.Em all past messages .
+Users who want forward secrecy need to generate temporary public keys,
+send them to one another, (use
+.Xr crypto_lock 3monocypher
+to authenticate them), and compute a shared secret with those
+temporary keys.
+.Sh 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's not fully