in src/derivation/hmac_kdf.c [26:156]
CK_RV hmac_kdf_sample(CK_SESSION_HANDLE session) {
CK_RV rv;
/* CKM_SP800_108_KDF is a vendor defined mechanism in CloudHSM.
* It implements key derivation using the Counter mode construction
* specified in Section 5.1 of NIST Special Publication 800-108.
*/
/* Generate the Key Derivation Key aka the base key. This key will be
* used as an input to the derivation function, along with other input data.
*/
CK_OBJECT_HANDLE base_key;
CK_MECHANISM base_key_mech = {CKM_AES_KEY_GEN, NULL, 0};
CK_OBJECT_CLASS base_key_class = CKO_SECRET_KEY;
CK_KEY_TYPE base_key_type = CKK_AES;
CK_ULONG base_key_len = 32;
CK_ATTRIBUTE base_key_template[] = {
{CKA_CLASS, &base_key_class, sizeof(CK_OBJECT_CLASS)},
{CKA_KEY_TYPE, &base_key_type, sizeof(CK_KEY_TYPE)},
{CKA_VALUE_LEN, &base_key_len, sizeof(CKA_VALUE_LEN)},
{CKA_DERIVE, &true_val, sizeof(CK_BBOOL)}
};
rv = funcs->C_GenerateKey(session,
&base_key_mech,
base_key_template,
sizeof(base_key_template) / sizeof(CK_ATTRIBUTE),
&base_key);
if (CKR_OK != rv) {
printf("Failed to generate base key\n");
return EXIT_FAILURE;
} else {
printf("Generated base AES key of size 32 bytes. Handle: %lu\n", base_key);
}
/*
* Create a template for the derived key. Any supported secret key
* type may be derived.
*/
CK_OBJECT_HANDLE derived_key;
CK_OBJECT_CLASS derived_key_class = CKO_SECRET_KEY;
CK_KEY_TYPE derived_key_type = CKK_AES;
CK_ULONG derived_key_len = 32;
char * derived_key_label = "derived_aes_key";
CK_ATTRIBUTE derived_key_template[] = {
{CKA_CLASS, &derived_key_class, sizeof(CK_OBJECT_CLASS)},
{CKA_KEY_TYPE, &derived_key_type, sizeof(CK_KEY_TYPE)},
{CKA_VALUE_LEN, &derived_key_len, sizeof(CKA_VALUE_LEN)},
{CKA_LABEL, derived_key_label, sizeof(derived_key_label)}
};
/*
* The KDF uses a counter variable and a string of fixed data as inputs
* to a pseudo-random function.
*
* Counter || Label || 0x00 || Context || Length of derived keying material
*
* Consequently, the mechanism expects four input parameters.
*/
/*
* Input 1: Counter format
* Format of the iteration counter represented as a binary string.
* Only supported counter widths are 16 and 32
*/
CK_SP800_108_COUNTER_FORMAT counter_format;
counter_format.ulWidthInBits = 32;
/*
* Input 2: DKM format
* Format of the derived keying material. It has two fields -
*
* ulWidthInBits: Only supported DKM widths are 8, 16, 32 and 64
*
* dkmLengthMethod: Will be applicable in the future for derivation
* of multiple keys. For now, use the value below.
*/
CK_SP800_108_DKM_LENGTH_FORMAT dkm_format;
dkm_format.dkmLengthMethod = SP800_108_DKM_LENGTH_SUM_OF_KEYS;
dkm_format.ulWidthInBits = 32;
/*
* Input 3: Label
* The label is a string that identifies the purpose for the derived keying
* material. It is encoded as a binary string.
*/
CK_BYTE label[] = {0x1, 0xab, 0xe1};
/*
* Input 4: Context
* The context is a binary string containing information related to the
* derived keying material.
*/
CK_BYTE context[] = {0xc, 0x09, 0x7e, 0x7};
/* Populate the kdf parameters */
CK_PRF_DATA_PARAM kdf_data_params[] = {
{SP800_108_COUNTER_FORMAT, &counter_format, sizeof(CK_SP800_108_COUNTER_FORMAT)},
{SP800_108_DKM_FORMAT, &dkm_format, sizeof(CK_SP800_108_DKM_LENGTH_FORMAT)},
{SP800_108_PRF_LABEL, label, sizeof(label)},
{SP800_108_PRF_CONTEXT, context, sizeof(context)}
};
CK_SP800_108_KDF_PARAMS kdf_params;
kdf_params.prftype = CKM_SHA512_HMAC;
kdf_params.pDataParams = kdf_data_params;
kdf_params.ulNumberOfDataParams = 4;
/* Populate the derivation mechanism */
CK_MECHANISM derive_mech = {CKM_SP800_108_COUNTER_KDF,
&kdf_params,
sizeof(CK_SP800_108_KDF_PARAMS)};
/* Perform the derivation operation */
rv = funcs->C_DeriveKey(session,
&derive_mech,
base_key,
derived_key_template,
sizeof(derived_key_template) / sizeof(CK_ATTRIBUTE),
&derived_key);
if (CKR_OK != rv) {
printf("Failed to derive key\n");
} else {
printf("Derived AES key of size 32 bytes. Handle: %lu\n", derived_key);
}
return rv;
}