X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=sshbn.c;h=b40781ff2996dc65fe9659e4d15ef8921d1f52f3;hb=d23c0972cd850c77871f9a314e0520d7023c8b62;hp=a5e0552ff57523002adbafa6502cb0beda792a97;hpb=ead9081318aa17a9b90e26061ca79946e7fa7ca9;p=PuTTY.git diff --git a/sshbn.c b/sshbn.c index a5e0552f..b40781ff 100644 --- a/sshbn.c +++ b/sshbn.c @@ -1092,6 +1092,38 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod) return result; } +Bignum modsub(const Bignum a, const Bignum b, const Bignum n) +{ + Bignum a1, b1, ret; + + if (bignum_cmp(a, n) >= 0) a1 = bigmod(a, n); + else a1 = a; + if (bignum_cmp(b, n) >= 0) b1 = bigmod(b, n); + else b1 = b; + + if (bignum_cmp(a1, b1) >= 0) /* a >= b */ + { + ret = bigsub(a1, b1); + } + else + { + /* Handle going round the corner of the modulus without having + * negative support in Bignum */ + Bignum tmp = bigsub(n, b1); + if (tmp) { + ret = bigadd(tmp, a1); + freebn(tmp); + } else { + ret = NULL; + } + } + + if (a != a1) freebn(a1); + if (b != b1) freebn(b1); + + return ret; +} + /* * Compute p % mod. * The most significant word of mod MUST be non-zero. @@ -1201,6 +1233,37 @@ Bignum bignum_from_bytes(const unsigned char *data, int nbytes) return result; } +Bignum bignum_random_in_range(const Bignum lower, const Bignum upper) +{ + Bignum ret = NULL; + int upper_len = bignum_bitcount(upper); + int upper_bytes = upper_len / 8; + int upper_bits = upper_len % 8; + if (upper_bits) ++upper_bytes; + + do { + unsigned char *bytes; + int i; + + if (ret) freebn(ret); + + bytes = snewn(upper_bytes, unsigned char); + for (i = 0; i < upper_bytes; ++i) + { + bytes[i] = (unsigned char)random_byte(); + } + /* Mask the top to reduce failure rate to 50/50 */ + if (upper_bits) + { + bytes[i - 1] &= 0xFF >> (8 - upper_bits); + } + + ret = bignum_from_bytes(bytes, upper_bytes); + } while (bignum_cmp(ret, lower) < 0 || bignum_cmp(ret, upper) > 0); + + return ret; +} + /* * Read an SSH-1-format bignum from a data buffer. Return the number * of bytes consumed, or -1 if there wasn't enough data. @@ -1375,6 +1438,45 @@ Bignum bignum_rshift(Bignum a, int shift) return ret; } +/* + * Left-shift one bignum to form another. + */ +Bignum bignum_lshift(Bignum a, int shift) +{ + Bignum ret; + int bits, shiftWords, shiftBits; + + assert(shift >= 0); + + bits = bignum_bitcount(a) + shift; + ret = newbn((bits + BIGNUM_INT_BITS - 1) / BIGNUM_INT_BITS); + if (!ret) return NULL; + + shiftWords = shift / BIGNUM_INT_BITS; + shiftBits = shift % BIGNUM_INT_BITS; + + if (shiftBits == 0) + { + memcpy(&ret[1 + shiftWords], &a[1], sizeof(BignumInt) * a[0]); + } + else + { + int i; + BignumInt carry = 0; + + /* Remember that Bignum[0] is length, so add 1 */ + for (i = shiftWords + 1; i < ((int)a[0]) + shiftWords + 1; ++i) + { + BignumInt from = a[i - shiftWords]; + ret[i] = (from << shiftBits) | carry; + carry = from >> (BIGNUM_INT_BITS - shiftBits); + } + if (carry) ret[i] = carry; + } + + return ret; +} + /* * Non-modular multiplication and addition. */ @@ -1610,6 +1712,8 @@ Bignum bigdiv(Bignum a, Bignum b) { Bignum q = newbn(a[0]); bigdivmod(a, b, NULL, q); + while (q[0] > 1 && q[q[0]] == 0) + q[0]--; return q; } @@ -1620,6 +1724,8 @@ Bignum bigmod(Bignum a, Bignum b) { Bignum r = newbn(b[0]); bigdivmod(a, b, r, NULL); + while (r[0] > 1 && r[r[0]] == 0) + r[0]--; return r; } @@ -1679,6 +1785,8 @@ Bignum modinv(Bignum number, Bignum modulus) bigdivmod(a, b, t, q); while (t[0] > 1 && t[t[0]] == 0) t[0]--; + while (q[0] > 1 && q[q[0]] == 0) + q[0]--; freebn(a); a = b; b = t;