@@ -1389,4 +1389,123 @@ 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_SP80056C_KDF_iteration (const byte * z , word32 zSz ,
1394+ word32 counter , const byte * fixedInfo , word32 fixedInfoSz ,
1395+ enum wc_HashType hashType , 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_SP80056C_KDF_single (const byte * z , word32 zSz ,
1437+ const byte * fixedInfo , word32 fixedInfoSz , word32 derivedSecretSz ,
1438+ enum wc_HashType hashType , byte * output , word32 outputSz )
1439+ {
1440+ byte hashTempBuf [WC_MAX_DIGEST_SIZE ];
1441+ int ret = BAD_FUNC_ARG ;
1442+ word32 counter , outIdx ;
1443+ word32 inputSz ;
1444+ byte * hashOut ;
1445+ int hashOutSz ;
1446+ word32 reps ;
1447+
1448+ if (output == NULL || outputSz < derivedSecretSz )
1449+ return BAD_FUNC_ARG ;
1450+ if (z == NULL || zSz == 0 || (fixedInfoSz > 0 && fixedInfo == NULL ))
1451+ return BAD_FUNC_ARG ;
1452+ if (derivedSecretSz == 0 )
1453+ return BAD_FUNC_ARG ;
1454+
1455+ hashOutSz = wc_HashGetDigestSize (hashType );
1456+ if (hashOutSz == HASH_TYPE_E )
1457+ return BAD_FUNC_ARG ;
1458+
1459+ /* According to SP800_56C reps shall not be greater than 2**32-1. This is
1460+ * not possible using word32 integers. The code checks for overflow. */
1461+ reps = derivedSecretSz / hashOutSz ;
1462+ if (derivedSecretSz % hashOutSz ) {
1463+ if (reps + 1 < reps )
1464+ return BAD_FUNC_ARG ;
1465+ reps ++ ;
1466+ }
1467+
1468+ /* According to SP800_56C, table 1, the max input size (max_H_inputBits)
1469+ * depends on the HASH algo. The smaller value in the table is (2**64-1)/8.
1470+ * This is larger than the possible length using word32 integers. The code
1471+ * checks for overflow. */
1472+ inputSz = zSz ;
1473+ if (inputSz + 4 < inputSz )
1474+ return BAD_FUNC_ARG ;
1475+ inputSz += 4 ;
1476+ if (inputSz + fixedInfoSz < inputSz )
1477+ return BAD_FUNC_ARG ;
1478+
1479+ outIdx = 0 ;
1480+ for (counter = 1 ; counter <= reps ; counter ++ ) {
1481+ /* If the user provided a buffer output size bigger than the
1482+ * derivedSecretSz then the copy in hashTempBuf can be avoided.
1483+ * Nevertheless, the code conservatively does the copy anyway as the
1484+ * data is sensitive and the user may forget zeroing outputsz bytes
1485+ * instead of derivedSecretsz bytes. */
1486+ if (outIdx + hashOutSz <= derivedSecretSz ) {
1487+ hashOut = output + outIdx ;
1488+ }
1489+ else {
1490+ hashOut = hashTempBuf ;
1491+ }
1492+ ret = wc_SP80056C_KDF_iteration (z , zSz , counter ,
1493+ fixedInfo , fixedInfoSz , hashType , hashOut );
1494+ if (hashOut == hashTempBuf ) {
1495+ XMEMCPY (output + outIdx , hashTempBuf , derivedSecretSz - outIdx );
1496+ ForceZero (hashTempBuf , sizeof (hashTempBuf ));
1497+ }
1498+ if (ret != 0 )
1499+ break ;
1500+ outIdx += hashOutSz ;
1501+ }
1502+
1503+ if (ret != 0 ) {
1504+ ForceZero (output , derivedSecretSz );
1505+ }
1506+
1507+ return ret ;
1508+ }
1509+ #endif /* WC_KDF_NIST_SP_800_56C */
1510+
13921511#endif /* NO_KDF */
0 commit comments