2

We are using libsodium and regarding exchanging secrets we would like to use the so-called crypto_box (https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption). Under the hood, ECDH is used. The problem is that it can be possible as well, that I encrypt this secret by myself. In that case, Alice and Bob would be the same person and the public keys will not differ. Is that a security problem, because DH was not designed for this kind of use case?

Daniel S
  • 23,716
  • 1
  • 29
  • 67
Trafo
  • 21
  • 1
  • 1
    ECDH can be used for that use case; it normally involves doing a key exchange with an ephemeral key pair and storing the ephemeral public key with the file. Don't use crypto_box. There are a number of problems with it. It doesn't provide sender authentication, it uses HSalsa20 instead of a proper KDF (e.g. HKDF), it uses XSalsa20 instead of XChaCha20, and both parties can decrypt messages, which you usually want to prevent. – samuel-lucas6 Jan 26 '23 at 12:38
  • @samuel-lucas6 I would like to understand why not to use crypto_box. Especially because I meant crypto_box_easy with authentication (https://doc.libsodium.org/public-key_cryptography/authenticated_encryption). And there the sender is authenticated. Sadly I am stuck using libsodium, even though I share your concerns regarding a proper key derivation function. But from my knowledge, they embrace everywhere using XChaCha20, where do you get the information, and what are the alternatives? That both parties can decrypt the message is fine because the sender knows the message anyways. – Trafo Jan 26 '23 at 13:45
  • It's a common misconception that crypto_box_easy provides sender authentication. It doesn't. Also see RFC 7748 Section 7. crypto_box uses XSalsa20 as it says here. libsodium is an excellent library; the key derivation API is the weakest link but HKDF is being added. I know both parties is fine in this case but not for generic uses of crypto_box between two parties. – samuel-lucas6 Jan 26 '23 at 13:52
  • @samuel-lucas6 I got it now your statement, that the key derivation function is the weakest link. It is all about entropy. Blake2B is allowing maximal 128-bit entropy, because of collisions. And this is fine, till we are in a post-quantum world. And I agree HKDF where no entropy will get lost has definitely a lot of advantages. – Trafo Jan 27 '23 at 15:52
  • HSalsa20 is being used, not BLAKE2b. BLAKE2b can be used to create the equivalent of HKDF. All HKDF really does is an additional step to turn a shared secret (non-uniform) into a cryptographic key before using that uniform key to produce more keys. HMAC-SHA-2 in HKDF can be replaced with keyed BLAKE2b or HMAC-BLAKE2b. Technically, this additional step isn't required, but it should be slightly more secure, especially if a salt is used to add randomness. – samuel-lucas6 Jan 28 '23 at 09:52
  • @samuel-lucas6 I hope last one. Because I misunderstood your statement. Because you said libsodium is an excellent library; the key derivation API is the weakest link What you meant was not Key Derivation API directly which is using Blake2B you meant key derivation inside of cryptobox? Does that mean the key derivation function provided by libsodium will do the same as HKDF and transform a non-uniform secret ECDH result to a cryptographic key before extracting more, which is highly recommended for ECDH? And I don't have many benefits of replacing Blake2b with HKDF-SHA-2? – Trafo Jan 30 '23 at 14:58
  • Well it's quite complicated. The libsodium KDF is not widely used, unlike HKDF. It's not BLAKE2X, which is the 'official' BLAKE2 KDF, although that's basically not used at all. It also doesn't follow the extract-then-expand methodology of HKDF, so I don't think it achieves KDF security, just PRF security. If I'm correct, that means you should technically hash a shared secret prior to using it as the key in the libsodium KDF. I explain how to do that hashing with the public keys in my answer. – samuel-lucas6 Jan 30 '23 at 20:43
  • 1
    Thx for the info, helped me again a lot. Blake2X can be easily built out of Blake2B. They are not compatible because Blake2X needs some extra parameters for expanding the data. Blake2B personalized API is kind of the expand-part of HKDF, without having multiple steps, because it stops at the first and does not continue to append multiple random blocks. The extract-part is very often not needed, in case you have already a high entropy source, which the API of libsodium states out, why KDF security is not needed in that case. In case I don't have high entropy, I can hash it as you stated. Thx! – Trafo Jan 31 '23 at 07:55

2 Answers2

1

There's an elegant argument that the computational Diffie-Hellman problem with repeated keys is no harder than the generic computational Diffie-Hellman problem.

We write $\mathrm{CDH}(G,aG,bG)$ for the generic computational Diffie-Hellman problem of computing $abG$ given $g$, $aG$ and $bG$ and $\mathrm{rCDH}(G,aG)$ for the repeated key computational Diffie-Hellman problem of computing $a^2G$ given $G$ and $aG$. Suppose that we have an advantageous way of solving $\mathrm{rCDH}$ and a $\mathrm{CDH}$ instance $\mathrm{CDH}(G,A,B)$. I can compute $A+B=(a+b)G$ and $A-B=(a-b)G$ and call my $\mathrm{rCDH}$ solver twice to get $\mathrm{rCDH}(G,A+B)=(a^2+2ab+b^2)G$ and $\mathrm{rCDH}(G,A-B)=(a^2-2ab+b^2)G$. Subtracting these two return values gives me the point $4abG$ and scalar multiplying by $4^{-1}\mod \ell$ where $\ell$ is the group order gives $abG$ and thus solves the $\mathrm{CDH}(G,A,B)$ problem.

Daniel S
  • 23,716
  • 1
  • 29
  • 67
  • Subtitle [edited]: this supports that crypto_box is not weakened when the two parties use the same public/private key pair, but is not quite a proof of that. – fgrieu Jan 26 '23 at 13:22
  • 1
    @fgrieu I've just nerd-sniped myself with this one. Any security properties of crypto_box that depend on CDH are not weakened, but OTOH I can't construct a proof that $rDDH\Rightarrow DDH$. If there are any security properties that depend on DDH, I'm not sure if there's an additional hardness assumption in the repeated case. – Daniel S Jan 26 '23 at 13:29
1

I would never recommend using crypto_box as it has a number of limitations:

  • It doesn't provide sender authentication, only message authentication, because the public keys are not included in the key derivation, as recommended in RFC 7748.
  • It uses HSalsa20 for key derivation. Firstly, this causes the above problem, which was also an issue I reported in Monocypher. Secondly, HSalsa20/HChaCha20 should really be supplied a uniformly random key, whereas shared secrets are not.
  • It uses XSalsa20-Poly1305 instead of XChaCha20-Poly1305. This isn't a security problem as both are secure, but (X)ChaCha20 is far more popular now, and ChaCha20 is slightly more efficient and has better diffusion.

Instead, you can do the following:

  1. Use crypto_box_keypair to randomly generate an ephemeral key pair (ephemeralPrivateKey, ephemeralPublicKey).
  2. Use crypto_scalarmult to perform a key exchange between your privateKey and ephemeralPublicKey. This produces sharedSecret.
  3. Erase the ephemeralPrivateKey (e.g. using sodium_memzero or the equivalent in your programming language).
  4. Derive an encryption key for XChaCha20-Poly1305 using crypto_generichash, with sharedSecret || your publicKey || ephemeralPublicKey as the message.
  5. Encrypt the plaintext using XChaCha20-Poly1305 with the above key and a randomly generated nonce.
  6. Prepend ephemeralPublicKey and the nonce to the ciphertext.

If the crypto_kx API is accessible, that does key derivation similarly for you, just use crypto_kx_client_session_keys to derive one key rather than two. There's no need to use crypto_kx_server_session_keys because there's no second party involved.

This provides sender authentication, uses a hash function for key derivation (HKDF or the personalised BLAKE2b KDF API could be used instead), derives a unique key each time, and uses a newer AEAD.

Documentation

samuel-lucas6
  • 1,783
  • 7
  • 17
  • Thx for the answer. The alternative will still not provide any sender authentication, because of the ephemeral key? It just uses better algorithms? And in my use case, a more common scenario is that Alice and Bob are different. That sender and receiver could be the same, is just an edge case. In that case, I can skip the ephemeral key and use the sender key. And in case the sender and receiver are the same it seems like I can use the same public key as well, because of the other answer. If I would like to have sender authentication, I should use on top public key signature? – Trafo Jan 26 '23 at 14:50
  • This does provide sender authentication because the public keys are included in the key derivation. It doesn't matter that the public key is ephemeral. Doing Alice and Bob gets far more complicated because you should still be using ephemeral keys. See this blog post for an explanation. – samuel-lucas6 Jan 26 '23 at 15:27
  • I should also add that just performing the key exchange with your own public key would result in the same shared secret and key each time unless you're performing some salting. – samuel-lucas6 Jan 26 '23 at 15:34
  • But given the same params for scalarmut would that not be anyways the case? Even in case, both public keys differ? I guess that is the argument for using ephemeral keys. – Trafo Jan 26 '23 at 15:51
  • The same parameters will produce the same shared secret. Not sure what you mean by 'both public keys differ'. Using a different or ephemeral public key anywhere will result in a different shared secret and hence a different key. If you look at the blog post I linked (technically 3 posts), it will explain more important reasons for using ephemeral keys. It's up to you how secure you want things to be/what properties you're looking for. I suggest you search for answers to further questions and ask a new question if you can't find an answer anywhere. – samuel-lucas6 Jan 26 '23 at 16:06
  • 1
    Thx very much, your posted blog post helped a lot. I understood now the struggles and why for example my naive thought to just encrypt and sign asymmetrically is less straightforward than I expected and why the crypto box has its flaws. Will use HKDF instead of crypto_generichash. Regarding the blog post and your suggested way, I see that they use two times ECDH (ephemeral-static and static-static) which you skipped because you assumed that Alice and Bob are the same. As well KCI attack seems to be irrelevant with ephemeral ECDH? – Trafo Jan 26 '23 at 16:41