diff options
Diffstat (limited to 'src/util/crypto_ecc.c')
-rw-r--r-- | src/util/crypto_ecc.c | 727 |
1 files changed, 431 insertions, 296 deletions
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c index 2561ab2e6..a93512e38 100644 --- a/src/util/crypto_ecc.c +++ b/src/util/crypto_ecc.c | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
7 | by the Free Software Foundation; either version 2, or (at your | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 10 | GNUnet is distributed in the hope that it will be useful, but |
@@ -30,6 +30,12 @@ | |||
30 | 30 | ||
31 | #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS | 31 | #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS |
32 | 32 | ||
33 | /** | ||
34 | * Name of the curve we are using. Note that we have hard-coded | ||
35 | * structs that use 256 bits, so using a bigger curve will require | ||
36 | * changes that break stuff badly. The name of the curve given here | ||
37 | * must be agreed by all peers and be supported by libgcrypt. | ||
38 | */ | ||
33 | #define CURVE "NIST P-256" | 39 | #define CURVE "NIST P-256" |
34 | 40 | ||
35 | #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) | 41 | #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) |
@@ -47,28 +53,14 @@ | |||
47 | 53 | ||
48 | 54 | ||
49 | /** | 55 | /** |
50 | * The private information of an ECC private key. | ||
51 | */ | ||
52 | struct GNUNET_CRYPTO_EccPrivateKey | ||
53 | { | ||
54 | |||
55 | /** | ||
56 | * Libgcrypt S-expression for the ECC key. | ||
57 | */ | ||
58 | gcry_sexp_t sexp; | ||
59 | }; | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Free memory occupied by ECC key | 56 | * Free memory occupied by ECC key |
64 | * | 57 | * |
65 | * @param privatekey pointer to the memory to free | 58 | * @param priv pointer to the memory to free |
66 | */ | 59 | */ |
67 | void | 60 | void |
68 | GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *privatekey) | 61 | GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *priv) |
69 | { | 62 | { |
70 | gcry_sexp_release (privatekey->sexp); | 63 | GNUNET_free (priv); |
71 | GNUNET_free (privatekey); | ||
72 | } | 64 | } |
73 | 65 | ||
74 | 66 | ||
@@ -133,6 +125,141 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, | |||
133 | 125 | ||
134 | 126 | ||
135 | /** | 127 | /** |
128 | * If target != size, move target bytes to the end of the size-sized | ||
129 | * buffer and zero out the first target-size bytes. | ||
130 | * | ||
131 | * @param buf original buffer | ||
132 | * @param size number of bytes in the buffer | ||
133 | * @param target target size of the buffer | ||
134 | */ | ||
135 | static void | ||
136 | adjust (unsigned char *buf, | ||
137 | size_t size, | ||
138 | size_t target) | ||
139 | { | ||
140 | if (size < target) | ||
141 | { | ||
142 | memmove (&buf[target - size], buf, size); | ||
143 | memset (buf, 0, target - size); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | |||
148 | /** | ||
149 | * Output the given MPI value to the given buffer. | ||
150 | * | ||
151 | * @param buf where to output to | ||
152 | * @param size number of bytes in buf | ||
153 | * @param val value to write to buf | ||
154 | */ | ||
155 | static void | ||
156 | mpi_print (unsigned char *buf, | ||
157 | size_t size, | ||
158 | gcry_mpi_t val) | ||
159 | { | ||
160 | size_t rsize; | ||
161 | |||
162 | rsize = size; | ||
163 | GNUNET_assert (0 == | ||
164 | gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize, | ||
165 | val)); | ||
166 | adjust (buf, rsize, size); | ||
167 | } | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Convert data buffer into MPI value. | ||
172 | * | ||
173 | * @param result where to store MPI value (allocated) | ||
174 | * @param data raw data (GCRYMPI_FMT_USG) | ||
175 | * @param size number of bytes in data | ||
176 | */ | ||
177 | static void | ||
178 | mpi_scan (gcry_mpi_t *result, | ||
179 | const unsigned char *data, | ||
180 | size_t size) | ||
181 | { | ||
182 | int rc; | ||
183 | |||
184 | if (0 != (rc = gcry_mpi_scan (result, | ||
185 | GCRYMPI_FMT_USG, | ||
186 | data, size, &size))) | ||
187 | { | ||
188 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
189 | GNUNET_assert (0); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | |||
194 | /** | ||
195 | * Convert the given private key from the network format to the | ||
196 | * S-expression that can be used by libgcrypt. | ||
197 | * | ||
198 | * @param priv private key to decode | ||
199 | * @return NULL on error | ||
200 | */ | ||
201 | static gcry_sexp_t | ||
202 | decode_private_key (const struct GNUNET_CRYPTO_EccPrivateKey *priv) | ||
203 | { | ||
204 | gcry_sexp_t result; | ||
205 | gcry_mpi_t d; | ||
206 | size_t erroff; | ||
207 | int rc; | ||
208 | |||
209 | mpi_scan (&d, | ||
210 | priv->d, | ||
211 | sizeof (priv->d)); | ||
212 | rc = gcry_sexp_build (&result, &erroff, | ||
213 | "(private-key(ecdsa(curve \"" CURVE "\")(d %m)))", | ||
214 | d); | ||
215 | gcry_mpi_release (d); | ||
216 | if (0 != rc) | ||
217 | { | ||
218 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */ | ||
219 | GNUNET_assert (0); | ||
220 | } | ||
221 | #if EXTRA_CHECKS | ||
222 | if (0 != (rc = gcry_pk_testkey (result))) | ||
223 | { | ||
224 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); | ||
225 | GNUNET_assert (0); | ||
226 | } | ||
227 | #endif | ||
228 | return result; | ||
229 | } | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Initialize public key struct from the respective point | ||
234 | * on the curve. | ||
235 | * | ||
236 | * @param q point on curve | ||
237 | * @param pub public key struct to initialize | ||
238 | * @param ctx context to use for ECC operations | ||
239 | */ | ||
240 | static void | ||
241 | point_to_public_key (gcry_mpi_point_t q, | ||
242 | gcry_ctx_t ctx, | ||
243 | struct GNUNET_CRYPTO_EccPublicKey *pub) | ||
244 | { | ||
245 | gcry_mpi_t q_x; | ||
246 | gcry_mpi_t q_y; | ||
247 | |||
248 | q_x = gcry_mpi_new (256); | ||
249 | q_y = gcry_mpi_new (256); | ||
250 | if (gcry_mpi_ec_get_affine (q_x, q_y, q, ctx)) | ||
251 | { | ||
252 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0); | ||
253 | return; | ||
254 | } | ||
255 | mpi_print (pub->q_x, sizeof (pub->q_x), q_x); | ||
256 | mpi_print (pub->q_y, sizeof (pub->q_y), q_y); | ||
257 | gcry_mpi_release (q_x); | ||
258 | gcry_mpi_release (q_y); | ||
259 | } | ||
260 | |||
261 | |||
262 | /** | ||
136 | * Extract the public key for the given private key. | 263 | * Extract the public key for the given private key. |
137 | * | 264 | * |
138 | * @param priv the private key | 265 | * @param priv the private key |
@@ -140,26 +267,25 @@ key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, | |||
140 | */ | 267 | */ |
141 | void | 268 | void |
142 | GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv, | 269 | GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv, |
143 | struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub) | 270 | struct GNUNET_CRYPTO_EccPublicKey *pub) |
144 | { | 271 | { |
145 | gcry_mpi_t skey; | 272 | gcry_sexp_t sexp; |
146 | size_t size; | 273 | gcry_ctx_t ctx; |
274 | gcry_mpi_point_t q; | ||
147 | int rc; | 275 | int rc; |
148 | 276 | ||
149 | memset (pub, 0, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)); | 277 | sexp = decode_private_key (priv); |
150 | rc = key_from_sexp (&skey, priv->sexp, "public-key", "q"); | 278 | GNUNET_assert (NULL != sexp); |
151 | if (rc) | 279 | if (0 != (rc = gcry_mpi_ec_new (&ctx, sexp, NULL))) |
152 | rc = key_from_sexp (&skey, priv->sexp, "private-key", "q"); | 280 | { |
153 | if (rc) | 281 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ |
154 | rc = key_from_sexp (&skey, priv->sexp, "ecc", "q"); | 282 | return; |
155 | GNUNET_assert (0 == rc); | 283 | } |
156 | pub->size = htons (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)); | 284 | gcry_sexp_release (sexp); |
157 | size = GNUNET_CRYPTO_ECC_MAX_PUBLIC_KEY_LENGTH; | 285 | q = gcry_mpi_ec_get_point ("q", ctx, 0); |
158 | GNUNET_assert (0 == | 286 | point_to_public_key (q, ctx, pub); |
159 | gcry_mpi_print (GCRYMPI_FMT_USG, pub->key, size, &size, | 287 | gcry_ctx_release (ctx); |
160 | skey)); | 288 | gcry_mpi_point_release (q); |
161 | pub->len = htons (size); | ||
162 | gcry_mpi_release (skey); | ||
163 | } | 289 | } |
164 | 290 | ||
165 | 291 | ||
@@ -170,10 +296,10 @@ GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv | |||
170 | * @return string representing 'pub' | 296 | * @return string representing 'pub' |
171 | */ | 297 | */ |
172 | char * | 298 | char * |
173 | GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub) | 299 | GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKey *pub) |
174 | { | 300 | { |
175 | char *pubkeybuf; | 301 | char *pubkeybuf; |
176 | size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8; | 302 | size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKey)) * 8; |
177 | char *end; | 303 | char *end; |
178 | 304 | ||
179 | if (keylen % 5 > 0) | 305 | if (keylen % 5 > 0) |
@@ -181,7 +307,7 @@ GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyB | |||
181 | keylen /= 5; | 307 | keylen /= 5; |
182 | pubkeybuf = GNUNET_malloc (keylen + 1); | 308 | pubkeybuf = GNUNET_malloc (keylen + 1); |
183 | end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, | 309 | end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, |
184 | sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded), | 310 | sizeof (struct GNUNET_CRYPTO_EccPublicKey), |
185 | pubkeybuf, | 311 | pubkeybuf, |
186 | keylen); | 312 | keylen); |
187 | if (NULL == end) | 313 | if (NULL == end) |
@@ -205,9 +331,9 @@ GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKeyB | |||
205 | int | 331 | int |
206 | GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, | 332 | GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, |
207 | size_t enclen, | 333 | size_t enclen, |
208 | struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub) | 334 | struct GNUNET_CRYPTO_EccPublicKey *pub) |
209 | { | 335 | { |
210 | size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) * 8; | 336 | size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKey)) * 8; |
211 | 337 | ||
212 | if (keylen % 5 > 0) | 338 | if (keylen % 5 > 0) |
213 | keylen += 5 - keylen % 5; | 339 | keylen += 5 - keylen % 5; |
@@ -217,10 +343,7 @@ GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, | |||
217 | 343 | ||
218 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen, | 344 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen, |
219 | pub, | 345 | pub, |
220 | sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded))) | 346 | sizeof (struct GNUNET_CRYPTO_EccPublicKey))) |
221 | return GNUNET_SYSERR; | ||
222 | if ( (ntohs (pub->size) != sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded)) || | ||
223 | (ntohs (pub->len) > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH) ) | ||
224 | return GNUNET_SYSERR; | 347 | return GNUNET_SYSERR; |
225 | return GNUNET_OK; | 348 | return GNUNET_OK; |
226 | } | 349 | } |
@@ -230,137 +353,46 @@ GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc, | |||
230 | * Convert the given public key from the network format to the | 353 | * Convert the given public key from the network format to the |
231 | * S-expression that can be used by libgcrypt. | 354 | * S-expression that can be used by libgcrypt. |
232 | * | 355 | * |
233 | * @param publicKey public key to decode | 356 | * @param pub public key to decode |
234 | * @return NULL on error | 357 | * @return NULL on error |
235 | */ | 358 | */ |
236 | static gcry_sexp_t | 359 | static gcry_sexp_t |
237 | decode_public_key (const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *publicKey) | 360 | decode_public_key (const struct GNUNET_CRYPTO_EccPublicKey *pub) |
238 | { | 361 | { |
239 | gcry_sexp_t result; | 362 | gcry_sexp_t pub_sexp; |
240 | gcry_mpi_t q; | 363 | gcry_mpi_t q_x; |
241 | size_t size; | 364 | gcry_mpi_t q_y; |
242 | size_t erroff; | 365 | gcry_mpi_point_t q; |
366 | gcry_ctx_t ctx; | ||
243 | int rc; | 367 | int rc; |
244 | 368 | ||
245 | if (ntohs (publicKey->len) > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH) | 369 | mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x)); |
246 | { | 370 | mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y)); |
247 | GNUNET_break (0); | 371 | q = gcry_mpi_point_new (256); |
248 | return NULL; | 372 | gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE); |
249 | } | 373 | gcry_mpi_release (q_x); |
250 | size = ntohs (publicKey->len); | 374 | gcry_mpi_release (q_y); |
251 | if (0 != (rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, publicKey->key, size, &size))) | ||
252 | { | ||
253 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
254 | return NULL; | ||
255 | } | ||
256 | |||
257 | rc = gcry_sexp_build (&result, &erroff, | ||
258 | "(public-key(ecdsa(curve \"" CURVE "\")(q %m)))", | ||
259 | q); | ||
260 | gcry_mpi_release (q); | ||
261 | if (0 != rc) | ||
262 | { | ||
263 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */ | ||
264 | return NULL; | ||
265 | } | ||
266 | #if EXTRA_CHECKS | ||
267 | if (0 != (rc = gcry_pk_testkey (result))) | ||
268 | { | ||
269 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); | ||
270 | gcry_sexp_release (result); | ||
271 | return NULL; | ||
272 | } | ||
273 | #endif | ||
274 | return result; | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Encode the private key in a format suitable for | ||
280 | * storing it into a file. | ||
281 | * | ||
282 | * @param key key to encode | ||
283 | * @return encoding of the private key. | ||
284 | * The first 4 bytes give the size of the array, as usual. | ||
285 | */ | ||
286 | struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded * | ||
287 | GNUNET_CRYPTO_ecc_encode_key (const struct GNUNET_CRYPTO_EccPrivateKey *key) | ||
288 | { | ||
289 | struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *retval; | ||
290 | char buf[65536]; | ||
291 | uint16_t be; | ||
292 | size_t size; | ||
293 | |||
294 | #if EXTRA_CHECKS | ||
295 | if (0 != gcry_pk_testkey (key->sexp)) | ||
296 | { | ||
297 | GNUNET_break (0); | ||
298 | return NULL; | ||
299 | } | ||
300 | #endif | ||
301 | size = gcry_sexp_sprint (key->sexp, | ||
302 | GCRYSEXP_FMT_DEFAULT, | ||
303 | &buf[2], sizeof (buf) - sizeof (uint16_t)); | ||
304 | if (0 == size) | ||
305 | { | ||
306 | GNUNET_break (0); | ||
307 | return NULL; | ||
308 | } | ||
309 | GNUNET_assert (size < 65536 - sizeof (uint16_t)); | ||
310 | be = htons ((uint16_t) size + (sizeof (be))); | ||
311 | memcpy (buf, &be, sizeof (be)); | ||
312 | size += sizeof (be); | ||
313 | retval = GNUNET_malloc (size); | ||
314 | memcpy (retval, buf, size); | ||
315 | return retval; | ||
316 | } | ||
317 | |||
318 | |||
319 | /** | ||
320 | * Decode the private key from the file-format back | ||
321 | * to the "normal", internal format. | ||
322 | * | ||
323 | * @param buf the buffer where the private key data is stored | ||
324 | * @param len the length of the data in 'buffer' | ||
325 | * @param validate GNUNET_YES to validate that the key is well-formed, | ||
326 | * GNUNET_NO if the key comes from a totally trusted source | ||
327 | * and validation is considered too expensive | ||
328 | * @return NULL on error | ||
329 | */ | ||
330 | struct GNUNET_CRYPTO_EccPrivateKey * | ||
331 | GNUNET_CRYPTO_ecc_decode_key (const char *buf, | ||
332 | size_t len, | ||
333 | int validate) | ||
334 | { | ||
335 | struct GNUNET_CRYPTO_EccPrivateKey *ret; | ||
336 | uint16_t be; | ||
337 | gcry_sexp_t sexp; | ||
338 | int rc; | ||
339 | size_t erroff; | ||
340 | 375 | ||
341 | if (len < sizeof (uint16_t)) | 376 | /* create basic ECC context */ |
342 | return NULL; | 377 | if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE))) |
343 | memcpy (&be, buf, sizeof (be)); | ||
344 | if (len < ntohs (be)) | ||
345 | return NULL; | ||
346 | len = ntohs (be); | ||
347 | if (0 != (rc = gcry_sexp_sscan (&sexp, | ||
348 | &erroff, | ||
349 | &buf[2], | ||
350 | len - sizeof (uint16_t)))) | ||
351 | { | 378 | { |
352 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_scan", rc); | 379 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ |
380 | gcry_mpi_point_release (q); | ||
353 | return NULL; | 381 | return NULL; |
354 | } | 382 | } |
355 | if ( (GNUNET_YES == validate) && | 383 | /* initialize 'ctx' with 'q' */ |
356 | (0 != (rc = gcry_pk_testkey (sexp))) ) | 384 | gcry_mpi_ec_set_point ("q", q, ctx); |
385 | gcry_mpi_point_release (q); | ||
386 | |||
387 | /* convert 'ctx' to 'sexp' */ | ||
388 | if (0 != (rc = gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx))) | ||
357 | { | 389 | { |
358 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); | 390 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc); |
391 | gcry_ctx_release (ctx); | ||
359 | return NULL; | 392 | return NULL; |
360 | } | 393 | } |
361 | ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey)); | 394 | gcry_ctx_release (ctx); |
362 | ret->sexp = sexp; | 395 | return pub_sexp; |
363 | return ret; | ||
364 | } | 396 | } |
365 | 397 | ||
366 | 398 | ||
@@ -372,9 +404,10 @@ GNUNET_CRYPTO_ecc_decode_key (const char *buf, | |||
372 | struct GNUNET_CRYPTO_EccPrivateKey * | 404 | struct GNUNET_CRYPTO_EccPrivateKey * |
373 | GNUNET_CRYPTO_ecc_key_create () | 405 | GNUNET_CRYPTO_ecc_key_create () |
374 | { | 406 | { |
375 | struct GNUNET_CRYPTO_EccPrivateKey *ret; | 407 | struct GNUNET_CRYPTO_EccPrivateKey *priv; |
376 | gcry_sexp_t s_key; | 408 | gcry_sexp_t priv_sexp; |
377 | gcry_sexp_t s_keyparam; | 409 | gcry_sexp_t s_keyparam; |
410 | gcry_mpi_t d; | ||
378 | int rc; | 411 | int rc; |
379 | 412 | ||
380 | if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL, | 413 | if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL, |
@@ -383,7 +416,7 @@ GNUNET_CRYPTO_ecc_key_create () | |||
383 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); | 416 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); |
384 | return NULL; | 417 | return NULL; |
385 | } | 418 | } |
386 | if (0 != (rc = gcry_pk_genkey (&s_key, s_keyparam))) | 419 | if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam))) |
387 | { | 420 | { |
388 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc); | 421 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc); |
389 | gcry_sexp_release (s_keyparam); | 422 | gcry_sexp_release (s_keyparam); |
@@ -391,16 +424,24 @@ GNUNET_CRYPTO_ecc_key_create () | |||
391 | } | 424 | } |
392 | gcry_sexp_release (s_keyparam); | 425 | gcry_sexp_release (s_keyparam); |
393 | #if EXTRA_CHECKS | 426 | #if EXTRA_CHECKS |
394 | if (0 != (rc = gcry_pk_testkey (s_key))) | 427 | if (0 != (rc = gcry_pk_testkey (priv_sexp))) |
395 | { | 428 | { |
396 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); | 429 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); |
397 | gcry_sexp_release (s_key); | 430 | gcry_sexp_release (priv_sexp); |
398 | return NULL; | 431 | return NULL; |
399 | } | 432 | } |
400 | #endif | 433 | #endif |
401 | ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey)); | 434 | if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d"))) |
402 | ret->sexp = s_key; | 435 | { |
403 | return ret; | 436 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc); |
437 | gcry_sexp_release (priv_sexp); | ||
438 | return NULL; | ||
439 | } | ||
440 | gcry_sexp_release (priv_sexp); | ||
441 | priv = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey)); | ||
442 | mpi_print (priv->d, sizeof (priv->d), d); | ||
443 | gcry_mpi_release (d); | ||
444 | return priv; | ||
404 | } | 445 | } |
405 | 446 | ||
406 | 447 | ||
@@ -438,15 +479,11 @@ short_wait () | |||
438 | struct GNUNET_CRYPTO_EccPrivateKey * | 479 | struct GNUNET_CRYPTO_EccPrivateKey * |
439 | GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | 480 | GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) |
440 | { | 481 | { |
441 | struct GNUNET_CRYPTO_EccPrivateKey *ret; | 482 | struct GNUNET_CRYPTO_EccPrivateKey *priv; |
442 | struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc; | ||
443 | uint16_t len; | ||
444 | struct GNUNET_DISK_FileHandle *fd; | 483 | struct GNUNET_DISK_FileHandle *fd; |
445 | unsigned int cnt; | 484 | unsigned int cnt; |
446 | int ec; | 485 | int ec; |
447 | uint64_t fs; | 486 | uint64_t fs; |
448 | struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub; | ||
449 | struct GNUNET_PeerIdentity pid; | ||
450 | 487 | ||
451 | if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) | 488 | if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) |
452 | return NULL; | 489 | return NULL; |
@@ -479,7 +516,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
479 | 516 | ||
480 | while (GNUNET_YES != | 517 | while (GNUNET_YES != |
481 | GNUNET_DISK_file_lock (fd, 0, | 518 | GNUNET_DISK_file_lock (fd, 0, |
482 | sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded), | 519 | sizeof (struct GNUNET_CRYPTO_EccPrivateKey), |
483 | GNUNET_YES)) | 520 | GNUNET_YES)) |
484 | { | 521 | { |
485 | short_wait (); | 522 | short_wait (); |
@@ -493,23 +530,17 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
493 | } | 530 | } |
494 | LOG (GNUNET_ERROR_TYPE_INFO, | 531 | LOG (GNUNET_ERROR_TYPE_INFO, |
495 | _("Creating a new private key. This may take a while.\n")); | 532 | _("Creating a new private key. This may take a while.\n")); |
496 | ret = GNUNET_CRYPTO_ecc_key_create (); | 533 | priv = GNUNET_CRYPTO_ecc_key_create (); |
497 | GNUNET_assert (ret != NULL); | 534 | GNUNET_assert (NULL != priv); |
498 | enc = GNUNET_CRYPTO_ecc_encode_key (ret); | 535 | GNUNET_assert (sizeof (*priv) == |
499 | GNUNET_assert (enc != NULL); | 536 | GNUNET_DISK_file_write (fd, priv, sizeof (*priv))); |
500 | GNUNET_assert (ntohs (enc->size) == | ||
501 | GNUNET_DISK_file_write (fd, enc, ntohs (enc->size))); | ||
502 | GNUNET_free (enc); | ||
503 | |||
504 | GNUNET_DISK_file_sync (fd); | 537 | GNUNET_DISK_file_sync (fd); |
505 | if (GNUNET_YES != | 538 | if (GNUNET_YES != |
506 | GNUNET_DISK_file_unlock (fd, 0, | 539 | GNUNET_DISK_file_unlock (fd, 0, |
507 | sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) | 540 | sizeof (struct GNUNET_CRYPTO_EccPrivateKey))) |
508 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); | 541 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); |
509 | GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); | 542 | GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); |
510 | GNUNET_CRYPTO_ecc_key_get_public (ret, &pub); | 543 | return priv; |
511 | GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); | ||
512 | return ret; | ||
513 | } | 544 | } |
514 | /* key file exists already, read it! */ | 545 | /* key file exists already, read it! */ |
515 | fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, | 546 | fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, |
@@ -524,7 +555,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
524 | { | 555 | { |
525 | if (GNUNET_YES != | 556 | if (GNUNET_YES != |
526 | GNUNET_DISK_file_lock (fd, 0, | 557 | GNUNET_DISK_file_lock (fd, 0, |
527 | sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded), | 558 | sizeof (struct GNUNET_CRYPTO_EccPrivateKey), |
528 | GNUNET_NO)) | 559 | GNUNET_NO)) |
529 | { | 560 | { |
530 | if (0 == ++cnt % 60) | 561 | if (0 == ++cnt % 60) |
@@ -546,7 +577,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
546 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename); | 577 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename); |
547 | if (GNUNET_YES != | 578 | if (GNUNET_YES != |
548 | GNUNET_DISK_file_unlock (fd, 0, | 579 | GNUNET_DISK_file_unlock (fd, 0, |
549 | sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) | 580 | sizeof (struct GNUNET_CRYPTO_EccPrivateKey))) |
550 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); | 581 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); |
551 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); | 582 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); |
552 | 583 | ||
@@ -554,13 +585,13 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
554 | } | 585 | } |
555 | if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) | 586 | if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) |
556 | fs = 0; | 587 | fs = 0; |
557 | if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)) | 588 | if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKey)) |
558 | { | 589 | { |
559 | /* maybe we got the read lock before the key generating | 590 | /* maybe we got the read lock before the key generating |
560 | * process had a chance to get the write lock; give it up! */ | 591 | * process had a chance to get the write lock; give it up! */ |
561 | if (GNUNET_YES != | 592 | if (GNUNET_YES != |
562 | GNUNET_DISK_file_unlock (fd, 0, | 593 | GNUNET_DISK_file_unlock (fd, 0, |
563 | sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) | 594 | sizeof (struct GNUNET_CRYPTO_EccPrivateKey))) |
564 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); | 595 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); |
565 | if (0 == ++cnt % 10) | 596 | if (0 == ++cnt % 10) |
566 | { | 597 | { |
@@ -568,7 +599,7 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
568 | _ | 599 | _ |
569 | ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"), | 600 | ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"), |
570 | filename, (unsigned int) fs, | 601 | filename, (unsigned int) fs, |
571 | (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)); | 602 | (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKey)); |
572 | LOG (GNUNET_ERROR_TYPE_ERROR, | 603 | LOG (GNUNET_ERROR_TYPE_ERROR, |
573 | _ | 604 | _ |
574 | ("This may be ok if someone is currently generating a key.\n")); | 605 | ("This may be ok if someone is currently generating a key.\n")); |
@@ -578,33 +609,15 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
578 | } | 609 | } |
579 | break; | 610 | break; |
580 | } | 611 | } |
581 | enc = GNUNET_malloc (fs); | 612 | fs = sizeof (struct GNUNET_CRYPTO_EccPrivateKey); |
582 | GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs)); | 613 | priv = GNUNET_malloc (fs); |
583 | len = ntohs (enc->size); | 614 | GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs)); |
584 | ret = NULL; | ||
585 | if ((len > fs) || | ||
586 | (NULL == (ret = GNUNET_CRYPTO_ecc_decode_key ((char *) enc, len, GNUNET_YES)))) | ||
587 | { | ||
588 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
589 | _("File `%s' does not contain a valid private key. Deleting it.\n"), | ||
590 | filename); | ||
591 | if (0 != UNLINK (filename)) | ||
592 | { | ||
593 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename); | ||
594 | } | ||
595 | } | ||
596 | GNUNET_free (enc); | ||
597 | if (GNUNET_YES != | 615 | if (GNUNET_YES != |
598 | GNUNET_DISK_file_unlock (fd, 0, | 616 | GNUNET_DISK_file_unlock (fd, 0, |
599 | sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded))) | 617 | sizeof (struct GNUNET_CRYPTO_EccPrivateKey))) |
600 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); | 618 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); |
601 | GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); | 619 | GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); |
602 | if (ret != NULL) | 620 | return priv; |
603 | { | ||
604 | GNUNET_CRYPTO_ecc_key_get_public (ret, &pub); | ||
605 | GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey); | ||
606 | } | ||
607 | return ret; | ||
608 | } | 621 | } |
609 | 622 | ||
610 | 623 | ||
@@ -618,15 +631,15 @@ GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename) | |||
618 | struct GNUNET_CRYPTO_EccPrivateKey * | 631 | struct GNUNET_CRYPTO_EccPrivateKey * |
619 | GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg) | 632 | GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg) |
620 | { | 633 | { |
621 | struct GNUNET_CRYPTO_EccPrivateKey *pk; | 634 | struct GNUNET_CRYPTO_EccPrivateKey *priv; |
622 | char *fn; | 635 | char *fn; |
623 | 636 | ||
624 | if (GNUNET_OK != | 637 | if (GNUNET_OK != |
625 | GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn)) | 638 | GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn)) |
626 | return NULL; | 639 | return NULL; |
627 | pk = GNUNET_CRYPTO_ecc_key_create_from_file (fn); | 640 | priv = GNUNET_CRYPTO_ecc_key_create_from_file (fn); |
628 | GNUNET_free (fn); | 641 | GNUNET_free (fn); |
629 | return pk; | 642 | return priv; |
630 | } | 643 | } |
631 | 644 | ||
632 | 645 | ||
@@ -642,13 +655,13 @@ void | |||
642 | GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name) | 655 | GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name) |
643 | { | 656 | { |
644 | struct GNUNET_CONFIGURATION_Handle *cfg; | 657 | struct GNUNET_CONFIGURATION_Handle *cfg; |
645 | struct GNUNET_CRYPTO_EccPrivateKey *pk; | 658 | struct GNUNET_CRYPTO_EccPrivateKey *priv; |
646 | 659 | ||
647 | cfg = GNUNET_CONFIGURATION_create (); | 660 | cfg = GNUNET_CONFIGURATION_create (); |
648 | (void) GNUNET_CONFIGURATION_load (cfg, cfg_name); | 661 | (void) GNUNET_CONFIGURATION_load (cfg, cfg_name); |
649 | pk = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg); | 662 | priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg); |
650 | if (NULL != pk) | 663 | if (NULL != priv) |
651 | GNUNET_CRYPTO_ecc_key_free (pk); | 664 | GNUNET_CRYPTO_ecc_key_free (priv); |
652 | GNUNET_CONFIGURATION_destroy (cfg); | 665 | GNUNET_CONFIGURATION_destroy (cfg); |
653 | } | 666 | } |
654 | 667 | ||
@@ -665,18 +678,18 @@ int | |||
665 | GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, | 678 | GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, |
666 | struct GNUNET_PeerIdentity *dst) | 679 | struct GNUNET_PeerIdentity *dst) |
667 | { | 680 | { |
668 | struct GNUNET_CRYPTO_EccPrivateKey *my_private_key; | 681 | struct GNUNET_CRYPTO_EccPrivateKey *priv; |
669 | struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded my_public_key; | 682 | struct GNUNET_CRYPTO_EccPublicKey pub; |
670 | 683 | ||
671 | if (NULL == (my_private_key = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg))) | 684 | if (NULL == (priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg))) |
672 | { | 685 | { |
673 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 686 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
674 | _("Could not load peer's private key\n")); | 687 | _("Could not load peer's private key\n")); |
675 | return GNUNET_SYSERR; | 688 | return GNUNET_SYSERR; |
676 | } | 689 | } |
677 | GNUNET_CRYPTO_ecc_key_get_public (my_private_key, &my_public_key); | 690 | GNUNET_CRYPTO_ecc_key_get_public (priv, &pub); |
678 | GNUNET_CRYPTO_ecc_key_free (my_private_key); | 691 | GNUNET_CRYPTO_ecc_key_free (priv); |
679 | GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &dst->hashPubKey); | 692 | GNUNET_CRYPTO_hash (&pub, sizeof (pub), &dst->hashPubKey); |
680 | return GNUNET_OK; | 693 | return GNUNET_OK; |
681 | } | 694 | } |
682 | 695 | ||
@@ -692,24 +705,19 @@ static gcry_sexp_t | |||
692 | data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) | 705 | data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) |
693 | { | 706 | { |
694 | struct GNUNET_CRYPTO_ShortHashCode hc; | 707 | struct GNUNET_CRYPTO_ShortHashCode hc; |
695 | size_t bufSize; | ||
696 | gcry_sexp_t data; | 708 | gcry_sexp_t data; |
709 | int rc; | ||
697 | 710 | ||
698 | GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc); | 711 | GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc); |
699 | #define FORMATSTRING "(4:data(5:flags3:raw)(5:value32:01234567890123456789012345678901))" | 712 | if (0 != (rc = gcry_sexp_build (&data, NULL, |
700 | bufSize = strlen (FORMATSTRING) + 1; | 713 | "(data(flags rfc6979)(hash %s %b))", |
714 | "sha256", | ||
715 | sizeof (hc), | ||
716 | &hc))) | ||
701 | { | 717 | { |
702 | char buff[bufSize]; | 718 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); |
703 | 719 | return NULL; | |
704 | memcpy (buff, FORMATSTRING, bufSize); | ||
705 | memcpy (&buff | ||
706 | [bufSize - | ||
707 | strlen | ||
708 | ("01234567890123456789012345678901))") | ||
709 | - 1], &hc, sizeof (struct GNUNET_CRYPTO_ShortHashCode)); | ||
710 | GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0)); | ||
711 | } | 720 | } |
712 | #undef FORMATSTRING | ||
713 | return data; | 721 | return data; |
714 | } | 722 | } |
715 | 723 | ||
@@ -717,44 +725,49 @@ data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) | |||
717 | /** | 725 | /** |
718 | * Sign a given block. | 726 | * Sign a given block. |
719 | * | 727 | * |
720 | * @param key private key to use for the signing | 728 | * @param priv private key to use for the signing |
721 | * @param purpose what to sign (size, purpose) | 729 | * @param purpose what to sign (size, purpose) |
722 | * @param sig where to write the signature | 730 | * @param sig where to write the signature |
723 | * @return GNUNET_SYSERR on error, GNUNET_OK on success | 731 | * @return GNUNET_SYSERR on error, GNUNET_OK on success |
724 | */ | 732 | */ |
725 | int | 733 | int |
726 | GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key, | 734 | GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *priv, |
727 | const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, | 735 | const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, |
728 | struct GNUNET_CRYPTO_EccSignature *sig) | 736 | struct GNUNET_CRYPTO_EccSignature *sig) |
729 | { | 737 | { |
730 | gcry_sexp_t result; | 738 | gcry_sexp_t priv_sexp; |
739 | gcry_sexp_t sig_sexp; | ||
731 | gcry_sexp_t data; | 740 | gcry_sexp_t data; |
732 | size_t ssize; | ||
733 | int rc; | 741 | int rc; |
742 | gcry_mpi_t rs[2]; | ||
734 | 743 | ||
744 | priv_sexp = decode_private_key (priv); | ||
735 | data = data_to_pkcs1 (purpose); | 745 | data = data_to_pkcs1 (purpose); |
736 | if (0 != (rc = gcry_pk_sign (&result, data, key->sexp))) | 746 | if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp))) |
737 | { | 747 | { |
738 | LOG (GNUNET_ERROR_TYPE_WARNING, | 748 | LOG (GNUNET_ERROR_TYPE_WARNING, |
739 | _("ECC signing failed at %s:%d: %s\n"), __FILE__, | 749 | _("ECC signing failed at %s:%d: %s\n"), __FILE__, |
740 | __LINE__, gcry_strerror (rc)); | 750 | __LINE__, gcry_strerror (rc)); |
741 | gcry_sexp_release (data); | 751 | gcry_sexp_release (data); |
752 | gcry_sexp_release (priv_sexp); | ||
742 | return GNUNET_SYSERR; | 753 | return GNUNET_SYSERR; |
743 | } | 754 | } |
755 | gcry_sexp_release (priv_sexp); | ||
744 | gcry_sexp_release (data); | 756 | gcry_sexp_release (data); |
745 | ssize = gcry_sexp_sprint (result, | 757 | |
746 | GCRYSEXP_FMT_DEFAULT, | 758 | /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in |
747 | sig->sexpr, | 759 | 'signature' */ |
748 | GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH); | 760 | if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs"))) |
749 | if (0 == ssize) | ||
750 | { | 761 | { |
751 | GNUNET_break (0); | 762 | GNUNET_break (0); |
763 | gcry_sexp_release (sig_sexp); | ||
752 | return GNUNET_SYSERR; | 764 | return GNUNET_SYSERR; |
753 | } | 765 | } |
754 | sig->size = htons ((uint16_t) (ssize + sizeof (uint16_t))); | 766 | gcry_sexp_release (sig_sexp); |
755 | /* padd with zeros */ | 767 | mpi_print (sig->r, sizeof (sig->r), rs[0]); |
756 | memset (&sig->sexpr[ssize], 0, GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH - ssize); | 768 | mpi_print (sig->s, sizeof (sig->s), rs[1]); |
757 | gcry_sexp_release (result); | 769 | gcry_mpi_release (rs[0]); |
770 | gcry_mpi_release (rs[1]); | ||
758 | return GNUNET_OK; | 771 | return GNUNET_OK; |
759 | } | 772 | } |
760 | 773 | ||
@@ -765,7 +778,7 @@ GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *key, | |||
765 | * @param purpose what is the purpose that the signature should have? | 778 | * @param purpose what is the purpose that the signature should have? |
766 | * @param validate block to validate (size, purpose, data) | 779 | * @param validate block to validate (size, purpose, data) |
767 | * @param sig signature that is being validated | 780 | * @param sig signature that is being validated |
768 | * @param publicKey public key of the signer | 781 | * @param pub public key of the signer |
769 | * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid | 782 | * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid |
770 | */ | 783 | */ |
771 | int | 784 | int |
@@ -773,36 +786,43 @@ GNUNET_CRYPTO_ecc_verify (uint32_t purpose, | |||
773 | const struct GNUNET_CRYPTO_EccSignaturePurpose | 786 | const struct GNUNET_CRYPTO_EccSignaturePurpose |
774 | *validate, | 787 | *validate, |
775 | const struct GNUNET_CRYPTO_EccSignature *sig, | 788 | const struct GNUNET_CRYPTO_EccSignature *sig, |
776 | const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded | 789 | const struct GNUNET_CRYPTO_EccPublicKey *pub) |
777 | *publicKey) | ||
778 | { | 790 | { |
779 | gcry_sexp_t data; | 791 | gcry_sexp_t data; |
780 | gcry_sexp_t sigdata; | 792 | gcry_sexp_t sig_sexpr; |
781 | size_t size; | 793 | gcry_sexp_t pub_sexpr; |
782 | gcry_sexp_t psexp; | ||
783 | size_t erroff; | 794 | size_t erroff; |
784 | int rc; | 795 | int rc; |
796 | gcry_mpi_t r; | ||
797 | gcry_mpi_t s; | ||
785 | 798 | ||
786 | if (purpose != ntohl (validate->purpose)) | 799 | if (purpose != ntohl (validate->purpose)) |
787 | return GNUNET_SYSERR; /* purpose mismatch */ | 800 | return GNUNET_SYSERR; /* purpose mismatch */ |
788 | size = ntohs (sig->size); | 801 | |
789 | if ( (size < sizeof (uint16_t)) || | 802 | /* build s-expression for signature */ |
790 | (size > GNUNET_CRYPTO_ECC_SIGNATURE_DATA_ENCODING_LENGTH - sizeof (uint16_t)) ) | 803 | mpi_scan (&r, sig->r, sizeof (sig->r)); |
791 | return GNUNET_SYSERR; /* size out of range */ | 804 | mpi_scan (&s, sig->s, sizeof (sig->s)); |
805 | if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))", | ||
806 | r, s))) | ||
807 | { | ||
808 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); | ||
809 | gcry_mpi_release (r); | ||
810 | gcry_mpi_release (s); | ||
811 | return GNUNET_SYSERR; | ||
812 | } | ||
813 | gcry_mpi_release (r); | ||
814 | gcry_mpi_release (s); | ||
792 | data = data_to_pkcs1 (validate); | 815 | data = data_to_pkcs1 (validate); |
793 | GNUNET_assert (0 == | 816 | if (! (pub_sexpr = decode_public_key (pub))) |
794 | gcry_sexp_sscan (&sigdata, &erroff, | ||
795 | sig->sexpr, size - sizeof (uint16_t))); | ||
796 | if (! (psexp = decode_public_key (publicKey))) | ||
797 | { | 817 | { |
798 | gcry_sexp_release (data); | 818 | gcry_sexp_release (data); |
799 | gcry_sexp_release (sigdata); | 819 | gcry_sexp_release (sig_sexpr); |
800 | return GNUNET_SYSERR; | 820 | return GNUNET_SYSERR; |
801 | } | 821 | } |
802 | rc = gcry_pk_verify (sigdata, data, psexp); | 822 | rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr); |
803 | gcry_sexp_release (psexp); | 823 | gcry_sexp_release (pub_sexpr); |
804 | gcry_sexp_release (data); | 824 | gcry_sexp_release (data); |
805 | gcry_sexp_release (sigdata); | 825 | gcry_sexp_release (sig_sexpr); |
806 | if (0 != rc) | 826 | if (0 != rc) |
807 | { | 827 | { |
808 | LOG (GNUNET_ERROR_TYPE_WARNING, | 828 | LOG (GNUNET_ERROR_TYPE_WARNING, |
@@ -817,14 +837,14 @@ GNUNET_CRYPTO_ecc_verify (uint32_t purpose, | |||
817 | /** | 837 | /** |
818 | * Derive key material from a public and a private ECC key. | 838 | * Derive key material from a public and a private ECC key. |
819 | * | 839 | * |
820 | * @param key private key to use for the ECDH (x) | 840 | * @param priv private key to use for the ECDH (x) |
821 | * @param pub public key to use for the ECDY (yG) | 841 | * @param pub public key to use for the ECDH (yG) |
822 | * @param key_material where to write the key material (xyG) | 842 | * @param key_material where to write the key material (xyG) |
823 | * @return GNUNET_SYSERR on error, GNUNET_OK on success | 843 | * @return GNUNET_SYSERR on error, GNUNET_OK on success |
824 | */ | 844 | */ |
825 | int | 845 | int |
826 | GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key, | 846 | GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *priv, |
827 | const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub, | 847 | const struct GNUNET_CRYPTO_EccPublicKey *pub, |
828 | struct GNUNET_HashCode *key_material) | 848 | struct GNUNET_HashCode *key_material) |
829 | { | 849 | { |
830 | size_t slen; | 850 | size_t slen; |
@@ -835,36 +855,29 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key, | |||
835 | gcry_mpi_point_t q; | 855 | gcry_mpi_point_t q; |
836 | gcry_mpi_t d; | 856 | gcry_mpi_t d; |
837 | gcry_ctx_t ctx; | 857 | gcry_ctx_t ctx; |
838 | gcry_sexp_t psexp; | 858 | gcry_sexp_t pub_sexpr; |
859 | gcry_sexp_t ecdh_sexp; | ||
839 | gcry_mpi_t result_x; | 860 | gcry_mpi_t result_x; |
840 | gcry_mpi_t result_y; | 861 | gcry_mpi_t result_y; |
841 | 862 | ||
842 | /* first, extract the q = dP value from the public key */ | 863 | /* first, extract the q = dP value from the public key */ |
843 | if (! (psexp = decode_public_key (pub))) | 864 | if (! (pub_sexpr = decode_public_key (pub))) |
844 | return GNUNET_SYSERR; | 865 | return GNUNET_SYSERR; |
845 | if (0 != (rc = gcry_mpi_ec_new (&ctx, psexp, NULL))) | 866 | if (0 != (rc = gcry_mpi_ec_new (&ctx, pub_sexpr, NULL))) |
846 | { | 867 | { |
847 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ | 868 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ |
848 | return GNUNET_SYSERR; | 869 | return GNUNET_SYSERR; |
849 | } | 870 | } |
850 | gcry_sexp_release (psexp); | 871 | gcry_sexp_release (pub_sexpr); |
851 | q = gcry_mpi_ec_get_point ("q", ctx, 0); | 872 | q = gcry_mpi_ec_get_point ("q", ctx, 0); |
852 | gcry_ctx_release (ctx); | 873 | gcry_ctx_release (ctx); |
853 | 874 | ||
854 | /* second, extract the d value from our private key */ | 875 | /* second, extract the d value from our private key */ |
855 | rc = key_from_sexp (&d, key->sexp, "private-key", "d"); | 876 | mpi_scan (&d, priv->d, sizeof (priv->d)); |
856 | if (rc) | ||
857 | rc = key_from_sexp (&d, key->sexp, "ecc", "d"); | ||
858 | if (0 != rc) | ||
859 | { | ||
860 | GNUNET_break (0); | ||
861 | gcry_mpi_point_release (q); | ||
862 | return GNUNET_SYSERR; | ||
863 | } | ||
864 | 877 | ||
865 | /* create a new context for definitively the correct curve; | 878 | /* create a new context for definitively the correct curve; |
866 | theoretically the 'public_key' might not use the right curve */ | 879 | theoretically the 'public_key' might not use the right curve */ |
867 | if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, "NIST P-256"))) | 880 | if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE))) |
868 | { | 881 | { |
869 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ | 882 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */ |
870 | gcry_mpi_release (d); | 883 | gcry_mpi_release (d); |
@@ -891,7 +904,7 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key, | |||
891 | } | 904 | } |
892 | gcry_mpi_point_release (result); | 905 | gcry_mpi_point_release (result); |
893 | gcry_ctx_release (ctx); | 906 | gcry_ctx_release (ctx); |
894 | if (0 != (rc = gcry_sexp_build (&psexp, &erroff, | 907 | if (0 != (rc = gcry_sexp_build (&ecdh_sexp, &erroff, |
895 | "(dh-shared-secret (x %m)(y %m))", | 908 | "(dh-shared-secret (x %m)(y %m))", |
896 | result_x, | 909 | result_x, |
897 | result_y))) | 910 | result_y))) |
@@ -903,13 +916,135 @@ GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *key, | |||
903 | } | 916 | } |
904 | gcry_mpi_release (result_x); | 917 | gcry_mpi_release (result_x); |
905 | gcry_mpi_release (result_y); | 918 | gcry_mpi_release (result_y); |
906 | slen = gcry_sexp_sprint (psexp, GCRYSEXP_FMT_DEFAULT, sdata_buf, sizeof (sdata_buf)); | 919 | slen = gcry_sexp_sprint (ecdh_sexp, |
920 | GCRYSEXP_FMT_DEFAULT, | ||
921 | sdata_buf, sizeof (sdata_buf)); | ||
907 | GNUNET_assert (0 != slen); | 922 | GNUNET_assert (0 != slen); |
908 | gcry_sexp_release (psexp); | 923 | gcry_sexp_release (ecdh_sexp); |
909 | /* finally, get a string of the resulting S-expression and hash it to generate the key material */ | 924 | /* finally, get a string of the resulting S-expression and hash it |
925 | to generate the key material */ | ||
910 | GNUNET_CRYPTO_hash (sdata_buf, slen, key_material); | 926 | GNUNET_CRYPTO_hash (sdata_buf, slen, key_material); |
911 | return GNUNET_OK; | 927 | return GNUNET_OK; |
912 | } | 928 | } |
913 | 929 | ||
914 | 930 | ||
931 | /** | ||
932 | * Derive the 'h' value for key derivation, where | ||
933 | * 'h = H(l,P)'. | ||
934 | * | ||
935 | * @param pub public key for deriviation | ||
936 | * @param label label for deriviation | ||
937 | * @return h value | ||
938 | */ | ||
939 | static gcry_mpi_t | ||
940 | derive_h (const struct GNUNET_CRYPTO_EccPublicKey *pub, | ||
941 | const char *label) | ||
942 | { | ||
943 | gcry_mpi_t h; | ||
944 | struct GNUNET_HashCode hc; | ||
945 | |||
946 | GNUNET_CRYPTO_kdf (&hc, sizeof (hc), | ||
947 | "key-derivation", strlen ("key-derivation"), | ||
948 | pub, sizeof (*pub), | ||
949 | label, sizeof (label), | ||
950 | NULL, 0); | ||
951 | mpi_scan (&h, (unsigned char *) &hc, sizeof (hc)); | ||
952 | return h; | ||
953 | } | ||
954 | |||
955 | |||
956 | /** | ||
957 | * Derive a private key from a given private key and a label. | ||
958 | * Essentially calculates a private key 'd = H(l,P) * x mod n' | ||
959 | * where n is the size of the ECC group and P is the public | ||
960 | * key associated with the private key 'd'. | ||
961 | * | ||
962 | * @param priv original private key | ||
963 | * @param label label to use for key deriviation | ||
964 | * @return derived private key | ||
965 | */ | ||
966 | struct GNUNET_CRYPTO_EccPrivateKey * | ||
967 | GNUNET_CRYPTO_ecc_key_derive (const struct GNUNET_CRYPTO_EccPrivateKey *priv, | ||
968 | const char *label) | ||
969 | { | ||
970 | struct GNUNET_CRYPTO_EccPublicKey pub; | ||
971 | struct GNUNET_CRYPTO_EccPrivateKey *ret; | ||
972 | gcry_mpi_t h; | ||
973 | gcry_mpi_t x; | ||
974 | gcry_mpi_t d; | ||
975 | gcry_mpi_t n; | ||
976 | int rc; | ||
977 | |||
978 | GNUNET_CRYPTO_ecc_key_get_public (priv, &pub); | ||
979 | h = derive_h (&pub, label); | ||
980 | mpi_scan (&x, priv->d, sizeof (priv->d)); | ||
981 | /* initialize 'n' from P-256; hex copied from libgcrypt code */ | ||
982 | if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, | ||
983 | "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL))) | ||
984 | { | ||
985 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
986 | gcry_mpi_release (h); | ||
987 | return NULL; | ||
988 | } | ||
989 | d = gcry_mpi_new (256); | ||
990 | gcry_mpi_mulm (d, h, x, n); | ||
991 | gcry_mpi_release (h); | ||
992 | gcry_mpi_release (x); | ||
993 | gcry_mpi_release (n); | ||
994 | ret = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey); | ||
995 | mpi_print (ret->d, sizeof (ret->d), d); | ||
996 | gcry_mpi_release (d); | ||
997 | return ret; | ||
998 | } | ||
999 | |||
1000 | |||
1001 | /** | ||
1002 | * Derive a public key from a given public key and a label. | ||
1003 | * Essentially calculates a public key 'V = H(l,P) * P'. | ||
1004 | * | ||
1005 | * @param pub original public key | ||
1006 | * @param label label to use for key deriviation | ||
1007 | * @param result where to write the derived public key | ||
1008 | */ | ||
1009 | void | ||
1010 | GNUNET_CRYPTO_ecc_public_key_derive (const struct GNUNET_CRYPTO_EccPublicKey *pub, | ||
1011 | const char *label, | ||
1012 | struct GNUNET_CRYPTO_EccPublicKey *result) | ||
1013 | { | ||
1014 | gcry_mpi_t h; | ||
1015 | gcry_ctx_t ctx; | ||
1016 | gcry_mpi_t q_x; | ||
1017 | gcry_mpi_t q_y; | ||
1018 | gcry_mpi_point_t q; | ||
1019 | gcry_mpi_point_t v; | ||
1020 | int rc; | ||
1021 | |||
1022 | h = derive_h (pub, label); | ||
1023 | mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x)); | ||
1024 | mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y)); | ||
1025 | q = gcry_mpi_point_new (256); | ||
1026 | gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE); | ||
1027 | gcry_mpi_release (q_x); | ||
1028 | gcry_mpi_release (q_y); | ||
1029 | |||
1030 | /* create basic ECC context */ | ||
1031 | if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE))) | ||
1032 | { | ||
1033 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); | ||
1034 | gcry_mpi_point_release (q); | ||
1035 | gcry_mpi_release (h); | ||
1036 | return; | ||
1037 | } | ||
1038 | v = gcry_mpi_point_new (256); | ||
1039 | /* we could calculate 'h mod n' here first, but hopefully | ||
1040 | libgcrypt is smart enough to do that for us... */ | ||
1041 | gcry_mpi_ec_mul (v, h, q, ctx); | ||
1042 | gcry_mpi_release (h); | ||
1043 | gcry_mpi_point_release (q); | ||
1044 | point_to_public_key (v, ctx, result); | ||
1045 | gcry_mpi_point_release (v); | ||
1046 | gcry_ctx_release (ctx); | ||
1047 | } | ||
1048 | |||
1049 | |||
915 | /* end of crypto_ecc.c */ | 1050 | /* end of crypto_ecc.c */ |