X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/373641eaacc86b56715a2ebf0b603fce25c16051..HEAD:/pub/rsa-gen.c diff --git a/pub/rsa-gen.c b/pub/rsa-gen.c index 3b5334b8..b381bcd0 100644 --- a/pub/rsa-gen.c +++ b/pub/rsa-gen.c @@ -38,10 +38,11 @@ /*----- 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 @@ -54,136 +55,143 @@ * 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 -------------------------------------------------*/