Skip to main content
C_DeriveKey computes a new key from an existing base key and a derivation mechanism. SoftHSM v2 supports Diffie-Hellman (DH), Elliptic-Curve Diffie-Hellman (ECDH), and several symmetric data-encryption-based derivations.

Function

C_DeriveKey

CK_RV C_DeriveKey(
    CK_SESSION_HANDLE    hSession,
    CK_MECHANISM_PTR     pMechanism,
    CK_OBJECT_HANDLE     hBaseKey,
    CK_ATTRIBUTE_PTR     pTemplate,
    CK_ULONG             ulCount,
    CK_OBJECT_HANDLE_PTR phKey
);
hSession
CK_SESSION_HANDLE
required
Handle of the open session.
pMechanism
CK_MECHANISM_PTR
required
Derivation mechanism and its parameters (for example, the peer’s public key for ECDH).
hBaseKey
CK_OBJECT_HANDLE
required
Handle of the key from which to derive. Must have CKA_DERIVE = CK_TRUE. For DH and ECDH this is the local private key. For symmetric derivations this is a secret key.
pTemplate
CK_ATTRIBUTE_PTR
required
Attributes for the derived key object. Must specify at least CKA_CLASS, CKA_KEY_TYPE, and the key’s usage flags.
ulCount
CK_ULONG
required
Number of attributes in pTemplate.
phKey
CK_OBJECT_HANDLE_PTR
required
Receives the handle of the derived key object.

Supported mechanisms

DH key agreement

MechanismBase keyMechanism parameter
CKM_DH_PKCS_DERIVEDH private key (CKK_DH, CKO_PRIVATE_KEY)Peer’s public value as a raw big-endian CK_BYTE[] in pParameter

ECDH key agreement

MechanismBase keyMechanism parameter
CKM_ECDH1_DERIVEEC private key (CKK_EC) or Edwards key (CKK_EC_EDWARDS)CK_ECDH1_DERIVE_PARAMS
CKM_ECDH1_DERIVE is available when SoftHSM is built with WITH_ECC (for ECDH over prime curves) or WITH_EDDSA (for ECDH over Edwards curves such as X25519/X448).

Symmetric data-encryption derivations

These mechanisms derive a new secret key from an existing symmetric key by encrypting a provided data block. The mechanism parameter structure carries the data value.
MechanismBase key type
CKM_AES_ECB_ENCRYPT_DATACKK_AES
CKM_AES_CBC_ENCRYPT_DATACKK_AES
CKM_DES3_ECB_ENCRYPT_DATACKK_DES2 or CKK_DES3
CKM_DES3_CBC_ENCRYPT_DATACKK_DES2 or CKK_DES3
CKM_DES_ECB_ENCRYPT_DATACKK_DES (not in FIPS mode)
CKM_DES_CBC_ENCRYPT_DATACKK_DES (not in FIPS mode)

Concatenation derivations

Added in SoftHSM v2.7.0 (issue #571). These mechanisms derive a generic secret key by concatenating data with the base key value.
MechanismDescription
CKM_CONCATENATE_DATA_AND_BASEPrepend data to the base key
CKM_CONCATENATE_BASE_AND_DATAAppend data to the base key
CKM_CONCATENATE_BASE_AND_KEYConcatenate two key values
When no CKA_KEY_TYPE is specified in the template for concatenation mechanisms, SoftHSM defaults to CKK_GENERIC_SECRET.

CK_ECDH1_DERIVE_PARAMS

Required for CKM_ECDH1_DERIVE.
typedef struct CK_ECDH1_DERIVE_PARAMS {
    CK_EC_KDF_TYPE kdf;            /* key derivation function */
    CK_ULONG       ulSharedDataLen;
    CK_BYTE_PTR    pSharedData;    /* optional shared info / salt */
    CK_ULONG       ulPublicDataLen;
    CK_BYTE_PTR    pPublicData;    /* peer's EC public key (DER or raw point) */
} CK_ECDH1_DERIVE_PARAMS;

KDF values

ValueMeaning
CKD_NULLNo KDF — raw shared secret is returned as key material
CKD_SHA1_KDFANSI X9.63 KDF using SHA-1
CKD_SHA224_KDFANSI X9.63 KDF using SHA-224
CKD_SHA256_KDFANSI X9.63 KDF using SHA-256
CKD_SHA384_KDFANSI X9.63 KDF using SHA-384
CKD_SHA512_KDFANSI X9.63 KDF using SHA-512

Derived key template

The pTemplate passed to C_DeriveKey controls the attributes of the derived key. Supported derived key types are:
  • CKK_GENERIC_SECRET
  • CKK_DES
  • CKK_DES2
  • CKK_DES3
  • CKK_AES
Specifying any other key type returns CKR_TEMPLATE_INCONSISTENT. Typical template for an AES-256 derived key:
CK_OBJECT_CLASS keyClass  = CKO_SECRET_KEY;
CK_KEY_TYPE     keyType   = CKK_AES;
CK_ULONG        keyLen    = 32;
CK_BBOOL        ckTrue    = CK_TRUE;
CK_BBOOL        ckFalse   = CK_FALSE;

CK_ATTRIBUTE derivedTemplate[] = {
    { CKA_CLASS,       &keyClass, sizeof(keyClass) },
    { CKA_KEY_TYPE,    &keyType,  sizeof(keyType) },
    { CKA_VALUE_LEN,   &keyLen,   sizeof(keyLen) },
    { CKA_ENCRYPT,     &ckTrue,   sizeof(ckTrue) },
    { CKA_DECRYPT,     &ckTrue,   sizeof(ckTrue) },
    { CKA_TOKEN,       &ckFalse,  sizeof(ckFalse) },
    { CKA_SENSITIVE,   &ckTrue,   sizeof(ckTrue) },
    { CKA_EXTRACTABLE, &ckFalse,  sizeof(ckFalse) },
};

Error codes

Return valueMeaning
CKR_OKSuccess
CKR_ARGUMENTS_BADA required argument is NULL_PTR
CKR_MECHANISM_INVALIDThe mechanism is not supported
CKR_KEY_FUNCTION_NOT_PERMITTEDThe base key does not have CKA_DERIVE = CK_TRUE
CKR_KEY_TYPE_INCONSISTENTBase key type does not match the mechanism
CKR_TEMPLATE_INCONSISTENTDerived key type is not supported
CKR_USER_NOT_LOGGED_INPrivate key access without login

Example: ECDH key derivation

#include <pkcs11.h>

/*
 * Derive a shared AES-256 key using ECDH1 with CKD_SHA256_KDF.
 *
 * hPrivKey: local EC private key (CKA_DERIVE = CK_TRUE)
 * peerPubKeyDer: peer's EC public key as a DER-encoded point
 * peerPubKeyLen: length of peerPubKeyDer
 */
void ecdh_derive(CK_SESSION_HANDLE hSession,
                 CK_OBJECT_HANDLE  hPrivKey,
                 CK_BYTE          *peerPubKeyDer,
                 CK_ULONG          peerPubKeyLen,
                 CK_OBJECT_HANDLE *phDerivedKey)
{
    CK_ECDH1_DERIVE_PARAMS ecdhParams = {
        CKD_SHA256_KDF,   /* kdf */
        0,                /* ulSharedDataLen */
        NULL_PTR,         /* pSharedData */
        peerPubKeyLen,
        peerPubKeyDer
    };

    CK_MECHANISM mechanism = {
        CKM_ECDH1_DERIVE,
        &ecdhParams,
        sizeof(ecdhParams)
    };

    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
    CK_KEY_TYPE     keyType  = CKK_AES;
    CK_ULONG        keyLen   = 32;
    CK_BBOOL        ckTrue   = CK_TRUE;
    CK_BBOOL        ckFalse  = CK_FALSE;

    CK_ATTRIBUTE tmpl[] = {
        { CKA_CLASS,       &keyClass, sizeof(keyClass) },
        { CKA_KEY_TYPE,    &keyType,  sizeof(keyType)  },
        { CKA_VALUE_LEN,   &keyLen,   sizeof(keyLen)   },
        { CKA_ENCRYPT,     &ckTrue,   sizeof(ckTrue)   },
        { CKA_DECRYPT,     &ckTrue,   sizeof(ckTrue)   },
        { CKA_TOKEN,       &ckFalse,  sizeof(ckFalse)  },
        { CKA_SENSITIVE,   &ckTrue,   sizeof(ckTrue)   },
        { CKA_EXTRACTABLE, &ckFalse,  sizeof(ckFalse)  },
    };

    CK_RV rv = C_DeriveKey(hSession, &mechanism, hPrivKey,
                            tmpl, 8, phDerivedKey);
    /* rv == CKR_OK on success */
}

Build docs developers (and LLMs) love