static int pkey_hkdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) { HKDF_PKEY_CTX *kctx = ctx->data; if (kctx->md == NULL || kctx->key == NULL) return 0; switch (kctx->mode) { case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND: return HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key, kctx->key_len, kctx->info, kctx->info_len, key, *keylen) != NULL; case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY: if (key == NULL) { *keylen = EVP_MD_size(kctx->md); return 1; } return HKDF_Extract(kctx->md, kctx->salt, kctx->salt_len, kctx->key, kctx->key_len, key, keylen) != NULL; case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY: return HKDF_Expand(kctx->md, kctx->key, kctx->key_len, kctx->info, kctx->info_len, key, *keylen) != NULL; default: return 0; } }
static unsigned char *HKDF(const EVP_MD *evp_md, const unsigned char *salt, size_t salt_len, const unsigned char *key, size_t key_len, const unsigned char *info, size_t info_len, unsigned char *okm, size_t okm_len) { unsigned char prk[EVP_MAX_MD_SIZE]; size_t prk_len; if (!HKDF_Extract(evp_md, salt, salt_len, key, key_len, prk, &prk_len)) return NULL; return HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len); }