Skip to content

Commit

Permalink
Merge pull request #7589 from rizlik/sp800_56c
Browse files Browse the repository at this point in the history
wolfcrypt: support NIST 800-56C Option 1 KDF
  • Loading branch information
SparkiDev authored May 31, 2024
2 parents fc8a509 + 1744564 commit 4b77d4c
Show file tree
Hide file tree
Showing 4 changed files with 483 additions and 0 deletions.
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

0 comments on commit 4b77d4c

Please sign in to comment.