📄 sshbn.c
字号:
/* * Bignum routines for RSA and DH and stuff. */#include <stdio.h>#include <assert.h>#include <stdlib.h>#include <string.h>#include "misc.h"#if defined __GNUC__ && defined __i386__typedef unsigned long BignumInt;typedef unsigned long long BignumDblInt;#define BIGNUM_INT_MASK 0xFFFFFFFFUL#define BIGNUM_TOP_BIT 0x80000000UL#define BIGNUM_INT_BITS 32#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)#define DIVMOD_WORD(q, r, hi, lo, w) \ __asm__("div %2" : \ "=d" (r), "=a" (q) : \ "r" (w), "d" (hi), "a" (lo))#elsetypedef unsigned short BignumInt;typedef unsigned long BignumDblInt;#define BIGNUM_INT_MASK 0xFFFFU#define BIGNUM_TOP_BIT 0x8000U#define BIGNUM_INT_BITS 16#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2)#define DIVMOD_WORD(q, r, hi, lo, w) do { \ BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \ q = n / w; \ r = n % w; \} while (0)#endif#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8)#define BIGNUM_INTERNALtypedef BignumInt *Bignum;#include "ssh.h"const BignumInt bnZero[1] = { 0 };const BignumInt bnOne[2] = { 1, 1 };/* * The Bignum format is an array of `BignumInt'. The first * element of the array counts the remaining elements. The * remaining elements express the actual number, base 2^BIGNUM_INT_BITS, _least_ * significant digit first. (So it's trivial to extract the bit * with value 2^n for any n.) * * All Bignums in this module are positive. Negative numbers must * be dealt with outside it. * * INVARIANT: the most significant word of any Bignum must be * nonzero. */const Bignum Zero = (const Bignum) bnZero;const Bignum One = (const Bignum) bnOne;static Bignum newbn(int length){ Bignum b = snewn(length + 1, BignumInt); if (!b) abort(); /* FIXME */ memset(b, 0, (length + 1) * sizeof(*b)); b[0] = 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 = snewn(orig[0] + 1, BignumInt); if (!b) abort(); /* FIXME */ memcpy(b, orig, (orig[0] + 1) * sizeof(*b)); return b;}void freebn(Bignum b){ /* * Burn the evidence, just in case. */ memset(b, 0, sizeof(b[0]) * (b[0] + 1)); sfree(b);}Bignum bn_power_2(int n){ Bignum ret = newbn(n / BIGNUM_INT_BITS + 1); bignum_set_bit(ret, n, 1); return ret;}/* * Compute c = a * b. * Input is in the first len words of a and b. * Result is returned in the first 2*len words of c. */static void internal_mul(BignumInt *a, BignumInt *b, BignumInt *c, int len){ int i, j; BignumDblInt t; for (j = 0; j < 2 * len; j++) c[j] = 0; for (i = len - 1; i >= 0; i--) { t = 0; for (j = len - 1; j >= 0; j--) { t += MUL_WORD(a[i], (BignumDblInt) b[j]); t += (BignumDblInt) c[i + j + 1]; c[i + j + 1] = (BignumInt) t; t = t >> BIGNUM_INT_BITS; } c[i] = (BignumInt) t; }}static void internal_add_shifted(BignumInt *number, unsigned n, int shift){ int word = 1 + (shift / BIGNUM_INT_BITS); int bshift = shift % BIGNUM_INT_BITS; BignumDblInt addend; addend = (BignumDblInt)n << bshift; while (addend) { addend += number[word]; number[word] = (BignumInt) addend & BIGNUM_INT_MASK; addend >>= BIGNUM_INT_BITS; word++; }}/* * Compute a = a % m. * Input in first alen words of a and first mlen words of m. * Output in first alen words of a * (of which first alen-mlen words will be zero). * The MSW of m MUST have its high bit set. * Quotient is accumulated in the `quotient' array, which is a Bignum * rather than the internal bigendian format. Quotient parts are shifted * left by `qshift' before adding into quot. */static void internal_mod(BignumInt *a, int alen, BignumInt *m, int mlen, BignumInt *quot, int qshift){ BignumInt m0, m1; unsigned int h; int i, k; m0 = m[0]; if (mlen > 1) m1 = m[1]; else m1 = 0; for (i = 0; i <= alen - mlen; i++) { BignumDblInt t; unsigned int q, r, c, ai1; if (i == 0) { h = 0; } else { h = a[i - 1]; a[i - 1] = 0; } if (i == alen - 1) ai1 = 0; else ai1 = a[i + 1]; /* Find q = h:a[i] / m0 */ DIVMOD_WORD(q, r, h, a[i], m0); /* Refine our estimate of q by looking at h:a[i]:a[i+1] / m0:m1 */ t = MUL_WORD(m1, q); if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) { q--; t -= m1; r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */ if (r >= (BignumDblInt) m0 && t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--; } /* Subtract q * m from a[i...] */ c = 0; for (k = mlen - 1; k >= 0; k--) { t = MUL_WORD(q, m[k]); t += c; c = t >> BIGNUM_INT_BITS; if ((BignumInt) t > a[i + k]) c++; a[i + k] -= (BignumInt) t; } /* Add back m in case of borrow */ if (c != h) { t = 0; for (k = mlen - 1; k >= 0; k--) { t += m[k]; t += a[i + k]; a[i + k] = (BignumInt) t; t = t >> BIGNUM_INT_BITS; } q--; } if (quot) internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i)); }}/* * Compute (base ^ exp) % mod. */Bignum modpow(Bignum base_in, Bignum exp, Bignum mod){ BignumInt *a, *b, *n, *m; int mshift; int mlen, i, j; Bignum base, result; /* * The most significant word of mod needs to be non-zero. It * should already be, but let's make sure. */ assert(mod[mod[0]] != 0); /* * Make sure the base is smaller than the modulus, by reducing * it modulo the modulus if not. */ base = bigmod(base_in, mod); /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; m = snewn(mlen, BignumInt); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; /* Shift m left to make msb bit set */ for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++) if ((m[0] << mshift) & BIGNUM_TOP_BIT) break; if (mshift) { for (i = 0; i < mlen - 1; i++) m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift)); m[mlen - 1] = m[mlen - 1] << mshift; } /* Allocate n of size mlen, copy base to n */ n = snewn(mlen, BignumInt); 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 = snewn(2 * mlen, BignumInt); b = snewn(2 * mlen, BignumInt); for (i = 0; i < 2 * mlen; i++) a[i] = 0; a[2 * mlen - 1] = 1; /* Skip leading zero bits of exp. */ i = 0; j = BIGNUM_INT_BITS-1; while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) { j--; if (j < 0) { i++; j = BIGNUM_INT_BITS-1; } } /* Main computation */ while (i < exp[0]) { while (j >= 0) { internal_mul(a + mlen, a + mlen, b, mlen); internal_mod(b, mlen * 2, m, mlen, NULL, 0); if ((exp[exp[0] - i] & (1 << j)) != 0) { internal_mul(b + mlen, n, a, mlen); internal_mod(a, mlen * 2, m, mlen, NULL, 0); } else { BignumInt *t; t = a; a = b; b = t; } j--; } i++; j = BIGNUM_INT_BITS-1; } /* Fixup result in case the modulus was shifted */ if (mshift) { for (i = mlen - 1; i < 2 * mlen - 1; i++) a[i] = (a[i] << mshift) | (a[i + 1] >> (BIGNUM_INT_BITS - mshift)); a[2 * mlen - 1] = a[2 * mlen - 1] << mshift; internal_mod(a, mlen * 2, m, mlen, NULL, 0); for (i = 2 * mlen - 1; i >= mlen; i--) a[i] = (a[i] >> mshift) | (a[i - 1] << (BIGNUM_INT_BITS - mshift)); } /* 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; 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); freebn(base); return result;}/* * Compute (p * q) % mod. * The most significant word of mod MUST be non-zero. * We assume that the result array is the same size as the mod array. */Bignum modmul(Bignum p, Bignum q, Bignum mod){ BignumInt *a, *n, *m, *o; int mshift; 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 = snewn(mlen, BignumInt); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; /* Shift m left to make msb bit set */ for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++) if ((m[0] << mshift) & BIGNUM_TOP_BIT) break; if (mshift) { for (i = 0; i < mlen - 1; i++) m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift)); m[mlen - 1] = m[mlen - 1] << mshift; } pqlen = (p[0] > q[0] ? p[0] : q[0]); /* Allocate n of size pqlen, copy p to n */ n = snewn(pqlen, BignumInt); 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 = snewn(pqlen, BignumInt); 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 = snewn(2 * pqlen, BignumInt); /* Main computation */ internal_mul(n, o, a, pqlen); internal_mod(a, pqlen * 2, m, mlen, NULL, 0); /* Fixup result in case the modulus was shifted */ if (mshift) { for (i = 2 * pqlen - mlen - 1; i < 2 * pqlen - 1; i++) a[i] = (a[i] << mshift) | (a[i + 1] >> (BIGNUM_INT_BITS - mshift)); a[2 * pqlen - 1] = a[2 * pqlen - 1] << mshift; internal_mod(a, pqlen * 2, m, mlen, NULL, 0); for (i = 2 * pqlen - 1; i >= 2 * pqlen - mlen; i--) a[i] = (a[i] >> mshift) | (a[i - 1] << (BIGNUM_INT_BITS - mshift)); } /* Copy result to buffer */ 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; 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;}/* * Compute p % mod. * The most significant word of mod MUST be non-zero. * We assume that the result array is the same size as the mod array. * We optionally write out a quotient if `quotient' is non-NULL. * We can avoid writing out the result if `result' is NULL. */static void bigdivmod(Bignum p, Bignum mod, Bignum result, Bignum quotient){ BignumInt *n, *m; int mshift; int plen, mlen, i, j; /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; m = snewn(mlen, BignumInt); for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j]; /* Shift m left to make msb bit set */ for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++) if ((m[0] << mshift) & BIGNUM_TOP_BIT) break; if (mshift) { for (i = 0; i < mlen - 1; i++) m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift)); m[mlen - 1] = m[mlen - 1] << mshift; } plen = p[0]; /* Ensure plen > mlen */ if (plen <= mlen) plen = mlen + 1; /* Allocate n of size plen, copy p to n */ n = snewn(plen, BignumInt); for (j = 0; j < plen; j++) n[j] = 0; for (j = 1; j <= p[0]; j++) n[plen - j] = p[j]; /* Main computation */ internal_mod(n, plen, m, mlen, quotient, mshift); /* Fixup result in case the modulus was shifted */ if (mshift) { for (i = plen - mlen - 1; i < plen - 1; i++) n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift)); n[plen - 1] = n[plen - 1] << mshift; internal_mod(n, plen, m, mlen, quotient, 0); for (i = plen - 1; i >= plen - mlen; i--) n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift)); } /* Copy result to buffer */ if (result) { for (i = 1; i <= result[0]; i++) { int j = plen - i; result[i] = j >= 0 ? n[j] : 0; } } /* Free temporary arrays */ for (i = 0; i < mlen; i++) m[i] = 0; sfree(m); for (i = 0; i < plen; i++) n[i] = 0; sfree(n);}/* * Decrement a number. */void decbn(Bignum bn){ int i = 1; while (i < bn[0] && bn[i] == 0) bn[i++] = BIGNUM_INT_MASK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -