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

SRTP/SRTCP KDF: add APIs that derives one key from a label #7068

Merged
merged 2 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
99 changes: 99 additions & 0 deletions doc/dox_comments/header_files/kdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 derviation.
\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 derviation.
cconlon marked this conversation as resolved.
Show resolved Hide resolved
\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

Expand All @@ -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);

210 changes: 194 additions & 16 deletions wolfcrypt/src/kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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. */
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -1111,26 +1120,113 @@ 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. */
wc_AesFree(aes);
#ifdef WOLFSSL_SMALL_STACK
XFREE(aes, NULL, DYNAMIC_TYPE_CIPHER);
#endif
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. */
Expand All @@ -1139,6 +1235,88 @@ int wc_SRTCP_KDF(const byte* key, word32 keySz, const byte* salt, word32 saltSz,
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.
Expand Down
Loading