static u_char * derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, const u_char *shared_secret, u_int slen) { Buffer b; struct ssh_digest_ctx *hashctx; char c = id; u_int have; size_t mdsz; u_char *digest; if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) fatal("bad kex md size %zu", mdsz); digest = xmalloc(roundup(need, mdsz)); buffer_init(&b); buffer_append(&b, shared_secret, slen); /* K1 = HASH(K || H || "A" || session_id) */ if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) fatal("%s: ssh_digest_start failed", __func__); if (ssh_digest_update_buffer(hashctx, &b) != 0 || ssh_digest_update(hashctx, hash, hashlen) != 0 || ssh_digest_update(hashctx, &c, 1) != 0 || ssh_digest_update(hashctx, kex->session_id, kex->session_id_len) != 0) fatal("%s: ssh_digest_update failed", __func__); if (ssh_digest_final(hashctx, digest, mdsz) != 0) fatal("%s: ssh_digest_final failed", __func__); ssh_digest_free(hashctx); /* * expand key: * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) * Key = K1 || K2 || ... || Kn */ for (have = mdsz; need > have; have += mdsz) { if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) fatal("%s: ssh_digest_start failed", __func__); if (ssh_digest_update_buffer(hashctx, &b) != 0 || ssh_digest_update(hashctx, hash, hashlen) != 0 || ssh_digest_update(hashctx, digest, have) != 0) fatal("%s: ssh_digest_update failed", __func__); if (ssh_digest_final(hashctx, digest + have, mdsz) != 0) fatal("%s: ssh_digest_final failed", __func__); ssh_digest_free(hashctx); } buffer_free(&b); #ifdef DEBUG_KEX fprintf(stderr, "key '%c'== ", c); dump_digest("key", digest, need); #endif return digest; }
static int derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, const u_char *shared_secret, u_int slen, u_char **keyp) { struct kex *kex = ssh->kex; struct sshbuf *b = NULL; struct ssh_digest_ctx *hashctx = NULL; char c = id; u_int have; size_t mdsz; u_char *digest; int r; if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) return SSH_ERR_INVALID_ARGUMENT; if ((digest = calloc(1, roundup(need, mdsz))) == NULL || (b = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_put(b, shared_secret, slen)) < 0) goto out; /* K1 = HASH(K || H || "A" || session_id) */ if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || ssh_digest_update_buffer(hashctx, b) != 0 || ssh_digest_update(hashctx, hash, hashlen) != 0 || ssh_digest_update(hashctx, &c, 1) != 0 || ssh_digest_update(hashctx, kex->session_id, kex->session_id_len) != 0 || ssh_digest_final(hashctx, digest, mdsz) != 0) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } ssh_digest_free(hashctx); hashctx = NULL; /* * expand key: * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) * Key = K1 || K2 || ... || Kn */ for (have = mdsz; need > have; have += mdsz) { if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || ssh_digest_update_buffer(hashctx, b) != 0 || ssh_digest_update(hashctx, hash, hashlen) != 0 || ssh_digest_update(hashctx, digest, have) != 0 || ssh_digest_final(hashctx, digest + have, mdsz) != 0) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } ssh_digest_free(hashctx); hashctx = NULL; } #ifdef DEBUG_KEX fprintf(stderr, "key '%c'== ", c); dump_digest("key", digest, need); #endif *keyp = digest; digest = NULL; r = 0; out: if (digest) free(digest); if (b) sshbuf_free(b); ssh_digest_free(hashctx); return r; }
int ssh_hmac_update_buffer(struct ssh_hmac_ctx *ctx, const struct sshbuf *b) { return ssh_digest_update_buffer(ctx->digest, b); }