mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
New vtable API for keygen progress reporting.
The old API was one of those horrible things I used to do when I was young and foolish, in which you have just one function, and indicate which of lots of things it's doing by passing in flags. It was crying out to be replaced with a vtable. While I'm at it, I've reworked the code on the Windows side that decides what to do with the progress bar, so that it's based on actually justifiable estimates of probability rather than magic integer constants. Since computers are generally faster now than they were at the start of this project, I've also decided there's no longer any point in making the fixed final part of RSA key generation bother to report progress at all. So the progress bars are now only for the variable part, i.e. the actual prime generations.
This commit is contained in:
parent
63b8f537f2
commit
a7bdefb394
2
Recipe
2
Recipe
@ -282,7 +282,7 @@ UXSSH = SSH uxnoise uxagentc uxgss uxshare
|
|||||||
SFTP = psftpcommon sftp sftpcommon logging cmdline
|
SFTP = psftpcommon sftp sftpcommon logging cmdline
|
||||||
|
|
||||||
# Components of the prime-generation system.
|
# Components of the prime-generation system.
|
||||||
SSHPRIME = sshprime smallprimes primecandidate mpunsafe
|
SSHPRIME = sshprime smallprimes primecandidate millerrabin mpunsafe
|
||||||
|
|
||||||
# Miscellaneous objects appearing in all the utilities, or all the
|
# Miscellaneous objects appearing in all the utilities, or all the
|
||||||
# network ones, or the Unix or Windows subsets of those in turn.
|
# network ones, or the Unix or Windows subsets of those in turn.
|
||||||
|
70
cmdgen.c
70
cmdgen.c
@ -13,36 +13,35 @@
|
|||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#include "sshkeygen.h"
|
||||||
#include "mpint.h"
|
#include "mpint.h"
|
||||||
|
|
||||||
struct progress {
|
FILE *progress_fp = NULL;
|
||||||
int phase, current;
|
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void progress_update(void *param, int action, int phase, int iprogress)
|
static ProgressReceiver cmdgen_progress = { .vt = &cmdgen_progress_vt };
|
||||||
{
|
|
||||||
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.
|
* Stubs to let everything else link sensibly.
|
||||||
@ -184,10 +183,12 @@ int main(int argc, char **argv)
|
|||||||
char *ssh2alg = NULL;
|
char *ssh2alg = NULL;
|
||||||
char *old_passphrase = NULL, *new_passphrase = NULL;
|
char *old_passphrase = NULL, *new_passphrase = NULL;
|
||||||
bool load_encrypted;
|
bool load_encrypted;
|
||||||
progfn_t progressfn = is_interactive() ? progress_update : no_progress;
|
|
||||||
const char *random_device = NULL;
|
const char *random_device = NULL;
|
||||||
int exit_status = 0;
|
int exit_status = 0;
|
||||||
|
|
||||||
|
if (is_interactive())
|
||||||
|
progress_fp = stderr;
|
||||||
|
|
||||||
#define RETURN(status) do { exit_status = (status); goto out; } while (0)
|
#define RETURN(status) do { exit_status = (status); goto out; } while (0)
|
||||||
|
|
||||||
/* ------------------------------------------------------------------
|
/* ------------------------------------------------------------------
|
||||||
@ -333,7 +334,7 @@ int main(int argc, char **argv)
|
|||||||
outtype = PUBLIC;
|
outtype = PUBLIC;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
progressfn = no_progress;
|
progress_fp = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -645,10 +646,6 @@ int main(int argc, char **argv)
|
|||||||
char *entropy;
|
char *entropy;
|
||||||
char default_comment[80];
|
char default_comment[80];
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
struct progress prog;
|
|
||||||
|
|
||||||
prog.phase = -1;
|
|
||||||
prog.current = -1;
|
|
||||||
|
|
||||||
tm = ltime();
|
tm = ltime();
|
||||||
if (keytype == DSA)
|
if (keytype == DSA)
|
||||||
@ -673,25 +670,25 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (keytype == DSA) {
|
if (keytype == DSA) {
|
||||||
struct dss_key *dsskey = snew(struct dss_key);
|
struct dss_key *dsskey = snew(struct dss_key);
|
||||||
dsa_generate(dsskey, bits, progressfn, &prog);
|
dsa_generate(dsskey, bits, &cmdgen_progress);
|
||||||
ssh2key = snew(ssh2_userkey);
|
ssh2key = snew(ssh2_userkey);
|
||||||
ssh2key->key = &dsskey->sshk;
|
ssh2key->key = &dsskey->sshk;
|
||||||
ssh1key = NULL;
|
ssh1key = NULL;
|
||||||
} else if (keytype == ECDSA) {
|
} else if (keytype == ECDSA) {
|
||||||
struct ecdsa_key *ek = snew(struct ecdsa_key);
|
struct ecdsa_key *ek = snew(struct ecdsa_key);
|
||||||
ecdsa_generate(ek, bits, progressfn, &prog);
|
ecdsa_generate(ek, bits);
|
||||||
ssh2key = snew(ssh2_userkey);
|
ssh2key = snew(ssh2_userkey);
|
||||||
ssh2key->key = &ek->sshk;
|
ssh2key->key = &ek->sshk;
|
||||||
ssh1key = NULL;
|
ssh1key = NULL;
|
||||||
} else if (keytype == ED25519) {
|
} else if (keytype == ED25519) {
|
||||||
struct eddsa_key *ek = snew(struct eddsa_key);
|
struct eddsa_key *ek = snew(struct eddsa_key);
|
||||||
eddsa_generate(ek, bits, progressfn, &prog);
|
eddsa_generate(ek, bits);
|
||||||
ssh2key = snew(ssh2_userkey);
|
ssh2key = snew(ssh2_userkey);
|
||||||
ssh2key->key = &ek->sshk;
|
ssh2key->key = &ek->sshk;
|
||||||
ssh1key = NULL;
|
ssh1key = NULL;
|
||||||
} else {
|
} else {
|
||||||
RSAKey *rsakey = snew(RSAKey);
|
RSAKey *rsakey = snew(RSAKey);
|
||||||
rsa_generate(rsakey, bits, progressfn, &prog);
|
rsa_generate(rsakey, bits, &cmdgen_progress);
|
||||||
rsakey->comment = NULL;
|
rsakey->comment = NULL;
|
||||||
if (keytype == RSA1) {
|
if (keytype == RSA1) {
|
||||||
ssh1key = rsakey;
|
ssh1key = rsakey;
|
||||||
@ -700,7 +697,6 @@ int main(int argc, char **argv)
|
|||||||
ssh2key->key = &rsakey->sshk;
|
ssh2key->key = &rsakey->sshk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
progressfn(&prog, PROGFN_PROGRESS, INT_MAX, -1);
|
|
||||||
|
|
||||||
if (ssh2key)
|
if (ssh2key)
|
||||||
ssh2key->comment = dupstr(default_comment);
|
ssh2key->comment = dupstr(default_comment);
|
||||||
|
214
millerrabin.c
Normal file
214
millerrabin.c
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* 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,26 +1313,6 @@ void openssh_bcrypt(const char *passphrase,
|
|||||||
const unsigned char *salt, int saltbytes,
|
const unsigned char *salt, int saltbytes,
|
||||||
int rounds, unsigned char *out, int outbytes);
|
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
|
* Connection-sharing API provided by platforms. This function must
|
||||||
* either:
|
* either:
|
||||||
|
@ -70,8 +70,6 @@ static const struct PacketProtocolLayerVtable ssh1_login_server_vtable = {
|
|||||||
NULL /* no layer names in SSH-1 */,
|
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 *ssh1_login_server_new(
|
||||||
PacketProtocolLayer *successor_layer, RSAKey *hostkey,
|
PacketProtocolLayer *successor_layer, RSAKey *hostkey,
|
||||||
AuthPolicy *authpolicy, const SshServerConfig *ssc)
|
AuthPolicy *authpolicy, const SshServerConfig *ssc)
|
||||||
@ -142,7 +140,9 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
|
|||||||
if (server_key_bits < 512)
|
if (server_key_bits < 512)
|
||||||
server_key_bits = s->hostkey->bytes + 256;
|
server_key_bits = s->hostkey->bytes + 256;
|
||||||
s->servkey = snew(RSAKey);
|
s->servkey = snew(RSAKey);
|
||||||
rsa_generate(s->servkey, server_key_bits, no_progress, NULL);
|
ProgressReceiver null_progress;
|
||||||
|
null_progress.vt = &null_progress_vt;
|
||||||
|
rsa_generate(s->servkey, server_key_bits, &null_progress);
|
||||||
s->servkey->comment = NULL;
|
s->servkey->comment = NULL;
|
||||||
s->servkey_generated_here = true;
|
s->servkey_generated_here = true;
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,6 @@ static strbuf *finalise_and_sign_exhash(struct ssh2_transport_state *s)
|
|||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void no_progress(void *param, int action, int phase, int iprogress)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
|
void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
|
||||||
{
|
{
|
||||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||||
@ -101,7 +97,9 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
|
|||||||
* group! It's good enough for testing a client against,
|
* group! It's good enough for testing a client against,
|
||||||
* but not for serious use.
|
* but not for serious use.
|
||||||
*/
|
*/
|
||||||
s->p = primegen(pcs_new(s->pbits), 1, no_progress, NULL);
|
ProgressReceiver null_progress;
|
||||||
|
null_progress.vt = &null_progress_vt;
|
||||||
|
s->p = primegen(pcs_new(s->pbits), &null_progress);
|
||||||
s->g = mp_from_integer(2);
|
s->g = mp_from_integer(2);
|
||||||
s->dh_ctx = dh_setup_gex(s->p, s->g);
|
s->dh_ctx = dh_setup_gex(s->p, s->g);
|
||||||
s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;
|
s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;
|
||||||
@ -263,7 +261,9 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
|
|||||||
ppl_logevent("Generating a %d-bit RSA key", extra->minklen);
|
ppl_logevent("Generating a %d-bit RSA key", extra->minklen);
|
||||||
|
|
||||||
s->rsa_kex_key = snew(RSAKey);
|
s->rsa_kex_key = snew(RSAKey);
|
||||||
rsa_generate(s->rsa_kex_key, extra->minklen, no_progress, NULL);
|
ProgressReceiver null_progress;
|
||||||
|
null_progress.vt = &null_progress_vt;
|
||||||
|
rsa_generate(s->rsa_kex_key, extra->minklen, &null_progress);
|
||||||
s->rsa_kex_key->comment = NULL;
|
s->rsa_kex_key->comment = NULL;
|
||||||
s->rsa_kex_key_needs_freeing = true;
|
s->rsa_kex_key_needs_freeing = true;
|
||||||
}
|
}
|
||||||
|
74
sshdssg.c
74
sshdssg.c
@ -7,71 +7,50 @@
|
|||||||
#include "sshkeygen.h"
|
#include "sshkeygen.h"
|
||||||
#include "mpint.h"
|
#include "mpint.h"
|
||||||
|
|
||||||
int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
|
int dsa_generate(struct dss_key *key, int bits, ProgressReceiver *prog)
|
||||||
void *pfnparam)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Set up the phase limits for the progress report. We do this
|
* Progress-reporting setup.
|
||||||
* by passing minus the phase number.
|
|
||||||
*
|
*
|
||||||
* For prime generation: our initial filter finds things
|
* DSA generation involves three potentially long jobs: inventing
|
||||||
* coprime to everything below 2^16. Computing the product of
|
* the small prime q, the large prime p, and finding an order-q
|
||||||
* (p-1)/p for all prime p below 2^16 gives about 20.33; so
|
* element of the multiplicative group of p.
|
||||||
* 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;
|
* The latter is done by finding an element whose order is
|
||||||
* since pi(x) ~ x/log(x), when x is in the region of 2^B, the
|
* _divisible_ by q and raising it to the power of (p-1)/q. Every
|
||||||
* prime density will be d/dx pi(x) ~ 1/log(B), i.e. about
|
* element whose order is not divisible by q is a qth power of q
|
||||||
* 1/0.6931B. So the chance of any given candidate being prime
|
* distinct elements whose order _is_ divisible by q, so the
|
||||||
* is 20.33/0.6931B, which is roughly 29.34 divided by B.
|
* probability of not finding a suitable element on the first try
|
||||||
|
* is in the region of 1/q, i.e. at most 2^-159.
|
||||||
*
|
*
|
||||||
* So now we have this probability P, we're looking at an
|
* (So the probability of success will end up indistinguishable
|
||||||
* exponential distribution with parameter P: we will manage in
|
* from 1 in IEEE standard floating point! But what can you do.)
|
||||||
* 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, 0x2800);
|
ProgressPhase phase_q = primegen_add_progress_phase(prog, 160);
|
||||||
pfn(pfnparam, PROGFN_EXP_PHASE, 1, -0x1D57C4 / 160);
|
ProgressPhase phase_p = primegen_add_progress_phase(prog, bits);
|
||||||
pfn(pfnparam, PROGFN_PHASE_EXTENT, 2, 0x40 * bits);
|
ProgressPhase phase_g = progress_add_probabilistic(
|
||||||
pfn(pfnparam, PROGFN_EXP_PHASE, 2, -0x1D57C4 / bits);
|
prog, estimate_modexp_cost(bits), 1.0 - 0x1.0p-159);
|
||||||
|
progress_ready(prog);
|
||||||
/*
|
|
||||||
* 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;
|
PrimeCandidateSource *pcs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate q: a prime of length 160.
|
* Generate q: a prime of length 160.
|
||||||
*/
|
*/
|
||||||
|
progress_start_phase(prog, phase_q);
|
||||||
pcs = pcs_new(160);
|
pcs = pcs_new(160);
|
||||||
mp_int *q = primegen(pcs, 1, pfn, pfnparam);
|
mp_int *q = primegen(pcs, prog);
|
||||||
|
progress_report_phase_complete(prog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now generate p: a prime of length `bits', such that p-1 is
|
* Now generate p: a prime of length `bits', such that p-1 is
|
||||||
* divisible by q.
|
* divisible by q.
|
||||||
*/
|
*/
|
||||||
|
progress_start_phase(prog, phase_p);
|
||||||
pcs = pcs_new(bits);
|
pcs = pcs_new(bits);
|
||||||
pcs_require_residue_1(pcs, q);
|
pcs_require_residue_1(pcs, q);
|
||||||
mp_int *p = primegen(pcs, 2, pfn, pfnparam);
|
mp_int *p = primegen(pcs, prog);
|
||||||
|
progress_report_phase_complete(prog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next we need g. Raise 2 to the power (p-1)/q modulo p, and
|
* Next we need g. Raise 2 to the power (p-1)/q modulo p, and
|
||||||
@ -79,12 +58,12 @@ int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
|
|||||||
* soon as we hit a non-unit (and non-zero!) one, that'll do
|
* soon as we hit a non-unit (and non-zero!) one, that'll do
|
||||||
* for g.
|
* 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 *power = mp_div(p, q); /* this is floor(p/q) == (p-1)/q */
|
||||||
mp_int *h = mp_from_integer(1);
|
mp_int *h = mp_from_integer(1);
|
||||||
int progress = 0;
|
|
||||||
mp_int *g;
|
mp_int *g;
|
||||||
while (1) {
|
while (1) {
|
||||||
pfn(pfnparam, PROGFN_PROGRESS, 3, ++progress);
|
progress_report_attempt(prog);
|
||||||
g = mp_modpow(h, power, p);
|
g = mp_modpow(h, power, p);
|
||||||
if (mp_hs_integer(g, 2))
|
if (mp_hs_integer(g, 2))
|
||||||
break; /* got one */
|
break; /* got one */
|
||||||
@ -93,6 +72,7 @@ int dsa_generate(struct dss_key *key, int bits, progfn_t pfn,
|
|||||||
}
|
}
|
||||||
mp_free(h);
|
mp_free(h);
|
||||||
mp_free(power);
|
mp_free(power);
|
||||||
|
progress_report_phase_complete(prog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we're nearly done. All we need now is our private key x,
|
* Now we're nearly done. All we need now is our private key x,
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#include "sshkeygen.h"
|
||||||
#include "mpint.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))
|
if (!ec_nist_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt))
|
||||||
return 0;
|
return 0;
|
||||||
@ -20,8 +20,7 @@ int ecdsa_generate(struct ecdsa_key *ek, int bits,
|
|||||||
return 1;
|
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))
|
if (!ec_ed_alg_and_curve_by_bits(bits, &ek->curve, &ek->sshk.vt))
|
||||||
return 0;
|
return 0;
|
||||||
|
93
sshkeygen.h
93
sshkeygen.h
@ -67,10 +67,99 @@ void pcs_inspect(PrimeCandidateSource *pcs, mp_int **limit_out,
|
|||||||
/* Query functions for primegen to use */
|
/* Query functions for primegen to use */
|
||||||
unsigned pcs_get_bits(PrimeCandidateSource *pcs);
|
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.
|
* The top-level API for generating primes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This function consumes and frees the PrimeCandidateSource you give it */
|
/* This function consumes and frees the PrimeCandidateSource you give it */
|
||||||
mp_int *primegen(PrimeCandidateSource *pcs,
|
mp_int *primegen(PrimeCandidateSource *pcs, ProgressReceiver *prog);
|
||||||
int phase, progfn_t pfn, void *pfnparam);
|
|
||||||
|
/* 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);
|
||||||
|
235
sshprime.c
235
sshprime.c
@ -3,6 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "mpint.h"
|
#include "mpint.h"
|
||||||
#include "mpunsafe.h"
|
#include "mpunsafe.h"
|
||||||
@ -26,177 +28,54 @@
|
|||||||
* - go back to square one if any M-R test fails.
|
* - go back to square one if any M-R test fails.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
ProgressPhase primegen_add_progress_phase(ProgressReceiver *prog,
|
||||||
* The Miller-Rabin primality test is an extension to the Fermat
|
unsigned bits)
|
||||||
* 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.
|
* The density of primes near x is 1/(log x). When x is about 2^b,
|
||||||
*
|
* that's 1/(b log 2).
|
||||||
* Lemma: if a^2 == 1 (mod p), and p is prime, then either a == 1
|
*
|
||||||
* or a == -1 (mod p).
|
* 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
|
||||||
* Proof: p divides a^2-1, i.e. p divides (a+1)(a-1). Hence,
|
* having no factor less than 2^16 (at least, unless the prime is
|
||||||
* since p is prime, either p divides (a+1) or p divides (a-1).
|
* so small that PrimeCandidateSource gives up on that winnowing).
|
||||||
* But this is the same as saying that either a is congruent to
|
* The density of _those_ numbers is about 1/19.76. So the odds of
|
||||||
* -1 mod p or a is congruent to +1 mod p. []
|
* hitting a prime per expensive attempt are boosted by a factor
|
||||||
*
|
* of 19.76.
|
||||||
* 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)
|
const double log_2 = 0.693147180559945309417232121458;
|
||||||
* and n dividing (a-1), without the whole of mn dividing either.
|
double winnow_factor = (bits < 32 ? 1.0 : 19.76);
|
||||||
* For example, consider a=10 and p=99. 99 = 9 * 11; 9 divides
|
double prob = winnow_factor / (bits * log_2);
|
||||||
* 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.
|
/*
|
||||||
*
|
* Estimate the cost of prime generation as the cost of the M-R
|
||||||
* So the Miller-Rabin test, as well as considering a^(p-1),
|
* modexps.
|
||||||
* 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
|
double cost = (miller_rabin_checks_needed(bits) *
|
||||||
* possible (i.e. q must be odd), and we consider the powers
|
estimate_modexp_cost(bits));
|
||||||
*
|
return progress_add_probabilistic(prog, cost, prob);
|
||||||
* 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)
|
|
||||||
*
|
mp_int *primegen(PrimeCandidateSource *pcs, ProgressReceiver *prog)
|
||||||
* 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.)
|
|
||||||
*/
|
|
||||||
mp_int *primegen(PrimeCandidateSource *pcs,
|
|
||||||
int phase, progfn_t pfn, void *pfnparam)
|
|
||||||
{
|
{
|
||||||
pcs_ready(pcs);
|
pcs_ready(pcs);
|
||||||
|
|
||||||
int progress = 0;
|
|
||||||
|
|
||||||
STARTOVER:
|
STARTOVER:
|
||||||
|
|
||||||
pfn(pfnparam, PROGFN_PROGRESS, phase, ++progress);
|
progress_report_attempt(prog);
|
||||||
|
|
||||||
mp_int *p = pcs_generate(pcs);
|
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;
|
bool known_bad = false;
|
||||||
|
unsigned nchecks = miller_rabin_checks_needed(mp_get_nbits(p));
|
||||||
/*
|
for (unsigned check = 0; check < nchecks; check++) {
|
||||||
* Now, for each check ...
|
if (!miller_rabin_test_random(mr)) {
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!passed)
|
|
||||||
known_bad = true;
|
known_bad = true;
|
||||||
|
break;
|
||||||
mp_free(wqp);
|
}
|
||||||
}
|
}
|
||||||
|
miller_rabin_free(mr);
|
||||||
mp_free(q);
|
|
||||||
mp_free(two);
|
|
||||||
mp_free(pm1);
|
|
||||||
monty_free(mc);
|
|
||||||
mp_free(m_pm1);
|
|
||||||
|
|
||||||
if (known_bad) {
|
if (known_bad) {
|
||||||
mp_free(p);
|
mp_free(p);
|
||||||
@ -209,3 +88,39 @@ mp_int *primegen(PrimeCandidateSource *pcs,
|
|||||||
pcs_free(pcs);
|
pcs_free(pcs);
|
||||||
return p;
|
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,49 +14,12 @@
|
|||||||
static void invent_firstbits(unsigned *one, unsigned *two,
|
static void invent_firstbits(unsigned *one, unsigned *two,
|
||||||
unsigned min_separation);
|
unsigned min_separation);
|
||||||
|
|
||||||
int rsa_generate(RSAKey *key, int bits, progfn_t pfn,
|
int rsa_generate(RSAKey *key, int bits, ProgressReceiver *prog)
|
||||||
void *pfnparam)
|
|
||||||
{
|
{
|
||||||
unsigned pfirst, qfirst;
|
unsigned pfirst, qfirst;
|
||||||
|
|
||||||
key->sshk.vt = &ssh_rsa;
|
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.
|
* We don't generate e; we just use a standard one always.
|
||||||
*/
|
*/
|
||||||
@ -80,15 +43,23 @@ int rsa_generate(RSAKey *key, int bits, progfn_t pfn,
|
|||||||
int pbits = bits - qbits;
|
int pbits = bits - qbits;
|
||||||
assert(pbits >= 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;
|
PrimeCandidateSource *pcs;
|
||||||
|
|
||||||
|
progress_start_phase(prog, phase_p);
|
||||||
pcs = pcs_new_with_firstbits(pbits, pfirst, NFIRSTBITS);
|
pcs = pcs_new_with_firstbits(pbits, pfirst, NFIRSTBITS);
|
||||||
pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1);
|
pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1);
|
||||||
mp_int *p = primegen(pcs, 1, pfn, pfnparam);
|
mp_int *p = primegen(pcs, prog);
|
||||||
|
progress_report_phase_complete(prog);
|
||||||
|
|
||||||
|
progress_start_phase(prog, phase_q);
|
||||||
pcs = pcs_new_with_firstbits(qbits, qfirst, NFIRSTBITS);
|
pcs = pcs_new_with_firstbits(qbits, qfirst, NFIRSTBITS);
|
||||||
pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1);
|
pcs_avoid_residue_small(pcs, RSA_EXPONENT, 1);
|
||||||
mp_int *q = primegen(pcs, 2, pfn, pfnparam);
|
mp_int *q = primegen(pcs, prog);
|
||||||
|
progress_report_phase_complete(prog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure p > q, by swapping them if not.
|
* Ensure p > q, by swapping them if not.
|
||||||
@ -108,22 +79,17 @@ int rsa_generate(RSAKey *key, int bits, progfn_t pfn,
|
|||||||
* the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1),
|
* the other helpful quantities: n=pq, d=e^-1 mod (p-1)(q-1),
|
||||||
* and (q^-1 mod p).
|
* and (q^-1 mod p).
|
||||||
*/
|
*/
|
||||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 1);
|
|
||||||
mp_int *modulus = mp_mul(p, q);
|
mp_int *modulus = mp_mul(p, q);
|
||||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 2);
|
|
||||||
mp_int *pm1 = mp_copy(p);
|
mp_int *pm1 = mp_copy(p);
|
||||||
mp_sub_integer_into(pm1, pm1, 1);
|
mp_sub_integer_into(pm1, pm1, 1);
|
||||||
mp_int *qm1 = mp_copy(q);
|
mp_int *qm1 = mp_copy(q);
|
||||||
mp_sub_integer_into(qm1, qm1, 1);
|
mp_sub_integer_into(qm1, qm1, 1);
|
||||||
mp_int *phi_n = mp_mul(pm1, qm1);
|
mp_int *phi_n = mp_mul(pm1, qm1);
|
||||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 3);
|
|
||||||
mp_free(pm1);
|
mp_free(pm1);
|
||||||
mp_free(qm1);
|
mp_free(qm1);
|
||||||
mp_int *private_exponent = mp_invert(exponent, phi_n);
|
mp_int *private_exponent = mp_invert(exponent, phi_n);
|
||||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 4);
|
|
||||||
mp_free(phi_n);
|
mp_free(phi_n);
|
||||||
mp_int *iqmp = mp_invert(q, p);
|
mp_int *iqmp = mp_invert(q, p);
|
||||||
pfn(pfnparam, PROGFN_PROGRESS, 3, 5);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate the returned structure.
|
* 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)
|
#define return_void(out, expression) (expression)
|
||||||
|
|
||||||
static void no_progress(void *param, int action, int phase, int iprogress) {}
|
static ProgressReceiver null_progress = { .vt = &null_progress_vt };
|
||||||
|
|
||||||
mp_int *primegen_wrapper(PrimeCandidateSource *pcs)
|
mp_int *primegen_wrapper(PrimeCandidateSource *pcs)
|
||||||
{
|
{
|
||||||
return primegen(pcs, 0, no_progress, NULL);
|
return primegen(pcs, &null_progress);
|
||||||
}
|
}
|
||||||
#define primegen primegen_wrapper
|
#define primegen primegen_wrapper
|
||||||
|
|
||||||
RSAKey *rsa1_generate(int bits)
|
RSAKey *rsa1_generate(int bits)
|
||||||
{
|
{
|
||||||
RSAKey *rsakey = snew(RSAKey);
|
RSAKey *rsakey = snew(RSAKey);
|
||||||
rsa_generate(rsakey, bits, no_progress, NULL);
|
rsa_generate(rsakey, bits, &null_progress);
|
||||||
rsakey->comment = NULL;
|
rsakey->comment = NULL;
|
||||||
return rsakey;
|
return rsakey;
|
||||||
}
|
}
|
||||||
@ -1072,7 +1072,7 @@ ssh_key *rsa_generate_wrapper(int bits)
|
|||||||
ssh_key *dsa_generate_wrapper(int bits)
|
ssh_key *dsa_generate_wrapper(int bits)
|
||||||
{
|
{
|
||||||
struct dss_key *dsskey = snew(struct dss_key);
|
struct dss_key *dsskey = snew(struct dss_key);
|
||||||
dsa_generate(dsskey, bits, no_progress, NULL);
|
dsa_generate(dsskey, bits, &null_progress);
|
||||||
return &dsskey->sshk;
|
return &dsskey->sshk;
|
||||||
}
|
}
|
||||||
#define dsa_generate dsa_generate_wrapper
|
#define dsa_generate dsa_generate_wrapper
|
||||||
@ -1080,7 +1080,7 @@ ssh_key *dsa_generate_wrapper(int bits)
|
|||||||
ssh_key *ecdsa_generate_wrapper(int bits)
|
ssh_key *ecdsa_generate_wrapper(int bits)
|
||||||
{
|
{
|
||||||
struct ecdsa_key *ek = snew(struct ecdsa_key);
|
struct ecdsa_key *ek = snew(struct ecdsa_key);
|
||||||
if (!ecdsa_generate(ek, bits, no_progress, NULL)) {
|
if (!ecdsa_generate(ek, bits)) {
|
||||||
sfree(ek);
|
sfree(ek);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1091,7 +1091,7 @@ ssh_key *ecdsa_generate_wrapper(int bits)
|
|||||||
ssh_key *eddsa_generate_wrapper(int bits)
|
ssh_key *eddsa_generate_wrapper(int bits)
|
||||||
{
|
{
|
||||||
struct eddsa_key *ek = snew(struct eddsa_key);
|
struct eddsa_key *ek = snew(struct eddsa_key);
|
||||||
if (!eddsa_generate(ek, bits, no_progress, NULL)) {
|
if (!eddsa_generate(ek, bits)) {
|
||||||
sfree(ek);
|
sfree(ek);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
|
#include "sshkeygen.h"
|
||||||
#include "licence.h"
|
#include "licence.h"
|
||||||
#include "winsecur.h"
|
#include "winsecur.h"
|
||||||
|
|
||||||
@ -59,76 +60,106 @@ void nonfatal(const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Progress report code. This is really horrible :-)
|
* ProgressReceiver implementation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PROGRESSRANGE 65535
|
#define PROGRESSRANGE 65535
|
||||||
#define MAXPHASE 5
|
#define MAXPHASE 5
|
||||||
struct progress {
|
|
||||||
int nphases;
|
struct progressphase {
|
||||||
struct {
|
double startpoint, total;
|
||||||
bool exponential;
|
double exp_probability, exp_current_value;
|
||||||
unsigned startpoint, total;
|
|
||||||
unsigned param, current, n; /* if exponential */
|
|
||||||
unsigned mult; /* if linear */
|
|
||||||
} phases[MAXPHASE];
|
|
||||||
unsigned total, divisor, range;
|
|
||||||
HWND progbar;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void progress_update(void *param, int action, int phase, int iprogress)
|
struct progress {
|
||||||
{
|
int nphases;
|
||||||
struct progress *p = (struct progress *) param;
|
struct progressphase phases[MAXPHASE], *currphase;
|
||||||
unsigned progress = iprogress;
|
|
||||||
int position;
|
|
||||||
|
|
||||||
if (action < PROGFN_READY && p->nphases < phase)
|
double scale;
|
||||||
p->nphases = phase;
|
HWND progbar;
|
||||||
switch (action) {
|
|
||||||
case PROGFN_INITIALISE:
|
ProgressReceiver rec;
|
||||||
p->nphases = 0;
|
};
|
||||||
break;
|
|
||||||
case PROGFN_LIN_PHASE:
|
static ProgressPhase win_progress_add_probabilistic(
|
||||||
p->phases[phase-1].exponential = false;
|
ProgressReceiver *prog, double cost_per_attempt, double probability) {
|
||||||
p->phases[phase-1].mult = p->phases[phase].total / progress;
|
struct progress *p = container_of(prog, struct progress, rec);
|
||||||
break;
|
|
||||||
case PROGFN_EXP_PHASE:
|
assert(p->nphases < MAXPHASE);
|
||||||
p->phases[phase-1].exponential = true;
|
int phase = p->nphases++;
|
||||||
p->phases[phase-1].param = 0x10000 + progress;
|
|
||||||
p->phases[phase-1].current = p->phases[phase-1].total;
|
p->phases[phase].exp_probability = 1.0 - probability;
|
||||||
p->phases[phase-1].n = 0;
|
p->phases[phase].exp_current_value = 1.0;
|
||||||
break;
|
/* Expected number of attempts = 1 / probability of attempt succeeding */
|
||||||
case PROGFN_PHASE_EXTENT:
|
p->phases[phase].total = cost_per_attempt / probability;
|
||||||
p->phases[phase-1].total = progress;
|
|
||||||
break;
|
ProgressPhase ph = { .n = phase };
|
||||||
case PROGFN_READY: {
|
return ph;
|
||||||
unsigned total = 0;
|
}
|
||||||
int i;
|
|
||||||
for (i = 0; i < p->nphases; i++) {
|
static void win_progress_ready(ProgressReceiver *prog)
|
||||||
p->phases[i].startpoint = total;
|
{
|
||||||
total += p->phases[i].total;
|
struct progress *p = container_of(prog, struct progress, rec);
|
||||||
}
|
|
||||||
p->total = total;
|
double total = 0;
|
||||||
p->divisor = ((p->total + PROGRESSRANGE - 1) / PROGRESSRANGE);
|
for (int i = 0; i < p->nphases; i++) {
|
||||||
p->range = p->total / p->divisor;
|
p->phases[i].startpoint = total;
|
||||||
SendMessage(p->progbar, PBM_SETRANGE, 0, MAKELPARAM(0, p->range));
|
total += p->phases[i].total;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PassphraseProcStruct {
|
struct PassphraseProcStruct {
|
||||||
@ -353,17 +384,16 @@ static DWORD WINAPI generate_key_thread(void *param)
|
|||||||
struct progress prog;
|
struct progress prog;
|
||||||
prog.progbar = params->progressbar;
|
prog.progbar = params->progressbar;
|
||||||
|
|
||||||
progress_update(&prog, PROGFN_INITIALISE, 0, 0);
|
win_progress_initialise(&prog);
|
||||||
|
|
||||||
if (params->keytype == DSA)
|
if (params->keytype == DSA)
|
||||||
dsa_generate(params->dsskey, params->key_bits, progress_update, &prog);
|
dsa_generate(params->dsskey, params->key_bits, &prog.rec);
|
||||||
else if (params->keytype == ECDSA)
|
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)
|
else if (params->keytype == ED25519)
|
||||||
eddsa_generate(params->edkey, 255, progress_update, &prog);
|
eddsa_generate(params->edkey, 255);
|
||||||
else
|
else
|
||||||
rsa_generate(params->key, params->key_bits, progress_update, &prog);
|
rsa_generate(params->key, params->key_bits, &prog.rec);
|
||||||
|
|
||||||
PostMessage(params->dialog, WM_DONEKEY, 0, 0);
|
PostMessage(params->dialog, WM_DONEKEY, 0, 0);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user