summaryrefslogtreecommitdiff
path: root/src/util/rsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/rsa.c')
-rw-r--r--src/util/rsa.c925
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 @@
+/*
+ This file is part of TALER
+ (C) 2014 Christian Grothoff (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file util/rsa.c
+ * @brief RSA key management utilities. Most of the code here is taken from
+ * gnunet-0.9.5a
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ *
+ * Authors of the gnunet code:
+ * Christian Grothoff
+ * Krista Bennett
+ * Gerd Knorr <kraxel@bytesex.org>
+ * Ioana Patrascu
+ * Tzvetan Horozov
+ */
+
+#include "platform.h"
+#include "gcrypt.h"
+#include "gnunet/gnunet_util_lib.h"
+#include "taler_rsa.h"
+
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+/**
+ * Log an error message at log-level 'level' that indicates
+ * a failure of the command 'cmd' with the message given
+ * by gcry_strerror(rc).
+ */
+#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)
+
+/**
+ * Shorthand to cleanup non null mpi data types
+ */
+#define mpi_release_non_null(mpi) \
+ if (NULL != mpi) gcry_mpi_release (mpi);
+
+/**
+ * The private information of an RSA key pair.
+ * NOTE: this must match the definition in crypto_ksk.c and gnunet-rsa.c!
+ */
+struct TALER_RSA_PrivateKey
+{
+ /**
+ * Libgcrypt S-expression for the ECC key.
+ */
+ gcry_sexp_t sexp;
+};
+
+
+/**
+ * Extract values from an S-expression.
+ *
+ * @param array where to store the result(s)
+ * @param sexp S-expression to parse
+ * @param topname top-level name in the S-expression that is of interest
+ * @param elems names of the elements to extract
+ * @return 0 on success
+ */
+static int
+key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
+ const char *elems)
+{
+ gcry_sexp_t list;
+ gcry_sexp_t l2;
+ const char *s;
+ unsigned int i;
+ unsigned int idx;
+
+ if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
+ return 1;
+ l2 = gcry_sexp_cadr (list);
+ gcry_sexp_release (list);
+ list = l2;
+ if (! list)
+ return 2;
+ idx = 0;
+ for (s = elems; *s; s++, idx++)
+ {
+ if (! (l2 = gcry_sexp_find_token (list, s, 1)))
+ {
+ for (i = 0; i < idx; i++)
+ {
+ gcry_free (array[i]);
+ array[i] = NULL;
+ }
+ gcry_sexp_release (list);
+ return 3; /* required parameter not found */
+ }
+ array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release (l2);
+ if (! array[idx])
+ {
+ for (i = 0; i < idx; i++)
+ {
+ gcry_free (array[i]);
+ array[i] = NULL;
+ }
+ gcry_sexp_release (list);
+ return 4; /* required parameter is invalid */
+ }
+ }
+ gcry_sexp_release (list);
+ return 0;
+}
+
+/**
+ * If target != size, move target bytes to the
+ * end of the size-sized buffer and zero out the
+ * first target-size bytes.
+ *
+ * @param buf original buffer
+ * @param size number of bytes in the buffer
+ * @param target target size of the buffer
+ */
+static void
+adjust (unsigned char *buf, size_t size, size_t target)
+{
+ if (size < target)
+ {
+ memmove (&buf[target - size], buf, size);
+ memset (buf, 0, target - size);
+ }
+}
+
+
+/**
+ * Create a new private key. Caller must free return value.
+ *
+ * @return fresh private key
+ */
+struct TALER_RSA_PrivateKey *
+TALER_RSA_key_create ()
+{
+ struct TALER_RSA_PrivateKey *ret;
+ gcry_sexp_t s_key;
+ gcry_sexp_t s_keyparam;
+
+ GNUNET_assert (0 ==
+ gcry_sexp_build (&s_keyparam, NULL,
+ "(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
+ 2048));
+ GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam));
+ gcry_sexp_release (s_keyparam);
+#if EXTRA_CHECKS
+ GNUNET_assert (0 == gcry_pk_testkey (s_key));
+#endif
+ ret = GNUNET_malloc (sizeof (struct TALER_RSA_PrivateKey));
+ ret->sexp = s_key;
+ return ret;
+}
+
+
+/**
+ * Free memory occupied by the private key.
+ *
+ * @param key pointer to the memory to free
+ */
+void
+TALER_RSA_key_free (struct TALER_RSA_PrivateKey *key)
+{
+ gcry_sexp_release (key->sexp);
+ GNUNET_free (key);
+}
+
+
+/**
+ * Encode the private key in a format suitable for
+ * storing it into a file.
+ * @return encoding of the private key
+ */
+struct TALER_RSA_PrivateKeyBinaryEncoded *
+TALER_RSA_encode_key (const struct TALER_RSA_PrivateKey *hostkey)
+{
+ struct TALER_RSA_PrivateKeyBinaryEncoded *retval;
+ gcry_mpi_t pkv[6];
+ void *pbu[6];
+ size_t sizes[6];
+ int rc;
+ int i;
+ int size;
+
+#if EXTRA_CHECKS
+ if (gcry_pk_testkey (hostkey->sexp))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+#endif
+
+ memset (pkv, 0, sizeof (gcry_mpi_t) * 6);
+ rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpqu");
+ if (rc)
+ rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpqu");
+ if (rc)
+ rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpq");
+ if (rc)
+ rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpq");
+ if (rc)
+ rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "ned");
+ if (rc)
+ rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned");
+ GNUNET_assert (0 == rc);
+ size = sizeof (struct TALER_RSA_PrivateKeyBinaryEncoded);
+ for (i = 0; i < 6; i++)
+ {
+ if (NULL != pkv[i])
+ {
+ GNUNET_assert (0 ==
+ gcry_mpi_aprint (GCRYMPI_FMT_USG,
+ (unsigned char **) &pbu[i], &sizes[i],
+ pkv[i]));
+ size += sizes[i];
+ }
+ else
+ {
+ pbu[i] = NULL;
+ sizes[i] = 0;
+ }
+ }
+ GNUNET_assert (size < 65536);
+ retval = GNUNET_malloc (size);
+ retval->len = htons (size);
+ i = 0;
+ retval->sizen = htons (sizes[0]);
+ memcpy (&((char *) (&retval[1]))[i], pbu[0], sizes[0]);
+ i += sizes[0];
+ retval->sizee = htons (sizes[1]);
+ memcpy (&((char *) (&retval[1]))[i], pbu[1], sizes[1]);
+ i += sizes[1];
+ retval->sized = htons (sizes[2]);
+ memcpy (&((char *) (&retval[1]))[i], pbu[2], sizes[2]);
+ i += sizes[2];
+ /* swap p and q! */
+ retval->sizep = htons (sizes[4]);
+ memcpy (&((char *) (&retval[1]))[i], pbu[4], sizes[4]);
+ i += sizes[4];
+ retval->sizeq = htons (sizes[3]);
+ memcpy (&((char *) (&retval[1]))[i], pbu[3], sizes[3]);
+ i += sizes[3];
+ retval->sizedmp1 = htons (0);
+ retval->sizedmq1 = htons (0);
+ memcpy (&((char *) (&retval[1]))[i], pbu[5], sizes[5]);
+ for (i = 0; i < 6; i++)
+ {
+ if (pkv[i] != NULL)
+ gcry_mpi_release (pkv[i]);
+ if (pbu[i] != NULL)
+ free (pbu[i]);
+ }
+ return retval;
+}
+
+
+/**
+ * Extract the public key of the given private key.
+ *
+ * @param priv the private key
+ * @param pub where to write the public key
+ */
+void
+TALER_RSA_key_get_public (const struct TALER_RSA_PrivateKey *priv,
+ struct TALER_RSA_PublicKeyBinaryEncoded *pub)
+{
+ gcry_mpi_t skey[2];
+ size_t size;
+ int rc;
+
+ rc = key_from_sexp (skey, priv->sexp, "public-key", "ne");
+ if (0 != rc)
+ rc = key_from_sexp (skey, priv->sexp, "private-key", "ne");
+ if (0 != rc)
+ rc = key_from_sexp (skey, priv->sexp, "rsa", "ne");
+ GNUNET_assert (0 == rc);
+ pub->len =
+ htons (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded) -
+ sizeof (pub->padding));
+ pub->sizen = htons (TALER_RSA_DATA_ENCODING_LENGTH);
+ pub->padding = 0;
+ size = TALER_RSA_DATA_ENCODING_LENGTH;
+ GNUNET_assert (0 ==
+ gcry_mpi_print (GCRYMPI_FMT_USG, &pub->key[0], size, &size,
+ skey[0]));
+ adjust (&pub->key[0], size, TALER_RSA_DATA_ENCODING_LENGTH);
+ size = TALER_RSA_KEY_LENGTH - TALER_RSA_DATA_ENCODING_LENGTH;
+ GNUNET_assert (0 ==
+ gcry_mpi_print (GCRYMPI_FMT_USG,
+ &pub->key
+ [TALER_RSA_DATA_ENCODING_LENGTH], size,
+ &size, skey[1]));
+ adjust (&pub->key[TALER_RSA_DATA_ENCODING_LENGTH], size,
+ TALER_RSA_KEY_LENGTH -
+ TALER_RSA_DATA_ENCODING_LENGTH);
+ gcry_mpi_release (skey[0]);
+ gcry_mpi_release (skey[1]);
+}
+
+
+/**
+ * Decode the private key from the data-format back
+ * to the "normal", internal format.
+ *
+ * @param buf the buffer where the private key data is stored
+ * @param len the length of the data in 'buffer'
+ * @return NULL on error
+ */
+struct TALER_RSA_PrivateKey *
+TALER_RSA_decode_key (const char *buf, uint16_t len)
+{
+ struct TALER_RSA_PrivateKey *ret;
+ const struct TALER_RSA_PrivateKeyBinaryEncoded *encoding =
+ (const struct TALER_RSA_PrivateKeyBinaryEncoded *) buf;
+ gcry_sexp_t res;
+ gcry_mpi_t n;
+ gcry_mpi_t e;
+ gcry_mpi_t d;
+ gcry_mpi_t p;
+ gcry_mpi_t q;
+ gcry_mpi_t u;
+ int rc;
+ size_t size;
+ size_t pos;
+ uint16_t enc_len;
+ size_t erroff;
+
+ enc_len = ntohs (encoding->len);
+ if (len != enc_len)
+ return NULL;
+
+ pos = 0;
+ size = ntohs (encoding->sizen);
+ rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG,
+ &((const unsigned char *) (&encoding[1]))[pos], size,
+ &size);
+ pos += ntohs (encoding->sizen);
+ if (0 != rc)
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ return NULL;
+ }
+ size = ntohs (encoding->sizee);
+ rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG,
+ &((const unsigned char *) (&encoding[1]))[pos], size,
+ &size);
+ pos += ntohs (encoding->sizee);
+ if (0 != rc)
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ gcry_mpi_release (n);
+ return NULL;
+ }
+ size = ntohs (encoding->sized);
+ rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG,
+ &((const unsigned char *) (&encoding[1]))[pos], size,
+ &size);
+ pos += ntohs (encoding->sized);
+ if (0 != rc)
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ return NULL;
+ }
+ /* swap p and q! */
+ size = ntohs (encoding->sizep);
+ if (size > 0)
+ {
+ rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG,
+ &((const unsigned char *) (&encoding[1]))[pos], size,
+ &size);
+ pos += ntohs (encoding->sizep);
+ if (0 != rc)
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ gcry_mpi_release (d);
+ return NULL;
+ }
+ }
+ else
+ q = NULL;
+ size = ntohs (encoding->sizeq);
+ if (size > 0)
+ {
+ rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG,
+ &((const unsigned char *) (&encoding[1]))[pos], size,
+ &size);
+ pos += ntohs (encoding->sizeq);
+ if (0 != rc)
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ gcry_mpi_release (d);
+ if (NULL != q)
+ gcry_mpi_release (q);
+ return NULL;
+ }
+ }
+ else
+ p = NULL;
+ pos += ntohs (encoding->sizedmp1);
+ pos += ntohs (encoding->sizedmq1);
+ size =
+ ntohs (encoding->len) - sizeof (struct TALER_RSA_PrivateKeyBinaryEncoded) - pos;
+ if (size > 0)
+ {
+ rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG,
+ &((const unsigned char *) (&encoding[1]))[pos], size,
+ &size);
+ if (0 != rc)
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ gcry_mpi_release (d);
+ if (NULL != p)
+ gcry_mpi_release (p);
+ if (NULL != q)
+ gcry_mpi_release (q);
+ return NULL;
+ }
+ }
+ else
+ u = NULL;
+
+ if ((NULL != p) && (NULL != q) && (NULL != u))
+ {
+ rc = gcry_sexp_build (&res, &erroff,
+ "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))",
+ n, e, d, p, q, u);
+ }
+ else
+ {
+ if ((NULL != p) && (NULL != q))
+ {
+ rc = gcry_sexp_build (&res, &erroff,
+ "(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))",
+ n, e, d, p, q);
+ }
+ else
+ {
+ rc = gcry_sexp_build (&res, &erroff,
+ "(private-key(rsa(n %m)(e %m)(d %m)))", n, e, d);
+ }
+ }
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ gcry_mpi_release (d);
+ if (NULL != p)
+ gcry_mpi_release (p);
+ if (NULL != q)
+ gcry_mpi_release (q);
+ if (NULL != u)
+ gcry_mpi_release (u);
+
+ if (0 != rc)
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
+ if (0 != (rc = gcry_pk_testkey (res)))
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
+ return NULL;
+ }
+ ret = GNUNET_malloc (sizeof (struct TALER_RSA_PrivateKey));
+ ret->sexp = res;
+ return ret;
+}
+
+
+/**
+ * Convert a public key to a string.
+ *
+ * @param pub key to convert
+ * @return string representing 'pub'
+ */
+char *
+TALER_RSA_public_key_to_string (const struct TALER_RSA_PublicKeyBinaryEncoded *pub)
+{
+ char *pubkeybuf;
+ size_t keylen = (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) * 8;
+ char *end;
+
+ if (keylen % 5 > 0)
+ keylen += 5 - keylen % 5;
+ keylen /= 5;
+ pubkeybuf = GNUNET_malloc (keylen + 1);
+ end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
+ sizeof (struct TALER_RSA_PublicKeyBinaryEncoded),
+ pubkeybuf,
+ keylen);
+ if (NULL == end)
+ {
+ GNUNET_free (pubkeybuf);
+ return NULL;
+ }
+ *end = '\0';
+ return pubkeybuf;
+}
+
+
+/**
+ * Convert a string representing a public key to a public key.
+ *
+ * @param enc encoded public key
+ * @param enclen number of bytes in enc (without 0-terminator)
+ * @param pub where to store the public key
+ * @return GNUNET_OK on success
+ */
+int
+TALER_RSA_public_key_from_string (const char *enc,
+ size_t enclen,
+ struct TALER_RSA_PublicKeyBinaryEncoded *pub)
+{
+ size_t keylen = (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) * 8;
+
+ if (keylen % 5 > 0)
+ keylen += 5 - keylen % 5;
+ keylen /= 5;
+ if (enclen != keylen)
+ return GNUNET_SYSERR;
+
+ if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
+ (unsigned char*) pub,
+ sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)))
+ return GNUNET_SYSERR;
+ if ( (ntohs (pub->len) != sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) ||
+ (ntohs (pub->padding) != 0) ||
+ (ntohs (pub->sizen) != TALER_RSA_DATA_ENCODING_LENGTH) )
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Convert the data specified in the given purpose argument to an
+ * S-expression suitable for signature operations.
+ *
+ * @param ptr pointer to the data to convert
+ * @param size the size of the data
+ * @return converted s-expression
+ */
+static gcry_sexp_t
+data_to_sexp (const void *ptr, size_t size)
+{
+ gcry_mpi_t value;
+ gcry_sexp_t data;
+
+ value = NULL;
+ data = NULL;
+ GNUNET_assert (0 == gcry_mpi_scan (&value, GCRYMPI_FMT_USG, ptr, size, NULL));
+ GNUNET_assert (0 == gcry_sexp_build (&data, NULL, "(data (flags raw) (value %M))", value));
+ gcry_mpi_release (value);
+ return data;
+}
+
+
+/**
+ * Sign the given hash block.
+ *
+ * @param key private key to use for the signing
+ * @param hash the block containing the hash of the message to sign
+ * @param hash_size the size of the hash block
+ * @param sig where to write the signature
+ * @return GNUNET_SYSERR on error, GNUNET_OK on success
+ */
+int
+TALER_RSA_sign (const struct TALER_RSA_PrivateKey *key,
+ const void *hash,
+ size_t hash_size,
+ struct TALER_RSA_Signature *sig)
+{
+ gcry_sexp_t result;
+ gcry_sexp_t data;
+ size_t ssize;
+ gcry_mpi_t rval;
+
+ data = data_to_sexp (hash, hash_size);
+ GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp));
+ gcry_sexp_release (data);
+ GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "s"));
+ gcry_sexp_release (result);
+ ssize = sizeof (struct TALER_RSA_Signature);
+ GNUNET_assert (0 ==
+ gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) sig, ssize,
+ &ssize, rval));
+ gcry_mpi_release (rval);
+ adjust (sig->sig, ssize, sizeof (struct TALER_RSA_Signature));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Convert the given public key from the network format to the
+ * S-expression that can be used by libgcrypt.
+ *
+ * @param publicKey public key to decode
+ * @return NULL on error
+ */
+static gcry_sexp_t
+decode_public_key (const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey)
+{
+ gcry_sexp_t result;
+ gcry_mpi_t n;
+ gcry_mpi_t e;
+ size_t size;
+ size_t erroff;
+ int rc;
+
+ if ((ntohs (publicKey->sizen) != TALER_RSA_DATA_ENCODING_LENGTH) ||
+ (ntohs (publicKey->len) !=
+ sizeof (struct TALER_RSA_PublicKeyBinaryEncoded) -
+ sizeof (publicKey->padding)))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ size = TALER_RSA_DATA_ENCODING_LENGTH;
+ if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, &publicKey->key[0], size, &size)))
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ return NULL;
+ }
+ size = TALER_RSA_KEY_LENGTH - TALER_RSA_DATA_ENCODING_LENGTH;
+ if (0 != (rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG,
+ &publicKey->key[TALER_RSA_DATA_ENCODING_LENGTH],
+ size, &size)))
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ gcry_mpi_release (n);
+ return NULL;
+ }
+ rc = gcry_sexp_build (&result, &erroff, "(public-key(rsa(n %m)(e %m)))", n,
+ e);
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ if (0 != rc)
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */
+ return NULL;
+ }
+ return result;
+}
+
+
+/**
+ * Verify signature with the given hash.
+ *
+ * @param hash the hash code to verify against the signature
+ * @param sig signature that is being validated
+ * @param publicKey public key of the signer
+ * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
+ */
+int
+TALER_RSA_hash_verify (const struct GNUNET_HashCode *hash,
+ const struct TALER_RSA_Signature *sig,
+ const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey)
+{
+ gcry_sexp_t data;
+ gcry_sexp_t sigdata;
+ size_t size;
+ gcry_mpi_t val;
+ gcry_sexp_t psexp;
+ size_t erroff;
+ int rc;
+
+ size = sizeof (struct TALER_RSA_Signature);
+ GNUNET_assert (0 ==
+ gcry_mpi_scan (&val, GCRYMPI_FMT_USG,
+ (const unsigned char *) sig, size, &size));
+ GNUNET_assert (0 ==
+ gcry_sexp_build (&sigdata, &erroff, "(sig-val(rsa(s %m)))",
+ val));
+ gcry_mpi_release (val);
+ data = data_to_sexp (hash, sizeof (struct GNUNET_HashCode));
+ if (! (psexp = decode_public_key (publicKey)))
+ {
+ gcry_sexp_release (data);
+ gcry_sexp_release (sigdata);
+ return GNUNET_SYSERR;
+ }
+ rc = gcry_pk_verify (sigdata, data, psexp);
+ gcry_sexp_release (psexp);
+ gcry_sexp_release (data);
+ gcry_sexp_release (sigdata);
+ if (rc)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("RSA signature verification failed at %s:%d: %s\n"), __FILE__,
+ __LINE__, gcry_strerror (rc));
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify signature on the given message
+ *
+ * @param msg the message
+ * @param size the size of the message
+ * @param sig signature that is being validated
+ * @param publicKey public key of the signer
+ * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
+ */
+int
+TALER_RSA_verify (const void *msg, size_t size,
+ const struct TALER_RSA_Signature *sig,
+ const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey)
+{
+ struct GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash (msg, size, &hash);
+ return TALER_RSA_hash_verify (&hash, sig, publicKey);
+}
+
+/**
+ * The blinding key is equal in length to the RSA modulus
+ */
+#define TALER_RSA_BLINDING_KEY_LEN TALER_RSA_DATA_ENCODING_LENGTH
+
+struct TALER_RSA_BlindingKey
+{
+ /**
+ * The blinding factor
+ */
+ gcry_mpi_t r;
+};
+
+struct TALER_RSA_BlindingKey *
+TALER_RSA_blinding_key_create ()
+{
+ struct TALER_RSA_BlindingKey *blind;
+
+ blind = GNUNET_new (struct TALER_RSA_BlindingKey);
+ blind->r = gcry_mpi_new (TALER_RSA_BLINDING_KEY_LEN * 8);
+ gcry_mpi_randomize (blind->r, TALER_RSA_BLINDING_KEY_LEN * 8, GCRY_STRONG_RANDOM);
+ return blind;
+}
+
+
+void
+TALER_RSA_blinding_key_destroy (struct TALER_RSA_BlindingKey *bkey)
+{
+ gcry_mpi_release (bkey->r);
+ GNUNET_free (bkey);
+}
+
+
+struct TALER_RSA_BlindedSignaturePurpose *
+TALER_RSA_message_blind (const void *msg, size_t size,
+ struct TALER_RSA_BlindingKey *bkey,
+ struct TALER_RSA_PublicKeyBinaryEncoded *pkey)
+{
+ struct TALER_RSA_BlindedSignaturePurpose *bsp;
+ struct GNUNET_HashCode hash;
+ gcry_sexp_t psexp;
+ gcry_mpi_t data;
+ gcry_mpi_t skey[2];
+ gcry_mpi_t r_e;
+ gcry_mpi_t data_r_e;
+ size_t rsize;
+ gcry_error_t rc;
+ int ret;
+
+ bsp = NULL;
+ psexp = NULL;
+ data = NULL;
+ skey[0] = skey[1] = NULL;
+ r_e = NULL;
+ data_r_e = NULL;
+ rsize = 0;
+ rc = 0;
+ ret = 0;
+ if (! (psexp = decode_public_key (pkey)))
+ return NULL;
+ ret = key_from_sexp (skey, psexp, "public-key", "ne");
+ if (0 != ret)
+ ret = key_from_sexp (skey, psexp, "rsa", "ne");
+ gcry_sexp_release (psexp);
+ psexp = NULL;
+ GNUNET_assert (0 == ret);
+ GNUNET_CRYPTO_hash (msg, size, &hash);
+ if (0 != (rc=gcry_mpi_scan (&data, GCRYMPI_FMT_USG,
+ (const unsigned char *) msg, size, &rsize)))
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_WARNING, "gcry_mpi_scan", rc);
+ goto cleanup;
+ }
+ r_e = gcry_mpi_new (0);
+ gcry_mpi_powm (r_e, bkey->r,
+ skey[1], /* e */
+ skey[0]); /* n */
+
+ data_r_e = gcry_mpi_new (0);
+ gcry_mpi_mulm (data_r_e, data, r_e, skey[0]);
+
+ bsp = GNUNET_new (struct TALER_RSA_BlindedSignaturePurpose);
+ rc = gcry_mpi_print (GCRYMPI_FMT_USG,
+ (unsigned char *) bsp,
+ sizeof (struct TALER_RSA_BlindedSignaturePurpose),
+ &rsize,
+ data_r_e);
+ GNUNET_assert (0 == rc);
+ adjust ((unsigned char *) bsp, rsize,
+ sizeof (struct TALER_RSA_BlindedSignaturePurpose));
+
+ cleanup:
+ if (NULL != psexp) gcry_sexp_release (psexp);
+ mpi_release_non_null (skey[0]);
+ mpi_release_non_null (skey[1]);
+ mpi_release_non_null (data);
+ mpi_release_non_null (r_e);
+ mpi_release_non_null (data_r_e);
+ return bsp;
+}
+
+
+int
+TALER_RSA_unblind (struct TALER_RSA_Signature *sig,
+ struct TALER_RSA_BlindingKey *bkey,
+ struct TALER_RSA_PublicKeyBinaryEncoded *pkey)
+{
+ gcry_sexp_t psexp;
+ gcry_mpi_t skey;
+ gcry_mpi_t sigval;
+ gcry_mpi_t r_inv;
+ gcry_mpi_t ubsig;
+ size_t rsize;
+ gcry_error_t rc;
+ int ret;
+
+ psexp = NULL;
+ skey = NULL;
+ sigval = NULL;
+ r_inv = NULL;
+ ubsig = NULL;
+ rsize = 0;
+ rc = 0;
+ ret = GNUNET_SYSERR;
+ if (! (psexp = decode_public_key (pkey)))
+ return GNUNET_SYSERR;
+ ret = key_from_sexp (&skey, psexp, "public-key", "n");
+ if (0 != ret)
+ ret = key_from_sexp (&skey, psexp, "rsa", "n");
+ gcry_sexp_release (psexp);
+ psexp = NULL;
+ if (0 != (rc = gcry_mpi_scan (&sigval, GCRYMPI_FMT_USG,
+ (const unsigned char *) sig,
+ sizeof (struct TALER_RSA_Signature),
+ &rsize)))
+ {
+ LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
+ goto cleanup;
+ }
+ r_inv = gcry_mpi_new (0);
+ GNUNET_assert (1 == gcry_mpi_invm (r_inv, bkey->r, skey)); /* n: skey */
+ ubsig = gcry_mpi_new (0);
+ gcry_mpi_mulm (ubsig, sigval, r_inv, skey);
+ rc = gcry_mpi_print (GCRYMPI_FMT_USG,
+ (unsigned char *) sig,
+ sizeof (struct TALER_RSA_Signature),
+ &rsize,
+ ubsig);
+ GNUNET_assert (0 == rc);
+ adjust ((unsigned char *) sig, rsize, sizeof (struct TALER_RSA_Signature));
+ ret = GNUNET_OK;
+
+ cleanup:
+ if (NULL != psexp) gcry_sexp_release (psexp);
+ mpi_release_non_null (skey);
+ mpi_release_non_null (sigval);
+ mpi_release_non_null (r_inv);
+ mpi_release_non_null (ubsig);
+ return ret;
+}
+
+
+/**
+ * Encode a blinding key
+ *
+ * @param bkey the blinding key to encode
+ * @param bkey_enc where to store the encoded binary key
+ * @return #GNUNET_OK upon successful encoding; #GNUNET_SYSERR upon failure
+ */
+int
+TALER_RSA_blinding_key_encode (struct TALER_RSA_BlindingKey *bkey,
+ struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc)
+{
+ GNUNET_abort (); /* FIXME: not implemented */
+}
+
+
+/**
+ * Decode a blinding key from its encoded form
+ *
+ * @param bkey_enc the encoded blinding key
+ * @return the decoded blinding key; NULL upon error
+ */
+struct TALER_RSA_BlindingKey *
+TALER_RSA_blinding_key_decode (struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc)
+{
+ GNUNET_abort (); /* FIXME: not implemented */
+}
+
+/* end of util/rsa.c */