diff --git a/doc/dox_comments/header_files/kdf.h b/doc/dox_comments/header_files/kdf.h index 86fa87466..02088c75d 100644 --- a/doc/dox_comments/header_files/kdf.h +++ b/doc/dox_comments/header_files/kdf.h @@ -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); diff --git a/wolfcrypt/src/kdf.c b/wolfcrypt/src/kdf.c index 34514e49b..6c4ba7366 100644 --- a/wolfcrypt/src/kdf.c +++ b/wolfcrypt/src/kdf.c @@ -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. diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index b32179e33..0c7b64c65 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -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; } diff --git a/wolfssl/wolfcrypt/kdf.h b/wolfssl/wolfcrypt/kdf.h index 3e1c20d3e..6a6a85698 100644 --- a/wolfssl/wolfcrypt/kdf.h +++ b/wolfssl/wolfcrypt/kdf.h @@ -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);