progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / pub / rsa-gen.c
index 3b5334b..b381bcd 100644 (file)
 
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @rsa_gen@ --- *
+/* --- @rsa_gen@, @rsa_gen_e --- *
  *
  * Arguments:  @rsa_priv *rp@ = pointer to block to be filled in
  *             @unsigned nbits@ = required modulus size in bits
+ *             @mp *e@ = public exponent
  *             @grand *r@ = random number source
  *             @unsigned n@ = number of attempts to make
  *             @pgen_proc *event@ = event handler function
  *             possible.
  */
 
-int rsa_gen(rsa_priv *rp, unsigned nbits, grand *r, unsigned n,
-           pgen_proc *event, void *ectx)
+static int genprime(mp **pp, mp **dd, const char *name,
+                   unsigned nbits, mp *e,
+                   grand *r, unsigned nsteps, 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.
-   */
-
-  if ((rp->p = strongprime("p", MP_NEWSEC, nbits/2, r, n, event, ectx)) == 0)
-    goto fail_p;
-
-  /* --- Do painful fiddling with GCD steppers --- *
-   *
-   * Also, arrange that %$q \ge \lceil 2^{N-1}/p \rceil$%, so that %$p q$%
-   * has the right length.
-   */
-
-  {
-    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);
-      goto fail_q;
-    }
-    rp->q = q;
+  pgen_jumpctx jctx; pfilt j;
+  mp *p = MP_NEWSEC, *t = MP_NEW, *u = MP_NEW;
+  rabin rb;
+  mpw p3, j3, a;
+  int rc = -1;
+
+  j.m = MP_NEW;
+
+  /* Find a start position for the search. */
+  p = strongprime_setup(name, p, &j, nbits, r, nsteps, event, ectx);
+  if (!p) goto end;
+
+  /* Special handling for e = 3. */
+  if (MP_EQ(e, MP_THREE)) {
+    /* We must have p == 2 (mod 3): if p == 0 (mod 3) then p is not prime; if
+     * p == 1 (mod 3) then e|(p - 1).  So fiddle the start position and jump
+     * context to allow for this.
+     */
+
+    /* Figure out the residues of the start position and jump. */
+    mp_div(0, &t, p, MP_THREE); p3 = t->v[0];
+    mp_div(0, &u, j.m, MP_THREE); j3 = u->v[0];
+
+    /* If the jump is a multiple of three already, then we're stuffed unless
+     * the start position is 2 (mod 3).  This shouldn't happen, since the
+     * jump should be twice a multiple of two large primes, which will be
+     * nonzero (mod 3).
+     *
+     * Set a = (2 - p) j mod 3.  Then p' = p + a j == p (mod j), and p' ==
+     * p + (2 - p) j^2 == 2 (mod 3).
+     */
+    assert(j3 != 0);
+    a = ((2 - p3)*j3)%3;
+    if (a == 1) p = mp_add(p, p, j.m);
+    else if (a == 2) { t = mp_lsl(t, j.m, 1); p = mp_add(p, p, t); }
+
+    /* Finally, multiply j by three to make sure it preserves this
+     * congruence.
+     */
+    pfilt_muladd(&j, &j, 3, 0);
   }
 
-  /* --- 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);
-    goto fail_q;
-  }
+  /* Set the search going. */
+  jctx.j = &j;
+  p = pgen(name, p, p, event, ectx,
+          nsteps, pgen_jump, &jctx,
+          rabin_iters(nbits), pgen_test, &rb);
+
+  if (!p) goto end;
+
+  /* Check the GCD constraint. */
+  t = mp_sub(t, p, MP_ONE);
+  mp_gcd(&t, &u, 0, e, t);
+  if (!MP_EQ(t, MP_ONE)) goto end;
+
+  /* All is good. */
+  mp_drop(*pp); *pp = p; p = 0;
+  mp_drop(*dd); *dd = u; u = 0;
+  rc = 0;
+end:
+  mp_drop(p); mp_drop(t); mp_drop(u);
+  mp_drop(j.m);
+  return (rc);
+}
 
-  if (MP_NEGP(phi)) {
-    mp *z = rp->p;
-    rp->p = rp->q;
-    rp->q = z;
+int rsa_gen_e(rsa_priv *rp, unsigned nbits, mp *e,
+             grand *r, unsigned nsteps, pgen_proc *event, void *ectx)
+{
+  mp *p = MP_NEWSEC, *q = MP_NEWSEC, *n = MP_NEW;
+  mp *dp = MP_NEWSEC, *dq = MP_NEWSEC;
+  mp *t = MP_NEW, *u = MP_NEW, *v = MP_NEW;
+  mp *tt;
+  int rc = -1;
+
+#define RETRY(what) \
+  do { if (nsteps) goto fail; else goto retry_##what; } while (0)
+
+  /* Find the first prime. */
+retry_all:
+retry_p:
+  if (genprime(&p, &dp, "p", nbits/2, e, r, nsteps, event, ectx))
+    RETRY(p);
+
+  /* Find the second prime. */
+retry_q:
+  if (genprime(&q, &dq, "q", nbits/2, e, r, nsteps, event, ectx))
+    RETRY(q);
+
+  /* Check that gcd(p - 1, q - 1) is sufficiently large. */
+  u = mp_sub(u, p, MP_ONE);
+  v = mp_sub(v, q, MP_ONE);
+  mp_gcd(&t, 0, 0, u, v);
+  if (mp_bits(t) >= 8) RETRY(all);
+
+  /* Arrange for p > q. */
+  if (MP_CMP(p, <, q)) {
+    tt = p;  p  = q;  q  = tt;
+    tt = dp; dp = dq; dq = tt;
   }
 
-  /* --- Work out the modulus and the CRT coefficient --- */
+  /* Check that the modulus is the right size. */
+  n = mp_mul(n, p, q);
+  if (mp_bits(n) != nbits) RETRY(all);
 
-  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.
+  /* Now we want to calculate d.  The unit-group exponent is λ = lcm(p - 1,
+   * q - 1), so d == e^-1 (mod λ).
    */
+  u = mp_mul(u, u, v);
+  mp_div(&t, 0, u, t);
+  rp->d = mp_modinv(MP_NEW, e, t);
+
+  /* All done. */
+  rp->e = MP_COPY(e);
+  rp->q_inv = mp_modinv(MP_NEW, q, p);
+  rp->p = p; p = 0; rp->dp = dp; dp = 0;
+  rp->q = q; q = 0; rp->dq = dq; dq = 0;
+  rp->n = n; n = 0;
+  rc = 0;
+
+fail:
+  mp_drop(p); mp_drop(dp);
+  mp_drop(q); mp_drop(dq);
+  mp_drop(n);
+  mp_drop(t); mp_drop(u); mp_drop(v);
+  return (rc);
+}
 
-  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;
-  if (mp_bits(rp->n) != nbits)
-    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);
+int rsa_gen(rsa_priv *rp, unsigned nbits,
+           grand *r, unsigned nsteps, pgen_proc *event, void *ectx)
+{
+  mp *f4 = mp_fromulong(MP_NEW, 65537);
+  int rc = rsa_gen_e(rp, nbits, f4, r, nsteps, event, ectx);
+  mp_drop(f4); return (rc);
 }
 
 /*----- That's all, folks -------------------------------------------------*/