diff --git a/ssh.h b/ssh.h index 2aaa679b..7b256cd1 100644 --- a/ssh.h +++ b/ssh.h @@ -665,6 +665,7 @@ struct ssh_hashalg { void (*final)(ssh_hash *, unsigned char *); /* ALSO FREES THE ssh_hash! */ void (*free)(ssh_hash *); int hlen; /* output length in bytes */ + int blocklen; /* length of the hash's input block, or 0 for N/A */ const char *text_name; }; diff --git a/sshhmac.c b/sshhmac.c index 8f2577a6..31e15ea8 100644 --- a/sshhmac.c +++ b/sshhmac.c @@ -14,7 +14,6 @@ struct hmac { struct hmac_extra { const ssh_hashalg *hashalg; - size_t blklen; const char *suffix; }; @@ -23,6 +22,15 @@ 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; + /* + * HMAC is not well defined as a wrapper on an absolutely general + * hash function; it expects that the function it's wrapping will + * consume data in fixed-size blocks, and it's partially defined + * in terms of that block size. So we insist that the hash we're + * given must have defined a meaningful block size. + */ + assert(extra->hashalg->blocklen); + ctx->h_outer = ctx->h_inner = ctx->h_live = NULL; ctx->digest = snewn(extra->hashalg->hlen, uint8_t); @@ -67,7 +75,7 @@ static void hmac_key(ssh2_mac *mac, ptrlen key) size_t klen; strbuf *sb = NULL; - if (key.len > extra->blklen) { + if (key.len > extra->hashalg->blocklen) { /* * RFC 2104 section 2: if the key exceeds the block length of * the underlying hash, then we start by hashing the key, and @@ -98,13 +106,13 @@ static void hmac_key(ssh2_mac *mac, ptrlen key) 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++) + for (size_t i = klen; i < extra->hashalg->blocklen; 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++) + for (size_t i = klen; i < extra->hashalg->blocklen; i++) put_byte(ctx->h_inner, PAD_INNER); if (sb) @@ -153,7 +161,7 @@ static const char *hmac_text_name(ssh2_mac *mac) return ctx->text_name->s; } -const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, 64, "" }; +const struct hmac_extra ssh_hmac_sha256_extra = { &ssh_sha256, "" }; const ssh2_macalg ssh_hmac_sha256 = { hmac_new, hmac_free, hmac_key, hmac_start, hmac_genresult, hmac_text_name, @@ -161,7 +169,7 @@ const ssh2_macalg ssh_hmac_sha256 = { 32, 32, &ssh_hmac_sha256_extra, }; -const struct hmac_extra ssh_hmac_md5_extra = { &ssh_md5, 64, "" }; +const struct hmac_extra ssh_hmac_md5_extra = { &ssh_md5, "" }; const ssh2_macalg ssh_hmac_md5 = { hmac_new, hmac_free, hmac_key, hmac_start, hmac_genresult, hmac_text_name, @@ -169,7 +177,7 @@ const ssh2_macalg ssh_hmac_md5 = { 16, 16, &ssh_hmac_md5_extra, }; -const struct hmac_extra ssh_hmac_sha1_extra = { &ssh_sha1, 64, "" }; +const struct hmac_extra ssh_hmac_sha1_extra = { &ssh_sha1, "" }; const ssh2_macalg ssh_hmac_sha1 = { hmac_new, hmac_free, hmac_key, @@ -178,7 +186,7 @@ const ssh2_macalg ssh_hmac_sha1 = { 20, 20, &ssh_hmac_sha1_extra, }; -const struct hmac_extra ssh_hmac_sha1_96_extra = { &ssh_sha1, 64, "-96" }; +const struct hmac_extra ssh_hmac_sha1_96_extra = { &ssh_sha1, "-96" }; const ssh2_macalg ssh_hmac_sha1_96 = { hmac_new, hmac_free, hmac_key, @@ -188,7 +196,7 @@ const ssh2_macalg ssh_hmac_sha1_96 = { }; const struct hmac_extra ssh_hmac_sha1_buggy_extra = { - &ssh_sha1, 64, " (bug-compatible)" + &ssh_sha1, " (bug-compatible)" }; const ssh2_macalg ssh_hmac_sha1_buggy = { @@ -199,7 +207,7 @@ const ssh2_macalg ssh_hmac_sha1_buggy = { }; const struct hmac_extra ssh_hmac_sha1_96_buggy_extra = { - &ssh_sha1, 64, "-96 (bug-compatible)" + &ssh_sha1, "-96 (bug-compatible)" }; const ssh2_macalg ssh_hmac_sha1_96_buggy = { diff --git a/sshmd5.c b/sshmd5.c index 4fcc906b..2a083f8d 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -271,5 +271,5 @@ static void md5_final(ssh_hash *hash, unsigned char *output) } const ssh_hashalg ssh_md5 = { - md5_new, md5_copy, md5_final, md5_free, 16, "MD5" + md5_new, md5_copy, md5_final, md5_free, 16, 64, "MD5" }; diff --git a/sshsh256.c b/sshsh256.c index 940726bd..fbd8bdb2 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -252,7 +252,7 @@ static void sha256_final(ssh_hash *hash, unsigned char *output) } 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, 64, "SHA-256" }; #ifdef COMPILER_SUPPORTS_SHA_NI diff --git a/sshsh512.c b/sshsh512.c index 7e27d738..bacba0d4 100644 --- a/sshsh512.c +++ b/sshsh512.c @@ -13,7 +13,7 @@ typedef struct { uint64_t h[8]; - unsigned char block[128]; + unsigned char block[BLKSIZE]; int blkused; uint64_t lenhi, lenlo; BinarySink_IMPLEMENTATION; @@ -343,7 +343,7 @@ static void sha512_final(ssh_hash *hash, unsigned char *output) } const ssh_hashalg ssh_sha512 = { - sha512_new, sha512_copy, sha512_final, sha512_free, 64, "SHA-512" + sha512_new, sha512_copy, sha512_final, sha512_free, 64, BLKSIZE, "SHA-512" }; static ssh_hash *sha384_new(const ssh_hashalg *alg) @@ -363,5 +363,5 @@ static void sha384_final(ssh_hash *hash, unsigned char *output) } const ssh_hashalg ssh_sha384 = { - sha384_new, sha512_copy, sha384_final, sha512_free, 48, "SHA-384" + sha384_new, sha512_copy, sha384_final, sha512_free, 48, BLKSIZE, "SHA-384" }; diff --git a/sshsha.c b/sshsha.c index 9f4fb5c7..82f1c913 100644 --- a/sshsha.c +++ b/sshsha.c @@ -281,7 +281,7 @@ static void sha1_final(ssh_hash *hash, unsigned char *output) } 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, 64, "SHA-1" }; #ifdef COMPILER_SUPPORTS_SHA_NI