mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-25 01:02:24 +00:00
Centralised HMAC implementation.
This replaces all the separate HMAC-implementing wrappers in the various source files implementing the underlying hashes. The new HMAC code also correctly handles the case of a key longer than the underlying hash's block length, by replacing it with its own hash. This means I can reinstate the test vectors in RFC 6234 which exercise that case, which I didn't add to cryptsuite before because they'd have failed. It also allows me to remove the ad-hoc code at the call site in cproxy.c which turns out to have been doing the same thing - I think that must have been the only call site where the question came up (since MAC keys invented by the main SSH-2 BPP are always shorter than that).
This commit is contained in:
parent
d73f692eea
commit
baff23cdd6
9
Recipe
9
Recipe
@ -255,6 +255,7 @@ SSHCRYPTO = ARITH sshmd5 sshsha sshsh256 sshsh512
|
|||||||
+ sshrsa sshdss sshecc
|
+ sshrsa sshdss sshecc
|
||||||
+ sshdes sshblowf sshaes sshccp ssharcf
|
+ sshdes sshblowf sshaes sshccp ssharcf
|
||||||
+ sshdh sshcrc sshcrcda sshauxcrypt
|
+ sshdh sshcrc sshcrcda sshauxcrypt
|
||||||
|
+ sshhmac
|
||||||
SSHCOMMON = sshcommon sshrand SSHCRYPTO
|
SSHCOMMON = sshcommon sshrand SSHCRYPTO
|
||||||
+ sshverstring
|
+ sshverstring
|
||||||
+ sshpubk sshzlib
|
+ sshpubk sshzlib
|
||||||
@ -333,13 +334,13 @@ psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
|
|||||||
pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
|
pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
|
||||||
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
|
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
|
||||||
+ sshsh512 winutils sshecc winmisc winmiscs winhelp conf pageant.res
|
+ sshsh512 winutils sshecc winmisc winmiscs winhelp conf pageant.res
|
||||||
+ sshauxcrypt LIBS
|
+ sshauxcrypt sshhmac LIBS
|
||||||
|
|
||||||
puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
|
puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
|
||||||
+ sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc
|
+ sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc
|
||||||
+ sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res
|
+ sshpubk sshaes sshsh256 sshsh512 IMPORT winutils puttygen.res
|
||||||
+ tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc
|
+ tree234 notiming winhelp winnojmp CONF LIBS wintime sshecc
|
||||||
+ sshecdsag sshauxcrypt winsecur winmiscs
|
+ sshecdsag sshauxcrypt sshhmac winsecur winmiscs
|
||||||
|
|
||||||
pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
|
pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
|
||||||
+ uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg
|
+ uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg
|
||||||
@ -357,7 +358,7 @@ plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal
|
|||||||
PUTTYGEN_UNIX = sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
|
PUTTYGEN_UNIX = sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
|
||||||
+ sshrand uxnoise sshsha MISC sshrsa sshdss uxcons uxstore uxmisc
|
+ sshrand uxnoise sshsha MISC sshrsa sshdss uxcons uxstore uxmisc
|
||||||
+ sshpubk sshaes sshsh256 sshsh512 IMPORT puttygen.res time tree234
|
+ sshpubk sshaes sshsh256 sshsh512 IMPORT puttygen.res time tree234
|
||||||
+ uxgen notiming CONF sshecc sshecdsag uxnogtk sshauxcrypt
|
+ uxgen notiming CONF sshecc sshecdsag uxnogtk sshauxcrypt sshhmac
|
||||||
puttygen : [U] cmdgen PUTTYGEN_UNIX
|
puttygen : [U] cmdgen PUTTYGEN_UNIX
|
||||||
cgtest : [UT] cgtest PUTTYGEN_UNIX
|
cgtest : [UT] cgtest PUTTYGEN_UNIX
|
||||||
|
|
||||||
@ -368,7 +369,7 @@ pageant : [X] uxpgnt uxagentc aqsync pageant sshrsa sshpubk sshdes ARITH
|
|||||||
+ sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512
|
+ sshmd5 version tree234 misc sshaes sshsha sshdss sshsh256 sshsh512
|
||||||
+ sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons
|
+ sshecc CONF uxsignal nocproxy nogss be_none x11fwd ux_x11 uxcons
|
||||||
+ gtkask gtkmisc nullplug logging UXMISC uxagentsock utils memory
|
+ gtkask gtkmisc nullplug logging UXMISC uxagentsock utils memory
|
||||||
+ sshauxcrypt
|
+ sshauxcrypt sshhmac
|
||||||
|
|
||||||
ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
|
ptermapp : [XT] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
|
||||||
+ uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg
|
+ uxsignal CHARSET uxpterm version time xpmpterm xpmptcfg
|
||||||
|
11
cproxy.c
11
cproxy.c
@ -18,15 +18,8 @@
|
|||||||
static void hmacmd5_chap(const unsigned char *challenge, int challen,
|
static void hmacmd5_chap(const unsigned char *challenge, int challen,
|
||||||
const char *passwd, unsigned char *response)
|
const char *passwd, unsigned char *response)
|
||||||
{
|
{
|
||||||
ptrlen key = ptrlen_from_asciz(passwd);
|
mac_simple(&ssh_hmac_md5, ptrlen_from_asciz(passwd),
|
||||||
unsigned char md5buf[16];
|
make_ptrlen(challenge, challen), response);
|
||||||
|
|
||||||
if (key.len > 64) {
|
|
||||||
hash_simple(&ssh_md5, key, md5buf);
|
|
||||||
key = make_ptrlen(md5buf, 16);
|
|
||||||
}
|
|
||||||
mac_simple(&ssh_hmac_md5, key, make_ptrlen(challenge, challen), response);
|
|
||||||
smemclr(md5buf, sizeof(md5buf));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void proxy_socks5_offerencryptedauth(BinarySink *bs)
|
void proxy_socks5_offerencryptedauth(BinarySink *bs)
|
||||||
|
@ -31,10 +31,16 @@ struct BinarySink {
|
|||||||
* put 'BinarySink_DELEGATE_IMPLEMENTATION' in its declaration, and
|
* put 'BinarySink_DELEGATE_IMPLEMENTATION' in its declaration, and
|
||||||
* when an instance is set up, use 'BinarySink_DELEGATE_INIT' to point
|
* when an instance is set up, use 'BinarySink_DELEGATE_INIT' to point
|
||||||
* at the object it wants to delegate to.
|
* at the object it wants to delegate to.
|
||||||
|
*
|
||||||
|
* In such a delegated structure, you might sometimes want to have the
|
||||||
|
* delegation stop being valid (e.g. it might be delegating to an
|
||||||
|
* object that only sometimes exists). You can null out the delegate
|
||||||
|
* pointer using BinarySink_DELEGATE_CLEAR.
|
||||||
*/
|
*/
|
||||||
#define BinarySink_DELEGATE_IMPLEMENTATION BinarySink *binarysink_
|
#define BinarySink_DELEGATE_IMPLEMENTATION BinarySink *binarysink_
|
||||||
#define BinarySink_DELEGATE_INIT(obj, othersink) \
|
#define BinarySink_DELEGATE_INIT(obj, othersink) \
|
||||||
((obj)->binarysink_ = BinarySink_UPCAST(othersink))
|
((obj)->binarysink_ = BinarySink_UPCAST(othersink))
|
||||||
|
#define BinarySink_DELEGATE_CLEAR(obj) ((obj)->binarysink_ = NULL)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The implementing type's write function will want to downcast its
|
* The implementing type's write function will want to downcast its
|
||||||
|
210
sshhmac.c
Normal file
210
sshhmac.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Implementation of HMAC (RFC 2104) for PuTTY, in a general form that
|
||||||
|
* can wrap any underlying hash function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ssh.h"
|
||||||
|
|
||||||
|
struct hmac {
|
||||||
|
ssh_hash *h_outer, *h_inner, *h_live;
|
||||||
|
uint8_t *digest;
|
||||||
|
strbuf *text_name;
|
||||||
|
ssh2_mac mac;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hmac_extra {
|
||||||
|
const ssh_hashalg *hashalg;
|
||||||
|
size_t blklen;
|
||||||
|
const char *suffix;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
||||||
|
{
|
||||||
|
struct hmac *ctx = snew(struct hmac);
|
||||||
|
const struct hmac_extra *extra = (const struct hmac_extra *)alg->extra;
|
||||||
|
|
||||||
|
ctx->h_outer = ctx->h_inner = ctx->h_live = NULL;
|
||||||
|
ctx->digest = snewn(extra->hashalg->hlen, uint8_t);
|
||||||
|
|
||||||
|
ctx->text_name = strbuf_new();
|
||||||
|
strbuf_catf(ctx->text_name, "HMAC-%s%s",
|
||||||
|
extra->hashalg->text_name, extra->suffix);
|
||||||
|
|
||||||
|
ctx->mac.vt = alg;
|
||||||
|
BinarySink_DELEGATE_CLEAR(&ctx->mac);
|
||||||
|
|
||||||
|
return &ctx->mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmac_free(ssh2_mac *mac)
|
||||||
|
{
|
||||||
|
struct hmac *ctx = container_of(mac, struct hmac, mac);
|
||||||
|
const struct hmac_extra *extra = (const struct hmac_extra *)mac->vt->extra;
|
||||||
|
|
||||||
|
if (ctx->h_outer)
|
||||||
|
ssh_hash_free(ctx->h_outer);
|
||||||
|
if (ctx->h_inner)
|
||||||
|
ssh_hash_free(ctx->h_inner);
|
||||||
|
if (ctx->h_live)
|
||||||
|
ssh_hash_free(ctx->h_live);
|
||||||
|
smemclr(ctx->digest, extra->hashalg->hlen);
|
||||||
|
sfree(ctx->digest);
|
||||||
|
strbuf_free(ctx->text_name);
|
||||||
|
|
||||||
|
smemclr(ctx, sizeof(*ctx));
|
||||||
|
sfree(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PAD_OUTER 0x5C
|
||||||
|
#define PAD_INNER 0x36
|
||||||
|
|
||||||
|
static void hmac_key(ssh2_mac *mac, ptrlen key)
|
||||||
|
{
|
||||||
|
struct hmac *ctx = container_of(mac, struct hmac, mac);
|
||||||
|
const struct hmac_extra *extra = (const struct hmac_extra *)mac->vt->extra;
|
||||||
|
|
||||||
|
const uint8_t *kp;
|
||||||
|
size_t klen;
|
||||||
|
strbuf *sb = NULL;
|
||||||
|
|
||||||
|
if (key.len > extra->blklen) {
|
||||||
|
/*
|
||||||
|
* RFC 2104 section 2: if the key exceeds the block length of
|
||||||
|
* the underlying hash, then we start by hashing the key, and
|
||||||
|
* use that hash as the 'true' key for the HMAC construction.
|
||||||
|
*/
|
||||||
|
sb = strbuf_new();
|
||||||
|
strbuf_append(sb, extra->hashalg->hlen);
|
||||||
|
|
||||||
|
ssh_hash *htmp = ssh_hash_new(extra->hashalg);
|
||||||
|
put_datapl(htmp, key);
|
||||||
|
ssh_hash_final(htmp, sb->u);
|
||||||
|
|
||||||
|
kp = sb->u;
|
||||||
|
klen = sb->len;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* A short enough key is used as is.
|
||||||
|
*/
|
||||||
|
kp = (const uint8_t *)key.ptr;
|
||||||
|
klen = key.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->h_outer)
|
||||||
|
ssh_hash_free(ctx->h_outer);
|
||||||
|
if (ctx->h_inner)
|
||||||
|
ssh_hash_free(ctx->h_inner);
|
||||||
|
|
||||||
|
ctx->h_outer = ssh_hash_new(extra->hashalg);
|
||||||
|
for (size_t i = 0; i < klen; i++)
|
||||||
|
put_byte(ctx->h_outer, PAD_OUTER ^ kp[i]);
|
||||||
|
for (size_t i = klen; i < extra->blklen; i++)
|
||||||
|
put_byte(ctx->h_outer, PAD_OUTER);
|
||||||
|
|
||||||
|
ctx->h_inner = ssh_hash_new(extra->hashalg);
|
||||||
|
for (size_t i = 0; i < klen; i++)
|
||||||
|
put_byte(ctx->h_inner, PAD_INNER ^ kp[i]);
|
||||||
|
for (size_t i = klen; i < extra->blklen; i++)
|
||||||
|
put_byte(ctx->h_inner, PAD_INNER);
|
||||||
|
|
||||||
|
if (sb)
|
||||||
|
strbuf_free(sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmac_start(ssh2_mac *mac)
|
||||||
|
{
|
||||||
|
struct hmac *ctx = container_of(mac, struct hmac, mac);
|
||||||
|
|
||||||
|
assert(ctx->h_outer);
|
||||||
|
if (ctx->h_live)
|
||||||
|
ssh_hash_free(ctx->h_live);
|
||||||
|
|
||||||
|
ctx->h_live = ssh_hash_copy(ctx->h_inner);
|
||||||
|
BinarySink_DELEGATE_INIT(&ctx->mac, ctx->h_live);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hmac_genresult(ssh2_mac *mac, unsigned char *output)
|
||||||
|
{
|
||||||
|
struct hmac *ctx = container_of(mac, struct hmac, mac);
|
||||||
|
const struct hmac_extra *extra = (const struct hmac_extra *)mac->vt->extra;
|
||||||
|
|
||||||
|
assert(ctx->h_live);
|
||||||
|
ssh_hash_final(ctx->h_live, ctx->digest);
|
||||||
|
|
||||||
|
ctx->h_live = NULL;
|
||||||
|
BinarySink_DELEGATE_CLEAR(&ctx->mac);
|
||||||
|
|
||||||
|
ssh_hash *htmp = ssh_hash_copy(ctx->h_outer);
|
||||||
|
put_data(htmp, ctx->digest, extra->hashalg->hlen);
|
||||||
|
ssh_hash_final(htmp, ctx->digest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some instances of HMAC truncate the output hash, so instead of
|
||||||
|
* writing it directly to 'output' we wrote it to our own
|
||||||
|
* full-length buffer, and now we copy the required amount.
|
||||||
|
*/
|
||||||
|
memcpy(output, ctx->digest, mac->vt->len);
|
||||||
|
smemclr(ctx->digest, extra->hashalg->hlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *hmac_text_name(ssh2_mac *mac)
|
||||||
|
{
|
||||||
|
struct hmac *ctx = container_of(mac, struct hmac, mac);
|
||||||
|
return ctx->text_name->s;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, 64, "" };
|
||||||
|
const ssh2_macalg ssh_hmac_sha256 = {
|
||||||
|
hmac_new, hmac_free, hmac_key,
|
||||||
|
hmac_start, hmac_genresult, hmac_text_name,
|
||||||
|
"hmac-sha2-256", "hmac-sha2-256-etm@openssh.com",
|
||||||
|
32, 32, &ssh_hmac_sha256_extra,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hmac_extra ssh_hmac_md5_extra = { &ssh_md5, 64, "" };
|
||||||
|
const ssh2_macalg ssh_hmac_md5 = {
|
||||||
|
hmac_new, hmac_free, hmac_key,
|
||||||
|
hmac_start, hmac_genresult, hmac_text_name,
|
||||||
|
"hmac-md5", "hmac-md5-etm@openssh.com",
|
||||||
|
16, 16, &ssh_hmac_md5_extra,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hmac_extra ssh_hmac_sha1_extra = { &ssh_sha1, 64, "" };
|
||||||
|
|
||||||
|
const ssh2_macalg ssh_hmac_sha1 = {
|
||||||
|
hmac_new, hmac_free, hmac_key,
|
||||||
|
hmac_start, hmac_genresult, hmac_text_name,
|
||||||
|
"hmac-sha1", "hmac-sha1-etm@openssh.com",
|
||||||
|
20, 20, &ssh_hmac_sha1_extra,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hmac_extra ssh_hmac_sha1_96_extra = { &ssh_sha1, 64, "-96" };
|
||||||
|
|
||||||
|
const ssh2_macalg ssh_hmac_sha1_96 = {
|
||||||
|
hmac_new, hmac_free, hmac_key,
|
||||||
|
hmac_start, hmac_genresult, hmac_text_name,
|
||||||
|
"hmac-sha1-96", "hmac-sha1-96-etm@openssh.com",
|
||||||
|
12, 20, &ssh_hmac_sha1_96_extra,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hmac_extra ssh_hmac_sha1_buggy_extra = {
|
||||||
|
&ssh_sha1, 64, " (bug-compatible)"
|
||||||
|
};
|
||||||
|
|
||||||
|
const ssh2_macalg ssh_hmac_sha1_buggy = {
|
||||||
|
hmac_new, hmac_free, hmac_key,
|
||||||
|
hmac_start, hmac_genresult, hmac_text_name,
|
||||||
|
"hmac-sha1", NULL,
|
||||||
|
20, 16, &ssh_hmac_sha1_buggy_extra,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct hmac_extra ssh_hmac_sha1_96_buggy_extra = {
|
||||||
|
&ssh_sha1, 64, "-96 (bug-compatible)"
|
||||||
|
};
|
||||||
|
|
||||||
|
const ssh2_macalg ssh_hmac_sha1_96_buggy = {
|
||||||
|
hmac_new, hmac_free, hmac_key,
|
||||||
|
hmac_start, hmac_genresult, hmac_text_name,
|
||||||
|
"hmac-sha1-96", NULL,
|
||||||
|
12, 16, &ssh_hmac_sha1_96_buggy_extra,
|
||||||
|
};
|
114
sshmd5.c
114
sshmd5.c
@ -273,117 +273,3 @@ static void md5_final(ssh_hash *hash, unsigned char *output)
|
|||||||
const ssh_hashalg ssh_md5 = {
|
const ssh_hashalg ssh_md5 = {
|
||||||
md5_new, md5_copy, md5_final, md5_free, 16, "MD5"
|
md5_new, md5_copy, md5_final, md5_free, 16, "MD5"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
* 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).
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hmacmd5_context {
|
|
||||||
struct MD5Context md5[3];
|
|
||||||
ssh2_mac mac;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hmacmd5_context *hmacmd5_make_context(void)
|
|
||||||
{
|
|
||||||
struct hmacmd5_context *ctx = snew(struct hmacmd5_context);
|
|
||||||
BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->md5[2]);
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssh2_mac *hmacmd5_ssh2_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
|
||||||
{
|
|
||||||
struct hmacmd5_context *ctx = hmacmd5_make_context();
|
|
||||||
ctx->mac.vt = alg;
|
|
||||||
return &ctx->mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmacmd5_free_context(struct hmacmd5_context *ctx)
|
|
||||||
{
|
|
||||||
smemclr(ctx, sizeof(*ctx));
|
|
||||||
sfree(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacmd5_ssh2_free(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
struct hmacmd5_context *ctx =
|
|
||||||
container_of(mac, struct hmacmd5_context, mac);
|
|
||||||
hmacmd5_free_context(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmacmd5_key(struct hmacmd5_context *ctx, void const *keyv, int len)
|
|
||||||
{
|
|
||||||
unsigned char foo[64];
|
|
||||||
unsigned char const *key = (unsigned char const *)keyv;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memset(foo, 0x36, 64);
|
|
||||||
for (i = 0; i < len && i < 64; i++)
|
|
||||||
foo[i] ^= key[i];
|
|
||||||
MD5Init(&ctx->md5[0]);
|
|
||||||
put_data(&ctx->md5[0], foo, 64);
|
|
||||||
|
|
||||||
memset(foo, 0x5C, 64);
|
|
||||||
for (i = 0; i < len && i < 64; i++)
|
|
||||||
foo[i] ^= key[i];
|
|
||||||
MD5Init(&ctx->md5[1]);
|
|
||||||
put_data(&ctx->md5[1], foo, 64);
|
|
||||||
|
|
||||||
smemclr(foo, 64); /* burn the evidence */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacmd5_ssh2_setkey(ssh2_mac *mac, ptrlen key)
|
|
||||||
{
|
|
||||||
struct hmacmd5_context *ctx =
|
|
||||||
container_of(mac, struct hmacmd5_context, mac);
|
|
||||||
hmacmd5_key(ctx, key.ptr, key.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacmd5_start(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
struct hmacmd5_context *ctx =
|
|
||||||
container_of(mac, struct hmacmd5_context, mac);
|
|
||||||
|
|
||||||
ctx->md5[2] = ctx->md5[0]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&ctx->md5[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacmd5_genresult(ssh2_mac *mac, unsigned char *hmac)
|
|
||||||
{
|
|
||||||
struct hmacmd5_context *ctx =
|
|
||||||
container_of(mac, struct hmacmd5_context, mac);
|
|
||||||
struct MD5Context s;
|
|
||||||
unsigned char intermediate[16];
|
|
||||||
|
|
||||||
s = ctx->md5[2]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&s);
|
|
||||||
MD5Final(intermediate, &s);
|
|
||||||
s = ctx->md5[1]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&s);
|
|
||||||
put_data(&s, intermediate, 16);
|
|
||||||
MD5Final(hmac, &s);
|
|
||||||
smemclr(intermediate, sizeof(intermediate));
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmacmd5_do_hmac(struct hmacmd5_context *ctx,
|
|
||||||
const void *blk, int len, unsigned char *hmac)
|
|
||||||
{
|
|
||||||
ssh2_mac_start(&ctx->mac);
|
|
||||||
put_data(&ctx->mac, blk, len);
|
|
||||||
ssh2_mac_genresult(&ctx->mac, hmac);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *hmacmd5_text_name(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
return "HMAC-MD5";
|
|
||||||
}
|
|
||||||
|
|
||||||
const ssh2_macalg ssh_hmac_md5 = {
|
|
||||||
hmacmd5_ssh2_new, hmacmd5_ssh2_free, hmacmd5_ssh2_setkey,
|
|
||||||
hmacmd5_start, hmacmd5_genresult, hmacmd5_text_name,
|
|
||||||
"hmac-md5", "hmac-md5-etm@openssh.com",
|
|
||||||
16, 16,
|
|
||||||
};
|
|
||||||
|
87
sshsh256.c
87
sshsh256.c
@ -255,93 +255,6 @@ const ssh_hashalg ssh_sha256 = {
|
|||||||
sha256_new, sha256_copy, sha256_final, sha256_free, 32, "SHA-256"
|
sha256_new, sha256_copy, sha256_final, sha256_free, 32, "SHA-256"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
* The above is the SHA-256 algorithm itself. Now we implement the
|
|
||||||
* HMAC wrapper on it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hmacsha256 {
|
|
||||||
SHA256_State sha[3];
|
|
||||||
ssh2_mac mac;
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssh2_mac *hmacsha256_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
|
||||||
{
|
|
||||||
struct hmacsha256 *ctx = snew(struct hmacsha256);
|
|
||||||
ctx->mac.vt = alg;
|
|
||||||
BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->sha[2]);
|
|
||||||
return &ctx->mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha256_free(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac);
|
|
||||||
smemclr(ctx, sizeof(*ctx));
|
|
||||||
sfree(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sha256_key_internal(struct hmacsha256 *ctx,
|
|
||||||
const 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];
|
|
||||||
SHA256_Init(&ctx->sha[0]);
|
|
||||||
put_data(&ctx->sha[0], foo, 64);
|
|
||||||
|
|
||||||
memset(foo, 0x5C, 64);
|
|
||||||
for (i = 0; i < len && i < 64; i++)
|
|
||||||
foo[i] ^= key[i];
|
|
||||||
SHA256_Init(&ctx->sha[1]);
|
|
||||||
put_data(&ctx->sha[1], foo, 64);
|
|
||||||
|
|
||||||
smemclr(foo, 64); /* burn the evidence */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha256_key(ssh2_mac *mac, ptrlen key)
|
|
||||||
{
|
|
||||||
struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac);
|
|
||||||
sha256_key_internal(ctx, key.ptr, key.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha256_start(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac);
|
|
||||||
|
|
||||||
ctx->sha[2] = ctx->sha[0]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&ctx->sha[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha256_genresult(ssh2_mac *mac, unsigned char *hmac)
|
|
||||||
{
|
|
||||||
struct hmacsha256 *ctx = container_of(mac, struct hmacsha256, mac);
|
|
||||||
SHA256_State s;
|
|
||||||
unsigned char intermediate[32];
|
|
||||||
|
|
||||||
s = ctx->sha[2]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&s);
|
|
||||||
SHA256_Final(&s, intermediate);
|
|
||||||
s = ctx->sha[1]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&s);
|
|
||||||
put_data(&s, intermediate, 32);
|
|
||||||
SHA256_Final(&s, hmac);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *hmacsha256_text_name(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
return "HMAC-SHA-256";
|
|
||||||
}
|
|
||||||
|
|
||||||
const ssh2_macalg ssh_hmac_sha256 = {
|
|
||||||
hmacsha256_new, hmacsha256_free, hmacsha256_key,
|
|
||||||
hmacsha256_start, hmacsha256_genresult, hmacsha256_text_name,
|
|
||||||
"hmac-sha2-256", "hmac-sha2-256-etm@openssh.com",
|
|
||||||
32, 32,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef COMPILER_SUPPORTS_SHA_NI
|
#ifdef COMPILER_SUPPORTS_SHA_NI
|
||||||
|
|
||||||
#if defined _MSC_VER && defined _M_AMD64
|
#if defined _MSC_VER && defined _M_AMD64
|
||||||
|
138
sshsha.c
138
sshsha.c
@ -284,144 +284,6 @@ const ssh_hashalg ssh_sha1 = {
|
|||||||
sha1_new, sha1_copy, sha1_final, sha1_free, 20, "SHA-1"
|
sha1_new, sha1_copy, sha1_final, sha1_free, 20, "SHA-1"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
* The above is the SHA-1 algorithm itself. Now we implement the
|
|
||||||
* HMAC wrapper on it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hmacsha1 {
|
|
||||||
SHA_State sha[3];
|
|
||||||
ssh2_mac mac;
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssh2_mac *hmacsha1_new(const ssh2_macalg *alg, ssh_cipher *cipher)
|
|
||||||
{
|
|
||||||
struct hmacsha1 *ctx = snew(struct hmacsha1);
|
|
||||||
ctx->mac.vt = alg;
|
|
||||||
BinarySink_DELEGATE_INIT(&ctx->mac, &ctx->sha[2]);
|
|
||||||
return &ctx->mac;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha1_free(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac);
|
|
||||||
smemclr(ctx, sizeof(*ctx));
|
|
||||||
sfree(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sha1_key_internal(SHA_State *keys,
|
|
||||||
const 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(&keys[0]);
|
|
||||||
put_data(&keys[0], foo, 64);
|
|
||||||
|
|
||||||
memset(foo, 0x5C, 64);
|
|
||||||
for (i = 0; i < len && i < 64; i++)
|
|
||||||
foo[i] ^= key[i];
|
|
||||||
SHA_Init(&keys[1]);
|
|
||||||
put_data(&keys[1], foo, 64);
|
|
||||||
|
|
||||||
smemclr(foo, 64); /* burn the evidence */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha1_key(ssh2_mac *mac, ptrlen key)
|
|
||||||
{
|
|
||||||
struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac);
|
|
||||||
sha1_key_internal(ctx->sha, key.ptr, key.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha1_start(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac);
|
|
||||||
|
|
||||||
ctx->sha[2] = ctx->sha[0]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&ctx->sha[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hmacsha1_genresult(ssh2_mac *mac, unsigned char *hmac)
|
|
||||||
{
|
|
||||||
struct hmacsha1 *ctx = container_of(mac, struct hmacsha1, mac);
|
|
||||||
SHA_State s;
|
|
||||||
unsigned char intermediate[20];
|
|
||||||
|
|
||||||
s = ctx->sha[2]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&s);
|
|
||||||
SHA_Final(&s, intermediate);
|
|
||||||
s = ctx->sha[1]; /* structure copy */
|
|
||||||
BinarySink_COPIED(&s);
|
|
||||||
put_data(&s, intermediate, 20);
|
|
||||||
SHA_Final(&s, intermediate);
|
|
||||||
memcpy(hmac, intermediate, ctx->mac.vt->len);
|
|
||||||
smemclr(intermediate, sizeof(intermediate));
|
|
||||||
}
|
|
||||||
|
|
||||||
void hmac_sha1_simple(const void *key, int keylen,
|
|
||||||
const void *data, int datalen,
|
|
||||||
unsigned char *output) {
|
|
||||||
SHA_State states[2];
|
|
||||||
unsigned char intermediate[20];
|
|
||||||
|
|
||||||
sha1_key_internal(states, key, keylen);
|
|
||||||
put_data(&states[0], data, datalen);
|
|
||||||
SHA_Final(&states[0], intermediate);
|
|
||||||
|
|
||||||
put_data(&states[1], intermediate, 20);
|
|
||||||
SHA_Final(&states[1], output);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct hmacsha1_extra {
|
|
||||||
const char *textname;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *hmacsha1_text_name(ssh2_mac *mac)
|
|
||||||
{
|
|
||||||
const struct hmacsha1_extra *extra =
|
|
||||||
(const struct hmacsha1_extra *)mac->vt->extra;
|
|
||||||
return extra->textname;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct hmacsha1_extra ssh_hmac_sha1_extra = { "HMAC-SHA1" };
|
|
||||||
const ssh2_macalg ssh_hmac_sha1 = {
|
|
||||||
hmacsha1_new, hmacsha1_free, hmacsha1_key,
|
|
||||||
hmacsha1_start, hmacsha1_genresult, hmacsha1_text_name,
|
|
||||||
"hmac-sha1", "hmac-sha1-etm@openssh.com",
|
|
||||||
20, 20, &ssh_hmac_sha1_extra,
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct hmacsha1_extra ssh_hmac_sha1_96_extra = { "HMAC-SHA1-96" };
|
|
||||||
const ssh2_macalg ssh_hmac_sha1_96 = {
|
|
||||||
hmacsha1_new, hmacsha1_free, hmacsha1_key,
|
|
||||||
hmacsha1_start, hmacsha1_genresult, hmacsha1_text_name,
|
|
||||||
"hmac-sha1-96", "hmac-sha1-96-etm@openssh.com",
|
|
||||||
12, 20, &ssh_hmac_sha1_96_extra,
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct hmacsha1_extra ssh_hmac_sha1_buggy_extra = {
|
|
||||||
"bug-compatible HMAC-SHA1",
|
|
||||||
};
|
|
||||||
const ssh2_macalg ssh_hmac_sha1_buggy = {
|
|
||||||
hmacsha1_new, hmacsha1_free, hmacsha1_key,
|
|
||||||
hmacsha1_start, hmacsha1_genresult, hmacsha1_text_name,
|
|
||||||
"hmac-sha1", NULL,
|
|
||||||
20, 16, &ssh_hmac_sha1_buggy_extra,
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct hmacsha1_extra ssh_hmac_sha1_96_buggy_extra = {
|
|
||||||
"bug-compatible HMAC-SHA1-96",
|
|
||||||
};
|
|
||||||
const ssh2_macalg ssh_hmac_sha1_96_buggy = {
|
|
||||||
hmacsha1_new, hmacsha1_free, hmacsha1_key,
|
|
||||||
hmacsha1_start, hmacsha1_genresult, hmacsha1_text_name,
|
|
||||||
"hmac-sha1-96", NULL,
|
|
||||||
12, 16, &ssh_hmac_sha1_96_buggy_extra,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef COMPILER_SUPPORTS_SHA_NI
|
#ifdef COMPILER_SUPPORTS_SHA_NI
|
||||||
|
|
||||||
#if defined _MSC_VER && defined _M_AMD64
|
#if defined _MSC_VER && defined _M_AMD64
|
||||||
|
@ -1483,15 +1483,14 @@ class standard_test_vectors(MyTestBase):
|
|||||||
'77966b957a878e720584779a62825c18da26415e49a7176a894e7510fd1451f5'))
|
'77966b957a878e720584779a62825c18da26415e49a7176a894e7510fd1451f5'))
|
||||||
|
|
||||||
def testHmacSHA(self):
|
def testHmacSHA(self):
|
||||||
# Test cases from RFC 6234 section 8.5, omitting the ones
|
# Test cases from RFC 6234 section 8.5.
|
||||||
# which have a long enough key to require hashing it first.
|
def vector(key, message, s1=None, s256=None):
|
||||||
# (Our implementation doesn't support that, because it knows
|
if s1 is not None:
|
||||||
# it only has to deal with a fixed key length.)
|
self.assertEqualBin(
|
||||||
def vector(key, message, s1, s256):
|
mac_str('hmac_sha1', key, message), unhex(s1))
|
||||||
self.assertEqualBin(
|
if s256 is not None:
|
||||||
mac_str('hmac_sha1', key, message), unhex(s1))
|
self.assertEqualBin(
|
||||||
self.assertEqualBin(
|
mac_str('hmac_sha256', key, message), unhex(s256))
|
||||||
mac_str('hmac_sha256', key, message), unhex(s256))
|
|
||||||
vector(
|
vector(
|
||||||
unhex("0b"*20), "Hi There",
|
unhex("0b"*20), "Hi There",
|
||||||
"b617318655057264e28bc0b6fb378c8ef146be00",
|
"b617318655057264e28bc0b6fb378c8ef146be00",
|
||||||
@ -1509,6 +1508,26 @@ class standard_test_vectors(MyTestBase):
|
|||||||
unhex("cd"*50),
|
unhex("cd"*50),
|
||||||
"4c9007f4026250c6bc8414f9bf50c86c2d7235da",
|
"4c9007f4026250c6bc8414f9bf50c86c2d7235da",
|
||||||
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b")
|
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b")
|
||||||
|
vector(
|
||||||
|
unhex("aa"*80),
|
||||||
|
"Test Using Larger Than Block-Size Key - Hash Key First",
|
||||||
|
s1="aa4ae5e15272d00e95705637ce8a3b55ed402112")
|
||||||
|
vector(
|
||||||
|
unhex("aa"*131),
|
||||||
|
"Test Using Larger Than Block-Size Key - Hash Key First",
|
||||||
|
s256="60e431591ee0b67f0d8a26aacbf5b77f"
|
||||||
|
"8e0bc6213728c5140546040f0ee37f54")
|
||||||
|
vector(
|
||||||
|
unhex("aa"*80),
|
||||||
|
"Test Using Larger Than Block-Size Key and "
|
||||||
|
"Larger Than One Block-Size Data",
|
||||||
|
s1="e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
|
||||||
|
vector(
|
||||||
|
unhex("aa"*131),
|
||||||
|
"This is a test using a larger than block-size key and a "
|
||||||
|
"larger than block-size data. The key needs to be hashed "
|
||||||
|
"before being used by the HMAC algorithm.",
|
||||||
|
s256="9B09FFA71B942FCB27635FBCD5B0E944BFDC63644F0713938A7F51535C3A35E2")
|
||||||
|
|
||||||
def testEd25519(self):
|
def testEd25519(self):
|
||||||
def vector(privkey, pubkey, message, signature):
|
def vector(privkey, pubkey, message, signature):
|
||||||
|
Loading…
Reference in New Issue
Block a user