1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-17 11:00:59 -05: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:
Simon Tatham
2019-01-20 16:18:49 +00:00
parent d73f692eea
commit baff23cdd6
8 changed files with 251 additions and 361 deletions

138
sshsha.c
View File

@ -284,144 +284,6 @@ const ssh_hashalg ssh_sha1 = {
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
#if defined _MSC_VER && defined _M_AMD64