File: rfc6979.c

package info (click to toggle)
putty 0.78-2%2Bdeb12u2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 13,964 kB
  • sloc: ansic: 137,777; python: 7,775; perl: 1,798; makefile: 133; sh: 111
file content (359 lines) | stat: -rw-r--r-- 13,355 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
/*
 * Code to generate 'nonce' values for DSA signature algorithms, in a
 * deterministic way.
 */

#include "ssh.h"
#include "mpint.h"
#include "misc.h"

/*
 * All DSA-type signature systems depend on a nonce - a random number
 * generated during the signing operation.
 *
 * This nonce is a weak point of DSA and needs careful protection,
 * for multiple reasons:
 *
 *  1. If an attacker in possession of your public key and a single
 *     signature can find out or guess the nonce you used in that
 *     signature, they can immediately recover your _private key_.
 *
 *  2. If you reuse the same nonce in two different signatures, this
 *     will be instantly obvious to the attacker (one of the two
 *     values making up the signature will match), and again, they can
 *     immediately recover the private key as soon as they notice this.
 *
 *  3. In at least one system, information about your private key is
 *     leaked merely by generating nonces with a significant bias.
 *
 * Attacks #1 and #2 work across all of integer DSA, NIST-style ECDSA,
 * and EdDSA. The details vary, but the headline effects are the same.
 *
 * So we must be very careful with our nonces. They must be generated
 * with uniform distribution, but also, they must avoid depending on
 * any random number generator that has the slightest doubt about its
 * reliability.
 *
 * In particular, PuTTY's policy is that for this purpose we don't
 * _even_ trust the PRNG we use for other cryptography. This is mostly
 * a concern because of Windows, where system entropy sources are
 * limited and we have doubts about their trustworthiness
 * - even CryptGenRandom. PuTTY compensates as best it can with its
 * own ongoing entropy collection, and we trust that for session keys,
 * but revealing the private key that goes with a long-term public key
 * is a far worse outcome than revealing one SSH session key, and for
 * keeping your private key safe, we don't think the available Windows
 * entropy gives us enough confidence.
 *
 * A common strategy these days (although <hipster>PuTTY was doing it
 * before it was cool</hipster>) is to avoid using a PRNG based on
 * system entropy at all. Instead, you use a deterministic PRNG that
 * starts from a fixed input seed, and in that input seed you include
 * the message to be signed and the _private key_.
 *
 * Including the private key in the seed is counterintuitive, but does
 * actually make sense. A deterministic nonce generation strategy must
 * use _some_ piece of input that the attacker doesn't have, or else
 * they'd be able to repeat the entire computation and construct the
 * same nonce you did. And the one thing they don't know is the
 * private key! So we include that in the seed data (under enough
 * layers of overcautious hashing to protect it against exposure), and
 * then they _can't_ repeat the same construction. Moreover, if they
 * _could_, they'd already know the private key, so they wouldn't need
 * to perform an attack of this kind at all!
 *
 * (This trick doesn't, _per se_, protect against reuse of nonces.
 * That is left to chance, which is enough, because the space of
 * nonces is large enough to make it adequately unlikely. But it
 * avoids escalating the reuse risk due to inadequate entropy.)
 *
 * For integer DSA and ECDSA, the system we use for deterministic
 * generation of k is exactly the one specified in RFC 6979. We
 * switched to this from the old system that PuTTY used to use before
 * that RFC came out. The old system had a critical bug: it did not
 * always generate _enough_ data to get uniform distribution, because
 * its output was a single SHA-512 hash. We could have fixed that
 * minimally, by concatenating multiple hashes, but it seemed more
 * sensible to switch to a system that comes with test vectors.
 *
 * One downside of RFC 6979 is that it's based on rejection sampling
 * (that is, you generate a random number and keep retrying until it's
 * in range). This makes it play badly with our side-channel test
 * system, which wants every execution trace of a supposedly
 * constant-time operation to be the same. To work around this
 * awkwardness, we break up the algorithm further, into a setup phase
 * and an 'attempt to generate an output' phase, each of which is
 * individually constant-time.
 */

struct RFC6979 {
    /*
     * Size of the cyclic group over which we're doing DSA.
     * Equivalently, the multiplicative order of g (for integer DSA)
     * or the curve's base point (for ECDSA). For integer DSA this is
     * also the same thing as the small prime q from the key
     * parameters.
     *
     * This pointer is not owned. Freeing this structure will not free
     * it, and freeing the pointed-to integer before freeing this
     * structure will make this structure dangerous to use.
     */
    mp_int *q;

    /*
     * The private key integer, which is always the discrete log of
     * the public key with respect to the group generator.
     *
     * This pointer is not owned. Freeing this structure will not free
     * it, and freeing the pointed-to integer before freeing this
     * structure will make this structure dangerous to use.
     */
    mp_int *x;

    /*
     * Cached values derived from q: its length in bits, and in bytes.
     */
    size_t qbits, qbytes;

    /*
     * Reusable hash and MAC objects.
     */
    ssh_hash *hash;
    ssh2_mac *mac;

    /*
     * Cached value: the output length of the hash.
     */
    size_t hlen;

    /*
     * The byte string V used in the algorithm.
     */
    unsigned char V[MAX_HASH_LEN];

    /*
     * The string T to use during each attempt, and how many
     * hash-sized blocks to fill it with.
     */
    size_t T_nblocks;
    unsigned char *T;
};

static mp_int *bits2int(ptrlen b, RFC6979 *s)
{
    if (b.len > s->qbytes)
        b.len = s->qbytes;
    mp_int *x = mp_from_bytes_be(b);

    /*
     * Rationale for using mp_rshift_fixed_into and not
     * mp_rshift_safe_into: the shift count is derived from the
     * difference between the length of the modulus q, and the length
     * of the input bit string, i.e. between the _sizes_ of things
     * involved in the protocol. But the sizes aren't secret. Only the
     * actual values of integers and bit strings of those sizes are
     * secret. So it's OK for the shift count to be known to an
     * attacker - they'd know it anyway just from which DSA algorithm
     * we were using.
     */
    if (b.len * 8 > s->qbits)
        mp_rshift_fixed_into(x, x, b.len * 8 - s->qbits);

    return x;
}

static void BinarySink_put_int2octets(BinarySink *bs, mp_int *x, RFC6979 *s)
{
    mp_int *x_mod_q = mp_mod(x, s->q);
    for (size_t i = s->qbytes; i-- > 0 ;)
        put_byte(bs, mp_get_byte(x_mod_q, i));
    mp_free(x_mod_q);
}

static void BinarySink_put_bits2octets(BinarySink *bs, ptrlen b, RFC6979 *s)
{
    mp_int *x = bits2int(b, s);
    BinarySink_put_int2octets(bs, x, s);
    mp_free(x);
}

#define put_int2octets(bs, x, s) \
    BinarySink_put_int2octets(BinarySink_UPCAST(bs), x, s)
#define put_bits2octets(bs, b, s) \
    BinarySink_put_bits2octets(BinarySink_UPCAST(bs), b, s)

RFC6979 *rfc6979_new(const ssh_hashalg *hashalg, mp_int *q, mp_int *x)
{
    /* Make the state structure. */
    RFC6979 *s = snew(RFC6979);
    s->q = q;
    s->x = x;
    s->qbits = mp_get_nbits(q);
    s->qbytes = (s->qbits + 7) >> 3;
    s->hash = ssh_hash_new(hashalg);
    s->mac = hmac_new_from_hash(hashalg);
    s->hlen = hashalg->hlen;

    /* In each attempt, we concatenate enough hash blocks to be
     * greater than qbits in size. */
    size_t hbits = 8 * s->hlen;
    s->T_nblocks = (s->qbits + hbits - 1) / hbits;
    s->T = snewn(s->T_nblocks * s->hlen, unsigned char);

    return s;
}

void rfc6979_setup(RFC6979 *s, ptrlen message)
{
    unsigned char h1[MAX_HASH_LEN];
    unsigned char K[MAX_HASH_LEN];

    /* 3.2 (a): hash the message to get h1. */
    ssh_hash_reset(s->hash);
    put_datapl(s->hash, message);
    ssh_hash_digest(s->hash, h1);

    /* 3.2 (b): set V to a sequence of 0x01 bytes the same size as the
     * hash function's output. */
    memset(s->V, 1, s->hlen);

    /* 3.2 (c): set the initial HMAC key K to all zeroes, again the
     * same size as the hash function's output. */
    memset(K, 0, s->hlen);
    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));

    /* 3.2 (d): compute the MAC of V, the private key, and h1, with
     * key K, making a new key to replace K. */
    ssh2_mac_start(s->mac);
    put_data(s->mac, s->V, s->hlen);
    put_byte(s->mac, 0);
    put_int2octets(s->mac, s->x, s);
    put_bits2octets(s->mac, make_ptrlen(h1, s->hlen), s);
    ssh2_mac_genresult(s->mac, K);
    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));

    /* 3.2 (e): replace V with its HMAC using the new K. */
    ssh2_mac_start(s->mac);
    put_data(s->mac, s->V, s->hlen);
    ssh2_mac_genresult(s->mac, s->V);

    /* 3.2 (f): repeat step (d), only using the new K in place of the
     * initial all-zeroes one, and with the extra byte in the middle
     * of the MAC preimage being 1 rather than 0. */
    ssh2_mac_start(s->mac);
    put_data(s->mac, s->V, s->hlen);
    put_byte(s->mac, 1);
    put_int2octets(s->mac, s->x, s);
    put_bits2octets(s->mac, make_ptrlen(h1, s->hlen), s);
    ssh2_mac_genresult(s->mac, K);
    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));

    /* 3.2 (g): repeat step (e), using the again-replaced K. */
    ssh2_mac_start(s->mac);
    put_data(s->mac, s->V, s->hlen);
    ssh2_mac_genresult(s->mac, s->V);

    smemclr(h1, sizeof(h1));
    smemclr(K, sizeof(K));
}

RFC6979Result rfc6979_attempt(RFC6979 *s)
{
    RFC6979Result result;

    /* 3.2 (h) 1: set T to the empty string */
    /* 3.2 (h) 2: make lots of output by concatenating MACs of V */
    for (size_t i = 0; i < s->T_nblocks; i++) {
        ssh2_mac_start(s->mac);
        put_data(s->mac, s->V, s->hlen);
        ssh2_mac_genresult(s->mac, s->V);
        memcpy(s->T + i * s->hlen, s->V, s->hlen);
    }

    /* 3.2 (h) 3: if we have a number in [1, q-1], return it ... */
    result.k = bits2int(make_ptrlen(s->T, s->T_nblocks * s->hlen), s);
    result.ok = mp_hs_integer(result.k, 1) & ~mp_cmp_hs(result.k, s->q);

    /*
     * Perturb K and regenerate V ready for the next attempt.
     *
     * We do this unconditionally, whether or not the k we just
     * generated is acceptable. The time cost isn't large compared to
     * the public-key operation we're going to do next (not to mention
     * the larger number of these same operations we've already done),
     * and it makes side-channel testing easier if this function is
     * constant-time from beginning to end.
     *
     * In other rejection-sampling situations, particularly prime
     * generation, we're not this careful: it's enough to ensure that
     * _successful_ attempts run in constant time, Failures can do
     * whatever they like, on the theory that the only information
     * they _have_ to potentially expose via side channels is
     * information that was subsequently thrown away without being
     * used for anything important. (Hence, for example, it's fine to
     * have multiple different early-exit paths for failures you
     * detect at different times.)
     *
     * But here, the situation is different. Prime generation attempts
     * are independent of each other. These are not. All our
     * iterations round this loop use the _same_ secret data set up by
     * rfc6979_new(), and also, the perturbation step we're about to
     * compute will be used by the next iteration if there is one. So
     * it's absolutely _not_ true that a failed iteration deals
     * exclusively with data that won't contribute to the eventual
     * output. Hence, we have to be careful about the failures as well
     * as the successes.
     *
     * (Even so, it would be OK to make successes and failures take
     * different amounts of time, as long as each of those amounts was
     * consistent. But it's easier for testing to make them the same.)
     */
    ssh2_mac_start(s->mac);
    put_data(s->mac, s->V, s->hlen);
    put_byte(s->mac, 0);
    unsigned char K[MAX_HASH_LEN];
    ssh2_mac_genresult(s->mac, K);
    ssh2_mac_setkey(s->mac, make_ptrlen(K, s->hlen));
    smemclr(K, sizeof(K));

    ssh2_mac_start(s->mac);
    put_data(s->mac, s->V, s->hlen);
    ssh2_mac_genresult(s->mac, s->V);

    return result;
}

void rfc6979_free(RFC6979 *s)
{
    /* We don't free s->q or s->x: our caller still owns those. */

    ssh_hash_free(s->hash);
    ssh2_mac_free(s->mac);
    smemclr(s->T, s->T_nblocks * s->hlen);
    sfree(s->T);

    /* Clear the whole structure before freeing. Most fields aren't
     * sensitive (pointers or well-known length values), but V is, and
     * it's easier to clear the whole lot than fiddle about
     * identifying the sensitive fields. */
    smemclr(s, sizeof(*s));

    sfree(s);
}

mp_int *rfc6979(
    const ssh_hashalg *hashalg, mp_int *q, mp_int *x, ptrlen message)
{
    RFC6979 *s = rfc6979_new(hashalg, q, x);
    rfc6979_setup(s, message);
    RFC6979Result result;
    while (true) {
        result = rfc6979_attempt(s);
        if (result.ok)
            break;
        else
            mp_free(result.k);
    }
    rfc6979_free(s);
    return result.k;
}