mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Revert "New vtable API for keygen progress reporting."
This reverts commit a7bdefb394
.
I had accidentally mashed it together with another commit. I did
actually want to push both of them, but I'd rather push them
separately! So I'm backing out the combined blob, and I'll re-push
them with their proper comments and explanations.
This commit is contained in:
parent
a7bdefb394
commit
62733a8389
2
Recipe
2
Recipe
@ -282,7 +282,7 @@ UXSSH = SSH uxnoise uxagentc uxgss uxshare
|
||||
SFTP = psftpcommon sftp sftpcommon logging cmdline
|
||||
|
||||
# Components of the prime-generation system.
|
||||
SSHPRIME = sshprime smallprimes primecandidate millerrabin mpunsafe
|
||||
SSHPRIME = sshprime smallprimes primecandidate mpunsafe
|
||||
|
||||
# Miscellaneous objects appearing in all the utilities, or all the
|
||||
# network ones, or the Unix or Windows subsets of those in turn.
|
||||
|
70
cmdgen.c
70
cmdgen.c
@ -13,35 +13,36 @@
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshkeygen.h"
|
||||
#include "mpint.h"
|
||||
|
||||
FILE *progress_fp = NULL;
|
||||
|
||||
static void cmdgen_progress_report_attempt(ProgressReceiver *prog)
|
||||
{
|
||||
if (progress_fp) {
|
||||
fputc('+', progress_fp);
|
||||
fflush(progress_fp);
|
||||
}
|
||||
}
|
||||
static void cmdgen_progress_report_phase_complete(ProgressReceiver *prog)
|
||||
{
|
||||
if (progress_fp) {
|
||||
fputc('\n', progress_fp);
|
||||
fflush(progress_fp);
|
||||
}
|
||||
}
|
||||
|
||||
static const ProgressReceiverVtable cmdgen_progress_vt = {
|
||||
null_progress_add_probabilistic,
|
||||
null_progress_ready,
|
||||
null_progress_start_phase,
|
||||
cmdgen_progress_report_attempt,
|
||||
cmdgen_progress_report_phase_complete,
|
||||
struct progress {
|
||||
int phase, current;
|
||||
};
|
||||
|
||||
static ProgressReceiver cmdgen_progress = { .vt = &cmdgen_progress_vt };
|
||||
static void progress_update(void *param, int action, int phase, int iprogress)
|
||||
{
|
||||
struct progress *p = (struct progress *)param;
|
||||
if (action != PROGFN_PROGRESS)
|
||||
return;
|
||||
if (phase > p->phase) {
|
||||
if (p->phase >= 0)
|
||||
fputc('\n', stderr);
|
||||
p->phase = phase;
|
||||
if (iprogress >= 0)
|
||||
p->current = iprogress - 1;
|
||||
else
|
||||
p->current = iprogress;
|
||||
}
|
||||
while (p->current < iprogress) {
|
||||
fputc('+', stdout);
|
||||
p->current++;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void no_progress(void *param, int action, int phase, int iprogress)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Stubs to let everything else link sensibly.
|
||||
@ -183,12 +184,10 @@ int main(int argc, char **argv)
|
||||
char *ssh2alg = NULL;
|
||||
char *old_passphrase = NULL, *new_passphrase = NULL;
|
||||
bool load_encrypted;
|
||||
progfn_t progressfn = is_interactive() ? progress_update : no_progress;
|
||||
const char *random_device = NULL;
|
||||
int exit_status = 0;
|
||||
|
||||
if (is_interactive())
|
||||
progress_fp = stderr;
|
||||
|
||||
#define RETURN(status) do { exit_status = (status); goto out; } while (0)
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
@ -334,7 +333,7 @@ int main(int argc, char **argv)
|
||||
outtype = PUBLIC;
|
||||
break;
|
||||
case 'q':
|
||||
progress_fp = NULL;
|
||||
progressfn = no_progress;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -646,6 +645,10 @@ int main(int argc, char **argv)
|
||||
char *entropy;
|
||||
char default_comment[80];
|
||||
struct tm tm;
|
||||
struct progress prog;
|
||||
|
||||
prog.phase = -1;
|
||||
prog.current = -1;
|
||||
|
||||
tm = ltime();
|
||||
if (keytype == DSA)
|
||||
@ -670,25 +673,25 @@ int main(int argc, char **argv)
|
||||
|
||||
if (keytype == DSA) {
|
||||
struct dss_key *dsskey = snew(struct dss_key);
|
||||
dsa_generate(dsskey, bits, &cmdgen_progress);
|
||||
dsa_generate(dsskey, bits, progressfn, &prog);
|
||||
ssh2key = snew(ssh2_userkey);
|
||||
ssh2key->key = &dsskey->sshk;
|
||||
ssh1key = NULL;
|
||||
} else if (keytype == ECDSA) {
|
||||
struct ecdsa_key *ek = snew(struct ecdsa_key);
|
||||
ecdsa_generate(ek, bits);
|
||||
ecdsa_generate(ek, bits, progressfn, &prog);
|
||||
ssh2key = snew(ssh2_userkey);
|
||||
ssh2key->key = &ek->sshk;
|
||||
ssh1key = NULL;
|
||||
} else if (keytype == ED25519) {
|
||||
struct eddsa_key *ek = snew(struct eddsa_key);
|
||||
eddsa_generate(ek, bits);
|
||||
eddsa_generate(ek, bits, progressfn, &prog);
|
||||
ssh2key = snew(ssh2_userkey);
|
||||
ssh2key->key = &ek->sshk;
|
||||
ssh1key = NULL;
|
||||
} else {
|
||||
RSAKey *rsakey = snew(RSAKey);
|
||||
rsa_generate(rsakey, bits, &cmdgen_progress);
|
||||
rsa_generate(rsakey, bits, progressfn, &prog);
|
||||
rsakey->comment = NULL;
|
||||
if (keytype == RSA1) {
|
||||
ssh1key = rsakey;
|
||||
@ -697,6 +700,7 @@ int main(int argc, char **argv)
|
||||
ssh2key->key = &rsakey->sshk;
|
||||
}
|
||||
}
|
||||
progressfn(&prog, PROGFN_PROGRESS, INT_MAX, -1);
|
||||
|
||||
if (ssh2key)
|
||||
ssh2key->comment = dupstr(default_comment);
|
||||
|
214
millerrabin.c
214
millerrabin.c
@ -1,214 +0,0 @@
|
||||
/*
|
||||
* millerrabin.c: Miller-Rabin probabilistic primality testing, as
|
||||
* declared in sshkeygen.h.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "ssh.h"
|
||||
#include "sshkeygen.h"
|
||||
#include "mpint.h"
|
||||
#include "mpunsafe.h"
|
||||
|
||||
/*
|
||||
* The Miller-Rabin primality test is an extension to the Fermat
|
||||
* test. The Fermat test just checks that a^(p-1) == 1 mod p; this
|
||||
* is vulnerable to Carmichael numbers. Miller-Rabin considers how
|
||||
* that 1 is derived as well.
|
||||
*
|
||||
* Lemma: if a^2 == 1 (mod p), and p is prime, then either a == 1
|
||||
* or a == -1 (mod p).
|
||||
*
|
||||
* Proof: p divides a^2-1, i.e. p divides (a+1)(a-1). Hence,
|
||||
* since p is prime, either p divides (a+1) or p divides (a-1).
|
||||
* But this is the same as saying that either a is congruent to
|
||||
* -1 mod p or a is congruent to +1 mod p. []
|
||||
*
|
||||
* Comment: This fails when p is not prime. Consider p=mn, so
|
||||
* that mn divides (a+1)(a-1). Now we could have m dividing (a+1)
|
||||
* and n dividing (a-1), without the whole of mn dividing either.
|
||||
* For example, consider a=10 and p=99. 99 = 9 * 11; 9 divides
|
||||
* 10-1 and 11 divides 10+1, so a^2 is congruent to 1 mod p
|
||||
* without a having to be congruent to either 1 or -1.
|
||||
*
|
||||
* So the Miller-Rabin test, as well as considering a^(p-1),
|
||||
* considers a^((p-1)/2), a^((p-1)/4), and so on as far as it can
|
||||
* go. In other words. we write p-1 as q * 2^k, with k as large as
|
||||
* possible (i.e. q must be odd), and we consider the powers
|
||||
*
|
||||
* a^(q*2^0) a^(q*2^1) ... a^(q*2^(k-1)) a^(q*2^k)
|
||||
* i.e. a^((n-1)/2^k) a^((n-1)/2^(k-1)) ... a^((n-1)/2) a^(n-1)
|
||||
*
|
||||
* If p is to be prime, the last of these must be 1. Therefore, by
|
||||
* the above lemma, the one before it must be either 1 or -1. And
|
||||
* _if_ it's 1, then the one before that must be either 1 or -1,
|
||||
* and so on ... In other words, we expect to see a trailing chain
|
||||
* of 1s preceded by a -1. (If we're unlucky, our trailing chain of
|
||||
* 1s will be as long as the list so we'll never get to see what
|
||||
* lies before it. This doesn't count as a test failure because it
|
||||
* hasn't _proved_ that p is not prime.)
|
||||
*
|
||||
* For example, consider a=2 and p=1729. 1729 is a Carmichael
|
||||
* number: although it's not prime, it satisfies a^(p-1) == 1 mod p
|
||||
* for any a coprime to it. So the Fermat test wouldn't have a
|
||||
* problem with it at all, unless we happened to stumble on an a
|
||||
* which had a common factor.
|
||||
*
|
||||
* So. 1729 - 1 equals 27 * 2^6. So we look at
|
||||
*
|
||||
* 2^27 mod 1729 == 645
|
||||
* 2^108 mod 1729 == 1065
|
||||
* 2^216 mod 1729 == 1
|
||||
* 2^432 mod 1729 == 1
|
||||
* 2^864 mod 1729 == 1
|
||||
* 2^1728 mod 1729 == 1
|
||||
*
|
||||
* We do have a trailing string of 1s, so the Fermat test would
|
||||
* have been happy. But this trailing string of 1s is preceded by
|
||||
* 1065; whereas if 1729 were prime, we'd expect to see it preceded
|
||||
* by -1 (i.e. 1728.). Guards! Seize this impostor.
|
||||
*
|
||||
* (If we were unlucky, we might have tried a=16 instead of a=2;
|
||||
* now 16^27 mod 1729 == 1, so we would have seen a long string of
|
||||
* 1s and wouldn't have seen the thing _before_ the 1s. So, just
|
||||
* like the Fermat test, for a given p there may well exist values
|
||||
* of a which fail to show up its compositeness. So we try several,
|
||||
* just like the Fermat test. The difference is that Miller-Rabin
|
||||
* is not _in general_ fooled by Carmichael numbers.)
|
||||
*
|
||||
* Put simply, then, the Miller-Rabin test requires us to:
|
||||
*
|
||||
* 1. write p-1 as q * 2^k, with q odd
|
||||
* 2. compute z = (a^q) mod p.
|
||||
* 3. report success if z == 1 or z == -1.
|
||||
* 4. square z at most k-1 times, and report success if it becomes
|
||||
* -1 at any point.
|
||||
* 5. report failure otherwise.
|
||||
*
|
||||
* (We expect z to become -1 after at most k-1 squarings, because
|
||||
* if it became -1 after k squarings then a^(p-1) would fail to be
|
||||
* 1. And we don't need to investigate what happens after we see a
|
||||
* -1, because we _know_ that -1 squared is 1 modulo anything at
|
||||
* all, so after we've seen a -1 we can be sure of seeing nothing
|
||||
* but 1s.)
|
||||
*/
|
||||
|
||||
struct MillerRabin {
|
||||
MontyContext *mc;
|
||||
|
||||
size_t k;
|
||||
mp_int *q;
|
||||
|
||||
mp_int *two, *pm1, *m_pm1;
|
||||
};
|
||||
|
||||
MillerRabin *miller_rabin_new(mp_int *p)
|
||||
{
|
||||
MillerRabin *mr = snew(MillerRabin);
|
||||
|
||||
assert(mp_hs_integer(p, 2));
|
||||
assert(mp_get_bit(p, 0) == 1);
|
||||
|
||||
mr->k = 1;
|
||||
while (!mp_get_bit(p, mr->k))
|
||||
mr->k++;
|
||||
mr->q = mp_rshift_safe(p, mr->k);
|
||||
|
||||
mr->two = mp_from_integer(2);
|
||||
|
||||
mr->pm1 = mp_unsafe_copy(p);
|
||||
mp_sub_integer_into(mr->pm1, mr->pm1, 1);
|
||||
|
||||
mr->mc = monty_new(p);
|
||||
mr->m_pm1 = monty_import(mr->mc, mr->pm1);
|
||||
|
||||
return mr;
|
||||
}
|
||||
|
||||
void miller_rabin_free(MillerRabin *mr)
|
||||
{
|
||||
mp_free(mr->q);
|
||||
mp_free(mr->two);
|
||||
mp_free(mr->pm1);
|
||||
mp_free(mr->m_pm1);
|
||||
monty_free(mr->mc);
|
||||
smemclr(mr, sizeof(*mr));
|
||||
sfree(mr);
|
||||
}
|
||||
|
||||
struct mr_result {
|
||||
bool passed;
|
||||
bool potential_primitive_root;
|
||||
};
|
||||
|
||||
static struct mr_result miller_rabin_test_inner(MillerRabin *mr, mp_int *w)
|
||||
{
|
||||
/*
|
||||
* Compute w^q mod p.
|
||||
*/
|
||||
mp_int *wqp = monty_pow(mr->mc, w, mr->q);
|
||||
|
||||
/*
|
||||
* See if this is 1, or if it is -1, or if it becomes -1
|
||||
* when squared at most k-1 times.
|
||||
*/
|
||||
struct mr_result result;
|
||||
result.passed = false;
|
||||
result.potential_primitive_root = false;
|
||||
|
||||
if (mp_cmp_eq(wqp, monty_identity(mr->mc))) {
|
||||
result.passed = true;
|
||||
} else {
|
||||
for (size_t i = 0; i < mr->k; i++) {
|
||||
if (mp_cmp_eq(wqp, mr->m_pm1)) {
|
||||
result.passed = true;
|
||||
result.potential_primitive_root = (i == mr->k - 1);
|
||||
break;
|
||||
}
|
||||
if (i == mr->k - 1)
|
||||
break;
|
||||
monty_mul_into(mr->mc, wqp, wqp, wqp);
|
||||
}
|
||||
}
|
||||
|
||||
mp_free(wqp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool miller_rabin_test_random(MillerRabin *mr)
|
||||
{
|
||||
mp_int *mw = mp_random_in_range(mr->two, mr->pm1);
|
||||
struct mr_result result = miller_rabin_test_inner(mr, mw);
|
||||
mp_free(mw);
|
||||
return result.passed;
|
||||
}
|
||||
|
||||
mp_int *miller_rabin_find_potential_primitive_root(MillerRabin *mr)
|
||||
{
|
||||
while (true) {
|
||||
mp_int *mw = mp_unsafe_shrink(mp_random_in_range(mr->two, mr->pm1));
|
||||
struct mr_result result = miller_rabin_test_inner(mr, mw);
|
||||
|
||||
if (result.passed && result.potential_primitive_root) {
|
||||
mp_int *pr = monty_export(mr->mc, mw);
|
||||
mp_free(mw);
|
||||
return pr;
|
||||
}
|
||||
|
||||
mp_free(mw);
|
||||
|
||||
if (!result.passed) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned miller_rabin_checks_needed(unsigned bits)
|
||||
{
|
||||
/* Table 4.4 from Handbook of Applied Cryptography */
|
||||
return (bits >= 1300 ? 2 : bits >= 850 ? 3 : bits >= 650 ? 4 :
|
||||
bits >= 550 ? 5 : bits >= 450 ? 6 : bits >= 400 ? 7 :
|
||||
bits >= 350 ? 8 : bits >= 300 ? 9 : bits >= 250 ? 12 :
|
||||
bits >= 200 ? 15 : bits >= 150 ? 18 : 27);
|
||||
}
|
||||
|
20
ssh.h
20
ssh.h
@ -1313,6 +1313,26 @@ void openssh_bcrypt(const char *passphrase,
|
||||
const unsigned char *salt, int saltbytes,
|
||||
int rounds, unsigned char *out, int outbytes);
|
||||
|
||||
/*
|
||||
* For progress updates in the key generation utility.
|
||||
*/
|
||||
#define PROGFN_INITIALISE 1
|
||||
#define PROGFN_LIN_PHASE 2
|
||||
#define PROGFN_EXP_PHASE 3
|
||||
#define PROGFN_PHASE_EXTENT 4
|
||||
#define PROGFN_READY 5
|
||||
#define PROGFN_PROGRESS 6
|
||||
typedef void (*progfn_t) (void *param, int action, int phase, int progress);
|
||||
|
||||
int rsa_generate(RSAKey *key, int bits, progfn_t pfn,
|
||||
void *pfnparam);
|
||||
int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
|
||||
void *pfnparam);
|
||||
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);
|
||||
|
||||
/*
|
||||
* Connection-sharing API provided by platforms. This function must
|
||||
* either:
|
||||
|
@ -70,6 +70,8 @@ static const struct PacketProtocolLayerVtable ssh1_login_server_vtable = {
|
||||
NULL /* no layer names in SSH-1 */,
|
||||
};
|
||||
|
||||
static void no_progress(void *param, int action, int phase, int iprogress) {}
|
||||
|
||||
PacketProtocolLayer *ssh1_login_server_new(
|
||||
PacketProtocolLayer *successor_layer, RSAKey *hostkey,
|
||||
AuthPolicy *authpolicy, const SshServerConfig *ssc)
|
||||
@ -140,9 +142,7 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
|
||||
if (server_key_bits < 512)
|
||||
server_key_bits = s->hostkey->bytes + 256;
|
||||
s->servkey = snew(RSAKey);
|
||||
ProgressReceiver null_progress;
|
||||
null_progress.vt = &null_progress_vt;
|
||||
rsa_generate(s->servkey, server_key_bits, &null_progress);
|
||||
rsa_generate(s->servkey, server_key_bits, no_progress, NULL);
|
||||
s->servkey->comment = NULL;
|
||||
s->servkey_generated_here = true;
|
||||
}
|
||||
|
@ -36,6 +36,10 @@ static strbuf *finalise_and_sign_exhash(struct ssh2_transport_state *s)
|
||||
return sb;
|
||||
}
|
||||
|
||||
static void no_progress(void *param, int action, int phase, int iprogress)
|
||||
{
|
||||
}
|
||||
|
||||
void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
|
||||
{
|
||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||
@ -97,9 +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.
|
||||
*/
|
||||
ProgressReceiver null_progress;
|
||||
null_progress.vt = &null_progress_vt;
|
||||
s->p = primegen(pcs_new(s->pbits), &null_progress);
|
||||
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;
|
||||
@ -261,9 +263,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
|
||||
ppl_logevent("Generating a %d-bit RSA key", extra->minklen);
|
||||
|
||||
s->rsa_kex_key = snew(RSAKey);
|
||||
ProgressReceiver null_progress;
|
||||
null_progress.vt = &null_progress_vt;
|
||||
rsa_generate(s->rsa_kex_key, extra->minklen, &null_progress);
|
||||
rsa_generate(s->rsa_kex_key, extra->minklen, no_progress, NULL);
|
||||
s->rsa_kex_key->comment = NULL;
|
||||
s->rsa_kex_key_needs_freeing = true;
|
||||
}
|
||||
|
74
sshdssg.c
74
sshdssg.c
@ -7,50 +7,71 @@
|
||||
#include "sshkeygen.h"
|
||||
#include "mpint.h"
|
||||
|
||||
int dsa_generate(struct dss_key *key, int bits, ProgressReceiver *prog)
|
||||
int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
|
||||
void *pfnparam)
|
||||
{
|
||||
/*
|
||||
* Progress-reporting setup.
|
||||
* Set up the phase limits for the progress report. We do this
|
||||
* by passing minus the phase number.
|
||||
*
|
||||
* DSA generation involves three potentially long jobs: inventing
|
||||
* the small prime q, the large prime p, and finding an order-q
|
||||
* element of the multiplicative group of p.
|
||||
* For prime generation: our initial filter finds things
|
||||
* coprime to everything below 2^16. Computing the product of
|
||||
* (p-1)/p for all prime p below 2^16 gives about 20.33; so
|
||||
* among B-bit integers, one in every 20.33 will get through
|
||||
* the initial filter to be a candidate prime.
|
||||
*
|
||||
* The latter is done by finding an element whose order is
|
||||
* _divisible_ by q and raising it to the power of (p-1)/q. Every
|
||||
* element whose order is not divisible by q is a qth power of q
|
||||
* distinct elements whose order _is_ divisible by q, so the
|
||||
* probability of not finding a suitable element on the first try
|
||||
* is in the region of 1/q, i.e. at most 2^-159.
|
||||
* Meanwhile, we are searching for primes in the region of 2^B;
|
||||
* since pi(x) ~ x/log(x), when x is in the region of 2^B, the
|
||||
* prime density will be d/dx pi(x) ~ 1/log(B), i.e. about
|
||||
* 1/0.6931B. So the chance of any given candidate being prime
|
||||
* is 20.33/0.6931B, which is roughly 29.34 divided by B.
|
||||
*
|
||||
* (So the probability of success will end up indistinguishable
|
||||
* from 1 in IEEE standard floating point! But what can you do.)
|
||||
* So now we have this probability P, we're looking at an
|
||||
* exponential distribution with parameter P: we will manage in
|
||||
* one attempt with probability P, in two with probability
|
||||
* P(1-P), in three with probability P(1-P)^2, etc. The
|
||||
* probability that we have still not managed to find a prime
|
||||
* after N attempts is (1-P)^N.
|
||||
*
|
||||
* We therefore inform the progress indicator of the number B
|
||||
* (29.34/B), so that it knows how much to increment by each
|
||||
* time. We do this in 16-bit fixed point, so 29.34 becomes
|
||||
* 0x1D.57C4.
|
||||
*/
|
||||
ProgressPhase phase_q = primegen_add_progress_phase(prog, 160);
|
||||
ProgressPhase phase_p = primegen_add_progress_phase(prog, bits);
|
||||
ProgressPhase phase_g = progress_add_probabilistic(
|
||||
prog, estimate_modexp_cost(bits), 1.0 - 0x1.0p-159);
|
||||
progress_ready(prog);
|
||||
pfn(pfnparam, PROGFN_PHASE_EXTENT, 1, 0x2800);
|
||||
pfn(pfnparam, PROGFN_EXP_PHASE, 1, -0x1D57C4 / 160);
|
||||
pfn(pfnparam, PROGFN_PHASE_EXTENT, 2, 0x40 * bits);
|
||||
pfn(pfnparam, PROGFN_EXP_PHASE, 2, -0x1D57C4 / bits);
|
||||
|
||||
/*
|
||||
* In phase three we are finding an order-q element of the
|
||||
* multiplicative group of p, by finding an element whose order
|
||||
* is _divisible_ by q and raising it to the power of (p-1)/q.
|
||||
* _Most_ elements will have order divisible by q, since for a
|
||||
* start phi(p) of them will be primitive roots. So
|
||||
* realistically we don't need to set this much below 1 (64K).
|
||||
* Still, we'll set it to 1/2 (32K) to be on the safe side.
|
||||
*/
|
||||
pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x2000);
|
||||
pfn(pfnparam, PROGFN_EXP_PHASE, 3, -32768);
|
||||
|
||||
pfn(pfnparam, PROGFN_READY, 0, 0);
|
||||
|
||||
PrimeCandidateSource *pcs;
|
||||
|
||||
/*
|
||||
* Generate q: a prime of length 160.
|
||||
*/
|
||||
progress_start_phase(prog, phase_q);
|
||||
pcs = pcs_new(160);
|
||||
mp_int *q = primegen(pcs, prog);
|
||||
progress_report_phase_complete(prog);
|
||||
mp_int *q = primegen(pcs, 1, pfn, pfnparam);
|
||||
|
||||
/*
|
||||
* Now generate p: a prime of length `bits', such that p-1 is
|
||||
* divisible by q.
|
||||
*/
|
||||
progress_start_phase(prog, phase_p);
|
||||
pcs = pcs_new(bits);
|
||||
pcs_require_residue_1(pcs, q);
|
||||
mp_int *p = primegen(pcs, prog);
|
||||
progress_report_phase_complete(prog);
|
||||
mp_int *p = primegen(pcs, 2, pfn, pfnparam);
|
||||
|
||||
/*
|
||||
* Next we need g. Raise 2 to the power (p-1)/q modulo p, and
|
||||
@ -58,12 +79,12 @@ int dsa_generate(struct dss_key *key, int bits, ProgressReceiver *prog)
|
||||
* soon as we hit a non-unit (and non-zero!) one, that'll do
|
||||
* for g.
|
||||
*/
|
||||
progress_start_phase(prog, phase_g);
|
||||
mp_int *power = mp_div(p, q); /* this is floor(p/q) == (p-1)/q */
|
||||
mp_int *h = mp_from_integer(1);
|
||||
int progress = 0;
|
||||
mp_int *g;
|
||||
while (1) {
|
||||
progress_report_attempt(prog);
|
||||
pfn(pfnparam, PROGFN_PROGRESS, 3, ++progress);
|
||||
g = mp_modpow(h, power, p);
|
||||
if (mp_hs_integer(g, 2))
|
||||
break; /* got one */
|
||||
@ -72,7 +93,6 @@ int dsa_generate(struct dss_key *key, int bits, ProgressReceiver *prog)
|
||||
}
|
||||
mp_free(h);
|
||||
mp_free(power);
|
||||
progress_report_phase_complete(prog);
|
||||
|
||||
/*
|
||||
* Now we're nearly done. All we need now is our private key x,
|
||||
|
@ -3,10 +3,10 @@
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
#include "sshkeygen.h"
|
||||
#include "mpint.h"
|
||||
|
||||
int ecdsa_generate(struct ecdsa_key *ek, int bits)
|
||||
int ecdsa_generate(struct ecdsa_key *ek, int bits,
|
||||
progfn_t pfn, void *pfnparam)
|
||||
{
|
||||
if (!ec_nist_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt))
|
||||
return 0;
|
||||
@ -20,7 +20,8 @@ int ecdsa_generate(struct ecdsa_key *ek, int bits)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int eddsa_generate(struct eddsa_key *ek, int bits)
|
||||
int eddsa_generate(struct eddsa_key *ek, int bits,
|
||||
progfn_t pfn, void *pfnparam)
|
||||
{
|
||||
if (!ec_ed_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt))
|
||||
return 0;
|
||||
|
93
sshkeygen.h
93
sshkeygen.h
@ -67,99 +67,10 @@ void pcs_inspect(PrimeCandidateSource *pcs, mp_int **limit_out,
|
||||
/* Query functions for primegen to use */
|
||||
unsigned pcs_get_bits(PrimeCandidateSource *pcs);
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* A system for doing Miller-Rabin probabilistic primality tests.
|
||||
* These benefit from having set up some context beforehand, if you're
|
||||
* going to do more than one of them on the same candidate prime, so
|
||||
* we declare an object type here to store that context.
|
||||
*/
|
||||
|
||||
typedef struct MillerRabin MillerRabin;
|
||||
|
||||
/* Make and free a Miller-Rabin context. */
|
||||
MillerRabin *miller_rabin_new(mp_int *p);
|
||||
void miller_rabin_free(MillerRabin *mr);
|
||||
|
||||
/* Perform a single Miller-Rabin test, using a random witness value. */
|
||||
bool miller_rabin_test_random(MillerRabin *mr);
|
||||
|
||||
/* Suggest how many tests are needed to make it sufficiently unlikely
|
||||
* that a composite number will pass them all */
|
||||
unsigned miller_rabin_checks_needed(unsigned bits);
|
||||
|
||||
/* An extension to the M-R test, which iterates until it either finds
|
||||
* a witness value that is potentially a primitive root, or one
|
||||
* that proves the number to be composite. */
|
||||
mp_int *miller_rabin_find_potential_primitive_root(MillerRabin *mr);
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Callback API that allows key generation to report progress to its
|
||||
* caller.
|
||||
*/
|
||||
|
||||
typedef struct ProgressReceiverVtable ProgressReceiverVtable;
|
||||
typedef struct ProgressReceiver ProgressReceiver;
|
||||
typedef union ProgressPhase ProgressPhase;
|
||||
|
||||
union ProgressPhase {
|
||||
int n;
|
||||
void *p;
|
||||
};
|
||||
|
||||
struct ProgressReceiver {
|
||||
const ProgressReceiverVtable *vt;
|
||||
};
|
||||
|
||||
struct ProgressReceiverVtable {
|
||||
ProgressPhase (*add_probabilistic)(ProgressReceiver *prog,
|
||||
double cost_per_attempt,
|
||||
double attempt_probability);
|
||||
void (*ready)(ProgressReceiver *prog);
|
||||
void (*start_phase)(ProgressReceiver *prog, ProgressPhase phase);
|
||||
void (*report_attempt)(ProgressReceiver *prog);
|
||||
void (*report_phase_complete)(ProgressReceiver *prog);
|
||||
};
|
||||
|
||||
static inline ProgressPhase progress_add_probabilistic(ProgressReceiver *prog,
|
||||
double c, double p)
|
||||
{ return prog->vt->add_probabilistic(prog, c, p); }
|
||||
static inline void progress_ready(ProgressReceiver *prog)
|
||||
{ prog->vt->ready(prog); }
|
||||
static inline void progress_start_phase(
|
||||
ProgressReceiver *prog, ProgressPhase phase)
|
||||
{ prog->vt->start_phase(prog, phase); }
|
||||
static inline void progress_report_attempt(ProgressReceiver *prog)
|
||||
{ prog->vt->report_attempt(prog); }
|
||||
static inline void progress_report_phase_complete(ProgressReceiver *prog)
|
||||
{ prog->vt->report_phase_complete(prog); }
|
||||
|
||||
ProgressPhase null_progress_add_probabilistic(
|
||||
ProgressReceiver *prog, double c, double p);
|
||||
void null_progress_ready(ProgressReceiver *prog);
|
||||
void null_progress_start_phase(ProgressReceiver *prog, ProgressPhase phase);
|
||||
void null_progress_report_attempt(ProgressReceiver *prog);
|
||||
void null_progress_report_phase_complete(ProgressReceiver *prog);
|
||||
extern const ProgressReceiverVtable null_progress_vt;
|
||||
|
||||
/* A helper function for dreaming up progress cost estimates. */
|
||||
double estimate_modexp_cost(unsigned bits);
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* The top-level API for generating primes.
|
||||
*/
|
||||
|
||||
/* This function consumes and frees the PrimeCandidateSource you give it */
|
||||
mp_int *primegen(PrimeCandidateSource *pcs, ProgressReceiver *prog);
|
||||
|
||||
/* Estimate how long it will take, and add a phase to a ProgressReceiver */
|
||||
ProgressPhase primegen_add_progress_phase(ProgressReceiver *prog,
|
||||
unsigned bits);
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* The overall top-level API for generating entire key pairs.
|
||||
*/
|
||||
|
||||
int rsa_generate(RSAKey *key, int bits, ProgressReceiver *prog);
|
||||
int dsa_generate(struct dss_key *key, int bits, ProgressReceiver *prog);
|
||||
int ecdsa_generate(struct ecdsa_key *key, int bits);
|
||||
int eddsa_generate(struct eddsa_key *key, int bits);
|
||||
mp_int *primegen(PrimeCandidateSource *pcs,
|
||||
int phase, progfn_t pfn, void *pfnparam);
|
||||
|
229
sshprime.c
229
sshprime.c
@ -3,8 +3,6 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ssh.h"
|
||||
#include "mpint.h"
|
||||
#include "mpunsafe.h"
|
||||
@ -28,54 +26,177 @@
|
||||
* - go back to square one if any M-R test fails.
|
||||
*/
|
||||
|
||||
ProgressPhase primegen_add_progress_phase(ProgressReceiver *prog,
|
||||
unsigned bits)
|
||||
{
|
||||
/*
|
||||
* The density of primes near x is 1/(log x). When x is about 2^b,
|
||||
* that's 1/(b log 2).
|
||||
/*
|
||||
* The Miller-Rabin primality test is an extension to the Fermat
|
||||
* test. The Fermat test just checks that a^(p-1) == 1 mod p; this
|
||||
* is vulnerable to Carmichael numbers. Miller-Rabin considers how
|
||||
* that 1 is derived as well.
|
||||
*
|
||||
* But we're only doing the expensive part of the process (the M-R
|
||||
* checks) for a number that passes the initial winnowing test of
|
||||
* having no factor less than 2^16 (at least, unless the prime is
|
||||
* so small that PrimeCandidateSource gives up on that winnowing).
|
||||
* The density of _those_ numbers is about 1/19.76. So the odds of
|
||||
* hitting a prime per expensive attempt are boosted by a factor
|
||||
* of 19.76.
|
||||
* Lemma: if a^2 == 1 (mod p), and p is prime, then either a == 1
|
||||
* or a == -1 (mod p).
|
||||
*
|
||||
* Proof: p divides a^2-1, i.e. p divides (a+1)(a-1). Hence,
|
||||
* since p is prime, either p divides (a+1) or p divides (a-1).
|
||||
* But this is the same as saying that either a is congruent to
|
||||
* -1 mod p or a is congruent to +1 mod p. []
|
||||
*
|
||||
* Comment: This fails when p is not prime. Consider p=mn, so
|
||||
* that mn divides (a+1)(a-1). Now we could have m dividing (a+1)
|
||||
* and n dividing (a-1), without the whole of mn dividing either.
|
||||
* For example, consider a=10 and p=99. 99 = 9 * 11; 9 divides
|
||||
* 10-1 and 11 divides 10+1, so a^2 is congruent to 1 mod p
|
||||
* without a having to be congruent to either 1 or -1.
|
||||
*
|
||||
* So the Miller-Rabin test, as well as considering a^(p-1),
|
||||
* considers a^((p-1)/2), a^((p-1)/4), and so on as far as it can
|
||||
* go. In other words. we write p-1 as q * 2^k, with k as large as
|
||||
* possible (i.e. q must be odd), and we consider the powers
|
||||
*
|
||||
* a^(q*2^0) a^(q*2^1) ... a^(q*2^(k-1)) a^(q*2^k)
|
||||
* i.e. a^((n-1)/2^k) a^((n-1)/2^(k-1)) ... a^((n-1)/2) a^(n-1)
|
||||
*
|
||||
* If p is to be prime, the last of these must be 1. Therefore, by
|
||||
* the above lemma, the one before it must be either 1 or -1. And
|
||||
* _if_ it's 1, then the one before that must be either 1 or -1,
|
||||
* and so on ... In other words, we expect to see a trailing chain
|
||||
* of 1s preceded by a -1. (If we're unlucky, our trailing chain of
|
||||
* 1s will be as long as the list so we'll never get to see what
|
||||
* lies before it. This doesn't count as a test failure because it
|
||||
* hasn't _proved_ that p is not prime.)
|
||||
*
|
||||
* For example, consider a=2 and p=1729. 1729 is a Carmichael
|
||||
* number: although it's not prime, it satisfies a^(p-1) == 1 mod p
|
||||
* for any a coprime to it. So the Fermat test wouldn't have a
|
||||
* problem with it at all, unless we happened to stumble on an a
|
||||
* which had a common factor.
|
||||
*
|
||||
* So. 1729 - 1 equals 27 * 2^6. So we look at
|
||||
*
|
||||
* 2^27 mod 1729 == 645
|
||||
* 2^108 mod 1729 == 1065
|
||||
* 2^216 mod 1729 == 1
|
||||
* 2^432 mod 1729 == 1
|
||||
* 2^864 mod 1729 == 1
|
||||
* 2^1728 mod 1729 == 1
|
||||
*
|
||||
* We do have a trailing string of 1s, so the Fermat test would
|
||||
* have been happy. But this trailing string of 1s is preceded by
|
||||
* 1065; whereas if 1729 were prime, we'd expect to see it preceded
|
||||
* by -1 (i.e. 1728.). Guards! Seize this impostor.
|
||||
*
|
||||
* (If we were unlucky, we might have tried a=16 instead of a=2;
|
||||
* now 16^27 mod 1729 == 1, so we would have seen a long string of
|
||||
* 1s and wouldn't have seen the thing _before_ the 1s. So, just
|
||||
* like the Fermat test, for a given p there may well exist values
|
||||
* of a which fail to show up its compositeness. So we try several,
|
||||
* just like the Fermat test. The difference is that Miller-Rabin
|
||||
* is not _in general_ fooled by Carmichael numbers.)
|
||||
*
|
||||
* Put simply, then, the Miller-Rabin test requires us to:
|
||||
*
|
||||
* 1. write p-1 as q * 2^k, with q odd
|
||||
* 2. compute z = (a^q) mod p.
|
||||
* 3. report success if z == 1 or z == -1.
|
||||
* 4. square z at most k-1 times, and report success if it becomes
|
||||
* -1 at any point.
|
||||
* 5. report failure otherwise.
|
||||
*
|
||||
* (We expect z to become -1 after at most k-1 squarings, because
|
||||
* if it became -1 after k squarings then a^(p-1) would fail to be
|
||||
* 1. And we don't need to investigate what happens after we see a
|
||||
* -1, because we _know_ that -1 squared is 1 modulo anything at
|
||||
* all, so after we've seen a -1 we can be sure of seeing nothing
|
||||
* but 1s.)
|
||||
*/
|
||||
const double log_2 = 0.693147180559945309417232121458;
|
||||
double winnow_factor = (bits < 32 ? 1.0 : 19.76);
|
||||
double prob = winnow_factor / (bits * log_2);
|
||||
|
||||
/*
|
||||
* Estimate the cost of prime generation as the cost of the M-R
|
||||
* modexps.
|
||||
*/
|
||||
double cost = (miller_rabin_checks_needed(bits) *
|
||||
estimate_modexp_cost(bits));
|
||||
return progress_add_probabilistic(prog, cost, prob);
|
||||
}
|
||||
|
||||
mp_int *primegen(PrimeCandidateSource *pcs, ProgressReceiver *prog)
|
||||
mp_int *primegen(PrimeCandidateSource *pcs,
|
||||
int phase, progfn_t pfn, void *pfnparam)
|
||||
{
|
||||
pcs_ready(pcs);
|
||||
|
||||
int progress = 0;
|
||||
|
||||
STARTOVER:
|
||||
|
||||
progress_report_attempt(prog);
|
||||
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
|
||||
|
||||
mp_int *p = pcs_generate(pcs);
|
||||
|
||||
MillerRabin *mr = miller_rabin_new(p);
|
||||
/*
|
||||
* Now apply the Miller-Rabin primality test a few times. First
|
||||
* work out how many checks are needed.
|
||||
*/
|
||||
unsigned checks =
|
||||
bits >= 1300 ? 2 : bits >= 850 ? 3 : bits >= 650 ? 4 :
|
||||
bits >= 550 ? 5 : bits >= 450 ? 6 : bits >= 400 ? 7 :
|
||||
bits >= 350 ? 8 : bits >= 300 ? 9 : bits >= 250 ? 12 :
|
||||
bits >= 200 ? 15 : bits >= 150 ? 18 : 27;
|
||||
|
||||
/*
|
||||
* Next, write p-1 as q*2^k.
|
||||
*/
|
||||
size_t k;
|
||||
for (k = 0; mp_get_bit(p, k) == !k; k++)
|
||||
continue; /* find first 1 bit in p-1 */
|
||||
mp_int *q = mp_rshift_safe(p, k);
|
||||
|
||||
/*
|
||||
* Set up stuff for the Miller-Rabin checks.
|
||||
*/
|
||||
mp_int *two = mp_from_integer(2);
|
||||
mp_int *pm1 = mp_copy(p);
|
||||
mp_sub_integer_into(pm1, pm1, 1);
|
||||
MontyContext *mc = monty_new(p);
|
||||
mp_int *m_pm1 = monty_import(mc, pm1);
|
||||
|
||||
bool known_bad = false;
|
||||
unsigned nchecks = miller_rabin_checks_needed(mp_get_nbits(p));
|
||||
for (unsigned check = 0; check < nchecks; check++) {
|
||||
if (!miller_rabin_test_random(mr)) {
|
||||
known_bad = true;
|
||||
|
||||
/*
|
||||
* Now, for each check ...
|
||||
*/
|
||||
for (unsigned check = 0; check < checks && !known_bad; check++) {
|
||||
/*
|
||||
* Invent a random number between 1 and p-1.
|
||||
*/
|
||||
mp_int *w = mp_random_in_range(two, pm1);
|
||||
monty_import_into(mc, w, w);
|
||||
|
||||
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
|
||||
|
||||
/*
|
||||
* Compute w^q mod p.
|
||||
*/
|
||||
mp_int *wqp = monty_pow(mc, w, q);
|
||||
mp_free(w);
|
||||
|
||||
/*
|
||||
* See if this is 1, or if it is -1, or if it becomes -1
|
||||
* when squared at most k-1 times.
|
||||
*/
|
||||
bool passed = false;
|
||||
|
||||
if (mp_cmp_eq(wqp, monty_identity(mc)) || mp_cmp_eq(wqp, m_pm1)) {
|
||||
passed = true;
|
||||
} else {
|
||||
for (size_t i = 0; i < k - 1; i++) {
|
||||
monty_mul_into(mc, wqp, wqp, wqp);
|
||||
if (mp_cmp_eq(wqp, m_pm1)) {
|
||||
passed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
miller_rabin_free(mr);
|
||||
}
|
||||
|
||||
if (!passed)
|
||||
known_bad = true;
|
||||
|
||||
mp_free(wqp);
|
||||
}
|
||||
|
||||
mp_free(q);
|
||||
mp_free(two);
|
||||
mp_free(pm1);
|
||||
monty_free(mc);
|
||||
mp_free(m_pm1);
|
||||
|
||||
if (known_bad) {
|
||||
mp_free(p);
|
||||
@ -88,39 +209,3 @@ mp_int *primegen(PrimeCandidateSource *pcs, ProgressReceiver *prog)
|
||||
pcs_free(pcs);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Reusable null implementation of the progress-reporting API.
|
||||
*/
|
||||
|
||||
ProgressPhase null_progress_add_probabilistic(
|
||||
ProgressReceiver *prog, double c, double p) {
|
||||
ProgressPhase ph = { .n = 0 };
|
||||
return ph;
|
||||
}
|
||||
void null_progress_ready(ProgressReceiver *prog) {}
|
||||
void null_progress_start_phase(ProgressReceiver *prog, ProgressPhase phase) {}
|
||||
void null_progress_report_attempt(ProgressReceiver *prog) {}
|
||||
void null_progress_report_phase_complete(ProgressReceiver *prog) {}
|
||||
const ProgressReceiverVtable null_progress_vt = {
|
||||
null_progress_add_probabilistic,
|
||||
null_progress_ready,
|
||||
null_progress_start_phase,
|
||||
null_progress_report_attempt,
|
||||
null_progress_report_phase_complete,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Helper function for progress estimation.
|
||||
*/
|
||||
|
||||
double estimate_modexp_cost(unsigned bits)
|
||||
{
|
||||
/*
|
||||
* A modexp of n bits goes roughly like O(n^2.58), on the grounds
|
||||
* that our modmul is O(n^1.58) (Karatsuba) and you need O(n) of
|
||||
* them in a modexp.
|
||||
*/
|
||||
return pow(bits, 2.58);
|
||||
}
|
||||
|
56
sshrsag.c
56
sshrsag.c
@ -14,12 +14,49 @@
|
||||
static void invent_firstbits(unsigned *one, unsigned *two,
|
||||
unsigned min_separation);
|
||||
|
||||
int rsa_generate(RSAKey *key, int bits, ProgressReceiver *prog)
|
||||
int rsa_generate(RSAKey *key, int bits, progfn_t pfn,
|
||||
void *pfnparam)
|
||||
{
|
||||
unsigned pfirst, qfirst;
|
||||
|
||||
key->sshk.vt = &ssh_rsa;
|
||||
|
||||
/*
|
||||
* Set up the phase limits for the progress report. We do this
|
||||
* by passing minus the phase number.
|
||||
*
|
||||
* For prime generation: our initial filter finds things
|
||||
* coprime to everything below 2^16. Computing the product of
|
||||
* (p-1)/p for all prime p below 2^16 gives about 20.33; so
|
||||
* among B-bit integers, one in every 20.33 will get through
|
||||
* the initial filter to be a candidate prime.
|
||||
*
|
||||
* Meanwhile, we are searching for primes in the region of 2^B;
|
||||
* since pi(x) ~ x/log(x), when x is in the region of 2^B, the
|
||||
* prime density will be d/dx pi(x) ~ 1/log(B), i.e. about
|
||||
* 1/0.6931B. So the chance of any given candidate being prime
|
||||
* is 20.33/0.6931B, which is roughly 29.34 divided by B.
|
||||
*
|
||||
* So now we have this probability P, we're looking at an
|
||||
* exponential distribution with parameter P: we will manage in
|
||||
* one attempt with probability P, in two with probability
|
||||
* P(1-P), in three with probability P(1-P)^2, etc. The
|
||||
* probability that we have still not managed to find a prime
|
||||
* after N attempts is (1-P)^N.
|
||||
*
|
||||
* We therefore inform the progress indicator of the number B
|
||||
* (29.34/B), so that it knows how much to increment by each
|
||||
* time. We do this in 16-bit fixed point, so 29.34 becomes
|
||||
* 0x1D.57C4.
|
||||
*/
|
||||
pfn(pfnparam, PROGFN_PHASE_EXTENT, 1, 0x10000);
|
||||
pfn(pfnparam, PROGFN_EXP_PHASE, 1, -0x1D57C4 / (bits / 2));
|
||||
pfn(pfnparam, PROGFN_PHASE_EXTENT, 2, 0x10000);
|
||||
pfn(pfnparam, PROGFN_EXP_PHASE, 2, -0x1D57C4 / (bits - bits / 2));
|
||||
pfn(pfnparam, PROGFN_PHASE_EXTENT, 3, 0x4000);
|
||||
pfn(pfnparam, PROGFN_LIN_PHASE, 3, 5);
|
||||
pfn(pfnparam, PROGFN_READY, 0, 0);
|
||||
|
||||
/*
|
||||
* We don't generate e; we just use a standard one always.
|
||||
*/
|
||||
@ -43,23 +80,15 @@ int rsa_generate(RSAKey *key, int bits, ProgressReceiver *prog)
|
||||
int pbits = bits - qbits;
|
||||
assert(pbits >= qbits);
|
||||
|
||||
ProgressPhase phase_p = primegen_add_progress_phase(prog, pbits);
|
||||
ProgressPhase phase_q = primegen_add_progress_phase(prog, qbits);
|
||||
progress_ready(prog);
|
||||
|
||||
PrimeCandidateSource *pcs;
|
||||
|
||||
progress_start_phase(prog, phase_p);
|
||||
pcs = pcs_new_with_firstbits(pbits, pfirst, NFIRSTBITS);
|
||||
pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1);
|
||||
mp_int *p = primegen(pcs, prog);
|
||||
progress_report_phase_complete(prog);
|
||||
mp_int *p = primegen(pcs, 1, pfn, pfnparam);
|
||||
|
||||
progress_start_phase(prog, phase_q);
|
||||
pcs = pcs_new_with_firstbits(qbits, qfirst, NFIRSTBITS);
|
||||
pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1);
|
||||
mp_int *q = primegen(pcs, prog);
|
||||
progress_report_phase_complete(prog);
|
||||
mp_int *q = primegen(pcs, 2, pfn, pfnparam);
|
||||
|
||||
/*
|
||||
* Ensure p > q, by swapping them if not.
|
||||
@ -79,17 +108,22 @@ int rsa_generate(RSAKey *key, int bits, ProgressReceiver *prog)
|
||||
* the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1),
|
||||
* and (q^-1 mod p).
|
||||
*/
|
||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 1);
|
||||
mp_int *modulus = mp_mul(p, q);
|
||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 2);
|
||||
mp_int *pm1 = mp_copy(p);
|
||||
mp_sub_integer_into(pm1, pm1, 1);
|
||||
mp_int *qm1 = mp_copy(q);
|
||||
mp_sub_integer_into(qm1, qm1, 1);
|
||||
mp_int *phi_n = mp_mul(pm1, qm1);
|
||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 3);
|
||||
mp_free(pm1);
|
||||
mp_free(qm1);
|
||||
mp_int *private_exponent = mp_invert(exponent, phi_n);
|
||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 4);
|
||||
mp_free(phi_n);
|
||||
mp_int *iqmp = mp_invert(q, p);
|
||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 5);
|
||||
|
||||
/*
|
||||
* Populate the returned structure.
|
||||
|
12
testcrypt.c
12
testcrypt.c
@ -1047,18 +1047,18 @@ strbuf *rsa1_save_sb_wrapper(RSAKey *key, const char *comment,
|
||||
|
||||
#define return_void(out, expression) (expression)
|
||||
|
||||
static ProgressReceiver null_progress = { .vt = &null_progress_vt };
|
||||
static void no_progress(void *param, int action, int phase, int iprogress) {}
|
||||
|
||||
mp_int *primegen_wrapper(PrimeCandidateSource *pcs)
|
||||
{
|
||||
return primegen(pcs, &null_progress);
|
||||
return primegen(pcs, 0, no_progress, NULL);
|
||||
}
|
||||
#define primegen primegen_wrapper
|
||||
|
||||
RSAKey *rsa1_generate(int bits)
|
||||
{
|
||||
RSAKey *rsakey = snew(RSAKey);
|
||||
rsa_generate(rsakey, bits, &null_progress);
|
||||
rsa_generate(rsakey, bits, no_progress, NULL);
|
||||
rsakey->comment = NULL;
|
||||
return rsakey;
|
||||
}
|
||||
@ -1072,7 +1072,7 @@ ssh_key *rsa_generate_wrapper(int bits)
|
||||
ssh_key *dsa_generate_wrapper(int bits)
|
||||
{
|
||||
struct dss_key *dsskey = snew(struct dss_key);
|
||||
dsa_generate(dsskey, bits, &null_progress);
|
||||
dsa_generate(dsskey, bits, no_progress, NULL);
|
||||
return &dsskey->sshk;
|
||||
}
|
||||
#define dsa_generate dsa_generate_wrapper
|
||||
@ -1080,7 +1080,7 @@ ssh_key *dsa_generate_wrapper(int bits)
|
||||
ssh_key *ecdsa_generate_wrapper(int bits)
|
||||
{
|
||||
struct ecdsa_key *ek = snew(struct ecdsa_key);
|
||||
if (!ecdsa_generate(ek, bits)) {
|
||||
if (!ecdsa_generate(ek, bits, no_progress, NULL)) {
|
||||
sfree(ek);
|
||||
return NULL;
|
||||
}
|
||||
@ -1091,7 +1091,7 @@ ssh_key *ecdsa_generate_wrapper(int bits)
|
||||
ssh_key *eddsa_generate_wrapper(int bits)
|
||||
{
|
||||
struct eddsa_key *ek = snew(struct eddsa_key);
|
||||
if (!eddsa_generate(ek, bits)) {
|
||||
if (!eddsa_generate(ek, bits, no_progress, NULL)) {
|
||||
sfree(ek);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshkeygen.h"
|
||||
#include "licence.h"
|
||||
#include "winsecur.h"
|
||||
|
||||
@ -60,106 +59,76 @@ void nonfatal(const char *fmt, ...)
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* ProgressReceiver implementation.
|
||||
* Progress report code. This is really horrible :-)
|
||||
*/
|
||||
|
||||
#define PROGRESSRANGE 65535
|
||||
#define MAXPHASE 5
|
||||
|
||||
struct progressphase {
|
||||
double startpoint, total;
|
||||
double exp_probability, exp_current_value;
|
||||
};
|
||||
|
||||
struct progress {
|
||||
int nphases;
|
||||
struct progressphase phases[MAXPHASE], *currphase;
|
||||
|
||||
double scale;
|
||||
struct {
|
||||
bool exponential;
|
||||
unsigned startpoint, total;
|
||||
unsigned param, current, n; /* if exponential */
|
||||
unsigned mult; /* if linear */
|
||||
} phases[MAXPHASE];
|
||||
unsigned total, divisor, range;
|
||||
HWND progbar;
|
||||
|
||||
ProgressReceiver rec;
|
||||
};
|
||||
|
||||
static ProgressPhase win_progress_add_probabilistic(
|
||||
ProgressReceiver *prog, double cost_per_attempt, double probability) {
|
||||
struct progress *p = container_of(prog, struct progress, rec);
|
||||
|
||||
assert(p->nphases < MAXPHASE);
|
||||
int phase = p->nphases++;
|
||||
|
||||
p->phases[phase].exp_probability = 1.0 - probability;
|
||||
p->phases[phase].exp_current_value = 1.0;
|
||||
/* Expected number of attempts = 1 / probability of attempt succeeding */
|
||||
p->phases[phase].total = cost_per_attempt / probability;
|
||||
|
||||
ProgressPhase ph = { .n = phase };
|
||||
return ph;
|
||||
}
|
||||
|
||||
static void win_progress_ready(ProgressReceiver *prog)
|
||||
static void progress_update(void *param, int action, int phase, int iprogress)
|
||||
{
|
||||
struct progress *p = container_of(prog, struct progress, rec);
|
||||
struct progress *p = (struct progress *) param;
|
||||
unsigned progress = iprogress;
|
||||
int position;
|
||||
|
||||
double total = 0;
|
||||
for (int i = 0; i < p->nphases; i++) {
|
||||
if (action < PROGFN_READY && p->nphases < phase)
|
||||
p->nphases = phase;
|
||||
switch (action) {
|
||||
case PROGFN_INITIALISE:
|
||||
p->nphases = 0;
|
||||
break;
|
||||
case PROGFN_LIN_PHASE:
|
||||
p->phases[phase-1].exponential = false;
|
||||
p->phases[phase-1].mult = p->phases[phase].total / progress;
|
||||
break;
|
||||
case PROGFN_EXP_PHASE:
|
||||
p->phases[phase-1].exponential = true;
|
||||
p->phases[phase-1].param = 0x10000 + progress;
|
||||
p->phases[phase-1].current = p->phases[phase-1].total;
|
||||
p->phases[phase-1].n = 0;
|
||||
break;
|
||||
case PROGFN_PHASE_EXTENT:
|
||||
p->phases[phase-1].total = progress;
|
||||
break;
|
||||
case PROGFN_READY: {
|
||||
unsigned total = 0;
|
||||
int i;
|
||||
for (i = 0; i < p->nphases; i++) {
|
||||
p->phases[i].startpoint = total;
|
||||
total += p->phases[i].total;
|
||||
}
|
||||
p->scale = PROGRESSRANGE / total;
|
||||
|
||||
SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESSRANGE));
|
||||
}
|
||||
|
||||
static void win_progress_start_phase(ProgressReceiver *prog,
|
||||
ProgressPhase phase)
|
||||
{
|
||||
struct progress *p = container_of(prog, struct progress, rec);
|
||||
|
||||
assert(phase.n < p->nphases);
|
||||
p->currphase = &p->phases[phase.n];
|
||||
}
|
||||
|
||||
static void win_progress_update(struct progress *p, double phasepos)
|
||||
{
|
||||
double position = (p->currphase->startpoint +
|
||||
p->currphase->total * phasepos);
|
||||
position *= p->scale;
|
||||
if (position < 0)
|
||||
position = 0;
|
||||
if (position > PROGRESSRANGE)
|
||||
position = PROGRESSRANGE;
|
||||
|
||||
SendMessage(p->progbar, PBM_SETPOS, (WPARAM)position, 0);
|
||||
}
|
||||
|
||||
static void win_progress_report_attempt(ProgressReceiver *prog)
|
||||
{
|
||||
struct progress *p = container_of(prog, struct progress, rec);
|
||||
|
||||
p->currphase->exp_current_value *= p->currphase->exp_probability;
|
||||
win_progress_update(p, 1.0 - p->currphase->exp_current_value);
|
||||
}
|
||||
|
||||
static void win_progress_report_phase_complete(ProgressReceiver *prog)
|
||||
{
|
||||
struct progress *p = container_of(prog, struct progress, rec);
|
||||
|
||||
win_progress_update(p, 1.0);
|
||||
}
|
||||
|
||||
static const ProgressReceiverVtable win_progress_vt = {
|
||||
win_progress_add_probabilistic,
|
||||
win_progress_ready,
|
||||
win_progress_start_phase,
|
||||
win_progress_report_attempt,
|
||||
win_progress_report_phase_complete,
|
||||
};
|
||||
|
||||
static void win_progress_initialise(struct progress *p)
|
||||
{
|
||||
p->nphases = 0;
|
||||
p->rec.vt = &win_progress_vt;
|
||||
p->total = total;
|
||||
p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
|
||||
p->range = p->total / p->divisor;
|
||||
SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, p->range));
|
||||
break;
|
||||
}
|
||||
case PROGFN_PROGRESS:
|
||||
if (p->phases[phase-1].exponential) {
|
||||
while (p->phases[phase-1].n < progress) {
|
||||
p->phases[phase-1].n++;
|
||||
p->phases[phase-1].current *= p->phases[phase-1].param;
|
||||
p->phases[phase-1].current /= 0x10000;
|
||||
}
|
||||
position = (p->phases[phase-1].startpoint +
|
||||
p->phases[phase-1].total - p->phases[phase-1].current);
|
||||
} else {
|
||||
position = (p->phases[phase-1].startpoint +
|
||||
progress * p->phases[phase-1].mult);
|
||||
}
|
||||
SendMessage(p->progbar, PBM_SETPOS, position / p->divisor, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct PassphraseProcStruct {
|
||||
@ -384,16 +353,17 @@ static DWORD WINAPI generate_key_thread(void *param)
|
||||
struct progress prog;
|
||||
prog.progbar = params->progressbar;
|
||||
|
||||
win_progress_initialise(&prog);
|
||||
progress_update(&prog, PROGFN_INITIALISE, 0, 0);
|
||||
|
||||
if (params->keytype == DSA)
|
||||
dsa_generate(params->dsskey, params->key_bits, &prog.rec);
|
||||
dsa_generate(params->dsskey, params->key_bits, progress_update, &prog);
|
||||
else if (params->keytype == ECDSA)
|
||||
ecdsa_generate(params->eckey, params->curve_bits);
|
||||
ecdsa_generate(params->eckey, params->curve_bits,
|
||||
progress_update, &prog);
|
||||
else if (params->keytype == ED25519)
|
||||
eddsa_generate(params->edkey, 255);
|
||||
eddsa_generate(params->edkey, 255, progress_update, &prog);
|
||||
else
|
||||
rsa_generate(params->key, params->key_bits, &prog.rec);
|
||||
rsa_generate(params->key, params->key_bits, progress_update, &prog);
|
||||
|
||||
PostMessage(params->dialog, WM_DONEKEY, 0, 0);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user