chiark / gitweb /
c9a2da604a459e62560bbde0ff824b93a378f293
[catacomb] / pub / rsa-gen.c
1 /* -*-c-*-
2  *
3  * RSA parameter generation
4  *
5  * (c) 1999 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
12  * Catacomb is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with Catacomb; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <mLib/dstr.h>
31
32 #include "grand.h"
33 #include "mp.h"
34 #include "mpint.h"
35 #include "pgen.h"
36 #include "rsa.h"
37 #include "strongprime.h"
38
39 /*----- Main code ---------------------------------------------------------*/
40
41 /* --- @rsa_gen@ --- *
42  *
43  * Arguments:   @rsa_priv *rp@ = pointer to block to be filled in
44  *              @unsigned nbits@ = required modulus size in bits
45  *              @grand *r@ = random number source
46  *              @unsigned n@ = number of attempts to make
47  *              @pgen_proc *event@ = event handler function
48  *              @void *ectx@ = argument for the event handler
49  *
50  * Returns:     Zero if all went well, nonzero otherwise.
51  *
52  * Use:         Constructs a pair of strong RSA primes and other useful RSA
53  *              parameters.  A small encryption exponent is chosen if
54  *              possible.
55  */
56
57 int rsa_gen(rsa_priv *rp, unsigned nbits, grand *r, unsigned n,
58             pgen_proc *event, void *ectx)
59 {
60   pgen_gcdstepctx g;
61   mp *phi = MP_NEW;
62
63   /* --- Bits of initialization --- */
64
65   rp->e = mp_fromulong(MP_NEW, 0x10001);
66   rp->d = MP_NEW;
67
68   /* --- Generate strong primes %$p$% and %$q$% --- *
69    *
70    * Constrain the GCD of @q@ to ensure that overly small private exponents
71    * are impossible.  Current results suggest that if %$d < n^{0.29}$% then
72    * it can be guessed fairly easily.  This implementation is rather more
73    * conservative about that sort of thing.
74    */
75
76 again:
77   if ((rp->p = strongprime("p", MP_NEWSEC, nbits/2, r, n, event, ectx)) == 0)
78     goto fail_p;
79
80   /* --- Do painful fiddling with GCD steppers --- *
81    *
82    * Also, arrange that %$q \ge \lceil 2^{N-1}/p \rceil$%, so that %$p q$%
83    * has the right length.
84    */
85
86   {
87     mp *q;
88     mp *t = MP_NEW, *u = MP_NEW;
89     rabin rb;
90
91     if ((q = strongprime_setup("q", MP_NEWSEC, &g.jp, nbits / 2,
92                                r, n, event, ectx)) == 0)
93       goto fail_q;
94     t = mp_lsl(t, MP_ONE, nbits - 1);
95     mp_div(&t, &u, t, rp->p);
96     if (!MP_ZEROP(u)) t = mp_add(t, t, MP_ONE);
97     if (MP_CMP(q, <, t)) q = mp_leastcongruent(q, t, q, g.jp.m);
98     mp_drop(t);
99
100     g.r = mp_lsr(MP_NEW, rp->p, 1);
101     g.g = MP_NEW;
102     g.max = MP_256;
103     q = pgen("q", q, q, event, ectx, n, pgen_gcdstep, &g,
104              rabin_iters(nbits/2), pgen_test, &rb);
105     pfilt_destroy(&g.jp);
106     mp_drop(g.r);
107     if (!q) {
108       mp_drop(g.g);
109       if (n)
110         goto fail_q;
111       mp_drop(rp->p);
112       goto again;
113     }
114     rp->q = q;
115   }
116
117   /* --- Ensure that %$p > q$% --- *
118    *
119    * Also ensure that %$p$% and %$q$% are sufficiently different to deter
120    * square-root-based factoring methods.
121    */
122
123   phi = mp_sub(phi, rp->p, rp->q);
124   if (MP_LEN(phi) * 4 < MP_LEN(rp->p) * 3 ||
125       MP_LEN(phi) * 4 < MP_LEN(rp->q) * 3) {
126     mp_drop(rp->p);
127     mp_drop(g.g);
128     if (n)
129       goto fail_q;
130     mp_drop(rp->q);
131     goto again;
132   }
133
134   if (MP_NEGP(phi)) {
135     mp *z = rp->p;
136     rp->p = rp->q;
137     rp->q = z;
138   }
139
140   /* --- Work out the modulus and the CRT coefficient --- */
141
142   rp->n = mp_mul(MP_NEW, rp->p, rp->q);
143   rp->q_inv = mp_modinv(MP_NEW, rp->q, rp->p);
144
145   /* --- Work out %$\varphi(n) = (p - 1)(q - 1)$% --- *
146    *
147    * Save on further multiplications by noting that %$n = pq$% is known and
148    * that %$(p - 1)(q - 1) = pq - p - q + 1$%.  To minimize the size of @d@
149    * (useful for performance reasons, although not very because an overly
150    * small @d@ will be rejected for security reasons) this is then divided by
151    * %$\gcd(p - 1, q - 1)$%.
152    */
153
154   phi = mp_sub(phi, rp->n, rp->p);
155   phi = mp_sub(phi, phi, rp->q);
156   phi = mp_add(phi, phi, MP_ONE);
157   phi = mp_lsr(phi, phi, 1);
158   mp_div(&phi, 0, phi, g.g);
159
160   /* --- Decide on a public exponent --- *
161    *
162    * Simultaneously compute the private exponent.
163    */
164
165   mp_gcd(&g.g, 0, &rp->d, phi, rp->e);
166   if (!MP_EQ(g.g, MP_ONE) && MP_LEN(rp->d) * 4 > MP_LEN(rp->n) * 3)
167     goto fail_e;
168
169   /* --- Work out exponent residues --- */
170
171   rp->dp = MP_NEW; phi = mp_sub(phi, rp->p, MP_ONE);
172   mp_div(0, &rp->dp, rp->d, phi);
173
174   rp->dq = MP_NEW; phi = mp_sub(phi, rp->q, MP_ONE);
175   mp_div(0, &rp->dq, rp->d, phi);
176
177   /* --- Done --- */
178
179   mp_drop(phi);
180   mp_drop(g.g);
181   return (0);
182
183   /* --- Tidy up when something goes wrong --- */
184
185 fail_e:
186   mp_drop(g.g);
187   mp_drop(phi);
188   mp_drop(rp->n);
189   mp_drop(rp->q_inv);
190   mp_drop(rp->q);
191 fail_q:
192   mp_drop(rp->p);
193 fail_p:
194   mp_drop(rp->e);
195   if (rp->d)
196     mp_drop(rp->d);
197   return (-1);
198 }
199
200 /*----- That's all, folks -------------------------------------------------*/