Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wolfcrypt: support NIST 800-56C Option 1 KDF #7589

Merged
merged 3 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions doc/dox_comments/header_files/kdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,39 @@ int wc_SRTP_KDF_label(const byte* key, word32 keySz, const byte* salt,
*/
int wc_SRTP_KDF_kdr_to_idx(word32 kdr);

/**
* \brief Performs the single-step key derivation function (KDF) as specified in
* SP800-56C option 1.
*
* \param [in] z The input keying material.
* \param [in] zSz The size of the input keying material.
* \param [in] fixedInfo The fixed information to be included in the KDF.
* \param [in] fixedInfoSz The size of the fixed information.
* \param [in] derivedSecretSz The desired size of the derived secret.
* \param [in] hashType The hash algorithm to be used in the KDF.
* \param [out] output The buffer to store the derived secret.
* \param [in] outputSz The size of the output buffer.
*

* \return 0 if the KDF operation is successful,
* \return BAD_FUNC_ARG if the input parameters are invalid.
* \return negative error code if the KDF operation fails.
*
* _Example_
\code
unsigned char z[32] = { ... };
unsigned char fixedInfo[16] = { ... };
unsigned char output[32];
int ret;

ret = wc_KDA_KDF_onestep(z, sizeof(z), fixedInfo, sizeof(fixedInfo),
sizeof(output), WC_HASH_TYPE_SHA256, output, sizeof(output));
if (ret != 0) {
WOLFSSL_MSG("wc_KDA_KDF_onestep failed");
}
\endcode
*/
int wc_KDA_KDF_onestep(const byte* z, word32 zSz,
const byte* fixedInfo, word32 fixedInfoSz, word32 derivedSecretSz,
enum wc_HashType hashType, byte* output, word32 outputSz);

100 changes: 100 additions & 0 deletions wolfcrypt/src/kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1389,4 +1389,104 @@ int wc_SRTP_KDF_kdr_to_idx(word32 kdr)
}
#endif /* WC_SRTP_KDF */

#ifdef WC_KDF_NIST_SP_800_56C
static int wc_KDA_KDF_iteration(const byte* z, word32 zSz, word32 counter,
const byte* fixedInfo, word32 fixedInfoSz, enum wc_HashType hashType,
byte* output)
{
byte counterBuf[4];
wc_HashAlg hash;
int ret;

ret = wc_HashInit(&hash, hashType);
if (ret != 0)
return ret;
c32toa(counter, counterBuf);
ret = wc_HashUpdate(&hash, hashType, counterBuf, 4);
if (ret == 0) {
ret = wc_HashUpdate(&hash, hashType, z, zSz);
}
if (ret == 0 && fixedInfoSz > 0) {
ret = wc_HashUpdate(&hash, hashType, fixedInfo, fixedInfoSz);
}
if (ret == 0) {
ret = wc_HashFinal(&hash, hashType, output);
}
wc_HashFree(&hash, hashType);
return ret;
}

/**
* \brief Performs the single-step key derivation function (KDF) as specified in
* SP800-56C option 1.
*
* \param [in] z The input keying material.
* \param [in] zSz The size of the input keying material.
* \param [in] fixedInfo The fixed information to be included in the KDF.
* \param [in] fixedInfoSz The size of the fixed information.
* \param [in] derivedSecretSz The desired size of the derived secret.
* \param [in] hashType The hash algorithm to be used in the KDF.
* \param [out] output The buffer to store the derived secret.
* \param [in] outputSz The size of the output buffer.
*
* \return 0 if the KDF operation is successful.
* \return BAD_FUNC_ARG if the input parameters are invalid.
* \return negative error code if the KDF operation fails.
*/
int wc_KDA_KDF_onestep(const byte* z, word32 zSz, const byte* fixedInfo,
word32 fixedInfoSz, word32 derivedSecretSz, enum wc_HashType hashType,
byte* output, word32 outputSz)
{
byte hashTempBuf[WC_MAX_DIGEST_SIZE];
word32 counter, outIdx;
int hashOutSz;
int ret;

if (output == NULL || outputSz < derivedSecretSz)
return BAD_FUNC_ARG;
if (z == NULL || zSz == 0 || (fixedInfoSz > 0 && fixedInfo == NULL))
return BAD_FUNC_ARG;
if (derivedSecretSz == 0)
return BAD_FUNC_ARG;

hashOutSz = wc_HashGetDigestSize(hashType);
if (hashOutSz == HASH_TYPE_E)
return BAD_FUNC_ARG;

/* According to SP800_56C, table 1, the max input size (max_H_inputBits)
* depends on the HASH algo. The smaller value in the table is (2**64-1)/8.
* This is larger than the possible length using word32 integers. */

counter = 1;
outIdx = 0;
ret = 0;

/* According to SP800_56C the number of iterations shall not be greater than
* 2**32-1. This is not possible using word32 integers.*/
while (outIdx + hashOutSz <= derivedSecretSz) {
ret = wc_KDA_KDF_iteration(z, zSz, counter, fixedInfo, fixedInfoSz,
hashType, output + outIdx);
if (ret != 0)
break;
counter++;
outIdx += hashOutSz;
}

if (ret == 0 && outIdx < derivedSecretSz) {
ret = wc_KDA_KDF_iteration(z, zSz, counter, fixedInfo, fixedInfoSz,
hashType, hashTempBuf);
if (ret == 0) {
XMEMCPY(output + outIdx, hashTempBuf, derivedSecretSz - outIdx);
}
ForceZero(hashTempBuf, hashOutSz);
}

if (ret != 0) {
ForceZero(output, derivedSecretSz);
}

return ret;
}
#endif /* WC_KDF_NIST_SP_800_56C */

#endif /* NO_KDF */
Loading