Question

I am using ECDH to have a shared secret between Alice and Bob one running on Android and the other on embedded. My understanding is that the best practice is that both sides generate an AES key to encrypt messages. Can someone send some example on how both sides Alice and Bob generate the same AES key after they have agreed on a shared secret by using ECDH?

Was it helpful?

Solution

It's probably best to follow the NIST recommendations on Key Agreement schemes, e.g. using NIST SP 800-56A with the recommendations in the implementers guide and one of the key derivation methods specified in NIST SP 800-108. It describes how to convert the secret to bytes, and then one of the KDF's can be used to convert to (multiple) keys.

Note that the key derivations are in the lightweight API of Bouncy Castle since 1.50 and should therefore also be present in Spongy Castle. The most common NIST algorithm is in org.bouncycastle.crypto.generators.KDFCounterBytesGenerator. You can simply give it any HMAC (say HMAC SHA1) in the constructor and org.bouncycastle.crypto.params.KDFCounterParameters during initialization.

Note that this adheres to better cryptographic practices than the answer of Perseids, but may be significantly harder to understand/implement.

OTHER TIPS

After the successful ECDH run you've got the same group element on both ends. You now need to define a uniform encoding of the elements as byte array / octet stream. Using a hash function (for example SHA256) you can reduce the array to a 256bit value. If you need to derive several keys you can append the byte array with different constants for every key before hashing them.

A simple example: Let's say your elliptic curve point is (51357992175,89175716892). You can represent that curve point as the string "(51357992175,89175716892)". For different keys you can append some string constants like "MacKey" or "EncryptionKey". To get some raw byte values you can encode these strings with utf8. Overall the keys would be:

macKey        = sha256("(51357992175,89175716892)MacKey".getBytes("UTF-8"))
encryptionKey = sha256("(51357992175,89175716892)EncryptionKey".getBytes("UTF-8"))

Edit, regarding your question arising from the comments ("In my case I have one server and many clients that approach to him several times a day, and need to have a different AES key each time based on the shared secret.") on how to produce a large number of keys, one for each communication event:

You are getting into the - rather complex - area of cryptographic protocol design. Think about these questions:

  • How do you guarantee that a different key is generated for each new sent message? Standard solutions would be the use of a counter or a random number as nonce (number used once), each of them having their own problems. (Counter: It has to be strictly monotonic even in case of an application crash or backup restore. Random: It has to be large enough to prevent random collisions - something like 256bit would suffice - and you have to continuously trust the random number generator to be good.)
  • How do you prevent message replays attacking the receiving side? You can keep track of every nonce used (storage intensive) or possibly use a monotonic counter in case the nonce is monotonic and reject any message having a nonce less or equal the monotonic counter.
  • How do you react to message delaying, reordering or selective message blocking? In many cases it is important to be able to notice these events and you have to decide what to do in then. (TLS for example requires live interactions between the two parties and aborts the connection if anything arrives out of order, but is not able to detect delays (except if the now infamous heartbeats are used to ping the connection).)

With the extended warning behind us, back to your question: For each new key you can use a nonce (number used once) that is included in the key derivation to generate a unique key for the purpose. I'm basically rebuilding something similar to "5.1 KDF in Counter Mode" from NIST SP 800-108, which owlstead has already mentioned, with plain text components. At this point I would recommend to read it in any way as it is not that long and contains a lot of background considerations. Additionally to the nonce you should narrow the use of the key as close as possible. For example on the server side use:

macKey = sha256(sha256("(51357992175,89175716892); MacKey; ServerToClient; 2755".getBytes("UTF-8")))

for the 2755th key generated for message authentication purposes for communication from the server to the client. You can see the following components: The shared secret (the elliptic curve point), the purpose of the key (mac), the communication direction, a counting nonce. Also I use double hashing here to prevent any kind of length extension on the hash; an HMAC would be just as good here. The nonce itself can, and has to in some case, be published alongside of the message. In itself it does not contain any sensitive information.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top