1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/sshdssg.c
Simon Tatham a7f409eb61 Fix VS 2015 build failure.
Thanks to Pavel Kryukov's CI for pointing this out: VS 2015 doesn't
support C99 hex floating-point literals.

(VS 2017 does, and in general we're treating this as a C99-permitted
code base these days. So I was tempted to just increase the minimum
required compiler version and leave this code as it is. But since the
use of that particular floating literal was so totally frivolous and
unnecessary, I think I'll leave that for another day when it's more
important!)
2020-03-01 08:31:07 +00:00

103 lines
3.1 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);
double g_failure_probability = 1.0
/ (double)(1ULL << 53)
/ (double)(1ULL << 53)
/ (double)(1ULL << 53);
ProgressPhase phase_g = progress_add_probabilistic(
prog, estimate_modexp_cost(bits), 1.0 - g_failure_probability);
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;
}