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:
Simon Tatham 2000-09-05 14:28:17 +00:00
Родитель 5ca4d2d1c5
Коммит 35205e5cb7
10 изменённых файлов: 1324 добавлений и 304 удалений

Просмотреть файл

@ -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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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
};

239
sshbn.c Normal file
Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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
};

115
sshdh.c Normal file
Просмотреть файл

@ -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;
}

5
sshdss.c Normal file
Просмотреть файл

@ -0,0 +1,5 @@
#include "ssh.h"
struct ssh_hostkey ssh_dss = {
"ssh-dss"
};

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
Просмотреть файл

@ -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
};