4
$\begingroup$

I'm developing an application with multiple clients and one server. All clients will have the same hard-coded Curve25519 key pair as well as the server's public key. The server will have its own key pair as well as the clients' public key.

The idea was to allow communication between server and clients without any concern that the data from one client could be intercepted and decrypted by an attacker possessing the client key pair, nor could they originate messages that appeared to be from the server in order to control other clients.

I'm using libsodium and the crypto_box functions, and noticed that the following scenario works, which really puzzles me:

Alice has a key pair, pKa and sKa.
Bob has a key pair, pKb and sKb.
Each also have each other's public key (pKa and pKb)

Alice wants to send a message to Bob, so she passes pKb and sKa to crypto_box.
Bob can decrypt the message by passing pKa and sKb to crypto_box_open.
However, Eve has a copy of Alice's key pair and intercepted the outgoing message. She uses crypto_box_open and passes in pKb and sKa, the same keys that were used to encrypt the message. This yields the plain text message. She changes the message, re-encrypts it, and sends it on to Bob.

I'm relatively new to crypto, so I'm sure I must be doing something wrong or just misunderstanding the application of the technology. If someone could help me out, that would be awesome.

$\endgroup$
  • $\begingroup$ Also, hardcoded Keys are tricky. What if the keys get compromised? You'll need to alter the source in order to establish a safe channel again. $\endgroup$ – Yorick de Wid Oct 31 '15 at 18:52
  • $\begingroup$ @MaartenBodewes - In the example, Bob is the server, so both statements are correct. They also have each other's public key. $\endgroup$ – TimH Nov 3 '15 at 17:57
  • $\begingroup$ @YorickdeWid - True, and I may deal with that differently in the final implementation, but that will be another question that has likely already been answered quite well. $\endgroup$ – TimH Nov 3 '15 at 18:00
3
$\begingroup$

However, Eve has a copy of Alice's key pair and intercepted the outgoing message. She uses crypto_box_open and passes in pKb and sKa, the same keys that were used to encrypt the message. This yields the plain text message. She changes the message, re-encrypts it, and sends it on to Bob.

As you correctly observed, Eve having Alice's private key is insecure. It allows Eve to decrypt and replace messages with arbitrary contents. In any public key encryption system it would allow Eve to at least replace messages, though some would not allow decryption.

An equally serious issue would be for messages going the other way. If Bob sends Alice a message, Eve who has Alices keys would be able to read and modify the message.

In short, private keys must be kept private. You cannot share a key-pair between multiple users unless they all trust each other completely. In your situation, the normal thing to do would be for each client to have their own key pair.

$\endgroup$
  • $\begingroup$ So would a more secure method be to have all client possess a hard-coded public key for the server, but generate and store their own key pair? $\endgroup$ – TimH Oct 30 '15 at 18:01
  • 1
    $\begingroup$ @TimH, yes, exactly. The client can send their public key with the message if you only need one way authentication. $\endgroup$ – otus Oct 31 '15 at 6:00
2
$\begingroup$

What you observed here is a "special" and "unusual" behavior of the NaCl interface in the way it handles the crypto_box.

What the crypto_box does is basically perform a static Diffie-Hellman key-exchange (using your secret and the recipient's public key) between you and the receiver and derive keys from that. So you get the same symmetric encryption key for every crypto_box you create.

What you did expect is a different, randomized key for each crypto_box as would be normal with public-key encryption.
You can't achieve this trivially with NaCl, but you can implement ECIES (or a variant thereof) yourself, which has the desired property (and doesn't require the sender to have a key-pair). This can be achieved by creating a new key-pair for each crypto_box and appending the (ephemeral) public key to each message and destroying the (ephemeral) private key.

And of course the standard security warning:
Private keys are meant to be kept private. There should be no situation where you need to share / distribute them.

$\endgroup$
  • 1
    $\begingroup$ ECIES basically uses static-ephemeral Diffie–Hellman. You can do similar with crypto_box by generating an ephemeral key-pair for each message you send. $\endgroup$ – otus Oct 31 '15 at 6:07
  • $\begingroup$ @otus, thank you. I had a logic flaw when thinking about this myself. I've updated my answer accordingly. $\endgroup$ – SEJPM Oct 31 '15 at 12:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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