1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-22 14:39:24 -05:00

Factor out the DSA deterministic k generator.

It's now a separate function, which you call with an identifying
string to be hashed into the generation of x. The idea is that other
DSA-like signature algorithms can reuse the same function, with a
different id string.

As a minor refinement, we now also never return k=1.
This commit is contained in:
Simon Tatham 2014-11-01 19:48:48 +00:00
parent eac7e041f1
commit a2b64dca47
2 changed files with 38 additions and 22 deletions

6
ssh.h
View File

@ -141,6 +141,12 @@ void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen,
unsigned char *out, int outlen, unsigned char *out, int outlen,
void *key); void *key);
/*
* Helper function for k generation in DSA, reused in ECDSA
*/
Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key,
unsigned char *digest, int digest_len);
typedef struct { typedef struct {
uint32 h[4]; uint32 h[4];
} MD5_Core_State; } MD5_Core_State;

View File

@ -518,7 +518,8 @@ static int dss_pubkey_bits(void *blob, int len)
return ret; return ret;
} }
static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key,
unsigned char *digest, int digest_len)
{ {
/* /*
* The basic DSS signing algorithm is: * The basic DSS signing algorithm is:
@ -591,21 +592,16 @@ static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen)
* Computer Security Group for helping to argue out all the * Computer Security Group for helping to argue out all the
* fine details. * fine details.
*/ */
struct dss_key *dss = (struct dss_key *) key;
SHA512_State ss; SHA512_State ss;
unsigned char digest[20], digest512[64]; unsigned char digest512[64];
Bignum proto_k, k, gkp, hash, kinv, hxr, r, s; Bignum proto_k, k;
unsigned char *bytes;
int nbytes, i;
SHA_Simple(data, datalen, digest);
/* /*
* Hash some identifying text plus x. * Hash some identifying text plus x.
*/ */
SHA512_Init(&ss); SHA512_Init(&ss);
SHA512_Bytes(&ss, "DSA deterministic k generator", 30); SHA512_Bytes(&ss, id_string, strlen(id_string) + 1);
sha512_mpint(&ss, dss->x); sha512_mpint(&ss, private_key);
SHA512_Final(&ss, digest512); SHA512_Final(&ss, digest512);
/* /*
@ -613,7 +609,7 @@ static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen)
*/ */
SHA512_Init(&ss); SHA512_Init(&ss);
SHA512_Bytes(&ss, digest512, sizeof(digest512)); SHA512_Bytes(&ss, digest512, sizeof(digest512));
SHA512_Bytes(&ss, digest, sizeof(digest)); SHA512_Bytes(&ss, digest, digest_len);
while (1) { while (1) {
SHA512_State ss2 = ss; /* structure copy */ SHA512_State ss2 = ss; /* structure copy */
@ -625,23 +621,37 @@ static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen)
* Now convert the result into a bignum, and reduce it mod q. * Now convert the result into a bignum, and reduce it mod q.
*/ */
proto_k = bignum_from_bytes(digest512, 64); proto_k = bignum_from_bytes(digest512, 64);
k = bigmod(proto_k, dss->q); k = bigmod(proto_k, modulus);
freebn(proto_k); freebn(proto_k);
kinv = modinv(k, dss->q); /* k^-1 mod q */
if (!kinv) { /* very unlikely */ if (bignum_cmp(k, One) != 0 && bignum_cmp(k, Zero) != 0) {
freebn(k); smemclr(&ss, sizeof(ss));
/* Perturb the hash to think of a different k. */ smemclr(digest512, sizeof(digest512));
SHA512_Bytes(&ss, "x", 1); return k;
/* Go round and try again. */
continue;
} }
break; /* Very unlikely we get here, but if so, k was unsuitable. */
freebn(k);
/* Perturb the hash to think of a different k. */
SHA512_Bytes(&ss, "x", 1);
/* Go round and try again. */
} }
}
smemclr(&ss, sizeof(ss)); static unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen)
{
struct dss_key *dss = (struct dss_key *) key;
Bignum k, gkp, hash, kinv, hxr, r, s;
unsigned char digest[20];
unsigned char *bytes;
int nbytes, i;
smemclr(digest512, sizeof(digest512)); SHA_Simple(data, datalen, digest);
k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x,
digest, sizeof(digest));
kinv = modinv(k, dss->q); /* k^-1 mod q */
assert(kinv);
/* /*
* Now we have k, so just go ahead and compute the signature. * Now we have k, so just go ahead and compute the signature.