#include <stdlib.h>
#include <string.h>
+#if 0 // use PuTTY main debugging for diagbn()
+#include <windows.h>
+#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 };
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));
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));
* 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;
}
/*
* The most significant word of mod MUST be non-zero.
* We assume that the result array is the same size as the mod array.
*/
-void modpow(Bignum base, Bignum exp, Bignum mod, Bignum result)
+Bignum modpow(Bignum base, Bignum exp, Bignum mod)
{
unsigned short *a, *b, *n, *m;
int mshift;
int mlen, 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 */
}
/* 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;
}
/* Copy result to buffer */
+ result = newbn(mod[0]);
for (i = 0; i < mlen; i++)
result[result[0] - i] = a[i+mlen];
+ 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;
}
/*
* The most significant word of mod MUST be non-zero.
* We assume that the result array is the same size as the mod array.
*/
-void modmul(Bignum p, Bignum q, Bignum mod, Bignum result)
+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 */
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);
}
/* Copy result to buffer */
- 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;
}
/*
/* 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 */
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];
}
/* 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);
}
/*
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);
+ *result = bignum_from_bytes(p, b);
- 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;
-
- return p - data;
+ return p + b - data;
}
/*
*/
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;
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);
return bigmuladd(a, b, NULL);
}
+/*
+ * 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.
*/
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<morenibbles; i++) putchar('-');
+ for (i=0; i<morenibbles; i++) debugprint(("-"));
for (i=nibbles; i-- ;)
- putchar(hex[(bignum_byte(md, i/2) >> (4*(i%2))) & 0xF]);
+ debugprint(("%c",hex[(bignum_byte(md, i/2) >> (4*(i%2))) & 0xF]));
- if (prefix) putchar('\n');
+ if (prefix) debugprint(("\n"));
}
/*
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];