diff options
Diffstat (limited to 'src/util/rsa.c')
-rw-r--r-- | src/util/rsa.c | 925 |
1 files changed, 925 insertions, 0 deletions
diff --git a/src/util/rsa.c b/src/util/rsa.c new file mode 100644 index 000000000..cde56be9e --- /dev/null +++ b/src/util/rsa.c | |||
@@ -0,0 +1,925 @@ | |||
1 | /* | ||
2 | This file is part of TALER | ||
3 | (C) 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | TALER is free software; you can redistribute it and/or modify it under the | ||
6 | terms of the GNU General Public License as published by the Free Software | ||
7 | Foundation; either version 3, or (at your option) any later version. | ||
8 | |||
9 | TALER is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||
11 | A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file util/rsa.c | ||
19 | * @brief RSA key management utilities. Most of the code here is taken from | ||
20 | * gnunet-0.9.5a | ||
21 | * @author Sree Harsha Totakura <sreeharsha@totakura.in> | ||
22 | * | ||
23 | * Authors of the gnunet code: | ||
24 | * Christian Grothoff | ||
25 | * Krista Bennett | ||
26 | * Gerd Knorr <kraxel@bytesex.org> | ||
27 | * Ioana Patrascu | ||
28 | * Tzvetan Horozov | ||
29 | */ | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gcrypt.h" | ||
33 | #include "gnunet/gnunet_util_lib.h" | ||
34 | #include "taler_rsa.h" | ||
35 | |||
36 | |||
37 | |||
38 | #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) | ||
39 | |||
40 | #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) | ||
41 | |||
42 | #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename) | ||
43 | |||
44 | /** | ||
45 | * Log an error message at log-level 'level' that indicates | ||
46 | * a failure of the command 'cmd' with the message given | ||
47 | * by gcry_strerror(rc). | ||
48 | */ | ||
49 | #define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0) | ||
50 | |||
51 | /** | ||
52 | * Shorthand to cleanup non null mpi data types | ||
53 | */ | ||
54 | #define mpi_release_non_null(mpi) \ | ||
55 | if (NULL != mpi) gcry_mpi_release (mpi); | ||
56 | |||
57 | /** | ||
58 | * The private information of an RSA key pair. | ||
59 | * NOTE: this must match the definition in crypto_ksk.c and gnunet-rsa.c! | ||
60 | */ | ||
61 | struct TALER_RSA_PrivateKey | ||
62 | { | ||
63 | /** | ||
64 | * Libgcrypt S-expression for the ECC key. | ||
65 | */ | ||
66 | gcry_sexp_t sexp; | ||
67 | }; | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Extract values from an S-expression. | ||
72 | * | ||
73 | * @param array where to store the result(s) | ||
74 | * @param sexp S-expression to parse | ||
75 | * @param topname top-level name in the S-expression that is of interest | ||
76 | * @param elems names of the elements to extract | ||
77 | * @return 0 on success | ||
78 | */ | ||
79 | static int | ||
80 | key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname, | ||
81 | const char *elems) | ||
82 | { | ||
83 | gcry_sexp_t list; | ||
84 | gcry_sexp_t l2; | ||
85 | const char *s; | ||
86 | unsigned int i; | ||
87 | unsigned int idx; | ||
88 | |||
89 | if (! (list = gcry_sexp_find_token (sexp, topname, 0))) | ||
90 | return 1; | ||
91 | l2 = gcry_sexp_cadr (list); | ||
92 | gcry_sexp_release (list); | ||
93 | list = l2; | ||
94 | if (! list) | ||
95 | return 2; | ||
96 | idx = 0; | ||
97 | for (s = elems; *s; s++, idx++) | ||
98 | { | ||
99 | if (! (l2 = gcry_sexp_find_token (list, s, 1))) | ||
100 | { | ||
101 | for (i = 0; i < idx; i++) | ||
102 | { | ||
103 | gcry_free (array[i]); | ||
104 | array[i] = NULL; | ||
105 | } | ||
106 | gcry_sexp_release (list); | ||
107 | return 3; /* required parameter not found */ | ||
108 | } | ||
109 | array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); | ||
110 | gcry_sexp_release (l2); | ||
111 | if (! array[idx]) | ||
112 | { | ||
113 | for (i = 0; i < idx; i++) | ||
114 | { | ||
115 | gcry_free (array[i]); | ||
116 | array[i] = NULL; | ||
117 | } | ||
118 | gcry_sexp_release (list); | ||
119 | return 4; /* required parameter is invalid */ | ||
120 | } | ||
121 | } | ||
122 | gcry_sexp_release (list); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * If target != size, move target bytes to the | ||
128 | * end of the size-sized buffer and zero out the | ||
129 | * 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, size_t size, size_t target) | ||
137 | { | ||
138 | if (size < target) | ||
139 | { | ||
140 | memmove (&buf[target - size], buf, size); | ||
141 | memset (buf, 0, target - size); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Create a new private key. Caller must free return value. | ||
148 | * | ||
149 | * @return fresh private key | ||
150 | */ | ||
151 | struct TALER_RSA_PrivateKey * | ||
152 | TALER_RSA_key_create () | ||
153 | { | ||
154 | struct TALER_RSA_PrivateKey *ret; | ||
155 | gcry_sexp_t s_key; | ||
156 | gcry_sexp_t s_keyparam; | ||
157 | |||
158 | GNUNET_assert (0 == | ||
159 | gcry_sexp_build (&s_keyparam, NULL, | ||
160 | "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))", | ||
161 | 2048)); | ||
162 | GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam)); | ||
163 | gcry_sexp_release (s_keyparam); | ||
164 | #if EXTRA_CHECKS | ||
165 | GNUNET_assert (0 == gcry_pk_testkey (s_key)); | ||
166 | #endif | ||
167 | ret = GNUNET_malloc (sizeof (struct TALER_RSA_PrivateKey)); | ||
168 | ret->sexp = s_key; | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Free memory occupied by the private key. | ||
175 | * | ||
176 | * @param key pointer to the memory to free | ||
177 | */ | ||
178 | void | ||
179 | TALER_RSA_key_free (struct TALER_RSA_PrivateKey *key) | ||
180 | { | ||
181 | gcry_sexp_release (key->sexp); | ||
182 | GNUNET_free (key); | ||
183 | } | ||
184 | |||
185 | |||
186 | /** | ||
187 | * Encode the private key in a format suitable for | ||
188 | * storing it into a file. | ||
189 | * @return encoding of the private key | ||
190 | */ | ||
191 | struct TALER_RSA_PrivateKeyBinaryEncoded * | ||
192 | TALER_RSA_encode_key (const struct TALER_RSA_PrivateKey *hostkey) | ||
193 | { | ||
194 | struct TALER_RSA_PrivateKeyBinaryEncoded *retval; | ||
195 | gcry_mpi_t pkv[6]; | ||
196 | void *pbu[6]; | ||
197 | size_t sizes[6]; | ||
198 | int rc; | ||
199 | int i; | ||
200 | int size; | ||
201 | |||
202 | #if EXTRA_CHECKS | ||
203 | if (gcry_pk_testkey (hostkey->sexp)) | ||
204 | { | ||
205 | GNUNET_break (0); | ||
206 | return NULL; | ||
207 | } | ||
208 | #endif | ||
209 | |||
210 | memset (pkv, 0, sizeof (gcry_mpi_t) * 6); | ||
211 | rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpqu"); | ||
212 | if (rc) | ||
213 | rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpqu"); | ||
214 | if (rc) | ||
215 | rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpq"); | ||
216 | if (rc) | ||
217 | rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpq"); | ||
218 | if (rc) | ||
219 | rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "ned"); | ||
220 | if (rc) | ||
221 | rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned"); | ||
222 | GNUNET_assert (0 == rc); | ||
223 | size = sizeof (struct TALER_RSA_PrivateKeyBinaryEncoded); | ||
224 | for (i = 0; i < 6; i++) | ||
225 | { | ||
226 | if (NULL != pkv[i]) | ||
227 | { | ||
228 | GNUNET_assert (0 == | ||
229 | gcry_mpi_aprint (GCRYMPI_FMT_USG, | ||
230 | (unsigned char **) &pbu[i], &sizes[i], | ||
231 | pkv[i])); | ||
232 | size += sizes[i]; | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | pbu[i] = NULL; | ||
237 | sizes[i] = 0; | ||
238 | } | ||
239 | } | ||
240 | GNUNET_assert (size < 65536); | ||
241 | retval = GNUNET_malloc (size); | ||
242 | retval->len = htons (size); | ||
243 | i = 0; | ||
244 | retval->sizen = htons (sizes[0]); | ||
245 | memcpy (&((char *) (&retval[1]))[i], pbu[0], sizes[0]); | ||
246 | i += sizes[0]; | ||
247 | retval->sizee = htons (sizes[1]); | ||
248 | memcpy (&((char *) (&retval[1]))[i], pbu[1], sizes[1]); | ||
249 | i += sizes[1]; | ||
250 | retval->sized = htons (sizes[2]); | ||
251 | memcpy (&((char *) (&retval[1]))[i], pbu[2], sizes[2]); | ||
252 | i += sizes[2]; | ||
253 | /* swap p and q! */ | ||
254 | retval->sizep = htons (sizes[4]); | ||
255 | memcpy (&((char *) (&retval[1]))[i], pbu[4], sizes[4]); | ||
256 | i += sizes[4]; | ||
257 | retval->sizeq = htons (sizes[3]); | ||
258 | memcpy (&((char *) (&retval[1]))[i], pbu[3], sizes[3]); | ||
259 | i += sizes[3]; | ||
260 | retval->sizedmp1 = htons (0); | ||
261 | retval->sizedmq1 = htons (0); | ||
262 | memcpy (&((char *) (&retval[1]))[i], pbu[5], sizes[5]); | ||
263 | for (i = 0; i < 6; i++) | ||
264 | { | ||
265 | if (pkv[i] != NULL) | ||
266 | gcry_mpi_release (pkv[i]); | ||
267 | if (pbu[i] != NULL) | ||
268 | free (pbu[i]); | ||
269 | } | ||
270 | return retval; | ||
271 | } | ||
272 | |||
273 | |||
274 | /** | ||
275 | * Extract the public key of the given private key. | ||
276 | * | ||
277 | * @param priv the private key | ||
278 | * @param pub where to write the public key | ||
279 | */ | ||
280 | void | ||
281 | TALER_RSA_key_get_public (const struct TALER_RSA_PrivateKey *priv, | ||
282 | struct TALER_RSA_PublicKeyBinaryEncoded *pub) | ||
283 | { | ||
284 | gcry_mpi_t skey[2]; | ||
285 | size_t size; | ||
286 | int rc; | ||
287 | |||
288 | rc = key_from_sexp (skey, priv->sexp, "public-key", "ne"); | ||
289 | if (0 != rc) | ||
290 | rc = key_from_sexp (skey, priv->sexp, "private-key", "ne"); | ||
291 | if (0 != rc) | ||
292 | rc = key_from_sexp (skey, priv->sexp, "rsa", "ne"); | ||
293 | GNUNET_assert (0 == rc); | ||
294 | pub->len = | ||
295 | htons (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded) - | ||
296 | sizeof (pub->padding)); | ||
297 | pub->sizen = htons (TALER_RSA_DATA_ENCODING_LENGTH); | ||
298 | pub->padding = 0; | ||
299 | size = TALER_RSA_DATA_ENCODING_LENGTH; | ||
300 | GNUNET_assert (0 == | ||
301 | gcry_mpi_print (GCRYMPI_FMT_USG, &pub->key[0], size, &size, | ||
302 | skey[0])); | ||
303 | adjust (&pub->key[0], size, TALER_RSA_DATA_ENCODING_LENGTH); | ||
304 | size = TALER_RSA_KEY_LENGTH - TALER_RSA_DATA_ENCODING_LENGTH; | ||
305 | GNUNET_assert (0 == | ||
306 | gcry_mpi_print (GCRYMPI_FMT_USG, | ||
307 | &pub->key | ||
308 | [TALER_RSA_DATA_ENCODING_LENGTH], size, | ||
309 | &size, skey[1])); | ||
310 | adjust (&pub->key[TALER_RSA_DATA_ENCODING_LENGTH], size, | ||
311 | TALER_RSA_KEY_LENGTH - | ||
312 | TALER_RSA_DATA_ENCODING_LENGTH); | ||
313 | gcry_mpi_release (skey[0]); | ||
314 | gcry_mpi_release (skey[1]); | ||
315 | } | ||
316 | |||
317 | |||
318 | /** | ||
319 | * Decode the private key from the data-format back | ||
320 | * to the "normal", internal format. | ||
321 | * | ||
322 | * @param buf the buffer where the private key data is stored | ||
323 | * @param len the length of the data in 'buffer' | ||
324 | * @return NULL on error | ||
325 | */ | ||
326 | struct TALER_RSA_PrivateKey * | ||
327 | TALER_RSA_decode_key (const char *buf, uint16_t len) | ||
328 | { | ||
329 | struct TALER_RSA_PrivateKey *ret; | ||
330 | const struct TALER_RSA_PrivateKeyBinaryEncoded *encoding = | ||
331 | (const struct TALER_RSA_PrivateKeyBinaryEncoded *) buf; | ||
332 | gcry_sexp_t res; | ||
333 | gcry_mpi_t n; | ||
334 | gcry_mpi_t e; | ||
335 | gcry_mpi_t d; | ||
336 | gcry_mpi_t p; | ||
337 | gcry_mpi_t q; | ||
338 | gcry_mpi_t u; | ||
339 | int rc; | ||
340 | size_t size; | ||
341 | size_t pos; | ||
342 | uint16_t enc_len; | ||
343 | size_t erroff; | ||
344 | |||
345 | enc_len = ntohs (encoding->len); | ||
346 | if (len != enc_len) | ||
347 | return NULL; | ||
348 | |||
349 | pos = 0; | ||
350 | size = ntohs (encoding->sizen); | ||
351 | rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, | ||
352 | &((const unsigned char *) (&encoding[1]))[pos], size, | ||
353 | &size); | ||
354 | pos += ntohs (encoding->sizen); | ||
355 | if (0 != rc) | ||
356 | { | ||
357 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
358 | return NULL; | ||
359 | } | ||
360 | size = ntohs (encoding->sizee); | ||
361 | rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, | ||
362 | &((const unsigned char *) (&encoding[1]))[pos], size, | ||
363 | &size); | ||
364 | pos += ntohs (encoding->sizee); | ||
365 | if (0 != rc) | ||
366 | { | ||
367 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
368 | gcry_mpi_release (n); | ||
369 | return NULL; | ||
370 | } | ||
371 | size = ntohs (encoding->sized); | ||
372 | rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG, | ||
373 | &((const unsigned char *) (&encoding[1]))[pos], size, | ||
374 | &size); | ||
375 | pos += ntohs (encoding->sized); | ||
376 | if (0 != rc) | ||
377 | { | ||
378 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
379 | gcry_mpi_release (n); | ||
380 | gcry_mpi_release (e); | ||
381 | return NULL; | ||
382 | } | ||
383 | /* swap p and q! */ | ||
384 | size = ntohs (encoding->sizep); | ||
385 | if (size > 0) | ||
386 | { | ||
387 | rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG, | ||
388 | &((const unsigned char *) (&encoding[1]))[pos], size, | ||
389 | &size); | ||
390 | pos += ntohs (encoding->sizep); | ||
391 | if (0 != rc) | ||
392 | { | ||
393 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
394 | gcry_mpi_release (n); | ||
395 | gcry_mpi_release (e); | ||
396 | gcry_mpi_release (d); | ||
397 | return NULL; | ||
398 | } | ||
399 | } | ||
400 | else | ||
401 | q = NULL; | ||
402 | size = ntohs (encoding->sizeq); | ||
403 | if (size > 0) | ||
404 | { | ||
405 | rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG, | ||
406 | &((const unsigned char *) (&encoding[1]))[pos], size, | ||
407 | &size); | ||
408 | pos += ntohs (encoding->sizeq); | ||
409 | if (0 != rc) | ||
410 | { | ||
411 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
412 | gcry_mpi_release (n); | ||
413 | gcry_mpi_release (e); | ||
414 | gcry_mpi_release (d); | ||
415 | if (NULL != q) | ||
416 | gcry_mpi_release (q); | ||
417 | return NULL; | ||
418 | } | ||
419 | } | ||
420 | else | ||
421 | p = NULL; | ||
422 | pos += ntohs (encoding->sizedmp1); | ||
423 | pos += ntohs (encoding->sizedmq1); | ||
424 | size = | ||
425 | ntohs (encoding->len) - sizeof (struct TALER_RSA_PrivateKeyBinaryEncoded) - pos; | ||
426 | if (size > 0) | ||
427 | { | ||
428 | rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG, | ||
429 | &((const unsigned char *) (&encoding[1]))[pos], size, | ||
430 | &size); | ||
431 | if (0 != rc) | ||
432 | { | ||
433 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
434 | gcry_mpi_release (n); | ||
435 | gcry_mpi_release (e); | ||
436 | gcry_mpi_release (d); | ||
437 | if (NULL != p) | ||
438 | gcry_mpi_release (p); | ||
439 | if (NULL != q) | ||
440 | gcry_mpi_release (q); | ||
441 | return NULL; | ||
442 | } | ||
443 | } | ||
444 | else | ||
445 | u = NULL; | ||
446 | |||
447 | if ((NULL != p) && (NULL != q) && (NULL != u)) | ||
448 | { | ||
449 | rc = gcry_sexp_build (&res, &erroff, | ||
450 | "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))", | ||
451 | n, e, d, p, q, u); | ||
452 | } | ||
453 | else | ||
454 | { | ||
455 | if ((NULL != p) && (NULL != q)) | ||
456 | { | ||
457 | rc = gcry_sexp_build (&res, &erroff, | ||
458 | "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))", | ||
459 | n, e, d, p, q); | ||
460 | } | ||
461 | else | ||
462 | { | ||
463 | rc = gcry_sexp_build (&res, &erroff, | ||
464 | "(private-key(rsa(n %m)(e %m)(d %m)))", n, e, d); | ||
465 | } | ||
466 | } | ||
467 | gcry_mpi_release (n); | ||
468 | gcry_mpi_release (e); | ||
469 | gcry_mpi_release (d); | ||
470 | if (NULL != p) | ||
471 | gcry_mpi_release (p); | ||
472 | if (NULL != q) | ||
473 | gcry_mpi_release (q); | ||
474 | if (NULL != u) | ||
475 | gcry_mpi_release (u); | ||
476 | |||
477 | if (0 != rc) | ||
478 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); | ||
479 | if (0 != (rc = gcry_pk_testkey (res))) | ||
480 | { | ||
481 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc); | ||
482 | return NULL; | ||
483 | } | ||
484 | ret = GNUNET_malloc (sizeof (struct TALER_RSA_PrivateKey)); | ||
485 | ret->sexp = res; | ||
486 | return ret; | ||
487 | } | ||
488 | |||
489 | |||
490 | /** | ||
491 | * Convert a public key to a string. | ||
492 | * | ||
493 | * @param pub key to convert | ||
494 | * @return string representing 'pub' | ||
495 | */ | ||
496 | char * | ||
497 | TALER_RSA_public_key_to_string (const struct TALER_RSA_PublicKeyBinaryEncoded *pub) | ||
498 | { | ||
499 | char *pubkeybuf; | ||
500 | size_t keylen = (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) * 8; | ||
501 | char *end; | ||
502 | |||
503 | if (keylen % 5 > 0) | ||
504 | keylen += 5 - keylen % 5; | ||
505 | keylen /= 5; | ||
506 | pubkeybuf = GNUNET_malloc (keylen + 1); | ||
507 | end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub, | ||
508 | sizeof (struct TALER_RSA_PublicKeyBinaryEncoded), | ||
509 | pubkeybuf, | ||
510 | keylen); | ||
511 | if (NULL == end) | ||
512 | { | ||
513 | GNUNET_free (pubkeybuf); | ||
514 | return NULL; | ||
515 | } | ||
516 | *end = '\0'; | ||
517 | return pubkeybuf; | ||
518 | } | ||
519 | |||
520 | |||
521 | /** | ||
522 | * Convert a string representing a public key to a public key. | ||
523 | * | ||
524 | * @param enc encoded public key | ||
525 | * @param enclen number of bytes in enc (without 0-terminator) | ||
526 | * @param pub where to store the public key | ||
527 | * @return GNUNET_OK on success | ||
528 | */ | ||
529 | int | ||
530 | TALER_RSA_public_key_from_string (const char *enc, | ||
531 | size_t enclen, | ||
532 | struct TALER_RSA_PublicKeyBinaryEncoded *pub) | ||
533 | { | ||
534 | size_t keylen = (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) * 8; | ||
535 | |||
536 | if (keylen % 5 > 0) | ||
537 | keylen += 5 - keylen % 5; | ||
538 | keylen /= 5; | ||
539 | if (enclen != keylen) | ||
540 | return GNUNET_SYSERR; | ||
541 | |||
542 | if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen, | ||
543 | (unsigned char*) pub, | ||
544 | sizeof (struct TALER_RSA_PublicKeyBinaryEncoded))) | ||
545 | return GNUNET_SYSERR; | ||
546 | if ( (ntohs (pub->len) != sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) || | ||
547 | (ntohs (pub->padding) != 0) || | ||
548 | (ntohs (pub->sizen) != TALER_RSA_DATA_ENCODING_LENGTH) ) | ||
549 | return GNUNET_SYSERR; | ||
550 | return GNUNET_OK; | ||
551 | } | ||
552 | |||
553 | |||
554 | /** | ||
555 | * Convert the data specified in the given purpose argument to an | ||
556 | * S-expression suitable for signature operations. | ||
557 | * | ||
558 | * @param ptr pointer to the data to convert | ||
559 | * @param size the size of the data | ||
560 | * @return converted s-expression | ||
561 | */ | ||
562 | static gcry_sexp_t | ||
563 | data_to_sexp (const void *ptr, size_t size) | ||
564 | { | ||
565 | gcry_mpi_t value; | ||
566 | gcry_sexp_t data; | ||
567 | |||
568 | value = NULL; | ||
569 | data = NULL; | ||
570 | GNUNET_assert (0 == gcry_mpi_scan (&value, GCRYMPI_FMT_USG, ptr, size, NULL)); | ||
571 | GNUNET_assert (0 == gcry_sexp_build (&data, NULL, "(data (flags raw) (value %M))", value)); | ||
572 | gcry_mpi_release (value); | ||
573 | return data; | ||
574 | } | ||
575 | |||
576 | |||
577 | /** | ||
578 | * Sign the given hash block. | ||
579 | * | ||
580 | * @param key private key to use for the signing | ||
581 | * @param hash the block containing the hash of the message to sign | ||
582 | * @param hash_size the size of the hash block | ||
583 | * @param sig where to write the signature | ||
584 | * @return GNUNET_SYSERR on error, GNUNET_OK on success | ||
585 | */ | ||
586 | int | ||
587 | TALER_RSA_sign (const struct TALER_RSA_PrivateKey *key, | ||
588 | const void *hash, | ||
589 | size_t hash_size, | ||
590 | struct TALER_RSA_Signature *sig) | ||
591 | { | ||
592 | gcry_sexp_t result; | ||
593 | gcry_sexp_t data; | ||
594 | size_t ssize; | ||
595 | gcry_mpi_t rval; | ||
596 | |||
597 | data = data_to_sexp (hash, hash_size); | ||
598 | GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp)); | ||
599 | gcry_sexp_release (data); | ||
600 | GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "s")); | ||
601 | gcry_sexp_release (result); | ||
602 | ssize = sizeof (struct TALER_RSA_Signature); | ||
603 | GNUNET_assert (0 == | ||
604 | gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) sig, ssize, | ||
605 | &ssize, rval)); | ||
606 | gcry_mpi_release (rval); | ||
607 | adjust (sig->sig, ssize, sizeof (struct TALER_RSA_Signature)); | ||
608 | return GNUNET_OK; | ||
609 | } | ||
610 | |||
611 | |||
612 | /** | ||
613 | * Convert the given public key from the network format to the | ||
614 | * S-expression that can be used by libgcrypt. | ||
615 | * | ||
616 | * @param publicKey public key to decode | ||
617 | * @return NULL on error | ||
618 | */ | ||
619 | static gcry_sexp_t | ||
620 | decode_public_key (const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey) | ||
621 | { | ||
622 | gcry_sexp_t result; | ||
623 | gcry_mpi_t n; | ||
624 | gcry_mpi_t e; | ||
625 | size_t size; | ||
626 | size_t erroff; | ||
627 | int rc; | ||
628 | |||
629 | if ((ntohs (publicKey->sizen) != TALER_RSA_DATA_ENCODING_LENGTH) || | ||
630 | (ntohs (publicKey->len) != | ||
631 | sizeof (struct TALER_RSA_PublicKeyBinaryEncoded) - | ||
632 | sizeof (publicKey->padding))) | ||
633 | { | ||
634 | GNUNET_break (0); | ||
635 | return NULL; | ||
636 | } | ||
637 | size = TALER_RSA_DATA_ENCODING_LENGTH; | ||
638 | if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, &publicKey->key[0], size, &size))) | ||
639 | { | ||
640 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
641 | return NULL; | ||
642 | } | ||
643 | size = TALER_RSA_KEY_LENGTH - TALER_RSA_DATA_ENCODING_LENGTH; | ||
644 | if (0 != (rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG, | ||
645 | &publicKey->key[TALER_RSA_DATA_ENCODING_LENGTH], | ||
646 | size, &size))) | ||
647 | { | ||
648 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
649 | gcry_mpi_release (n); | ||
650 | return NULL; | ||
651 | } | ||
652 | rc = gcry_sexp_build (&result, &erroff, "(public-key(rsa(n %m)(e %m)))", n, | ||
653 | e); | ||
654 | gcry_mpi_release (n); | ||
655 | gcry_mpi_release (e); | ||
656 | if (0 != rc) | ||
657 | { | ||
658 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */ | ||
659 | return NULL; | ||
660 | } | ||
661 | return result; | ||
662 | } | ||
663 | |||
664 | |||
665 | /** | ||
666 | * Verify signature with the given hash. | ||
667 | * | ||
668 | * @param hash the hash code to verify against the signature | ||
669 | * @param sig signature that is being validated | ||
670 | * @param publicKey public key of the signer | ||
671 | * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid | ||
672 | */ | ||
673 | int | ||
674 | TALER_RSA_hash_verify (const struct GNUNET_HashCode *hash, | ||
675 | const struct TALER_RSA_Signature *sig, | ||
676 | const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey) | ||
677 | { | ||
678 | gcry_sexp_t data; | ||
679 | gcry_sexp_t sigdata; | ||
680 | size_t size; | ||
681 | gcry_mpi_t val; | ||
682 | gcry_sexp_t psexp; | ||
683 | size_t erroff; | ||
684 | int rc; | ||
685 | |||
686 | size = sizeof (struct TALER_RSA_Signature); | ||
687 | GNUNET_assert (0 == | ||
688 | gcry_mpi_scan (&val, GCRYMPI_FMT_USG, | ||
689 | (const unsigned char *) sig, size, &size)); | ||
690 | GNUNET_assert (0 == | ||
691 | gcry_sexp_build (&sigdata, &erroff, "(sig-val(rsa(s %m)))", | ||
692 | val)); | ||
693 | gcry_mpi_release (val); | ||
694 | data = data_to_sexp (hash, sizeof (struct GNUNET_HashCode)); | ||
695 | if (! (psexp = decode_public_key (publicKey))) | ||
696 | { | ||
697 | gcry_sexp_release (data); | ||
698 | gcry_sexp_release (sigdata); | ||
699 | return GNUNET_SYSERR; | ||
700 | } | ||
701 | rc = gcry_pk_verify (sigdata, data, psexp); | ||
702 | gcry_sexp_release (psexp); | ||
703 | gcry_sexp_release (data); | ||
704 | gcry_sexp_release (sigdata); | ||
705 | if (rc) | ||
706 | { | ||
707 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
708 | _("RSA signature verification failed at %s:%d: %s\n"), __FILE__, | ||
709 | __LINE__, gcry_strerror (rc)); | ||
710 | return GNUNET_SYSERR; | ||
711 | } | ||
712 | return GNUNET_OK; | ||
713 | } | ||
714 | |||
715 | |||
716 | /** | ||
717 | * Verify signature on the given message | ||
718 | * | ||
719 | * @param msg the message | ||
720 | * @param size the size of the message | ||
721 | * @param sig signature that is being validated | ||
722 | * @param publicKey public key of the signer | ||
723 | * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid | ||
724 | */ | ||
725 | int | ||
726 | TALER_RSA_verify (const void *msg, size_t size, | ||
727 | const struct TALER_RSA_Signature *sig, | ||
728 | const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey) | ||
729 | { | ||
730 | struct GNUNET_HashCode hash; | ||
731 | |||
732 | GNUNET_CRYPTO_hash (msg, size, &hash); | ||
733 | return TALER_RSA_hash_verify (&hash, sig, publicKey); | ||
734 | } | ||
735 | |||
736 | /** | ||
737 | * The blinding key is equal in length to the RSA modulus | ||
738 | */ | ||
739 | #define TALER_RSA_BLINDING_KEY_LEN TALER_RSA_DATA_ENCODING_LENGTH | ||
740 | |||
741 | struct TALER_RSA_BlindingKey | ||
742 | { | ||
743 | /** | ||
744 | * The blinding factor | ||
745 | */ | ||
746 | gcry_mpi_t r; | ||
747 | }; | ||
748 | |||
749 | struct TALER_RSA_BlindingKey * | ||
750 | TALER_RSA_blinding_key_create () | ||
751 | { | ||
752 | struct TALER_RSA_BlindingKey *blind; | ||
753 | |||
754 | blind = GNUNET_new (struct TALER_RSA_BlindingKey); | ||
755 | blind->r = gcry_mpi_new (TALER_RSA_BLINDING_KEY_LEN * 8); | ||
756 | gcry_mpi_randomize (blind->r, TALER_RSA_BLINDING_KEY_LEN * 8, GCRY_STRONG_RANDOM); | ||
757 | return blind; | ||
758 | } | ||
759 | |||
760 | |||
761 | void | ||
762 | TALER_RSA_blinding_key_destroy (struct TALER_RSA_BlindingKey *bkey) | ||
763 | { | ||
764 | gcry_mpi_release (bkey->r); | ||
765 | GNUNET_free (bkey); | ||
766 | } | ||
767 | |||
768 | |||
769 | struct TALER_RSA_BlindedSignaturePurpose * | ||
770 | TALER_RSA_message_blind (const void *msg, size_t size, | ||
771 | struct TALER_RSA_BlindingKey *bkey, | ||
772 | struct TALER_RSA_PublicKeyBinaryEncoded *pkey) | ||
773 | { | ||
774 | struct TALER_RSA_BlindedSignaturePurpose *bsp; | ||
775 | struct GNUNET_HashCode hash; | ||
776 | gcry_sexp_t psexp; | ||
777 | gcry_mpi_t data; | ||
778 | gcry_mpi_t skey[2]; | ||
779 | gcry_mpi_t r_e; | ||
780 | gcry_mpi_t data_r_e; | ||
781 | size_t rsize; | ||
782 | gcry_error_t rc; | ||
783 | int ret; | ||
784 | |||
785 | bsp = NULL; | ||
786 | psexp = NULL; | ||
787 | data = NULL; | ||
788 | skey[0] = skey[1] = NULL; | ||
789 | r_e = NULL; | ||
790 | data_r_e = NULL; | ||
791 | rsize = 0; | ||
792 | rc = 0; | ||
793 | ret = 0; | ||
794 | if (! (psexp = decode_public_key (pkey))) | ||
795 | return NULL; | ||
796 | ret = key_from_sexp (skey, psexp, "public-key", "ne"); | ||
797 | if (0 != ret) | ||
798 | ret = key_from_sexp (skey, psexp, "rsa", "ne"); | ||
799 | gcry_sexp_release (psexp); | ||
800 | psexp = NULL; | ||
801 | GNUNET_assert (0 == ret); | ||
802 | GNUNET_CRYPTO_hash (msg, size, &hash); | ||
803 | if (0 != (rc=gcry_mpi_scan (&data, GCRYMPI_FMT_USG, | ||
804 | (const unsigned char *) msg, size, &rsize))) | ||
805 | { | ||
806 | LOG_GCRY (GNUNET_ERROR_TYPE_WARNING, "gcry_mpi_scan", rc); | ||
807 | goto cleanup; | ||
808 | } | ||
809 | r_e = gcry_mpi_new (0); | ||
810 | gcry_mpi_powm (r_e, bkey->r, | ||
811 | skey[1], /* e */ | ||
812 | skey[0]); /* n */ | ||
813 | |||
814 | data_r_e = gcry_mpi_new (0); | ||
815 | gcry_mpi_mulm (data_r_e, data, r_e, skey[0]); | ||
816 | |||
817 | bsp = GNUNET_new (struct TALER_RSA_BlindedSignaturePurpose); | ||
818 | rc = gcry_mpi_print (GCRYMPI_FMT_USG, | ||
819 | (unsigned char *) bsp, | ||
820 | sizeof (struct TALER_RSA_BlindedSignaturePurpose), | ||
821 | &rsize, | ||
822 | data_r_e); | ||
823 | GNUNET_assert (0 == rc); | ||
824 | adjust ((unsigned char *) bsp, rsize, | ||
825 | sizeof (struct TALER_RSA_BlindedSignaturePurpose)); | ||
826 | |||
827 | cleanup: | ||
828 | if (NULL != psexp) gcry_sexp_release (psexp); | ||
829 | mpi_release_non_null (skey[0]); | ||
830 | mpi_release_non_null (skey[1]); | ||
831 | mpi_release_non_null (data); | ||
832 | mpi_release_non_null (r_e); | ||
833 | mpi_release_non_null (data_r_e); | ||
834 | return bsp; | ||
835 | } | ||
836 | |||
837 | |||
838 | int | ||
839 | TALER_RSA_unblind (struct TALER_RSA_Signature *sig, | ||
840 | struct TALER_RSA_BlindingKey *bkey, | ||
841 | struct TALER_RSA_PublicKeyBinaryEncoded *pkey) | ||
842 | { | ||
843 | gcry_sexp_t psexp; | ||
844 | gcry_mpi_t skey; | ||
845 | gcry_mpi_t sigval; | ||
846 | gcry_mpi_t r_inv; | ||
847 | gcry_mpi_t ubsig; | ||
848 | size_t rsize; | ||
849 | gcry_error_t rc; | ||
850 | int ret; | ||
851 | |||
852 | psexp = NULL; | ||
853 | skey = NULL; | ||
854 | sigval = NULL; | ||
855 | r_inv = NULL; | ||
856 | ubsig = NULL; | ||
857 | rsize = 0; | ||
858 | rc = 0; | ||
859 | ret = GNUNET_SYSERR; | ||
860 | if (! (psexp = decode_public_key (pkey))) | ||
861 | return GNUNET_SYSERR; | ||
862 | ret = key_from_sexp (&skey, psexp, "public-key", "n"); | ||
863 | if (0 != ret) | ||
864 | ret = key_from_sexp (&skey, psexp, "rsa", "n"); | ||
865 | gcry_sexp_release (psexp); | ||
866 | psexp = NULL; | ||
867 | if (0 != (rc = gcry_mpi_scan (&sigval, GCRYMPI_FMT_USG, | ||
868 | (const unsigned char *) sig, | ||
869 | sizeof (struct TALER_RSA_Signature), | ||
870 | &rsize))) | ||
871 | { | ||
872 | LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc); | ||
873 | goto cleanup; | ||
874 | } | ||
875 | r_inv = gcry_mpi_new (0); | ||
876 | GNUNET_assert (1 == gcry_mpi_invm (r_inv, bkey->r, skey)); /* n: skey */ | ||
877 | ubsig = gcry_mpi_new (0); | ||
878 | gcry_mpi_mulm (ubsig, sigval, r_inv, skey); | ||
879 | rc = gcry_mpi_print (GCRYMPI_FMT_USG, | ||
880 | (unsigned char *) sig, | ||
881 | sizeof (struct TALER_RSA_Signature), | ||
882 | &rsize, | ||
883 | ubsig); | ||
884 | GNUNET_assert (0 == rc); | ||
885 | adjust ((unsigned char *) sig, rsize, sizeof (struct TALER_RSA_Signature)); | ||
886 | ret = GNUNET_OK; | ||
887 | |||
888 | cleanup: | ||
889 | if (NULL != psexp) gcry_sexp_release (psexp); | ||
890 | mpi_release_non_null (skey); | ||
891 | mpi_release_non_null (sigval); | ||
892 | mpi_release_non_null (r_inv); | ||
893 | mpi_release_non_null (ubsig); | ||
894 | return ret; | ||
895 | } | ||
896 | |||
897 | |||
898 | /** | ||
899 | * Encode a blinding key | ||
900 | * | ||
901 | * @param bkey the blinding key to encode | ||
902 | * @param bkey_enc where to store the encoded binary key | ||
903 | * @return #GNUNET_OK upon successful encoding; #GNUNET_SYSERR upon failure | ||
904 | */ | ||
905 | int | ||
906 | TALER_RSA_blinding_key_encode (struct TALER_RSA_BlindingKey *bkey, | ||
907 | struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc) | ||
908 | { | ||
909 | GNUNET_abort (); /* FIXME: not implemented */ | ||
910 | } | ||
911 | |||
912 | |||
913 | /** | ||
914 | * Decode a blinding key from its encoded form | ||
915 | * | ||
916 | * @param bkey_enc the encoded blinding key | ||
917 | * @return the decoded blinding key; NULL upon error | ||
918 | */ | ||
919 | struct TALER_RSA_BlindingKey * | ||
920 | TALER_RSA_blinding_key_decode (struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc) | ||
921 | { | ||
922 | GNUNET_abort (); /* FIXME: not implemented */ | ||
923 | } | ||
924 | |||
925 | /* end of util/rsa.c */ | ||