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