X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=sshbn.c;h=7aa1069709f774964aa1de309fcb9f3412d528ef;hb=5471539a6738484b48fb938c88dce547a3e4b299;hp=facdf3d576b17f7bea92fdf5cb281b716006311d;hpb=2725a51d3c44d1eb9760f08b8482db25d9401a86;p=PuTTY.git diff --git a/sshbn.c b/sshbn.c index facdf3d5..7aa10697 100644 --- a/sshbn.c +++ b/sshbn.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "misc.h" @@ -19,6 +20,7 @@ typedef BignumInt *Bignum; BignumInt bnZero[1] = { 0 }; BignumInt bnOne[2] = { 1, 1 }; +BignumInt bnTen[2] = { 1, 10 }; /* * The Bignum format is an array of `BignumInt'. The first @@ -34,7 +36,7 @@ BignumInt bnOne[2] = { 1, 1 }; * nonzero. */ -Bignum Zero = bnZero, One = bnOne; +Bignum Zero = bnZero, One = bnOne, Ten = bnTen; static Bignum newbn(int length) { @@ -43,8 +45,6 @@ static Bignum newbn(int length) assert(length >= 0 && length < INT_MAX / BIGNUM_INT_BITS); b = snewn(length + 1, BignumInt); - if (!b) - abort(); /* FIXME */ memset(b, 0, (length + 1) * sizeof(*b)); b[0] = length; return b; @@ -1008,6 +1008,35 @@ 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); + assert(tmp); + ret = bigadd(tmp, a1); + freebn(tmp); + } + + 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. @@ -1113,11 +1142,89 @@ Bignum bignum_from_bytes(const unsigned char *data, int nbytes) (BignumInt)byte << (8*i % BIGNUM_INT_BITS); } - while (result[0] > 1 && result[result[0]] == 0) - result[0]--; + bn_restore_invariant(result); + return result; +} + +Bignum bignum_from_bytes_le(const unsigned char *data, int nbytes) +{ + Bignum result; + int w, i; + + assert(nbytes >= 0 && nbytes < INT_MAX/8); + + w = (nbytes + BIGNUM_INT_BYTES - 1) / BIGNUM_INT_BYTES; /* bytes->words */ + + result = newbn(w); + for (i = 1; i <= w; i++) + result[i] = 0; + for (i = 0; i < nbytes; ++i) { + unsigned char byte = *data++; + result[1 + i / BIGNUM_INT_BYTES] |= + (BignumInt)byte << (8*i % BIGNUM_INT_BITS); + } + + bn_restore_invariant(result); return result; } +Bignum bignum_from_decimal(const char *decimal) +{ + Bignum result = copybn(Zero); + + while (*decimal) { + Bignum tmp, tmp2; + + if (!isdigit((unsigned char)*decimal)) { + freebn(result); + return 0; + } + + tmp = bigmul(result, Ten); + tmp2 = bignum_from_long(*decimal - '0'); + result = bigadd(tmp, tmp2); + freebn(tmp); + freebn(tmp2); + + decimal++; + } + + return result; +} + +Bignum bignum_random_in_range(const Bignum lower, const Bignum upper) +{ + Bignum ret = NULL; + unsigned char *bytes; + int upper_len = bignum_bitcount(upper); + int upper_bytes = upper_len / 8; + int upper_bits = upper_len % 8; + if (upper_bits) ++upper_bytes; + + bytes = snewn(upper_bytes, unsigned char); + do { + int i; + + if (ret) freebn(ret); + + 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); + smemclr(bytes, upper_bytes); + sfree(bytes); + + 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. @@ -1202,9 +1309,9 @@ int bignum_bit(Bignum bn, int i) */ void bignum_set_bit(Bignum bn, int bitnum, int value) { - if (bitnum < 0 || bitnum >= (int)(BIGNUM_INT_BITS * bn[0])) - abort(); /* beyond the end */ - else { + if (bitnum < 0 || bitnum >= (int)(BIGNUM_INT_BITS * bn[0])) { + if (value) abort(); /* beyond the end */ + } else { int v = bitnum / BIGNUM_INT_BITS + 1; BignumInt mask = (BignumInt)1 << (bitnum % BIGNUM_INT_BITS); if (value) @@ -1292,6 +1399,44 @@ 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); + + 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. */ @@ -1735,7 +1880,7 @@ char *bignum_decimal(Bignum x) * testdata/bignum.py . */ -void modalfatalbox(char *p, ...) +void modalfatalbox(const char *p, ...) { va_list ap; fprintf(stderr, "FATAL ERROR: ");