зеркало из https://github.com/github/putty.git
SSH 2 support, phase 1, debugging. Currently does Diffie-Hellman and gets
the same results as the server, which is a pretty good start. [originally from svn r569]
This commit is contained in:
Родитель
5ca4d2d1c5
Коммит
35205e5cb7
10
Makefile
10
Makefile
|
@ -57,7 +57,8 @@ SOBJS = scp.$(OBJ) windlg.$(OBJ) ssh.$(OBJ) be_none.$(OBJ)
|
|||
MOBJS = misc.$(OBJ) version.$(OBJ)
|
||||
##-- objects putty pscp
|
||||
OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ)
|
||||
OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ)
|
||||
OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ)
|
||||
OBJS3 = sshbn.$(OBJ)
|
||||
##-- resources putty
|
||||
PRESRC = win_res.$(RES)
|
||||
##-- resources puttytel
|
||||
|
@ -78,7 +79,7 @@ LIBS2 = wsock32.lib comctl32.lib comdlg32.lib
|
|||
|
||||
all: putty.exe puttytel.exe pscp.exe
|
||||
|
||||
putty.exe: $(GOBJS1) $(GOBJS2) $(POBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(PRESRC) putty.rsp
|
||||
putty.exe: $(GOBJS1) $(GOBJS2) $(POBJS) $(MOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(PRESRC) putty.rsp
|
||||
link $(LFLAGS) -out:putty.exe @putty.rsp
|
||||
|
||||
puttytel.exe: $(GOBJS1) $(GOBJS2) $(TOBJS) $(MOBJS) $(TRESRC) puttytel.rsp
|
||||
|
@ -95,6 +96,7 @@ putty.rsp: makefile
|
|||
echo $(MOBJS) >> putty.rsp
|
||||
echo $(OBJS1) >> putty.rsp
|
||||
echo $(OBJS2) >> putty.rsp
|
||||
echo $(OBJS3) >> putty.rsp
|
||||
echo $(PRESRC) >> putty.rsp
|
||||
echo $(LIBS1) >> putty.rsp
|
||||
echo $(LIBS2) >> putty.rsp
|
||||
|
@ -115,6 +117,7 @@ pscp.rsp: makefile
|
|||
echo $(MOBJS) >> pscp.rsp
|
||||
echo $(OBJS1) >> pscp.rsp
|
||||
echo $(OBJS2) >> pscp.rsp
|
||||
echo $(OBJS3) >> pscp.rsp
|
||||
echo $(SRESRC) >> pscp.rsp
|
||||
echo $(LIBS1) >> pscp.rsp
|
||||
echo $(LIBS2) >> pscp.rsp
|
||||
|
@ -138,6 +141,9 @@ sshrsa.$(OBJ): sshrsa.c ssh.h
|
|||
sshsha.$(OBJ): sshsha.c ssh.h
|
||||
sshrand.$(OBJ): sshrand.c ssh.h
|
||||
sshblowf.$(OBJ): sshblowf.c ssh.h
|
||||
sshdh.$(OBJ): sshdh.c ssh.h
|
||||
sshdss.$(OBJ): sshdss.c ssh.h
|
||||
sshbn.$(OBJ): sshbn.c ssh.h
|
||||
scp.$(OBJ): scp.c putty.h scp.h
|
||||
version.$(OBJ): version.c
|
||||
be_all.$(OBJ): be_all.c
|
||||
|
|
800
ssh.c
800
ssh.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
60
ssh.h
60
ssh.h
|
@ -1,10 +1,23 @@
|
|||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Useful thing.
|
||||
*/
|
||||
#ifndef lenof
|
||||
#define lenof(x) ( (sizeof((x))) / (sizeof(*(x))))
|
||||
#endif
|
||||
|
||||
#define SSH_CIPHER_IDEA 1
|
||||
#define SSH_CIPHER_DES 2
|
||||
#define SSH_CIPHER_3DES 3
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
|
||||
#ifdef MSCRYPTOAPI
|
||||
#define APIEXTRA 8
|
||||
#else
|
||||
#define APIEXTRA 0
|
||||
#endif
|
||||
|
||||
struct RSAKey {
|
||||
int bits;
|
||||
int bytes;
|
||||
|
@ -48,10 +61,43 @@ void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
|||
unsigned len);
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||
|
||||
typedef struct {
|
||||
uint32 h[5];
|
||||
unsigned char block[64];
|
||||
int blkused;
|
||||
uint32 lenhi, lenlo;
|
||||
} SHA_State;
|
||||
|
||||
void SHA_Init(SHA_State *s);
|
||||
void SHA_Bytes(SHA_State *s, void *p, int len);
|
||||
void SHA_Final(SHA_State *s, unsigned char *output);
|
||||
|
||||
struct ssh_cipher {
|
||||
void (*sesskey)(unsigned char *key);
|
||||
void (*encrypt)(unsigned char *blk, int len);
|
||||
void (*decrypt)(unsigned char *blk, int len);
|
||||
char *name;
|
||||
int blksize;
|
||||
};
|
||||
|
||||
struct ssh_mac {
|
||||
void (*sesskey)(unsigned char *key, int len);
|
||||
void (*generate)(unsigned char *blk, int len, unsigned long seq);
|
||||
int (*verify)(unsigned char *blk, int len, unsigned long seq);
|
||||
char *name;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct ssh_kex {
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct ssh_hostkey {
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct ssh_compress {
|
||||
char *name;
|
||||
};
|
||||
|
||||
#ifndef MSCRYPTOAPI
|
||||
|
@ -62,3 +108,17 @@ int random_byte(void);
|
|||
void random_add_noise(void *noise, int length);
|
||||
|
||||
void logevent (char *);
|
||||
|
||||
/*
|
||||
* A Bignum is stored as a sequence of `unsigned short' words. The
|
||||
* first tells how many remain; the remaining ones are digits, LS
|
||||
* first.
|
||||
*/
|
||||
typedef unsigned short *Bignum;
|
||||
|
||||
Bignum newbn(int length);
|
||||
void freebn(Bignum b);
|
||||
void modpow(Bignum base, Bignum exp, Bignum mod, Bignum result);
|
||||
|
||||
Bignum dh_create_e(void);
|
||||
Bignum dh_find_K(Bignum f);
|
||||
|
|
|
@ -414,5 +414,7 @@ static void blowfish_decrypt_blk(unsigned char *blk, int len)
|
|||
struct ssh_cipher ssh_blowfish = {
|
||||
blowfish_sesskey,
|
||||
blowfish_encrypt_blk,
|
||||
blowfish_decrypt_blk
|
||||
blowfish_decrypt_blk,
|
||||
"blowfish-cbc",
|
||||
8
|
||||
};
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Bignum routines for RSA and DH and stuff.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
static unsigned short Zero[1] = { 0 };
|
||||
|
||||
#if defined TESTMODE || defined RSADEBUG
|
||||
#ifndef DLVL
|
||||
#define DLVL 10000
|
||||
#endif
|
||||
#define debug(x) bndebug(#x,x)
|
||||
static int level = 0;
|
||||
static void bndebug(char *name, Bignum b) {
|
||||
int i;
|
||||
int w = 50-level-strlen(name)-5*b[0];
|
||||
if (level >= DLVL)
|
||||
return;
|
||||
if (w < 0) w = 0;
|
||||
dprintf("%*s%s%*s", level, "", name, w, "");
|
||||
for (i=b[0]; i>0; i--)
|
||||
dprintf(" %04x", b[i]);
|
||||
dprintf("\n");
|
||||
}
|
||||
#define dmsg(x) do {if(level<DLVL){dprintf("%*s",level,"");printf x;}} while(0)
|
||||
#define enter(x) do { dmsg(x); level += 4; } while(0)
|
||||
#define leave(x) do { level -= 4; dmsg(x); } while(0)
|
||||
#else
|
||||
#define debug(x)
|
||||
#define dmsg(x)
|
||||
#define enter(x)
|
||||
#define leave(x)
|
||||
#endif
|
||||
|
||||
Bignum newbn(int length) {
|
||||
Bignum b = malloc((length+1)*sizeof(unsigned short));
|
||||
if (!b)
|
||||
abort(); /* FIXME */
|
||||
memset(b, 0, (length+1)*sizeof(*b));
|
||||
b[0] = length;
|
||||
return b;
|
||||
}
|
||||
|
||||
void freebn(Bignum b) {
|
||||
/*
|
||||
* Burn the evidence, just in case.
|
||||
*/
|
||||
memset(b, 0, sizeof(b[0]) * (b[0] + 1));
|
||||
free(b);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 bigmul(unsigned short *a, unsigned short *b, unsigned short *c,
|
||||
int len)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long ai, t;
|
||||
|
||||
for (j = len - 1; j >= 0; j--)
|
||||
c[j+len] = 0;
|
||||
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
ai = a[i];
|
||||
t = 0;
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
t += ai * (unsigned long) b[j];
|
||||
t += (unsigned long) c[i+j+1];
|
||||
c[i+j+1] = (unsigned short)t;
|
||||
t = t >> 16;
|
||||
}
|
||||
c[i] = (unsigned short)t;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a = a % m.
|
||||
* Input in first 2*len words of a and first len words of m.
|
||||
* Output in first 2*len words of a (of which first len words will be zero).
|
||||
* The MSW of m MUST have its high bit set.
|
||||
*/
|
||||
static void bigmod(unsigned short *a, unsigned short *m, int len)
|
||||
{
|
||||
unsigned short m0, m1;
|
||||
unsigned int h;
|
||||
int i, k;
|
||||
|
||||
/* Special case for len == 1 */
|
||||
if (len == 1) {
|
||||
a[1] = (((long) a[0] << 16) + a[1]) % m[0];
|
||||
a[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m0 = m[0];
|
||||
m1 = m[1];
|
||||
|
||||
for (i = 0; i <= len; i++) {
|
||||
unsigned long t;
|
||||
unsigned int q, r, c;
|
||||
|
||||
if (i == 0) {
|
||||
h = 0;
|
||||
} else {
|
||||
h = a[i-1];
|
||||
a[i-1] = 0;
|
||||
}
|
||||
|
||||
/* Find q = h:a[i] / m0 */
|
||||
t = ((unsigned long) h << 16) + a[i];
|
||||
q = t / m0;
|
||||
r = t % m0;
|
||||
|
||||
/* Refine our estimate of q by looking at
|
||||
h:a[i]:a[i+1] / m0:m1 */
|
||||
t = (long) m1 * (long) q;
|
||||
if (t > ((unsigned long) r << 16) + a[i+1]) {
|
||||
q--;
|
||||
t -= m1;
|
||||
r = (r + m0) & 0xffff; /* overflow? */
|
||||
if (r >= (unsigned long)m0 &&
|
||||
t > ((unsigned long) r << 16) + a[i+1])
|
||||
q--;
|
||||
}
|
||||
|
||||
/* Substract q * m from a[i...] */
|
||||
c = 0;
|
||||
for (k = len - 1; k >= 0; k--) {
|
||||
t = (long) q * (long) m[k];
|
||||
t += c;
|
||||
c = t >> 16;
|
||||
if ((unsigned short) t > a[i+k]) c++;
|
||||
a[i+k] -= (unsigned short) t;
|
||||
}
|
||||
|
||||
/* Add back m in case of borrow */
|
||||
if (c != h) {
|
||||
t = 0;
|
||||
for (k = len - 1; k >= 0; k--) {
|
||||
t += m[k];
|
||||
t += a[i+k];
|
||||
a[i+k] = (unsigned short)t;
|
||||
t = t >> 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute (base ^ exp) % mod.
|
||||
* The base MUST be smaller than the modulus.
|
||||
* 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)
|
||||
{
|
||||
unsigned short *a, *b, *n, *m;
|
||||
int mshift;
|
||||
int mlen, i, j;
|
||||
|
||||
/* Allocate m of size mlen, copy mod to m */
|
||||
/* We use big endian internally */
|
||||
mlen = mod[0];
|
||||
m = malloc(mlen * sizeof(unsigned short));
|
||||
for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j];
|
||||
|
||||
/* Shift m left to make msb bit set */
|
||||
for (mshift = 0; mshift < 15; mshift++)
|
||||
if ((m[0] << mshift) & 0x8000) break;
|
||||
if (mshift) {
|
||||
for (i = 0; i < mlen - 1; i++)
|
||||
m[i] = (m[i] << mshift) | (m[i+1] >> (16-mshift));
|
||||
m[mlen-1] = m[mlen-1] << mshift;
|
||||
}
|
||||
|
||||
/* Allocate n of size mlen, copy base to n */
|
||||
n = malloc(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));
|
||||
for (i = 0; i < 2*mlen; i++) a[i] = 0;
|
||||
a[2*mlen-1] = 1;
|
||||
|
||||
/* Skip leading zero bits of exp. */
|
||||
i = 0; j = 15;
|
||||
while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
|
||||
j--;
|
||||
if (j < 0) { i++; j = 15; }
|
||||
}
|
||||
|
||||
/* Main computation */
|
||||
while (i < exp[0]) {
|
||||
while (j >= 0) {
|
||||
bigmul(a + mlen, a + mlen, b, mlen);
|
||||
bigmod(b, m, mlen);
|
||||
if ((exp[exp[0] - i] & (1 << j)) != 0) {
|
||||
bigmul(b + mlen, n, a, mlen);
|
||||
bigmod(a, m, mlen);
|
||||
} else {
|
||||
unsigned short *t;
|
||||
t = a; a = b; b = t;
|
||||
}
|
||||
j--;
|
||||
}
|
||||
i++; j = 15;
|
||||
}
|
||||
|
||||
/* 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] >> (16-mshift));
|
||||
a[2*mlen-1] = a[2*mlen-1] << mshift;
|
||||
bigmod(a, m, mlen);
|
||||
for (i = 2*mlen - 1; i >= mlen; i--)
|
||||
a[i] = (a[i] >> mshift) | (a[i-1] << (16-mshift));
|
||||
}
|
||||
|
||||
/* Copy result to buffer */
|
||||
for (i = 0; i < mlen; i++)
|
||||
result[result[0] - i] = a[i+mlen];
|
||||
|
||||
/* 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);
|
||||
}
|
8
sshdes.c
8
sshdes.c
|
@ -685,7 +685,9 @@ static void des3_decrypt_blk(unsigned char *blk, int len) {
|
|||
struct ssh_cipher ssh_3des = {
|
||||
des3_sesskey,
|
||||
des3_encrypt_blk,
|
||||
des3_decrypt_blk
|
||||
des3_decrypt_blk,
|
||||
"3des-cbc",
|
||||
8
|
||||
};
|
||||
|
||||
static void des_sesskey(unsigned char *key) {
|
||||
|
@ -705,5 +707,7 @@ static void des_decrypt_blk(unsigned char *blk, int len) {
|
|||
struct ssh_cipher ssh_des = {
|
||||
des_sesskey,
|
||||
des_encrypt_blk,
|
||||
des_decrypt_blk
|
||||
des_decrypt_blk,
|
||||
"des-cbc", /* should never be used - not a valid cipher in ssh2 */
|
||||
8
|
||||
};
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
#include "ssh.h"
|
||||
|
||||
struct ssh_kex ssh_diffiehellman = {
|
||||
"diffie-hellman-group1-sha1"
|
||||
};
|
||||
|
||||
/*
|
||||
* The prime p used in the key exchange.
|
||||
*/
|
||||
static unsigned short P[] = {
|
||||
64,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x5381, 0xECE6, 0x6651, 0x4928,
|
||||
0x1FE6, 0x7C4B, 0x2411, 0xAE9F, 0x9FA5, 0x5A89, 0x6BFB, 0xEE38,
|
||||
0xB7ED, 0xF406, 0x5CB6, 0x0BFF, 0xED6B, 0xA637, 0x42E9, 0xF44C,
|
||||
0x7EC6, 0x625E, 0xB576, 0xE485, 0xC245, 0x6D51, 0x356D, 0x4FE1,
|
||||
0x1437, 0xF25F, 0x0A6D, 0x302B, 0x431B, 0xCD3A, 0x19B3, 0xEF95,
|
||||
0x04DD, 0x8E34, 0x0879, 0x514A, 0x9B22, 0x3B13, 0xBEA6, 0x020B,
|
||||
0xCC74, 0x8A67, 0x4E08, 0x2902, 0x1CD1, 0x80DC, 0x628B, 0xC4C6,
|
||||
0xC234, 0x2168, 0xDAA2, 0xC90F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* The order q of the group: (p-1)/2.
|
||||
*/
|
||||
static unsigned short Q[] = {
|
||||
64,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x29C0, 0xF673, 0x3328, 0x2494,
|
||||
0x8FF3, 0xBE25, 0x9208, 0xD74F, 0xCFD2, 0xAD44, 0x35FD, 0xF71C,
|
||||
0x5BF6, 0x7A03, 0xAE5B, 0x85FF, 0xF6B5, 0xD31B, 0x2174, 0x7A26,
|
||||
0x3F63, 0x312F, 0xDABB, 0xF242, 0xE122, 0xB6A8, 0x9AB6, 0xA7F0,
|
||||
0x8A1B, 0xF92F, 0x8536, 0x9815, 0x218D, 0xE69D, 0x8CD9, 0xF7CA,
|
||||
0x026E, 0xC71A, 0x043C, 0x28A5, 0xCD91, 0x1D89, 0xDF53, 0x0105,
|
||||
0xE63A, 0x4533, 0x2704, 0x9481, 0x0E68, 0xC06E, 0x3145, 0x6263,
|
||||
0x611A, 0x10B4, 0xED51, 0xE487, 0xFFFF, 0xFFFF, 0xFFFF, 0x7FFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* The bitmask covering q (for ease of generation of x).
|
||||
*/
|
||||
static unsigned short Qmask[] = {
|
||||
64,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x7FFF,
|
||||
};
|
||||
|
||||
/*
|
||||
* The generator g = 2.
|
||||
*/
|
||||
static unsigned short G[] = { 1, 2 };
|
||||
|
||||
/*
|
||||
* Variables.
|
||||
*/
|
||||
static Bignum x, e;
|
||||
|
||||
/*
|
||||
* DH stage 1: invent a number x between 1 and q, and compute e =
|
||||
* g^x mod p. Return e.
|
||||
*/
|
||||
Bignum dh_create_e(void) {
|
||||
int i;
|
||||
|
||||
x = newbn(Q[0]);
|
||||
|
||||
tryagain:
|
||||
|
||||
/*
|
||||
* Create a potential x, by ANDing a string of random bytes
|
||||
* with Qmask.
|
||||
*/
|
||||
for (i = 1; i <= x[0]; i++)
|
||||
x[i] = ((random_byte() << 8) + random_byte()) & Qmask[i];
|
||||
|
||||
/*
|
||||
* If x <= 1, go round again.
|
||||
*/
|
||||
for (i = 2; i <= x[0]; i++)
|
||||
if (x[i] != 0)
|
||||
break;
|
||||
if (i > x[0] && x[1] <= 1)
|
||||
goto tryagain;
|
||||
|
||||
/*
|
||||
* If x >= q, go round again.
|
||||
*/
|
||||
for (i = x[0]; i > 0; i--) {
|
||||
if (x[i] > Q[i])
|
||||
goto tryagain;
|
||||
if (x[i] < Q[i])
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Done. Now compute e = g^x mod p.
|
||||
*/
|
||||
e = newbn(P[0]);
|
||||
modpow(G, x, P, e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/*
|
||||
* DH stage 2: given a number f, compute K = f^x mod p.
|
||||
*/
|
||||
Bignum dh_find_K(Bignum f) {
|
||||
Bignum K = newbn(P[0]);
|
||||
modpow(f, x, P, K);
|
||||
return K;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#include "ssh.h"
|
||||
|
||||
struct ssh_hostkey ssh_dss = {
|
||||
"ssh-dss"
|
||||
};
|
202
sshrsa.c
202
sshrsa.c
|
@ -9,12 +9,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
typedef unsigned short *Bignum;
|
||||
|
||||
static unsigned short Zero[1] = { 0 };
|
||||
|
||||
#if defined TESTMODE || defined RSADEBUG
|
||||
#ifndef DLVL
|
||||
#define DLVL 10000
|
||||
|
@ -42,201 +36,7 @@ static void bndebug(char *name, Bignum b) {
|
|||
#define leave(x)
|
||||
#endif
|
||||
|
||||
static Bignum newbn(int length) {
|
||||
Bignum b = malloc((length+1)*sizeof(unsigned short));
|
||||
if (!b)
|
||||
abort(); /* FIXME */
|
||||
b[0] = length;
|
||||
return b;
|
||||
}
|
||||
|
||||
static void freebn(Bignum b) {
|
||||
free(b);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 bigmul(unsigned short *a, unsigned short *b, unsigned short *c,
|
||||
int len)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long ai, t;
|
||||
|
||||
for (j = len - 1; j >= 0; j--)
|
||||
c[j+len] = 0;
|
||||
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
ai = a[i];
|
||||
t = 0;
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
t += ai * (unsigned long) b[j];
|
||||
t += (unsigned long) c[i+j+1];
|
||||
c[i+j+1] = (unsigned short)t;
|
||||
t = t >> 16;
|
||||
}
|
||||
c[i] = (unsigned short)t;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute a = a % m.
|
||||
* Input in first 2*len words of a and first len words of m.
|
||||
* Output in first 2*len words of a (of which first len words will be zero).
|
||||
* The MSW of m MUST have its high bit set.
|
||||
*/
|
||||
static void bigmod(unsigned short *a, unsigned short *m, int len)
|
||||
{
|
||||
unsigned short m0, m1;
|
||||
unsigned int h;
|
||||
int i, k;
|
||||
|
||||
/* Special case for len == 1 */
|
||||
if (len == 1) {
|
||||
a[1] = (((long) a[0] << 16) + a[1]) % m[0];
|
||||
a[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m0 = m[0];
|
||||
m1 = m[1];
|
||||
|
||||
for (i = 0; i <= len; i++) {
|
||||
unsigned long t;
|
||||
unsigned int q, r, c;
|
||||
|
||||
if (i == 0) {
|
||||
h = 0;
|
||||
} else {
|
||||
h = a[i-1];
|
||||
a[i-1] = 0;
|
||||
}
|
||||
|
||||
/* Find q = h:a[i] / m0 */
|
||||
t = ((unsigned long) h << 16) + a[i];
|
||||
q = t / m0;
|
||||
r = t % m0;
|
||||
|
||||
/* Refine our estimate of q by looking at
|
||||
h:a[i]:a[i+1] / m0:m1 */
|
||||
t = (long) m1 * (long) q;
|
||||
if (t > ((unsigned long) r << 16) + a[i+1]) {
|
||||
q--;
|
||||
t -= m1;
|
||||
r = (r + m0) & 0xffff; /* overflow? */
|
||||
if (r >= (unsigned long)m0 &&
|
||||
t > ((unsigned long) r << 16) + a[i+1])
|
||||
q--;
|
||||
}
|
||||
|
||||
/* Substract q * m from a[i...] */
|
||||
c = 0;
|
||||
for (k = len - 1; k >= 0; k--) {
|
||||
t = (long) q * (long) m[k];
|
||||
t += c;
|
||||
c = t >> 16;
|
||||
if ((unsigned short) t > a[i+k]) c++;
|
||||
a[i+k] -= (unsigned short) t;
|
||||
}
|
||||
|
||||
/* Add back m in case of borrow */
|
||||
if (c != h) {
|
||||
t = 0;
|
||||
for (k = len - 1; k >= 0; k--) {
|
||||
t += m[k];
|
||||
t += a[i+k];
|
||||
a[i+k] = (unsigned short)t;
|
||||
t = t >> 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute (base ^ exp) % mod.
|
||||
* The base MUST be smaller than the modulus.
|
||||
* The most significant word of mod MUST be non-zero.
|
||||
* We assume that the result array is the same size as the mod array.
|
||||
*/
|
||||
static void modpow(Bignum base, Bignum exp, Bignum mod, Bignum result)
|
||||
{
|
||||
unsigned short *a, *b, *n, *m;
|
||||
int mshift;
|
||||
int mlen, i, j;
|
||||
|
||||
/* Allocate m of size mlen, copy mod to m */
|
||||
/* We use big endian internally */
|
||||
mlen = mod[0];
|
||||
m = malloc(mlen * sizeof(unsigned short));
|
||||
for (j = 0; j < mlen; j++) m[j] = mod[mod[0] - j];
|
||||
|
||||
/* Shift m left to make msb bit set */
|
||||
for (mshift = 0; mshift < 15; mshift++)
|
||||
if ((m[0] << mshift) & 0x8000) break;
|
||||
if (mshift) {
|
||||
for (i = 0; i < mlen - 1; i++)
|
||||
m[i] = (m[i] << mshift) | (m[i+1] >> (16-mshift));
|
||||
m[mlen-1] = m[mlen-1] << mshift;
|
||||
}
|
||||
|
||||
/* Allocate n of size mlen, copy base to n */
|
||||
n = malloc(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));
|
||||
for (i = 0; i < 2*mlen; i++) a[i] = 0;
|
||||
a[2*mlen-1] = 1;
|
||||
|
||||
/* Skip leading zero bits of exp. */
|
||||
i = 0; j = 15;
|
||||
while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) {
|
||||
j--;
|
||||
if (j < 0) { i++; j = 15; }
|
||||
}
|
||||
|
||||
/* Main computation */
|
||||
while (i < exp[0]) {
|
||||
while (j >= 0) {
|
||||
bigmul(a + mlen, a + mlen, b, mlen);
|
||||
bigmod(b, m, mlen);
|
||||
if ((exp[exp[0] - i] & (1 << j)) != 0) {
|
||||
bigmul(b + mlen, n, a, mlen);
|
||||
bigmod(a, m, mlen);
|
||||
} else {
|
||||
unsigned short *t;
|
||||
t = a; a = b; b = t;
|
||||
}
|
||||
j--;
|
||||
}
|
||||
i++; j = 15;
|
||||
}
|
||||
|
||||
/* 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] >> (16-mshift));
|
||||
a[2*mlen-1] = a[2*mlen-1] << mshift;
|
||||
bigmod(a, m, mlen);
|
||||
for (i = 2*mlen - 1; i >= mlen; i--)
|
||||
a[i] = (a[i] >> mshift) | (a[i-1] << (16-mshift));
|
||||
}
|
||||
|
||||
/* Copy result to buffer */
|
||||
for (i = 0; i < mlen; i++)
|
||||
result[result[0] - i] = a[i+mlen];
|
||||
|
||||
/* 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);
|
||||
}
|
||||
#include "ssh.h"
|
||||
|
||||
int makekey(unsigned char *data, struct RSAKey *result,
|
||||
unsigned char **keystr) {
|
||||
|
|
185
sshsha.c
185
sshsha.c
|
@ -1,12 +1,27 @@
|
|||
/*
|
||||
* SHA core transform algorithm, used here solely as a `stirring'
|
||||
* function for the PuTTY random number pool. Implemented directly
|
||||
* from the specification by Simon Tatham.
|
||||
* SHA1 hash algorithm. Used in SSH2 as a MAC, and the transform is
|
||||
* also used as a `stirring' function for the PuTTY random number
|
||||
* pool. Implemented directly from the specification by Simon
|
||||
* Tatham.
|
||||
*/
|
||||
|
||||
#include "ssh.h"
|
||||
|
||||
#define rol(x,y) ( ((x) << (y)) | (((word32)x) >> (32-y)) )
|
||||
typedef unsigned int uint32;
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Core SHA algorithm: processes 16-word blocks into a message digest.
|
||||
*/
|
||||
|
||||
#define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) )
|
||||
|
||||
void SHA_Core_Init(uint32 h[5]) {
|
||||
h[0] = 0x67452301;
|
||||
h[1] = 0xefcdab89;
|
||||
h[2] = 0x98badcfe;
|
||||
h[3] = 0x10325476;
|
||||
h[4] = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
void SHATransform(word32 *digest, word32 *block) {
|
||||
word32 w[80];
|
||||
|
@ -50,3 +65,165 @@ void SHATransform(word32 *digest, word32 *block) {
|
|||
digest[3] += d;
|
||||
digest[4] += e;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Outer SHA algorithm: take an arbitrary length byte string,
|
||||
* convert it into 16-word blocks with the prescribed padding at
|
||||
* the end, and pass those blocks to the core SHA algorithm.
|
||||
*/
|
||||
|
||||
void SHA_Init(SHA_State *s) {
|
||||
SHA_Core_Init(s->h);
|
||||
s->blkused = 0;
|
||||
s->lenhi = s->lenlo = 0;
|
||||
}
|
||||
|
||||
void SHA_Bytes(SHA_State *s, void *p, int len) {
|
||||
unsigned char *q = (unsigned char *)p;
|
||||
uint32 wordblock[16];
|
||||
uint32 lenw = len;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Update the length field.
|
||||
*/
|
||||
s->lenlo += lenw;
|
||||
s->lenhi += (s->lenlo < lenw);
|
||||
|
||||
if (s->blkused && s->blkused+len < 64) {
|
||||
/*
|
||||
* Trivial case: just add to the block.
|
||||
*/
|
||||
memcpy(s->block + s->blkused, q, len);
|
||||
s->blkused += len;
|
||||
} else {
|
||||
/*
|
||||
* We must complete and process at least one block.
|
||||
*/
|
||||
while (s->blkused + len >= 64) {
|
||||
memcpy(s->block + s->blkused, q, 64 - s->blkused);
|
||||
q += 64 - s->blkused;
|
||||
len -= 64 - s->blkused;
|
||||
/* Now process the block. Gather bytes big-endian into words */
|
||||
for (i = 0; i < 16; i++) {
|
||||
wordblock[i] =
|
||||
( ((uint32)s->block[i*4+0]) << 24 ) |
|
||||
( ((uint32)s->block[i*4+1]) << 16 ) |
|
||||
( ((uint32)s->block[i*4+2]) << 8 ) |
|
||||
( ((uint32)s->block[i*4+3]) << 0 );
|
||||
}
|
||||
SHATransform(s->h, wordblock);
|
||||
s->blkused = 0;
|
||||
}
|
||||
memcpy(s->block, q, len);
|
||||
s->blkused = len;
|
||||
}
|
||||
}
|
||||
|
||||
void SHA_Final(SHA_State *s, unsigned char *output) {
|
||||
int i;
|
||||
int pad;
|
||||
unsigned char c[64];
|
||||
uint32 lenhi, lenlo;
|
||||
|
||||
if (s->blkused >= 56)
|
||||
pad = 56 + 64 - s->blkused;
|
||||
else
|
||||
pad = 56 - s->blkused;
|
||||
|
||||
lenhi = (s->lenhi << 3) | (s->lenlo >> (32-3));
|
||||
lenlo = (s->lenlo << 3);
|
||||
|
||||
memset(c, 0, pad);
|
||||
c[0] = 0x80;
|
||||
SHA_Bytes(s, &c, pad);
|
||||
|
||||
c[0] = (lenhi >> 24) & 0xFF;
|
||||
c[1] = (lenhi >> 16) & 0xFF;
|
||||
c[2] = (lenhi >> 8) & 0xFF;
|
||||
c[3] = (lenhi >> 0) & 0xFF;
|
||||
c[4] = (lenlo >> 24) & 0xFF;
|
||||
c[5] = (lenlo >> 16) & 0xFF;
|
||||
c[6] = (lenlo >> 8) & 0xFF;
|
||||
c[7] = (lenlo >> 0) & 0xFF;
|
||||
|
||||
SHA_Bytes(s, &c, 8);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
output[i*4 ] = (s->h[i] >> 24) & 0xFF;
|
||||
output[i*4+1] = (s->h[i] >> 16) & 0xFF;
|
||||
output[i*4+2] = (s->h[i] >> 8) & 0xFF;
|
||||
output[i*4+3] = (s->h[i] ) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
void SHA_Simple(void *p, int len, unsigned char *output) {
|
||||
SHA_State s;
|
||||
|
||||
SHA_Init(&s);
|
||||
SHA_Bytes(&s, p, len);
|
||||
SHA_Final(&s, output);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* The above is the SHA-1 algorithm itself. Now we implement the
|
||||
* HMAC wrapper on it.
|
||||
*/
|
||||
|
||||
static SHA_State sha1_mac_s1, sha1_mac_s2;
|
||||
|
||||
static void sha1_sesskey(unsigned char *key, int len) {
|
||||
unsigned char foo[64];
|
||||
int i;
|
||||
|
||||
memset(foo, 0x36, 64);
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
SHA_Init(&sha1_mac_s1);
|
||||
SHA_Bytes(&sha1_mac_s1, foo, 64);
|
||||
|
||||
memset(foo, 0x5C, 64);
|
||||
for (i = 0; i < len && i < 64; i++)
|
||||
foo[i] ^= key[i];
|
||||
SHA_Init(&sha1_mac_s2);
|
||||
SHA_Bytes(&sha1_mac_s2, foo, 64);
|
||||
|
||||
memset(foo, 0, 64); /* burn the evidence */
|
||||
}
|
||||
|
||||
static void sha1_do_hmac(unsigned char *blk, int len, unsigned long seq,
|
||||
unsigned char *hmac) {
|
||||
SHA_State s;
|
||||
unsigned char intermediate[20];
|
||||
|
||||
intermediate[0] = (unsigned char)((seq >> 24) & 0xFF);
|
||||
intermediate[1] = (unsigned char)((seq >> 16) & 0xFF);
|
||||
intermediate[2] = (unsigned char)((seq >> 8) & 0xFF);
|
||||
intermediate[3] = (unsigned char)((seq ) & 0xFF);
|
||||
|
||||
s = sha1_mac_s1; /* structure copy */
|
||||
SHA_Bytes(&s, intermediate, 4);
|
||||
SHA_Bytes(&s, blk, len);
|
||||
SHA_Final(&s, intermediate);
|
||||
s = sha1_mac_s2; /* structure copy */
|
||||
SHA_Bytes(&s, intermediate, 20);
|
||||
SHA_Final(&s, hmac);
|
||||
}
|
||||
|
||||
static void sha1_generate(unsigned char *blk, int len, unsigned long seq) {
|
||||
sha1_do_hmac(blk, len, seq, blk+len);
|
||||
}
|
||||
|
||||
static int sha1_verify(unsigned char *blk, int len, unsigned long seq) {
|
||||
unsigned char correct[20];
|
||||
sha1_do_hmac(blk, len, seq, correct);
|
||||
return !memcmp(correct, blk+len, 20);
|
||||
}
|
||||
|
||||
struct ssh_mac ssh_sha1 = {
|
||||
sha1_sesskey,
|
||||
sha1_generate,
|
||||
sha1_verify,
|
||||
"hmac-sha1",
|
||||
20
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче