mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
a7bdefb394
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.
99 lines
2.9 KiB
C
99 lines
2.9 KiB
C
/*
|
|
* DSS key generation.
|
|
*/
|
|
|
|
#include "misc.h"
|
|
#include "ssh.h"
|
|
#include "sshkeygen.h"
|
|
#include "mpint.h"
|
|
|
|
int dsa_generate(struct dss_key *key, int bits, ProgressReceiver *prog)
|
|
{
|
|
/*
|
|
* Progress-reporting setup.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* (So the probability of success will end up indistinguishable
|
|
* from 1 in IEEE standard floating point! But what can you do.)
|
|
*/
|
|
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);
|
|
|
|
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);
|
|
|
|
/*
|
|
* 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);
|
|
|
|
/*
|
|
* Next we need g. Raise 2 to the power (p-1)/q modulo p, and
|
|
* if that comes out to one then try 3, then 4 and so on. As
|
|
* 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);
|
|
mp_int *g;
|
|
while (1) {
|
|
progress_report_attempt(prog);
|
|
g = mp_modpow(h, power, p);
|
|
if (mp_hs_integer(g, 2))
|
|
break; /* got one */
|
|
mp_free(g);
|
|
mp_add_integer_into(h, h, 1);
|
|
}
|
|
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,
|
|
* which should be a number between 1 and q-1 exclusive, and
|
|
* our public key y = g^x mod p.
|
|
*/
|
|
mp_int *two = mp_from_integer(2);
|
|
mp_int *qm1 = mp_copy(q);
|
|
mp_sub_integer_into(qm1, qm1, 1);
|
|
mp_int *x = mp_random_in_range(two, qm1);
|
|
mp_free(two);
|
|
mp_free(qm1);
|
|
|
|
key->sshk.vt = &ssh_dss;
|
|
|
|
key->p = p;
|
|
key->q = q;
|
|
key->g = g;
|
|
key->x = x;
|
|
key->y = mp_modpow(key->g, key->x, key->p);
|
|
|
|
return 1;
|
|
}
|