Skip to content

Commit 4b77d4c

Browse files
authored
Merge pull request #7589 from rizlik/sp800_56c
wolfcrypt: support NIST 800-56C Option 1 KDF
2 parents fc8a509 + 1744564 commit 4b77d4c

4 files changed

Lines changed: 483 additions & 0 deletions

File tree

doc/dox_comments/header_files/kdf.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,39 @@ int wc_SRTP_KDF_label(const byte* key, word32 keySz, const byte* salt,
223223
*/
224224
int wc_SRTP_KDF_kdr_to_idx(word32 kdr);
225225

226+
/**
227+
* \brief Performs the single-step key derivation function (KDF) as specified in
228+
* SP800-56C option 1.
229+
*
230+
* \param [in] z The input keying material.
231+
* \param [in] zSz The size of the input keying material.
232+
* \param [in] fixedInfo The fixed information to be included in the KDF.
233+
* \param [in] fixedInfoSz The size of the fixed information.
234+
* \param [in] derivedSecretSz The desired size of the derived secret.
235+
* \param [in] hashType The hash algorithm to be used in the KDF.
236+
* \param [out] output The buffer to store the derived secret.
237+
* \param [in] outputSz The size of the output buffer.
238+
*
239+
240+
* \return 0 if the KDF operation is successful,
241+
* \return BAD_FUNC_ARG if the input parameters are invalid.
242+
* \return negative error code if the KDF operation fails.
243+
*
244+
* _Example_
245+
\code
246+
unsigned char z[32] = { ... };
247+
unsigned char fixedInfo[16] = { ... };
248+
unsigned char output[32];
249+
int ret;
250+
251+
ret = wc_KDA_KDF_onestep(z, sizeof(z), fixedInfo, sizeof(fixedInfo),
252+
sizeof(output), WC_HASH_TYPE_SHA256, output, sizeof(output));
253+
if (ret != 0) {
254+
WOLFSSL_MSG("wc_KDA_KDF_onestep failed");
255+
}
256+
\endcode
257+
*/
258+
int wc_KDA_KDF_onestep(const byte* z, word32 zSz,
259+
const byte* fixedInfo, word32 fixedInfoSz, word32 derivedSecretSz,
260+
enum wc_HashType hashType, byte* output, word32 outputSz);
261+

wolfcrypt/src/kdf.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,4 +1389,104 @@ int wc_SRTP_KDF_kdr_to_idx(word32 kdr)
13891389
}
13901390
#endif /* WC_SRTP_KDF */
13911391

1392+
#ifdef WC_KDF_NIST_SP_800_56C
1393+
static int wc_KDA_KDF_iteration(const byte* z, word32 zSz, word32 counter,
1394+
const byte* fixedInfo, word32 fixedInfoSz, enum wc_HashType hashType,
1395+
byte* output)
1396+
{
1397+
byte counterBuf[4];
1398+
wc_HashAlg hash;
1399+
int ret;
1400+
1401+
ret = wc_HashInit(&hash, hashType);
1402+
if (ret != 0)
1403+
return ret;
1404+
c32toa(counter, counterBuf);
1405+
ret = wc_HashUpdate(&hash, hashType, counterBuf, 4);
1406+
if (ret == 0) {
1407+
ret = wc_HashUpdate(&hash, hashType, z, zSz);
1408+
}
1409+
if (ret == 0 && fixedInfoSz > 0) {
1410+
ret = wc_HashUpdate(&hash, hashType, fixedInfo, fixedInfoSz);
1411+
}
1412+
if (ret == 0) {
1413+
ret = wc_HashFinal(&hash, hashType, output);
1414+
}
1415+
wc_HashFree(&hash, hashType);
1416+
return ret;
1417+
}
1418+
1419+
/**
1420+
* \brief Performs the single-step key derivation function (KDF) as specified in
1421+
* SP800-56C option 1.
1422+
*
1423+
* \param [in] z The input keying material.
1424+
* \param [in] zSz The size of the input keying material.
1425+
* \param [in] fixedInfo The fixed information to be included in the KDF.
1426+
* \param [in] fixedInfoSz The size of the fixed information.
1427+
* \param [in] derivedSecretSz The desired size of the derived secret.
1428+
* \param [in] hashType The hash algorithm to be used in the KDF.
1429+
* \param [out] output The buffer to store the derived secret.
1430+
* \param [in] outputSz The size of the output buffer.
1431+
*
1432+
* \return 0 if the KDF operation is successful.
1433+
* \return BAD_FUNC_ARG if the input parameters are invalid.
1434+
* \return negative error code if the KDF operation fails.
1435+
*/
1436+
int wc_KDA_KDF_onestep(const byte* z, word32 zSz, const byte* fixedInfo,
1437+
word32 fixedInfoSz, word32 derivedSecretSz, enum wc_HashType hashType,
1438+
byte* output, word32 outputSz)
1439+
{
1440+
byte hashTempBuf[WC_MAX_DIGEST_SIZE];
1441+
word32 counter, outIdx;
1442+
int hashOutSz;
1443+
int ret;
1444+
1445+
if (output == NULL || outputSz < derivedSecretSz)
1446+
return BAD_FUNC_ARG;
1447+
if (z == NULL || zSz == 0 || (fixedInfoSz > 0 && fixedInfo == NULL))
1448+
return BAD_FUNC_ARG;
1449+
if (derivedSecretSz == 0)
1450+
return BAD_FUNC_ARG;
1451+
1452+
hashOutSz = wc_HashGetDigestSize(hashType);
1453+
if (hashOutSz == HASH_TYPE_E)
1454+
return BAD_FUNC_ARG;
1455+
1456+
/* According to SP800_56C, table 1, the max input size (max_H_inputBits)
1457+
* depends on the HASH algo. The smaller value in the table is (2**64-1)/8.
1458+
* This is larger than the possible length using word32 integers. */
1459+
1460+
counter = 1;
1461+
outIdx = 0;
1462+
ret = 0;
1463+
1464+
/* According to SP800_56C the number of iterations shall not be greater than
1465+
* 2**32-1. This is not possible using word32 integers.*/
1466+
while (outIdx + hashOutSz <= derivedSecretSz) {
1467+
ret = wc_KDA_KDF_iteration(z, zSz, counter, fixedInfo, fixedInfoSz,
1468+
hashType, output + outIdx);
1469+
if (ret != 0)
1470+
break;
1471+
counter++;
1472+
outIdx += hashOutSz;
1473+
}
1474+
1475+
if (ret == 0 && outIdx < derivedSecretSz) {
1476+
ret = wc_KDA_KDF_iteration(z, zSz, counter, fixedInfo, fixedInfoSz,
1477+
hashType, hashTempBuf);
1478+
if (ret == 0) {
1479+
XMEMCPY(output + outIdx, hashTempBuf, derivedSecretSz - outIdx);
1480+
}
1481+
ForceZero(hashTempBuf, hashOutSz);
1482+
}
1483+
1484+
if (ret != 0) {
1485+
ForceZero(output, derivedSecretSz);
1486+
}
1487+
1488+
return ret;
1489+
}
1490+
#endif /* WC_KDF_NIST_SP_800_56C */
1491+
13921492
#endif /* NO_KDF */

0 commit comments

Comments
 (0)