diff options
author | Jeff Burdges <burdges@gnunet.org> | 2016-05-30 15:54:56 +0000 |
---|---|---|
committer | Jeff Burdges <burdges@gnunet.org> | 2016-05-30 15:54:56 +0000 |
commit | afb40a6d7a49d2608b709d6e8863675a6a301c99 (patch) | |
tree | 26c97c0217311d2313ecac5daa853d428ecf9025 /src/util/crypto_kdf.c | |
parent | 295a7ab56564369098a12e2cc39fac0d5225c465 (diff) | |
download | gnunet-afb40a6d7a49d2608b709d6e8863675a6a301c99.tar.gz gnunet-afb40a6d7a49d2608b709d6e8863675a6a301c99.zip |
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.
Diffstat (limited to 'src/util/crypto_kdf.c')
-rw-r--r-- | src/util/crypto_kdf.c | 68 |
1 files changed, 64 insertions, 4 deletions
diff --git a/src/util/crypto_kdf.c b/src/util/crypto_kdf.c index 242fbf296..056fda529 100644 --- a/src/util/crypto_kdf.c +++ b/src/util/crypto_kdf.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * @file src/util/crypto_kdf.c | 22 | * @file src/util/crypto_kdf.c |
23 | * @brief Key derivation | 23 | * @brief Key derivation |
24 | * @author Nils Durner | 24 | * @author Nils Durner |
25 | * @author Jeffrey Burdges <burdges@gnunet.org> | ||
25 | */ | 26 | */ |
26 | 27 | ||
27 | #include <gcrypt.h> | 28 | #include <gcrypt.h> |
@@ -43,8 +44,9 @@ | |||
43 | * @return #GNUNET_YES on success | 44 | * @return #GNUNET_YES on success |
44 | */ | 45 | */ |
45 | int | 46 | int |
46 | GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, const void *xts, | 47 | GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, |
47 | size_t xts_len, const void *skm, size_t skm_len, | 48 | const void *xts, size_t xts_len, |
49 | const void *skm, size_t skm_len, | ||
48 | va_list argp) | 50 | va_list argp) |
49 | { | 51 | { |
50 | /* | 52 | /* |
@@ -76,8 +78,9 @@ GNUNET_CRYPTO_kdf_v (void *result, size_t out_len, const void *xts, | |||
76 | * @return #GNUNET_YES on success | 78 | * @return #GNUNET_YES on success |
77 | */ | 79 | */ |
78 | int | 80 | int |
79 | GNUNET_CRYPTO_kdf (void *result, size_t out_len, const void *xts, | 81 | GNUNET_CRYPTO_kdf (void *result, size_t out_len, |
80 | size_t xts_len, const void *skm, size_t skm_len, ...) | 82 | const void *xts, size_t xts_len, |
83 | const void *skm, size_t skm_len, ...) | ||
81 | { | 84 | { |
82 | va_list argp; | 85 | va_list argp; |
83 | int ret; | 86 | int ret; |
@@ -88,3 +91,60 @@ GNUNET_CRYPTO_kdf (void *result, size_t out_len, const void *xts, | |||
88 | 91 | ||
89 | return ret; | 92 | return ret; |
90 | } | 93 | } |
94 | |||
95 | |||
96 | /** | ||
97 | * Deterministically generate a pseudo-random number uniformly from the | ||
98 | * integers modulo a libgcrypt mpi. | ||
99 | * | ||
100 | * @param[out] r MPI value set to the FDH | ||
101 | * @param n MPI to work modulo | ||
102 | * @param xts salt | ||
103 | * @param xts_len length of @a xts | ||
104 | * @param skm source key material | ||
105 | * @param skm_len length of @a skm | ||
106 | * @param ctx context string | ||
107 | */ | ||
108 | void | ||
109 | GNUNET_CRYPTO_kdf_mod_mpi (gcry_mpi_t *r, | ||
110 | gcry_mpi_t n, | ||
111 | const void *xts, size_t xts_len, | ||
112 | const void *skm, size_t skm_len, | ||
113 | const char *ctx) | ||
114 | { | ||
115 | gcry_error_t rc; | ||
116 | unsigned int nbits; | ||
117 | size_t rsize; | ||
118 | unsigned int ctr; | ||
119 | |||
120 | nbits = gcry_mpi_get_nbits (n); | ||
121 | /* GNUNET_assert (nbits > 512); */ | ||
122 | |||
123 | ctr = 0; | ||
124 | do { | ||
125 | /* Ain't clear if n is always divisible by 8 */ | ||
126 | uint8_t buf[ (nbits-1)/8 + 1 ]; | ||
127 | |||
128 | rc = GNUNET_CRYPTO_kdf (buf, | ||
129 | sizeof (buf), | ||
130 | xts, xts_len, | ||
131 | skm, skm_len, | ||
132 | ctx, strlen(ctx), | ||
133 | &ctr, sizeof(ctr), | ||
134 | NULL, 0); | ||
135 | GNUNET_assert (GNUNET_YES == rc); | ||
136 | |||
137 | rc = gcry_mpi_scan (r, | ||
138 | GCRYMPI_FMT_USG, | ||
139 | (const unsigned char *) buf, | ||
140 | sizeof (buf), | ||
141 | &rsize); | ||
142 | GNUNET_assert (0 == rc); /* Allocation erro? */ | ||
143 | |||
144 | gcry_mpi_clear_highbit (*r, nbits); | ||
145 | GNUNET_assert( 0 == gcry_mpi_test_bit (*r, nbits) ); | ||
146 | ++ctr; | ||
147 | } while ( 0 <= gcry_mpi_cmp(*r,n) ); | ||
148 | } | ||
149 | |||
150 | |||