CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
ecdh.cpp
Go to the documentation of this file.
1
11
12#include "ecdh.h"
13#include <mbedtls/ecdh.h>
14#include <mbedtls/ecp.h>
15#include <mbedtls/ctr_drbg.h>
16#include <mbedtls/entropy.h>
17#include <mbedtls/platform_util.h>
18#include <esp_random.h>
19#include <string.h>
20
24#if defined(MBEDTLS_PRIVATE)
25#define ECP_POINT_X(P) (P).MBEDTLS_PRIVATE(X)
26#define ECP_POINT_Y(P) (P).MBEDTLS_PRIVATE(Y)
27#define ECP_POINT_Z(P) (P).MBEDTLS_PRIVATE(Z)
28#else
29#define ECP_POINT_X(P) (P).X
30#define ECP_POINT_Y(P) (P).Y
31#define ECP_POINT_Z(P) (P).Z
32#endif
33
41static int hw_random(void* ctx, unsigned char* buf, size_t len) {
42 (void)ctx;
43 esp_fill_random(buf, len);
44 return 0;
45}
46
52void ecdh_secure_clear(void* ptr, size_t size) {
53 mbedtls_platform_zeroize(ptr, size);
54}
55
64 uint8_t* privkey,
65 const uint8_t* peer_pubkey,
66 uint8_t* shared_out
67) {
68 if (!privkey || !peer_pubkey || !shared_out) {
69 return false;
70 }
71
72 // Verify uncompressed point format (0x04 prefix)
73 if (peer_pubkey[0] != 0x04) {
74 ecdh_secure_clear(privkey, 32);
75 return false;
76 }
77
78 mbedtls_ecp_group grp;
79 mbedtls_mpi d; // Private key scalar
80 mbedtls_ecp_point Q; // Peer public key point
81 mbedtls_ecp_point S; // Shared secret point
82
83 mbedtls_ecp_group_init(&grp);
84 mbedtls_mpi_init(&d);
85 mbedtls_ecp_point_init(&Q);
86 mbedtls_ecp_point_init(&S);
87
88 bool success = false;
89 int ret;
90
91 // Load P-256 curve parameters
92 ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
93 if (ret != 0) {
94 goto cleanup;
95 }
96
97 // Import private key scalar
98 ret = mbedtls_mpi_read_binary(&d, privkey, 32);
99 if (ret != 0) {
100 goto cleanup;
101 }
102
103 // Import peer public key point (skip 0x04 prefix)
104 ret = mbedtls_mpi_read_binary(&ECP_POINT_X(Q), peer_pubkey + 1, 32);
105 if (ret != 0) {
106 goto cleanup;
107 }
108
109 ret = mbedtls_mpi_read_binary(&ECP_POINT_Y(Q), peer_pubkey + 33, 32);
110 if (ret != 0) {
111 goto cleanup;
112 }
113
114 ret = mbedtls_mpi_lset(&ECP_POINT_Z(Q), 1);
115 if (ret != 0) {
116 goto cleanup;
117 }
118
119 // Validate peer public key is on curve
120 ret = mbedtls_ecp_check_pubkey(&grp, &Q);
121 if (ret != 0) {
122 goto cleanup;
123 }
124
125 // Compute ECDH: S = d * Q
126 // Using constant-time scalar multiplication
127 ret = mbedtls_ecp_mul(&grp, &S, &d, &Q, hw_random, NULL);
128 if (ret != 0) {
129 goto cleanup;
130 }
131
132 // Extract X coordinate as shared secret (32 bytes)
133 ret = mbedtls_mpi_write_binary(&ECP_POINT_X(S), shared_out, 32);
134 if (ret != 0) {
135 goto cleanup;
136 }
137
138 success = true;
139
140cleanup:
141 // Securely clear all sensitive data
142 mbedtls_ecp_group_free(&grp);
143 mbedtls_mpi_free(&d);
144 mbedtls_ecp_point_free(&Q);
145 mbedtls_ecp_point_free(&S);
146
147 // ALWAYS clear the private key from caller's buffer
148 ecdh_secure_clear(privkey, 32);
149
150 return success;
151}
152
153bool ecdh_p256_generate_keypair(uint8_t* privkey_out, uint8_t* pubkey_out) {
154 if (!privkey_out || !pubkey_out) {
155 return false;
156 }
157
158 mbedtls_ecp_group grp;
159 mbedtls_mpi d;
160 mbedtls_ecp_point Q;
161
162 mbedtls_ecp_group_init(&grp);
163 mbedtls_mpi_init(&d);
164 mbedtls_ecp_point_init(&Q);
165
166 bool success = false;
167 int ret;
168
169 // Load P-256 curve
170 ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
171 if (ret != 0) {
172 goto cleanup;
173 }
174
175 // Generate key pair
176 ret = mbedtls_ecp_gen_keypair(&grp, &d, &Q, hw_random, NULL);
177 if (ret != 0) {
178 goto cleanup;
179 }
180
181 // Export private key
182 ret = mbedtls_mpi_write_binary(&d, privkey_out, 32);
183 if (ret != 0) {
184 goto cleanup;
185 }
186
187 // Export public key in uncompressed format (04 || X || Y)
188 pubkey_out[0] = 0x04;
189 ret = mbedtls_mpi_write_binary(&ECP_POINT_X(Q), pubkey_out + 1, 32);
190 if (ret != 0) {
191 goto cleanup;
192 }
193
194 ret = mbedtls_mpi_write_binary(&ECP_POINT_Y(Q), pubkey_out + 33, 32);
195 if (ret != 0) {
196 goto cleanup;
197 }
198
199 success = true;
200
201cleanup:
202 mbedtls_ecp_group_free(&grp);
203 mbedtls_mpi_free(&d);
204 mbedtls_ecp_point_free(&Q);
205
206 if (!success) {
207 ecdh_secure_clear(privkey_out, 32);
208 ecdh_secure_clear(pubkey_out, 65);
209 }
210
211 return success;
212}
213
214bool ecdh_p256_derive_pubkey(const uint8_t* privkey, uint8_t* pubkey_out) {
215 if (!privkey || !pubkey_out) {
216 return false;
217 }
218
219 mbedtls_ecp_group grp;
220 mbedtls_mpi d;
221 mbedtls_ecp_point Q;
222
223 mbedtls_ecp_group_init(&grp);
224 mbedtls_mpi_init(&d);
225 mbedtls_ecp_point_init(&Q);
226
227 bool success = false;
228 int ret;
229
230 // Load P-256 curve
231 ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
232 if (ret != 0) {
233 goto cleanup;
234 }
235
236 // Import private key
237 ret = mbedtls_mpi_read_binary(&d, privkey, 32);
238 if (ret != 0) {
239 goto cleanup;
240 }
241
242 // Compute public key: Q = d * G
243 ret = mbedtls_ecp_mul(&grp, &Q, &d, &grp.G, hw_random, NULL);
244 if (ret != 0) {
245 goto cleanup;
246 }
247
248 // Export in uncompressed format
249 pubkey_out[0] = 0x04;
250 ret = mbedtls_mpi_write_binary(&ECP_POINT_X(Q), pubkey_out + 1, 32);
251 if (ret != 0) {
252 goto cleanup;
253 }
254
255 ret = mbedtls_mpi_write_binary(&ECP_POINT_Y(Q), pubkey_out + 33, 32);
256 if (ret != 0) {
257 goto cleanup;
258 }
259
260 success = true;
261
262cleanup:
263 mbedtls_ecp_group_free(&grp);
264 mbedtls_mpi_free(&d);
265 mbedtls_ecp_point_free(&Q);
266
267 return success;
268}
#define ECP_POINT_Z(P)
Definition ecdh.cpp:31
static int hw_random(void *ctx, unsigned char *buf, size_t len)
Hardware RNG callback used by MbedTLS.
Definition ecdh.cpp:41
bool ecdh_p256_generate_keypair(uint8_t *privkey_out, uint8_t *pubkey_out)
Definition ecdh.cpp:153
bool ecdh_p256_compute_shared_secret(uint8_t *privkey, const uint8_t *peer_pubkey, uint8_t *shared_out)
Computes ECDH shared secret on P-256 using local private key and peer public key.
Definition ecdh.cpp:63
#define ECP_POINT_Y(P)
Definition ecdh.cpp:30
void ecdh_secure_clear(void *ptr, size_t size)
Securely clears sensitive memory using platform zeroize.
Definition ecdh.cpp:52
#define ECP_POINT_X(P)
MbedTLS 3.x/4.x compatibility macros for ECP point field access.
Definition ecdh.cpp:29
bool ecdh_p256_derive_pubkey(const uint8_t *privkey, uint8_t *pubkey_out)
Definition ecdh.cpp:214