Welcome to mirror list, hosted at ThFree Co, Russian Federation.

rsa.c « keygen - github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b9676e7ac24b64422cd684ac06ad51b4dbfdb81f (plain)
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
/*
 * RSA key generation.
 */

#include <assert.h>

#include "ssh.h"
#include "sshkeygen.h"
#include "mpint.h"

#define RSA_EXPONENT 65537

#define NFIRSTBITS 13
static void invent_firstbits(unsigned *one, unsigned *two,
                             unsigned min_separation);

typedef struct RSAPrimeDetails RSAPrimeDetails;
struct RSAPrimeDetails {
    bool strong;
    int bits, bitsm1m1, bitsm1, bitsp1;
    unsigned firstbits;
    ProgressPhase phase_main, phase_m1m1, phase_m1, phase_p1;
};

#define STRONG_MARGIN (20 + NFIRSTBITS)

static RSAPrimeDetails setup_rsa_prime(
    int bits, bool strong, PrimeGenerationContext *pgc, ProgressReceiver *prog)
{
    RSAPrimeDetails pd;
    pd.bits = bits;
    if (strong) {
        pd.bitsm1 = (bits - STRONG_MARGIN) / 2;
        pd.bitsp1 = (bits - STRONG_MARGIN) - pd.bitsm1;
        pd.bitsm1m1 = (pd.bitsm1 - STRONG_MARGIN) / 2;
        if (pd.bitsm1m1 < STRONG_MARGIN) {
            /* Absurdly small prime, but we should at least not crash. */
            strong = false;
        }
    }
    pd.strong = strong;

    if (pd.strong) {
        pd.phase_m1m1 = primegen_add_progress_phase(pgc, prog, pd.bitsm1m1);
        pd.phase_m1 = primegen_add_progress_phase(pgc, prog, pd.bitsm1);
        pd.phase_p1 = primegen_add_progress_phase(pgc, prog, pd.bitsp1);
    }
    pd.phase_main = primegen_add_progress_phase(pgc, prog, pd.bits);

    return pd;
}

static mp_int *generate_rsa_prime(
    RSAPrimeDetails pd, PrimeGenerationContext *pgc, ProgressReceiver *prog)
{
    mp_int *m1m1 = NULL, *m1 = NULL, *p1 = NULL, *p = NULL;
    PrimeCandidateSource *pcs;

    if (pd.strong) {
        progress_start_phase(prog, pd.phase_m1m1);
        pcs = pcs_new_with_firstbits(pd.bitsm1m1, pd.firstbits, NFIRSTBITS);
        m1m1 = primegen_generate(pgc, pcs, prog);
        progress_report_phase_complete(prog);

        progress_start_phase(prog, pd.phase_m1);
        pcs = pcs_new_with_firstbits(pd.bitsm1, pd.firstbits, NFIRSTBITS);
        pcs_require_residue_1_mod_prime(pcs, m1m1);
        m1 = primegen_generate(pgc, pcs, prog);
        progress_report_phase_complete(prog);

        progress_start_phase(prog, pd.phase_p1);
        pcs = pcs_new_with_firstbits(pd.bitsp1, pd.firstbits, NFIRSTBITS);
        p1 = primegen_generate(pgc, pcs, prog);
        progress_report_phase_complete(prog);
    }

    progress_start_phase(prog, pd.phase_main);
    pcs = pcs_new_with_firstbits(pd.bits, pd.firstbits, NFIRSTBITS);
    pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1);
    if (pd.strong) {
        pcs_require_residue_1_mod_prime(pcs, m1);
        mp_int *p1_minus_1 = mp_copy(p1);
        mp_sub_integer_into(p1_minus_1, p1, 1);
        pcs_require_residue(pcs, p1, p1_minus_1);
        mp_free(p1_minus_1);
    }
    p = primegen_generate(pgc, pcs, prog);
    progress_report_phase_complete(prog);

    if (m1m1)
        mp_free(m1m1);
    if (m1)
        mp_free(m1);
    if (p1)
        mp_free(p1);

    return p;
}

int rsa_generate(RSAKey *key, int bits, bool strong,
                 PrimeGenerationContext *pgc, ProgressReceiver *prog)
{
    key->sshk.vt = &ssh_rsa;

    /*
     * We don't generate e; we just use a standard one always.
     */
    mp_int *exponent = mp_from_integer(RSA_EXPONENT);

    /*
     * Generate p and q: primes with combined length `bits', not
     * congruent to 1 modulo e. (Strictly speaking, we wanted (p-1)
     * and e to be coprime, and (q-1) and e to be coprime, but in
     * general that's slightly more fiddly to arrange. By choosing
     * a prime e, we can simplify the criterion.)
     *
     * We give a min_separation of 2 to invent_firstbits(), ensuring
     * that the two primes won't be very close to each other. (The
     * chance of them being _dangerously_ close is negligible - even
     * more so than an attacker guessing a whole 256-bit session key -
     * but it doesn't cost much to make sure.)
     */
    int qbits = bits / 2;
    int pbits = bits - qbits;
    assert(pbits >= qbits);

    RSAPrimeDetails pd = setup_rsa_prime(pbits, strong, pgc, prog);
    RSAPrimeDetails qd = setup_rsa_prime(qbits, strong, pgc, prog);
    progress_ready(prog);

    invent_firstbits(&pd.firstbits, &qd.firstbits, 2);

    mp_int *p = generate_rsa_prime(pd, pgc, prog);
    mp_int *q = generate_rsa_prime(qd, pgc, prog);

    /*
     * Ensure p > q, by swapping them if not.
     *
     * We only need to do this if the two primes were generated with
     * the same number of bits (i.e. if the requested key size is
     * even) - otherwise it's already guaranteed!
     */
    if (pbits == qbits) {
        mp_cond_swap(p, q, mp_cmp_hs(q, p));
    } else {
        assert(mp_cmp_hs(p, q));
    }

    /*
     * Now we have p, q and e. All we need to do now is work out
     * the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1),
     * and (q^-1 mod p).
     */
    mp_int *modulus = mp_mul(p, q);
    mp_int *pm1 = mp_copy(p);
    mp_sub_integer_into(pm1, pm1, 1);
    mp_int *qm1 = mp_copy(q);
    mp_sub_integer_into(qm1, qm1, 1);
    mp_int *phi_n = mp_mul(pm1, qm1);
    mp_free(pm1);
    mp_free(qm1);
    mp_int *private_exponent = mp_invert(exponent, phi_n);
    mp_free(phi_n);
    mp_int *iqmp = mp_invert(q, p);

    /*
     * Populate the returned structure.
     */
    key->modulus = modulus;
    key->exponent = exponent;
    key->private_exponent = private_exponent;
    key->p = p;
    key->q = q;
    key->iqmp = iqmp;

    key->bits = mp_get_nbits(modulus);
    key->bytes = (key->bits + 7) / 8;

    return 1;
}

/*
 * Invent a pair of values suitable for use as the 'firstbits' values
 * for the two RSA primes, such that their product is at least 2, and
 * such that their difference is also at least min_separation.
 *
 * This is used for generating RSA keys which have exactly the
 * specified number of bits rather than one fewer - if you generate an
 * a-bit and a b-bit number completely at random and multiply them
 * together, you could end up with either an (ab-1)-bit number or an
 * (ab)-bit number. The former happens log(2)*2-1 of the time (about
 * 39%) and, though actually harmless, every time it occurs it has a
 * non-zero probability of sparking a user email along the lines of
 * 'Hey, I asked PuTTYgen for a 2048-bit key and I only got 2047 bits!
 * Bug!'
 */
static inline unsigned firstbits_b_min(
    unsigned a, unsigned lo, unsigned hi, unsigned min_separation)
{
    /* To get a large enough product, b must be at least this much */
    unsigned b_min = (2*lo*lo + a - 1) / a;
    /* Now enforce a<b, optionally with minimum separation */
    if (b_min < a + min_separation)
        b_min = a + min_separation;
    /* And cap at the upper limit */
    if (b_min > hi)
        b_min = hi;
    return b_min;
}

static void invent_firstbits(unsigned *one, unsigned *two,
                             unsigned min_separation)
{
    /*
     * We'll pick 12 initial bits (number selected at random) for each
     * prime, not counting the leading 1. So we want to return two
     * values in the range [2^12,2^13) whose product is at least 2^25.
     *
     * Strategy: count up all the viable pairs, then select a random
     * number in that range and use it to pick a pair.
     *
     * To keep things simple, we'll ensure a < b, and randomly swap
     * them at the end.
     */
    const unsigned lo = 1<<12, hi = 1<<13, minproduct = 2*lo*lo;
    unsigned a, b;

    /*
     * Count up the number of prefixes of b that would be valid for
     * each prefix of a.
     */
    mp_int *total = mp_new(32);
    for (a = lo; a < hi; a++) {
        unsigned b_min = firstbits_b_min(a, lo, hi, min_separation);
        mp_add_integer_into(total, total, hi - b_min);
    }

    /*
     * Make up a random number in the range [0,2*total).
     */
    mp_int *mlo = mp_from_integer(0), *mhi = mp_new(32);
    mp_lshift_fixed_into(mhi, total, 1);
    mp_int *randval = mp_random_in_range(mlo, mhi);
    mp_free(mlo);
    mp_free(mhi);

    /*
     * Use the low bit of randval as our swap indicator, leaving the
     * rest of it in the range [0,total).
     */
    unsigned swap = mp_get_bit(randval, 0);
    mp_rshift_fixed_into(randval, randval, 1);

    /*
     * Now do the same counting loop again to make the actual choice.
     */
    a = b = 0;
    for (unsigned a_candidate = lo; a_candidate < hi; a_candidate++) {
        unsigned b_min = firstbits_b_min(a_candidate, lo, hi, min_separation);
        unsigned limit = hi - b_min;

        unsigned b_candidate = b_min + mp_get_integer(randval);
        unsigned use_it = 1 ^ mp_hs_integer(randval, limit);
        a ^= (a ^ a_candidate) & -use_it;
        b ^= (b ^ b_candidate) & -use_it;

        mp_sub_integer_into(randval, randval, limit);
    }

    mp_free(randval);
    mp_free(total);

    /*
     * Check everything came out right.
     */
    assert(lo <= a);
    assert(a < hi);
    assert(lo <= b);
    assert(b < hi);
    assert(a * b >= minproduct);
    assert(b >= a + min_separation);

    /*
     * Last-minute optional swap of a and b.
     */
    unsigned diff = (a ^ b) & (-swap);
    a ^= diff;
    b ^= diff;

    *one = a;
    *two = b;
}