/*
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
*/
/**
* @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
*
* Authors of the gnunet code:
* Christian Grothoff
* Krista Bennett
* Gerd Knorr
* 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 */