Hi Abhilash,
I am trying to do the ECDH shared secret computation using the mbedTLS library. I am referring to multiple examples such as ecdh_curve25519.c and ecdh_main.c.
Ok. You should probably know a few things about those examples:
1. They both perform what's known as "ephemeral ECDH" (or sometimes ECDHE). 2. They're both using the low-level part of our ECDH API. For ecdh_curve25519, that is because that curve is not supported by the higher-level API yet - for the other example, I don't know what the reason is. 3. Curve25519 is quite different from other curves regarding how public keys are represented.
In my case, in my application firmware, I already have a device _priv key and I receive a server_public key; both generated using a curve ECP_DP_SECP256R1 in the bootloader itself. So in the application firmware, I would like to do generate a shared secret from here on and preserve it for future use.
Ok, so you want to do what's known as "static ECDH". So the example ecdh_curve25519 is not a great example, due to points 1 and 3 above. Also, since the curve you're using supports it, you may want to use the higher-level part of our ECDH API (the functions that accept a context as an argument).
The following is the steps that I do:
- Create a new client context, entropy context, ctr_drbg context variables.
- use mbedtls_"respective"_init() to initalize all the three variables
- Seed a random number using mbedtls_ctr_drbg_seed() function.
- load the P256 elliptic curve in client context using mbedtls_ecp_group_load()
All this looks absolutely correct.
- Then use mbedtls_mpi_lset() to set Qp.Z =1
- Then read the server pub key using mbedtls_mpi_read_binary(&ctx_cli.Qp.X, server_pub, 65);
From the 65 I assume that the server public key as encoded as an uncompressed
point. Then you can read it with:
mbedtls_ecp_point_read_binary(&ctx_cli.grp, &ctx_cli.Qp, server_pub, 65);
(For Curve25519 mbedtls_ecp_point_read_binary() isn't implemented yet which is why the example does a direct call to an MPI function and accesses individual point coordinates, but Curve25519 and P-256 don't use the same coordinate systems.)
- Now the question is: Should I initialize the ctx_cli with my already generated device_priv key using
mbedtls_mpi_read_binary(&ctx_cli.d, device_priv_key, 50) ?
That looks almost correct, except 50 does not look like a valid size for a private key for the curve you're using.
- Then I use mbedtls_ecdh_compute_shared(&ctx_cli.grp, &ctx_cli.z, &ctx_cli.Qp, &ctx_cli.d, mbedtls_ctr_drbg_random, &ctr_drbg); to compute the shared secret in z.
That's correct, but you could also call
mbedtls_ecdh_calc_secret( &ctx_cli, &olen, buf, blen, mbedtls_ctr_drbg_random, &ctr_drbg );
which also serializes the secret to a buffer.
Questions:
- Do I need to generate a keypair for client context using
mbedtls_ecdh_gen_public(&ctx_cli.grp, &ctx_cli.d, &ctx_cli.Q, mbedtls_ctr_drbg_random, &ctrDrbg)? And then set pvtkey as device priv key and pub key as service pub key?
I'm not sure I understand the context of the question, so I'll distinguish two cases:
- When provisioning the device, you need to generate a key pair for it, which can indeed be done as show. - Once the device is working, it doesn't need to generate new key pairs, just load the one that was provisioned as described below.
- I see that ctx_cli.Q has two components, Q.x and Q.y. How do I
extract these two values from a public key? Do I need to separately initialize them?
I don't recommend you manipulate those directly, but use the `mbedtls_ecp_point_{read,write}_binary()` functions instead.
Please let me know if the flow is correct. In all the examples, they generate a key pair and just update the public key part (Qp.X) of the key. They do not touch the private key part (d) of the key. Please confirm if I can upload my private key directly in my case.
Your flow looks correct, and the difference from the examples is that they're demonstrating ephemeral ECDH while it looks like you want to do static ECDH.
Also if my platform is a little endian, is there a recommended step before using mbedtls_mpi_read_binary_le functions?
Then endianness of your plaftorm should not matter, and you shouldn't need to use that function.
Regards, Manuel.