diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-01-09 15:51:57 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-01-09 15:51:57 +0000 |
commit | efd634ccf636b870b2dbd79f8969f8999c5573fa (patch) | |
tree | 4492353a28bf7add22f9ea7a42233a6bd679ca44 /src/util | |
parent | 8215376b2d1b4a3d95a0cf1ba474cf4be437c1b0 (diff) | |
download | gnunet-efd634ccf636b870b2dbd79f8969f8999c5573fa.tar.gz gnunet-efd634ccf636b870b2dbd79f8969f8999c5573fa.zip |
adding support for blind signatures (modernized version of Taler logic, with variable key length)
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/Makefile.am | 7 | ||||
-rw-r--r-- | src/util/crypto_rsa.c | 796 | ||||
-rw-r--r-- | src/util/test_crypto_rsa.c | 82 |
3 files changed, 885 insertions, 0 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am index a71dd76df..87651e620 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am | |||
@@ -88,6 +88,7 @@ libgnunetutil_la_SOURCES = \ | |||
88 | crypto_mpi.c \ | 88 | crypto_mpi.c \ |
89 | crypto_paillier.c \ | 89 | crypto_paillier.c \ |
90 | crypto_random.c \ | 90 | crypto_random.c \ |
91 | crypto_rsa.c \ | ||
91 | disk.c \ | 92 | disk.c \ |
92 | disk.h \ | 93 | disk.h \ |
93 | getopt.c \ | 94 | getopt.c \ |
@@ -229,6 +230,7 @@ check_PROGRAMS = \ | |||
229 | test_crypto_hkdf \ | 230 | test_crypto_hkdf \ |
230 | test_crypto_paillier \ | 231 | test_crypto_paillier \ |
231 | test_crypto_random \ | 232 | test_crypto_random \ |
233 | test_crypto_rsa \ | ||
232 | test_disk \ | 234 | test_disk \ |
233 | test_getopt \ | 235 | test_getopt \ |
234 | test_connection.nc \ | 236 | test_connection.nc \ |
@@ -404,6 +406,11 @@ test_crypto_random_SOURCES = \ | |||
404 | test_crypto_random_LDADD = \ | 406 | test_crypto_random_LDADD = \ |
405 | libgnunetutil.la | 407 | libgnunetutil.la |
406 | 408 | ||
409 | test_crypto_rsa_SOURCES = \ | ||
410 | test_crypto_rsa.c | ||
411 | test_crypto_rsa_LDADD = \ | ||
412 | libgnunetutil.la | ||
413 | |||
407 | test_disk_SOURCES = \ | 414 | test_disk_SOURCES = \ |
408 | test_disk.c | 415 | test_disk.c |
409 | test_disk_LDADD = \ | 416 | test_disk_LDADD = \ |
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c new file mode 100644 index 000000000..c14e6b9b1 --- /dev/null +++ b/src/util/crypto_rsa.c | |||
@@ -0,0 +1,796 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet 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 | GNUnet 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 | GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file util/crypto_rsa.c | ||
19 | * @brief Chaum-style Blind signatures based on RSA | ||
20 | * @author Sree Harsha Totakura <sreeharsha@totakura.in> | ||
21 | * @author Christian Grothoff | ||
22 | */ | ||
23 | #include "platform.h" | ||
24 | #include <gcrypt.h> | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) | ||
28 | |||
29 | |||
30 | /** | ||
31 | * The private information of an RSA key pair. | ||
32 | */ | ||
33 | struct GNUNET_CRYPTO_rsa_PrivateKey | ||
34 | { | ||
35 | /** | ||
36 | * Libgcrypt S-expression for the RSA private key. | ||
37 | */ | ||
38 | gcry_sexp_t sexp; | ||
39 | }; | ||
40 | |||
41 | |||
42 | /** | ||
43 | * The public information of an RSA key pair. | ||
44 | */ | ||
45 | struct GNUNET_CRYPTO_rsa_PublicKey | ||
46 | { | ||
47 | /** | ||
48 | * Libgcrypt S-expression for the RSA public key. | ||
49 | */ | ||
50 | gcry_sexp_t sexp; | ||
51 | }; | ||
52 | |||
53 | |||
54 | /** | ||
55 | * @brief an RSA signature | ||
56 | */ | ||
57 | struct GNUNET_CRYPTO_rsa_Signature | ||
58 | { | ||
59 | /** | ||
60 | * Libgcrypt S-expression for the RSA signature. | ||
61 | */ | ||
62 | gcry_sexp_t sexp; | ||
63 | }; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * @brief RSA blinding key | ||
68 | */ | ||
69 | struct GNUNET_CRYPTO_rsa_BlindingKey | ||
70 | { | ||
71 | /** | ||
72 | * Random value used for blinding. | ||
73 | */ | ||
74 | gcry_mpi_t r; | ||
75 | }; | ||
76 | |||
77 | |||
78 | /** | ||
79 | * Extract values from an S-expression. | ||
80 | * | ||
81 | * @param array where to store the result(s) | ||
82 | * @param sexp S-expression to parse | ||
83 | * @param topname top-level name in the S-expression that is of interest | ||
84 | * @param elems names of the elements to extract | ||
85 | * @return 0 on success | ||
86 | */ | ||
87 | static int | ||
88 | key_from_sexp (gcry_mpi_t *array, | ||
89 | gcry_sexp_t sexp, | ||
90 | const char *topname, | ||
91 | const char *elems) | ||
92 | { | ||
93 | gcry_sexp_t list; | ||
94 | gcry_sexp_t l2; | ||
95 | const char *s; | ||
96 | unsigned int i; | ||
97 | unsigned int idx; | ||
98 | |||
99 | if (! (list = gcry_sexp_find_token (sexp, topname, 0))) | ||
100 | return 1; | ||
101 | l2 = gcry_sexp_cadr (list); | ||
102 | gcry_sexp_release (list); | ||
103 | list = l2; | ||
104 | if (! list) | ||
105 | return 2; | ||
106 | idx = 0; | ||
107 | for (s = elems; *s; s++, idx++) | ||
108 | { | ||
109 | if (! (l2 = gcry_sexp_find_token (list, s, 1))) | ||
110 | { | ||
111 | for (i = 0; i < idx; i++) | ||
112 | { | ||
113 | gcry_free (array[i]); | ||
114 | array[i] = NULL; | ||
115 | } | ||
116 | gcry_sexp_release (list); | ||
117 | return 3; /* required parameter not found */ | ||
118 | } | ||
119 | array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); | ||
120 | gcry_sexp_release (l2); | ||
121 | if (! array[idx]) | ||
122 | { | ||
123 | for (i = 0; i < idx; i++) | ||
124 | { | ||
125 | gcry_free (array[i]); | ||
126 | array[i] = NULL; | ||
127 | } | ||
128 | gcry_sexp_release (list); | ||
129 | return 4; /* required parameter is invalid */ | ||
130 | } | ||
131 | } | ||
132 | gcry_sexp_release (list); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | |||
137 | /** | ||
138 | * Create a new private key. Caller must free return value. | ||
139 | * | ||
140 | * @param len length of the key in bits (i.e. 2048) | ||
141 | * @return fresh private key | ||
142 | */ | ||
143 | struct GNUNET_CRYPTO_rsa_PrivateKey * | ||
144 | GNUNET_CRYPTO_rsa_private_key_create (unsigned int len) | ||
145 | { | ||
146 | struct GNUNET_CRYPTO_rsa_PrivateKey *ret; | ||
147 | gcry_sexp_t s_key; | ||
148 | gcry_sexp_t s_keyparam; | ||
149 | |||
150 | GNUNET_assert (0 == | ||
151 | gcry_sexp_build (&s_keyparam, | ||
152 | NULL, | ||
153 | "(genkey(rsa(nbits %d)))", | ||
154 | len)); | ||
155 | GNUNET_assert (0 == | ||
156 | gcry_pk_genkey (&s_key, | ||
157 | s_keyparam)); | ||
158 | gcry_sexp_release (s_keyparam); | ||
159 | #if EXTRA_CHECKS | ||
160 | GNUNET_assert (0 == | ||
161 | gcry_pk_testkey (s_key)); | ||
162 | #endif | ||
163 | ret = GNUNET_new (struct GNUNET_CRYPTO_rsa_PrivateKey); | ||
164 | ret->sexp = s_key; | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | |||
169 | /** | ||
170 | * Free memory occupied by the private key. | ||
171 | * | ||
172 | * @param key pointer to the memory to free | ||
173 | */ | ||
174 | void | ||
175 | GNUNET_CRYPTO_rsa_private_key_free (struct GNUNET_CRYPTO_rsa_PrivateKey *key) | ||
176 | { | ||
177 | gcry_sexp_release (key->sexp); | ||
178 | GNUNET_free (key); | ||
179 | } | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Encode the private key in a format suitable for | ||
184 | * storing it into a file. | ||
185 | * | ||
186 | * @param key the private key | ||
187 | * @param[out] buffer set to a buffer with the encoded key | ||
188 | * @return size of memory allocated in @a buffer | ||
189 | */ | ||
190 | size_t | ||
191 | GNUNET_CRYPTO_rsa_private_key_encode (const struct GNUNET_CRYPTO_rsa_PrivateKey *key, | ||
192 | char **buffer) | ||
193 | { | ||
194 | size_t n; | ||
195 | char *b; | ||
196 | |||
197 | n = gcry_sexp_sprint (key->sexp, | ||
198 | GCRYSEXP_FMT_DEFAULT, | ||
199 | NULL, | ||
200 | 0); | ||
201 | b = GNUNET_malloc (n); | ||
202 | GNUNET_assert (n == | ||
203 | gcry_sexp_sprint (key->sexp, | ||
204 | GCRYSEXP_FMT_DEFAULT, | ||
205 | b, | ||
206 | n)); | ||
207 | *buffer = b; | ||
208 | return n; | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Decode the private key from the data-format back | ||
214 | * to the "normal", internal format. | ||
215 | * | ||
216 | * @param buf the buffer where the private key data is stored | ||
217 | * @param len the length of the data in @a buf | ||
218 | * @return NULL on error | ||
219 | */ | ||
220 | struct GNUNET_CRYPTO_rsa_PrivateKey * | ||
221 | GNUNET_CRYPTO_rsa_private_key_decode (const char *buf, | ||
222 | size_t len) | ||
223 | { | ||
224 | struct GNUNET_CRYPTO_rsa_PrivateKey *key; | ||
225 | |||
226 | key = GNUNET_new (struct GNUNET_CRYPTO_rsa_PrivateKey); | ||
227 | if (0 != | ||
228 | gcry_sexp_new (&key->sexp, | ||
229 | buf, | ||
230 | len, | ||
231 | 0)) | ||
232 | { | ||
233 | GNUNET_break_op (0); | ||
234 | GNUNET_free (key); | ||
235 | return NULL; | ||
236 | } | ||
237 | /* FIXME: verify that this is an RSA private key */ | ||
238 | return key; | ||
239 | } | ||
240 | |||
241 | |||
242 | /** | ||
243 | * Extract the public key of the given private key. | ||
244 | * | ||
245 | * @param priv the private key | ||
246 | * @retur NULL on error, otherwise the public key | ||
247 | */ | ||
248 | struct GNUNET_CRYPTO_rsa_PublicKey * | ||
249 | GNUNET_CRYPTO_rsa_private_key_get_public (const struct GNUNET_CRYPTO_rsa_PrivateKey *priv) | ||
250 | { | ||
251 | struct GNUNET_CRYPTO_rsa_PublicKey *pub; | ||
252 | gcry_mpi_t ne[2]; | ||
253 | int rc; | ||
254 | gcry_sexp_t result; | ||
255 | |||
256 | rc = key_from_sexp (ne, priv->sexp, "public-key", "ne"); | ||
257 | if (0 != rc) | ||
258 | rc = key_from_sexp (ne, priv->sexp, "private-key", "ne"); | ||
259 | if (0 != rc) | ||
260 | rc = key_from_sexp (ne, priv->sexp, "rsa", "ne"); | ||
261 | if (0 != rc) | ||
262 | { | ||
263 | GNUNET_break_op (0); | ||
264 | return NULL; | ||
265 | } | ||
266 | rc = gcry_sexp_build (&result, | ||
267 | NULL, | ||
268 | "(public-key(rsa(n %m)(e %m)))", | ||
269 | ne[0], | ||
270 | ne[1]); | ||
271 | gcry_mpi_release (ne[0]); | ||
272 | gcry_mpi_release (ne[1]); | ||
273 | pub = GNUNET_new (struct GNUNET_CRYPTO_rsa_PublicKey); | ||
274 | pub->sexp = result; | ||
275 | return pub; | ||
276 | } | ||
277 | |||
278 | |||
279 | /** | ||
280 | * Free memory occupied by the public key. | ||
281 | * | ||
282 | * @param key pointer to the memory to free | ||
283 | */ | ||
284 | void | ||
285 | GNUNET_CRYPTO_rsa_public_key_free (struct GNUNET_CRYPTO_rsa_PublicKey *key) | ||
286 | { | ||
287 | gcry_sexp_release (key->sexp); | ||
288 | GNUNET_free (key); | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Encode the public key in a format suitable for | ||
294 | * storing it into a file. | ||
295 | * | ||
296 | * @param key the private key | ||
297 | * @param[out] buffer set to a buffer with the encoded key | ||
298 | * @return size of memory allocated in @a buffer | ||
299 | */ | ||
300 | size_t | ||
301 | GNUNET_CRYPTO_rsa_public_key_encode (const struct GNUNET_CRYPTO_rsa_PublicKey *key, | ||
302 | char **buffer) | ||
303 | { | ||
304 | size_t n; | ||
305 | char *b; | ||
306 | |||
307 | n = gcry_sexp_sprint (key->sexp, | ||
308 | GCRYSEXP_FMT_ADVANCED, | ||
309 | NULL, | ||
310 | 0); | ||
311 | b = GNUNET_malloc (n); | ||
312 | GNUNET_assert (n == | ||
313 | gcry_sexp_sprint (key->sexp, | ||
314 | GCRYSEXP_FMT_ADVANCED, | ||
315 | b, | ||
316 | n)); | ||
317 | *buffer = b; | ||
318 | return n; | ||
319 | } | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Decode the public key from the data-format back | ||
324 | * to the "normal", internal format. | ||
325 | * | ||
326 | * @param buf the buffer where the public key data is stored | ||
327 | * @param len the length of the data in @a buf | ||
328 | * @return NULL on error | ||
329 | */ | ||
330 | struct GNUNET_CRYPTO_rsa_PublicKey * | ||
331 | GNUNET_CRYPTO_rsa_public_key_decode (const char *buf, | ||
332 | size_t len) | ||
333 | { | ||
334 | struct GNUNET_CRYPTO_rsa_PublicKey *key; | ||
335 | gcry_mpi_t n; | ||
336 | int ret; | ||
337 | |||
338 | key = GNUNET_new (struct GNUNET_CRYPTO_rsa_PublicKey); | ||
339 | if (0 != | ||
340 | gcry_sexp_new (&key->sexp, | ||
341 | buf, | ||
342 | len, | ||
343 | 0)) | ||
344 | { | ||
345 | GNUNET_break_op (0); | ||
346 | GNUNET_free (key); | ||
347 | return NULL; | ||
348 | } | ||
349 | /* verify that this is an RSA public key */ | ||
350 | ret = key_from_sexp (&n, key->sexp, "public-key", "n"); | ||
351 | if (0 != ret) | ||
352 | ret = key_from_sexp (&n, key->sexp, "rsa", "n"); | ||
353 | if (0 != ret) | ||
354 | { | ||
355 | /* this is no public RSA key */ | ||
356 | GNUNET_break (0); | ||
357 | gcry_sexp_release (key->sexp); | ||
358 | GNUNET_free (key); | ||
359 | return NULL; | ||
360 | } | ||
361 | gcry_mpi_release (n); | ||
362 | return key; | ||
363 | } | ||
364 | |||
365 | |||
366 | /** | ||
367 | * Create a blinding key | ||
368 | * | ||
369 | * @param len length of the key in bits (i.e. 2048) | ||
370 | * @return the newly created blinding key | ||
371 | */ | ||
372 | struct GNUNET_CRYPTO_rsa_BlindingKey * | ||
373 | GNUNET_CRYPTO_rsa_blinding_key_create (unsigned int len) | ||
374 | { | ||
375 | struct GNUNET_CRYPTO_rsa_BlindingKey *blind; | ||
376 | |||
377 | blind = GNUNET_new (struct GNUNET_CRYPTO_rsa_BlindingKey); | ||
378 | blind->r = gcry_mpi_new (len); | ||
379 | gcry_mpi_randomize (blind->r, | ||
380 | len, | ||
381 | GCRY_STRONG_RANDOM); | ||
382 | return blind; | ||
383 | } | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Destroy a blinding key | ||
388 | * | ||
389 | * @param bkey the blinding key to destroy | ||
390 | */ | ||
391 | void | ||
392 | GNUNET_CRYPTO_rsa_blinding_key_free (struct GNUNET_CRYPTO_rsa_BlindingKey *bkey) | ||
393 | { | ||
394 | gcry_mpi_release (bkey->r); | ||
395 | GNUNET_free (bkey); | ||
396 | } | ||
397 | |||
398 | |||
399 | /** | ||
400 | * Encode the blinding key in a format suitable for | ||
401 | * storing it into a file. | ||
402 | * | ||
403 | * @param bkey the blinding key | ||
404 | * @param[out] buffer set to a buffer with the encoded key | ||
405 | * @return size of memory allocated in @a buffer | ||
406 | */ | ||
407 | size_t | ||
408 | GNUNET_CRYPTO_rsa_blinding_key_encode (const struct GNUNET_CRYPTO_rsa_BlindingKey *bkey, | ||
409 | char **buffer) | ||
410 | { | ||
411 | size_t n; | ||
412 | char *b; | ||
413 | size_t rsize; | ||
414 | |||
415 | gcry_mpi_print (GCRYMPI_FMT_USG, | ||
416 | NULL, | ||
417 | 0, | ||
418 | &n, | ||
419 | bkey->r); | ||
420 | b = GNUNET_malloc (n); | ||
421 | GNUNET_assert (0 == | ||
422 | gcry_mpi_print (GCRYMPI_FMT_USG, | ||
423 | (unsigned char *) b, | ||
424 | n, | ||
425 | &rsize, | ||
426 | bkey->r)); | ||
427 | *buffer = b; | ||
428 | return n; | ||
429 | } | ||
430 | |||
431 | |||
432 | /** | ||
433 | * Decode the blinding key from the data-format back | ||
434 | * to the "normal", internal format. | ||
435 | * | ||
436 | * @param buf the buffer where the public key data is stored | ||
437 | * @param len the length of the data in @a buf | ||
438 | * @return NULL on error | ||
439 | */ | ||
440 | struct GNUNET_CRYPTO_rsa_BlindingKey * | ||
441 | GNUNET_CRYPTO_rsa_blinding_key_decode (const char *buf, | ||
442 | size_t len) | ||
443 | { | ||
444 | struct GNUNET_CRYPTO_rsa_BlindingKey *bkey; | ||
445 | size_t rsize; | ||
446 | |||
447 | bkey = GNUNET_new (struct GNUNET_CRYPTO_rsa_BlindingKey); | ||
448 | if (0 != | ||
449 | gcry_mpi_scan (&bkey->r, | ||
450 | GCRYMPI_FMT_USG, | ||
451 | (const unsigned char *) buf, | ||
452 | len, | ||
453 | &rsize)) | ||
454 | { | ||
455 | GNUNET_break_op (0); | ||
456 | GNUNET_free (bkey); | ||
457 | return NULL; | ||
458 | } | ||
459 | return bkey; | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * Blinds the given message with the given blinding key | ||
465 | * | ||
466 | * @param hash hash of the message to sign | ||
467 | * @param bkey the blinding key | ||
468 | * @param pkey the public key of the signer | ||
469 | * @param[out] buffer set to a buffer with the blinded message to be signed | ||
470 | * @return number of bytes stored in @a buffer | ||
471 | */ | ||
472 | size_t | ||
473 | GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash, | ||
474 | struct GNUNET_CRYPTO_rsa_BlindingKey *bkey, | ||
475 | struct GNUNET_CRYPTO_rsa_PublicKey *pkey, | ||
476 | char **buffer) | ||
477 | { | ||
478 | gcry_mpi_t data; | ||
479 | gcry_mpi_t ne[2]; | ||
480 | gcry_mpi_t r_e; | ||
481 | gcry_mpi_t data_r_e; | ||
482 | size_t rsize; | ||
483 | size_t n; | ||
484 | gcry_error_t rc; | ||
485 | char *b; | ||
486 | int ret; | ||
487 | |||
488 | ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne"); | ||
489 | if (0 != ret) | ||
490 | ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne"); | ||
491 | if (0 != ret) | ||
492 | { | ||
493 | GNUNET_break (0); | ||
494 | *buffer = NULL; | ||
495 | return 0; | ||
496 | } | ||
497 | if (0 != (rc = gcry_mpi_scan (&data, | ||
498 | GCRYMPI_FMT_USG, | ||
499 | (const unsigned char *) hash, | ||
500 | sizeof (struct GNUNET_HashCode), | ||
501 | &rsize))) | ||
502 | { | ||
503 | GNUNET_break (0); | ||
504 | gcry_mpi_release (ne[0]); | ||
505 | gcry_mpi_release (ne[1]); | ||
506 | *buffer = NULL; | ||
507 | return 0; | ||
508 | } | ||
509 | r_e = gcry_mpi_new (0); | ||
510 | gcry_mpi_powm (r_e, | ||
511 | bkey->r, | ||
512 | ne[1], | ||
513 | ne[0]); | ||
514 | data_r_e = gcry_mpi_new (0); | ||
515 | gcry_mpi_mulm (data_r_e, | ||
516 | data, | ||
517 | r_e, | ||
518 | ne[0]); | ||
519 | gcry_mpi_release (ne[0]); | ||
520 | gcry_mpi_release (ne[1]); | ||
521 | gcry_mpi_release (r_e); | ||
522 | |||
523 | gcry_mpi_print (GCRYMPI_FMT_USG, | ||
524 | NULL, | ||
525 | 0, | ||
526 | &n, | ||
527 | data_r_e); | ||
528 | b = GNUNET_malloc (n); | ||
529 | rc = gcry_mpi_print (GCRYMPI_FMT_USG, | ||
530 | (unsigned char *) b, | ||
531 | n, | ||
532 | &rsize, | ||
533 | data_r_e); | ||
534 | gcry_mpi_release (data_r_e); | ||
535 | *buffer = b; | ||
536 | return n; | ||
537 | } | ||
538 | |||
539 | |||
540 | /** | ||
541 | * Convert the data specified in the given purpose argument to an | ||
542 | * S-expression suitable for signature operations. | ||
543 | * | ||
544 | * @param ptr pointer to the data to convert | ||
545 | * @param size the size of the data | ||
546 | * @return converted s-expression | ||
547 | */ | ||
548 | static gcry_sexp_t | ||
549 | data_to_sexp (const void *ptr, size_t size) | ||
550 | { | ||
551 | gcry_mpi_t value; | ||
552 | gcry_sexp_t data; | ||
553 | |||
554 | value = NULL; | ||
555 | data = NULL; | ||
556 | GNUNET_assert (0 == | ||
557 | gcry_mpi_scan (&value, | ||
558 | GCRYMPI_FMT_USG, | ||
559 | ptr, | ||
560 | size, | ||
561 | NULL)); | ||
562 | GNUNET_assert (0 == | ||
563 | gcry_sexp_build (&data, | ||
564 | NULL, | ||
565 | "(data (flags raw) (value %M))", | ||
566 | value)); | ||
567 | gcry_mpi_release (value); | ||
568 | return data; | ||
569 | } | ||
570 | |||
571 | |||
572 | /** | ||
573 | * Sign the given message. | ||
574 | * | ||
575 | * @param key private key to use for the signing | ||
576 | * @param msg the message to sign | ||
577 | * @param msg_len number of bytes in @a msg to sign | ||
578 | * @return NULL on error, signature on success | ||
579 | */ | ||
580 | struct GNUNET_CRYPTO_rsa_Signature * | ||
581 | GNUNET_CRYPTO_rsa_sign (const struct GNUNET_CRYPTO_rsa_PrivateKey *key, | ||
582 | const void *msg, | ||
583 | size_t msg_len) | ||
584 | { | ||
585 | struct GNUNET_CRYPTO_rsa_Signature *sig; | ||
586 | gcry_sexp_t result; | ||
587 | gcry_sexp_t data; | ||
588 | |||
589 | data = data_to_sexp (msg, | ||
590 | msg_len); | ||
591 | if (0 != | ||
592 | gcry_pk_sign (&result, | ||
593 | data, | ||
594 | key->sexp)) | ||
595 | { | ||
596 | GNUNET_break (0); | ||
597 | return NULL; | ||
598 | } | ||
599 | gcry_sexp_release (data); | ||
600 | sig = GNUNET_new (struct GNUNET_CRYPTO_rsa_Signature); | ||
601 | sig->sexp = result; | ||
602 | return sig; | ||
603 | } | ||
604 | |||
605 | |||
606 | /** | ||
607 | * Free memory occupied by signature. | ||
608 | * | ||
609 | * @param sig memory to freee | ||
610 | */ | ||
611 | void | ||
612 | GNUNET_CRYPTO_rsa_signature_free (struct GNUNET_CRYPTO_rsa_Signature *sig) | ||
613 | { | ||
614 | gcry_sexp_release (sig->sexp); | ||
615 | GNUNET_free (sig); | ||
616 | } | ||
617 | |||
618 | |||
619 | /** | ||
620 | * Encode the signature key in a format suitable for | ||
621 | * storing it into a file. | ||
622 | * | ||
623 | * @param sig the signature | ||
624 | * @param[out] buffer set to a buffer with the encoded key | ||
625 | * @return size of memory allocated in @a buffer | ||
626 | */ | ||
627 | size_t | ||
628 | GNUNET_CRYPTO_rsa_signature_encode (const struct GNUNET_CRYPTO_rsa_Signature *sig, | ||
629 | char **buffer) | ||
630 | { | ||
631 | size_t n; | ||
632 | char *b; | ||
633 | |||
634 | n = gcry_sexp_sprint (sig->sexp, | ||
635 | GCRYSEXP_FMT_ADVANCED, | ||
636 | NULL, | ||
637 | 0); | ||
638 | b = GNUNET_malloc (n); | ||
639 | GNUNET_assert (n == | ||
640 | gcry_sexp_sprint (sig->sexp, | ||
641 | GCRYSEXP_FMT_ADVANCED, | ||
642 | b, | ||
643 | n)); | ||
644 | *buffer = b; | ||
645 | return n; | ||
646 | } | ||
647 | |||
648 | |||
649 | /** | ||
650 | * Decode the public key from the data-format back | ||
651 | * to the "normal", internal format. | ||
652 | * | ||
653 | * @param buf the buffer where the public key data is stored | ||
654 | * @param len the length of the data in @a buf | ||
655 | * @return NULL on error | ||
656 | */ | ||
657 | struct GNUNET_CRYPTO_rsa_Signature * | ||
658 | GNUNET_CRYPTO_rsa_signature_decode (const char *buf, | ||
659 | size_t len) | ||
660 | { | ||
661 | struct GNUNET_CRYPTO_rsa_Signature *sig; | ||
662 | int ret; | ||
663 | gcry_mpi_t s; | ||
664 | |||
665 | sig = GNUNET_new (struct GNUNET_CRYPTO_rsa_Signature); | ||
666 | if (0 != | ||
667 | gcry_sexp_new (&sig->sexp, | ||
668 | buf, | ||
669 | len, | ||
670 | 0)) | ||
671 | { | ||
672 | GNUNET_break_op (0); | ||
673 | GNUNET_free (sig); | ||
674 | return NULL; | ||
675 | } | ||
676 | /* verify that this is an RSA signature */ | ||
677 | ret = key_from_sexp (&s, sig->sexp, "sig-val", "s"); | ||
678 | if (0 != ret) | ||
679 | ret = key_from_sexp (&s, sig->sexp, "rsa", "s"); | ||
680 | if (0 != ret) | ||
681 | { | ||
682 | /* this is no RSA Signature */ | ||
683 | GNUNET_break_op (0); | ||
684 | gcry_sexp_release (sig->sexp); | ||
685 | GNUNET_free (sig); | ||
686 | return NULL; | ||
687 | } | ||
688 | gcry_mpi_release (s); | ||
689 | return sig; | ||
690 | } | ||
691 | |||
692 | |||
693 | /** | ||
694 | * Unblind a signature made on blinding signature purpose. The signature | ||
695 | * purpose should have been generated with #GNUNET_CRYPTO_rsa_sign() using | ||
696 | * a message that was generated with #GNUNET_CRYPTO_rsa_blind(). | ||
697 | * | ||
698 | * @param sig the signature made on the blinded signature purpose | ||
699 | * @param bkey the blinding key used to blind the signature purpose | ||
700 | * @param pkey the public key of the signer | ||
701 | * @return unblinded signature on success, NULL on error | ||
702 | */ | ||
703 | struct GNUNET_CRYPTO_rsa_Signature * | ||
704 | GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_rsa_Signature *sig, | ||
705 | struct GNUNET_CRYPTO_rsa_BlindingKey *bkey, | ||
706 | struct GNUNET_CRYPTO_rsa_PublicKey *pkey) | ||
707 | { | ||
708 | gcry_mpi_t n; | ||
709 | gcry_mpi_t s; | ||
710 | gcry_mpi_t r_inv; | ||
711 | gcry_mpi_t ubsig; | ||
712 | int ret; | ||
713 | struct GNUNET_CRYPTO_rsa_Signature *sret; | ||
714 | |||
715 | ret = key_from_sexp (&n, pkey->sexp, "public-key", "n"); | ||
716 | if (0 != ret) | ||
717 | ret = key_from_sexp (&n, pkey->sexp, "rsa", "n"); | ||
718 | if (0 != ret) | ||
719 | { | ||
720 | GNUNET_break_op (0); | ||
721 | return NULL; | ||
722 | } | ||
723 | ret = key_from_sexp (&s, sig->sexp, "sig-val", "s"); | ||
724 | if (0 != ret) | ||
725 | ret = key_from_sexp (&s, sig->sexp, "rsa", "s"); | ||
726 | if (0 != ret) | ||
727 | { | ||
728 | gcry_mpi_release (n); | ||
729 | GNUNET_break_op (0); | ||
730 | return NULL; | ||
731 | } | ||
732 | r_inv = gcry_mpi_new (0); | ||
733 | if (1 != | ||
734 | gcry_mpi_invm (r_inv, | ||
735 | bkey->r, | ||
736 | n)) | ||
737 | { | ||
738 | GNUNET_break_op (0); | ||
739 | gcry_mpi_release (n); | ||
740 | gcry_mpi_release (r_inv); | ||
741 | gcry_mpi_release (s); | ||
742 | return NULL; | ||
743 | } | ||
744 | ubsig = gcry_mpi_new (0); | ||
745 | gcry_mpi_mulm (ubsig, s, r_inv, n); | ||
746 | gcry_mpi_release (n); | ||
747 | gcry_mpi_release (r_inv); | ||
748 | gcry_mpi_release (s); | ||
749 | |||
750 | sret = GNUNET_new (struct GNUNET_CRYPTO_rsa_Signature); | ||
751 | GNUNET_assert (0 == | ||
752 | gcry_sexp_build (&sret->sexp, | ||
753 | NULL, | ||
754 | "(sig-val (rsa (s %M)))", | ||
755 | ubsig)); | ||
756 | gcry_mpi_release (ubsig); | ||
757 | return sret; | ||
758 | } | ||
759 | |||
760 | |||
761 | /** | ||
762 | * Verify signature with the given hash. | ||
763 | * | ||
764 | * @param hash hash of the message to verify to match the @a sig | ||
765 | * @param sig signature that is being validated | ||
766 | * @param public_key public key of the signer | ||
767 | * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid | ||
768 | */ | ||
769 | int | ||
770 | GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash, | ||
771 | const struct GNUNET_CRYPTO_rsa_Signature *sig, | ||
772 | const struct GNUNET_CRYPTO_rsa_PublicKey *public_key) | ||
773 | { | ||
774 | gcry_sexp_t data; | ||
775 | int rc; | ||
776 | |||
777 | data = data_to_sexp (hash, | ||
778 | sizeof (struct GNUNET_HashCode)); | ||
779 | rc = gcry_pk_verify (sig->sexp, | ||
780 | data, | ||
781 | public_key->sexp); | ||
782 | gcry_sexp_release (data); | ||
783 | if (0 != rc) | ||
784 | { | ||
785 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
786 | _("RSA signature verification failed at %s:%d: %s\n"), | ||
787 | __FILE__, | ||
788 | __LINE__, | ||
789 | gcry_strerror (rc)); | ||
790 | return GNUNET_SYSERR; | ||
791 | } | ||
792 | return GNUNET_OK; | ||
793 | } | ||
794 | |||
795 | |||
796 | /* end of util/rsa.c */ | ||
diff --git a/src/util/test_crypto_rsa.c b/src/util/test_crypto_rsa.c new file mode 100644 index 000000000..a0a6b4722 --- /dev/null +++ b/src/util/test_crypto_rsa.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2014 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet 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 | GNUnet 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/test_crypto_rsa.c | ||
19 | * @brief testcase for utility functions for RSA cryptography | ||
20 | * @author Sree Harsha Totakura <sreeharsha@totakura.in> | ||
21 | */ | ||
22 | #include "platform.h" | ||
23 | #include <gnunet/gnunet_util_lib.h> | ||
24 | |||
25 | #define KEY_SIZE 1024 | ||
26 | |||
27 | |||
28 | int | ||
29 | main (int argc, | ||
30 | char *argv[]) | ||
31 | { | ||
32 | #define RND_BLK_SIZE 4096 | ||
33 | unsigned char rnd_blk[RND_BLK_SIZE]; | ||
34 | struct GNUNET_CRYPTO_rsa_PrivateKey *priv; | ||
35 | struct GNUNET_CRYPTO_rsa_PublicKey *pub; | ||
36 | struct GNUNET_CRYPTO_rsa_BlindingKey *bkey; | ||
37 | struct GNUNET_CRYPTO_rsa_Signature *sig; | ||
38 | struct GNUNET_CRYPTO_rsa_Signature *bsig; | ||
39 | struct GNUNET_HashCode hash; | ||
40 | char *blind_buf; | ||
41 | size_t bsize; | ||
42 | |||
43 | GNUNET_log_setup ("test-rsa", "WARNING", NULL); | ||
44 | GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, | ||
45 | rnd_blk, | ||
46 | RND_BLK_SIZE); | ||
47 | GNUNET_CRYPTO_hash (rnd_blk, | ||
48 | RND_BLK_SIZE, | ||
49 | &hash); | ||
50 | priv = GNUNET_CRYPTO_rsa_private_key_create (KEY_SIZE); | ||
51 | pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv); | ||
52 | /* try ordinary sig first */ | ||
53 | sig = GNUNET_CRYPTO_rsa_sign (priv, | ||
54 | &hash, | ||
55 | sizeof (hash)); | ||
56 | GNUNET_assert (GNUNET_OK == | ||
57 | GNUNET_CRYPTO_rsa_verify (&hash, sig, pub)); | ||
58 | GNUNET_CRYPTO_rsa_signature_free (sig); | ||
59 | |||
60 | /* test blind signing */ | ||
61 | bkey = GNUNET_CRYPTO_rsa_blinding_key_create (KEY_SIZE); | ||
62 | bsize = GNUNET_CRYPTO_rsa_blind (&hash, | ||
63 | bkey, | ||
64 | pub, | ||
65 | &blind_buf); | ||
66 | GNUNET_assert (0 != bsize); | ||
67 | bsig = GNUNET_CRYPTO_rsa_sign (priv, | ||
68 | blind_buf, | ||
69 | bsize); | ||
70 | GNUNET_free (blind_buf); | ||
71 | sig = GNUNET_CRYPTO_rsa_unblind (bsig, | ||
72 | bkey, | ||
73 | pub); | ||
74 | GNUNET_CRYPTO_rsa_signature_free (bsig); | ||
75 | GNUNET_assert (GNUNET_OK == | ||
76 | GNUNET_CRYPTO_rsa_verify (&hash, sig, pub)); | ||
77 | GNUNET_CRYPTO_rsa_signature_free (sig); | ||
78 | GNUNET_CRYPTO_rsa_private_key_free (priv); | ||
79 | GNUNET_CRYPTO_rsa_public_key_free (pub); | ||
80 | GNUNET_CRYPTO_rsa_blinding_key_free (bkey); | ||
81 | return 0; | ||
82 | } | ||