+static u_char *
+derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen,
+ BIGNUM *shared_secret)
+{
+ Buffer b;
+ EVP_MD_CTX md;
+ char c = id;
+ u_int have;
+ int mdsz;
+ u_char *digest;
+
+ if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0)
+ fatal("bad kex md size %d", mdsz);
+ digest = xmalloc(roundup(need, mdsz));
+
+ buffer_init(&b);
+ buffer_put_bignum2(&b, shared_secret);
+
+ /* K1 = HASH(K || H || "A" || session_id) */
+ EVP_DigestInit(&md, kex->evp_md);
+ if (!(datafellows & SSH_BUG_DERIVEKEY))
+ EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+ EVP_DigestUpdate(&md, hash, hashlen);
+ EVP_DigestUpdate(&md, &c, 1);
+ EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len);
+ EVP_DigestFinal(&md, digest, NULL);
+
+ /*
+ * expand key:
+ * Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
+ * Key = K1 || K2 || ... || Kn
+ */
+ for (have = mdsz; need > have; have += mdsz) {
+ EVP_DigestInit(&md, kex->evp_md);
+ if (!(datafellows & SSH_BUG_DERIVEKEY))
+ EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+ EVP_DigestUpdate(&md, hash, hashlen);
+ EVP_DigestUpdate(&md, digest, have);
+ EVP_DigestFinal(&md, digest + have, NULL);
+ }
+ buffer_free(&b);
+#ifdef DEBUG_KEX
+ fprintf(stderr, "key '%c'== ", c);
+ dump_digest("key", digest, need);
+#endif
+ return digest;
+}
+
+Newkeys *current_keys[MODE_MAX];
+
+#define NKEYS 6
+void
+kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret)