X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/59600f67b6dd739bb31a2cb23e887adef13c3ac8..2e8324fc5624af5e4d3de5955bf781cf8a7c027c:/sshbn.c diff --git a/sshbn.c b/sshbn.c index 8dfaa298..3a5ddc03 100644 --- a/sshbn.c +++ b/sshbn.c @@ -6,6 +6,17 @@ #include #include +#if 0 // use PuTTY main debugging for diagbn() +#include +#include "putty.h" +#define debugprint debug +#else +#define debugprint(x) printf x +#endif + +#define BIGNUM_INTERNAL +typedef unsigned short *Bignum; + #include "ssh.h" unsigned short bnZero[1] = { 0 }; @@ -27,8 +38,8 @@ unsigned short bnOne[2] = { 1, 1 }; Bignum Zero = bnZero, One = bnOne; -Bignum newbn(int length) { - Bignum b = malloc((length+1)*sizeof(unsigned short)); +static Bignum newbn(int length) { + Bignum b = smalloc((length+1)*sizeof(unsigned short)); if (!b) abort(); /* FIXME */ memset(b, 0, (length+1)*sizeof(*b)); @@ -36,8 +47,12 @@ Bignum newbn(int length) { return b; } +void bn_restore_invariant(Bignum b) { + while (b[0] > 1 && b[b[0]] == 0) b[0]--; +} + Bignum copybn(Bignum orig) { - Bignum b = malloc((orig[0]+1)*sizeof(unsigned short)); + Bignum b = smalloc((orig[0]+1)*sizeof(unsigned short)); if (!b) abort(); /* FIXME */ memcpy(b, orig, (orig[0]+1)*sizeof(*b)); @@ -49,7 +64,13 @@ void freebn(Bignum b) { * Burn the evidence, just in case. */ memset(b, 0, sizeof(b[0]) * (b[0] + 1)); - free(b); + sfree(b); +} + +Bignum bn_power_2(int n) { + Bignum ret = newbn((n+15)/16); + bignum_set_bit(ret, n, 1); + return ret; } /* @@ -194,7 +215,7 @@ Bignum modpow(Bignum base, Bignum exp, Bignum mod) /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; - m = malloc(mlen * sizeof(unsigned short)); + m = smalloc(mlen * sizeof(unsigned short)); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; /* Shift m left to make msb bit set */ @@ -207,14 +228,14 @@ Bignum modpow(Bignum base, Bignum exp, Bignum mod) } /* Allocate n of size mlen, copy base to n */ - n = malloc(mlen * sizeof(unsigned short)); + n = smalloc(mlen * sizeof(unsigned short)); i = mlen - base[0]; for (j = 0; j < i; j++) n[j] = 0; for (j = 0; j < base[0]; j++) n[i+j] = base[base[0] - j]; /* Allocate a and b of size 2*mlen. Set a = 1 */ - a = malloc(2 * mlen * sizeof(unsigned short)); - b = malloc(2 * mlen * sizeof(unsigned short)); + a = smalloc(2 * mlen * sizeof(unsigned short)); + b = smalloc(2 * mlen * sizeof(unsigned short)); for (i = 0; i < 2*mlen; i++) a[i] = 0; a[2*mlen-1] = 1; @@ -259,10 +280,10 @@ Bignum modpow(Bignum base, Bignum exp, Bignum mod) while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ - for (i = 0; i < 2*mlen; i++) a[i] = 0; free(a); - for (i = 0; i < 2*mlen; i++) b[i] = 0; free(b); - for (i = 0; i < mlen; i++) m[i] = 0; free(m); - for (i = 0; i < mlen; i++) n[i] = 0; free(n); + for (i = 0; i < 2*mlen; i++) a[i] = 0; sfree(a); + for (i = 0; i < 2*mlen; i++) b[i] = 0; sfree(b); + for (i = 0; i < mlen; i++) m[i] = 0; sfree(m); + for (i = 0; i < mlen; i++) n[i] = 0; sfree(n); return result; } @@ -276,13 +297,13 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod) { unsigned short *a, *n, *m, *o; int mshift; - int pqlen, mlen, i, j; + int pqlen, mlen, rlen, i, j; Bignum result; /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; - m = malloc(mlen * sizeof(unsigned short)); + m = smalloc(mlen * sizeof(unsigned short)); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; /* Shift m left to make msb bit set */ @@ -297,19 +318,19 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod) pqlen = (p[0] > q[0] ? p[0] : q[0]); /* Allocate n of size pqlen, copy p to n */ - n = malloc(pqlen * sizeof(unsigned short)); + n = smalloc(pqlen * sizeof(unsigned short)); i = pqlen - p[0]; for (j = 0; j < i; j++) n[j] = 0; for (j = 0; j < p[0]; j++) n[i+j] = p[p[0] - j]; /* Allocate o of size pqlen, copy q to o */ - o = malloc(pqlen * sizeof(unsigned short)); + o = smalloc(pqlen * sizeof(unsigned short)); i = pqlen - q[0]; for (j = 0; j < i; j++) o[j] = 0; for (j = 0; j < q[0]; j++) o[i+j] = q[q[0] - j]; /* Allocate a of size 2*pqlen for result */ - a = malloc(2 * pqlen * sizeof(unsigned short)); + a = smalloc(2 * pqlen * sizeof(unsigned short)); /* Main computation */ internal_mul(n, o, a, pqlen); @@ -326,16 +347,17 @@ Bignum modmul(Bignum p, Bignum q, Bignum mod) } /* Copy result to buffer */ - result = newbn(mod[0]); - for (i = 0; i < mlen; i++) - result[result[0] - i] = a[i+2*pqlen-mlen]; + rlen = (mlen < pqlen*2 ? mlen : pqlen*2); + result = newbn(rlen); + for (i = 0; i < rlen; i++) + result[result[0] - i] = a[i+2*pqlen-rlen]; while (result[0] > 1 && result[result[0]] == 0) result[0]--; /* Free temporary arrays */ - for (i = 0; i < 2*pqlen; i++) a[i] = 0; free(a); - for (i = 0; i < mlen; i++) m[i] = 0; free(m); - for (i = 0; i < pqlen; i++) n[i] = 0; free(n); - for (i = 0; i < pqlen; i++) o[i] = 0; free(o); + for (i = 0; i < 2*pqlen; i++) a[i] = 0; sfree(a); + for (i = 0; i < mlen; i++) m[i] = 0; sfree(m); + for (i = 0; i < pqlen; i++) n[i] = 0; sfree(n); + for (i = 0; i < pqlen; i++) o[i] = 0; sfree(o); return result; } @@ -355,7 +377,7 @@ void bigmod(Bignum p, Bignum mod, Bignum result, Bignum quotient) /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; - m = malloc(mlen * sizeof(unsigned short)); + m = smalloc(mlen * sizeof(unsigned short)); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; /* Shift m left to make msb bit set */ @@ -372,7 +394,7 @@ void bigmod(Bignum p, Bignum mod, Bignum result, Bignum quotient) if (plen <= mlen) plen = mlen+1; /* Allocate n of size plen, copy p to n */ - n = malloc(plen * sizeof(unsigned short)); + n = smalloc(plen * sizeof(unsigned short)); for (j = 0; j < plen; j++) n[j] = 0; for (j = 1; j <= p[0]; j++) n[plen-j] = p[j]; @@ -396,8 +418,8 @@ void bigmod(Bignum p, Bignum mod, Bignum result, Bignum quotient) } /* Free temporary arrays */ - for (i = 0; i < mlen; i++) m[i] = 0; free(m); - for (i = 0; i < plen; i++) n[i] = 0; free(n); + for (i = 0; i < mlen; i++) m[i] = 0; sfree(m); + for (i = 0; i < plen; i++) n[i] = 0; sfree(n); } /* @@ -410,41 +432,47 @@ void decbn(Bignum bn) { bn[i]--; } +Bignum bignum_from_bytes(unsigned char *data, int nbytes) { + Bignum result; + int w, i; + + w = (nbytes+1)/2; /* bytes -> words */ + + result = newbn(w); + for (i=1; i<=w; i++) + result[i] = 0; + for (i=nbytes; i-- ;) { + unsigned char byte = *data++; + if (i & 1) + result[1+i/2] |= byte<<8; + else + result[1+i/2] |= byte; + } + + while (result[0] > 1 && result[result[0]] == 0) result[0]--; + return result; +} + /* * Read an ssh1-format bignum from a data buffer. Return the number * of bytes consumed. */ int ssh1_read_bignum(unsigned char *data, Bignum *result) { unsigned char *p = data; - Bignum bn; int i; int w, b; w = 0; for (i=0; i<2; i++) w = (w << 8) + *p++; - b = (w+7)/8; /* bits -> bytes */ - w = (w+15)/16; /* bits -> words */ if (!result) /* just return length */ return b + 2; - bn = newbn(w); - - for (i=1; i<=w; i++) - bn[i] = 0; - for (i=b; i-- ;) { - unsigned char byte = *p++; - if (i & 1) - bn[1+i/2] |= byte<<8; - else - bn[1+i/2] |= byte; - } - - *result = bn; + *result = bignum_from_bytes(p, b); - return p - data; + return p + b - data; } /* @@ -452,7 +480,6 @@ int ssh1_read_bignum(unsigned char *data, Bignum *result) { */ int ssh1_bignum_bitcount(Bignum bn) { int bitcount = bn[0] * 16 - 1; - while (bitcount >= 0 && (bn[bitcount/16+1] >> (bitcount % 16)) == 0) bitcount--; return bitcount + 1; @@ -574,7 +601,7 @@ Bignum bigmuladd(Bignum a, Bignum b, Bignum addend) { Bignum ret; /* mlen space for a, mlen space for b, 2*mlen for result */ - workspace = malloc(mlen * 4 * sizeof(unsigned short)); + workspace = smalloc(mlen * 4 * sizeof(unsigned short)); for (i = 0; i < mlen; i++) { workspace[0*mlen + i] = (mlen-i <= a[0] ? a[mlen-i] : 0); workspace[1*mlen + i] = (mlen-i <= b[0] ? b[mlen-i] : 0); @@ -620,6 +647,30 @@ Bignum bigmul(Bignum a, Bignum b) { } /* + * Create a bignum which is the bitmask covering another one. That + * is, the smallest integer which is >= N and is also one less than + * a power of two. + */ +Bignum bignum_bitmask(Bignum n) { + Bignum ret = copybn(n); + int i; + unsigned short j; + + i = ret[0]; + while (n[i] == 0 && i > 0) + i--; + if (i <= 0) + return ret; /* input was zero */ + j = 1; + while (j < n[i]) + j = 2*j+1; + ret[i] = j; + while (--i > 0) + ret[i] = 0xFFFF; + return ret; +} + +/* * Convert a (max 16-bit) short into a bignum. */ Bignum bignum_from_short(unsigned short n) { @@ -667,19 +718,19 @@ unsigned short bignum_mod_short(Bignum number, unsigned short modulus) { return (unsigned short) r; } -static void diagbn(char *prefix, Bignum md) { +void diagbn(char *prefix, Bignum md) { int i, nibbles, morenibbles; static const char hex[] = "0123456789ABCDEF"; - printf("%s0x", prefix ? prefix : ""); + debugprint(("%s0x", prefix ? prefix : "")); nibbles = (3 + ssh1_bignum_bitcount(md))/4; if (nibbles<1) nibbles=1; morenibbles = 4*md[0] - nibbles; - for (i=0; i> (4*(i%2))) & 0xF]); + debugprint(("%c",hex[(bignum_byte(md, i/2) >> (4*(i%2))) & 0xF])); - if (prefix) putchar('\n'); + if (prefix) debugprint(("\n")); } /* @@ -787,14 +838,14 @@ char *bignum_decimal(Bignum x) { i = ssh1_bignum_bitcount(x); ndigits = (28*i + 92)/93; /* multiply by 28/93 and round up */ ndigits++; /* allow for trailing \0 */ - ret = malloc(ndigits); + ret = smalloc(ndigits); /* * Now allocate some workspace to hold the binary form as we * repeatedly divide it by ten. Initialise this to the * big-endian form of the number. */ - workspace = malloc(sizeof(unsigned short) * x[0]); + workspace = smalloc(sizeof(unsigned short) * x[0]); for (i = 0; i < x[0]; i++) workspace[i] = x[x[0] - i];