2 This file is part of GNUnet.
3 (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file util/crypto_rsa.c
23 * @brief public key cryptography (RSA) with libgcrypt
24 * @author Christian Grothoff
26 * Note that the code locks often needlessly on the gcrypt-locking api.
27 * One would think that simple MPI operations should not require locking
28 * (since only global operations on the random pool must be locked,
29 * strictly speaking). But libgcrypt does sometimes require locking in
30 * unexpected places, so the safe solution is to always lock even if it
31 * is not required. The performance impact is minimal anyway.
36 #include "gnunet_common.h"
37 #include "gnunet_crypto_lib.h"
38 #include "gnunet_disk_lib.h"
40 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
42 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
44 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
47 * The private information of an RSA key pair.
48 * NOTE: this must match the definition in crypto_ksk.c
50 struct GNUNET_CRYPTO_RsaPrivateKey
57 * GNUnet mandates a certain format for the encoding
58 * of private RSA key information that is provided
59 * by the RSA implementations. This format is used
60 * to serialize a private RSA key (typically when
61 * writing it to disk).
63 struct RsaPrivateKeyBinaryEncoded
66 * Total size of the structure, in bytes, in big-endian!
68 uint16_t len GNUNET_PACKED;
69 uint16_t sizen GNUNET_PACKED; /* in big-endian! */
70 uint16_t sizee GNUNET_PACKED; /* in big-endian! */
71 uint16_t sized GNUNET_PACKED; /* in big-endian! */
72 uint16_t sizep GNUNET_PACKED; /* in big-endian! */
73 uint16_t sizeq GNUNET_PACKED; /* in big-endian! */
74 uint16_t sizedmp1 GNUNET_PACKED; /* in big-endian! */
75 uint16_t sizedmq1 GNUNET_PACKED; /* in big-endian! */
76 /* followed by the actual values */
80 #define HOSTKEY_LEN 2048
82 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS
86 * Log an error message at log-level 'level' that indicates
87 * a failure of the command 'cmd' with the message given
88 * by gcry_strerror(rc).
90 #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);
93 * If target != size, move target bytes to the
94 * end of the size-sized buffer and zero out the
95 * first target-size bytes.
98 adjust (unsigned char *buf, size_t size, size_t target)
102 memmove (&buf[target - size], buf, size);
103 memset (buf, 0, target - size);
108 * This HostKey implementation uses RSA.
110 struct GNUNET_CRYPTO_RsaPrivateKey *
111 GNUNET_CRYPTO_rsa_key_create ()
113 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
115 gcry_sexp_t s_keyparam;
118 gcry_sexp_build (&s_keyparam, NULL,
119 "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
121 GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam));
122 gcry_sexp_release (s_keyparam);
124 GNUNET_assert (0 == gcry_pk_testkey (s_key));
126 ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
132 * Free memory occupied by hostkey
135 GNUNET_CRYPTO_rsa_key_free (struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
137 gcry_sexp_release (hostkey->sexp);
138 GNUNET_free (hostkey);
142 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
145 gcry_sexp_t list, l2;
149 list = gcry_sexp_find_token (sexp, topname, 0);
154 l2 = gcry_sexp_cadr (list);
155 gcry_sexp_release (list);
163 for (s = elems; *s; s++, idx++)
165 l2 = gcry_sexp_find_token (list, s, 1);
168 for (i = 0; i < idx; i++)
170 gcry_free (array[i]);
173 gcry_sexp_release (list);
174 return 3; /* required parameter not found */
176 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
177 gcry_sexp_release (l2);
180 for (i = 0; i < idx; i++)
182 gcry_free (array[i]);
185 gcry_sexp_release (list);
186 return 4; /* required parameter is invalid */
189 gcry_sexp_release (list);
194 * Extract the public key of the host.
195 * @param priv the private key
196 * @param pub where to write the public key
199 GNUNET_CRYPTO_rsa_key_get_public (const struct GNUNET_CRYPTO_RsaPrivateKey
202 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
209 rc = key_from_sexp (skey, priv->sexp, "public-key", "ne");
211 rc = key_from_sexp (skey, priv->sexp, "private-key", "ne");
213 rc = key_from_sexp (skey, priv->sexp, "rsa", "ne");
214 GNUNET_assert (0 == rc);
216 htons (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) -
217 sizeof (pub->padding));
218 pub->sizen = htons (GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH);
220 size = GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH;
222 gcry_mpi_print (GCRYMPI_FMT_USG, &pub->key[0], size, &size,
224 adjust (&pub->key[0], size, GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH);
226 GNUNET_CRYPTO_RSA_KEY_LENGTH - GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH;
228 gcry_mpi_print (GCRYMPI_FMT_USG,
230 [GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH],
231 size, &size, skey[1]));
232 adjust (&pub->key[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH], size,
233 GNUNET_CRYPTO_RSA_KEY_LENGTH -
234 GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH);
235 gcry_mpi_release (skey[0]);
236 gcry_mpi_release (skey[1]);
241 * Internal: publicKey => RSA-Key.
243 * Note that the return type is not actually a private
244 * key but rather an sexpression for the public key!
246 static struct GNUNET_CRYPTO_RsaPrivateKey *
247 public2PrivateKey (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
250 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
258 if ((ntohs (publicKey->sizen) != GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH) ||
259 (ntohs (publicKey->len) !=
260 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) -
261 sizeof (publicKey->padding)))
266 size = GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH;
267 rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, &publicKey->key[0], size, &size);
270 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
274 GNUNET_CRYPTO_RSA_KEY_LENGTH - GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH;
276 gcry_mpi_scan (&e, GCRYMPI_FMT_USG,
277 &publicKey->key[GNUNET_CRYPTO_RSA_DATA_ENCODING_LENGTH],
281 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
282 gcry_mpi_release (n);
285 rc = gcry_sexp_build (&result, &erroff, "(public-key(rsa(n %m)(e %m)))", n,
287 gcry_mpi_release (n);
288 gcry_mpi_release (e);
291 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */
294 ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
301 * Encode the private key in a format suitable for
302 * storing it into a file.
303 * @returns encoding of the private key.
304 * The first 4 bytes give the size of the array, as usual.
306 static struct RsaPrivateKeyBinaryEncoded *
307 rsa_encode_key (const struct GNUNET_CRYPTO_RsaPrivateKey *hostkey)
309 struct RsaPrivateKeyBinaryEncoded *retval;
318 if (gcry_pk_testkey (hostkey->sexp))
325 memset (pkv, 0, sizeof (gcry_mpi_t) * 6);
326 rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpqu");
328 rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpqu");
330 rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpq");
332 rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpq");
334 rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "ned");
336 rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned");
337 GNUNET_assert (0 == rc);
338 size = sizeof (struct RsaPrivateKeyBinaryEncoded);
339 for (i = 0; i < 6; i++)
344 gcry_mpi_aprint (GCRYMPI_FMT_USG,
345 (unsigned char **) &pbu[i],
355 GNUNET_assert (size < 65536);
356 retval = GNUNET_malloc (size);
357 retval->len = htons (size);
359 retval->sizen = htons (sizes[0]);
360 memcpy (&((char *) (&retval[1]))[i], pbu[0], sizes[0]);
362 retval->sizee = htons (sizes[1]);
363 memcpy (&((char *) (&retval[1]))[i], pbu[1], sizes[1]);
365 retval->sized = htons (sizes[2]);
366 memcpy (&((char *) (&retval[1]))[i], pbu[2], sizes[2]);
369 retval->sizep = htons (sizes[4]);
370 memcpy (&((char *) (&retval[1]))[i], pbu[4], sizes[4]);
372 retval->sizeq = htons (sizes[3]);
373 memcpy (&((char *) (&retval[1]))[i], pbu[3], sizes[3]);
375 retval->sizedmp1 = htons (0);
376 retval->sizedmq1 = htons (0);
377 memcpy (&((char *) (&retval[1]))[i], pbu[5], sizes[5]);
378 for (i = 0; i < 6; i++)
381 gcry_mpi_release (pkv[i]);
389 * Decode the private key from the file-format back
390 * to the "normal", internal format.
392 * @param buf the buffer where the private key data is stored
393 * @param len the length of the data in 'buffer'
395 struct GNUNET_CRYPTO_RsaPrivateKey *
396 GNUNET_CRYPTO_rsa_decode_key (const char *buf, uint16_t len)
398 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
399 const struct RsaPrivateKeyBinaryEncoded *encoding =
400 (const struct RsaPrivateKeyBinaryEncoded *) buf;
402 gcry_mpi_t n, e, d, p, q, u;
408 enc_len = ntohs (encoding->len);
413 size = ntohs (encoding->sizen);
414 rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG,
415 &((const unsigned char *) (&encoding[1]))[pos], size,
417 pos += ntohs (encoding->sizen);
420 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
423 size = ntohs (encoding->sizee);
424 rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG,
425 &((const unsigned char *) (&encoding[1]))[pos], size,
427 pos += ntohs (encoding->sizee);
430 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
431 gcry_mpi_release (n);
434 size = ntohs (encoding->sized);
435 rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG,
436 &((const unsigned char *) (&encoding[1]))[pos], size,
438 pos += ntohs (encoding->sized);
441 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
442 gcry_mpi_release (n);
443 gcry_mpi_release (e);
447 size = ntohs (encoding->sizep);
450 rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG,
451 &((const unsigned char *) (&encoding[1]))[pos],
453 pos += ntohs (encoding->sizep);
456 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
457 gcry_mpi_release (n);
458 gcry_mpi_release (e);
459 gcry_mpi_release (d);
465 size = ntohs (encoding->sizeq);
468 rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG,
469 &((const unsigned char *) (&encoding[1]))[pos],
471 pos += ntohs (encoding->sizeq);
474 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
475 gcry_mpi_release (n);
476 gcry_mpi_release (e);
477 gcry_mpi_release (d);
479 gcry_mpi_release (q);
485 pos += ntohs (encoding->sizedmp1);
486 pos += ntohs (encoding->sizedmq1);
488 ntohs (encoding->len) - sizeof (struct RsaPrivateKeyBinaryEncoded) - pos;
491 rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG,
492 &((const unsigned char *) (&encoding[1]))[pos],
496 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
497 gcry_mpi_release (n);
498 gcry_mpi_release (e);
499 gcry_mpi_release (d);
501 gcry_mpi_release (p);
503 gcry_mpi_release (q);
510 if ((p != NULL) && (q != NULL) && (u != NULL))
512 rc = gcry_sexp_build (&res, &size, /* erroff */
513 "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))",
518 if ((p != NULL) && (q != NULL))
520 rc = gcry_sexp_build (&res, &size, /* erroff */
521 "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))",
526 rc = gcry_sexp_build (&res, &size, /* erroff */
527 "(private-key(rsa(n %m)(e %m)(d %m)))", n, e,
531 gcry_mpi_release (n);
532 gcry_mpi_release (e);
533 gcry_mpi_release (d);
535 gcry_mpi_release (p);
537 gcry_mpi_release (q);
539 gcry_mpi_release (u);
542 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
544 if (gcry_pk_testkey (res))
546 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
550 ret = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
557 * Create a new private key by reading it from a file. If the
558 * files does not exist, create a new key and write it to the
559 * file. Caller must free return value. Note that this function
560 * can not guarantee that another process might not be trying
561 * the same operation on the same file at the same time.
562 * If the contents of the file
563 * are invalid the old file is deleted and a fresh key is
566 * @return new private key, NULL on error (for example,
569 struct GNUNET_CRYPTO_RsaPrivateKey *
570 GNUNET_CRYPTO_rsa_key_create_from_file (const char *filename)
572 struct GNUNET_CRYPTO_RsaPrivateKey *ret;
573 struct RsaPrivateKeyBinaryEncoded *enc;
575 struct GNUNET_DISK_FileHandle *fd;
579 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
580 struct GNUNET_PeerIdentity pid;
582 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
584 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
586 fd = GNUNET_DISK_file_open (filename,
587 GNUNET_DISK_OPEN_WRITE |
588 GNUNET_DISK_OPEN_CREATE |
589 GNUNET_DISK_OPEN_FAILIFEXISTS,
590 GNUNET_DISK_PERM_USER_READ |
591 GNUNET_DISK_PERM_USER_WRITE);
596 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
598 /* must exist but not be accessible, fail for good! */
599 if (0 != ACCESS (filename, R_OK))
600 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access",
603 GNUNET_break (0); /* what is going on!? */
608 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
614 GNUNET_DISK_file_lock (fd, 0,
616 RsaPrivateKeyBinaryEncoded),
623 LOG (GNUNET_ERROR_TYPE_ERROR,
624 _("Could not aquire lock on file `%s': %s...\n"), filename,
628 LOG (GNUNET_ERROR_TYPE_INFO,
629 _("Creating a new private key. This may take a while.\n"));
630 ret = GNUNET_CRYPTO_rsa_key_create ();
631 GNUNET_assert (ret != NULL);
632 enc = rsa_encode_key (ret);
633 GNUNET_assert (enc != NULL);
634 GNUNET_assert (ntohs (enc->len) ==
635 GNUNET_DISK_file_write (fd, enc, ntohs (enc->len)));
638 GNUNET_DISK_file_sync (fd);
640 GNUNET_DISK_file_unlock (fd, 0,
642 RsaPrivateKeyBinaryEncoded)))
643 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
644 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
645 GNUNET_CRYPTO_rsa_key_get_public (ret, &pub);
646 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
647 LOG (GNUNET_ERROR_TYPE_INFO,
648 _("I am host `%s'. Stored new private key in `%s'.\n"),
649 GNUNET_i2s (&pid), filename);
652 /* hostkey file exists already, read it! */
653 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
654 GNUNET_DISK_PERM_NONE);
657 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
664 GNUNET_DISK_file_lock (fd, 0,
665 sizeof (struct RsaPrivateKeyBinaryEncoded),
671 LOG (GNUNET_ERROR_TYPE_ERROR,
672 _("Could not aquire lock on file `%s': %s...\n"), filename,
674 LOG (GNUNET_ERROR_TYPE_ERROR,
676 ("This may be ok if someone is currently generating a hostkey.\n"));
681 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
683 /* eh, what!? File we opened is now gone!? */
684 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
686 GNUNET_DISK_file_unlock (fd, 0,
688 RsaPrivateKeyBinaryEncoded)))
689 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
690 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
694 if (GNUNET_YES != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES))
696 if (fs < sizeof (struct RsaPrivateKeyBinaryEncoded))
698 /* maybe we got the read lock before the hostkey generating
699 * process had a chance to get the write lock; give it up! */
701 GNUNET_DISK_file_unlock (fd, 0,
703 RsaPrivateKeyBinaryEncoded)))
704 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
707 LOG (GNUNET_ERROR_TYPE_ERROR,
709 ("When trying to read hostkey file `%s' I found %u bytes but I need at least %u.\n"),
710 filename, (unsigned int) fs,
711 (unsigned int) sizeof (struct RsaPrivateKeyBinaryEncoded));
712 LOG (GNUNET_ERROR_TYPE_ERROR,
714 ("This may be ok if someone is currently generating a hostkey.\n"));
716 sleep (2); /* wait a bit longer! */
721 enc = GNUNET_malloc (fs);
722 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, enc, fs));
723 len = ntohs (enc->len);
726 (NULL == (ret = GNUNET_CRYPTO_rsa_decode_key ((char *) enc, len))))
728 LOG (GNUNET_ERROR_TYPE_ERROR,
730 ("File `%s' does not contain a valid private key. Deleting it.\n"),
732 if (0 != UNLINK (filename))
734 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
739 GNUNET_DISK_file_unlock (fd, 0,
740 sizeof (struct RsaPrivateKeyBinaryEncoded)))
741 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
742 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
745 GNUNET_CRYPTO_rsa_key_get_public (ret, &pub);
746 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &pid.hashPubKey);
747 LOG (GNUNET_ERROR_TYPE_INFO,
748 _("I am host `%s'. Read private key from `%s'.\n"),
749 GNUNET_i2s (&pid), filename);
756 * Encrypt a block with the public key of another host that uses the
759 * @param block the block to encrypt
760 * @param size the size of block
761 * @param publicKey the encoded public key used to encrypt
762 * @param target where to store the encrypted block
763 * @returns GNUNET_SYSERR on error, GNUNET_OK if ok
766 GNUNET_CRYPTO_rsa_encrypt (const void *block, size_t size,
768 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey,
769 struct GNUNET_CRYPTO_RsaEncryptedData *target)
773 struct GNUNET_CRYPTO_RsaPrivateKey *pubkey;
779 GNUNET_assert (size <= sizeof (GNUNET_HashCode));
780 pubkey = public2PrivateKey (publicKey);
782 return GNUNET_SYSERR;
785 gcry_mpi_scan (&val, GCRYMPI_FMT_USG, block, isize, &isize));
787 gcry_sexp_build (&data, &erroff,
788 "(data (flags pkcs1)(value %m))", val));
789 gcry_mpi_release (val);
790 GNUNET_assert (0 == gcry_pk_encrypt (&result, data, pubkey->sexp));
791 gcry_sexp_release (data);
792 GNUNET_CRYPTO_rsa_key_free (pubkey);
794 GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "a"));
795 gcry_sexp_release (result);
796 isize = sizeof (struct GNUNET_CRYPTO_RsaEncryptedData);
798 gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) target,
799 isize, &isize, rval));
800 gcry_mpi_release (rval);
801 adjust (&target->encoding[0], isize,
802 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
807 * Decrypt a given block with the hostkey.
809 * @param key the key with which to decrypt this block
810 * @param block the data to decrypt, encoded as returned by encrypt
811 * @param result pointer to a location where the result can be stored
812 * @param max the maximum number of bits to store for the result, if
813 * the decrypted block is bigger, an error is returned
814 * @return the size of the decrypted block, -1 on error
817 GNUNET_CRYPTO_rsa_decrypt (const struct GNUNET_CRYPTO_RsaPrivateKey * key,
818 const struct GNUNET_CRYPTO_RsaEncryptedData *
819 block, void *result, size_t max)
821 gcry_sexp_t resultsexp;
830 GNUNET_assert (0 == gcry_pk_testkey (key->sexp));
832 size = sizeof (struct GNUNET_CRYPTO_RsaEncryptedData);
834 gcry_mpi_scan (&val, GCRYMPI_FMT_USG, &block->encoding[0],
837 gcry_sexp_build (&data, &erroff,
838 "(enc-val(flags)(rsa(a %m)))", val));
839 gcry_mpi_release (val);
840 GNUNET_assert (0 == gcry_pk_decrypt (&resultsexp, data, key->sexp));
841 gcry_sexp_release (data);
842 /* resultsexp has format "(value %m)" */
843 GNUNET_assert (NULL !=
844 (val = gcry_sexp_nth_mpi (resultsexp, 1, GCRYMPI_FMT_USG)));
845 gcry_sexp_release (resultsexp);
846 tmp = GNUNET_malloc (max + HOSTKEY_LEN / 8);
847 size = max + HOSTKEY_LEN / 8;
849 gcry_mpi_print (GCRYMPI_FMT_USG, tmp, size, &size, val));
850 gcry_mpi_release (val);
852 endp += (size - max);
854 memcpy (result, endp, size);
861 * Sign a given block.
863 * @param key private key to use for the signing
864 * @param purpose what to sign (size, purpose)
865 * @param sig where to write the signature
866 * @return GNUNET_SYSERR on error, GNUNET_OK on success
869 GNUNET_CRYPTO_rsa_sign (const struct GNUNET_CRYPTO_RsaPrivateKey *key,
870 const struct GNUNET_CRYPTO_RsaSignaturePurpose
871 *purpose, struct GNUNET_CRYPTO_RsaSignature *sig)
881 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
882 #define FORMATSTRING "(4:data(5:flags5:pkcs1)(4:hash6:sha51264:0123456789012345678901234567890123456789012345678901234567890123))"
883 bufSize = strlen (FORMATSTRING) + 1;
884 buff = GNUNET_malloc (bufSize);
885 memcpy (buff, FORMATSTRING, bufSize);
889 ("0123456789012345678901234567890123456789012345678901234567890123))")
890 - 1], &hc, sizeof (GNUNET_HashCode));
891 GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
893 GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp));
894 gcry_sexp_release (data);
895 GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "s"));
896 gcry_sexp_release (result);
897 ssize = sizeof (struct GNUNET_CRYPTO_RsaSignature);
899 gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) sig,
900 ssize, &ssize, rval));
901 gcry_mpi_release (rval);
902 adjust (sig->sig, ssize, sizeof (struct GNUNET_CRYPTO_RsaSignature));
910 * @param purpose what is the purpose that the signature should have?
911 * @param validate block to validate (size, purpose, data)
912 * @param sig signature that is being validated
913 * @param publicKey public key of the signer
914 * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
917 GNUNET_CRYPTO_rsa_verify (uint32_t purpose,
918 const struct GNUNET_CRYPTO_RsaSignaturePurpose
920 const struct GNUNET_CRYPTO_RsaSignature *sig,
921 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
928 struct GNUNET_CRYPTO_RsaPrivateKey *hostkey;
935 if (purpose != ntohl (validate->purpose))
936 return GNUNET_SYSERR; /* purpose mismatch */
937 GNUNET_CRYPTO_hash (validate, ntohl (validate->size), &hc);
938 size = sizeof (struct GNUNET_CRYPTO_RsaSignature);
940 gcry_mpi_scan (&val, GCRYMPI_FMT_USG,
941 (const unsigned char *) sig, size, &size));
943 gcry_sexp_build (&sigdata, &erroff, "(sig-val(rsa(s %m)))",
945 gcry_mpi_release (val);
946 bufSize = strlen (FORMATSTRING) + 1;
947 buff = GNUNET_malloc (bufSize);
948 memcpy (buff, FORMATSTRING, bufSize);
950 [strlen (FORMATSTRING) -
952 ("0123456789012345678901234567890123456789012345678901234567890123))")],
953 &hc, sizeof (GNUNET_HashCode));
954 GNUNET_assert (0 == gcry_sexp_new (&data, buff, bufSize, 0));
956 hostkey = public2PrivateKey (publicKey);
959 gcry_sexp_release (data);
960 gcry_sexp_release (sigdata);
961 return GNUNET_SYSERR;
963 rc = gcry_pk_verify (sigdata, data, hostkey->sexp);
964 GNUNET_CRYPTO_rsa_key_free (hostkey);
965 gcry_sexp_release (data);
966 gcry_sexp_release (sigdata);
969 LOG (GNUNET_ERROR_TYPE_WARNING,
970 _("RSA signature verification failed at %s:%d: %s\n"), __FILE__,
971 __LINE__, gcry_strerror (rc));
972 return GNUNET_SYSERR;
978 /* end of crypto_rsa.c */