--- /dev/null
+/* -*-c-*-
+ *
+ * RSA parameter generation
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/dstr.h>
+
+#include "grand.h"
+#include "mp.h"
+#include "mpint.h"
+#include "pgen.h"
+#include "rsa.h"
+#include "strongprime.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @rsa_gen@ --- *
+ *
+ * Arguments: @rsa_priv *rp@ = pointer to block to be filled in
+ * @unsigned nbits@ = required modulus size in bits
+ * @grand *r@ = random number source
+ * @unsigned n@ = number of attempts to make
+ * @pgen_proc *event@ = event handler function
+ * @void *ectx@ = argument for the event handler
+ *
+ * Returns: Zero if all went well, nonzero otherwise.
+ *
+ * Use: Constructs a pair of strong RSA primes and other useful RSA
+ * parameters. A small encryption exponent is chosen if
+ * possible.
+ */
+
+int rsa_gen(rsa_priv *rp, unsigned nbits, grand *r, unsigned n,
+ pgen_proc *event, void *ectx)
+{
+ pgen_gcdstepctx g;
+ mp *phi = MP_NEW;
+
+ /* --- Bits of initialization --- */
+
+ rp->e = mp_fromulong(MP_NEW, 0x10001);
+ rp->d = MP_NEW;
+
+ /* --- Generate strong primes %$p$% and %$q$% --- *
+ *
+ * Constrain the GCD of @q@ to ensure that overly small private exponents
+ * are impossible. Current results suggest that if %$d < n^{0.29}$% then
+ * it can be guessed fairly easily. This implementation is rather more
+ * conservative about that sort of thing.
+ */
+
+again:
+ if ((rp->p = strongprime("p", MP_NEWSEC, nbits/2, r, n, event, ectx)) == 0)
+ goto fail_p;
+
+ /* --- Do painful fiddling with GCD steppers --- */
+
+ {
+ mp *q;
+ rabin rb;
+
+ if ((q = strongprime_setup("q", MP_NEWSEC, &g.jp, nbits / 2,
+ r, n, event, ectx)) == 0)
+ goto fail_q;
+ g.r = mp_lsr(MP_NEW, rp->p, 1);
+ g.g = MP_NEW;
+ g.max = MP_256;
+ q = pgen("q", q, q, event, ectx, n, pgen_gcdstep, &g,
+ rabin_iters(nbits/2), pgen_test, &rb);
+ pfilt_destroy(&g.jp);
+ mp_drop(g.r);
+ if (!q) {
+ mp_drop(g.g);
+ if (n)
+ goto fail_q;
+ mp_drop(rp->p);
+ goto again;
+ }
+ rp->q = q;
+ }
+
+ /* --- Ensure that %$p > q$% --- *
+ *
+ * Also ensure that %$p$% and %$q$% are sufficiently different to deter
+ * square-root-based factoring methods.
+ */
+
+ phi = mp_sub(phi, rp->p, rp->q);
+ if (MP_LEN(phi) * 4 < MP_LEN(rp->p) * 3 ||
+ MP_LEN(phi) * 4 < MP_LEN(rp->q) * 3) {
+ mp_drop(rp->p);
+ mp_drop(g.g);
+ if (n)
+ goto fail_q;
+ mp_drop(rp->q);
+ goto again;
+ }
+
+ if (MP_NEGP(phi)) {
+ mp *z = rp->p;
+ rp->p = rp->q;
+ rp->q = z;
+ }
+
+ /* --- Work out the modulus and the CRT coefficient --- */
+
+ rp->n = mp_mul(MP_NEW, rp->p, rp->q);
+ rp->q_inv = mp_modinv(MP_NEW, rp->q, rp->p);
+
+ /* --- Work out %$\varphi(n) = (p - 1)(q - 1)$% --- *
+ *
+ * Save on further multiplications by noting that %$n = pq$% is known and
+ * that %$(p - 1)(q - 1) = pq - p - q + 1$%. To minimize the size of @d@
+ * (useful for performance reasons, although not very because an overly
+ * small @d@ will be rejected for security reasons) this is then divided by
+ * %$\gcd(p - 1, q - 1)$%.
+ */
+
+ phi = mp_sub(phi, rp->n, rp->p);
+ phi = mp_sub(phi, phi, rp->q);
+ phi = mp_add(phi, phi, MP_ONE);
+ phi = mp_lsr(phi, phi, 1);
+ mp_div(&phi, 0, phi, g.g);
+
+ /* --- Decide on a public exponent --- *
+ *
+ * Simultaneously compute the private exponent.
+ */
+
+ mp_gcd(&g.g, 0, &rp->d, phi, rp->e);
+ if (!MP_EQ(g.g, MP_ONE) && MP_LEN(rp->d) * 4 > MP_LEN(rp->n) * 3)
+ goto fail_e;
+
+ /* --- Work out exponent residues --- */
+
+ rp->dp = MP_NEW; phi = mp_sub(phi, rp->p, MP_ONE);
+ mp_div(0, &rp->dp, rp->d, phi);
+
+ rp->dq = MP_NEW; phi = mp_sub(phi, rp->q, MP_ONE);
+ mp_div(0, &rp->dq, rp->d, phi);
+
+ /* --- Done --- */
+
+ mp_drop(phi);
+ mp_drop(g.g);
+ return (0);
+
+ /* --- Tidy up when something goes wrong --- */
+
+fail_e:
+ mp_drop(g.g);
+ mp_drop(phi);
+ mp_drop(rp->n);
+ mp_drop(rp->q_inv);
+ mp_drop(rp->q);
+fail_q:
+ mp_drop(rp->p);
+fail_p:
+ mp_drop(rp->e);
+ if (rp->d)
+ mp_drop(rp->d);
+ return (-1);
+}
+
+/*----- That's all, folks -------------------------------------------------*/