Skip to content

EVP_KDF-IKEV2KDF

NAME

EVP_KDF-IKEV2KDF - The IKEV2KDF EVP_KDF implementation

DESCRIPTION

Support for computing the IKEV2KDF KDF through the EVP_KDF API.

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.

Identity

"IKEV2KDF" is the name for this implementation; it can be used with the EVP_KDF_fetch() function.

Supported parameters

The supported parameters are:

  • "properties" (OSSL_KDF_PARAM_PROPERTIES) <UTF8 string>
  • "digest" (OSSL_KDF_PARAM_DIGEST) <UTF8 string>

    These parameters work as described in "PARAMETERS" in EVP_KDF(3). The digest parameter must be set to one of "SHA1", "SHA224", "SHA256", "SHA384", or "SHA512" for the IKEV2KDF implementation. 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 the SEEDKEY, or the new shared secret (new g^ir) used for deriving DKM(Child_DH) or REKEY. 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.

  • "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 the SEEDKEY used for deriving DKM(Initial SA). If a value is already set, the contents are replaced.

  • "key" (OSSL_KDF_PARAM_KEY) <octet string>

    This parameter sets the SK_d used for deriving DKM(Child_SA) or REKEY. If a value is already set, the contents are replaced.

  • "mode" (OSSL_KDF_PARAM_MODE) <int>

    This parameter sets the IKEv2 KDF mode. The IKEV2KDF implementation supports three different modes of operation:

    • EVP_KDF_IKEV2_MODE_GEN

      It generates the SKEYSEED used 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 (Ni and Nr) as input and generates the SKEYSEED.

    • 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) using SKEYSEED generated 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 the SK_d as input along with new nonces.

      Finally, it derives keying material for the Child_DH, using the SK_d as input along with new nonces and new shared secret (new g^ir).

    • EVP_KDF_IKEV2_MODE_REKEY

      It derives a new SKEYSEED when rekeying the IKE SA, using the existing SK_d as input along with new nonces and new shared secret (new g^ir).

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.

EXAMPLES

Example of SEEDKEY generation

This example derives a 32-byte SEEDKEY using SHA-256 with the appropriate shared secret and nonces:

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)

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)

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)

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

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

RFC 7296 and SP800-135

SEE ALSO

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.

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.