mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-06 22:12:47 -05:00
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:
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
|
||||
};
|
||||
|
Reference in New Issue
Block a user