aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-01-08 18:37:20 +0100
committerChristian Grothoff <christian@grothoff.org>2015-01-08 18:37:20 +0100
commit57d1f08dbca256f5fe16d57b29bfa523dec8f6c4 (patch)
tree3b3ee5f3b8c174887217e5c465048dea4e79bae2 /src/util
-initial import for mint
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am39
-rw-r--r--src/util/db.c196
-rw-r--r--src/util/json.c194
-rw-r--r--src/util/microhttpd.c417
-rw-r--r--src/util/misc.supp28
-rw-r--r--src/util/rsa.c925
-rw-r--r--src/util/test_hash_context.c48
-rw-r--r--src/util/test_rsa.c112
-rw-r--r--src/util/util.c528
9 files changed, 2487 insertions, 0 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
new file mode 100644
index 000000000..f935802a6
--- /dev/null
+++ b/src/util/Makefile.am
@@ -0,0 +1,39 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/include $(LIBGCRYPT_CFLAGS) $(POSTGRESQL_CPPFLAGS)
+
+lib_LTLIBRARIES = \
+ libtalerutil.la
+
+libtalerutil_la_SOURCES = \
+ util.c \
+ json.c \
+ db.c \
+ microhttpd.c \
+ rsa.c
+
+libtalerutil_la_LIBADD = \
+ -lgnunetutil \
+ $(LIBGCRYPT_LIBS) \
+ -ljansson \
+ -lmicrohttpd \
+ -lpq
+
+libtalerutil_la_LDFLAGS = \
+ $(POSTGRESQL_LDFLAGS) \
+ -version-info 0:0:0 \
+ -export-dynamic -no-undefined
+
+check_PROGRAMS = \
+ test-hash-context \
+ test-rsa
+
+TESTS = \
+ $(check_PROGRAMS)
+
+test_hash_context_SOURCES = test_hash_context.c
+test_hash_context_CPPFLAGS = $(AM_CPPFLAGS) $(LIBGCRYPT_CFLAGS)
+test_hash_context_LDADD = libtalerutil.la \
+ -lgnunetutil $(LIBGCRYPT_LIBS)
+
+test_rsa_SOURCES = test_rsa.c
+test_rsa_LDADD = libtalerutil.la \
+ -lgnunetutil $(LIBGCRYPT_LIBS)
diff --git a/src/util/db.c b/src/util/db.c
new file mode 100644
index 000000000..a0b234a06
--- /dev/null
+++ b/src/util/db.c
@@ -0,0 +1,196 @@
+/*
+ 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/db.c
+ * @brief helper functions for DB interactions
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Florian Dold
+ */
+
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_db_lib.h"
+
+
+/**
+ * Execute a prepared statement.
+ */
+PGresult *
+TALER_DB_exec_prepared (PGconn *db_conn,
+ const char *name,
+ const struct TALER_DB_QueryParam *params)
+{
+ unsigned len;
+ unsigned i;
+
+ /* count the number of parameters */
+
+ {
+ const struct TALER_DB_QueryParam *x;
+ for (len = 0, x = params;
+ x->more;
+ len +=1, x += 1);
+ }
+
+ /* new scope to allow stack allocation without alloca */
+
+ {
+ void *param_values[len];
+ int param_lengths[len];
+ int param_formats[len];
+
+ for (i = 0; i < len; i += 1)
+ {
+ param_values[i] = (void *) params[i].data;
+ param_lengths[i] = params[i].size;
+ param_formats[i] = 1;
+ }
+ return PQexecPrepared (db_conn, name, len,
+ (const char **) param_values, param_lengths, param_formats, 1);
+ }
+}
+
+
+/**
+ * Extract results from a query result according to the given specification.
+ * If colums are NULL, the destination is not modified, and GNUNET_NO
+ * is returned.
+ *
+ * @return
+ * GNUNET_YES if all results could be extracted
+ * GNUNET_NO if at least one result was NULL
+ * GNUNET_SYSERR if a result was invalid (non-existing field)
+ */
+int
+TALER_DB_extract_result (PGresult *result,
+ struct TALER_DB_ResultSpec *rs,
+ int row)
+{
+ int had_null = GNUNET_NO;
+
+ for (; NULL != rs->fname; rs += 1)
+ {
+ int fnum;
+ fnum = PQfnumber (result, rs->fname);
+ if (fnum < 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "field '%s' does not exist in result\n", rs->fname);
+ return GNUNET_SYSERR;
+ }
+
+ /* if a field is null, continue but
+ * remember that we now return a different result */
+
+ if (PQgetisnull (result, row, fnum))
+ {
+ had_null = GNUNET_YES;
+ continue;
+ }
+ const char *res;
+ if (rs->dst_size != PQgetlength (result, row, fnum))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "field '%s' has wrong size (got %u, expected %u)\n",
+ rs->fname, (int) PQgetlength (result, row, fnum), (int) rs->dst_size);
+ return GNUNET_SYSERR;
+ }
+ res = PQgetvalue (result, row, fnum);
+ GNUNET_assert (NULL != res);
+ memcpy (rs->dst, res, rs->dst_size);
+ }
+ if (GNUNET_YES == had_null)
+ return GNUNET_NO;
+ return GNUNET_YES;
+}
+
+
+int
+TALER_DB_field_isnull (PGresult *result,
+ int row,
+ const char *fname)
+{
+ int fnum;
+ fnum = PQfnumber (result, fname);
+ GNUNET_assert (fnum >= 0);
+ if (PQgetisnull (result, row, fnum))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+int
+TALER_DB_extract_amount_nbo (PGresult *result,
+ int row,
+ const char *val_name,
+ const char *frac_name,
+ const char *curr_name,
+ struct TALER_AmountNBO *r_amount_nbo)
+{
+ int val_num;
+ int frac_num;
+ int curr_num;
+ int len;
+
+ GNUNET_assert (NULL != strstr (val_name, "_val"));
+ GNUNET_assert (NULL != strstr (frac_name, "_frac"));
+ GNUNET_assert (NULL != strstr (curr_name, "_curr"));
+
+ val_num = PQfnumber (result, val_name);
+ GNUNET_assert (val_num >= 0);
+ frac_num = PQfnumber (result, frac_name);
+ GNUNET_assert (frac_num >= 0);
+ curr_num = PQfnumber (result, curr_name);
+ GNUNET_assert (curr_num >= 0);
+
+ r_amount_nbo->value = *(uint32_t *) PQgetvalue (result, row, val_num);
+ r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, frac_num);
+ memset (r_amount_nbo->currency, 0, TALER_CURRENCY_LEN);
+ // FIXME: overflow?
+ len = PQgetlength (result, row, curr_num);
+ len = GNUNET_MIN (TALER_CURRENCY_LEN, len);
+ memcpy (r_amount_nbo->currency, PQgetvalue (result, row, curr_num), len);
+ r_amount_nbo->currency[TALER_CURRENCY_LEN - 1] = '\0';
+
+ return GNUNET_OK;
+}
+
+
+int
+TALER_DB_extract_amount (PGresult *result,
+ int row,
+ const char *val_name,
+ const char *frac_name,
+ const char *curr_name,
+ struct TALER_Amount *r_amount)
+{
+ struct TALER_AmountNBO amount_nbo;
+
+ (void)
+ TALER_DB_extract_amount_nbo (result,
+ row,
+ val_name,
+ frac_name,
+ curr_name,
+ &amount_nbo);
+ r_amount->value = ntohl (amount_nbo.value);
+ r_amount->fraction = ntohl (amount_nbo.fraction);
+ (void) strncpy (r_amount->currency, amount_nbo.currency, TALER_CURRENCY_LEN);
+
+ return GNUNET_OK;
+}
+
+/* end of util/db.c */
diff --git a/src/util/json.c b/src/util/json.c
new file mode 100644
index 000000000..269e6cf26
--- /dev/null
+++ b/src/util/json.c
@@ -0,0 +1,194 @@
+/*
+ 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/json.c
+ * @brief helper functions for JSON processing using libjansson
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_util.h"
+#include "taler_json_lib.h"
+
+/**
+ * Shorthand for exit jumps.
+ */
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+/**
+ * Print JSON parsing related error information
+ */
+#define WARN_JSON(error) \
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
+ "JSON parsing failed at %s:%u: %s (%s)", \
+ __FILE__, __LINE__, error.text, error.source)
+
+/**
+ * Shorthand for JSON parsing related exit jumps.
+ */
+#define UNPACK_EXITIF(cond) \
+ do { \
+ if (cond) { WARN_JSON(error); goto EXITIF_exit; } \
+ } while (0)
+
+/**
+ * Convert a TALER amount to a JSON
+ * object.
+ *
+ * @param amount the amount
+ * @return a json object describing the amount
+ */
+json_t *
+TALER_JSON_from_amount (struct TALER_Amount amount)
+{
+ json_t *j;
+ j = json_pack ("{s: s, s:I, s:I}",
+ "currency", amount.currency,
+ "value", (json_int_t) amount.value,
+ "fraction", (json_int_t) amount.fraction);
+ GNUNET_assert (NULL != j);
+ return j;
+}
+
+
+/**
+ * Convert absolute timestamp to a json string.
+ *
+ * @param the time stamp
+ * @return a json string with the timestamp in @a stamp
+ */
+json_t *
+TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp)
+{
+ json_t *j;
+ char *mystr;
+ int ret;
+ ret = GNUNET_asprintf (&mystr, "%llu",
+ (long long) (stamp.abs_value_us / (1000 * 1000)));
+ GNUNET_assert (ret > 0);
+ j = json_string (mystr);
+ GNUNET_free (mystr);
+ return j;
+}
+
+
+
+/**
+ * Convert binary data to a JSON string
+ * with the base32crockford encoding.
+ *
+ * @param data binary data
+ * @param size size of @a data in bytes
+ * @return json string that encodes @a data
+ */
+json_t *
+TALER_JSON_from_data (const void *data, size_t size)
+{
+ char *buf;
+ json_t *json;
+ buf = TALER_data_to_string_alloc (data, size);
+ json = json_string (buf);
+ GNUNET_free (buf);
+ return json;
+}
+
+
+/**
+ * Parse given JSON object to Amount
+ *
+ * @param json the json object representing Amount
+ * @param r_amount where the amount has to be written
+ * @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
+ */
+int
+TALER_JSON_to_amount (json_t *json,
+ struct TALER_Amount *r_amount)
+{
+ char *currency;
+ json_int_t value;
+ json_int_t fraction;
+ json_error_t error;
+
+ UNPACK_EXITIF (0 != json_unpack_ex (json, &error, JSON_STRICT,
+ "{s:s, s:I, s:I}",
+ "curreny", &currency,
+ "value", &value,
+ "fraction", &fraction));
+ EXITIF (3 < strlen (currency));
+ r_amount->value = (uint32_t) value;
+ r_amount->fraction = (uint32_t) fraction;
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Parse given JSON object to Amount
+ *
+ * @param json the json object representing Amount
+ * @param r_amount where the amount has to be written
+ * @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
+ */
+int
+TALER_JSON_to_abs (json_t *json,
+ struct GNUNET_TIME_Absolute *abs)
+{
+ const char *str;
+ unsigned long long abs_value_s;
+
+ GNUNET_assert (NULL != abs);
+ EXITIF (NULL == (str = json_string_value (json)));
+ EXITIF (1 > sscanf (str, "%llu", &abs_value_s));
+ abs->abs_value_us = abs_value_s * 1000 * 1000;
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ return GNUNET_SYSERR;
+}
+
+/**
+ * Parse given JSON object to data
+ *
+ * @param json the json object representing data
+ * @param out the pointer to hold the parsed data.
+ * @param out_size the size of r_data.
+ * @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
+ */
+int
+TALER_JSON_to_data (json_t *json,
+ void *out,
+ size_t out_size)
+{
+ const char *enc;
+ unsigned int len;
+
+ EXITIF (NULL == (enc = json_string_value (json)));
+ len = strlen (enc);
+ EXITIF ((((len * 5) / 8) + ((((len * 5) % 8) == 0) ? 0 : 1)) == out_size);
+ EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, len, out, out_size));
+ return GNUNET_OK;
+ EXITIF_exit:
+ return GNUNET_SYSERR;
+}
+
+/* End of util/json.c */
diff --git a/src/util/microhttpd.c b/src/util/microhttpd.c
new file mode 100644
index 000000000..f3bea74f8
--- /dev/null
+++ b/src/util/microhttpd.c
@@ -0,0 +1,417 @@
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_microhttpd_lib.h"
+
+
+
+/**
+ * Initial size for POST
+ * request buffer.
+ */
+#define REQUEST_BUFFER_INITIAL 1024
+
+/**
+ * Maximum POST request size
+ */
+#define REQUEST_BUFFER_MAX (1024*1024)
+
+
+/**
+ * Buffer for POST requests.
+ */
+struct Buffer
+{
+ /**
+ * Allocated memory
+ */
+ char *data;
+
+ /**
+ * Number of valid bytes in buffer.
+ */
+ size_t fill;
+
+ /**
+ * Number of allocated bytes in buffer.
+ */
+ size_t alloc;
+};
+
+
+/**
+ * Initialize a buffer.
+ *
+ * @param buf the buffer to initialize
+ * @param data the initial data
+ * @param data_size size of the initial data
+ * @param alloc_size size of the buffer
+ * @param max_size maximum size that the buffer can grow to
+ * @return a GNUnet result code
+ */
+static int
+buffer_init (struct Buffer *buf, const void *data, size_t data_size, size_t alloc_size, size_t max_size)
+{
+ if (data_size > max_size || alloc_size > max_size)
+ return GNUNET_SYSERR;
+ if (data_size > alloc_size)
+ alloc_size = data_size;
+ buf->data = GNUNET_malloc (alloc_size);
+ memcpy (buf->data, data, data_size);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Free the data in a buffer. Does *not* free
+ * the buffer object itself.
+ *
+ * @param buf buffer to de-initialize
+ */
+static void
+buffer_deinit (struct Buffer *buf)
+{
+ GNUNET_free (buf->data);
+ buf->data = NULL;
+}
+
+
+/**
+ * Append data to a buffer, growing the buffer if necessary.
+ *
+ * @param buf the buffer to append to
+ * @param data the data to append
+ * @param size the size of @a data
+ * @param max_size maximum size that the buffer can grow to
+ * @return GNUNET_OK on success,
+ * GNUNET_NO if the buffer can't accomodate for the new data
+ * GNUNET_SYSERR on fatal error (out of memory?)
+ */
+static int
+buffer_append (struct Buffer *buf, const void *data, size_t data_size, size_t max_size)
+{
+ if (buf->fill + data_size > max_size)
+ return GNUNET_NO;
+ if (data_size + buf->fill > buf->alloc)
+ {
+ char *new_buf;
+ size_t new_size = buf->alloc;
+ while (new_size < buf->fill + data_size)
+ new_size += 2;
+ if (new_size > max_size)
+ return GNUNET_NO;
+ new_buf = GNUNET_malloc (new_size);
+ memcpy (new_buf, buf->data, buf->fill);
+ buf->data = new_buf;
+ buf->alloc = new_size;
+ }
+ memcpy (buf->data + buf->fill, data, data_size);
+ buf->fill += data_size;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Send JSON object as response. Decreases the reference count of the
+ * JSON object.
+ *
+ * @param connection the MHD connection
+ * @param json the json object
+ * @param status_code the http status code
+ * @return MHD result code
+ */
+int
+send_response_json (struct MHD_Connection *connection,
+ json_t *json,
+ unsigned int status_code)
+{
+ struct MHD_Response *resp;
+ char *json_str;
+
+ json_str = json_dumps (json, JSON_INDENT(2));
+ json_decref (json);
+ resp = MHD_create_response_from_buffer (strlen (json_str), json_str,
+ MHD_RESPMEM_MUST_FREE);
+ if (NULL == resp)
+ return MHD_NO;
+ return MHD_queue_response (connection, status_code, resp);
+}
+
+
+/**
+ * Send a JSON object via an MHD connection,
+ * specified with the JANSSON pack syntax (see json_pack).
+ *
+ * @param connection connection to send the JSON over
+ * @param http_code HTTP status for the response
+ * @param fmt format string for pack
+ * @param ... varargs
+ * @return MHD_YES on success or MHD_NO on error
+ */
+int
+request_send_json_pack (struct MHD_Connection *connection,
+ unsigned int http_code,
+ const char *fmt, ...)
+{
+ json_t *msg;
+ va_list argp;
+ int ret;
+
+ va_start(argp, fmt);
+ msg = json_vpack_ex (NULL, 0, fmt, argp);
+ va_end(argp);
+ if (NULL == msg)
+ return MHD_NO;
+ ret = send_response_json (connection, msg, http_code);
+ json_decref (msg);
+ return ret;
+}
+
+
+/**
+ * Process a POST request containing a JSON object.
+ *
+ * @param connection the MHD connection
+ * @param con_cs the closure (contains a 'struct Buffer *')
+ * @param upload_data the POST data
+ * @param upload_data_size the POST data size
+ * @param json the JSON object for a completed request
+ *
+ * @returns
+ * GNUNET_YES if json object was parsed
+ * GNUNET_NO is request incomplete or invalid
+ * GNUNET_SYSERR on internal error
+ */
+int
+process_post_json (struct MHD_Connection *connection,
+ void **con_cls,
+ const char *upload_data,
+ size_t *upload_data_size,
+ json_t **json)
+{
+ struct Buffer *r = *con_cls;
+
+ if (NULL == *con_cls)
+ {
+ /* We are seeing a fresh POST request. */
+
+ r = GNUNET_new (struct Buffer);
+ if (GNUNET_OK != buffer_init (r, upload_data, *upload_data_size,
+ REQUEST_BUFFER_INITIAL, REQUEST_BUFFER_MAX))
+ {
+ *con_cls = NULL;
+ buffer_deinit (r);
+ GNUNET_free (r);
+ return GNUNET_SYSERR;
+ }
+ *upload_data_size = 0;
+ *con_cls = r;
+ return GNUNET_NO;
+ }
+ if (0 != *upload_data_size)
+ {
+ /* We are seeing an old request with more data available. */
+
+ if (GNUNET_OK != buffer_append (r, upload_data, *upload_data_size,
+ REQUEST_BUFFER_MAX))
+ {
+ /* Request too long or we're out of memory. */
+
+ *con_cls = NULL;
+ buffer_deinit (r);
+ GNUNET_free (r);
+ return GNUNET_SYSERR;
+ }
+ *upload_data_size = 0;
+ return GNUNET_NO;
+ }
+
+ /* We have seen the whole request. */
+
+ *json = json_loadb (r->data, r->fill, 0, NULL);
+ buffer_deinit (r);
+ GNUNET_free (r);
+ if (NULL == *json)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Can't parse JSON request body\n");
+ return request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
+ GNUNET_NO, GNUNET_SYSERR,
+ "{s:s}",
+ "error", "invalid json");
+ }
+ *con_cls = NULL;
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Navigate through a JSON tree.
+ *
+ * Sends an error response if navigation is impossible (i.e.
+ * the JSON object is invalid)
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param ... navigation specification (see JNAV_*)
+ * @return GNUNET_YES if navigation was successful
+ * GNUNET_NO if json is malformed, error response was generated
+ * GNUNET_SYSERR on internal error
+ */
+int
+request_json_require_nav (struct MHD_Connection *connection,
+ const json_t *root, ...)
+{
+ va_list argp;
+ int ignore = GNUNET_NO;
+ // what's our current path from 'root'?
+ json_t *path;
+
+ path = json_array ();
+
+ va_start(argp, root);
+
+ while (1)
+ {
+ int command = va_arg(argp, int);
+ switch (command)
+ {
+ case JNAV_FIELD:
+ {
+ const char *fname = va_arg(argp, const char *);
+ if (GNUNET_YES == ignore)
+ break;
+ json_array_append_new (path, json_string (fname));
+ root = json_object_get (root, fname);
+ if (NULL == root)
+ {
+
+ (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
+ 0, 0,
+ "{s:s,s:o}",
+ "error", "missing field in JSON",
+ "path", path);
+ ignore = GNUNET_YES;
+ break;
+ }
+ }
+ break;
+ case JNAV_INDEX:
+ {
+ int fnum = va_arg(argp, int);
+ if (GNUNET_YES == ignore)
+ break;
+ json_array_append_new (path, json_integer (fnum));
+ root = json_array_get (root, fnum);
+ if (NULL == root)
+ {
+ (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
+ 0, 0,
+ "{s:s, s:o}",
+ "error", "missing index in JSON",
+ "path", path);
+ ignore = GNUNET_YES;
+ break;
+ }
+ }
+ break;
+ case JNAV_RET_DATA:
+ {
+ void *where = va_arg (argp, void *);
+ size_t len = va_arg (argp, size_t);
+ const char *str;
+ int res;
+
+ va_end(argp);
+ if (GNUNET_YES == ignore)
+ return GNUNET_NO;
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
+ 0, 0,
+ "{s:s, s:o}",
+ "error", "string expected",
+ "path", path);
+ return GNUNET_NO;
+ }
+ res = GNUNET_STRINGS_string_to_data (str, strlen (str),
+ where, len);
+ if (GNUNET_OK != res)
+ {
+ (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
+ 0, 0,
+ "{s:s,s:o}",
+ "error", "malformed binary data in JSON",
+ "path", path);
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+ }
+ break;
+ case JNAV_RET_DATA_VAR:
+ {
+ void **where = va_arg (argp, void **);
+ size_t *len = va_arg (argp, size_t *);
+ const char *str;
+
+ va_end(argp);
+ if (GNUNET_YES == ignore)
+ return GNUNET_NO;
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ *len = (strlen (str) * 5) / 8;
+ if (where != NULL)
+ {
+ int res;
+ *where = GNUNET_malloc (*len);
+ res = GNUNET_STRINGS_string_to_data (str, strlen (str),
+ *where, *len);
+ if (GNUNET_OK != res)
+ {
+ (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
+ 0, 0,
+ "{s:s, s:o}",
+ "error", "malformed binary data in JSON",
+ "path", path);
+ return GNUNET_NO;
+ }
+ }
+ return GNUNET_OK;
+ }
+ break;
+ case JNAV_RET_TYPED_JSON:
+ {
+ int typ = va_arg (argp, int);
+ const json_t **r_json = va_arg (argp, const json_t **);
+
+ va_end(argp);
+ if (GNUNET_YES == ignore)
+ return GNUNET_NO;
+ if (typ != -1 && json_typeof (root) != typ)
+ {
+ (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
+ 0, 0,
+ "{s:s, s:i, s:i s:o}",
+ "error", "wrong JSON field type",
+ "type_expected", typ,
+ "type_actual", json_typeof (root),
+ "path", path);
+ return GNUNET_NO;
+ }
+ *r_json = root;
+ return GNUNET_OK;
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ }
+ GNUNET_assert (0);
+}
+
+
+
diff --git a/src/util/misc.supp b/src/util/misc.supp
new file mode 100644
index 000000000..afcac6128
--- /dev/null
+++ b/src/util/misc.supp
@@ -0,0 +1,28 @@
+{
+ <gnunet_gcrypt_init>
+ Memcheck:Leak
+ match-leak-kinds:reachable
+ ...
+ fun:GNUNET_CRYPTO_random_init
+ fun:call_init.part.0
+ ...
+}
+
+{
+ <mpi_ec_new>
+ Memcheck:Leak
+ match-leak-kinds:reachable
+ ...
+ fun:point_from_keyparam
+ fun:_gcry_mpi_ec_new
+ ...
+}
+
+{
+ <gnunet_log_setup>
+ Memcheck:Leak
+ match-leak-kinds:reachable
+ ...
+ fun:GNUNET_log_setup
+ ...
+} \ No newline at end of file
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 */
diff --git a/src/util/test_hash_context.c b/src/util/test_hash_context.c
new file mode 100644
index 000000000..e5110f212
--- /dev/null
+++ b/src/util/test_hash_context.c
@@ -0,0 +1,48 @@
+/*
+ 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/test_hash_context.c
+ * @brief test case for incremental hashing
+ * @author Florian Dold
+ */
+
+#include "platform.h"
+#include "taler_util.h"
+#include <gcrypt.h>
+
+#define LEN 1234
+
+int main()
+{
+ char data[1234];
+ struct GNUNET_HashCode hc1;
+ struct GNUNET_HashCode hc2;
+ struct TALER_HashContext hctx;
+
+ memset (data, 42, LEN);
+
+ TALER_hash_context_start (&hctx);
+ TALER_hash_context_read (&hctx, data, LEN);
+ TALER_hash_context_finish (&hctx, &hc1);
+
+ GNUNET_CRYPTO_hash (data, LEN, &hc2);
+
+ if (0 == memcmp (&hc1, &hc2, sizeof (struct GNUNET_HashCode)))
+ return 0;
+ return 1;
+}
+
diff --git a/src/util/test_rsa.c b/src/util/test_rsa.c
new file mode 100644
index 000000000..ac3ae2cd4
--- /dev/null
+++ b/src/util/test_rsa.c
@@ -0,0 +1,112 @@
+/*
+ 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/test_rsa.c
+ * @brief testcase for utility functions for RSA cryptography
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include "taler_rsa.h"
+#include <gnunet/gnunet_util_lib.h>
+
+#define TEST_PURPOSE UINT32_MAX
+
+
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+int
+main (int argc, char *argv[])
+{
+#define RND_BLK_SIZE 4096
+ unsigned char rnd_blk[RND_BLK_SIZE];
+ struct TALER_RSA_PrivateKey *priv;
+ struct TALER_RSA_PrivateKeyBinaryEncoded *priv_enc;
+ struct TALER_RSA_PublicKeyBinaryEncoded pubkey;
+ struct TALER_RSA_BlindingKey *bkey;
+ struct TALER_RSA_BlindedSignaturePurpose *bsp;
+ struct TALER_RSA_Signature sig;
+ struct GNUNET_HashCode hash;
+ int ret;
+
+ priv = NULL;
+ bsp = NULL;
+ bkey = NULL;
+ ret = 1;
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, rnd_blk,
+ RND_BLK_SIZE);
+ GNUNET_CRYPTO_hash (rnd_blk, RND_BLK_SIZE, &hash);
+ priv = TALER_RSA_key_create ();
+ GNUNET_assert (NULL != priv);
+ EXITIF (GNUNET_OK != TALER_RSA_sign (priv,
+ &hash, sizeof (hash),
+ &sig));
+ TALER_RSA_key_get_public (priv, &pubkey);
+ EXITIF (NULL == (priv_enc = TALER_RSA_encode_key (priv)));
+ TALER_RSA_key_free (priv);
+ priv = NULL;
+ EXITIF (NULL == (priv = TALER_RSA_decode_key ((const char *) priv_enc,
+ ntohs (priv_enc->len))));
+ GNUNET_free (priv_enc);
+ priv_enc = NULL;
+ EXITIF (GNUNET_OK != TALER_RSA_hash_verify (&hash,
+ &sig,
+ &pubkey));
+ EXITIF (GNUNET_OK != TALER_RSA_verify (rnd_blk,
+ RND_BLK_SIZE,
+ &sig,
+ &pubkey));
+
+ /* test blind signing */
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, rnd_blk,
+ RND_BLK_SIZE);
+ GNUNET_CRYPTO_hash (rnd_blk, RND_BLK_SIZE, &hash);
+ (void) memset (&sig, 0, sizeof (struct TALER_RSA_Signature));
+ EXITIF (NULL == (bkey = TALER_RSA_blinding_key_create ()));
+ EXITIF (NULL == (bsp =
+ TALER_RSA_message_blind (&hash, sizeof (hash),
+ bkey, &pubkey)));
+ EXITIF (GNUNET_OK != TALER_RSA_sign (priv,
+ bsp,
+ sizeof (struct TALER_RSA_BlindedSignaturePurpose),
+ &sig));
+ EXITIF (GNUNET_OK != TALER_RSA_unblind (&sig,
+ bkey,
+ &pubkey));
+ EXITIF (GNUNET_OK != TALER_RSA_hash_verify (&hash,
+ &sig,
+ &pubkey));
+ ret = 0; /* all OK */
+
+ EXITIF_exit:
+ if (NULL != priv)
+ {
+ TALER_RSA_key_free (priv);
+ priv = NULL;
+ }
+ if (NULL != priv_enc)
+ {
+ GNUNET_free (priv_enc);
+ priv_enc = NULL;
+ }
+ if (NULL != bkey)
+ TALER_RSA_blinding_key_destroy (bkey);
+ GNUNET_free_non_null (bsp);
+ return ret;
+}
diff --git a/src/util/util.c b/src/util/util.c
new file mode 100644
index 000000000..3677bcbde
--- /dev/null
+++ b/src/util/util.c
@@ -0,0 +1,528 @@
+/*
+ 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.c
+ * @brief Common utility functions
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ */
+
+#include "platform.h"
+#include "taler_util.h"
+#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <gcrypt.h>
+
+#define CURVE "Ed25519"
+
+#define AMOUNT_FRAC_BASE 1000000
+#define AMOUNT_FRAC_LEN 6
+
+
+
+static void
+fatal_error_handler (void *cls, int wtf, const char *msg)
+{
+ LOG_ERROR("Fatal error in Gcrypt: %s\n", msg);
+ abort();
+}
+
+
+/**
+ * Initialize Gcrypt library.
+ */
+void
+TALER_gcrypt_init()
+{
+ gcry_set_fatalerror_handler (&fatal_error_handler, NULL);
+ TALER_assert_as(gcry_check_version(NEED_LIBGCRYPT_VERSION),
+ "libgcrypt version mismatch");
+ /* Disable secure memory. */
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+}
+
+
+/**
+ * Generate a ECC private key.
+ *
+ * @return the s-expression representing the generated ECC private key; NULL
+ * upon error
+ */
+gcry_sexp_t
+TALER_genkey ()
+{
+ gcry_sexp_t priv_sexp;
+ gcry_sexp_t s_keyparam;
+ int rc;
+
+ if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
+ "(genkey(ecc(curve \"" CURVE "\")"
+ "(flags eddsa)))")))
+ {
+ LOG_GCRY_ERROR ("gcry_sexp_build", rc);
+ return NULL;
+ }
+ if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
+ {
+ LOG_GCRY_ERROR ("gcry_pk_genkey", rc);
+ gcry_sexp_release (s_keyparam);
+ return NULL;
+ }
+ gcry_sexp_release (s_keyparam);
+ if (0 != (rc = gcry_pk_testkey (priv_sexp)))
+ {
+ LOG_GCRY_ERROR("gcry_pk_testkey", rc);
+ gcry_sexp_release (priv_sexp);
+ return NULL;
+ }
+ return priv_sexp;
+}
+
+
+/**
+ * Parse money amount description, in the format "A:B.C".
+ *
+ * @param str amount description
+ * @param denom amount to write the result to
+ * @return GNUNET_OK if the string is a valid amount specification,
+ * GNUNET_SYSERR if it is invalid.
+ */
+int
+TALER_string_to_amount (const char *str, struct TALER_Amount *denom)
+{
+ unsigned int i; // pos in str
+ int n; // number tmp
+ unsigned int c; // currency pos
+ uint32_t b; // base for suffix
+
+ memset (denom, 0, sizeof (struct TALER_Amount));
+
+ i = n = c = 0;
+
+ while (isspace(str[i]))
+ i++;
+
+ if (0 == str[i])
+ {
+ printf("null before currency\n");
+ return GNUNET_SYSERR;
+ }
+
+ while (str[i] != ':')
+ {
+ if (0 == str[i])
+ {
+ printf("null before colon");
+ return GNUNET_SYSERR;
+ }
+ if (c > 3)
+ {
+ printf("currency too long\n");
+ return GNUNET_SYSERR;
+ }
+ denom->currency[c] = str[i];
+ c++;
+ i++;
+ }
+
+ // skip colon
+ i++;
+
+ if (0 == str[i])
+ {
+ printf("null before value\n");
+ return GNUNET_SYSERR;
+ }
+
+ while (str[i] != '.')
+ {
+ if (0 == str[i])
+ {
+ return GNUNET_OK;
+ }
+ n = str[i] - '0';
+ if (n < 0 || n > 9)
+ {
+ printf("invalid character '%c' before comma at %u\n", (char) n, i);
+ return GNUNET_SYSERR;
+ }
+ denom->value = (denom->value * 10) + n;
+ i++;
+ }
+
+ // skip the dot
+ i++;
+
+ if (0 == str[i])
+ {
+ printf("null after dot");
+ return GNUNET_SYSERR;
+ }
+
+ b = 100000;
+
+ while (0 != str[i])
+ {
+ n = str[i] - '0';
+ if (b == 0 || n < 0 || n > 9)
+ {
+ printf("error after comma");
+ return GNUNET_SYSERR;
+ }
+ denom->fraction += n * b;
+ b /= 10;
+ i++;
+ }
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * FIXME
+ */
+struct TALER_AmountNBO
+TALER_amount_hton (struct TALER_Amount d)
+{
+ struct TALER_AmountNBO dn;
+ dn.value = htonl (d.value);
+ dn.fraction = htonl (d.fraction);
+ memcpy (dn.currency, d.currency, TALER_CURRENCY_LEN);
+
+ return dn;
+}
+
+
+/**
+ * FIXME
+ */
+struct TALER_Amount
+TALER_amount_ntoh (struct TALER_AmountNBO dn)
+{
+ struct TALER_Amount d;
+ d.value = ntohl (dn.value);
+ d.fraction = ntohl (dn.fraction);
+ memcpy (d.currency, dn.currency, sizeof(dn.currency));
+
+ return d;
+}
+
+
+/**
+ * Compare the value/fraction of two amounts. Does not compare the currency,
+ * i.e. comparing amounts with the same value and fraction but different
+ * currency would return 0.
+ *
+ * @param a1 first amount
+ * @param a2 second amount
+ * @return result of the comparison
+ */
+int
+TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2)
+{
+ a1 = TALER_amount_normalize (a1);
+ a2 = TALER_amount_normalize (a2);
+ if (a1.value == a2.value)
+ {
+ if (a1.fraction < a2.fraction)
+ return -1;
+ if (a1.fraction > a2.fraction)
+ return 1;
+ return 0;
+ }
+ if (a1.value < a2.value)
+ return -1;
+ return 1;
+}
+
+
+/**
+ * Perform saturating subtraction of amounts.
+ *
+ * @param a1 amount to subtract from
+ * @param a2 amount to subtract
+ * @return (a1-a2) or 0 if a2>=a1
+ */
+struct TALER_Amount
+TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2)
+{
+ a1 = TALER_amount_normalize (a1);
+ a2 = TALER_amount_normalize (a2);
+
+ if (a1.value < a2.value)
+ {
+ a1.value = 0;
+ a1.fraction = 0;
+ return a1;
+ }
+
+ if (a1.fraction < a2.fraction)
+ {
+ if (0 == a1.value)
+ {
+ a1.fraction = 0;
+ return a1;
+ }
+ a1.fraction += AMOUNT_FRAC_BASE;
+ a1.value -= 1;
+ }
+
+ a1.fraction -= a2.fraction;
+ a1.value -= a2.value;
+
+ return a1;
+}
+
+
+/**
+ * Perform saturating addition of amounts.
+ *
+ * @param a1 first amount to add
+ * @param a2 second amount to add
+ * @return sum of a1 and a2
+ */
+struct TALER_Amount
+TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2)
+{
+ a1 = TALER_amount_normalize (a1);
+ a2 = TALER_amount_normalize (a2);
+
+ a1.value += a2.value;
+ a1.fraction += a2.fraction;
+
+ if (0 == a1.currency[0])
+ {
+ memcpy (a2.currency, a1.currency, TALER_CURRENCY_LEN);
+ }
+
+ if (0 == a2.currency[0])
+ {
+ memcpy (a1.currency, a2.currency, TALER_CURRENCY_LEN);
+ }
+
+ if (0 != a1.currency[0] && 0 != memcmp (a1.currency, a2.currency, TALER_CURRENCY_LEN))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "adding mismatching currencies\n");
+ }
+
+ if (a1.value < a2.value)
+ {
+ a1.value = UINT32_MAX;
+ a2.value = UINT32_MAX;
+ return a1;
+ }
+
+ return TALER_amount_normalize (a1);
+}
+
+
+/**
+ * Normalize the given amount.
+ *
+ * @param amout amount to normalize
+ * @return normalized amount
+ */
+struct TALER_Amount
+TALER_amount_normalize (struct TALER_Amount amount)
+{
+ while (amount.value != UINT32_MAX && amount.fraction >= AMOUNT_FRAC_BASE)
+ {
+ amount.fraction -= AMOUNT_FRAC_BASE;
+ amount.value += 1;
+ }
+ return amount;
+}
+
+
+/**
+ * Convert amount to string.
+ *
+ * @param amount amount to convert to string
+ * @return freshly allocated string representation
+ */
+char *
+TALER_amount_to_string (struct TALER_Amount amount)
+{
+ char tail[AMOUNT_FRAC_LEN + 1] = { 0 };
+ char curr[TALER_CURRENCY_LEN + 1] = { 0 };
+ char *result = NULL;
+ int len;
+
+ memcpy (curr, amount.currency, TALER_CURRENCY_LEN);
+
+ amount = TALER_amount_normalize (amount);
+ if (0 != amount.fraction)
+ {
+ unsigned int i;
+ uint32_t n = amount.fraction;
+ for (i = 0; (i < AMOUNT_FRAC_LEN) && (n != 0); i++)
+ {
+ tail[i] = '0' + (n / (AMOUNT_FRAC_BASE / 10));
+ n = (n * 10) % (AMOUNT_FRAC_BASE);
+ }
+ tail[i] = 0;
+ len = GNUNET_asprintf (&result, "%s:%lu.%s", curr, (unsigned long) amount.value, tail);
+ }
+ else
+ {
+ len = GNUNET_asprintf (&result, "%s:%lu", curr, (unsigned long) amount.value);
+ }
+ GNUNET_assert (len > 0);
+ return result;
+}
+
+
+
+/**
+ * Return the base32crockford encoding of the given buffer.
+ *
+ * The returned string will be freshly allocated, and must be free'd
+ * with GNUNET_free.
+ *
+ * @param buffer with data
+ * @param size size of the buffer
+ * @return freshly allocated, null-terminated string
+ */
+char *
+TALER_data_to_string_alloc (const void *buf, size_t size)
+{
+ char *str_buf;
+ size_t len = size * 8;
+ char *end;
+
+ if (len % 5 > 0)
+ len += 5 - len % 5;
+ len /= 5;
+ str_buf = GNUNET_malloc (len + 1);
+ end = GNUNET_STRINGS_data_to_string (buf, size, str_buf, len);
+ if (NULL == end)
+ {
+ GNUNET_free (str_buf);
+ return NULL;
+ }
+ *end = '\0';
+ return str_buf;
+}
+
+
+/**
+ * Get encoded binary data from a configuration.
+ *
+ * @return GNUNET_OK on success
+ * GNUNET_NO is the value does not exist
+ * GNUNET_SYSERR on encoding error
+ */
+int
+TALER_configuration_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section, const char *option,
+ void *buf, size_t buf_size)
+{
+ char *enc;
+ int res;
+ size_t data_size;
+ if (GNUNET_OK != (res = GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &enc)))
+ return res;
+ data_size = (strlen (enc) * 5) / 8;
+ if (data_size != buf_size)
+ {
+ GNUNET_free (enc);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, strlen (enc),
+ buf, buf_size))
+ {
+ GNUNET_free (enc);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+static void
+derive_refresh_key (const struct GNUNET_HashCode *secret,
+ struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
+ struct GNUNET_CRYPTO_SymmetricSessionKey *skey)
+{
+ static const char ctx_key[] = "taler-key-skey";
+ static const char ctx_iv[] = "taler-key-iv";
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
+ ctx_key, strlen (ctx_key),
+ secret, sizeof (struct GNUNET_HashCode),
+ NULL, 0));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
+ ctx_iv, strlen (ctx_iv),
+ secret, sizeof (struct GNUNET_HashCode),
+ NULL, 0));
+}
+
+
+int
+TALER_refresh_decrypt (const void *input, size_t input_size, const struct GNUNET_HashCode *secret, void *result)
+{
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+
+ derive_refresh_key (secret, &iv, &skey);
+
+ return GNUNET_CRYPTO_symmetric_decrypt (input, input_size, &skey, &iv, result);
+}
+
+
+int
+TALER_refresh_encrypt (const void *input, size_t input_size, const struct GNUNET_HashCode *secret, void *result)
+{
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+
+ derive_refresh_key (secret, &iv, &skey);
+
+ return GNUNET_CRYPTO_symmetric_encrypt (input, input_size, &skey, &iv, result);
+}
+
+
+void
+TALER_hash_context_start (struct TALER_HashContext *hc)
+{
+ GNUNET_assert (0 == gcry_md_open (&hc->hd, GCRY_MD_SHA512, 0));
+}
+
+
+void
+TALER_hash_context_read (struct TALER_HashContext *hc, void *buf, size_t size)
+{
+ gcry_md_write (hc->hd, buf, size);
+}
+
+
+void
+TALER_hash_context_finish (struct TALER_HashContext *hc,
+ struct GNUNET_HashCode *r_hash)
+{
+ void *res = gcry_md_read (hc->hd, 0);
+ GNUNET_assert (NULL != res);
+ if (NULL != r_hash)
+ memcpy (r_hash, res, sizeof (struct GNUNET_HashCode));
+ gcry_md_close (hc->hd);
+}
+
+
+/* end of util.c */