[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r37214 - in gnunet/src: include util
From: |
gnunet |
Subject: |
[GNUnet-SVN] r37214 - in gnunet/src: include util |
Date: |
Mon, 30 May 2016 17:54:56 +0200 |
Author: burdges
Date: 2016-05-30 17:54:56 +0200 (Mon, 30 May 2016)
New Revision: 37214
Modified:
gnunet/src/include/gnunet_crypto_lib.h
gnunet/src/util/crypto_kdf.c
gnunet/src/util/crypto_rsa.c
gnunet/src/util/test_crypto_rsa.c
Log:
Use a uniform random number mod an RSA composites for both
the blinding factor and the full domain hash.
This resolves an attack against the blinding factor in Taler:
There was a call to GNUNET_CRYPTO_kdf in
bkey = rsa_blinding_key_derive (len, bks);
that gives exactly len bits where
len = GNUNET_CRYPTO_rsa_public_key_len (pkey);
Now r = 2^(len-1)/pkey.n is the probability that a set high bit being
okay, meaning bkey < pkey.n. It follows that (1-r)/2 of the time bkey >
pkey.n making the effective bkey be
bkey mod pkey.n = bkey - pkey.n
so the effective bkey has its high bit set with probability r/2.
We expect r to be close to 1/2 if the exchange is honest, but the
exchange can choose r otherwise.
In blind signing, the exchange sees
B = bkey * S mod pkey.n
On deposit, the exchange sees S so they can compute bkey' = B/S mod
pkey.n for all B they recorded to see if bkey' has it's high bit set.
Also, note the exchange can compute 1/S efficiently since they know the
factors of pkey.n.
I suppose that happens with probability r/(1+r) if its the wrong B, not
completely sure. If otoh we've the right B, then we've the probability
r/2 of a set high bit in the effective bkey.
Interestingly, r^2-r has a maximum at the default r=1/2 anyways, giving
the wrong and right probabilities 1/3 and 1/4, respectively.
I fear this gives the exchange a meaningful fraction of a bit of
information per coin involved in the transaction. It sounds damaging if
numerous coins were involved. And it could run across transactions in
some scenarios.
I suspect we need a more uniform deterministic pseudo-random number
generator for blinding factors. Just fyi, our old call to
gcry_mpi_randomize had this same problem.
I do not believe this caused a problem for the full domain hash, but
we can fix it easily enough anyways.
Modified: gnunet/src/include/gnunet_crypto_lib.h
===================================================================
--- gnunet/src/include/gnunet_crypto_lib.h 2016-05-30 15:54:38 UTC (rev
37213)
+++ gnunet/src/include/gnunet_crypto_lib.h 2016-05-30 15:54:56 UTC (rev
37214)
@@ -27,6 +27,7 @@
* @author Gerd Knorr <address@hidden>
* @author Ioana Patrascu
* @author Tzvetan Horozov
+ * @author Jeffrey Burdges <address@hidden>
*
* @defgroup crypto Crypto library: cryptographic operations
* Provides cryptographic primitives.
@@ -1015,6 +1016,26 @@
/**
+ * Deterministically generate a pseudo-random number uniformly from the
+ * integers modulo a libgcrypt mpi.
+ *
+ * @param[out] r MPI value set to the FDH
+ * @param n MPI to work modulo
+ * @param xts salt
+ * @param xts_len length of @a xts
+ * @param skm source key material
+ * @param skm_len length of @a skm
+ * @param ctx context string
+ */
+void
+GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r,
+ gcry_mpi_t n,
+ const void *xts, size_t xts_len,
+ const void *skm, size_t skm_len,
+ const char *ctx);
+
+
+/**
* @ingroup hash
* @brief Derive key
* @param result buffer for the derived key, allocated by caller
Modified: gnunet/src/util/crypto_kdf.c
===================================================================
--- gnunet/src/util/crypto_kdf.c 2016-05-30 15:54:38 UTC (rev 37213)
+++ gnunet/src/util/crypto_kdf.c 2016-05-30 15:54:56 UTC (rev 37214)
@@ -22,6 +22,7 @@
* @file src/util/crypto_kdf.c
* @brief Key derivation
* @author Nils Durner
+ * @author Jeffrey Burdges <address@hidden>
*/
#include <gcrypt.h>
@@ -43,8 +44,9 @@
* @return #GNUNET_YES on success
*/
int
-GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, const void *xts,
- size_t xts_len, const void *skm, size_t skm_len,
+GNUNET_CRYPTO_kdf_v (void *result, size_t out_len,
+ const void *xts, size_t xts_len,
+ const void *skm, size_t skm_len,
va_list argp)
{
/*
@@ -76,8 +78,9 @@
* @return #GNUNET_YES on success
*/
int
-GNUNET_CRYPTO_kdf (void *result, size_t out_len, const void *xts,
- size_t xts_len, const void *skm, size_t skm_len, ...)
+GNUNET_CRYPTO_kdf (void *result, size_t out_len,
+ const void *xts, size_t xts_len,
+ const void *skm, size_t skm_len, ...)
{
va_list argp;
int ret;
@@ -88,3 +91,60 @@
return ret;
}
+
+
+/**
+ * Deterministically generate a pseudo-random number uniformly from the
+ * integers modulo a libgcrypt mpi.
+ *
+ * @param[out] r MPI value set to the FDH
+ * @param n MPI to work modulo
+ * @param xts salt
+ * @param xts_len length of @a xts
+ * @param skm source key material
+ * @param skm_len length of @a skm
+ * @param ctx context string
+ */
+void
+GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r,
+ gcry_mpi_t n,
+ const void *xts, size_t xts_len,
+ const void *skm, size_t skm_len,
+ const char *ctx)
+{
+ gcry_error_t rc;
+ unsigned int nbits;
+ size_t rsize;
+ unsigned int ctr;
+
+ nbits = gcry_mpi_get_nbits (n);
+ /* GNUNET_assert (nbits > 512); */
+
+ ctr = 0;
+ do {
+ /* Ain't clear if n is always divisible by 8 */
+ uint8_t buf[ (nbits-1)/8 + 1 ];
+
+ rc = GNUNET_CRYPTO_kdf (buf,
+ sizeof (buf),
+ xts, xts_len,
+ skm, skm_len,
+ ctx, strlen(ctx),
+ &ctr, sizeof(ctr),
+ NULL, 0);
+ GNUNET_assert (GNUNET_YES == rc);
+
+ rc = gcry_mpi_scan (r,
+ GCRYMPI_FMT_USG,
+ (const unsigned char *) buf,
+ sizeof (buf),
+ &rsize);
+ GNUNET_assert (0 == rc); /* Allocation erro? */
+
+ gcry_mpi_clear_highbit (*r, nbits);
+ GNUNET_assert( 0 == gcry_mpi_test_bit (*r, nbits) );
+ ++ctr;
+ } while ( 0 <= gcry_mpi_cmp(*r,n) );
+}
+
+
Modified: gnunet/src/util/crypto_rsa.c
===================================================================
--- gnunet/src/util/crypto_rsa.c 2016-05-30 15:54:38 UTC (rev 37213)
+++ gnunet/src/util/crypto_rsa.c 2016-05-30 15:54:56 UTC (rev 37214)
@@ -400,31 +400,24 @@
* @return the newly created blinding key
*/
static struct RsaBlindingKey *
-rsa_blinding_key_derive (unsigned int len,
+rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks)
{
+ char *xts = "Blinding KDF extrator HMAC key"; /* Trusts bks' randomness
more */
struct RsaBlindingKey *blind;
- uint8_t buf[len / 8];
- int rc;
- size_t rsize;
+ gcry_mpi_t n;
blind = GNUNET_new (struct RsaBlindingKey);
- /* FIXME: #4483: actually derive key from bks! - Jeff,
- check that you're happy with this!*/
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CRYPTO_kdf (buf,
- sizeof (buf),
- "blinding-kdf",
- strlen ("blinding-kdf"),
- bks,
- sizeof (*bks),
- NULL, 0));
- rc = gcry_mpi_scan (&blind->r,
- GCRYMPI_FMT_USG,
- (const unsigned char *) buf,
- sizeof (buf),
- &rsize);
- GNUNET_assert (0 == rc);
+
+ /* Extract the composite n from the RSA public key */
+ GNUNET_assert( 0 == key_from_sexp (&n, pkey->sexp, "rsa", "n") );
+ GNUNET_assert( 0 == gcry_mpi_get_flag(n, GCRYMPI_FLAG_OPAQUE) );
+
+ GNUNET_CRYPTO_kdf_mod_mpi (&blind->r,
+ n,
+ xts, strlen(xts),
+ bks, sizeof(*bks),
+ "Blinding KDF");
return blind;
}
@@ -538,13 +531,10 @@
GNUNET_CRYPTO_rsa_public_key_len (const struct GNUNET_CRYPTO_RsaPublicKey *key)
{
gcry_mpi_t n;
- int ret;
unsigned int rval;
- ret = key_from_sexp (&n, key->sexp, "rsa", "n");
- if (0 != ret)
- {
- /* this is no public RSA key */
+ if (0 != key_from_sexp (&n, key->sexp, "rsa", "n"))
+ { /* Not an RSA public key */
GNUNET_break (0);
return 0;
}
@@ -610,91 +600,33 @@
* @param hash initial hash of the message to sign
* @param pkey the public key of the signer
* @param rsize If not NULL, the number of bytes actually stored in buffer
- * @return libgcrypt error that to represent an allocation failure
*/
-/* FIXME: exported symbol without proper prefix... */
-gcry_error_t
+static void
rsa_full_domain_hash (gcry_mpi_t *r,
- const struct GNUNET_HashCode *hash,
- const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
- size_t *rsize)
+ const struct GNUNET_HashCode *hash,
+ const struct GNUNET_CRYPTO_RsaPublicKey
*pkey)
{
- unsigned int i;
- unsigned int nbits;
- unsigned int nhashes;
- gcry_error_t rc;
- char *buf;
- size_t buf_len;
- gcry_md_hd_t h;
- gcry_md_hd_t h0;
- struct GNUNET_HashCode *hs;
+ gcry_mpi_t n;
+ char *xts;
+ size_t xts_len;
- /* Uncomment the following to debug without using the full domain hash */
- /*
- rc = gcry_mpi_scan (r,
- GCRYMPI_FMT_USG,
- (const unsigned char *)hash,
- sizeof(struct GNUNET_HashCode),
- rsize);
- return rc;
- */
+ /* Extract the composite n from the RSA public key */
+ GNUNET_assert( 0 == key_from_sexp (&n, pkey->sexp, "rsa", "n") );
+ GNUNET_assert( 0 == gcry_mpi_get_flag(n, GCRYMPI_FLAG_OPAQUE) );
- nbits = GNUNET_CRYPTO_rsa_public_key_len (pkey);
- if (nbits < 512)
- nbits = 512;
+ /* We key with the public denomination key as a homage to RSA-PSS by *
+ * Mihir Bellare and Phillip Rogaway. Doing this lowers the degree *
+ * of the hypothetical polyomial-time attack on RSA-KTI created by a *
+ * polynomial-time one-more forgary attack. Yey seeding! */
+ xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &xts);
- /* Already almost an HMAC since we consume a hash, so no GCRY_MD_FLAG_HMAC.
*/
- rc = gcry_md_open (&h, GCRY_MD_SHA512, 0);
- if (0 != rc)
- return rc;
+ GNUNET_CRYPTO_kdf_mod_mpi (r,
+ n,
+ xts, xts_len,
+ hash, sizeof(*hash),
+ "RSA-FDA FTpsW!");
- /* We seed with the public denomination key as a homage to RSA-PSS by *
- * Mihir Bellare and Phillip Rogaway. Doing this lowers the degree *
- * of the hypothetical polyomial-time attack on RSA-KTI created by a *
- * polynomial-time one-more forgary attack. Yey seeding! */
- buf_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &buf);
- gcry_md_write (h, buf, buf_len);
- GNUNET_free (buf);
-
- nhashes = (nbits-1) / (8 * sizeof(struct GNUNET_HashCode)) + 1;
- hs = GNUNET_new_array (nhashes,
- struct GNUNET_HashCode);
- for (i=0; i<nhashes; i++)
- {
- gcry_md_write (h, hash, sizeof(struct GNUNET_HashCode));
- rc = gcry_md_copy (&h0, h);
- if (0 != rc)
- {
- gcry_md_close (h0);
- break;
- }
- gcry_md_putc (h0, i % 256);
- memcpy (&hs[i],
- gcry_md_read (h0, GCRY_MD_SHA512),
- sizeof(struct GNUNET_HashCode));
- gcry_md_close (h0);
- }
- gcry_md_close (h);
- if (0 != rc)
- {
- GNUNET_free (hs);
- return rc;
- }
-
- rc = gcry_mpi_scan (r,
- GCRYMPI_FMT_USG,
- (const unsigned char *) hs,
- nhashes * sizeof(struct GNUNET_HashCode),
- rsize);
- GNUNET_free (hs);
- if (0 != rc)
- return rc;
-
- /* Do not allow *r to exceed n or signatures fail to verify unpredictably. *
- * This happening with gcry_mpi_clear_highbit (*r, nbits-1) so maybe *
- * gcry_mpi_clear_highbit is broken, but setting the highbit sounds good. */
- gcry_mpi_set_highbit (*r, nbits-2);
- return rc;
+ GNUNET_free (xts);
}
@@ -718,11 +650,8 @@
gcry_mpi_t ne[2];
gcry_mpi_t r_e;
gcry_mpi_t data_r_e;
- size_t rsize;
size_t n;
- gcry_error_t rc;
int ret;
- unsigned int len;
ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne");
if (0 != ret)
@@ -734,17 +663,8 @@
return 0;
}
- rc = rsa_full_domain_hash (&data, hash, pkey, &rsize);
- if (0 != rc) /* Allocation error in libgcrypt */
- {
- GNUNET_break (0);
- gcry_mpi_release (ne[0]);
- gcry_mpi_release (ne[1]);
- *buffer = NULL;
- return 0;
- }
- len = GNUNET_CRYPTO_rsa_public_key_len (pkey);
- bkey = rsa_blinding_key_derive (len,
+ rsa_full_domain_hash (&data, hash, pkey);
+ bkey = rsa_blinding_key_derive (pkey,
bks);
r_e = gcry_mpi_new (0);
gcry_mpi_powm (r_e,
@@ -886,13 +806,11 @@
{
struct GNUNET_CRYPTO_RsaPublicKey *pkey;
gcry_mpi_t v = NULL;
- gcry_error_t rc;
struct GNUNET_CRYPTO_RsaSignature *sig;
pkey = GNUNET_CRYPTO_rsa_private_key_get_public (key);
- rc = rsa_full_domain_hash (&v, hash, pkey, NULL);
+ rsa_full_domain_hash (&v, hash, pkey);
GNUNET_CRYPTO_rsa_public_key_free (pkey);
- GNUNET_assert (0 == rc);
sig = rsa_sign_mpi (key, v);
gcry_mpi_release (v);
@@ -1034,7 +952,6 @@
gcry_mpi_t ubsig;
int ret;
struct GNUNET_CRYPTO_RsaSignature *sret;
- unsigned int len;
ret = key_from_sexp (&n, pkey->sexp, "public-key", "n");
if (0 != ret)
@@ -1053,8 +970,7 @@
GNUNET_break_op (0);
return NULL;
}
- len = GNUNET_CRYPTO_rsa_public_key_len (pkey);
- bkey = rsa_blinding_key_derive (len,
+ bkey = rsa_blinding_key_derive (pkey,
bks);
r_inv = gcry_mpi_new (0);
@@ -1106,8 +1022,7 @@
gcry_mpi_t r;
int rc;
- rc = rsa_full_domain_hash (&r, hash, pkey, NULL);
- GNUNET_assert (0 == rc); /* Allocation error in libgcrypt */
+ rsa_full_domain_hash (&r, hash, pkey);
data = mpi_to_sexp(r);
gcry_mpi_release (r);
Modified: gnunet/src/util/test_crypto_rsa.c
===================================================================
--- gnunet/src/util/test_crypto_rsa.c 2016-05-30 15:54:38 UTC (rev 37213)
+++ gnunet/src/util/test_crypto_rsa.c 2016-05-30 15:54:56 UTC (rev 37214)
@@ -18,6 +18,7 @@
* @file util/test_crypto_rsa.c
* @brief testcase for utility functions for RSA cryptography
* @author Sree Harsha Totakura <address@hidden>
+ * @author Jeffrey Burdges <address@hidden>
*/
#include "platform.h"
#include <gcrypt.h>
@@ -26,13 +27,6 @@
#define KEY_SIZE 1024
-gcry_error_t
-rsa_full_domain_hash (gcry_mpi_t *r,
- const struct GNUNET_HashCode *hash,
- const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
- size_t *rsize);
-
-
int
main (int argc,
char *argv[])
@@ -50,7 +44,6 @@
struct GNUNET_HashCode hash;
char *blind_buf;
size_t bsize;
- gcry_mpi_t v;
GNUNET_log_setup ("test-rsa", "WARNING", NULL);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
@@ -82,14 +75,6 @@
(void) fprintf (stderr, "The above warning is expected.\n");
GNUNET_free (enc);
- /* test full domain hash size */
- GNUNET_assert (0 == rsa_full_domain_hash (&v, &hash, pub, NULL));
- GNUNET_assert (gcry_mpi_get_nbits(v) < KEY_SIZE);
- gcry_mpi_clear_highbit (v, gcry_mpi_get_nbits(v)-1); /* clear the set high
bit */
- GNUNET_assert (gcry_mpi_get_nbits(v) > 3*KEY_SIZE/4);
- /* This test necessarily randomly fails with probability 2^(3 - KEY_SIZE/4)
*/
- gcry_mpi_release(v);
-
/* try ordinary sig first */
sig = GNUNET_CRYPTO_rsa_sign_fdh (priv,
&hash);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r37214 - in gnunet/src: include util,
gnunet <=