From 5a6f12336d7ddfb0322898cba3cde010341e945c Mon Sep 17 00:00:00 2001
From: Simon Tatham <anakin@pobox.com>
Date: Mon, 1 Apr 2024 07:45:21 +0100
Subject: Add an extra HMAC constructor function.

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.

origin: backport, https://git.tartarus.org/?p=simon/putty.git;a=commitdiff_plain;h=dea3ddca0537299ebfe907dd4c883fe65bfb4035
---
 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 adeccd29..fa70c8e6 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);
@@ -261,3 +267,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 0961c0b2..b33be1c7 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;
