mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
1c039d0a7b
This code base has always been a bit confused about which spelling it likes to use to refer to that signature algorithm. The SSH protocol id is "ssh-dss". But everyone I know refers to it as the Digital Signature _Algorithm_, not the Digital Signature _Standard_. When I moved everything down into the crypto subdir, I took the opportunity to rename sshdss.c to dsa.c. Now I'm doing the rest of the job: all internal identifiers and code comments refer to DSA, and the spelling "dss" only survives in externally visible identifiers that have to remain constant. (Such identifiers include the SSH protocol id, and also the string id used to identify the key type in PuTTY's own host key cache. We can't change the latter without causing everyone a backwards-compatibility headache, and if we _did_ ever decide to do that, we'd surely want to do a much more thorough job of making the cache format more sensible!)
104 lines
3.2 KiB
C
104 lines
3.2 KiB
C
/*
|
|
* DSA key generation.
|
|
*/
|
|
|
|
#include "misc.h"
|
|
#include "ssh.h"
|
|
#include "sshkeygen.h"
|
|
#include "mpint.h"
|
|
|
|
int dsa_generate(struct dsa_key *key, int bits, PrimeGenerationContext *pgc,
|
|
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(pgc, prog, 160);
|
|
ProgressPhase phase_p = primegen_add_progress_phase(pgc, 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_generate(pgc, 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_mod_prime(pcs, q);
|
|
mp_int *p = primegen_generate(pgc, 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(2);
|
|
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_dsa;
|
|
|
|
key->p = p;
|
|
key->q = q;
|
|
key->g = g;
|
|
key->x = x;
|
|
key->y = mp_modpow(key->g, key->x, key->p);
|
|
|
|
return 1;
|
|
}
|