From 8b2715b210ef80d1904dc07e6faf8b924a3b09b3 Mon Sep 17 00:00:00 2001 From: simon Date: Thu, 12 Oct 2000 14:24:58 +0000 Subject: [PATCH] Implement MD5 MAC for the benefit of old SSH2 servers git-svn-id: svn://svn.tartarus.org/sgt/putty@709 cda61777-01e9-0310-a592-d414129be87e --- ssh.c | 25 ++++++++++++---------- sshmd5.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 11 deletions(-) diff --git a/ssh.c b/ssh.c index 29cddc44..342bc53a 100644 --- a/ssh.c +++ b/ssh.c @@ -167,7 +167,7 @@ const static struct ssh_kex *kex_algs[] = { &ssh_diffiehellman }; extern const struct ssh_hostkey ssh_dss; const static struct ssh_hostkey *hostkey_algs[] = { &ssh_dss }; -extern const struct ssh_mac ssh_sha1, ssh_sha1_buggy; +extern const struct ssh_mac ssh_md5, ssh_sha1, ssh_sha1_buggy; static void nullmac_key(unsigned char *key) { } static void nullmac_generate(unsigned char *blk, int len, unsigned long seq) { } @@ -175,8 +175,10 @@ static int nullmac_verify(unsigned char *blk, int len, unsigned long seq) { retu const static struct ssh_mac ssh_mac_none = { nullmac_key, nullmac_key, nullmac_generate, nullmac_verify, "none", 0 }; -const static struct ssh_mac *macs[] = { &ssh_sha1, &ssh_mac_none }; -const static struct ssh_mac *buggymacs[] = { &ssh_sha1_buggy, &ssh_mac_none }; +const static struct ssh_mac *macs[] = { + &ssh_sha1, &ssh_md5, &ssh_mac_none }; +const static struct ssh_mac *buggymacs[] = { + &ssh_sha1_buggy, &ssh_md5, &ssh_mac_none }; const static struct ssh_compress ssh_comp_none = { "none" @@ -1830,6 +1832,7 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) static char *str; static Bignum e, f, K; static const struct ssh_mac **maclist; + static int nmacs; static const struct ssh_cipher *cscipher_tobe = NULL; static const struct ssh_cipher *sccipher_tobe = NULL; static const struct ssh_mac *csmac_tobe = NULL; @@ -1864,9 +1867,9 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) * Be prepared to work around the buggy MAC problem. */ if (cfg.buggymac) - maclist = buggymacs; + maclist = buggymacs, nmacs = lenof(buggymacs); else - maclist = macs; + maclist = macs, nmacs = lenof(macs); begin_key_exchange: /* @@ -1907,16 +1910,16 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) } /* List client->server MAC algorithms. */ ssh2_pkt_addstring_start(); - for (i = 0; i < lenof(maclist); i++) { + for (i = 0; i < nmacs; i++) { ssh2_pkt_addstring_str(maclist[i]->name); - if (i < lenof(maclist)-1) + if (i < nmacs-1) ssh2_pkt_addstring_str(","); } /* List server->client MAC algorithms. */ ssh2_pkt_addstring_start(); - for (i = 0; i < lenof(maclist); i++) { + for (i = 0; i < nmacs; i++) { ssh2_pkt_addstring_str(maclist[i]->name); - if (i < lenof(maclist)-1) + if (i < nmacs-1) ssh2_pkt_addstring_str(","); } /* List client->server compression algorithms. */ @@ -1989,14 +1992,14 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) } } ssh2_pkt_getstring(&str, &len); /* client->server mac */ - for (i = 0; i < lenof(maclist); i++) { + for (i = 0; i < nmacs; i++) { if (in_commasep_string(maclist[i]->name, str, len)) { csmac_tobe = maclist[i]; break; } } ssh2_pkt_getstring(&str, &len); /* server->client mac */ - for (i = 0; i < lenof(maclist); i++) { + for (i = 0; i < nmacs; i++) { if (in_commasep_string(maclist[i]->name, str, len)) { scmac_tobe = maclist[i]; break; diff --git a/sshmd5.c b/sshmd5.c index f2ce2b3e..a84e6ad0 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -192,3 +192,77 @@ void MD5Final(unsigned char output[16], struct MD5Context *s) { output[4*i+0] = (s->core.h[i] >> 0) & 0xFF; } } + +/* ---------------------------------------------------------------------- + * The above is the MD5 algorithm itself. Now we implement the + * HMAC wrapper on it. + */ + +static struct MD5Context md5_cs_mac_s1, md5_cs_mac_s2; +static struct MD5Context md5_sc_mac_s1, md5_sc_mac_s2; + +static void md5_key(struct MD5Context *s1, struct MD5Context *s2, + 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]; + MD5Init(s1); + MD5Update(s1, foo, 64); + + memset(foo, 0x5C, 64); + for (i = 0; i < len && i < 64; i++) + foo[i] ^= key[i]; + MD5Init(s2); + MD5Update(s2, foo, 64); + + memset(foo, 0, 64); /* burn the evidence */ +} + +static void md5_cskey(unsigned char *key) { + md5_key(&md5_cs_mac_s1, &md5_cs_mac_s2, key, 16); +} + +static void md5_sckey(unsigned char *key) { + md5_key(&md5_sc_mac_s1, &md5_sc_mac_s2, key, 16); +} + +static void md5_do_hmac(struct MD5Context *s1, struct MD5Context *s2, + unsigned char *blk, int len, unsigned long seq, + unsigned char *hmac) { + struct MD5Context s; + unsigned char intermediate[16]; + + 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 = *s1; /* structure copy */ + MD5Update(&s, intermediate, 4); + MD5Update(&s, blk, len); + MD5Final(intermediate, &s); + s = *s2; /* structure copy */ + MD5Update(&s, intermediate, 16); + MD5Final(hmac, &s); +} + +static void md5_generate(unsigned char *blk, int len, unsigned long seq) { + md5_do_hmac(&md5_cs_mac_s1, &md5_cs_mac_s2, blk, len, seq, blk+len); +} + +static int md5_verify(unsigned char *blk, int len, unsigned long seq) { + unsigned char correct[16]; + md5_do_hmac(&md5_sc_mac_s1, &md5_sc_mac_s2, blk, len, seq, correct); + return !memcmp(correct, blk+len, 16); +} + +struct ssh_mac ssh_md5 = { + md5_cskey, md5_sckey, + md5_generate, + md5_verify, + "hmac-md5", + 16 +}; -- 2.11.0