X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ba6e6b64033b1f9de49feccb5c9cd438354481f7..0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a:/pub/dh-check.c diff --git a/pub/dh-check.c b/pub/dh-check.c new file mode 100644 index 0000000..06f02ae --- /dev/null +++ b/pub/dh-check.c @@ -0,0 +1,170 @@ +/* -*-c-*- + * + * Checks Diffie-Hellman group parameters + * + * (c) 2001 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 + +#include "dh.h" +#include "keycheck.h" +#include "mp.h" +#include "mpmont.h" +#include "mpmul.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @dh_checkparam@ --- * + * + * Arguments: @keycheck *kc@ = keycheck state + * @const dh_param *dp@ = pointer to the parameter set + * @mp **v@ = optional vector of factors + * @size_t n@ = size of vector + * + * Returns: Zero if all OK, or return status from function. + * + * Use: Checks a set of Diffie-Hellman parameters for consistency and + * security. + */ + +int dh_checkparam(keycheck *kc, const dh_param *dp, mp **v, size_t n) +{ + int rc = 0; + mpmont mm; + mp *pm1 = MP_NEW; + mp *q = MP_NEW; + mp *x; + mpmul mu; + size_t i; + + /* --- Check that the numbers which are supposed to be prime are --- */ + + if ((!v && keycheck_prime(kc, KCSEV_WARN, dp->q, "q")) || + keycheck_prime(kc, KCSEV_ERR, dp->p, "p")) + goto fail; + + /* --- Ensure that %$q$% is a sensible choice of number --- */ + + pm1 = mp_sub(pm1, dp->p, MP_ONE); + mp_div(0, &q, pm1, dp->q); + if (!mp_eq(q, MP_ZERO) && + keycheck_report(kc, KCSEV_ERR, "q not a factor of p - 1")) + goto fail; + + /* --- Check that %$g$% is actually right --- * + * + * This isn't perfect. If %$q$% is composite and we don't have the factors + * of %$p - 1$% then the order of %$g$% may be some factor of %$q$% which + * we can't find. (If we do have the factors, we check them all lower + * down.) We do strip out powers of two from %$q$% before testing, though. + */ + + if ((mp_eq(dp->g, MP_ONE) || mp_eq(dp->g, pm1)) && + keycheck_report(kc, KCSEV_ERR, "g is degenerate (+/-1 mod p)")) + goto fail; + q = mp_odd(q, dp->q, &i); + mpmont_create(&mm, dp->p); + x = mpmont_mul(&mm, MP_NEW, dp->g, mm.r2); + q = mpmont_expr(&mm, q, x, q); + mp_drop(x); + do { + if (mp_eq(q, mm.r) != !i) { + if (keycheck_report(kc, KCSEV_ERR, "order of g != q")) { + mpmont_destroy(&mm); + goto fail; + } + break; + } + if (i) { + q = mp_sqr(q, q); + q = mpmont_reduce(&mm, q, q); + } + } while (i--); + + /* --- Check Lim-Lee primes more carefully --- * + * + * In this case, we really can be sure whether the order of %$g$% is + * actually %$q$% as advertised. Also ensure that the individual primes + * are really prime, and that their product is correct. + */ + + if (!v) + mpmont_destroy(&mm); + else { + dstr d = DSTR_INIT; + mp *r = MP_NEW; + + mpmul_init(&mu); + for (i = 0; i < n; i++) { + DRESET(&d); + dstr_putf(&d, "factor f_%lu of p", (unsigned long)i); + if ((rc = keycheck_prime(kc, KCSEV_ERR, v[i], d.buf)) != 0) + break; + mp_div(&q, &r, dp->q, v[i]); + if (mp_eq(r, MP_ZERO) && !mp_eq(q, MP_ONE)) { + q = mpmont_exp(&mm, q, dp->g, q); + if (mp_eq(q, MP_ONE) && + (rc = keycheck_report(kc, KCSEV_ERR, + "order of g is proper divisor of q")) != 0) + break; + } + mpmul_add(&mu, v[i]); + } + mp_drop(q); + mp_drop(r); + q = mpmul_done(&mu); + mpmont_destroy(&mm); + dstr_destroy(&d); + if (rc) + goto fail; + q = mp_lsl(q, q, 1); + if (!mp_eq(q, pm1) && + keycheck_report(kc, KCSEV_ERR, "product of f_i != (p - 1)/2")) + goto fail; + } + + /* --- Finally, check the key sizes --- */ + + if ((mp_bits(dp->p) < 1024 && + keycheck_report(kc, KCSEV_WARN, + "p too small to resist index calculus attacks")) || + (mp_bits(dp->q) < 160 && + keycheck_report(kc, KCSEV_WARN, + "q too small to resist collision-finding attacks"))) + goto fail; + + /* --- Done --- */ + +tidy: + mp_drop(q); + mp_drop(pm1); + return (rc); +fail: + rc = -1; + goto tidy; +} + +/*----- That's all, folks -------------------------------------------------*/