From 8671a58011e85048f831eeb9c5f14966be5fe0f5 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 15 Mar 2003 17:51:05 +0000 Subject: [PATCH] Implement RSA blinding, to defeat Brumley and Boneh's RSA timing attacks. In the PuTTY suite I'm pretty sure they're only applicable to a forwarded Pageant, and if your remote sysadmin is abusing your Pageant then you're shafted _anyway_; but it can't hurt to take precautions now, just in case things change in future. git-svn-id: svn://svn.tartarus.org/sgt/putty@2941 cda61777-01e9-0310-a592-d414129be87e --- sshrsa.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/sshrsa.c b/sshrsa.c index e95f8b63..c60823e4 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -1,8 +1,5 @@ /* - * RSA implementation just sufficient for ssh client-side - * initialisation step - * - * Rewritten for more speed by Joris van Rantwijk, Jun 1999. + * RSA implementation for PuTTY. */ #include @@ -92,13 +89,94 @@ void rsaencrypt(unsigned char *data, int length, struct RSAKey *key) freebn(b2); } -Bignum rsadecrypt(Bignum input, struct RSAKey *key) +/* + * This function is a wrapper on modpow(). It has the same effect + * as modpow(), but employs RSA blinding to protect against timing + * attacks. + */ +static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key) { + Bignum random, random_encrypted, random_inverse; + Bignum input_blinded, ret_blinded; Bignum ret; - ret = modpow(input, key->private_exponent, key->modulus); + + /* + * Start by inventing a random number chosen uniformly from the + * range 2..modulus-1. (We do this by preparing a random number + * of the right length and retrying if it's greater than the + * modulus, to prevent any potential Bleichenbacher-like + * attacks making use of the uneven distribution within the + * range that would arise from just reducing our number mod n. + * There are timing implications to the potential retries, of + * course, but all they tell you is the modulus, which you + * already knew.) + */ + while (1) { + int bits, byte, bitsleft, v; + random = copybn(key->modulus); + /* + * Find the topmost set bit. (This function will return its + * index plus one.) Then we'll set all bits from that one + * downwards randomly. + */ + bits = bignum_bitcount(random); + byte = 0; + bitsleft = 0; + while (bits--) { + if (bitsleft <= 0) + bitsleft = 8, byte = random_byte(); + v = byte & 1; + byte >>= 1; + bitsleft--; + bignum_set_bit(random, bits, v); + } + + /* + * Now check that this number is strictly greater than + * zero, and strictly less than modulus. + */ + if (bignum_cmp(random, Zero) <= 0 || + bignum_cmp(random, key->modulus) >= 0) { + freebn(random); + continue; + } else { + break; + } + } + + /* + * 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. + * + * 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. + */ + random_encrypted = modpow(random, key->exponent, key->modulus); + random_inverse = modinv(random, key->modulus); + input_blinded = modmul(input, random_encrypted, key->modulus); + ret_blinded = modpow(input_blinded, key->private_exponent, key->modulus); + ret = modmul(ret_blinded, random_inverse, key->modulus); + + freebn(ret_blinded); + freebn(input_blinded); + freebn(random_inverse); + freebn(random_encrypted); + freebn(random); + return ret; } +Bignum rsadecrypt(Bignum input, struct RSAKey *key) +{ + return rsa_privkey_op(input, key); +} + int rsastr_len(struct RSAKey *key) { Bignum md, ex; @@ -639,7 +717,7 @@ static unsigned char *rsa2_sign(void *key, char *data, int datalen, in = bignum_from_bytes(bytes, nbytes); sfree(bytes); - out = modpow(in, rsa->private_exponent, rsa->modulus); + out = rsa_privkey_op(in, rsa); freebn(in); nbytes = (bignum_bitcount(out) + 7) / 8; -- 2.11.0