Merge pull request #7068 from SparkiDev/srtp_kdf_label

SRTP/SRTCP KDF: add APIs that derives one key from a label
This commit is contained in:
Chris Conlon
2023-12-14 14:54:58 -07:00
committed by GitHub
4 changed files with 370 additions and 24 deletions

View File

@ -4,7 +4,7 @@
\brief This function derives keys using SRTP KDF algorithm.
\return 0 Returned upon successful key derviation.
\return 0 Returned upon successful key derivation.
\return BAD_FUNC_ARG Returned when key or salt is NULL
\return BAD_FUNC_ARG Returned when key length is not 16, 24 or 32.
\return BAD_FUNC_ARG Returned when saltSz is larger than 14.
@ -44,6 +44,8 @@
\endcode
\sa wc_SRTCP_KDF
\sa wc_SRTP_KDF_label
\sa wc_SRTCP_KDF_label
\sa wc_SRTP_KDF_kdr_to_idx
*/
int wc_SRTP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
@ -55,7 +57,7 @@ int wc_SRTP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
\brief This function derives keys using SRTCP KDF algorithm.
\return 0 Returned upon successful key derviation.
\return 0 Returned upon successful key derivation.
\return BAD_FUNC_ARG Returned when key or salt is NULL
\return BAD_FUNC_ARG Returned when key length is not 16, 24 or 32.
\return BAD_FUNC_ARG Returned when saltSz is larger than 14.
@ -95,12 +97,107 @@ int wc_SRTP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
\endcode
\sa wc_SRTP_KDF
\sa wc_SRTP_KDF_label
\sa wc_SRTCP_KDF_label
\sa wc_SRTP_KDF_kdr_to_idx
*/
int wc_SRTCP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
int kdrIdx, const byte* index, byte* key1, word32 key1Sz, byte* key2,
word32 key2Sz, byte* key3, word32 key3Sz);
/*!
\ingroup SrtpKdf
\brief This function derives a key with label using SRTP KDF algorithm.
\return 0 Returned upon successful key derivation.
\return BAD_FUNC_ARG Returned when key, salt or outKey is NULL
\return BAD_FUNC_ARG Returned when key length is not 16, 24 or 32.
\return BAD_FUNC_ARG Returned when saltSz is larger than 14.
\return BAD_FUNC_ARG Returned when kdrIdx is less than -1 or larger than 24.
\return MEMORY_E on dynamic memory allocation failure.
\param [in] key Key to use with encryption.
\param [in] keySz Size of key in bytes.
\param [in] salt Random non-secret value.
\param [in] saltSz Size of random in bytes.
\param [in] kdrIdx Key derivation rate. kdr = 0 when -1, otherwise kdr = 2^kdrIdx.
\param [in] index Index value to XOR in.
\param [in] label Label to use when deriving key.
\param [out] outKey Derived key.
\param [in] outKeySz Size of derived key in bytes.
_Example_
\code
unsigned char key[16] = { ... };
unsigned char salt[14] = { ... };
unsigned char index[6] = { ... };
unsigned char keyE[16];
int kdrIdx = 0; // Use all of index
int ret;
ret = wc_SRTP_KDF_label(key, sizeof(key), salt, sizeof(salt), kdrIdx, index,
WC_SRTP_LABEL_ENCRYPTION, keyE, sizeof(keyE));
if (ret != 0) {
WOLFSSL_MSG("wc_SRTP_KDF failed");
}
\endcode
\sa wc_SRTP_KDF
\sa wc_SRTCP_KDF
\sa wc_SRTCP_KDF_label
\sa wc_SRTP_KDF_kdr_to_idx
*/
int wc_SRTP_KDF_label(const byte* key, word32 keySz, const byte* salt,
word32 saltSz, int kdrIdx, const byte* index, byte label, byte* outKey,
word32 outKeySz);
/*!
\ingroup SrtpKdf
\brief This function derives key with label using SRTCP KDF algorithm.
\return 0 Returned upon successful key derivation.
\return BAD_FUNC_ARG Returned when key, salt or outKey is NULL
\return BAD_FUNC_ARG Returned when key length is not 16, 24 or 32.
\return BAD_FUNC_ARG Returned when saltSz is larger than 14.
\return BAD_FUNC_ARG Returned when kdrIdx is less than -1 or larger than 24.
\return MEMORY_E on dynamic memory allocation failure.
\param [in] key Key to use with encryption.
\param [in] keySz Size of key in bytes.
\param [in] salt Random non-secret value.
\param [in] saltSz Size of random in bytes.
\param [in] kdrIdx Key derivation rate. kdr = 0 when -1, otherwise kdr = 2^kdrIdx.
\param [in] index Index value to XOR in.
\param [in] label Label to use when deriving key.
\param [out] outKey Derived key.
\param [in] outKeySz Size of derived key in bytes.
_Example_
\code
unsigned char key[16] = { ... };
unsigned char salt[14] = { ... };
unsigned char index[4] = { ... };
unsigned char keyE[16];
int kdrIdx = 0; // Use all of index
int ret;
ret = wc_SRTCP_KDF_label(key, sizeof(key), salt, sizeof(salt), kdrIdx,
index, WC_SRTCP_LABEL_ENCRYPTION, keyE, sizeof(keyE));
if (ret != 0) {
WOLFSSL_MSG("wc_SRTP_KDF failed");
}
\endcode
\sa wc_SRTP_KDF
\sa wc_SRTCP_KDF
\sa wc_SRTP_KDF_label
\sa wc_SRTP_KDF_kdr_to_idx
*/
int wc_SRTP_KDF_label(const byte* key, word32 keySz, const byte* salt,
word32 saltSz, int kdrIdx, const byte* index, byte label, byte* outKey,
word32 outKeySz);
/*!
\ingroup SrtpKdf
@ -121,6 +218,8 @@ int wc_SRTCP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
\sa wc_SRTP_KDF
\sa wc_SRTCP_KDF
\sa wc_SRTP_KDF_label
\sa wc_SRTCP_KDF_label
*/
int wc_SRTP_KDF_kdr_to_idx(word32 kdr);

View File

@ -890,8 +890,9 @@ static void wc_srtp_kdf_first_block(const byte* salt, word32 saltSz, int kdrIdx,
word32 i;
/* XOR salt into zeroized buffer. */
for (i = 0; i < WC_SRTP_MAX_SALT - saltSz; i++)
for (i = 0; i < WC_SRTP_MAX_SALT - saltSz; i++) {
block[i] = 0;
}
XMEMCPY(block + WC_SRTP_MAX_SALT - saltSz, salt, saltSz);
block[WC_SRTP_MAX_SALT] = 0;
/* block[15] is counter. */
@ -905,8 +906,9 @@ static void wc_srtp_kdf_first_block(const byte* salt, word32 saltSz, int kdrIdx,
if ((kdrIdx & 0x7) == 0) {
/* Just XOR in as no bit shifting. */
for (i = 0; i < indexSz; i++)
for (i = 0; i < indexSz; i++) {
block[i + WC_SRTP_MAX_SALT - indexSz] ^= index[i];
}
}
else {
/* XOR in as bit shifted index. */
@ -1025,26 +1027,33 @@ int wc_SRTP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
}
/* Setup AES object. */
if (ret == 0)
if (ret == 0) {
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
if (ret == 0)
}
if (ret == 0) {
ret = wc_AesSetKey(aes, key, keySz, NULL, AES_ENCRYPTION);
}
/* Calculate first block that can be used in each derivation. */
if (ret == 0)
wc_srtp_kdf_first_block(salt, saltSz, kdrIdx, index, 6, block);
if (ret == 0) {
wc_srtp_kdf_first_block(salt, saltSz, kdrIdx, index, WC_SRTP_INDEX_LEN,
block);
}
/* Calculate first key if required. */
if ((ret == 0) && (key1 != NULL)) {
ret = wc_srtp_kdf_derive_key(block, 6, 0x00, key1, key1Sz, aes);
ret = wc_srtp_kdf_derive_key(block, WC_SRTP_INDEX_LEN,
WC_SRTP_LABEL_ENCRYPTION, key1, key1Sz, aes);
}
/* Calculate second key if required. */
if ((ret == 0) && (key2 != NULL)) {
ret = wc_srtp_kdf_derive_key(block, 6, 0x01, key2, key2Sz, aes);
ret = wc_srtp_kdf_derive_key(block, WC_SRTP_INDEX_LEN,
WC_SRTP_LABEL_MSG_AUTH, key2, key2Sz, aes);
}
/* Calculate third key if required. */
if ((ret == 0) && (key3 != NULL)) {
ret = wc_srtp_kdf_derive_key(block, 6, 0x02, key3, key3Sz, aes);
ret = wc_srtp_kdf_derive_key(block, WC_SRTP_INDEX_LEN,
WC_SRTP_LABEL_SALT, key3, key3Sz, aes);
}
/* AES object memset so can always free. */
@ -1111,26 +1120,33 @@ int wc_SRTCP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
}
/* Setup AES object. */
if (ret == 0)
if (ret == 0) {
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
if (ret == 0)
}
if (ret == 0) {
ret = wc_AesSetKey(aes, key, keySz, NULL, AES_ENCRYPTION);
}
/* Calculate first block that can be used in each derivation. */
if (ret == 0)
wc_srtp_kdf_first_block(salt, saltSz, kdrIdx, index, 4, block);
if (ret == 0) {
wc_srtp_kdf_first_block(salt, saltSz, kdrIdx, index, WC_SRTCP_INDEX_LEN,
block);
}
/* Calculate first key if required. */
if ((ret == 0) && (key1 != NULL)) {
ret = wc_srtp_kdf_derive_key(block, 4, 0x03, key1, key1Sz, aes);
ret = wc_srtp_kdf_derive_key(block, WC_SRTCP_INDEX_LEN,
WC_SRTCP_LABEL_ENCRYPTION, key1, key1Sz, aes);
}
/* Calculate second key if required. */
if ((ret == 0) && (key2 != NULL)) {
ret = wc_srtp_kdf_derive_key(block, 4, 0x04, key2, key2Sz, aes);
ret = wc_srtp_kdf_derive_key(block, WC_SRTCP_INDEX_LEN,
WC_SRTCP_LABEL_MSG_AUTH, key2, key2Sz, aes);
}
/* Calculate third key if required. */
if ((ret == 0) && (key3 != NULL)) {
ret = wc_srtp_kdf_derive_key(block, 4, 0x05, key3, key3Sz, aes);
ret = wc_srtp_kdf_derive_key(block, WC_SRTCP_INDEX_LEN,
WC_SRTCP_LABEL_SALT, key3, key3Sz, aes);
}
/* AES object memset so can always free. */
@ -1141,6 +1157,168 @@ int wc_SRTCP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
return ret;
}
/* Derive key with label using SRTP KDF algorithm.
*
* SP 800-135 (RFC 3711).
*
* @param [in] key Key to use with encryption.
* @param [in] keySz Size of key in bytes.
* @param [in] salt Random non-secret value.
* @param [in] saltSz Size of random in bytes.
* @param [in] kdrIdx Key derivation rate index. kdr = 0 when -1, otherwise
* kdr = 2^kdrIdx. See wc_SRTP_KDF_kdr_to_idx()
* @param [in] index Index value to XOR in.
* @param [in] label Label to use when deriving key.
* @param [out] outKey Derived key.
* @param [in] outKeySz Size of derived key in bytes.
* @return BAD_FUNC_ARG when key, salt or outKey is NULL.
* @return BAD_FUNC_ARG when key length is not 16, 24 or 32.
* @return BAD_FUNC_ARG when saltSz is larger than 14.
* @return BAD_FUNC_ARG when kdrIdx is less than -1 or larger than 24.
* @return MEMORY_E on dynamic memory allocation failure.
* @return 0 on success.
*/
int wc_SRTP_KDF_label(const byte* key, word32 keySz, const byte* salt,
word32 saltSz, int kdrIdx, const byte* index, byte label, byte* outKey,
word32 outKeySz)
{
int ret = 0;
byte block[AES_BLOCK_SIZE];
#ifdef WOLFSSL_SMALL_STACK
Aes* aes = NULL;
#else
Aes aes[1];
#endif
/* Validate parameters. */
if ((key == NULL) || (keySz > AES_256_KEY_SIZE) || (salt == NULL) ||
(saltSz > WC_SRTP_MAX_SALT) || (kdrIdx < -1) || (kdrIdx > 24) ||
(outKey == NULL)) {
ret = BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret == 0) {
aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_CIPHER);
if (aes == NULL) {
ret = MEMORY_E;
}
}
if (aes != NULL)
#endif
{
XMEMSET(aes, 0, sizeof(Aes));
}
/* Setup AES object. */
if (ret == 0) {
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
}
if (ret == 0) {
ret = wc_AesSetKey(aes, key, keySz, NULL, AES_ENCRYPTION);
}
/* Calculate first block that can be used in each derivation. */
if (ret == 0) {
wc_srtp_kdf_first_block(salt, saltSz, kdrIdx, index, WC_SRTP_INDEX_LEN,
block);
}
if (ret == 0) {
/* Calculate key. */
ret = wc_srtp_kdf_derive_key(block, WC_SRTP_INDEX_LEN, label, outKey,
outKeySz, aes);
}
/* AES object memset so can always free. */
wc_AesFree(aes);
#ifdef WOLFSSL_SMALL_STACK
XFREE(aes, NULL, DYNAMIC_TYPE_CIPHER);
#endif
return ret;
}
/* Derive key with label using SRTCP KDF algorithm.
*
* SP 800-135 (RFC 3711).
*
* @param [in] key Key to use with encryption.
* @param [in] keySz Size of key in bytes.
* @param [in] salt Random non-secret value.
* @param [in] saltSz Size of random in bytes.
* @param [in] kdrIdx Key derivation rate index. kdr = 0 when -1, otherwise
* kdr = 2^kdrIdx. See wc_SRTP_KDF_kdr_to_idx()
* @param [in] index Index value to XOR in.
* @param [in] label Label to use when deriving key.
* @param [out] outKey Derived key.
* @param [in] outKeySz Size of derived key in bytes.
* @return BAD_FUNC_ARG when key, salt or outKey is NULL.
* @return BAD_FUNC_ARG when key length is not 16, 24 or 32.
* @return BAD_FUNC_ARG when saltSz is larger than 14.
* @return BAD_FUNC_ARG when kdrIdx is less than -1 or larger than 24.
* @return MEMORY_E on dynamic memory allocation failure.
* @return 0 on success.
*/
int wc_SRTCP_KDF_label(const byte* key, word32 keySz, const byte* salt,
word32 saltSz, int kdrIdx, const byte* index, byte label, byte* outKey,
word32 outKeySz)
{
int ret = 0;
byte block[AES_BLOCK_SIZE];
#ifdef WOLFSSL_SMALL_STACK
Aes* aes = NULL;
#else
Aes aes[1];
#endif
/* Validate parameters. */
if ((key == NULL) || (keySz > AES_256_KEY_SIZE) || (salt == NULL) ||
(saltSz > WC_SRTP_MAX_SALT) || (kdrIdx < -1) || (kdrIdx > 24) ||
(outKey == NULL)) {
ret = BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
if (ret == 0) {
aes = (Aes*)XMALLOC(sizeof(Aes), NULL, DYNAMIC_TYPE_CIPHER);
if (aes == NULL) {
ret = MEMORY_E;
}
}
if (aes != NULL)
#endif
{
XMEMSET(aes, 0, sizeof(Aes));
}
/* Setup AES object. */
if (ret == 0) {
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
}
if (ret == 0) {
ret = wc_AesSetKey(aes, key, keySz, NULL, AES_ENCRYPTION);
}
/* Calculate first block that can be used in each derivation. */
if (ret == 0) {
wc_srtp_kdf_first_block(salt, saltSz, kdrIdx, index, WC_SRTCP_INDEX_LEN,
block);
}
if (ret == 0) {
/* Calculate key. */
ret = wc_srtp_kdf_derive_key(block, WC_SRTCP_INDEX_LEN, label, outKey,
outKeySz, aes);
}
/* AES object memset so can always free. */
wc_AesFree(aes);
#ifdef WOLFSSL_SMALL_STACK
XFREE(aes, NULL, DYNAMIC_TYPE_CIPHER);
#endif
return ret;
}
/* Converts a kdr value to an index to use in SRTP/SRTCP KDF API.
*
* @param [in] kdr Key derivation rate to convert.

View File

@ -25617,11 +25617,35 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srtpkdf_test(void)
keyS, tv[i].ksSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyE, tv[i].ke, 16) != 0)
if (XMEMCMP(keyE, tv[i].ke, tv[i].keSz) != 0)
return WC_TEST_RET_ENC_NC;
if (XMEMCMP(keyA, tv[i].ka, 20) != 0)
if (XMEMCMP(keyA, tv[i].ka, tv[i].kaSz) != 0)
return WC_TEST_RET_ENC_NC;
if (XMEMCMP(keyS, tv[i].ks, 14) != 0)
if (XMEMCMP(keyS, tv[i].ks, tv[i].ksSz) != 0)
return WC_TEST_RET_ENC_NC;
ret = wc_SRTP_KDF_label(tv[i].key, tv[i].keySz, tv[i].salt,
tv[i].saltSz, tv[i].kdfIdx, tv[i].index, WC_SRTP_LABEL_ENCRYPTION,
keyE, tv[i].keSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyE, tv[i].ke, tv[i].keSz) != 0)
return WC_TEST_RET_ENC_NC;
ret = wc_SRTP_KDF_label(tv[i].key, tv[i].keySz, tv[i].salt,
tv[i].saltSz, tv[i].kdfIdx, tv[i].index, WC_SRTP_LABEL_MSG_AUTH,
keyA, tv[i].kaSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyA, tv[i].ka, tv[i].kaSz) != 0)
return WC_TEST_RET_ENC_NC;
ret = wc_SRTP_KDF_label(tv[i].key, tv[i].keySz, tv[i].salt,
tv[i].saltSz, tv[i].kdfIdx, tv[i].index, WC_SRTP_LABEL_SALT, keyS,
tv[i].ksSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyS, tv[i].ks, tv[i].ksSz) != 0)
return WC_TEST_RET_ENC_NC;
ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz,
@ -25629,11 +25653,35 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srtpkdf_test(void)
keyS, tv[i].ksSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyE, tv[i].ke_c, 16) != 0)
if (XMEMCMP(keyE, tv[i].ke_c, tv[i].keSz) != 0)
return WC_TEST_RET_ENC_NC;
if (XMEMCMP(keyA, tv[i].ka_c, 20) != 0)
if (XMEMCMP(keyA, tv[i].ka_c, tv[i].kaSz) != 0)
return WC_TEST_RET_ENC_NC;
if (XMEMCMP(keyS, tv[i].ks_c, 14) != 0)
if (XMEMCMP(keyS, tv[i].ks_c, tv[i].ksSz) != 0)
return WC_TEST_RET_ENC_NC;
ret = wc_SRTCP_KDF_label(tv[i].key, tv[i].keySz, tv[i].salt,
tv[i].saltSz, tv[i].kdfIdx, tv[i].index_c,
WC_SRTCP_LABEL_ENCRYPTION, keyE, tv[i].keSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyE, tv[i].ke_c, tv[i].keSz) != 0)
return WC_TEST_RET_ENC_NC;
ret = wc_SRTCP_KDF_label(tv[i].key, tv[i].keySz, tv[i].salt,
tv[i].saltSz, tv[i].kdfIdx, tv[i].index_c, WC_SRTCP_LABEL_MSG_AUTH,
keyA, tv[i].kaSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyA, tv[i].ka_c, tv[i].kaSz) != 0)
return WC_TEST_RET_ENC_NC;
ret = wc_SRTCP_KDF_label(tv[i].key, tv[i].keySz, tv[i].salt,
tv[i].saltSz, tv[i].kdfIdx, tv[i].index_c, WC_SRTCP_LABEL_SALT,
keyS, tv[i].kaSz);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(keyS, tv[i].ks_c, tv[i].ksSz) != 0)
return WC_TEST_RET_ENC_NC;
}

View File

@ -106,6 +106,21 @@ WOLFSSL_API int wc_SSH_KDF(byte hashId, byte keyId,
#endif /* WOLFSSL_WOLFSSH */
#ifdef WC_SRTP_KDF
/* Label values for purpose. */
#define WC_SRTP_LABEL_ENCRYPTION 0x00
#define WC_SRTP_LABEL_MSG_AUTH 0x01
#define WC_SRTP_LABEL_SALT 0x02
#define WC_SRTCP_LABEL_ENCRYPTION 0x03
#define WC_SRTCP_LABEL_MSG_AUTH 0x04
#define WC_SRTCP_LABEL_SALT 0x05
#define WC_SRTP_LABEL_HDR_ENCRYPTION 0x06
#define WC_SRTP_LABEL_HDR_SALT 0x07
/* Length of index for SRTP KDF. */
#define WC_SRTP_INDEX_LEN 6
/* Length of index for SRTCP KDF. */
#define WC_SRTCP_INDEX_LEN 4
/* Maximum length of salt that can be used with SRTP/SRTCP. */
#define WC_SRTP_MAX_SALT 14
@ -115,6 +130,12 @@ WOLFSSL_API int wc_SRTP_KDF(const byte* key, word32 keySz, const byte* salt,
WOLFSSL_API int wc_SRTCP_KDF(const byte* key, word32 keySz, const byte* salt,
word32 saltSz, int kdrIdx, const byte* index, byte* key1, word32 key1Sz,
byte* key2, word32 key2Sz, byte* key3, word32 key3Sz);
WOLFSSL_API int wc_SRTP_KDF_label(const byte* key, word32 keySz,
const byte* salt, word32 saltSz, int kdrIdx, const byte* index, byte label,
byte* outKey, word32 outKeySz);
WOLFSSL_API int wc_SRTCP_KDF_label(const byte* key, word32 keySz,
const byte* salt, word32 saltSz, int kdrIdx, const byte* index, byte label,
byte* outKey, word32 outKeySz);
WOLFSSL_API int wc_SRTP_KDF_kdr_to_idx(word32 kdr);