1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Turn SSH hashes into a classoid.

The new version of ssh_hash has the same nice property as ssh2_mac,
that I can make the generic interface object type function directly as
a BinarySink so that clients don't have to call h->sink() and worry
about the separate sink object they get back from that.
This commit is contained in:
Simon Tatham 2018-09-13 16:41:46 +01:00
parent 853bd8b284
commit 4f9a90fc1a
7 changed files with 210 additions and 204 deletions

99
ssh.c
View File

@ -668,8 +668,7 @@ enum RekeyClass {
struct ssh_tag {
char *v_c, *v_s;
void *exhash;
BinarySink *exhash_bs;
ssh_hash *exhash;
Socket s;
@ -4780,11 +4779,10 @@ static void add_to_commasep(strbuf *buf, const char *data)
static void ssh2_mkkey(Ssh ssh, strbuf *out, Bignum K, unsigned char *H,
char chr, int keylen)
{
const struct ssh_hash *h = ssh->kex->hash;
const struct ssh_hashalg *h = ssh->kex->hash;
int keylen_padded;
unsigned char *key;
void *s, *s2;
BinarySink *bs;
ssh_hash *s, *s2;
if (keylen == 0)
return;
@ -4805,32 +4803,30 @@ static void ssh2_mkkey(Ssh ssh, strbuf *out, Bignum K, unsigned char *H,
key = strbuf_append(out, keylen_padded);
/* First hlen bytes. */
s = h->init();
bs = h->sink(s);
s = ssh_hash_new(h);
if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))
put_mp_ssh2(bs, K);
put_data(bs, H, h->hlen);
put_byte(bs, chr);
put_data(bs, ssh->v2_session_id, ssh->v2_session_id_len);
h->final(s, key);
put_mp_ssh2(s, K);
put_data(s, H, h->hlen);
put_byte(s, chr);
put_data(s, ssh->v2_session_id, ssh->v2_session_id_len);
ssh_hash_final(s, key);
/* Subsequent blocks of hlen bytes. */
if (keylen_padded > h->hlen) {
int offset;
s = h->init();
bs = h->sink(s);
s = ssh_hash_new(h);
if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))
put_mp_ssh2(bs, K);
put_data(bs, H, h->hlen);
put_mp_ssh2(s, K);
put_data(s, H, h->hlen);
for (offset = h->hlen; offset < keylen_padded; offset += h->hlen) {
put_data(bs, key + offset - h->hlen, h->hlen);
s2 = h->copy(s);
h->final(s2, key + offset);
put_data(s, key + offset - h->hlen, h->hlen);
s2 = ssh_hash_copy(s);
ssh_hash_final(s2, key + offset);
}
h->free(s);
ssh_hash_free(s);
}
}
@ -5600,14 +5596,13 @@ static void do_ssh2_transport(void *vctx)
get_string(pktin); /* server->client language */
s->ignorepkt = get_bool(pktin) && !s->guessok;
ssh->exhash = ssh->kex->hash->init();
ssh->exhash_bs = ssh->kex->hash->sink(ssh->exhash);
put_stringz(ssh->exhash_bs, ssh->v_c);
put_stringz(ssh->exhash_bs, ssh->v_s);
put_string(ssh->exhash_bs, s->our_kexinit, s->our_kexinitlen);
ssh->exhash = ssh_hash_new(ssh->kex->hash);
put_stringz(ssh->exhash, ssh->v_c);
put_stringz(ssh->exhash, ssh->v_s);
put_string(ssh->exhash, s->our_kexinit, s->our_kexinitlen);
sfree(s->our_kexinit);
/* Include the type byte in the hash of server's KEXINIT */
put_string(ssh->exhash_bs,
put_string(ssh->exhash,
(const char *)BinarySource_UPCAST(pktin)->data - 1,
BinarySource_UPCAST(pktin)->len + 1);
@ -5844,18 +5839,18 @@ static void do_ssh2_transport(void *vctx)
* involve user interaction. */
set_busy_status(ssh->frontend, BUSY_NOT);
put_stringpl(ssh->exhash_bs, s->hostkeydata);
put_stringpl(ssh->exhash, s->hostkeydata);
if (dh_is_gex(ssh->kex)) {
if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))
put_uint32(ssh->exhash_bs, DH_MIN_SIZE);
put_uint32(ssh->exhash_bs, s->pbits);
put_uint32(ssh->exhash, DH_MIN_SIZE);
put_uint32(ssh->exhash, s->pbits);
if (!(ssh->remote_bugs & BUG_SSH2_OLDGEX))
put_uint32(ssh->exhash_bs, DH_MAX_SIZE);
put_mp_ssh2(ssh->exhash_bs, s->p);
put_mp_ssh2(ssh->exhash_bs, s->g);
put_uint32(ssh->exhash, DH_MAX_SIZE);
put_mp_ssh2(ssh->exhash, s->p);
put_mp_ssh2(ssh->exhash, s->g);
}
put_mp_ssh2(ssh->exhash_bs, s->e);
put_mp_ssh2(ssh->exhash_bs, s->f);
put_mp_ssh2(ssh->exhash, s->e);
put_mp_ssh2(ssh->exhash, s->f);
dh_cleanup(ssh->kex_ctx);
freebn(s->f);
@ -5893,19 +5888,19 @@ static void do_ssh2_transport(void *vctx)
}
s->hostkeydata = get_string(pktin);
put_stringpl(ssh->exhash_bs, s->hostkeydata);
put_stringpl(ssh->exhash, s->hostkeydata);
s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata);
{
strbuf *pubpoint = strbuf_new();
ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint));
put_string(ssh->exhash_bs, pubpoint->u, pubpoint->len);
put_string(ssh->exhash, pubpoint->u, pubpoint->len);
strbuf_free(pubpoint);
}
{
ptrlen keydata = get_string(pktin);
put_stringpl(ssh->exhash_bs, keydata);
put_stringpl(ssh->exhash, keydata);
s->K = ssh_ecdhkex_getkey(s->eckey, keydata.ptr, keydata.len);
if (!get_err(pktin) && !s->K) {
ssh_ecdhkex_freekey(s->eckey);
@ -6100,7 +6095,7 @@ static void do_ssh2_transport(void *vctx)
if (ssh->hostkey_alg) {
s->hkey = ssh_key_new_pub(ssh->hostkey_alg,
s->hostkeydata);
put_string(ssh->exhash_bs,
put_string(ssh->exhash,
s->hostkeydata.ptr, s->hostkeydata.len);
}
/*
@ -6149,18 +6144,18 @@ static void do_ssh2_transport(void *vctx)
set_busy_status(ssh->frontend, BUSY_NOT);
if (!s->hkey)
put_stringz(ssh->exhash_bs, "");
put_stringz(ssh->exhash, "");
if (dh_is_gex(ssh->kex)) {
/* min, preferred, max */
put_uint32(ssh->exhash_bs, s->pbits);
put_uint32(ssh->exhash_bs, s->pbits);
put_uint32(ssh->exhash_bs, s->pbits * 2);
put_uint32(ssh->exhash, s->pbits);
put_uint32(ssh->exhash, s->pbits);
put_uint32(ssh->exhash, s->pbits * 2);
put_mp_ssh2(ssh->exhash_bs, s->p);
put_mp_ssh2(ssh->exhash_bs, s->g);
put_mp_ssh2(ssh->exhash, s->p);
put_mp_ssh2(ssh->exhash, s->g);
}
put_mp_ssh2(ssh->exhash_bs, s->e);
put_mp_ssh2(ssh->exhash_bs, s->f);
put_mp_ssh2(ssh->exhash, s->e);
put_mp_ssh2(ssh->exhash, s->f);
/*
* MIC verification is done below, after we compute the hash
@ -6192,7 +6187,7 @@ static void do_ssh2_transport(void *vctx)
}
s->hostkeydata = get_string(pktin);
put_stringpl(ssh->exhash_bs, s->hostkeydata);
put_stringpl(ssh->exhash, s->hostkeydata);
s->hkey = ssh_key_new_pub(ssh->hostkey_alg, s->hostkeydata);
rsakeydata = get_string(pktin);
@ -6203,7 +6198,7 @@ static void do_ssh2_transport(void *vctx)
crStopV;
}
put_stringpl(ssh->exhash_bs, rsakeydata);
put_stringpl(ssh->exhash, rsakeydata);
/*
* Next, set up a shared secret K, of precisely KLEN -
@ -6249,7 +6244,7 @@ static void do_ssh2_transport(void *vctx)
put_string(s->pktout, outstr, outstrlen);
ssh_pkt_write(ssh, s->pktout);
put_string(ssh->exhash_bs, outstr, outstrlen);
put_string(ssh->exhash, outstr, outstrlen);
strbuf_free(buf);
sfree(outstr);
@ -6270,9 +6265,9 @@ static void do_ssh2_transport(void *vctx)
}
}
put_mp_ssh2(ssh->exhash_bs, s->K);
assert(ssh->kex->hash->hlen <= sizeof(s->exchange_hash));
ssh->kex->hash->final(ssh->exhash, s->exchange_hash);
put_mp_ssh2(ssh->exhash, s->K);
assert(ssh_hash_alg(ssh->exhash)->hlen <= sizeof(s->exchange_hash));
ssh_hash_final(ssh->exhash, s->exchange_hash);
#ifndef NO_GSSAPI
if (ssh->kex->main_type == KEXTYPE_GSS) {

37
ssh.h
View File

@ -331,11 +331,12 @@ int detect_attack(struct crcda_ctx *ctx, unsigned char *buf, uint32 len,
/*
* SSH2 RSA key exchange functions
*/
struct ssh_hash;
struct ssh_hashalg;
struct RSAKey *ssh_rsakex_newkey(const void *data, int len);
void ssh_rsakex_freekey(struct RSAKey *key);
int ssh_rsakex_klen(struct RSAKey *key);
void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen,
void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
unsigned char *in, int inlen,
unsigned char *out, int outlen, struct RSAKey *key);
/*
@ -527,20 +528,30 @@ int ssh2_mac_verresult(ssh2_mac *, const void *);
void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq);
int ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq);
struct ssh_hash {
void *(*init)(void); /* also allocates context */
void *(*copy)(const void *);
BinarySink *(*sink) (void *);
void (*final)(void *, unsigned char *); /* also frees context */
void (*free)(void *);
typedef struct ssh_hash {
const struct ssh_hashalg *vt;
BinarySink_DELEGATE_IMPLEMENTATION;
} ssh_hash;
struct ssh_hashalg {
ssh_hash *(*new)(const struct ssh_hashalg *alg);
ssh_hash *(*copy)(ssh_hash *);
void (*final)(ssh_hash *, unsigned char *); /* ALSO FREES THE ssh_hash! */
void (*free)(ssh_hash *);
int hlen; /* output length in bytes */
const char *text_name;
};
#define ssh_hash_new(alg) ((alg)->new(alg))
#define ssh_hash_copy(ctx) ((ctx)->vt->copy(ctx))
#define ssh_hash_final(ctx, out) ((ctx)->vt->final(ctx, out))
#define ssh_hash_free(ctx) ((ctx)->vt->free(ctx))
#define ssh_hash_alg(ctx) ((ctx)->vt)
struct ssh_kex {
const char *name, *groupname;
enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH, KEXTYPE_GSS } main_type;
const struct ssh_hash *hash;
const struct ssh_hashalg *hash;
const void *extra; /* private to the kex methods */
};
@ -625,10 +636,10 @@ extern const struct ssh2_ciphers ssh2_aes;
extern const struct ssh2_ciphers ssh2_blowfish;
extern const struct ssh2_ciphers ssh2_arcfour;
extern const struct ssh2_ciphers ssh2_ccp;
extern const struct ssh_hash ssh_sha1;
extern const struct ssh_hash ssh_sha256;
extern const struct ssh_hash ssh_sha384;
extern const struct ssh_hash ssh_sha512;
extern const struct ssh_hashalg ssh_sha1;
extern const struct ssh_hashalg ssh_sha256;
extern const struct ssh_hashalg ssh_sha384;
extern const struct ssh_hashalg ssh_sha512;
extern const struct ssh_kexes ssh_diffiehellman_group1;
extern const struct ssh_kexes ssh_diffiehellman_group14;
extern const struct ssh_kexes ssh_diffiehellman_gex;

View File

@ -1688,7 +1688,7 @@ static int BinarySource_get_point(BinarySource *src, struct ec_point *point)
struct ecsign_extra {
struct ec_curve *(*curve)(void);
const struct ssh_hash *hash;
const struct ssh_hashalg *hash;
/* These fields are used by the OpenSSH PEM format importer/exporter */
const unsigned char *oid;
@ -2227,7 +2227,7 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
Bignum r, s;
unsigned char digest[512 / 8];
int digestLen;
void *hashctx;
ssh_hash *hashctx;
BinarySource_BARE_INIT(src, sigstr.ptr, sigstr.len);
@ -2241,9 +2241,9 @@ static int ecdsa_verify(ssh_key *key, ptrlen sig, ptrlen data)
digestLen = extra->hash->hlen;
assert(digestLen <= sizeof(digest));
hashctx = extra->hash->init();
put_data(extra->hash->sink(hashctx), data.ptr, data.len);
extra->hash->final(hashctx, digest);
hashctx = ssh_hash_new(extra->hash);
put_data(hashctx, data.ptr, data.len);
ssh_hash_final(hashctx, digest);
/* Verify the signature */
ret = _ecdsa_verify(&ec->publicKey, digest, digestLen, r, s);
@ -2363,14 +2363,14 @@ static void ecdsa_sign(ssh_key *key, const void *data, int datalen,
put_byte(bs, bignum_byte(s, i));
freebn(s);
} else {
void *hashctx;
ssh_hash *hashctx;
strbuf *substr;
digestLen = extra->hash->hlen;
assert(digestLen <= sizeof(digest));
hashctx = extra->hash->init();
put_data(extra->hash->sink(hashctx), data, datalen);
extra->hash->final(hashctx, digest);
hashctx = ssh_hash_new(extra->hash);
put_data(hashctx, data, datalen);
ssh_hash_final(hashctx, digest);
/* Do the signature */
_ecdsa_sign(ec->privateKey, ec->publicKey.curve, digest, digestLen, &r, &s);

View File

@ -783,7 +783,7 @@ int ssh_rsakex_klen(struct RSAKey *rsa)
return bignum_bitcount(rsa->modulus);
}
static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen,
static void oaep_mask(const struct ssh_hashalg *h, void *seed, int seedlen,
void *vdata, int datalen)
{
unsigned char *data = (unsigned char *)vdata;
@ -791,16 +791,14 @@ static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen,
while (datalen > 0) {
int i, max = (datalen > h->hlen ? h->hlen : datalen);
void *s;
BinarySink *bs;
ssh_hash *s;
unsigned char hash[SSH2_KEX_MAX_HASH_LEN];
assert(h->hlen <= SSH2_KEX_MAX_HASH_LEN);
s = h->init();
bs = h->sink(s);
put_data(bs, seed, seedlen);
put_uint32(bs, count);
h->final(s, hash);
s = ssh_hash_new(h);
put_data(s, seed, seedlen);
put_uint32(s, count);
ssh_hash_final(s, hash);
count++;
for (i = 0; i < max; i++)
@ -811,7 +809,8 @@ static void oaep_mask(const struct ssh_hash *h, void *seed, int seedlen,
}
}
void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen,
void ssh_rsakex_encrypt(const struct ssh_hashalg *h,
unsigned char *in, int inlen,
unsigned char *out, int outlen, struct RSAKey *rsa)
{
Bignum b1, b2;
@ -866,7 +865,10 @@ void ssh_rsakex_encrypt(const struct ssh_hash *h, unsigned char *in, int inlen,
out[i + 1] = random_byte();
/* At position 1+HLEN, the data block DB, consisting of: */
/* The hash of the label (we only support an empty label here) */
h->final(h->init(), out + HLEN + 1);
{
ssh_hash *s = ssh_hash_new(h);
ssh_hash_final(s, 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. */

View File

@ -204,51 +204,51 @@ void SHA256_Simple(const void *p, int len, unsigned char *output) {
* Thin abstraction for things where hashes are pluggable.
*/
static void *sha256_init(void)
{
SHA256_State *s;
struct sha256_hash {
SHA256_State state;
ssh_hash hash;
};
s = snew(SHA256_State);
SHA256_Init(s);
return s;
static ssh_hash *sha256_new(const struct ssh_hashalg *alg)
{
struct sha256_hash *h = snew(struct sha256_hash);
SHA256_Init(&h->state);
h->hash.vt = alg;
BinarySink_DELEGATE_INIT(&h->hash, &h->state);
return &h->hash;
}
static void *sha256_copy(const void *vold)
static ssh_hash *sha256_copy(ssh_hash *hashold)
{
const SHA256_State *old = (const SHA256_State *)vold;
SHA256_State *s;
struct sha256_hash *hold, *hnew;
ssh_hash *hashnew = sha256_new(hashold->vt);
s = snew(SHA256_State);
*s = *old;
BinarySink_COPIED(s);
return s;
hold = FROMFIELD(hashold, struct sha256_hash, hash);
hnew = FROMFIELD(hashnew, struct sha256_hash, hash);
hnew->state = hold->state;
BinarySink_COPIED(&hnew->state);
return hashnew;
}
static void sha256_free(void *handle)
static void sha256_free(ssh_hash *hash)
{
SHA256_State *s = handle;
struct sha256_hash *h = FROMFIELD(hash, struct sha256_hash, hash);
smemclr(s, sizeof(*s));
sfree(s);
smemclr(h, sizeof(*h));
sfree(h);
}
static BinarySink *sha256_sink(void *handle)
static void sha256_final(ssh_hash *hash, unsigned char *output)
{
SHA256_State *s = handle;
return BinarySink_UPCAST(s);
struct sha256_hash *h = FROMFIELD(hash, struct sha256_hash, hash);
SHA256_Final(&h->state, output);
sha256_free(hash);
}
static void sha256_final(void *handle, unsigned char *output)
{
SHA256_State *s = handle;
SHA256_Final(s, output);
sha256_free(s);
}
const struct ssh_hash ssh_sha256 = {
sha256_init, sha256_copy, sha256_sink, sha256_final, sha256_free,
32, "SHA-256"
const struct ssh_hashalg ssh_sha256 = {
sha256_new, sha256_copy, sha256_final, sha256_free, 32, "SHA-256"
};
/* ----------------------------------------------------------------------

View File

@ -327,74 +327,71 @@ void SHA384_Simple(const void *p, int len, unsigned char *output) {
* Thin abstraction for things where hashes are pluggable.
*/
static void *sha512_init(void)
{
SHA512_State *s;
s = snew(SHA512_State);
SHA512_Init(s);
return s;
}
static void *sha512_copy(const void *vold)
{
const SHA512_State *old = (const SHA512_State *)vold;
SHA512_State *s;
s = snew(SHA512_State);
*s = *old;
BinarySink_COPIED(s);
return s;
}
static void sha512_free(void *handle)
{
SHA512_State *s = handle;
smemclr(s, sizeof(*s));
sfree(s);
}
static BinarySink *sha512_sink(void *handle)
{
SHA512_State *s = handle;
return BinarySink_UPCAST(s);
}
static void sha512_final(void *handle, unsigned char *output)
{
SHA512_State *s = handle;
SHA512_Final(s, output);
sha512_free(s);
}
const struct ssh_hash ssh_sha512 = {
sha512_init, sha512_copy, sha512_sink, sha512_final, sha512_free,
64, "SHA-512"
struct sha512_hash {
SHA512_State state;
ssh_hash hash;
};
static void *sha384_init(void)
static ssh_hash *sha512_new(const struct ssh_hashalg *alg)
{
SHA512_State *s;
s = snew(SHA512_State);
SHA384_Init(s);
return s;
struct sha512_hash *h = snew(struct sha512_hash);
SHA512_Init(&h->state);
h->hash.vt = alg;
BinarySink_DELEGATE_INIT(&h->hash, &h->state);
return &h->hash;
}
static void sha384_final(void *handle, unsigned char *output)
static ssh_hash *sha512_copy(ssh_hash *hashold)
{
SHA512_State *s = handle;
struct sha512_hash *hold, *hnew;
ssh_hash *hashnew = sha512_new(hashold->vt);
SHA384_Final(s, output);
smemclr(s, sizeof(*s));
sfree(s);
hold = FROMFIELD(hashold, struct sha512_hash, hash);
hnew = FROMFIELD(hashnew, struct sha512_hash, hash);
hnew->state = hold->state;
BinarySink_COPIED(&hnew->state);
return hashnew;
}
const struct ssh_hash ssh_sha384 = {
sha384_init, sha512_copy, sha512_sink, sha384_final, sha512_free,
48, "SHA-384"
static void sha512_free(ssh_hash *hash)
{
struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash);
smemclr(h, sizeof(*h));
sfree(h);
}
static void sha512_final(ssh_hash *hash, unsigned char *output)
{
struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash);
SHA512_Final(&h->state, output);
sha512_free(hash);
}
const struct ssh_hashalg ssh_sha512 = {
sha512_new, sha512_copy, sha512_final, sha512_free, 64, "SHA-512"
};
static ssh_hash *sha384_new(const struct ssh_hashalg *alg)
{
struct sha512_hash *h = snew(struct sha512_hash);
SHA384_Init(&h->state);
h->hash.vt = alg;
BinarySink_DELEGATE_INIT(&h->hash, &h->state);
return &h->hash;
}
static void sha384_final(ssh_hash *hash, unsigned char *output)
{
struct sha512_hash *h = FROMFIELD(hash, struct sha512_hash, hash);
SHA384_Final(&h->state, output);
sha512_free(hash);
}
const struct ssh_hashalg ssh_sha384 = {
sha384_new, sha512_copy, sha384_final, sha512_free, 48, "SHA-384"
};
#ifdef TEST

View File

@ -232,50 +232,51 @@ void SHA_Simple(const void *p, int len, unsigned char *output)
* Thin abstraction for things where hashes are pluggable.
*/
static void *sha1_init(void)
{
SHA_State *s;
struct sha1_hash {
SHA_State state;
ssh_hash hash;
};
s = snew(SHA_State);
SHA_Init(s);
return s;
static ssh_hash *sha1_new(const struct ssh_hashalg *alg)
{
struct sha1_hash *h = snew(struct sha1_hash);
SHA_Init(&h->state);
h->hash.vt = alg;
BinarySink_DELEGATE_INIT(&h->hash, &h->state);
return &h->hash;
}
static void *sha1_copy(const void *vold)
static ssh_hash *sha1_copy(ssh_hash *hashold)
{
const SHA_State *old = (const SHA_State *)vold;
SHA_State *s;
struct sha1_hash *hold, *hnew;
ssh_hash *hashnew = sha1_new(hashold->vt);
s = snew(SHA_State);
*s = *old;
BinarySink_COPIED(s);
return s;
hold = FROMFIELD(hashold, struct sha1_hash, hash);
hnew = FROMFIELD(hashnew, struct sha1_hash, hash);
hnew->state = hold->state;
BinarySink_COPIED(&hnew->state);
return hashnew;
}
static void sha1_free(void *handle)
static void sha1_free(ssh_hash *hash)
{
SHA_State *s = handle;
struct sha1_hash *h = FROMFIELD(hash, struct sha1_hash, hash);
smemclr(s, sizeof(*s));
sfree(s);
smemclr(h, sizeof(*h));
sfree(h);
}
static BinarySink *sha1_sink(void *handle)
static void sha1_final(ssh_hash *hash, unsigned char *output)
{
SHA_State *s = handle;
return BinarySink_UPCAST(s);
struct sha1_hash *h = FROMFIELD(hash, struct sha1_hash, hash);
SHA_Final(&h->state, output);
sha1_free(hash);
}
static void sha1_final(void *handle, unsigned char *output)
{
SHA_State *s = handle;
SHA_Final(s, output);
sha1_free(s);
}
const struct ssh_hash ssh_sha1 = {
sha1_init, sha1_copy, sha1_sink, sha1_final, sha1_free, 20, "SHA-1"
const struct ssh_hashalg ssh_sha1 = {
sha1_new, sha1_copy, sha1_final, sha1_free, 20, "SHA-1"
};
/* ----------------------------------------------------------------------