From 8c3e1dbf48b52bae8374c8f0983d92368ec55af4 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 19 Oct 2023 11:29:59 +1000 Subject: [PATCH] SRTP/SRTCP KDF: add implementation Add implementation of SRTP KDF and SRTCP KDF. One shot APIs compatible with SP 800-135 and ACVP testing. Tests added to test.c. Benchmarking added. Doxygen added. --- configure.ac | 17 + .../header_files/doxygen_groups.h | 1 + doc/dox_comments/header_files/doxygen_pages.h | 1 + doc/dox_comments/header_files/kdf.h | 126 ++++++ wolfcrypt/benchmark/benchmark.c | 104 ++++- wolfcrypt/benchmark/benchmark.h | 1 + wolfcrypt/src/kdf.c | 291 +++++++++++++ wolfcrypt/test/test.c | 400 ++++++++++++++++++ wolfssl/wolfcrypt/kdf.h | 15 + 9 files changed, 951 insertions(+), 5 deletions(-) create mode 100644 doc/dox_comments/header_files/kdf.h diff --git a/configure.ac b/configure.ac index cf493397d..222b055f5 100644 --- a/configure.ac +++ b/configure.ac @@ -3547,6 +3547,22 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_X963_KDF" fi +# SRTP-KDF +AC_ARG_ENABLE([srtp-kdf], + [AS_HELP_STRING([--enable-srtp-kdf],[Enable SRTP-KDF support (default: disabled)])], + [ ENABLED_SRTP_KDF=$enableval ], + [ ENABLED_SRTP_KDF=no ] + ) +if test "$ENABLED_SRTP" = "yes" +then + ENABLED_SRTP_KDF="yes" +fi +if test "$ENABLED_SRTP_KDF" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWC_SRTP_KDF -DHAVE_AES_ECB -DWOLFSSL_AES_DIRECT" +fi + + # DSA AC_ARG_ENABLE([dsa], [AS_HELP_STRING([--enable-dsa],[Enable DSA (default: disabled)])], @@ -9579,6 +9595,7 @@ echo " * wolfCrypt Only: $ENABLED_CRYPTONLY" echo " * HKDF: $ENABLED_HKDF" echo " * HPKE: $ENABLED_HPKE" echo " * X9.63 KDF: $ENABLED_X963KDF" +echo " * SRTP-KDF: $ENABLED_SRTP_KDF" echo " * PSK: $ENABLED_PSK" echo " * Poly1305: $ENABLED_POLY1305" echo " * LEANPSK: $ENABLED_LEANPSK" diff --git a/doc/dox_comments/header_files/doxygen_groups.h b/doc/dox_comments/header_files/doxygen_groups.h index 03ad196d3..709d462b1 100644 --- a/doc/dox_comments/header_files/doxygen_groups.h +++ b/doc/dox_comments/header_files/doxygen_groups.h @@ -206,6 +206,7 @@ \defgroup RSA Algorithms - RSA \defgroup SHA Algorithms - SHA 128/224/256/384/512 \defgroup SipHash Algorithm - SipHash + \defgroup SrtpKdf Algorithm - SRTP KDF \defgroup SRP Algorithms - SRP \defgroup ASN ASN.1 diff --git a/doc/dox_comments/header_files/doxygen_pages.h b/doc/dox_comments/header_files/doxygen_pages.h index 56b9025e0..2765449ac 100644 --- a/doc/dox_comments/header_files/doxygen_pages.h +++ b/doc/dox_comments/header_files/doxygen_pages.h @@ -57,6 +57,7 @@
  • \ref RSA
  • \ref SHA
  • \ref SipHash
  • +
  • \ref SrtpKdf
  • \ref SRP
  • */ diff --git a/doc/dox_comments/header_files/kdf.h b/doc/dox_comments/header_files/kdf.h new file mode 100644 index 000000000..86fa87466 --- /dev/null +++ b/doc/dox_comments/header_files/kdf.h @@ -0,0 +1,126 @@ + +/*! + \ingroup SrtpKdf + + \brief This function derives keys using SRTP KDF algorithm. + + \return 0 Returned upon successful key derviation. + \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. + \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 [out] key1 First key. Label value of 0x00. + \param [in] key1Sz Size of first key in bytes. + \param [out] key2 Second key. Label value of 0x01. + \param [in] key2Sz Size of second key in bytes. + \param [out] key3 Third key. Label value of 0x02. + \param [in] key3Sz Size of third key in bytes. + + + _Example_ + \code + unsigned char key[16] = { ... }; + unsigned char salt[14] = { ... }; + unsigned char index[6] = { ... }; + unsigned char keyE[16]; + unsigned char keyA[20]; + unsigned char keyS[14]; + int kdrIdx = 0; // Use all of index + int ret; + + ret = wc_SRTP_KDF(key, sizeof(key), salt, sizeof(salt), kdrIdx, index, + keyE, sizeof(keyE), keyA, sizeof(keyA), keyS, sizeof(keyS)); + if (ret != 0) { + WOLFSSL_MSG("wc_SRTP_KDF failed"); + } + \endcode + + \sa wc_SRTCP_KDF + \sa wc_SRTP_KDF_kdr_to_idx +*/ +int wc_SRTP_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 keys using SRTCP KDF algorithm. + + \return 0 Returned upon successful key derviation. + \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. + \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 [out] key1 First key. Label value of 0x00. + \param [in] key1Sz Size of first key in bytes. + \param [out] key2 Second key. Label value of 0x01. + \param [in] key2Sz Size of second key in bytes. + \param [out] key3 Third key. Label value of 0x02. + \param [in] key3Sz Size of third key in bytes. + + + _Example_ + \code + unsigned char key[16] = { ... }; + unsigned char salt[14] = { ... }; + unsigned char index[4] = { ... }; + unsigned char keyE[16]; + unsigned char keyA[20]; + unsigned char keyS[14]; + int kdrIdx = 0; // Use all of index + int ret; + + ret = wc_SRTCP_KDF(key, sizeof(key), salt, sizeof(salt), kdrIdx, index, + keyE, sizeof(keyE), keyA, sizeof(keyA), keyS, sizeof(keyS)); + if (ret != 0) { + WOLFSSL_MSG("wc_SRTP_KDF failed"); + } + \endcode + + \sa wc_SRTP_KDF + \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 converts a kdr value to an index to use in SRTP/SRTCP KDF API. + + \return Key derivation rate as an index. + + \param [in] kdr Key derivation rate to convert. + + _Example_ + \code + word32 kdr = 0x00000010; + int kdrIdx; + int ret; + + kdrIdx = wc_SRTP_KDF_kdr_to_idx(kdr); + \endcode + + \sa wc_SRTP_KDF + \sa wc_SRTCP_KDF +*/ +int wc_SRTP_KDF_kdr_to_idx(word32 kdr); + diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 1ff49a8d4..1b4e5832f 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -127,6 +127,7 @@ #ifdef WOLFSSL_SIPHASH #include #endif + #include #ifndef NO_PWDBASED #include #endif @@ -534,6 +535,9 @@ #define BENCH_PBKDF2 0x00000100 #define BENCH_SIPHASH 0x00000200 +/* KDF algorithms */ +#define BENCH_SRTP_KDF 0x00000001 + /* Asymmetric algorithms. */ #define BENCH_RSA_KEYGEN 0x00000001 #define BENCH_RSA 0x00000002 @@ -619,6 +623,8 @@ static word32 bench_cipher_algs = 0; static word32 bench_digest_algs = 0; /* MAC algorithms to benchmark. */ static word32 bench_mac_algs = 0; +/* KDF algorithms to benchmark. */ +static word32 bench_kdf_algs = 0; /* Asymmetric algorithms to benchmark. */ static word32 bench_asym_algs = 0; /* Post-Quantum Asymmetric algorithms to benchmark. */ @@ -797,9 +803,18 @@ static const bench_alg bench_mac_opt[] = { #ifndef NO_PWDBASED { "-pbkdf2", BENCH_PBKDF2 }, #endif +#endif #ifdef WOLFSSL_SIPHASH { "-siphash", BENCH_SIPHASH }, #endif + { NULL, 0 } +}; + +/* All recognized KDF algorithm choosing command line options. */ +static const bench_alg bench_kdf_opt[] = { + { "-kdf", 0xffffffff }, +#ifdef WC_SRTP_KDF + { "-srtp-kdf", BENCH_SRTP_KDF }, #endif { NULL, 0 } }; @@ -1646,6 +1661,7 @@ static void benchmark_static_init(int force) bench_cipher_algs = 0; bench_digest_algs = 0; bench_mac_algs = 0; + bench_kdf_algs = 0; bench_asym_algs = 0; bench_pq_asym_algs = 0; bench_other_algs = 0; @@ -2785,12 +2801,18 @@ static void* benchmarks_do(void* args) bench_pbkdf2(); } #endif - #ifdef WOLFSSL_SIPHASH - if (bench_all || (bench_mac_algs & BENCH_SIPHASH)) { - bench_siphash(); - } - #endif #endif /* NO_HMAC */ +#ifdef WOLFSSL_SIPHASH + if (bench_all || (bench_mac_algs & BENCH_SIPHASH)) { + bench_siphash(); + } +#endif + +#ifdef WC_SRTP_KDF + if (bench_all || (bench_kdf_algs & BENCH_SRTP_KDF)) { + bench_srtpkdf(); + } +#endif #ifdef HAVE_SCRYPT if (bench_all || (bench_other_algs & BENCH_SCRYPT)) @@ -6720,6 +6742,68 @@ void bench_siphash(void) } #endif +#ifdef WC_SRTP_KDF +void bench_srtpkdf(void) +{ + double start; + int count; + int ret = 0; + byte keyE[32]; + byte keyA[20]; + byte keyS[14]; + const byte *key = bench_key_buf; + const byte salt[14] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e }; + const byte index[6] = { 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA }; + int kdrIdx = 0; + int i; + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + ret = wc_SRTP_KDF(key, AES_128_KEY_SIZE, salt, sizeof(salt), + kdrIdx, index, keyE, AES_128_KEY_SIZE, keyA, sizeof(keyA), + keyS, sizeof(keyS)); + } + count += i; + } while (bench_stats_check(start)); + bench_stats_asym_finish("KDF", 128, "SRTP", 0, count, start, ret); + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + ret = wc_SRTP_KDF(key, AES_256_KEY_SIZE, salt, sizeof(salt), + kdrIdx, index, keyE, AES_256_KEY_SIZE, keyA, sizeof(keyA), + keyS, sizeof(keyS)); + } + count += i; + } while (bench_stats_check(start)); + bench_stats_asym_finish("KDF", 256, "SRTP", 0, count, start, ret); + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + ret = wc_SRTCP_KDF(key, AES_128_KEY_SIZE, salt, sizeof(salt), + kdrIdx, index, keyE, AES_128_KEY_SIZE, keyA, sizeof(keyA), + keyS, sizeof(keyS)); + } + count += i; + } while (bench_stats_check(start)); + bench_stats_asym_finish("KDF", 128, "SRTCP", 0, count, start, ret); + + bench_stats_start(&count, &start); + do { + for (i = 0; i < numBlocks; i++) { + ret = wc_SRTCP_KDF(key, AES_256_KEY_SIZE, salt, sizeof(salt), + kdrIdx, index, keyE, AES_256_KEY_SIZE, keyA, sizeof(keyA), + keyS, sizeof(keyS)); + } + count += i; + } while (bench_stats_check(start)); + bench_stats_asym_finish("KDF", 256, "SRTCP", 0, count, start, ret); +} +#endif + #ifndef NO_RSA #if defined(WOLFSSL_KEY_GEN) @@ -10660,6 +10744,8 @@ static void Usage(void) print_alg(bench_digest_opt[i].str, &line); for (i=0; bench_mac_opt[i].str != NULL; i++) print_alg(bench_mac_opt[i].str, &line); + for (i=0; bench_kdf_opt[i].str != NULL; i++) + print_alg(bench_kdf_opt[i].str, &line); for (i=0; bench_asym_opt[i].str != NULL; i++) print_alg(bench_asym_opt[i].str, &line); for (i=0; bench_other_opt[i].str != NULL; i++) @@ -10894,6 +10980,14 @@ int wolfcrypt_benchmark_main(int argc, char** argv) optMatched = 1; } } + /* Known KDF algorithms */ + for (i=0; !optMatched && bench_kdf_opt[i].str != NULL; i++) { + if (string_matches(argv[1], bench_kdf_opt[i].str)) { + bench_kdf_algs |= bench_kdf_opt[i].val; + bench_all = 0; + optMatched = 1; + } + } /* Known asymmetric algorithms */ for (i=0; !optMatched && bench_asym_opt[i].str != NULL; i++) { if (string_matches(argv[1], bench_asym_opt[i].str)) { diff --git a/wolfcrypt/benchmark/benchmark.h b/wolfcrypt/benchmark/benchmark.h index 765d15f55..cefef7ca6 100644 --- a/wolfcrypt/benchmark/benchmark.h +++ b/wolfcrypt/benchmark/benchmark.h @@ -95,6 +95,7 @@ void bench_hmac_sha256(int useDeviceID); void bench_hmac_sha384(int useDeviceID); void bench_hmac_sha512(int useDeviceID); void bench_siphash(void); +void bench_srtpkdf(void); void bench_rsaKeyGen(int useDeviceID); void bench_rsaKeyGen_size(int useDeviceID, word32 keySz); void bench_rsa(int useDeviceID); diff --git a/wolfcrypt/src/kdf.c b/wolfcrypt/src/kdf.c index 2568c444c..3b452d56f 100644 --- a/wolfcrypt/src/kdf.c +++ b/wolfcrypt/src/kdf.c @@ -52,6 +52,9 @@ #include #include +#ifdef WC_SRTP_KDF +#include +#endif #if defined(WOLFSSL_HAVE_PRF) && !defined(NO_HMAC) @@ -870,4 +873,292 @@ int wc_SSH_KDF(byte hashId, byte keyId, byte* key, word32 keySz, #endif /* WOLFSSL_WOLFSSH */ +#ifdef WC_SRTP_KDF +/* Calculate first block to encrypt. + * + * @param [in] salt Random value to XOR in. + * @param [in] saltSz Size of random value 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] indexSz Size of index value in bytes. + * @param [out] block First block to encrypt. + */ +static void wc_srtp_kdf_first_block(const byte* salt, word32 saltSz, int kdrIdx, + const byte* index, byte indexSz, unsigned char* block) +{ + word32 i; + + /* XOR salt into zeroized buffer. */ + 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. */ + + /* When kdrIdx is -1, don't XOR in index. */ + if (kdrIdx >= 0) { + /* Get the number of bits to shift index by. */ + word32 bits = kdrIdx & 0x7; + /* Reduce index size by number of bytes to remove. */ + indexSz -= kdrIdx >> 3; + + if ((kdrIdx & 0x7) == 0) { + /* Just XOR in as no bit shifting. */ + for (i = 0; i < indexSz; i++) + block[i + WC_SRTP_MAX_SALT - indexSz] ^= index[i]; + } + else { + /* XOR in as bit shifted index. */ + block[WC_SRTP_MAX_SALT - indexSz] ^= index[i+0] >> bits; + for (i = 1; i < indexSz; i++) { + block[i + WC_SRTP_MAX_SALT - indexSz] ^= + (index[i-1] << (8 - bits)) | + (index[i+0] >> bits ); + } + } + } +} + +/* Derive a key given the first block. + * + * @param [in, out] block First block to encrypt. Need label XORed in. + * @param [in] indexSz Size of index in bytes to calculate where label is + * XORed into. + * @param [in] label Label byte that differs for each key. + * @param [out] key Derived key. + * @param [in] keySz Size of key to derive in bytes. + * @param [in] aes AES object to encrypt with. + * @return 0 on success. + */ +static int wc_srtp_kdf_derive_key(byte* block, byte indexSz, byte label, + byte* key, word32 keySz, Aes* aes) +{ + int i; + int ret = 0; + /* Calculate the number of full blocks needed for derived key. */ + int blocks = keySz / AES_BLOCK_SIZE; + + /* XOR in label. */ + block[WC_SRTP_MAX_SALT - indexSz - 1] ^= label; + for (i = 0; (ret == 0) && (i < blocks); i++) { + /* Set counter. */ + block[15] = i; + /* Encrypt block into key buffer. */ + ret = wc_AesEcbEncrypt(aes, key, block, AES_BLOCK_SIZE); + /* Reposition for more derived key. */ + key += AES_BLOCK_SIZE; + /* Reduce the count of key bytes required. */ + keySz -= AES_BLOCK_SIZE; + } + /* Do any partial blocks. */ + if ((ret == 0) && (keySz > 0)) { + byte enc[AES_BLOCK_SIZE]; + /* Set counter. */ + block[15] = i; + /* Encrypt block into temporary. */ + ret = wc_AesEcbEncrypt(aes, enc, block, AES_BLOCK_SIZE); + if (ret == 0) { + /* Copy into key required amount. */ + XMEMCPY(key, enc, keySz); + } + } + /* XOR out label. */ + block[WC_SRTP_MAX_SALT - indexSz - 1] ^= label; + + return ret; +} + +/* Derive keys 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. kdr = 0 when -1, otherwise + * kdr = 2^kdrIdx. + * @param [in] index Index value to XOR in. + * @param [out] key1 First key. Label value of 0x00. + * @param [in] key1Sz Size of first key in bytes. + * @param [out] key2 Second key. Label value of 0x01. + * @param [in] key2Sz Size of second key in bytes. + * @param [out] key3 Third key. Label value of 0x02. + * @param [in] key3Sz Size of third key in bytes. + * @return BAD_FUNC_ARG when key or salt 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(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) +{ + 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)) { + 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, 6, block); + + /* Calculate first key if required. */ + if ((ret == 0) && (key1 != NULL)) { + ret = wc_srtp_kdf_derive_key(block, 6, 0x00, 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); + } + /* Calculate third key if required. */ + if ((ret == 0) && (key3 != NULL)) { + ret = wc_srtp_kdf_derive_key(block, 6, 0x02, 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 keys 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 [out] key1 First key. Label value of 0x03. + * @param [in] key1Sz Size of first key in bytes. + * @param [out] key2 Second key. Label value of 0x04. + * @param [in] key2Sz Size of second key in bytes. + * @param [out] key3 Third key. Label value of 0x05. + * @param [in] key3Sz Size of third key in bytes. + * @return BAD_FUNC_ARG when key or salt 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(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) +{ + 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)) { + 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, 4, block); + + /* Calculate first key if required. */ + if ((ret == 0) && (key1 != NULL)) { + ret = wc_srtp_kdf_derive_key(block, 4, 0x03, 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); + } + /* Calculate third key if required. */ + if ((ret == 0) && (key3 != NULL)) { + ret = wc_srtp_kdf_derive_key(block, 4, 0x05, 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; +} + +/* Converts a kdr value to an index to use in SRTP/SRTCP KDF API. + * + * @param [in] kdr Key derivation rate to convert. + * @return Key derivation rate as an index. + */ +int wc_SRTP_KDF_kdr_to_idx(word32 kdr) +{ + int idx = -1; + + /* Keep shifting value down and incrementing index until top bit is gone. */ + while (kdr != 0) { + kdr >>= 1; + idx++; + } + + /* Index of top bit set. */ + return idx; +} +#endif /* WC_SRTP_KDF */ + #endif /* NO_KDF */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 4fc747c54..4285c14b0 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -518,6 +518,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t tls13_kdf_test(void); #endif WOLFSSL_TEST_SUBROUTINE wc_test_ret_t x963kdf_test(void); WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void); +#ifdef WC_SRTP_KDF +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srtpkdf_test(void); +#endif WOLFSSL_TEST_SUBROUTINE wc_test_ret_t arc4_test(void); #ifdef WC_RC2 WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rc2_test(void); @@ -1333,6 +1336,13 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("HPKE test passed!\n"); #endif +#if defined(WC_SRTP_KDF) + if ( (ret = srtpkdf_test()) != 0) + TEST_FAIL("SRTP KDF test failed!\n", ret); + else + TEST_PASS("SRTP KDF test passed!\n"); +#endif + #if defined(HAVE_AESGCM) && defined(WOLFSSL_AES_128) && \ !defined(WOLFSSL_AFALG_XILINX_AES) && !defined(WOLFSSL_XILINX_CRYPT) && \ !defined(WOLFSSL_RENESAS_FSPSM_CRYPTONLY) @@ -24806,6 +24816,396 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t hpke_test(void) } #endif /* HAVE_HPKE && HAVE_ECC && HAVE_AESGCM */ +#if defined(WC_SRTP_KDF) +typedef struct Srtp_Kdf_Tv { + const unsigned char* key; + word32 keySz; + const unsigned char* salt; + word32 saltSz; + int kdfIdx; + const unsigned char* index; + const unsigned char* ke; + const unsigned char* ka; + const unsigned char* ks; + const unsigned char* index_c; + const unsigned char* ke_c; + const unsigned char* ka_c; + const unsigned char* ks_c; + word32 keSz; + word32 kaSz; + word32 ksSz; +} Srtp_Kdf_Tv; + +WOLFSSL_TEST_SUBROUTINE wc_test_ret_t srtpkdf_test(void) +{ + wc_test_ret_t ret = 0; + /* 128-bit key, kdrIdx = -1 */ + WOLFSSL_SMALL_STACK_STATIC const byte key_0[] = { + 0xc4, 0x80, 0x9f, 0x6d, 0x36, 0x98, 0x88, 0x72, + 0x8e, 0x26, 0xad, 0xb5, 0x32, 0x12, 0x98, 0x90 + }; + WOLFSSL_SMALL_STACK_STATIC const byte salt_0[] = { + 0x0e, 0x23, 0x00, 0x6c, 0x6c, 0x04, 0x4f, 0x56, + 0x62, 0x40, 0x0e, 0x9d, 0x1b, 0xd6 + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_0[] = { + 0x48, 0x71, 0x65, 0x64, 0x9c, 0xca + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_0[] = { + 0xdc, 0x38, 0x21, 0x92, 0xab, 0x65, 0x10, 0x8a, + 0x86, 0xb2, 0x59, 0xb6, 0x1b, 0x3a, 0xf4, 0x6f + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_0[] = { + 0xb8, 0x39, 0x37, 0xfb, 0x32, 0x17, 0x92, 0xee, + 0x87, 0xb7, 0x88, 0x19, 0x3b, 0xe5, 0xa4, 0xe3, + 0xbd, 0x32, 0x6e, 0xe4 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_0[] = { + 0xf1, 0xc0, 0x35, 0xc0, 0x0b, 0x5a, 0x54, 0xa6, + 0x16, 0x92, 0xc0, 0x16, 0x27, 0x6c + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_c_0[] = { + 0x56, 0xf3, 0xf1, 0x97 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_c_0[] = { + 0xab, 0x5b, 0xe0, 0xb4, 0x56, 0x23, 0x5d, 0xcf, + 0x77, 0xd5, 0x08, 0x69, 0x29, 0xba, 0xfb, 0x38 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_c_0[] = { + 0xc5, 0x2f, 0xde, 0x0b, 0x80, 0xb0, 0xf0, 0xba, + 0xd8, 0xd1, 0x56, 0x45, 0xcb, 0x86, 0xe7, 0xc7, + 0xc3, 0xd8, 0x77, 0x0e + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_c_0[] = { + 0xde, 0xb5, 0xf8, 0x5f, 0x81, 0x33, 0x6a, 0x96, + 0x5e, 0xd3, 0x2b, 0xb7, 0xed, 0xe8 + }; + /* 192-bit key, kdrIdx = 0 */ + WOLFSSL_SMALL_STACK_STATIC const byte key_1[] = { + 0xbb, 0x04, 0x5b, 0x1f, 0x53, 0xc6, 0x93, 0x2c, + 0x2b, 0xa6, 0x88, 0xf5, 0xe3, 0xf2, 0x24, 0x70, + 0xe1, 0x7d, 0x7d, 0xec, 0x8a, 0x93, 0x4d, 0xf2 + }; + WOLFSSL_SMALL_STACK_STATIC const byte salt_1[] = { + 0xe7, 0x22, 0xab, 0x92, 0xfc, 0x7c, 0x89, 0xb6, + 0x53, 0x8a, 0xf9, 0x3c, 0xb9, 0x52 + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_1[] = { + 0xd7, 0x87, 0x8f, 0x33, 0xb1, 0x76 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_1[] = { + 0x2c, 0xc8, 0x3e, 0x54, 0xb2, 0x33, 0x89, 0xb3, + 0x71, 0x65, 0x0f, 0x51, 0x61, 0x65, 0xe4, 0x93, + 0x07, 0x4e, 0xb3, 0x47, 0xba, 0x2d, 0x60, 0x60 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_1[] = { + 0x2e, 0x80, 0xe4, 0x82, 0x55, 0xa2, 0xbe, 0x6d, + 0xe0, 0x46, 0xcc, 0xc1, 0x75, 0x78, 0x6e, 0x78, + 0xd1, 0xd1, 0x47, 0x08 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_1[] = { + 0xe0, 0xc1, 0xe6, 0xaf, 0x1e, 0x8d, 0x8c, 0xfe, + 0xe5, 0x60, 0x70, 0xb5, 0xe6, 0xea + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_c_1[] = { + 0x40, 0xbf, 0xd4, 0xa9 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_c_1[] = { + 0x94, 0x0f, 0x55, 0xce, 0x58, 0xd8, 0x16, 0x65, + 0xf0, 0xfa, 0x46, 0x40, 0x0c, 0xda, 0xb1, 0x11, + 0x9e, 0x69, 0xa0, 0x93, 0x4e, 0xd7, 0xf2, 0x84 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_c_1[] = { + 0xf5, 0x41, 0x6f, 0xc2, 0x65, 0xc5, 0xb3, 0xef, + 0xbb, 0x22, 0xc8, 0xfc, 0x6b, 0x00, 0x14, 0xb2, + 0xf3, 0x3b, 0x8e, 0x29 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_c_1[] = { + 0x35, 0xb7, 0x42, 0x43, 0xf0, 0x01, 0x01, 0xb4, + 0x68, 0xa1, 0x28, 0x80, 0x37, 0xf0 + }; + /* 256-bit key, kdrIdx = 1 */ + WOLFSSL_SMALL_STACK_STATIC const byte key_2[] = { + 0x10, 0x38, 0x0a, 0xcd, 0xd6, 0x47, 0xab, 0xee, + 0xc0, 0xd4, 0x44, 0xf4, 0x7e, 0x51, 0x36, 0x02, + 0x79, 0xa8, 0x94, 0x80, 0x35, 0x40, 0xed, 0x50, + 0xf4, 0x45, 0x30, 0x3d, 0xb5, 0xf0, 0x2b, 0xbb + }; + WOLFSSL_SMALL_STACK_STATIC const byte salt_2[] = { + 0xc7, 0x31, 0xf2, 0xc8, 0x40, 0x43, 0xb8, 0x74, + 0x8a, 0x61, 0x84, 0x7a, 0x25, 0x8a + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_2[] = { + 0x82, 0xf1, 0x84, 0x8c, 0xac, 0x42 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_2[] = { + 0xb2, 0x26, 0x60, 0xaf, 0x08, 0x23, 0x14, 0x98, + 0x91, 0xde, 0x5d, 0x87, 0x95, 0x61, 0xca, 0x8f, + 0x0e, 0xce, 0xfb, 0x68, 0x4d, 0xd6, 0x28, 0xcb, + 0x28, 0xe2, 0x27, 0x20, 0x2d, 0xff, 0x64, 0xbb + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_2[] = { + 0x12, 0x6f, 0x52, 0xe8, 0x07, 0x7f, 0x07, 0x84, + 0xa0, 0x61, 0x96, 0xf8, 0xee, 0x4d, 0x05, 0x57, + 0x65, 0xc7, 0x50, 0xc1 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_2[] = { + 0x18, 0x5a, 0x59, 0xe5, 0x91, 0x4d, 0xc9, 0x6c, + 0xfa, 0x5b, 0x36, 0x06, 0x8c, 0x9a + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_c_2[] = { + 0x31, 0x2d, 0x58, 0x15 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_c_2[] = { + 0x14, 0xf2, 0xc8, 0x25, 0x02, 0x79, 0x22, 0xa1, + 0x96, 0xb6, 0xf7, 0x07, 0x76, 0xa6, 0xa3, 0xc4, + 0x37, 0xdf, 0xa0, 0xf8, 0x78, 0x93, 0x2c, 0xfa, + 0xea, 0x35, 0xf0, 0xf3, 0x3f, 0x32, 0x6e, 0xfd + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_c_2[] = { + 0x6e, 0x3d, 0x4a, 0x99, 0xea, 0x2f, 0x9d, 0x13, + 0x4a, 0x1e, 0x71, 0x2e, 0x15, 0xc0, 0xca, 0xb6, + 0x35, 0x78, 0xdf, 0xa4 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_c_2[] = { + 0xae, 0xe4, 0xec, 0x18, 0x31, 0x70, 0x5d, 0x3f, + 0xdc, 0x97, 0x89, 0x88, 0xfd, 0xff + }; + /* 128-bit key, kdrIdx = 8 */ + WOLFSSL_SMALL_STACK_STATIC const byte key_3[] = { + 0x36, 0xb4, 0xde, 0xcb, 0x2e, 0x51, 0x23, 0x76, + 0xe0, 0x27, 0x7e, 0x3e, 0xc8, 0xf6, 0x54, 0x04 + }; + WOLFSSL_SMALL_STACK_STATIC const byte salt_3[] = { + 0x73, 0x26, 0xf4, 0x3f, 0xc0, 0xd9, 0xc6, 0xe3, + 0x2f, 0x92, 0x7d, 0x46, 0x12, 0x76 + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_3[] = { + 0x44, 0x73, 0xb2, 0x2d, 0xb2, 0x60 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_3[] = { + 0x79, 0x91, 0x3d, 0x7b, 0x20, 0x5d, 0xea, 0xe2, + 0xeb, 0x46, 0x89, 0x68, 0x5a, 0x06, 0x73, 0x74 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_3[] = { + 0x2d, 0x2e, 0x97, 0x4e, 0x76, 0x8c, 0x62, 0xa6, + 0x57, 0x80, 0x13, 0x42, 0x0b, 0x51, 0xa7, 0x66, + 0xea, 0x31, 0x24, 0xe6 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_3[] = { + 0xcc, 0xd7, 0x31, 0xf6, 0x3b, 0xf3, 0x89, 0x8a, + 0x5b, 0x7b, 0xb5, 0x8b, 0x4c, 0x3f + }; + WOLFSSL_SMALL_STACK_STATIC const byte index_c_3[] = { + 0x4a, 0x7d, 0xaa, 0x85 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ke_c_3[] = { + 0x34, 0x99, 0x71, 0xfe, 0x12, 0x93, 0xae, 0x8c, + 0x4a, 0xe9, 0x84, 0xe4, 0x93, 0x53, 0x63, 0x88 + }; + WOLFSSL_SMALL_STACK_STATIC const byte ka_c_3[] = { + 0xa4, 0x53, 0x5e, 0x0a, 0x9c, 0xf2, 0xce, 0x13, + 0xef, 0x7a, 0x13, 0xee, 0x0a, 0xef, 0xba, 0x17, + 0x05, 0x18, 0xe3, 0xed + }; + WOLFSSL_SMALL_STACK_STATIC const byte ks_c_3[] = { + 0xe1, 0x29, 0x4f, 0x61, 0x30, 0x3c, 0x4d, 0x46, + 0x5f, 0x5c, 0x81, 0x3c, 0x38, 0xb6 + }; + #define SRTP_TV_CNT 4 + Srtp_Kdf_Tv tv[SRTP_TV_CNT] = { + { key_0, (word32)sizeof(key_0), salt_0, (word32)sizeof(salt_0), -1, + index_0, ke_0, ka_0, ks_0, index_c_0, ke_c_0, ka_c_0, ks_c_0, + 16, 20, 14 }, + { key_1, (word32)sizeof(key_1), salt_1, (word32)sizeof(salt_1), 0, + index_1, ke_1, ka_1, ks_1, index_c_1, ke_c_1, ka_c_1, ks_c_1, + 24, 20, 14 }, + { key_2, (word32)sizeof(key_2), salt_2, (word32)sizeof(salt_2), 1, + index_2, ke_2, ka_2, ks_2, index_c_2, ke_c_2, ka_c_2, ks_c_2, + 32, 20, 14 }, + { key_3, (word32)sizeof(key_3), salt_3, (word32)sizeof(salt_3), 8, + index_3, ke_3, ka_3, ks_3, index_c_3, ke_c_3, ka_c_3, ks_c_3, + 16, 20, 14 }, + }; + int i; + int idx; + unsigned char keyE[32]; + unsigned char keyA[20]; + unsigned char keyS[14]; + + for (i = 0; (ret == 0) && (i < SRTP_TV_CNT); i++) { + #ifndef WOLFSSL_AES_128 + if (tv[i].keySz == AES_128_KEY_SIZE) { + continue; + } + #endif + #ifndef WOLFSSL_AES_192 + if (tv[i].keySz == AES_192_KEY_SIZE) { + continue; + } + #endif + #ifndef WOLFSSL_AES_256 + if (tv[i].keySz == AES_256_KEY_SIZE) { + continue; + } + #endif + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (XMEMCMP(keyE, tv[i].ke, 16) != 0) + return WC_TEST_RET_ENC_NC; + if (XMEMCMP(keyA, tv[i].ka, 20) != 0) + return WC_TEST_RET_ENC_NC; + if (XMEMCMP(keyS, tv[i].ks, 14) != 0) + return WC_TEST_RET_ENC_NC; + + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + if (XMEMCMP(keyE, tv[i].ke_c, 16) != 0) + return WC_TEST_RET_ENC_NC; + if (XMEMCMP(keyA, tv[i].ka_c, 20) != 0) + return WC_TEST_RET_ENC_NC; + if (XMEMCMP(keyS, tv[i].ks_c, 14) != 0) + return WC_TEST_RET_ENC_NC; + } + +#ifdef WOLFSSL_AES_128 + i = 0; +#elif defined(WOLFSSL_AES_192) + i = 1; +#else + i = 2; +#endif + ret = wc_SRTP_KDF(tv[i].key, 33, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, 33, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, 15, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, 15, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, 15, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, 15, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(NULL, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(NULL, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, NULL, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, NULL, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + 25, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + 25, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + -2, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + -2, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != BAD_FUNC_ARG) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, NULL, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, NULL, tv[i].keSz, keyA, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, NULL, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, NULL, tv[i].kaSz, + keyS, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_SRTP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index, keyE, tv[i].keSz, keyA, tv[i].kaSz, + NULL, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + ret = wc_SRTCP_KDF(tv[i].key, tv[i].keySz, tv[i].salt, tv[i].saltSz, + tv[i].kdfIdx, tv[i].index_c, keyE, tv[i].keSz, keyA, tv[i].kaSz, + NULL, tv[i].ksSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + idx = wc_SRTP_KDF_kdr_to_idx(0); + if (idx != -1) + return WC_TEST_RET_ENC_NC; + for (i = 0; i < 32; i++) { + word32 kdr = 1 << i; + idx = wc_SRTP_KDF_kdr_to_idx(kdr); + if (idx != i) + return WC_TEST_RET_ENC_NC; + } + + return 0; +} +#endif + #ifdef HAVE_ECC /* size to use for ECC key gen tests */ diff --git a/wolfssl/wolfcrypt/kdf.h b/wolfssl/wolfcrypt/kdf.h index b1a64fe5d..3e1c20d3e 100644 --- a/wolfssl/wolfcrypt/kdf.h +++ b/wolfssl/wolfcrypt/kdf.h @@ -105,6 +105,21 @@ WOLFSSL_API int wc_SSH_KDF(byte hashId, byte keyId, #endif /* WOLFSSL_WOLFSSH */ +#ifdef WC_SRTP_KDF +/* Maximum length of salt that can be used with SRTP/SRTCP. */ +#define WC_SRTP_MAX_SALT 14 + +WOLFSSL_API int wc_SRTP_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_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_kdr_to_idx(word32 kdr); + +#endif /* WC_SRTP_KDF */ + #ifdef __cplusplus } /* extern "C" */ #endif