X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/8671a58011e85048f831eeb9c5f14966be5fe0f5..a5dd84675905dfc4274cf45424e6f3a9e385e1a7:/sshrsa.c diff --git a/sshrsa.c b/sshrsa.c index c60823e4..f7817361 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -89,6 +89,20 @@ void rsaencrypt(unsigned char *data, int length, struct RSAKey *key) freebn(b2); } +static void sha512_mpint(SHA512_State * s, Bignum b) +{ + unsigned char lenbuf[4]; + int len; + len = (bignum_bitcount(b) + 8) / 8; + PUT_32BIT(lenbuf, len); + SHA512_Bytes(s, lenbuf, 4); + while (len-- > 0) { + lenbuf[0] = bignum_byte(b, len); + SHA512_Bytes(s, lenbuf, 1); + } + memset(lenbuf, 0, sizeof(lenbuf)); +} + /* * This function is a wrapper on modpow(). It has the same effect * as modpow(), but employs RSA blinding to protect against timing @@ -100,6 +114,11 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key) Bignum input_blinded, ret_blinded; Bignum ret; + SHA512_State ss; + unsigned char digest512[64]; + int digestused = lenof(digest512); + int hashseq = 0; + /* * Start by inventing a random number chosen uniformly from the * range 2..modulus-1. (We do this by preparing a random number @@ -110,6 +129,10 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key) * There are timing implications to the potential retries, of * course, but all they tell you is the modulus, which you * already knew.) + * + * To preserve determinism and avoid Pageant needing to share + * the random number pool, we actually generate this `random' + * number by hashing stuff with the private key. */ while (1) { int bits, byte, bitsleft, v; @@ -123,8 +146,35 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key) byte = 0; bitsleft = 0; while (bits--) { - if (bitsleft <= 0) - bitsleft = 8, byte = random_byte(); + if (bitsleft <= 0) { + bitsleft = 8; + /* + * Conceptually the following few lines are equivalent to + * byte = random_byte(); + */ + if (digestused >= lenof(digest512)) { + unsigned char seqbuf[4]; + PUT_32BIT(seqbuf, hashseq); + SHA512_Init(&ss); + SHA512_Bytes(&ss, "RSA deterministic blinding", 26); + SHA512_Bytes(&ss, seqbuf, sizeof(seqbuf)); + sha512_mpint(&ss, key->private_exponent); + SHA512_Final(&ss, digest512); + hashseq++; + + /* + * Now hash that digest plus the signature + * input. + */ + SHA512_Init(&ss); + SHA512_Bytes(&ss, digest512, sizeof(digest512)); + sha512_mpint(&ss, input); + SHA512_Final(&ss, digest512); + + digestused = 0; + } + byte = digest512[digestused++]; + } v = byte & 1; byte >>= 1; bitsleft--; @@ -147,15 +197,16 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key) /* * RSA blinding relies on the fact that (xy)^d mod n is equal * to (x^d mod n) * (y^d mod n) mod n. We invent a random pair - * y and y^d; then we multiply x by y, raise to the power e mod - * n as usual, and divide by y^d to recover x^d. Thus the - * timing of the modpow does not reveal information about x, - * but only about xy, which is unpredictable to an attacker. + * y and y^d; then we multiply x by y, raise to the power d mod + * n as usual, and divide by y^d to recover x^d. Thus an + * attacker can't correlate the timing of the modpow with the + * input, because they don't know anything about the number + * that was input to the actual modpow. * * The clever bit is that we don't have to do a huge modpow to * get y and y^d; we will use the number we just invented as - * _y^d_, and use the RSA public exponent to compute y from it, - * which is much faster. + * _y^d_, and use the _public_ exponent to compute (y^d)^e = y + * from it, which is much faster to do. */ random_encrypted = modpow(random, key->exponent, key->modulus); random_inverse = modinv(random, key->modulus); @@ -315,7 +366,7 @@ unsigned char *rsa_public_blob(struct RSAKey *key, int *len) length = (ssh1_bignum_length(key->modulus) + ssh1_bignum_length(key->exponent) + 4); - ret = smalloc(length); + ret = snewn(length, unsigned char); PUT_32BIT(ret, bignum_bitcount(key->modulus)); pos = 4; @@ -387,7 +438,7 @@ static void *rsa2_newkey(char *data, int len) int slen; struct RSAKey *rsa; - rsa = smalloc(sizeof(struct RSAKey)); + rsa = snew(struct RSAKey); if (!rsa) return NULL; getstring(&data, &len, &p, &slen); @@ -418,7 +469,7 @@ static char *rsa2_fmtkey(void *key) int len; len = rsastr_len(rsa); - p = smalloc(len); + p = snewn(len, char); rsastr_fmt(p, rsa); return p; } @@ -438,7 +489,7 @@ static unsigned char *rsa2_public_blob(void *key, int *len) * (three length fields, 12+7=19). */ bloblen = 19 + elen + mlen; - blob = smalloc(bloblen); + blob = snewn(bloblen, unsigned char); p = blob; PUT_32BIT(p, 7); p += 4; @@ -474,7 +525,7 @@ static unsigned char *rsa2_private_blob(void *key, int *len) * sum of lengths. */ bloblen = 16 + dlen + plen + qlen + ulen; - blob = smalloc(bloblen); + blob = snewn(bloblen, unsigned char); p = blob; PUT_32BIT(p, dlen); p += 4; @@ -522,7 +573,7 @@ static void *rsa2_openssh_createkey(unsigned char **blob, int *len) char **b = (char **) blob; struct RSAKey *rsa; - rsa = smalloc(sizeof(struct RSAKey)); + rsa = snew(struct RSAKey); if (!rsa) return NULL; rsa->comment = NULL; @@ -578,6 +629,18 @@ static int rsa2_openssh_fmtkey(void *key, unsigned char *blob, int len) return bloblen; } +static int rsa2_pubkey_bits(void *blob, int len) +{ + struct RSAKey *rsa; + int ret; + + rsa = rsa2_newkey((char *) blob, len); + ret = bignum_bitcount(rsa->modulus); + rsa2_freekey(rsa); + + return ret; +} + static char *rsa2_fingerprint(void *key) { struct RSAKey *rsa = (struct RSAKey *) key; @@ -607,7 +670,7 @@ static char *rsa2_fingerprint(void *key) for (i = 0; i < 16; i++) sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "", digest[i]); - ret = smalloc(strlen(buffer) + 1); + ret = snewn(strlen(buffer) + 1, char); if (ret) strcpy(ret, buffer); return ret; @@ -664,7 +727,7 @@ static int rsa2_verifysig(void *key, char *sig, int siglen, ret = 1; - bytes = bignum_bitcount(rsa->modulus) / 8; + bytes = (bignum_bitcount(rsa->modulus)+7) / 8; /* Top (partial) byte should be zero. */ if (bignum_byte(out, bytes - 1) != 0) ret = 0; @@ -687,6 +750,7 @@ static int rsa2_verifysig(void *key, char *sig, int siglen, if (bignum_byte(out, i) != hash[j]) ret = 0; } + freebn(out); return ret; } @@ -704,7 +768,7 @@ static unsigned char *rsa2_sign(void *key, char *data, int datalen, SHA_Simple(data, datalen, hash); nbytes = (bignum_bitcount(rsa->modulus) - 1) / 8; - bytes = smalloc(nbytes); + bytes = snewn(nbytes, unsigned char); bytes[0] = 1; for (i = 1; i < nbytes - 20 - ASN1_LEN; i++) @@ -721,7 +785,7 @@ static unsigned char *rsa2_sign(void *key, char *data, int datalen, freebn(in); nbytes = (bignum_bitcount(out) + 7) / 8; - bytes = smalloc(4 + 7 + 4 + nbytes); + bytes = snewn(4 + 7 + 4 + nbytes, unsigned char); PUT_32BIT(bytes, 7); memcpy(bytes + 4, "ssh-rsa", 7); PUT_32BIT(bytes + 4 + 7, nbytes); @@ -742,6 +806,7 @@ const struct ssh_signkey ssh_rsa = { rsa2_createkey, rsa2_openssh_createkey, rsa2_openssh_fmtkey, + rsa2_pubkey_bits, rsa2_fingerprint, rsa2_verifysig, rsa2_sign,