I'm currently working in a constrained environment and need to derive a symmetric key (that will be used for AES-256 in GCM mode later) based on a low-entropy shared secret obtained via X25519.

To derive a symmetric key RFC 7748 states: Alice and Bob can then use a key-derivation function that includes K, K_A, and K_B to derive a symmetric key, where K is the shared secret, K_A is the public key of one participant in the key exchange and K_B is the public key of the other participant.

Since the RFC is rather vague here, I took a look at the implementation of libsodium. They implement the following key derivation (described in this page): rx || tx = BLAKE2B-512(p.n || client_pk || server_pk), where p.n is the shared secret, client_pk is the public key of the client and server_pk is the public key of the server.

The problem I am currently facing is that my constrained environment does not support BLAKE2B. So, I thought of the following options:

  1. Use another hash function implemented in my environment like SHA-512
  2. Use a known key derivation function like HKDF (also available in my environment)

Are both options 1 and 2 appropriate or do you see any security risks in either of them?


2 Answers 2


TL;DR Unless performance is an issue I'd go for HKDF. Use the functions for what they are designed for unless you have good enough reasons to avoid them.

libsodium seems to use a proprietary mechanism as a KDF. That has disadvantages as it may, for instance, not be available as a KDF in hardware accelerators or FIPS libraries. The main benefit seems to be is that it is fast in software while still secure.

BLAKE2B-512 is "just" a hash, so it doesn't really specify how the key material and possible other $Info$ or $OtherInfo$ parameters such as labels are handled. To derive two keys, libsodium uses a single call instead of two calls. That is fast and secure but it may not be compatible with API's that expect one KDF to be used per key (as in rx = KDF(IKM = p.n || client_pk || server_pk, label='rx') and tx = KDF(IKM = p.n || client_pk || server_pk, label='tx').

As for using a hash; there are quite a few questions already asked, such as this question for DH key agreement. In general it is considered secure as the hash compression function will disassociate the OKM (output keying material) from the IKM (input keying material, the bytes generated by x25519).

It might be a good idea to implement KDF1 which is a very simple construction to build a KDF from a hash. I've asked for the security of KDF1 & the almost identical KDF2 here.

You could also build HMAC from SHA-2 or use an existing HMAC function of course. TLS uses HMAC as KDF up to version 1.2 although they simply refer to is as "the PRF". However, if HKDF is already available then this strategy makes less sense - it is used in TLS 1.3.

HKDF is literally a known, NIST approved KDF. It is based on HMAC which has withstood a lot of crypt-analysis. So yes, that is definitely a good option. There is a question here on how to use it correctly (but at the moment there aren't any good answers, only a few informative comments).



We know that points of a curve satisfy the curve equation therefore the usual encoding of the points is structured and non-uniform.

Considering that $x^3 + 486662 x^2 + x$ is always a square for the points since it equals $y^2$.

This is the structure example;

  • it may result in related key attacks if AES is used.
  • and, the network data can be distinguishable from random.

The advice

  1. Use Elligator so that the encodings of the points are indistinguishable from random. This was a huge development since this helped the TOR network be more indistinguishable from random.

  2. Apply the usual advice and apply a KDF on the ECDH output. Using any cryptographic secure hash is fine to destroy any structure, however, the advice way is to use Key Derivation functions;

    HKDF; this is now standard in TLS 1.3 and mighty algorithm to produce multiple keys from a single source.

    HKDF has to parts

    • Extract: $\text{HKDF-Extract}(salt, IKM) \to PRK$ uses the salt to strength the Input Key Material (IKM)

    • Expand: $\text{KDF-Expand}(PRK, info, L) \to OKM$, this produces desired $L$ bits with additional info. This additional info can be used to derive many keys.

      If you used Alligator, then you definitely do not need the Extract part. If not, the Expand should be enough (no proof!), though prefer the Extract and Expand.

      This is simply why HKDF is the beast; it has built-in parameters that can be found in any standard implementation so that you don't need to reinvent yourself with a standard hash function.

  • There are also simpler KDFs; KDF-1 and KDF2 as layman KDF built with hash function with counter inputs and not powerful as HKDF.

Since available and better use HKDF.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.