2 * Implementation of HMAC (RFC 2104) for PuTTY, in a general form that
3 * can wrap any underlying hash function.
9 const ssh_hashalg
*hashalg
;
10 ssh_hash
*h_outer
, *h_inner
, *h_live
;
17 const ssh_hashalg
*hashalg_base
;
18 const char *suffix
, *annotation
;
21 static ssh2_mac
*hmac_new(const ssh2_macalg
*alg
, ssh_cipher
*cipher
)
23 struct hmac
*ctx
= snew(struct hmac
);
24 const struct hmac_extra
*extra
= (const struct hmac_extra
*)alg
->extra
;
26 ctx
->h_outer
= ssh_hash_new(extra
->hashalg_base
);
27 /* In case that hashalg was a selector vtable, we'll now switch to
28 * using whatever real one it selected, for all future purposes. */
29 ctx
->hashalg
= ssh_hash_alg(ctx
->h_outer
);
30 ctx
->h_inner
= ssh_hash_new(ctx
->hashalg
);
31 ctx
->h_live
= ssh_hash_new(ctx
->hashalg
);
34 * HMAC is not well defined as a wrapper on an absolutely general
35 * hash function; it expects that the function it's wrapping will
36 * consume data in fixed-size blocks, and it's partially defined
37 * in terms of that block size. So we insist that the hash we're
38 * given must have defined a meaningful block size.
40 assert(ctx
->hashalg
->blocklen
);
42 ctx
->digest
= snewn(ctx
->hashalg
->hlen
, uint8_t);
44 ctx
->text_name
= strbuf_new();
45 strbuf_catf(ctx
->text_name
, "HMAC-%s%s",
46 ctx
->hashalg
->text_basename
, extra
->suffix
);
47 if (extra
->annotation
|| ctx
->hashalg
->annotation
) {
48 strbuf_catf(ctx
->text_name
, " (");
50 if (extra
->annotation
) {
51 strbuf_catf(ctx
->text_name
, "%s%s", sep
, extra
->annotation
);
54 if (ctx
->hashalg
->annotation
) {
55 strbuf_catf(ctx
->text_name
, "%s%s", sep
, ctx
->hashalg
->annotation
);
58 strbuf_catf(ctx
->text_name
, ")");
62 BinarySink_DELEGATE_INIT(&ctx
->mac
, ctx
->h_live
);
67 static void hmac_free(ssh2_mac
*mac
)
69 struct hmac
*ctx
= container_of(mac
, struct hmac
, mac
);
71 ssh_hash_free(ctx
->h_outer
);
72 ssh_hash_free(ctx
->h_inner
);
73 ssh_hash_free(ctx
->h_live
);
74 smemclr(ctx
->digest
, ctx
->hashalg
->hlen
);
76 strbuf_free(ctx
->text_name
);
78 smemclr(ctx
, sizeof(*ctx
));
82 #define PAD_OUTER 0x5C
83 #define PAD_INNER 0x36
85 static void hmac_key(ssh2_mac
*mac
, ptrlen key
)
87 struct hmac
*ctx
= container_of(mac
, struct hmac
, mac
);
93 if (key
.len
> ctx
->hashalg
->blocklen
) {
95 * RFC 2104 section 2: if the key exceeds the block length of
96 * the underlying hash, then we start by hashing the key, and
97 * use that hash as the 'true' key for the HMAC construction.
100 strbuf_append(sb
, ctx
->hashalg
->hlen
);
101 hash_simple(ctx
->hashalg
, key
, sb
->u
);
106 * A short enough key is used as is.
108 kp
= (const uint8_t *)key
.ptr
;
112 ssh_hash_reset(ctx
->h_outer
);
113 for (size_t i
= 0; i
< klen
; i
++)
114 put_byte(ctx
->h_outer
, PAD_OUTER
^ kp
[i
]);
115 for (size_t i
= klen
; i
< ctx
->hashalg
->blocklen
; i
++)
116 put_byte(ctx
->h_outer
, PAD_OUTER
);
118 ssh_hash_reset(ctx
->h_inner
);
119 for (size_t i
= 0; i
< klen
; i
++)
120 put_byte(ctx
->h_inner
, PAD_INNER
^ kp
[i
]);
121 for (size_t i
= klen
; i
< ctx
->hashalg
->blocklen
; i
++)
122 put_byte(ctx
->h_inner
, PAD_INNER
);
128 static void hmac_start(ssh2_mac
*mac
)
130 struct hmac
*ctx
= container_of(mac
, struct hmac
, mac
);
131 ssh_hash_copyfrom(ctx
->h_live
, ctx
->h_inner
);
134 static void hmac_genresult(ssh2_mac
*mac
, unsigned char *output
)
136 struct hmac
*ctx
= container_of(mac
, struct hmac
, mac
);
139 /* Leave h_live and h_outer in place, so that the SSH-2 BPP can
140 * continue regenerating test results from different-length
141 * prefixes of the packet */
142 ssh_hash_digest_nondestructive(ctx
->h_live
, ctx
->digest
);
144 htmp
= ssh_hash_copy(ctx
->h_outer
);
145 put_data(htmp
, ctx
->digest
, ctx
->hashalg
->hlen
);
146 ssh_hash_final(htmp
, ctx
->digest
);
149 * Some instances of HMAC truncate the output hash, so instead of
150 * writing it directly to 'output' we wrote it to our own
151 * full-length buffer, and now we copy the required amount.
153 memcpy(output
, ctx
->digest
, mac
->vt
->len
);
154 smemclr(ctx
->digest
, ctx
->hashalg
->hlen
);
157 static const char *hmac_text_name(ssh2_mac
*mac
)
159 struct hmac
*ctx
= container_of(mac
, struct hmac
, mac
);
160 return ctx
->text_name
->s
;
163 static const struct hmac_extra ssh_hmac_sha256_extra
= { &ssh_sha256
, "" };
164 const ssh2_macalg ssh_hmac_sha256
= {
169 .genresult
= hmac_genresult
,
170 .text_name
= hmac_text_name
,
171 .name
= "hmac-sha2-256",
172 .etm_name
= "hmac-sha2-256-etm@openssh.com",
175 .extra
= &ssh_hmac_sha256_extra
,
178 static const struct hmac_extra ssh_hmac_md5_extra
= { &ssh_md5
, "" };
179 const ssh2_macalg ssh_hmac_md5
= {
184 .genresult
= hmac_genresult
,
185 .text_name
= hmac_text_name
,
187 .etm_name
= "hmac-md5-etm@openssh.com",
190 .extra
= &ssh_hmac_md5_extra
,
193 static const struct hmac_extra ssh_hmac_sha1_extra
= { &ssh_sha1
, "" };
195 const ssh2_macalg ssh_hmac_sha1
= {
200 .genresult
= hmac_genresult
,
201 .text_name
= hmac_text_name
,
203 .etm_name
= "hmac-sha1-etm@openssh.com",
206 .extra
= &ssh_hmac_sha1_extra
,
209 static const struct hmac_extra ssh_hmac_sha1_96_extra
= { &ssh_sha1
, "-96" };
211 const ssh2_macalg ssh_hmac_sha1_96
= {
216 .genresult
= hmac_genresult
,
217 .text_name
= hmac_text_name
,
218 .name
= "hmac-sha1-96",
219 .etm_name
= "hmac-sha1-96-etm@openssh.com",
222 .extra
= &ssh_hmac_sha1_96_extra
,
225 static const struct hmac_extra ssh_hmac_sha1_buggy_extra
= {
226 &ssh_sha1
, "", "bug-compatible"
229 const ssh2_macalg ssh_hmac_sha1_buggy
= {
234 .genresult
= hmac_genresult
,
235 .text_name
= hmac_text_name
,
239 .extra
= &ssh_hmac_sha1_buggy_extra
,
242 static const struct hmac_extra ssh_hmac_sha1_96_buggy_extra
= {
243 &ssh_sha1
, "-96", "bug-compatible"
246 const ssh2_macalg ssh_hmac_sha1_96_buggy
= {
251 .genresult
= hmac_genresult
,
252 .text_name
= hmac_text_name
,
253 .name
= "hmac-sha1-96",
256 .extra
= &ssh_hmac_sha1_96_buggy_extra
,