EVP_KDF-SS(7SSL)

✨ EVP_KDF-SS β€” the Single Step / One Step EVP_KDF implementation πŸ’–

okay bestie, settle in, because this one's actually so fun once it clicks πŸŽ€ this page lives in the OpenSSL family and it's all about the EVP_KDF-SS algorithm, which is the Single Step key derivation function (aka SSKDF, say it with me). SSKDF takes input like a shared secret key (the kind you get from a key establishment scheme, iykyk) plus some fixedinfo, and from that it derives a key. People also call it Concat KDF casually β€” same thing, no cap.

And the output? That's keying material. periodt. πŸ¦‹


🌸 Auxiliary function 🌸

The implementation uses a selectable auxiliary function H, and it can be one of these iconic options:

H(x) = hash(x, digest=md)
H(x) = HMAC_hash(x, key=salt, digest=md)
H(x) = KMACxxx(x, key=salt, custom="KDF", outlen=mac_size)

Both the HMAC and KMAC implementations set the key using the 'salt' value. And the hash and HMAC versions? They also require the digest to be set. don't forget it bestie πŸ’…


⭐ Identity ⭐

"SSKDF" is the name for this implementation β€” that's the string you hand to the EVP_KDF_fetch() function. remember it, it's giving main character energy πŸ‘‘


🌈 Supported parameters 🌈

These are the supported parameters, and yes, we're doing all of them:

  • "properties" (OSSL_KDF_PARAM_PROPERTIES) <UTF8 string>
  • "digest" (OSSL_KDF_PARAM_DIGEST) <UTF8 string> β€” This parameter is ignored for KMAC. (not its moment, ig πŸ™ˆ)
  • "mac" (OSSL_KDF_PARAM_MAC) <UTF8 string>
  • "maclen" (OSSL_KDF_PARAM_MAC_SIZE) <unsigned integer>
  • "salt" (OSSL_KDF_PARAM_SALT) <octet string> β€” These parameters work as described in "PARAMETERS" in EVP_KDF(3).
  • "key" (OSSL_KDF_PARAM_KEY) <octet string> β€” This parameter sets the shared secret that is used for key derivation.
  • "secret" (OSSL_KDF_PARAM_SECRET) <octet string> β€” This parameter sets the shared secret that is used for key derivation.
  • "info" (OSSL_KDF_PARAM_INFO) <octet string> β€” This parameter sets an optional value for fixedinfo, also known as otherinfo.

🫢 what the FIPS provider also supports 🫢

The OpenSSL FIPS provider also supports the following parameters:

  • "fips-indicator" (OSSL_KDF_PARAM_FIPS_APPROVED_INDICATOR) <integer> β€” A getter that returns 1 if the operation is FIPS approved, or 0 otherwise. This may be used after calling EVP_KDF_derive. It returns 0 if "key-check" is set to 0 and the check fails.
  • "key-check" (OSSL_KDF_PARAM_FIPS_KEY_CHECK) <integer> β€” The default value of 1 causes an error during EVP_KDF_CTX_set_params() if the length of used key-derivation key (OSSL_KDF_PARAM_KEY) is shorter than 112 bits. Setting this to zero will ignore the error and set the approved "fips-indicator" to 0.
⚠️ This option breaks FIPS compliance if it causes the approved "fips-indicator" to return 0. like, fr fr, be careful πŸ’€

πŸ’… NOTES πŸ’…

A context for SSKDF can be obtained by calling:

EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf);

The output length of an SSKDF is specified via the keylen parameter to the EVP_KDF_derive(3) function. that's the vibe check right there ✨


πŸŽ€ EXAMPLES πŸŽ€

Example numero uno: this derives 10 bytes using H(x) = SHA-256, with the secret key "secret" and fixedinfo value "label":

EVP_KDF *kdf;
EVP_KDF_CTX *kctx;
unsigned char out[10];
OSSL_PARAM params[4], *p = params;

kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
EVP_KDF_free(kdf);

*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,
                                         "secret", (size_t)6);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
                                         "label", (size_t)5);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
    error("EVP_KDF_derive");
}

EVP_KDF_CTX_free(kctx);

Example two, the glow up: this derives 10 bytes using H(x) = HMAC(SHA-256), with the secret key "secret", fixedinfo value "label" and salt "salt":

EVP_KDF *kdf;
EVP_KDF_CTX *kctx;
unsigned char out[10];
OSSL_PARAM params[6], *p = params;

kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
EVP_KDF_free(kdf);

*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC,
                                        SN_hmac, strlen(SN_hmac));
*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,
                                         "secret", (size_t)6);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
                                         "label", (size_t)5);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
                                         "salt", (size_t)4);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
    error("EVP_KDF_derive");
}

EVP_KDF_CTX_free(kctx);

Example three, the finale πŸ”₯: this derives 10 bytes using H(x) = KMAC128(x,salt,outlen), with the secret key "secret" fixedinfo value "label", salt of "salt" and KMAC outlen of 20:

EVP_KDF *kdf;
EVP_KDF_CTX *kctx;
unsigned char out[10];
OSSL_PARAM params[6], *p = params;

kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
kctx = EVP_KDF_CTX_new(kdf);
EVP_KDF_free(kdf);

*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC,
                                        SN_kmac128, strlen(SN_kmac128));
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
                                         "secret", (size_t)6);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
                                         "label", (size_t)5);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
                                         "salt", (size_t)4);
*p++ = OSSL_PARAM_construct_size_t(OSSL_KDF_PARAM_MAC_SIZE, (size_t)20);
*p = OSSL_PARAM_construct_end();
if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
    error("EVP_KDF_derive");
}

EVP_KDF_CTX_free(kctx);

πŸ‘‘ CONFORMING TO πŸ‘‘

NIST SP800-56Cr1. the standard said what it said πŸ’–


πŸ¦‹ SEE ALSO πŸ¦‹

EVP_KDF(3), EVP_KDF_CTX_new(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)

go read those too bestie, they're all connected πŸ’œ


🌸 HISTORY 🌸

This functionality was added in OpenSSL 3.0. a legend from the start, no notes ✨


Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved.

Copyright (c) 2019, Oracle and/or its affiliates. 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>.


and that's the whole page, bestie!! 🫢 this was version 4.0.3, dated 2026-09-29 β€” catch you in the next manpage, mwah πŸ’…βœ¨

πŸ“¦ where this page comes from