aboutsummaryrefslogtreecommitdiff
path: root/src/lib/util/crypto_rsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/crypto_rsa.c')
-rw-r--r--src/lib/util/crypto_rsa.c1263
1 files changed, 1263 insertions, 0 deletions
diff --git a/src/lib/util/crypto_rsa.c b/src/lib/util/crypto_rsa.c
new file mode 100644
index 000000000..2c446d21a
--- /dev/null
+++ b/src/lib/util/crypto_rsa.c
@@ -0,0 +1,1263 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014,2016,2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/crypto_rsa.c
23 * @brief Chaum-style Blind signatures based on RSA
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 * @author Christian Grothoff
26 * @author Jeffrey Burdges <burdges@gnunet.org>
27 */
28
29#include "platform.h"
30#include <gcrypt.h>
31#include "gnunet_util_lib.h"
32#include "benchmark.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-rsa", __VA_ARGS__)
35
36
37/**
38 * The private information of an RSA key pair.
39 */
40struct GNUNET_CRYPTO_RsaPrivateKey
41{
42 /**
43 * Libgcrypt S-expression for the RSA private key.
44 */
45 gcry_sexp_t sexp;
46};
47
48
49/**
50 * The public information of an RSA key pair.
51 */
52struct GNUNET_CRYPTO_RsaPublicKey
53{
54 /**
55 * Libgcrypt S-expression for the RSA public key.
56 */
57 gcry_sexp_t sexp;
58};
59
60
61/**
62 * @brief an RSA signature
63 */
64struct GNUNET_CRYPTO_RsaSignature
65{
66 /**
67 * Libgcrypt S-expression for the RSA signature.
68 */
69 gcry_sexp_t sexp;
70};
71
72
73/**
74 * @brief RSA blinding key
75 */
76struct RsaBlindingKey
77{
78 /**
79 * Random value used for blinding.
80 */
81 gcry_mpi_t r;
82};
83
84
85/**
86 * Extract values from an S-expression.
87 *
88 * @param array where to store the result(s)
89 * @param sexp S-expression to parse
90 * @param topname top-level name in the S-expression that is of interest
91 * @param elems names of the elements to extract
92 * @return 0 on success
93 */
94static int
95key_from_sexp (gcry_mpi_t *array,
96 gcry_sexp_t sexp,
97 const char *topname,
98 const char *elems)
99{
100 gcry_sexp_t list;
101 gcry_sexp_t l2;
102 const char *s;
103 unsigned int idx;
104
105 if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
106 return 1;
107 l2 = gcry_sexp_cadr (list);
108 gcry_sexp_release (list);
109 list = l2;
110 if (! list)
111 return 2;
112 idx = 0;
113 for (s = elems; *s; s++, idx++)
114 {
115 if (! (l2 = gcry_sexp_find_token (list, s, 1)))
116 {
117 for (unsigned int i = 0; i < idx; i++)
118 {
119 gcry_free (array[i]);
120 array[i] = NULL;
121 }
122 gcry_sexp_release (list);
123 return 3; /* required parameter not found */
124 }
125 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
126 gcry_sexp_release (l2);
127 if (! array[idx])
128 {
129 for (unsigned int i = 0; i < idx; i++)
130 {
131 gcry_free (array[i]);
132 array[i] = NULL;
133 }
134 gcry_sexp_release (list);
135 return 4; /* required parameter is invalid */
136 }
137 }
138 gcry_sexp_release (list);
139 return 0;
140}
141
142
143struct GNUNET_CRYPTO_RsaPrivateKey *
144GNUNET_CRYPTO_rsa_private_key_create (unsigned int len)
145{
146 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
147 gcry_sexp_t s_key;
148 gcry_sexp_t s_keyparam;
149
150 BENCHMARK_START (rsa_private_key_create);
151
152 GNUNET_assert (0 ==
153 gcry_sexp_build (&s_keyparam,
154 NULL,
155 "(genkey(rsa(nbits %d)))",
156 len));
157 GNUNET_assert (0 ==
158 gcry_pk_genkey (&s_key,
159 s_keyparam));
160 gcry_sexp_release (s_keyparam);
161#if EXTRA_CHECKS
162 GNUNET_assert (0 ==
163 gcry_pk_testkey (s_key));
164#endif
165 ret = GNUNET_new (struct GNUNET_CRYPTO_RsaPrivateKey);
166 ret->sexp = s_key;
167 BENCHMARK_END (rsa_private_key_create);
168 return ret;
169}
170
171
172void
173GNUNET_CRYPTO_rsa_private_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *key)
174{
175 gcry_sexp_release (key->sexp);
176 GNUNET_free (key);
177}
178
179
180size_t
181GNUNET_CRYPTO_rsa_private_key_encode (const struct
182 GNUNET_CRYPTO_RsaPrivateKey *key,
183 void **buffer)
184{
185 size_t n;
186 char *b;
187
188 n = gcry_sexp_sprint (key->sexp,
189 GCRYSEXP_FMT_DEFAULT,
190 NULL,
191 0);
192 b = GNUNET_malloc (n);
193 GNUNET_assert ((n - 1) == /* since the last byte is \0 */
194 gcry_sexp_sprint (key->sexp,
195 GCRYSEXP_FMT_DEFAULT,
196 b,
197 n));
198 *buffer = b;
199 return n;
200}
201
202
203struct GNUNET_CRYPTO_RsaPrivateKey *
204GNUNET_CRYPTO_rsa_private_key_decode (const void *buf,
205 size_t buf_size)
206{
207 struct GNUNET_CRYPTO_RsaPrivateKey *key;
208
209 key = GNUNET_new (struct GNUNET_CRYPTO_RsaPrivateKey);
210 if (0 !=
211 gcry_sexp_new (&key->sexp,
212 buf,
213 buf_size,
214 0))
215 {
216 LOG (GNUNET_ERROR_TYPE_WARNING,
217 "Decoded private key is not valid\n");
218 GNUNET_free (key);
219 return NULL;
220 }
221 if (0 != gcry_pk_testkey (key->sexp))
222 {
223 LOG (GNUNET_ERROR_TYPE_WARNING,
224 "Decoded private key is not valid\n");
225 GNUNET_CRYPTO_rsa_private_key_free (key);
226 return NULL;
227 }
228 return key;
229}
230
231
232struct GNUNET_CRYPTO_RsaPublicKey *
233GNUNET_CRYPTO_rsa_private_key_get_public (
234 const struct GNUNET_CRYPTO_RsaPrivateKey *priv)
235{
236 struct GNUNET_CRYPTO_RsaPublicKey *pub;
237 gcry_mpi_t ne[2];
238 int rc;
239 gcry_sexp_t result;
240
241 BENCHMARK_START (rsa_private_key_get_public);
242
243 rc = key_from_sexp (ne, priv->sexp, "public-key", "ne");
244 if (0 != rc)
245 rc = key_from_sexp (ne, priv->sexp, "private-key", "ne");
246 if (0 != rc)
247 rc = key_from_sexp (ne, priv->sexp, "rsa", "ne");
248 if (0 != rc)
249 {
250 GNUNET_break_op (0);
251 return NULL;
252 }
253 rc = gcry_sexp_build (&result,
254 NULL,
255 "(public-key(rsa(n %m)(e %m)))",
256 ne[0],
257 ne[1]);
258 gcry_mpi_release (ne[0]);
259 gcry_mpi_release (ne[1]);
260 pub = GNUNET_new (struct GNUNET_CRYPTO_RsaPublicKey);
261 pub->sexp = result;
262 BENCHMARK_END (rsa_private_key_get_public);
263 return pub;
264}
265
266
267void
268GNUNET_CRYPTO_rsa_public_key_free (struct GNUNET_CRYPTO_RsaPublicKey *key)
269{
270 gcry_sexp_release (key->sexp);
271 GNUNET_free (key);
272}
273
274
275GNUNET_NETWORK_STRUCT_BEGIN
276
277/**
278 * Format of the header of a serialized RSA public key.
279 */
280struct GNUNET_CRYPTO_RsaPublicKeyHeaderP
281{
282 /**
283 * length of modulus 'n' in bytes, in NBO
284 */
285 uint16_t modulus_length GNUNET_PACKED;
286
287 /**
288 * length of exponent in bytes, in NBO
289 */
290 uint16_t public_exponent_length GNUNET_PACKED;
291
292 /* followed by variable-size modulus and
293 public exponent follows as big-endian encoded
294 integers */
295};
296
297GNUNET_NETWORK_STRUCT_END
298
299
300bool
301GNUNET_CRYPTO_rsa_public_key_check (
302 const struct GNUNET_CRYPTO_RsaPublicKey *key)
303{
304 gcry_mpi_t ne[2];
305 int ret;
306
307 ret = key_from_sexp (ne,
308 key->sexp,
309 "public-key",
310 "ne");
311 if (0 != ret)
312 ret = key_from_sexp (ne,
313 key->sexp,
314 "rsa",
315 "ne");
316 if (0 != ret)
317 return false;
318 gcry_mpi_release (ne[0]);
319 gcry_mpi_release (ne[1]);
320 return true;
321}
322
323
324size_t
325GNUNET_CRYPTO_rsa_public_key_encode (
326 const struct GNUNET_CRYPTO_RsaPublicKey *key,
327 void **buffer)
328{
329 gcry_mpi_t ne[2];
330 size_t n_size;
331 size_t e_size;
332 size_t rsize;
333 size_t buf_size;
334 char *buf;
335 struct GNUNET_CRYPTO_RsaPublicKeyHeaderP hdr;
336 int ret;
337
338 ret = key_from_sexp (ne,
339 key->sexp,
340 "public-key",
341 "ne");
342 if (0 != ret)
343 ret = key_from_sexp (ne,
344 key->sexp,
345 "rsa",
346 "ne");
347 if (0 != ret)
348 {
349 GNUNET_break (0);
350 *buffer = NULL;
351 return 0;
352 }
353 gcry_mpi_print (GCRYMPI_FMT_USG,
354 NULL,
355 0,
356 &n_size,
357 ne[0]);
358 gcry_mpi_print (GCRYMPI_FMT_USG,
359 NULL,
360 0,
361 &e_size,
362 ne[1]);
363 if ( (e_size > UINT16_MAX) ||
364 (n_size > UINT16_MAX) )
365 {
366 GNUNET_break (0);
367 if (NULL != buffer)
368 *buffer = NULL;
369 gcry_mpi_release (ne[0]);
370 gcry_mpi_release (ne[1]);
371 return 0;
372 }
373 buf_size = n_size + e_size + sizeof (hdr);
374 if (NULL == buffer)
375 {
376 gcry_mpi_release (ne[0]);
377 gcry_mpi_release (ne[1]);
378 return buf_size;
379 }
380 buf = GNUNET_malloc (buf_size);
381 hdr.modulus_length = htons ((uint16_t) n_size);
382 hdr.public_exponent_length = htons ((uint16_t) e_size);
383 memcpy (buf,
384 &hdr,
385 sizeof (hdr));
386 GNUNET_assert (0 ==
387 gcry_mpi_print (GCRYMPI_FMT_USG,
388 (unsigned char *) &buf[sizeof (hdr)],
389 n_size,
390 &rsize,
391 ne[0]));
392
393 GNUNET_assert (0 ==
394 gcry_mpi_print (GCRYMPI_FMT_USG,
395 (unsigned char *) &buf[sizeof (hdr) + n_size],
396 e_size,
397 &rsize,
398 ne[1]));
399 *buffer = buf;
400 gcry_mpi_release (ne[0]);
401 gcry_mpi_release (ne[1]);
402 return buf_size;
403}
404
405
406void
407GNUNET_CRYPTO_rsa_public_key_hash (const struct GNUNET_CRYPTO_RsaPublicKey *key,
408 struct GNUNET_HashCode *hc)
409{
410 void *buf;
411 size_t buf_size;
412
413 buf_size = GNUNET_CRYPTO_rsa_public_key_encode (key,
414 &buf);
415 GNUNET_CRYPTO_hash (buf,
416 buf_size,
417 hc);
418 GNUNET_free (buf);
419}
420
421
422struct GNUNET_CRYPTO_RsaPublicKey *
423GNUNET_CRYPTO_rsa_public_key_decode (const char *buf,
424 size_t len)
425{
426 struct GNUNET_CRYPTO_RsaPublicKey *key;
427 struct GNUNET_CRYPTO_RsaPublicKeyHeaderP hdr;
428 size_t e_size;
429 size_t n_size;
430 gcry_mpi_t n;
431 gcry_mpi_t e;
432 gcry_sexp_t data;
433
434 if (len < sizeof (hdr))
435 {
436 GNUNET_break_op (0);
437 return NULL;
438 }
439 memcpy (&hdr, buf, sizeof (hdr));
440 n_size = ntohs (hdr.modulus_length);
441 e_size = ntohs (hdr.public_exponent_length);
442 if (len != sizeof (hdr) + e_size + n_size)
443 {
444 GNUNET_break_op (0);
445 return NULL;
446 }
447 if (0 !=
448 gcry_mpi_scan (&n,
449 GCRYMPI_FMT_USG,
450 &buf[sizeof (hdr)],
451 n_size,
452 NULL))
453 {
454 GNUNET_break_op (0);
455 return NULL;
456 }
457 if (0 !=
458 gcry_mpi_scan (&e,
459 GCRYMPI_FMT_USG,
460 &buf[sizeof (hdr) + n_size],
461 e_size,
462 NULL))
463 {
464 GNUNET_break_op (0);
465 gcry_mpi_release (n);
466 return NULL;
467 }
468
469 if (0 !=
470 gcry_sexp_build (&data,
471 NULL,
472 "(public-key(rsa(n %m)(e %m)))",
473 n,
474 e))
475 {
476 GNUNET_break (0);
477 gcry_mpi_release (n);
478 gcry_mpi_release (e);
479 return NULL;
480 }
481 gcry_mpi_release (n);
482 gcry_mpi_release (e);
483 key = GNUNET_new (struct GNUNET_CRYPTO_RsaPublicKey);
484 key->sexp = data;
485 return key;
486}
487
488
489/**
490 * Test for malicious RSA key.
491 *
492 * Assuming n is an RSA modulous and r is generated using a call to
493 * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a
494 * malicious RSA key designed to deanomize the user.
495 *
496 * @param r KDF result
497 * @param n RSA modulus
498 * @return True if gcd(r,n) = 1, False means RSA key is malicious
499 */
500static int
501rsa_gcd_validate (gcry_mpi_t r,
502 gcry_mpi_t n)
503{
504 gcry_mpi_t g;
505 int t;
506
507 g = gcry_mpi_new (0);
508 t = gcry_mpi_gcd (g, r, n);
509 gcry_mpi_release (g);
510 return t;
511}
512
513
514/**
515 * Create a blinding key
516 *
517 * @param len length of the key in bits (e.g. 2048)
518 * @param bks pre-secret to use to derive the blinding key
519 * @return the newly created blinding key, NULL if RSA key is malicious
520 */
521static struct RsaBlindingKey *
522rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
523 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks)
524{
525 const char *xts = "Blinding KDF extractor HMAC key"; /* Trusts bks' randomness more */
526 struct RsaBlindingKey *blind;
527 gcry_mpi_t n;
528
529 blind = GNUNET_new (struct RsaBlindingKey);
530
531 /* Extract the composite n from the RSA public key */
532 GNUNET_assert (0 ==
533 key_from_sexp (&n,
534 pkey->sexp,
535 "rsa",
536 "n"));
537 /* Assert that it at least looks like an RSA key */
538 GNUNET_assert (0 ==
539 gcry_mpi_get_flag (n,
540 GCRYMPI_FLAG_OPAQUE));
541 GNUNET_CRYPTO_kdf_mod_mpi (&blind->r,
542 n,
543 xts, strlen (xts),
544 bks, sizeof(*bks),
545 "Blinding KDF");
546 if (0 == rsa_gcd_validate (blind->r,
547 n))
548 {
549 gcry_mpi_release (blind->r);
550 GNUNET_free (blind);
551 blind = NULL;
552 }
553 gcry_mpi_release (n);
554 return blind;
555}
556
557
558/*
559 We originally added GNUNET_CRYPTO_kdf_mod_mpi for the benefit of the
560 previous routine.
561
562 There was previously a call to GNUNET_CRYPTO_kdf in
563 bkey = rsa_blinding_key_derive (len, bks);
564 that gives exactly len bits where
565 len = GNUNET_CRYPTO_rsa_public_key_len (pkey);
566
567 Now r = 2^(len-1)/pkey.n is the probability that a set high bit being
568 okay, meaning bkey < pkey.n. It follows that (1-r)/2 of the time bkey >
569 pkey.n making the effective bkey be
570 bkey mod pkey.n = bkey - pkey.n
571 so the effective bkey has its high bit set with probability r/2.
572
573 We expect r to be close to 1/2 if the exchange is honest, but the
574 exchange can choose r otherwise.
575
576 In blind signing, the exchange sees
577 B = bkey * S mod pkey.n
578 On deposit, the exchange sees S so they can compute bkey' = B/S mod
579 pkey.n for all B they recorded to see if bkey' has it's high bit set.
580 Also, note the exchange can compute 1/S efficiently since they know the
581 factors of pkey.n.
582
583 I suppose that happens with probability r/(1+r) if its the wrong B, not
584 completely sure. If otoh we've the right B, then we've the probability
585 r/2 of a set high bit in the effective bkey.
586
587 Interestingly, r^2-r has a maximum at the default r=1/2 anyways, giving
588 the wrong and right probabilities 1/3 and 1/4, respectively.
589
590 I feared this gives the exchange a meaningful fraction of a bit of
591 information per coin involved in the transaction. It sounds damaging if
592 numerous coins were involved. And it could run across transactions in
593 some scenarios.
594
595 We fixed this by using a more uniform deterministic pseudo-random number
596 generator for blinding factors. I do not believe this to be a problem
597 for the rsa_full_domain_hash routine, but better safe than sorry.
598 */
599
600
601int
602GNUNET_CRYPTO_rsa_signature_cmp (const struct GNUNET_CRYPTO_RsaSignature *s1,
603 const struct GNUNET_CRYPTO_RsaSignature *s2)
604{
605 void *b1;
606 void *b2;
607 size_t z1;
608 size_t z2;
609 int ret;
610
611 z1 = GNUNET_CRYPTO_rsa_signature_encode (s1,
612 &b1);
613 z2 = GNUNET_CRYPTO_rsa_signature_encode (s2,
614 &b2);
615 if (z1 != z2)
616 ret = 1;
617 else
618 ret = memcmp (b1,
619 b2,
620 z1);
621 GNUNET_free (b1);
622 GNUNET_free (b2);
623 return ret;
624}
625
626
627int
628GNUNET_CRYPTO_rsa_public_key_cmp (const struct GNUNET_CRYPTO_RsaPublicKey *p1,
629 const struct GNUNET_CRYPTO_RsaPublicKey *p2)
630{
631 void *b1;
632 void *b2;
633 size_t z1;
634 size_t z2;
635 int ret;
636
637 z1 = GNUNET_CRYPTO_rsa_public_key_encode (p1,
638 &b1);
639 z2 = GNUNET_CRYPTO_rsa_public_key_encode (p2,
640 &b2);
641 if (z1 != z2)
642 ret = 1;
643 else
644 ret = memcmp (b1,
645 b2,
646 z1);
647 GNUNET_free (b1);
648 GNUNET_free (b2);
649 return ret;
650}
651
652
653int
654GNUNET_CRYPTO_rsa_private_key_cmp (const struct GNUNET_CRYPTO_RsaPrivateKey *p1,
655 const struct GNUNET_CRYPTO_RsaPrivateKey *p2)
656{
657 void *b1;
658 void *b2;
659 size_t z1;
660 size_t z2;
661 int ret;
662
663 z1 = GNUNET_CRYPTO_rsa_private_key_encode (p1,
664 &b1);
665 z2 = GNUNET_CRYPTO_rsa_private_key_encode (p2,
666 &b2);
667 if (z1 != z2)
668 ret = 1;
669 else
670 ret = memcmp (b1,
671 b2,
672 z1);
673 GNUNET_free (b1);
674 GNUNET_free (b2);
675 return ret;
676}
677
678
679unsigned int
680GNUNET_CRYPTO_rsa_public_key_len (const struct GNUNET_CRYPTO_RsaPublicKey *key)
681{
682 gcry_mpi_t n;
683 unsigned int rval;
684
685 if (0 != key_from_sexp (&n, key->sexp, "rsa", "n"))
686 { /* Not an RSA public key */
687 GNUNET_break (0);
688 return 0;
689 }
690 rval = gcry_mpi_get_nbits (n);
691 gcry_mpi_release (n);
692 return rval;
693}
694
695
696/**
697 * Destroy a blinding key
698 *
699 * @param bkey the blinding key to destroy
700 */
701static void
702rsa_blinding_key_free (struct RsaBlindingKey *bkey)
703{
704 gcry_mpi_release (bkey->r);
705 GNUNET_free (bkey);
706}
707
708
709/**
710 * Print an MPI to a newly created buffer
711 *
712 * @param v MPI to print.
713 * @param[out] buffer newly allocated buffer containing the result
714 * @return number of bytes stored in @a buffer
715 */
716static size_t
717numeric_mpi_alloc_n_print (gcry_mpi_t v,
718 char **buffer)
719{
720 size_t n;
721 char *b;
722 size_t rsize;
723
724 gcry_mpi_print (GCRYMPI_FMT_USG,
725 NULL,
726 0,
727 &n,
728 v);
729 b = GNUNET_malloc (n);
730 GNUNET_assert (0 ==
731 gcry_mpi_print (GCRYMPI_FMT_USG,
732 (unsigned char *) b,
733 n,
734 &rsize,
735 v));
736 *buffer = b;
737 return n;
738}
739
740
741/**
742 * Computes a full domain hash seeded by the given public key.
743 * This gives a measure of provable security to the Taler exchange
744 * against one-more forgery attacks. See:
745 * https://eprint.iacr.org/2001/002.pdf
746 * http://www.di.ens.fr/~pointche/Documents/Papers/2001_fcA.pdf
747 *
748 * @param hash initial hash of the message to sign
749 * @param pkey the public key of the signer
750 * @param rsize If not NULL, the number of bytes actually stored in buffer
751 * @return MPI value set to the FDH, NULL if RSA key is malicious
752 */
753static gcry_mpi_t
754rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
755 const struct GNUNET_HashCode *hash)
756{
757 gcry_mpi_t r, n;
758 void *xts;
759 size_t xts_len;
760 int ok;
761
762 /* Extract the composite n from the RSA public key */
763 GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
764 /* Assert that it at least looks like an RSA key */
765 GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
766
767 /* We key with the public denomination key as a homage to RSA-PSS by *
768 * Mihir Bellare and Phillip Rogaway. Doing this lowers the degree *
769 * of the hypothetical polyomial-time attack on RSA-KTI created by a *
770 * polynomial-time one-more forgary attack. Yey seeding! */
771 xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey,
772 &xts);
773
774 GNUNET_CRYPTO_kdf_mod_mpi (&r,
775 n,
776 xts, xts_len,
777 hash, sizeof(*hash),
778 "RSA-FDA FTpsW!");
779 GNUNET_free (xts);
780 ok = rsa_gcd_validate (r, n);
781 gcry_mpi_release (n);
782 if (ok)
783 return r;
784 gcry_mpi_release (r);
785 return NULL;
786}
787
788
789enum GNUNET_GenericReturnValue
790GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash,
791 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
792 struct GNUNET_CRYPTO_RsaPublicKey *pkey,
793 void **buf,
794 size_t *buf_size)
795{
796 struct RsaBlindingKey *bkey;
797 gcry_mpi_t data;
798 gcry_mpi_t ne[2];
799 gcry_mpi_t r_e;
800 gcry_mpi_t data_r_e;
801 int ret;
802
803 BENCHMARK_START (rsa_blind);
804
805 GNUNET_assert (buf != NULL);
806 GNUNET_assert (buf_size != NULL);
807 ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne");
808 if (0 != ret)
809 ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne");
810 if (0 != ret)
811 {
812 GNUNET_break (0);
813 *buf = NULL;
814 *buf_size = 0;
815 return GNUNET_NO;
816 }
817
818 data = rsa_full_domain_hash (pkey, hash);
819 if (NULL == data)
820 goto rsa_gcd_validate_failure;
821
822 bkey = rsa_blinding_key_derive (pkey, bks);
823 if (NULL == bkey)
824 {
825 gcry_mpi_release (data);
826 goto rsa_gcd_validate_failure;
827 }
828
829 r_e = gcry_mpi_new (0);
830 gcry_mpi_powm (r_e,
831 bkey->r,
832 ne[1],
833 ne[0]);
834 data_r_e = gcry_mpi_new (0);
835 gcry_mpi_mulm (data_r_e,
836 data,
837 r_e,
838 ne[0]);
839 gcry_mpi_release (data);
840 gcry_mpi_release (ne[0]);
841 gcry_mpi_release (ne[1]);
842 gcry_mpi_release (r_e);
843 rsa_blinding_key_free (bkey);
844
845 *buf_size = numeric_mpi_alloc_n_print (data_r_e,
846 (char **) buf);
847 gcry_mpi_release (data_r_e);
848
849 BENCHMARK_END (rsa_blind);
850
851 return GNUNET_YES;
852
853rsa_gcd_validate_failure:
854 /* We know the RSA key is malicious here, so warn the wallet. */
855 /* GNUNET_break_op (0); */
856 gcry_mpi_release (ne[0]);
857 gcry_mpi_release (ne[1]);
858 *buf = NULL;
859 *buf_size = 0;
860 return GNUNET_NO;
861}
862
863
864/**
865 * Convert an MPI to an S-expression suitable for signature operations.
866 *
867 * @param value pointer to the data to convert
868 * @return converted s-expression
869 */
870static gcry_sexp_t
871mpi_to_sexp (gcry_mpi_t value)
872{
873 gcry_sexp_t data = NULL;
874
875 GNUNET_assert (0 ==
876 gcry_sexp_build (&data,
877 NULL,
878 "(data (flags raw) (value %M))",
879 value));
880 return data;
881}
882
883
884/**
885 * Sign the given MPI.
886 *
887 * @param key private key to use for the signing
888 * @param value the MPI to sign
889 * @return NULL on error, signature on success
890 */
891static struct GNUNET_CRYPTO_RsaSignature *
892rsa_sign_mpi (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
893 gcry_mpi_t value)
894{
895 struct GNUNET_CRYPTO_RsaSignature *sig;
896 gcry_sexp_t data;
897 gcry_sexp_t result;
898 int rc;
899
900 data = mpi_to_sexp (value);
901
902 if (0 !=
903 (rc = gcry_pk_sign (&result,
904 data,
905 key->sexp)))
906 {
907 LOG (GNUNET_ERROR_TYPE_WARNING,
908 _ ("RSA signing failed at %s:%d: %s\n"),
909 __FILE__,
910 __LINE__,
911 gcry_strerror (rc));
912 gcry_sexp_release (data);
913 GNUNET_break (0);
914 return NULL;
915 }
916
917 /* Lenstra protection was first added to libgcrypt 1.6.4
918 * with commit c17f84bd02d7ee93845e92e20f6ddba814961588.
919 */
920#if GCRYPT_VERSION_NUMBER < 0x010604
921 /* verify signature (guards against Lenstra's attack with fault injection...) */
922 struct GNUNET_CRYPTO_RsaPublicKey *public_key =
923 GNUNET_CRYPTO_rsa_private_key_get_public (key);
924 if (0 !=
925 gcry_pk_verify (result,
926 data,
927 public_key->sexp))
928 {
929 GNUNET_break (0);
930 GNUNET_CRYPTO_rsa_public_key_free (public_key);
931 gcry_sexp_release (data);
932 gcry_sexp_release (result);
933 return NULL;
934 }
935 GNUNET_CRYPTO_rsa_public_key_free (public_key);
936#endif
937
938 /* return signature */
939 gcry_sexp_release (data);
940 sig = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
941 sig->sexp = result;
942 return sig;
943}
944
945
946struct GNUNET_CRYPTO_RsaSignature *
947GNUNET_CRYPTO_rsa_sign_blinded (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
948 const void *msg,
949 size_t msg_len)
950{
951 gcry_mpi_t v = NULL;
952 struct GNUNET_CRYPTO_RsaSignature *sig;
953
954 BENCHMARK_START (rsa_sign_blinded);
955
956 GNUNET_assert (0 ==
957 gcry_mpi_scan (&v,
958 GCRYMPI_FMT_USG,
959 msg,
960 msg_len,
961 NULL));
962
963 sig = rsa_sign_mpi (key, v);
964 gcry_mpi_release (v);
965 BENCHMARK_END (rsa_sign_blinded);
966 return sig;
967}
968
969
970struct GNUNET_CRYPTO_RsaSignature *
971GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
972 const struct GNUNET_HashCode *hash)
973{
974 struct GNUNET_CRYPTO_RsaPublicKey *pkey;
975 gcry_mpi_t v = NULL;
976 struct GNUNET_CRYPTO_RsaSignature *sig;
977
978 pkey = GNUNET_CRYPTO_rsa_private_key_get_public (key);
979 v = rsa_full_domain_hash (pkey, hash);
980 GNUNET_CRYPTO_rsa_public_key_free (pkey);
981 if (NULL == v) /* rsa_gcd_validate failed meaning */
982 return NULL; /* our *own* RSA key is malicious. */
983
984 sig = rsa_sign_mpi (key, v);
985 gcry_mpi_release (v);
986 return sig;
987}
988
989
990void
991GNUNET_CRYPTO_rsa_signature_free (struct GNUNET_CRYPTO_RsaSignature *sig)
992{
993 gcry_sexp_release (sig->sexp);
994 GNUNET_free (sig);
995}
996
997
998size_t
999GNUNET_CRYPTO_rsa_signature_encode (
1000 const struct GNUNET_CRYPTO_RsaSignature *sig,
1001 void **buffer)
1002{
1003 gcry_mpi_t s;
1004 size_t buf_size;
1005 size_t rsize;
1006 unsigned char *buf;
1007 int ret;
1008
1009 ret = key_from_sexp (&s,
1010 sig->sexp,
1011 "sig-val",
1012 "s");
1013 if (0 != ret)
1014 ret = key_from_sexp (&s,
1015 sig->sexp,
1016 "rsa",
1017 "s");
1018 GNUNET_assert (0 == ret);
1019 gcry_mpi_print (GCRYMPI_FMT_USG,
1020 NULL,
1021 0,
1022 &buf_size,
1023 s);
1024 buf = GNUNET_malloc (buf_size);
1025 GNUNET_assert (0 ==
1026 gcry_mpi_print (GCRYMPI_FMT_USG,
1027 buf,
1028 buf_size,
1029 &rsize,
1030 s));
1031 GNUNET_assert (rsize == buf_size);
1032 *buffer = (void *) buf;
1033 gcry_mpi_release (s);
1034 return buf_size;
1035}
1036
1037
1038struct GNUNET_CRYPTO_RsaSignature *
1039GNUNET_CRYPTO_rsa_signature_decode (const void *buf,
1040 size_t buf_size)
1041{
1042 struct GNUNET_CRYPTO_RsaSignature *sig;
1043 gcry_mpi_t s;
1044 gcry_sexp_t data;
1045
1046 if (0 !=
1047 gcry_mpi_scan (&s,
1048 GCRYMPI_FMT_USG,
1049 buf,
1050 buf_size,
1051 NULL))
1052 {
1053 GNUNET_break_op (0);
1054 return NULL;
1055 }
1056
1057 if (0 !=
1058 gcry_sexp_build (&data,
1059 NULL,
1060 "(sig-val(rsa(s %M)))",
1061 s))
1062 {
1063 GNUNET_break (0);
1064 gcry_mpi_release (s);
1065 return NULL;
1066 }
1067 gcry_mpi_release (s);
1068 sig = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1069 sig->sexp = data;
1070 return sig;
1071}
1072
1073
1074struct GNUNET_CRYPTO_RsaPublicKey *
1075GNUNET_CRYPTO_rsa_public_key_dup (const struct GNUNET_CRYPTO_RsaPublicKey *key)
1076{
1077 struct GNUNET_CRYPTO_RsaPublicKey *dup;
1078 gcry_sexp_t dup_sexp;
1079 size_t erroff;
1080
1081 /* check if we really are exporting a public key */
1082 dup_sexp = gcry_sexp_find_token (key->sexp, "public-key", 0);
1083 GNUNET_assert (NULL != dup_sexp);
1084 gcry_sexp_release (dup_sexp);
1085 /* copy the sexp */
1086 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", key->sexp));
1087 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaPublicKey);
1088 dup->sexp = dup_sexp;
1089 return dup;
1090}
1091
1092
1093struct GNUNET_CRYPTO_RsaSignature *
1094GNUNET_CRYPTO_rsa_unblind (const struct GNUNET_CRYPTO_RsaSignature *sig,
1095 const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
1096 struct GNUNET_CRYPTO_RsaPublicKey *pkey)
1097{
1098 struct RsaBlindingKey *bkey;
1099 gcry_mpi_t n;
1100 gcry_mpi_t s;
1101 gcry_mpi_t r_inv;
1102 gcry_mpi_t ubsig;
1103 int ret;
1104 struct GNUNET_CRYPTO_RsaSignature *sret;
1105
1106 BENCHMARK_START (rsa_unblind);
1107
1108 ret = key_from_sexp (&n, pkey->sexp, "public-key", "n");
1109 if (0 != ret)
1110 ret = key_from_sexp (&n, pkey->sexp, "rsa", "n");
1111 if (0 != ret)
1112 {
1113 GNUNET_break_op (0);
1114 return NULL;
1115 }
1116 ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
1117 if (0 != ret)
1118 ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
1119 if (0 != ret)
1120 {
1121 gcry_mpi_release (n);
1122 GNUNET_break_op (0);
1123 return NULL;
1124 }
1125
1126 bkey = rsa_blinding_key_derive (pkey, bks);
1127 if (NULL == bkey)
1128 {
1129 /* RSA key is malicious since rsa_gcd_validate failed here.
1130 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1131 * so the exchange is being malicious in an unfamilair way, maybe
1132 * just trying to crash us. */
1133 GNUNET_break_op (0);
1134 gcry_mpi_release (n);
1135 gcry_mpi_release (s);
1136 return NULL;
1137 }
1138
1139 r_inv = gcry_mpi_new (0);
1140 if (1 !=
1141 gcry_mpi_invm (r_inv,
1142 bkey->r,
1143 n))
1144 {
1145 /* We cannot find r mod n, so gcd(r,n) != 1, which should get *
1146 * caught above, but we handle it the same here. */
1147 GNUNET_break_op (0);
1148 gcry_mpi_release (r_inv);
1149 rsa_blinding_key_free (bkey);
1150 gcry_mpi_release (n);
1151 gcry_mpi_release (s);
1152 return NULL;
1153 }
1154
1155 ubsig = gcry_mpi_new (0);
1156 gcry_mpi_mulm (ubsig, s, r_inv, n);
1157 gcry_mpi_release (n);
1158 gcry_mpi_release (r_inv);
1159 gcry_mpi_release (s);
1160 rsa_blinding_key_free (bkey);
1161
1162 sret = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1163 GNUNET_assert (0 ==
1164 gcry_sexp_build (&sret->sexp,
1165 NULL,
1166 "(sig-val (rsa (s %M)))",
1167 ubsig));
1168 gcry_mpi_release (ubsig);
1169 BENCHMARK_END (rsa_unblind);
1170 return sret;
1171}
1172
1173
1174enum GNUNET_GenericReturnValue
1175GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash,
1176 const struct GNUNET_CRYPTO_RsaSignature *sig,
1177 const struct GNUNET_CRYPTO_RsaPublicKey *pkey)
1178{
1179 gcry_sexp_t data;
1180 gcry_mpi_t r;
1181 int rc;
1182
1183 BENCHMARK_START (rsa_verify);
1184
1185 r = rsa_full_domain_hash (pkey, hash);
1186 if (NULL == r)
1187 {
1188 GNUNET_break_op (0);
1189 /* RSA key is malicious since rsa_gcd_validate failed here.
1190 * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
1191 * so the exchange is being malicious in an unfamilair way, maybe
1192 * just trying to crash us. Arguably, we've only an internal error
1193 * though because we should've detected this in our previous call
1194 * to GNUNET_CRYPTO_rsa_unblind. *///
1195 return GNUNET_NO;
1196 }
1197
1198 data = mpi_to_sexp (r);
1199 gcry_mpi_release (r);
1200
1201 rc = gcry_pk_verify (sig->sexp,
1202 data,
1203 pkey->sexp);
1204 gcry_sexp_release (data);
1205 if (0 != rc)
1206 {
1207 LOG (GNUNET_ERROR_TYPE_WARNING,
1208 _ ("RSA signature verification failed at %s:%d: %s\n"),
1209 __FILE__,
1210 __LINE__,
1211 gcry_strerror (rc));
1212 BENCHMARK_END (rsa_verify);
1213 return GNUNET_SYSERR;
1214 }
1215 BENCHMARK_END (rsa_verify);
1216 return GNUNET_OK;
1217}
1218
1219
1220struct GNUNET_CRYPTO_RsaPrivateKey *
1221GNUNET_CRYPTO_rsa_private_key_dup (
1222 const struct GNUNET_CRYPTO_RsaPrivateKey *key)
1223{
1224 struct GNUNET_CRYPTO_RsaPrivateKey *dup;
1225 gcry_sexp_t dup_sexp;
1226 size_t erroff;
1227
1228 /* check if we really are exporting a private key */
1229 dup_sexp = gcry_sexp_find_token (key->sexp, "private-key", 0);
1230 GNUNET_assert (NULL != dup_sexp);
1231 gcry_sexp_release (dup_sexp);
1232 /* copy the sexp */
1233 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", key->sexp));
1234 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaPrivateKey);
1235 dup->sexp = dup_sexp;
1236 return dup;
1237}
1238
1239
1240struct GNUNET_CRYPTO_RsaSignature *
1241GNUNET_CRYPTO_rsa_signature_dup (const struct GNUNET_CRYPTO_RsaSignature *sig)
1242{
1243 struct GNUNET_CRYPTO_RsaSignature *dup;
1244 gcry_sexp_t dup_sexp;
1245 size_t erroff;
1246 gcry_mpi_t s;
1247 int ret;
1248
1249 /* verify that this is an RSA signature */
1250 ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
1251 if (0 != ret)
1252 ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
1253 GNUNET_assert (0 == ret);
1254 gcry_mpi_release (s);
1255 /* copy the sexp */
1256 GNUNET_assert (0 == gcry_sexp_build (&dup_sexp, &erroff, "%S", sig->sexp));
1257 dup = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
1258 dup->sexp = dup_sexp;
1259 return dup;
1260}
1261
1262
1263/* end of util/rsa.c */