EVP_KDF-IKEV2KDF(7ssl)
π EVP_KDF-IKEV2KDF(7ssl) β OpenSSL's IKEv2 KDF, bestie π
okay so this is the OpenSSL manual page for EVP_KDF-IKEV2KDF(7ssl), and it's giving key-derivation main character energy β¨ no cap.
π NAME π
EVP_KDF-IKEV2KDF β the IKEV2KDF EVP_KDF implementation, periodt π
β¨ DESCRIPTION β¨
Support for computing the IKEV2KDF KDF through the EVP_KDF API. slay.
The EVP_KDF-IKEV2KDF algorithm implements the IKEv2 key derivation function. It is defined in RFC 7296, sections 2.13, 2.14, 2.17, 2.18 and is used by the Internet Key Exchange version 2 (IKEv2) protocol to derive various keys from the shared secret established during the Diffie-Hellman (DH) exchange. RFC 4753 specifies additional ECDH groups for use with IKEv2. The key derivation requires several inputs including the hash function, the shared secret (g^ir), nonces from both parties, the Security Parameter Index (SPI) values from both parties, and new shared secret (new g^ir). SA refers to the Security Association established between the two parties. iykyk π¦
πͺͺ Identity πͺͺ
"IKEV2KDF" is the name for this implementation; it can be used with the EVP_KDF_fetch() function. iconic β¨
π Supported parameters π
The supported parameters are:
"properties"(OSSL_KDF_PARAM_PROPERTIES)<UTF8 string>and"digest"(OSSL_KDF_PARAM_DIGEST)<UTF8 string>β these parameters work as described in"PARAMETERS"inEVP_KDF(3). The digest parameter must be set to one of"SHA1","SHA224","SHA256","SHA384", or"SHA512"for theIKEV2KDFimplementation. If a value is already set, the contents are replaced."secret"(OSSL_KDF_PARAM_SECRET)<octet string>β this parameter sets the shared secret (g^ir) used for generating theSEEDKEY, or the new shared secret (new g^ir) used for derivingDKM(Child_DH)orREKEY. The shared secret length is in the range of 8 to 1024 bytes as specified in the NIST ACVP draft (https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ikev2.html). If a value is already set, the contents are replaced. obsessed with the precision here π"ni"(OSSL_KDF_PARAM_IKEV2_NI)<octet string>β this parameter sets the initiator's nonce (Ni) value for the KDF. The nonce length is in the range of 8 to 256 bytes as specified in NIST ACVP draft (https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ikev2.html). If a value is already set, the contents are replaced."nr"(OSSL_KDF_PARAM_IKEV2_NR)<octet string>β this parameter sets the responder's nonce (Nr) value for the KDF. The nonce length is in the range of 8 to 256 bytes as specified in NIST ACVP draft (https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ikev2.html). If a value is already set, the contents are replaced."spii"(OSSL_KDF_PARAM_IKEV2_SPII)<octet string>β this parameter sets the initiator's Security Parameter Index (SPIi) value for the KDF. If a value is already set, the contents are replaced."spir"(OSSL_KDF_PARAM_IKEV2_SPIR)<octet string>β this parameter sets the responder's Security Parameter Index (SPIr) value for the KDF. If a value is already set, the contents are replaced."seedkey"(OSSL_KDF_PARAM_SEEDKEY)<octet string>β this parameter sets theSEEDKEYused for derivingDKM(Initial SA). If a value is already set, the contents are replaced."key"(OSSL_KDF_PARAM_KEY)<octet string>β this parameter sets theSK_dused for derivingDKM(Child_SA)orREKEY. If a value is already set, the contents are replaced."mode"(OSSL_KDF_PARAM_MODE)<int>β this parameter sets the IKEv2 KDF mode. TheIKEV2KDFimplementation supports three different modes of operation:EVP_KDF_IKEV2_MODE_GENβ it generates theSKEYSEEDused in deriving key material. It is the default mode if the"mode"parameter is not set. It takes the shared secret (g^ir) and nonces (NiandNr) as input and generates theSKEYSEED.EVP_KDF_IKEV2_MODE_DKMβ it operates in three stages, based on the input parameter sets.- It first performs initial key derivation: it derives the initial set of keys (
SK_d,SK_ai,SK_ar,SK_ei,SK_er,SK_pi,SK_pr) usingSKEYSEEDgenerated in"EVP_KDF_IKEV2_MODE_GEN", the nonces (from both sides), and security parameter index (SPI) values (from both sides). - Then, it derives keying material for the
Child_SA, using theSK_das input along with new nonces. - Finally, it derives keying material for the
Child_DH, using theSK_das input along with new nonces and new shared secret (new g^ir).
- It first performs initial key derivation: it derives the initial set of keys (
EVP_KDF_IKEV2_MODE_REKEYβ it derives a newSKEYSEEDwhen rekeying the IKE SA, using the existingSK_das input along with new nonces and new shared secret (new g^ir).
"fips-indicator"(OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR)<integer>β the OpenSSL FIPS provider returns 1 if the operation is FIPS approved, or 0 otherwise. See"FIPS indicators"infips_module(7)for more information. vibe check: approved or not approved, bestie π
π NOTES π
A context for IKEV2KDF can be obtained by calling:
EVP_KDF *kdf = EVP_KDF_fetch(NULL, "IKEV2KDF", NULL);
EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf);
The output length for IKEV2KDF can be specified by the caller based on the specific key being derived (e.g., SK_d, SK_ai, SK_ar, SK_ei, SK_er, SK_pi, SK_pr). Different keys may require different lengths depending on the cryptographic algorithms being used. literally so flexible π«Ά
β¨ EXAMPLES β¨
Okay bestie, this is the fun part β actual code you can copy-paste-slay into your project π Every example below is doing a real IKEv2 thing, so like, pay attention, iykyk.
π Example of SEEDKEY generation
This one derives a 32-byte SEEDKEY using SHA-256, with the appropriate shared secret and nonces. It's giving "first step of the whole vibe" energy:
EVP_KDF *kdf = NULL;
EVP_KDF_CTX *kctx = NULL;
unsigned char secret[32] = "0123456789abcdef0123456789abcdef"; /* g^ir */
unsigned char ni[8] = "01234567";
unsigned char nr[8] = "89abcdef";
int mode = EVP_KDF_IKEV2_MODE_GEN;
unsigned char out[32];
size_t outlen = sizeof(out);
OSSL_PARAM params[6], *p = params;
kdf = EVP_KDF_fetch(NULL, "IKEV2KDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
if (!kctx) {
/* Error handling */
}
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
SN_sha256, strlen(SN_sha256));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET,
secret, sizeof(secret));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NI,
ni, sizeof(ni));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NR,
nr, sizeof(nr));
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, outlen, params) <= 0) {
/* Error */
;
}
EVP_KDF_CTX_free(kctx);
EVP_KDF_free(kdf);
πΈ Example of deriving key material DKM(Initial SA)
Now we're deriving key material for the Initial SA, using skeyseed as the seed π¦ Notice the param array is params[8] here because there's more going on β we got SPIi and SPIr in the mix:
EVP_KDF *kdf = NULL;
EVP_KDF_CTX *kctx = NULL;
unsigned char ni[8] = "01234567";
unsigned char nr[8] = "89abcdef";
unsigned char spii[8] = "01234567";
unsigned char spir[8] = "89abcdef";
unsigned char skeyseed[32] = "0123456789abcdef0123456789abcdef";
int mode = EVP_KDF_IKEV2_MODE_DKM;
unsigned char out[224];
OSSL_PARAM params[8], *p = params;
kdf = EVP_KDF_fetch(NULL, "IKEV2KDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
if (!kctx) {
/* Error handling */
}
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
SN_sha256, strlen(SN_sha256));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SEED,
skeyseed, sizeof(skeyseed));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NI,
ni, sizeof(ni));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NR,
nr, sizeof(nr));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_SPII,
spii, sizeof(spii));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_SPIR,
spir, sizeof(spir));
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
/* Error handling */
;
}
EVP_KDF_CTX_free(kctx);
EVP_KDF_free(kdf);
π Example of generating DKM(Child_SA)
Child SA time!! π This one's leaner β params[6], no SPIs, just sk_d doing its main character thing:
EVP_KDF *kdf = NULL;
EVP_KDF_CTX *kctx = NULL;
unsigned char ni[8] = "01234567";
unsigned char nr[8] = "89abcdef";
unsigned char sk_d[32] = "0123456789abcdef0123456789abcdef";
int mode = EVP_KDF_IKEV2_MODE_DKM;
unsigned char out[224];
OSSL_PARAM params[6], *p = params;
kdf = EVP_KDF_fetch(NULL, "IKEV2KDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
if (!kctx) {
/* Error handling */
}
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
SN_sha256, strlen(SN_sha256));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
sk_d, sizeof(sk_d));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NI,
ni, sizeof(ni));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NR,
nr, sizeof(nr));
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
/* Error handling */
;
}
EVP_KDF_CTX_free(kctx);
EVP_KDF_free(kdf);
π¦ Example of generating DKM(Child_DH)
Same EVP_KDF_IKEV2_MODE_DKM mode, but now we're pulling in a new_secret (a fresh g^ir) alongside sk_d β so params[7] π₯:
EVP_KDF *kdf = NULL;
EVP_KDF_CTX *kctx = NULL;
unsigned char ni[8] = "01234567";
unsigned char nr[8] = "89abcdef";
unsigned char sk_d[32] = "0123456789abcdef0123456789abcdef";
unsigned char new_secret[32] = "0123456789abcdef0123456789abcdef"; /* new g^ir */
int mode = EVP_KDF_IKEV2_MODE_DKM;
unsigned char out[224];
OSSL_PARAM params[7], *p = params;
kdf = EVP_KDF_fetch(NULL, "IKEV2KDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
if (!kctx) {
/* Error handling */
}
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
SN_sha256, strlen(SN_sha256));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
sk_d, sizeof(sk_d));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET,
new_secret, sizeof(new_secret));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NI,
ni, sizeof(ni));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NR,
nr, sizeof(nr));
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
/* Error */
;
}
EVP_KDF_CTX_free(kctx);
EVP_KDF_free(kdf);
π Example of rekeying the IKE SA
Rekeying, bestie!! β¨ Switch that mode to EVP_KDF_IKEV2_MODE_REKEY and your output is a tidy 32 bytes again. Very "new keys, who dis" of you:
EVP_KDF *kdf = NULL;
EVP_KDF_CTX *kctx = NULL;
unsigned char ni[8] = "01234567";
unsigned char nr[8] = "89abcdef";
unsigned char sk_d[32] = "0123456789abcdef0123456789abcdef";
unsigned char new_secret[32] = "0123456789abcdef0123456789abcdef"; /* new g^ir */
int mode = EVP_KDF_IKEV2_MODE_REKEY;
unsigned char out[32];
OSSL_PARAM params[7], *p = params;
kdf = EVP_KDF_fetch(NULL, "IKEV2KDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
if (!kctx) {
/* Error handling */
}
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
SN_sha256, strlen(SN_sha256));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
sk_d, sizeof(sk_d));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET,
new_secret, sizeof(new_secret));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NI,
ni, sizeof(ni));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_IKEV2KDF_NR,
nr, sizeof(nr));
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
/* Error handling */
;
}
EVP_KDF_CTX_free(kctx);
EVP_KDF_free(kdf);
π CONFORMING TO
It's conforming to RFC 7296 and SP800-135 β certified good behavior, no cap π«Ά
β SEE ALSO
Go read these too, they're literally the supporting cast and they ate:
EVP_KDF(3)EVP_KDF_CTX_new(3)EVP_KDF_CTX_dup(3)EVP_KDF_CTX_free(3)EVP_KDF_CTX_set_params(3)EVP_KDF_CTX_get_kdf_size(3)EVP_KDF_derive(3)"PARAMETERS" in EVP_KDF(3)
π§ HISTORY
This functionality was added in OpenSSL 4.1. New drop, fresh out the oven π
π COPYRIGHT
Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.
That's the whole page, bestie β go forth and derive πΈ
Okay and like, the very last thing: this gorgeous piece of documentation is from version 4.1.0, dated 2026-10-23, and it goes by EVP_KDF-IKEV2KDF(7ssl) π mwah, take care of her π
π¦ where this page comes from
- nixos 26.05: openssl 4.1.0
- nixpkgs unstable: openssl 4.1.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms