/*
This file is part of GNUnet.
(C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2012 Christian Grothoff (and other contributing authors)
GNUnet 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 2, or (at your
option) any later version.
GNUnet 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 GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file util/crypto_ecc.c
* @brief public key cryptography (ECC) with libgcrypt
* @author Christian Grothoff
*/
#include "platform.h"
#include <gcrypt.h>
#include "gnunet_common.h"
#include "gnunet_util_lib.h"
#define EXTRA_CHECKS ALLOW_EXTRA_CHECKS || 1
#define CURVE "NIST P-521"
#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);
/**
* The private information of an ECC private key.
*/
struct GNUNET_CRYPTO_EccPrivateKey
{
/**
* Libgcrypt S-expression for the ECC key.
*/
gcry_sexp_t sexp;
};
/**
* Free memory occupied by ECC key
*
* @param privatekey pointer to the memory to free
*/
void
GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *privatekey)
{
gcry_sexp_release (privatekey->sexp);
GNUNET_free (privatekey);
}
/**
* 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;
list = gcry_sexp_find_token (sexp, topname, 0);
if (! list)
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++)
{
l2 = gcry_sexp_find_token (list, s, 1);
if (! l2)
{
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;
}
/**
* Extract the public key for the given private key.
*
* @param priv the private key
* @param pub where to write the public key
*/
void
GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *pub)
{
gcry_mpi_t skey;
size_t size;
int rc;
memset (pub, 0, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
rc = key_from_sexp (&skey, priv->sexp, "public-key", "q");
if (rc)
rc = key_from_sexp (&skey, priv->sexp, "private-key", "q");
if (rc)
rc = key_from_sexp (&skey,