diff --git a/primecandidate.c b/primecandidate.c index f884f591..2b191052 100644 --- a/primecandidate.c +++ b/primecandidate.c @@ -25,7 +25,8 @@ struct PrimeCandidateSource { unsigned avoid_residue, avoid_modulus; }; -PrimeCandidateSource *pcs_new(unsigned bits, unsigned first, unsigned nfirst) +PrimeCandidateSource *pcs_new_with_firstbits(unsigned bits, + unsigned first, unsigned nfirst) { PrimeCandidateSource *s = snew(PrimeCandidateSource); @@ -60,6 +61,11 @@ PrimeCandidateSource *pcs_new(unsigned bits, unsigned first, unsigned nfirst) return s; } +PrimeCandidateSource *pcs_new(unsigned bits) +{ + return pcs_new_with_firstbits(bits, 1, 1); +} + void pcs_free(PrimeCandidateSource *s) { mp_free(s->limit); @@ -295,3 +301,8 @@ void pcs_inspect(PrimeCandidateSource *pcs, mp_int **limit_out, *factor_out = mp_copy(pcs->factor); *addend_out = mp_copy(pcs->addend); } + +unsigned pcs_get_bits(PrimeCandidateSource *pcs) +{ + return pcs->bits; +} diff --git a/ssh.h b/ssh.h index 57ef5eb7..4661c1c3 100644 --- a/ssh.h +++ b/ssh.h @@ -1332,9 +1332,6 @@ int ecdsa_generate(struct ecdsa_key *key, int bits, progfn_t pfn, void *pfnparam); int eddsa_generate(struct eddsa_key *key, int bits, progfn_t pfn, void *pfnparam); -mp_int *primegen( - int bits, int modulus, int residue, mp_int *factor, - int phase, progfn_t pfn, void *pfnparam, unsigned firstbits); /* * Connection-sharing API provided by platforms. This function must diff --git a/ssh1login-server.c b/ssh1login-server.c index 3316a6c3..ecc99640 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -11,6 +11,7 @@ #include "sshppl.h" #include "sshcr.h" #include "sshserver.h" +#include "sshkeygen.h" struct ssh1_login_server_state { int crState; diff --git a/ssh2kex-server.c b/ssh2kex-server.c index 44134ccb..3a1907d9 100644 --- a/ssh2kex-server.c +++ b/ssh2kex-server.c @@ -10,6 +10,7 @@ #include "sshppl.h" #include "sshcr.h" #include "sshserver.h" +#include "sshkeygen.h" #include "storage.h" #include "ssh2transport.h" #include "mpint.h" @@ -100,7 +101,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted) * group! It's good enough for testing a client against, * but not for serious use. */ - s->p = primegen(s->pbits, 2, 2, NULL, 1, no_progress, NULL, 1); + s->p = primegen(pcs_new(s->pbits), 1, no_progress, NULL); s->g = mp_from_integer(2); s->dh_ctx = dh_setup_gex(s->p, s->g); s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; diff --git a/sshdssg.c b/sshdssg.c index 10f3d72f..79e11080 100644 --- a/sshdssg.c +++ b/sshdssg.c @@ -4,6 +4,7 @@ #include "misc.h" #include "ssh.h" +#include "sshkeygen.h" #include "mpint.h" int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, @@ -56,15 +57,21 @@ int dsa_generate(struct dss_key *key, int bits, progfn_t pfn, pfn(pfnparam, PROGFN_READY, 0, 0); + PrimeCandidateSource *pcs; + /* * Generate q: a prime of length 160. */ - mp_int *q = primegen(160, 0, 0, NULL, 1, pfn, pfnparam, 1); + pcs = pcs_new(160); + mp_int *q = primegen(pcs, 1, pfn, pfnparam); + /* * Now generate p: a prime of length `bits', such that p-1 is * divisible by q. */ - mp_int *p = primegen(bits, 0, 0, q, 2, pfn, pfnparam, 1); + pcs = pcs_new(bits); + pcs_require_residue_1(pcs, q); + mp_int *p = primegen(pcs, 2, pfn, pfnparam); /* * Next we need g. Raise 2 to the power (p-1)/q modulo p, and diff --git a/sshkeygen.h b/sshkeygen.h index f5af2a10..2e615ec9 100644 --- a/sshkeygen.h +++ b/sshkeygen.h @@ -23,15 +23,17 @@ typedef struct PrimeCandidateSource PrimeCandidateSource; /* * pcs_new: you say how many bits you want the prime to have (with the * usual semantics that an n-bit number is in the range [2^{n-1},2^n)) - * and also specify what you want its topmost 'nfirst' bits to be. + * and also optionally specify what you want its topmost 'nfirst' bits + * to be. * * (The 'first' system is used for RSA keys, where you need to arrange * that the product of your two primes is in a more tightly * constrained range than the factor of 4 you'd get by just generating - * two (n/2)-bit primes and multiplying them. Any application that - * doesn't need that can simply specify first = nfirst = 1.) + * two (n/2)-bit primes and multiplying them.) */ -PrimeCandidateSource *pcs_new(unsigned bits, unsigned first, unsigned nfirst); +PrimeCandidateSource *pcs_new(unsigned bits); +PrimeCandidateSource *pcs_new_with_firstbits(unsigned bits, + unsigned first, unsigned nfirst); /* Insist that generated numbers must be congruent to 'res' mod 'mod' */ void pcs_require_residue(PrimeCandidateSource *s, mp_int *mod, mp_int *res); @@ -61,3 +63,14 @@ void pcs_free(PrimeCandidateSource *s); * unit-testing this system. */ void pcs_inspect(PrimeCandidateSource *pcs, mp_int **limit_out, mp_int **factor_out, mp_int **addend_out); + +/* Query functions for primegen to use */ +unsigned pcs_get_bits(PrimeCandidateSource *pcs); + +/* ---------------------------------------------------------------------- + * The top-level API for generating primes. + */ + +/* This function consumes and frees the PrimeCandidateSource you give it */ +mp_int *primegen(PrimeCandidateSource *pcs, + int phase, progfn_t pfn, void *pfnparam); diff --git a/sshprime.c b/sshprime.c index a3abae71..1953f4ef 100644 --- a/sshprime.c +++ b/sshprime.c @@ -108,44 +108,13 @@ * all, so after we've seen a -1 we can be sure of seeing nothing * but 1s.) */ - -/* - * Generate a prime. We can deal with various extra properties of - * the prime: - * - * - to speed up use in RSA, we can arrange to select a prime with - * the property (prime % modulus) != residue. - * - * - for use in DSA, we can arrange to select a prime which is one - * more than a multiple of a dirty great bignum. In this case - * `bits' gives the size of the factor by which we _multiply_ - * that bignum, rather than the size of the whole number. - * - * - for the basically cosmetic purposes of generating keys of the - * length actually specified rather than off by one bit, we permit - * the caller to provide an unsigned integer 'firstbits' which will - * match the top few bits of the returned prime. (That is, there - * will exist some n such that (returnvalue >> n) == firstbits.) If - * 'firstbits' is not needed, specifying it to either 0 or 1 is - * an adequate no-op. - */ -mp_int *primegen( - int bits, int modulus, int residue, mp_int *factor, - int phase, progfn_t pfn, void *pfnparam, unsigned firstbits) +mp_int *primegen(PrimeCandidateSource *pcs, + int phase, progfn_t pfn, void *pfnparam) { - int progress = 0; - - size_t fbsize = 0; - while (firstbits >> fbsize) /* work out how to align this */ - fbsize++; - - PrimeCandidateSource *pcs = pcs_new(bits, firstbits, fbsize); - if (factor) - pcs_require_residue_1(pcs, factor); - if (modulus) - pcs_avoid_residue_small(pcs, modulus, residue); pcs_ready(pcs); + int progress = 0; + STARTOVER: pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress); diff --git a/sshrsag.c b/sshrsag.c index de11b150..5dd09a35 100644 --- a/sshrsag.c +++ b/sshrsag.c @@ -5,10 +5,12 @@ #include #include "ssh.h" +#include "sshkeygen.h" #include "mpint.h" #define RSA_EXPONENT 65537 +#define NFIRSTBITS 13 static void invent_firstbits(unsigned *one, unsigned *two, unsigned min_separation); @@ -77,10 +79,16 @@ int rsa_generate(RSAKey *key, int bits, progfn_t pfn, int qbits = bits / 2; int pbits = bits - qbits; assert(pbits >= qbits); - mp_int *p = primegen(pbits, RSA_EXPONENT, 1, NULL, - 1, pfn, pfnparam, pfirst); - mp_int *q = primegen(qbits, RSA_EXPONENT, 1, NULL, - 2, pfn, pfnparam, qfirst); + + PrimeCandidateSource *pcs; + + pcs = pcs_new_with_firstbits(pbits, pfirst, NFIRSTBITS); + pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1); + mp_int *p = primegen(pcs, 1, pfn, pfnparam); + + pcs = pcs_new_with_firstbits(qbits, qfirst, NFIRSTBITS); + pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1); + mp_int *q = primegen(pcs, 2, pfn, pfnparam); /* * Ensure p > q, by swapping them if not. diff --git a/test/cryptsuite.py b/test/cryptsuite.py index 5006a76e..c5a04c92 100755 --- a/test/cryptsuite.py +++ b/test/cryptsuite.py @@ -904,7 +904,7 @@ class keygen(MyTestBase): self.assertTrue (lo <= addend + (limit-1) * factor < hi) self.assertFalse(lo <= addend + limit * factor < hi) - pcs = pcs_new(64, 1, 1) + pcs = pcs_new(64) check(pcs, 2**63, 2**64, [(2, 1)]) pcs_require_residue(pcs, 3, 2) check(pcs, 2**63, 2**64, [(2, 1), (3, 2)]) @@ -918,7 +918,7 @@ class keygen(MyTestBase): # Now test-generate some actual values, and ensure they # satisfy all the congruences, and also avoid one residue mod # 5 that we told them to. Also, give a nontrivial range. - pcs = pcs_new(64, 0xAB, 8) + pcs = pcs_new_with_firstbits(64, 0xAB, 8) pcs_require_residue(pcs, 0x100, 0xCD) pcs_require_residue_1(pcs, 65537) pcs_avoid_residue_small(pcs, 5, 3) diff --git a/testcrypt.c b/testcrypt.c index 413f5fa1..7d9d3476 100644 --- a/testcrypt.c +++ b/testcrypt.c @@ -1049,11 +1049,9 @@ strbuf *rsa1_save_sb_wrapper(RSAKey *key, const char *comment, static void no_progress(void *param, int action, int phase, int iprogress) {} -mp_int *primegen_wrapper( - int bits, int modulus, int residue, mp_int *factor, unsigned firstbits) +mp_int *primegen_wrapper(PrimeCandidateSource *pcs) { - return primegen(bits, modulus, residue, factor, - 0, no_progress, NULL, firstbits); + return primegen(pcs, 0, no_progress, NULL); } #define primegen primegen_wrapper diff --git a/testcrypt.h b/testcrypt.h index 152af6ce..4469b391 100644 --- a/testcrypt.h +++ b/testcrypt.h @@ -265,8 +265,9 @@ FUNC1(val_key, dsa_generate, uint) FUNC1(opt_val_key, ecdsa_generate, uint) FUNC1(opt_val_key, eddsa_generate, uint) FUNC1(val_rsa, rsa1_generate, uint) -FUNC5(val_mpint, primegen, uint, uint, uint, val_mpint, uint) -FUNC3(val_pcs, pcs_new, uint, uint, uint) +FUNC1(val_mpint, primegen, val_pcs) +FUNC1(val_pcs, pcs_new, uint) +FUNC3(val_pcs, pcs_new_with_firstbits, uint, uint, uint) FUNC3(void, pcs_require_residue, val_pcs, val_mpint, val_mpint) FUNC2(void, pcs_require_residue_1, val_pcs, val_mpint) FUNC3(void, pcs_avoid_residue_small, val_pcs, uint, uint)