diff --git a/import.c b/import.c index effc65be..dd52e3a4 100644 --- a/import.c +++ b/import.c @@ -516,9 +516,9 @@ static void openssh_pem_derivekey( h = ssh_hash_new(&ssh_md5); put_datapl(h, passphrase); put_data(h, iv, 8); - ssh_hash_final(h, keybuf); + ssh_hash_digest(h, keybuf); - h = ssh_hash_new(&ssh_md5); + ssh_hash_reset(h); put_data(h, keybuf, 16); put_datapl(h, passphrase); put_data(h, iv, 8); @@ -1932,7 +1932,7 @@ static void sshcom_derivekey(ptrlen passphrase, uint8_t *keybuf) h = ssh_hash_new(&ssh_md5); put_datapl(h, passphrase); - ssh_hash_final(ssh_hash_copy(h), keybuf); + ssh_hash_digest_nondestructive(h, keybuf); put_data(h, keybuf, 16); ssh_hash_final(h, keybuf + 16); } diff --git a/ssh.h b/ssh.h index 92c80e92..2a023121 100644 --- a/ssh.h +++ b/ssh.h @@ -748,6 +748,13 @@ static inline ssh_hash *ssh_hash_copyfrom(ssh_hash *dest, ssh_hash *src) static inline void ssh_hash_final(ssh_hash *h, unsigned char *out) { h->vt->digest(h, out); h->vt->free(h); } +/* ssh_hash_digest_nondestructive generates a finalised hash from the + * given object without changing its state, so you can continue + * appending data to get a hash of an extended string. */ +static inline void ssh_hash_digest_nondestructive(ssh_hash *h, + unsigned char *out) +{ ssh_hash_final(ssh_hash_copy(h), out); } + /* Handy macros for defining all those text-name fields at once */ #define HASHALG_NAMES_BARE(base) \ base, NULL, base diff --git a/ssh2transport.c b/ssh2transport.c index 223ec5b7..da5320ac 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -275,25 +275,25 @@ static void ssh2_mkkey( put_data(h, H, hlen); put_byte(h, chr); put_data(h, s->session_id, s->session_id_len); - ssh_hash_final(h, key); + ssh_hash_digest(h, key); /* Subsequent blocks of hlen bytes. */ if (keylen_padded > hlen) { int offset; - h = ssh_hash_new(s->kex_alg->hash); + ssh_hash_reset(h); if (!(s->ppl.remote_bugs & BUG_SSH2_DERIVEKEY)) put_mp_ssh2(h, K); put_data(h, H, hlen); for (offset = hlen; offset < keylen_padded; offset += hlen) { put_data(h, key + offset - hlen, hlen); - ssh_hash *h2 = ssh_hash_copy(h); - ssh_hash_final(h2, key + offset); + ssh_hash_digest_nondestructive(h, key + offset); } - ssh_hash_free(h); } + + ssh_hash_free(h); } /* diff --git a/sshdss.c b/sshdss.c index 2bf26d9a..9cb78c69 100644 --- a/sshdss.c +++ b/sshdss.c @@ -399,12 +399,12 @@ mp_int *dss_gen_k(const char *id_string, mp_int *modulus, h = ssh_hash_new(&ssh_sha512); put_asciz(h, id_string); put_mp_ssh2(h, private_key); - ssh_hash_final(h, digest512); + ssh_hash_digest(h, digest512); /* * Now hash that digest plus the message hash. */ - h = ssh_hash_new(&ssh_sha512); + ssh_hash_reset(h); put_data(h, digest512, sizeof(digest512)); put_data(h, digest, digest_len); ssh_hash_final(h, digest512); diff --git a/sshhmac.c b/sshhmac.c index 5ba6e9c4..dece5c4e 100644 --- a/sshhmac.c +++ b/sshhmac.c @@ -98,11 +98,7 @@ static void hmac_key(ssh2_mac *mac, ptrlen key) */ sb = strbuf_new_nm(); strbuf_append(sb, ctx->hashalg->hlen); - - ssh_hash *htmp = ssh_hash_new(ctx->hashalg); - put_datapl(htmp, key); - ssh_hash_final(htmp, sb->u); - + hash_simple(ctx->hashalg, key, sb->u); kp = sb->u; klen = sb->len; } else { @@ -140,11 +136,10 @@ static void hmac_genresult(ssh2_mac *mac, unsigned char *output) struct hmac *ctx = container_of(mac, struct hmac, mac); ssh_hash *htmp; - /* Leave h_live in place, so that the SSH-2 BPP can continue - * regenerating test results from different-length prefixes of the - * packet */ - htmp = ssh_hash_copy(ctx->h_live); - ssh_hash_final(htmp, ctx->digest); + /* Leave h_live and h_outer in place, so that the SSH-2 BPP can + * continue regenerating test results from different-length + * prefixes of the packet */ + ssh_hash_digest_nondestructive(ctx->h_live, ctx->digest); htmp = ssh_hash_copy(ctx->h_outer); put_data(htmp, ctx->digest, ctx->hashalg->hlen); diff --git a/sshprng.c b/sshprng.c index ea40c99f..ea09ab04 100644 --- a/sshprng.c +++ b/sshprng.c @@ -273,9 +273,9 @@ void prng_add_entropy(prng *pr, unsigned source_id, ptrlen data) prngdebug("prng entropy reseed #%"PRIu32"\n", reseed_index); for (size_t i = 0; i < NCOLLECTORS; i++) { prngdebug("emptying collector %zu\n", i); - ssh_hash_final(pi->collectors[i], pi->pending_output); + ssh_hash_digest(pi->collectors[i], pi->pending_output); put_data(&pi->Prng, pi->pending_output, pi->hashalg->hlen); - pi->collectors[i] = ssh_hash_new(pi->hashalg); + ssh_hash_reset(pi->collectors[i]); if (reseed_index & 1) break; reseed_index >>= 1; diff --git a/sshpubk.c b/sshpubk.c index 442fb5ed..e202c39b 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -372,9 +372,7 @@ bool rsa_ssh1_savekey(const Filename *filename, RSAKey *key, if (passphrase) { unsigned char keybuf[16]; - ssh_hash *h = ssh_hash_new(&ssh_md5); - put_data(h, passphrase, strlen(passphrase)); - ssh_hash_final(h, keybuf); + hash_simple(&ssh_md5, ptrlen_from_asciz(passphrase), keybuf); des3_encrypt_pubkey(keybuf, buf->u + estart, buf->len - estart); smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */ } @@ -591,8 +589,8 @@ static void ssh2_ppk_derivekey(ptrlen passphrase, uint8_t *key) h = ssh_hash_new(&ssh_sha1); put_uint32(h, 0); put_datapl(h, passphrase); - ssh_hash_final(h, key + 0); - h = ssh_hash_new(&ssh_sha1); + ssh_hash_digest(h, key + 0); + ssh_hash_reset(h); put_uint32(h, 1); put_datapl(h, passphrase); ssh_hash_final(h, key + 20); diff --git a/sshrsa.c b/sshrsa.c index 81522aa8..2f68c663 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -832,16 +832,17 @@ static void oaep_mask(const ssh_hashalg *h, void *seed, int seedlen, unsigned char *data = (unsigned char *)vdata; unsigned count = 0; + ssh_hash *s = ssh_hash_new(h); + while (datalen > 0) { int i, max = (datalen > h->hlen ? h->hlen : datalen); - ssh_hash *s; unsigned char hash[MAX_HASH_LEN]; + ssh_hash_reset(s); assert(h->hlen <= MAX_HASH_LEN); - s = ssh_hash_new(h); put_data(s, seed, seedlen); put_uint32(s, count); - ssh_hash_final(s, hash); + ssh_hash_digest(s, hash); count++; for (i = 0; i < max; i++) @@ -850,6 +851,8 @@ static void oaep_mask(const ssh_hashalg *h, void *seed, int seedlen, data += max; datalen -= max; } + + ssh_hash_free(s); } strbuf *ssh_rsakex_encrypt(RSAKey *rsa, const ssh_hashalg *h, ptrlen in) @@ -907,10 +910,7 @@ strbuf *ssh_rsakex_encrypt(RSAKey *rsa, const ssh_hashalg *h, ptrlen in) random_read(out + 1, HLEN); /* At position 1+HLEN, the data block DB, consisting of: */ /* The hash of the label (we only support an empty label here) */ - { - ssh_hash *s = ssh_hash_new(h); - ssh_hash_final(s, out + HLEN + 1); - } + hash_simple(h, PTRLEN_LITERAL(""), out + HLEN + 1); /* A bunch of zero octets */ memset(out + 2*HLEN + 1, 0, outlen - (2*HLEN + 1)); /* A single 1 octet, followed by the input message data. */ @@ -953,7 +953,6 @@ mp_int *ssh_rsakex_decrypt( int outlen, i; unsigned char *out; unsigned char labelhash[64]; - ssh_hash *hash; BinarySource src[1]; const int HLEN = h->hlen; @@ -987,8 +986,7 @@ mp_int *ssh_rsakex_decrypt( } /* Check the label hash at position 1+HLEN */ assert(HLEN <= lenof(labelhash)); - hash = ssh_hash_new(h); - ssh_hash_final(hash, labelhash); + hash_simple(h, PTRLEN_LITERAL(""), labelhash); if (memcmp(out + HLEN + 1, labelhash, HLEN)) { sfree(out); return NULL; diff --git a/testcrypt.c b/testcrypt.c index 06f2f32b..8fd51d2d 100644 --- a/testcrypt.c +++ b/testcrypt.c @@ -623,6 +623,16 @@ mp_int *monty_modulus_wrapper(MontyContext *mc) } #define monty_modulus monty_modulus_wrapper +strbuf *ssh_hash_digest_wrapper(ssh_hash *h) +{ + strbuf *sb = strbuf_new(); + void *p = strbuf_append(sb, ssh_hash_alg(h)->hlen); + ssh_hash_digest(h, p); + return sb; +} +#undef ssh_hash_digest +#define ssh_hash_digest ssh_hash_digest_wrapper + strbuf *ssh_hash_final_wrapper(ssh_hash *h) { strbuf *sb = strbuf_new(); diff --git a/testcrypt.h b/testcrypt.h index 98a1daf0..61a8e538 100644 --- a/testcrypt.h +++ b/testcrypt.h @@ -122,7 +122,9 @@ FUNC3(void, ecc_edwards_get_affine, val_epoint, out_val_mpint, out_val_mpint) * API by the hash object also functioning as a BinarySink. */ FUNC1(opt_val_hash, ssh_hash_new, hashalg) +FUNC1(void, ssh_hash_reset, val_hash) FUNC1(val_hash, ssh_hash_copy, val_hash) +FUNC1(val_string, ssh_hash_digest, val_hash) FUNC1(val_string, ssh_hash_final, consumed_val_hash) FUNC2(void, ssh_hash_update, val_hash, val_string_ptrlen) diff --git a/testsc.c b/testsc.c index 319b1659..87f1e674 100644 --- a/testsc.c +++ b/testsc.c @@ -104,6 +104,7 @@ static uint64_t random_counter = 0; static const char *random_seedstr = NULL; static uint8_t random_buf[MAX_HASH_LEN]; static size_t random_buf_limit = 0; +static ssh_hash *random_hash; static void random_seed(const char *seedstr) { @@ -118,12 +119,12 @@ void random_read(void *vbuf, size_t size) uint8_t *buf = (uint8_t *)vbuf; while (size-- > 0) { if (random_buf_limit == 0) { - ssh_hash *h = ssh_hash_new(&ssh_sha256); - put_asciz(h, random_seedstr); - put_uint64(h, random_counter); + ssh_hash_reset(random_hash); + put_asciz(random_hash, random_seedstr); + put_uint64(random_hash, random_counter); random_counter++; - random_buf_limit = ssh_hash_alg(h)->hlen; - ssh_hash_final(h, random_buf); + random_buf_limit = ssh_hash_alg(random_hash)->hlen; + ssh_hash_digest(random_hash, random_buf); } *buf++ = random_buf[random_buf_limit--]; } @@ -1395,6 +1396,7 @@ int main(int argc, char **argv) bool test_names_given = false; memset(tests_to_run, 1, sizeof(tests_to_run)); + random_hash = ssh_hash_new(&ssh_sha256); while (--argc > 0) { char *p = *++argv; @@ -1555,6 +1557,8 @@ int main(int argc, char **argv) } } + ssh_hash_free(random_hash); + if (npass == nrun) { printf("All tests passed\n"); return 0; diff --git a/windows/winshare.c b/windows/winshare.c index 7f4af869..21edef09 100644 --- a/windows/winshare.c +++ b/windows/winshare.c @@ -86,11 +86,7 @@ static char *obfuscate_name(const char *realname) * We don't want to give away the length of the hostname either, * so having got it back out of CryptProtectMemory we now hash it. */ - { - ssh_hash *h = ssh_hash_new(&ssh_sha256); - put_string(h, cryptdata, cryptlen); - ssh_hash_final(h, digest); - } + hash_simple(&ssh_sha256, make_ptrlen(cryptdata, cryptlen), digest); sfree(cryptdata);