From dea3ddca0537299ebfe907dd4c883fe65bfb4035 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 1 Apr 2024 08:45:21 +0100 Subject: [PATCH] Add an extra HMAC constructor function. This takes a plain ssh_hashalg, and constructs the most natural kind of HMAC wrapper around it, taking its key length and output length to be the hash's output length. In other words, it converts SHA-foo into exactly the thing usually called HMAC-SHA-foo. It does it by constructing a new ssh2_macalg vtable, and including it in the same memory allocation as the actual hash object. That's the first time in PuTTY I've done it this way. Nothing yet uses this, but a new piece of code is about to. --- crypto/hmac.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- ssh.h | 5 +++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/crypto/hmac.c b/crypto/hmac.c index cc255829..afec9efb 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -18,9 +18,10 @@ struct hmac_extra { const char *suffix, *annotation; }; -static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher) +/* Most of hmac_new(). Takes the actual 'struct hmac' as a parameter, + * because sometimes it will have been allocated in a special way. */ +static ssh2_mac *hmac_new_inner(struct hmac *ctx, const ssh2_macalg *alg) { - struct hmac *ctx = snew(struct hmac); const struct hmac_extra *extra = (const struct hmac_extra *)alg->extra; ctx->h_outer = ssh_hash_new(extra->hashalg_base); @@ -64,6 +65,11 @@ static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher) return &ctx->mac; } +static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher) +{ + return hmac_new_inner(snew(struct hmac), alg); /* cipher isn't needed */ +} + static void hmac_free(ssh2_mac *mac) { struct hmac *ctx = container_of(mac, struct hmac, mac); @@ -277,3 +283,38 @@ const ssh2_macalg ssh_hmac_sha1_96_buggy = { .keylen = 16, .extra = &ssh_hmac_sha1_96_buggy_extra, }; + +ssh2_mac *hmac_new_from_hash(const ssh_hashalg *hash) +{ + /* + * Construct a custom ssh2_macalg, derived directly from the + * provided hash vtable. It's included in the same memory + * allocation as the struct hmac, so that it all gets freed + * together. + */ + + struct alloc { + struct hmac hmac; + ssh2_macalg alg; + struct hmac_extra extra; + }; + + struct alloc *alloc = snew(struct alloc); + alloc->alg.new = hmac_new; + alloc->alg.free = hmac_free; + alloc->alg.setkey = hmac_key; + alloc->alg.start = hmac_start; + alloc->alg.genresult = hmac_genresult; + alloc->alg.next_message = nullmac_next_message; + alloc->alg.text_name = hmac_text_name; + alloc->alg.name = NULL; + alloc->alg.etm_name = NULL; + alloc->alg.len = hash->hlen; + alloc->alg.keylen = hash->hlen; + alloc->alg.extra = &alloc->extra; + alloc->extra.hashalg_base = hash; + alloc->extra.suffix = ""; + alloc->extra.annotation = NULL; + + return hmac_new_inner(&alloc->hmac, &alloc->alg); +} diff --git a/ssh.h b/ssh.h index bf976467..7b1736d5 100644 --- a/ssh.h +++ b/ssh.h @@ -762,6 +762,11 @@ void nullmac_next_message(ssh2_mac *m); * string with a given key in the most obvious way. */ void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output); +/* Constructor that makes an HMAC object given just a MAC. This object + * will have empty 'name' and 'etm_name' fields, so it's not suitable + * for use in SSH. It's used as a subroutine in RFC 6979. */ +ssh2_mac *hmac_new_from_hash(const ssh_hashalg *hash); + struct ssh_hash { const ssh_hashalg *vt; BinarySink_DELEGATE_IMPLEMENTATION;