mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 09:27:59 +00:00
Malcolm Smith's patch to support CHAP (digest-based) authentication
when talking to SOCKS 5 proxies. Configures itself transparently (if the proxy offers CHAP it will use it, otherwise it falls back to ordinary cleartext passwords). [originally from svn r4517]
This commit is contained in:
parent
e2cd7e404e
commit
3af7d33340
39
Recipe
39
Recipe
@ -207,19 +207,26 @@ CHARSET = sbcsdat slookup sbcs utf8 toucs fromucs xenc mimeenc macenc localenc
|
||||
LIBS = advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib
|
||||
+ shell32.lib winmm.lib imm32.lib winspool.lib
|
||||
|
||||
# Network backend sets. This also brings in the relevant attachment
|
||||
# to proxy.c depending on whether we're crypto-avoidant or not.
|
||||
BE_ALL = be_all cproxy
|
||||
BE_NOSSH = be_nossh nocproxy
|
||||
BE_SSH = be_none cproxy
|
||||
BE_NONE = be_none nocproxy
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Definitions of actual programs. The program name, followed by a
|
||||
# colon, followed by a list of objects. Also in the list may be the
|
||||
# keywords [G] for Windows GUI app, [C] for Console app, [X] for
|
||||
# X/GTK Unix app, [U] for command-line Unix app, [M] for Macintosh app.
|
||||
|
||||
putty : [G] GUITERM NONSSH WINSSH be_all WINMISC win_res.res LIBS
|
||||
puttytel : [G] GUITERM NONSSH be_nossh WINMISC win_res.res LIBS
|
||||
plink : [C] plink console NONSSH WINSSH be_all logging WINMISC
|
||||
putty : [G] GUITERM NONSSH WINSSH BE_ALL WINMISC win_res.res LIBS
|
||||
puttytel : [G] GUITERM NONSSH BE_NOSSH WINMISC win_res.res LIBS
|
||||
plink : [C] plink console NONSSH WINSSH BE_ALL logging WINMISC
|
||||
+ plink.res LIBS
|
||||
pscp : [C] scp winsftp console WINSSH be_none SFTP wildcard WINMISC
|
||||
pscp : [C] scp winsftp console WINSSH BE_SSH SFTP wildcard WINMISC
|
||||
+ scp.res LIBS
|
||||
psftp : [C] psftp winsftp console WINSSH be_none SFTP WINMISC scp.res LIBS
|
||||
psftp : [C] psftp winsftp console WINSSH BE_SSH SFTP WINMISC scp.res LIBS
|
||||
|
||||
pageant : [G] pageant sshrsa sshpubk sshdes sshbn sshmd5 version tree234
|
||||
+ misc sshaes sshsha pageantc sshdss sshsh512 winutils winmisc
|
||||
@ -229,28 +236,28 @@ puttygen : [G] puttygen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
|
||||
+ sshrand noise sshsha winstore misc winctrls sshrsa sshdss winmisc
|
||||
+ sshpubk sshaes sshsh512 import winutils puttygen.res tree234 LIBS
|
||||
|
||||
pterm : [X] UXTERM uxmisc misc ldisc settings pty uxsel be_none uxstore
|
||||
pterm : [X] UXTERM uxmisc misc ldisc settings pty uxsel BE_NONE uxstore
|
||||
+ signal CHARSET cmdline ptermm version
|
||||
putty : [X] UXTERM uxmisc misc ldisc settings pty uxsel be_all uxstore
|
||||
putty : [X] UXTERM uxmisc misc ldisc settings pty uxsel BE_ALL uxstore
|
||||
+ signal CHARSET uxputty NONSSH UXSSH UXMISC ux_x11
|
||||
puttytel : [X] UXTERM uxmisc misc ldisc settings pty uxsel be_nossh uxstore
|
||||
+ signal CHARSET uxputty NONSSH UXMISC
|
||||
puttytel : [X] UXTERM uxmisc misc ldisc settings pty uxsel BE_NOSSH
|
||||
+ uxstore signal CHARSET uxputty NONSSH UXMISC
|
||||
|
||||
plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal ux_x11
|
||||
plink : [U] uxplink uxcons NONSSH UXSSH BE_ALL logging UXMISC signal ux_x11
|
||||
|
||||
puttygen : [U] cmdgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
|
||||
+ sshrand uxnoise sshsha misc sshrsa sshdss uxcons uxstore uxmisc
|
||||
+ sshpubk sshaes sshsh512 import puttygen.res tree234 uxgen
|
||||
|
||||
pscp : [U] scp uxsftp uxcons UXSSH be_none SFTP wildcard UXMISC
|
||||
psftp : [U] psftp uxsftp uxcons UXSSH be_none SFTP UXMISC
|
||||
pscp : [U] scp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC
|
||||
psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP UXMISC
|
||||
|
||||
PuTTY : [M] terminal wcwidth ldiscucs logging be_all mac macdlg macevlog
|
||||
PuTTY : [M] terminal wcwidth ldiscucs logging BE_ALL mac macdlg macevlog
|
||||
+ macterm macucs mac_res.rsrc testback NONSSH MACSSH MACMISC CHARSET
|
||||
+ stricmp vsnprint dialog config macctrls
|
||||
PuTTYtel : [M] terminal wcwidth ldiscucs logging be_nossh mac macdlg macevlog
|
||||
+ macterm macucs mac_res.rsrc testback NONSSH MACMISC CHARSET
|
||||
+ stricmp vsnprint dialog config macctrls
|
||||
PuTTYtel : [M] terminal wcwidth ldiscucs logging BE_NOSSH mac macdlg
|
||||
+ macevlog macterm macucs mac_res.rsrc testback NONSSH MACMISC
|
||||
+ CHARSET stricmp vsnprint dialog config macctrls
|
||||
PuTTYgen : [M] macpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
|
||||
+ sshrand macnoise sshsha macstore misc sshrsa sshdss macmisc sshpubk
|
||||
+ sshaes sshsh512 import macpgen.rsrc macpgkey macabout
|
||||
|
190
cproxy.c
Normal file
190
cproxy.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Routines to do cryptographic interaction with proxies in PuTTY.
|
||||
* This is in a separate module from proxy.c, so that it can be
|
||||
* conveniently removed in PuTTYtel by replacing this module with
|
||||
* the stub version nocproxy.c.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEFINE_PLUG_METHOD_MACROS
|
||||
#include "putty.h"
|
||||
#include "ssh.h" /* For MD5 support */
|
||||
#include "network.h"
|
||||
#include "proxy.h"
|
||||
|
||||
static void hmacmd5_chap(const unsigned char *challenge, int challen,
|
||||
const char *passwd, unsigned char *response)
|
||||
{
|
||||
void *hmacmd5_ctx;
|
||||
int pwlen;
|
||||
|
||||
hmacmd5_ctx = hmacmd5_make_context();
|
||||
|
||||
pwlen = strlen(passwd);
|
||||
if (pwlen>64) {
|
||||
unsigned char md5buf[16];
|
||||
MD5Simple(passwd, pwlen, md5buf);
|
||||
hmacmd5_key(hmacmd5_ctx, md5buf, 16);
|
||||
} else {
|
||||
hmacmd5_key(hmacmd5_ctx, passwd, pwlen);
|
||||
}
|
||||
|
||||
hmacmd5_do_hmac(hmacmd5_ctx, challenge, challen, response);
|
||||
hmacmd5_free_context(hmacmd5_ctx);
|
||||
}
|
||||
|
||||
void proxy_socks5_offerencryptedauth(char *command, int *len)
|
||||
{
|
||||
command[*len] = 0x03; /* CHAP */
|
||||
(*len)++;
|
||||
}
|
||||
|
||||
int proxy_socks5_handlechap (Proxy_Socket p)
|
||||
{
|
||||
|
||||
/* CHAP authentication reply format:
|
||||
* version number (1 bytes) = 1
|
||||
* number of commands (1 byte)
|
||||
*
|
||||
* For each command:
|
||||
* command identifier (1 byte)
|
||||
* data length (1 byte)
|
||||
*/
|
||||
unsigned char data[260];
|
||||
unsigned char outbuf[20];
|
||||
|
||||
while(p->chap_num_attributes == 0 ||
|
||||
p->chap_num_attributes_processed < p->chap_num_attributes) {
|
||||
if (p->chap_num_attributes == 0 ||
|
||||
p->chap_current_attribute == -1) {
|
||||
/* CHAP normally reads in two bytes, either at the
|
||||
* beginning or for each attribute/value pair. But if
|
||||
* we're waiting for the value's data, we might not want
|
||||
* to read 2 bytes.
|
||||
*/
|
||||
|
||||
if (bufchain_size(&p->pending_input_data) < 2)
|
||||
return 1; /* not got anything yet */
|
||||
|
||||
/* get the response */
|
||||
bufchain_fetch(&p->pending_input_data, data, 2);
|
||||
bufchain_consume(&p->pending_input_data, 2);
|
||||
}
|
||||
|
||||
if (p->chap_num_attributes == 0) {
|
||||
/* If there are no attributes, this is our first msg
|
||||
* with the server, where we negotiate version and
|
||||
* number of attributes
|
||||
*/
|
||||
if (data[0] != 0x01) {
|
||||
plug_closing(p->plug, "Proxy error: SOCKS proxy wants"
|
||||
" a different CHAP version",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
||||
if (data[1] == 0x00) {
|
||||
plug_closing(p->plug, "Proxy error: SOCKS proxy won't"
|
||||
" negotiate CHAP with us",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
||||
p->chap_num_attributes = data[1];
|
||||
} else {
|
||||
if (p->chap_current_attribute == -1) {
|
||||
/* We have to read in each attribute/value pair -
|
||||
* those we don't understand can be ignored, but
|
||||
* there are a few we'll need to handle.
|
||||
*/
|
||||
p->chap_current_attribute = data[0];
|
||||
p->chap_current_datalen = data[1];
|
||||
}
|
||||
if (bufchain_size(&p->pending_input_data) <
|
||||
p->chap_current_datalen)
|
||||
return 1; /* not got everything yet */
|
||||
|
||||
/* get the response */
|
||||
bufchain_fetch(&p->pending_input_data, data,
|
||||
p->chap_current_datalen);
|
||||
|
||||
bufchain_consume(&p->pending_input_data,
|
||||
p->chap_current_datalen);
|
||||
|
||||
switch (p->chap_current_attribute) {
|
||||
case 0x00:
|
||||
/* Successful authentication */
|
||||
if (data[0] == 0x00)
|
||||
p->state = 2;
|
||||
else {
|
||||
plug_closing(p->plug, "Proxy error: SOCKS proxy"
|
||||
" refused CHAP authentication",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 0x03:
|
||||
outbuf[0] = 0x01; /* Version */
|
||||
outbuf[1] = 0x01; /* One attribute */
|
||||
outbuf[2] = 0x04; /* Response */
|
||||
outbuf[3] = 0x10; /* Length */
|
||||
hmacmd5_chap(data, p->chap_current_datalen,
|
||||
p->cfg.proxy_password, &outbuf[4]);
|
||||
sk_write(p->sub_socket, outbuf, 20);
|
||||
break;
|
||||
case 0x11:
|
||||
/* Chose a protocol */
|
||||
if (data[0] != 0x85) {
|
||||
plug_closing(p->plug, "Proxy error: Server chose "
|
||||
"CHAP of other than HMAC-MD5 but we "
|
||||
"didn't offer it!",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p->chap_current_attribute = -1;
|
||||
p->chap_num_attributes_processed++;
|
||||
}
|
||||
if (p->state == 8 &&
|
||||
p->chap_num_attributes_processed >= p->chap_num_attributes) {
|
||||
p->chap_num_attributes = 0;
|
||||
p->chap_num_attributes_processed = 0;
|
||||
p->chap_current_datalen = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_socks5_selectchap(Proxy_Socket p)
|
||||
{
|
||||
if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) {
|
||||
char chapbuf[514];
|
||||
int ulen;
|
||||
chapbuf[0] = '\x01'; /* Version */
|
||||
chapbuf[1] = '\x02'; /* Number of attributes sent */
|
||||
chapbuf[2] = '\x11'; /* First attribute - algorithms list */
|
||||
chapbuf[3] = '\x01'; /* Only one CHAP algorithm */
|
||||
chapbuf[4] = '\x85'; /* ...and it's HMAC-MD5, the core one */
|
||||
chapbuf[5] = '\x02'; /* Second attribute - username */
|
||||
|
||||
ulen = strlen(p->cfg.proxy_username);
|
||||
if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1;
|
||||
|
||||
chapbuf[6] = ulen;
|
||||
memcpy(chapbuf+7, p->cfg.proxy_username, ulen);
|
||||
|
||||
sk_write(p->sub_socket, chapbuf, ulen + 7);
|
||||
p->chap_num_attributes = 0;
|
||||
p->chap_num_attributes_processed = 0;
|
||||
p->chap_current_attribute = -1;
|
||||
p->chap_current_datalen = 0;
|
||||
|
||||
p->state = 8;
|
||||
} else
|
||||
plug_closing(p->plug, "Proxy error: Server chose "
|
||||
"CHAP authentication but we didn't offer it!",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
36
nocproxy.c
Normal file
36
nocproxy.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Routines to refuse to do cryptographic interaction with proxies
|
||||
* in PuTTY. This is a stub implementation of the same interfaces
|
||||
* provided by cproxy.c, for use in PuTTYtel.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEFINE_PLUG_METHOD_MACROS
|
||||
#include "putty.h"
|
||||
#include "network.h"
|
||||
#include "proxy.h"
|
||||
|
||||
void proxy_socks5_offerencryptedauth(char * command, int * len)
|
||||
{
|
||||
/* For telnet, don't add any new encrypted authentication routines */
|
||||
}
|
||||
|
||||
int proxy_socks5_handlechap (Proxy_Socket p)
|
||||
{
|
||||
|
||||
plug_closing(p->plug, "Proxy error: Trying to handle a SOCKS5 CHAP request"
|
||||
" in telnet-only build",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int proxy_socks5_selectchap(Proxy_Socket p)
|
||||
{
|
||||
plug_closing(p->plug, "Proxy error: Trying to handle a SOCKS5 CHAP request"
|
||||
" in telnet-only build",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
24
proxy.c
24
proxy.c
@ -859,15 +859,16 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
* 0x03 = CHAP
|
||||
*/
|
||||
|
||||
char command[4];
|
||||
char command[5];
|
||||
int len;
|
||||
|
||||
command[0] = 5; /* version 5 */
|
||||
if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) {
|
||||
command[1] = 2; /* two methods supported: */
|
||||
command[2] = 0x00; /* no authentication */
|
||||
command[3] = 0x02; /* username/password */
|
||||
len = 4;
|
||||
len = 3;
|
||||
proxy_socks5_offerencryptedauth (command, &len);
|
||||
command[len++] = 0x02; /* username/password */
|
||||
command[1] = len - 2; /* Number of methods supported */
|
||||
} else {
|
||||
command[1] = 1; /* one methods supported: */
|
||||
command[2] = 0x00; /* no authentication */
|
||||
@ -923,7 +924,7 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
* authentication methods:
|
||||
* 0x00 = no authentication
|
||||
* 0x01 = GSSAPI
|
||||
* 0x02 = username/password
|
||||
* 0x02 = username/password
|
||||
* 0x03 = CHAP
|
||||
* 0xff = no acceptable methods
|
||||
*/
|
||||
@ -988,6 +989,12 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
p->state = 2; /* now proceed as authenticated */
|
||||
}
|
||||
|
||||
if (p->state == 8) {
|
||||
int ret;
|
||||
ret = proxy_socks5_handlechap(p);
|
||||
if (ret) return ret;
|
||||
}
|
||||
|
||||
if (p->state == 2) {
|
||||
|
||||
/* request format:
|
||||
@ -1156,10 +1163,9 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change)
|
||||
}
|
||||
|
||||
if (p->state == 6) {
|
||||
/* TODO: Handle CHAP authentication */
|
||||
plug_closing(p->plug, "Proxy error: We don't support CHAP authentication",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
int ret;
|
||||
ret = proxy_socks5_selectchap(p);
|
||||
if (ret) return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
14
proxy.h
14
proxy.h
@ -81,6 +81,12 @@ struct Socket_proxy_tag {
|
||||
|
||||
/* configuration, used to look up proxy settings */
|
||||
Config cfg;
|
||||
|
||||
/* CHAP transient data */
|
||||
int chap_num_attributes;
|
||||
int chap_num_attributes_processed;
|
||||
int chap_current_attribute;
|
||||
int chap_current_datalen;
|
||||
};
|
||||
|
||||
typedef struct Plug_proxy_tag * Proxy_Plug;
|
||||
@ -106,4 +112,12 @@ extern int proxy_socks5_negotiate (Proxy_Socket, int);
|
||||
*/
|
||||
char *format_telnet_command(SockAddr addr, int port, const Config *cfg);
|
||||
|
||||
/*
|
||||
* These are implemented in cproxy.c or nocproxy.c, depending on
|
||||
* whether encrypted proxy authentication is available.
|
||||
*/
|
||||
extern void proxy_socks5_offerencryptedauth(char *command, int *len);
|
||||
extern int proxy_socks5_handlechap (Proxy_Socket p);
|
||||
extern int proxy_socks5_selectchap(Proxy_Socket p);
|
||||
|
||||
#endif
|
||||
|
4
putty.h
4
putty.h
@ -338,8 +338,8 @@ struct config_tag {
|
||||
int proxy_type;
|
||||
char proxy_host[512];
|
||||
int proxy_port;
|
||||
char proxy_username[32];
|
||||
char proxy_password[32];
|
||||
char proxy_username[128];
|
||||
char proxy_password[128];
|
||||
char proxy_telnet_command[512];
|
||||
/* SSH options */
|
||||
char remote_cmd[512];
|
||||
|
7
ssh.h
7
ssh.h
@ -101,6 +101,13 @@ void MD5Init(struct MD5Context *context);
|
||||
void MD5Update(struct MD5Context *context, unsigned char const *buf,
|
||||
unsigned len);
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *context);
|
||||
void MD5Simple(void const *p, unsigned len, unsigned char output[16]);
|
||||
|
||||
void *hmacmd5_make_context(void);
|
||||
void hmacmd5_free_context(void *handle);
|
||||
void hmacmd5_key(void *handle, unsigned char const *key, int len);
|
||||
void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len,
|
||||
unsigned char *hmac);
|
||||
|
||||
typedef struct {
|
||||
uint32 h[5];
|
||||
|
70
sshmd5.c
70
sshmd5.c
@ -203,22 +203,34 @@ void MD5Final(unsigned char output[16], struct MD5Context *s)
|
||||
}
|
||||
}
|
||||
|
||||
void MD5Simple(void const *p, unsigned len, unsigned char output[16])
|
||||
{
|
||||
struct MD5Context s;
|
||||
|
||||
MD5Init(&s);
|
||||
MD5Update(&s, (unsigned char const *)p, len);
|
||||
MD5Final(output, &s);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* The above is the MD5 algorithm itself. Now we implement the
|
||||
* HMAC wrapper on it.
|
||||
*
|
||||
* Some of these functions are exported directly, because they are
|
||||
* useful elsewhere (SOCKS5 CHAP authentication uses HMAC-MD5).
|
||||
*/
|
||||
|
||||
static void *md5_make_context(void)
|
||||
void *hmacmd5_make_context(void)
|
||||
{
|
||||
return snewn(2, struct MD5Context);
|
||||
}
|
||||
|
||||
static void md5_free_context(void *handle)
|
||||
void hmacmd5_free_context(void *handle)
|
||||
{
|
||||
sfree(handle);
|
||||
}
|
||||
|
||||
static void md5_key_internal(void *handle, unsigned char *key, int len)
|
||||
void hmacmd5_key(void *handle, unsigned char const *key, int len)
|
||||
{
|
||||
struct MD5Context *keys = (struct MD5Context *)handle;
|
||||
unsigned char foo[64];
|
||||
@ -239,49 +251,65 @@ static void md5_key_internal(void *handle, unsigned char *key, int len)
|
||||
memset(foo, 0, 64); /* burn the evidence */
|
||||
}
|
||||
|
||||
static void md5_key(void *handle, unsigned char *key)
|
||||
static void hmacmd5_key_16(void *handle, unsigned char *key)
|
||||
{
|
||||
md5_key_internal(handle, key, 16);
|
||||
hmacmd5_key(handle, key, 16);
|
||||
}
|
||||
|
||||
static void md5_do_hmac(void *handle, unsigned char *blk, int len,
|
||||
unsigned long seq, unsigned char *hmac)
|
||||
static void hmacmd5_do_hmac_internal(void *handle,
|
||||
unsigned char const *blk, int len,
|
||||
unsigned char const *blk2, int len2,
|
||||
unsigned char *hmac)
|
||||
{
|
||||
struct MD5Context *keys = (struct MD5Context *)handle;
|
||||
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 = keys[0]; /* structure copy */
|
||||
MD5Update(&s, intermediate, 4);
|
||||
MD5Update(&s, blk, len);
|
||||
if (blk2) MD5Update(&s, blk2, len2);
|
||||
MD5Final(intermediate, &s);
|
||||
s = keys[1]; /* structure copy */
|
||||
MD5Update(&s, intermediate, 16);
|
||||
MD5Final(hmac, &s);
|
||||
}
|
||||
|
||||
static void md5_generate(void *handle, unsigned char *blk, int len,
|
||||
unsigned long seq)
|
||||
void hmacmd5_do_hmac(void *handle, unsigned char const *blk, int len,
|
||||
unsigned char *hmac)
|
||||
{
|
||||
md5_do_hmac(handle, blk, len, seq, blk + len);
|
||||
hmacmd5_do_hmac_internal(handle, blk, len, NULL, 0, hmac);
|
||||
}
|
||||
|
||||
static int md5_verify(void *handle, unsigned char *blk, int len,
|
||||
unsigned long seq)
|
||||
static void hmacmd5_do_hmac_ssh(void *handle, unsigned char const *blk, int len,
|
||||
unsigned long seq, unsigned char *hmac)
|
||||
{
|
||||
unsigned char seqbuf[16];
|
||||
|
||||
seqbuf[0] = (unsigned char) ((seq >> 24) & 0xFF);
|
||||
seqbuf[1] = (unsigned char) ((seq >> 16) & 0xFF);
|
||||
seqbuf[2] = (unsigned char) ((seq >> 8) & 0xFF);
|
||||
seqbuf[3] = (unsigned char) ((seq) & 0xFF);
|
||||
|
||||
hmacmd5_do_hmac_internal(handle, seqbuf, 4, blk, len, hmac);
|
||||
}
|
||||
|
||||
static void hmacmd5_generate(void *handle, unsigned char *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
hmacmd5_do_hmac_ssh(handle, blk, len, seq, blk + len);
|
||||
}
|
||||
|
||||
static int hmacmd5_verify(void *handle, unsigned char *blk, int len,
|
||||
unsigned long seq)
|
||||
{
|
||||
unsigned char correct[16];
|
||||
md5_do_hmac(handle, blk, len, seq, correct);
|
||||
hmacmd5_do_hmac_ssh(handle, blk, len, seq, correct);
|
||||
return !memcmp(correct, blk + len, 16);
|
||||
}
|
||||
|
||||
const struct ssh_mac ssh_md5 = {
|
||||
md5_make_context, md5_free_context, md5_key,
|
||||
md5_generate, md5_verify,
|
||||
hmacmd5_make_context, hmacmd5_free_context, hmacmd5_key_16,
|
||||
hmacmd5_generate, hmacmd5_verify,
|
||||
"hmac-md5",
|
||||
16
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user