From 391e0068af3fb3fdfdad847fad98bb5aeb96e0f2 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Wed, 1 Jul 2026 11:18:29 -0400 Subject: [PATCH] add proper support for P25 P2 MAC scrambling; fix and enhance message number following for KMM frames; correct and fix CMAC rekey calculations; --- src/common/p25/Crypto.cpp | 86 ++++++++++++++--------- src/common/p25/kmm/KMMFrame.cpp | 15 +++- src/common/p25/kmm/KMMFrame.h | 6 +- src/common/p25/kmm/KMMRekeyCommand.cpp | 2 - src/common/p25/lc/LC.cpp | 22 +----- src/common/p25/lc/LC.h | 3 + tests/crypto/P25_MAC_CMAC_Test.cpp | 10 +-- tests/p25/KMM_Rekey_CBC_Test.cpp | 2 +- tests/p25/KMM_Rekey_CMAC_Test.cpp | 95 +++++++++++++++++++++++++- tests/p25/P2_VCH_MACPDU_Test.cpp | 8 +-- 10 files changed, 180 insertions(+), 69 deletions(-) diff --git a/src/common/p25/Crypto.cpp b/src/common/p25/Crypto.cpp index b3b75d62..3dbcf204 100644 --- a/src/common/p25/Crypto.cpp +++ b/src/common/p25/Crypto.cpp @@ -454,6 +454,8 @@ UInt8Array P25Crypto::cryptAES_KMM_CBC(const uint8_t* macKey, const uint8_t* msg UInt8Array P25Crypto::cryptAES_KMM_CMAC_KDF(const uint8_t* kek, const uint8_t* msg, uint16_t msgLen, bool hasMN) { #if defined(ENABLE_SSL) + (void)msgLen; + // O T A R M A C uint8_t label[8U] = { 0x4FU, 0x54U, 0x41U, 0x52U, 0x20U, 0x4DU, 0x41U, 0x43U }; @@ -469,16 +471,23 @@ UInt8Array P25Crypto::cryptAES_KMM_CMAC_KDF(const uint8_t* kek, const uint8_t* m contextLen = 10U; } - /** DEBUG REMOVEME */ - Utils::dump(2U, "KEK", kek, MAX_ENC_KEY_LENGTH_BYTES); - Utils::dump(2U, "Label", label, 8U); - Utils::dump(2U, "Context", context, contextLen); - /** DEBUG REMOVEME */ - size_t len; uint8_t tempBuf[TEMP_BUFFER_LEN]; ::memset(tempBuf, 0x00U, TEMP_BUFFER_LEN); + // AACA-D Sec 13.5.2.2.2 SP800-108 counter-mode KDF: + // PRF input = i || Label || 0x00 || Context || L + uint8_t kdfInput[1U + 8U + 1U + 12U + 2U]; + uint8_t inputOffset = 0U; + kdfInput[inputOffset++] = 0x01U; // i + ::memcpy(kdfInput + inputOffset, label, 8U); + inputOffset += 8U; + kdfInput[inputOffset++] = 0x00U; // separator + ::memcpy(kdfInput + inputOffset, context, contextLen); + inputOffset += contextLen; + kdfInput[inputOffset++] = 0x01U; // L = 256 bits + kdfInput[inputOffset++] = 0x00U; + ERR_load_crypto_strings(); // create a library context (required for OpenSSL 3.0+) @@ -488,49 +497,64 @@ UInt8Array P25Crypto::cryptAES_KMM_CMAC_KDF(const uint8_t* kek, const uint8_t* m return nullptr; } - // load the KDF algorithm - EVP_KDF* kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL); - if (!kdf) { - LogError(LOG_P25, "EVP_KDF_fetch(), failed to load OpenSSL KDF algorithm: %s", ERR_error_string(ERR_get_error(), NULL)); + // fetch the HMAC implementation for SP800-108 PRF + EVP_MAC* hmac = EVP_MAC_fetch(libCtx, "HMAC", NULL); + if (!hmac) { + LogError(LOG_P25, "EVP_MAC_fetch(), failed to fetch OpenSSL HMAC: %s", ERR_error_string(ERR_get_error(), NULL)); OSSL_LIB_CTX_free(libCtx); return nullptr; } - // create a context for the MAC operation - EVP_KDF_CTX* ctx = EVP_KDF_CTX_new(kdf); + // create a context for the HMAC operation + EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(hmac); if (!ctx) { - LogError(LOG_P25, "EVP_KDF_CTX_new(), failed to create a OpenSSL KDF context: %s", ERR_error_string(ERR_get_error(), NULL)); - EVP_KDF_free(kdf); + LogError(LOG_P25, "EVP_MAC_CTX_new(), failed to create OpenSSL HMAC context: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MAC_free(hmac); OSSL_LIB_CTX_free(libCtx); return nullptr; } - // set the cipher to AES-256-CBC and initialize the MAC operation + // Initialize HMAC-SHA-256 keyed by TEK (K_IN) OSSL_PARAM params[] = { - OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC, "HMAC", 0), - OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, "SHA-256", 0), - OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (void*)kek, MAX_ENC_KEY_LENGTH_BYTES), - OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, (void*)label, 8U), - OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, (void*)context, contextLen), + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "SHA256", 0), OSSL_PARAM_END }; - // derive MAC key - if (EVP_KDF_derive(ctx, tempBuf, MAX_ENC_KEY_LENGTH_BYTES, params) <= 0) { - LogError(LOG_P25, "EVP_KDF_derive(), failed to derive MAC key: %s", ERR_error_string(ERR_get_error(), NULL)); - EVP_KDF_CTX_free(ctx); - EVP_KDF_free(kdf); + if (!EVP_MAC_init(ctx, kek, MAX_ENC_KEY_LENGTH_BYTES, params)) { + LogError(LOG_P25, "EVP_MAC_init(), failed to initialize HMAC-SHA-256: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(hmac); OSSL_LIB_CTX_free(libCtx); return nullptr; } - EVP_KDF_CTX_free(ctx); - EVP_KDF_free(kdf); - OSSL_LIB_CTX_free(libCtx); + if (!EVP_MAC_update(ctx, kdfInput, inputOffset)) { + LogError(LOG_P25, "EVP_MAC_update(), failed to update HMAC input: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(hmac); + OSSL_LIB_CTX_free(libCtx); + return nullptr; + } - /** DEBUG REMOVEME */ - Utils::dump(2U, "tempBuf", tempBuf, 128U); - /** DEBUG REMOVEME */ + if (!EVP_MAC_final(ctx, tempBuf, &len, TEMP_BUFFER_LEN)) { + LogError(LOG_P25, "EVP_MAC_final(), failed to finalize HMAC output: %s", ERR_error_string(ERR_get_error(), NULL)); + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(hmac); + OSSL_LIB_CTX_free(libCtx); + return nullptr; + } + + if (len < MAX_ENC_KEY_LENGTH_BYTES) { + LogError(LOG_P25, "EVP_MAC_final(), invalid HMAC output length for CMAC KDF: %zu", len); + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(hmac); + OSSL_LIB_CTX_free(libCtx); + return nullptr; + } + + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(hmac); + OSSL_LIB_CTX_free(libCtx); UInt8Array wrappedKey = std::unique_ptr(new uint8_t[MAX_ENC_KEY_LENGTH_BYTES]); ::memset(wrappedKey.get(), 0x00U, MAX_ENC_KEY_LENGTH_BYTES); diff --git a/src/common/p25/kmm/KMMFrame.cpp b/src/common/p25/kmm/KMMFrame.cpp index af307612..38a4a43f 100644 --- a/src/common/p25/kmm/KMMFrame.cpp +++ b/src/common/p25/kmm/KMMFrame.cpp @@ -42,6 +42,7 @@ KMMFrame::KMMFrame() : m_macKId(0U), m_macFormat(0U), m_messageNumber(0U), + m_hasMessageNumber(false), m_dstLlId(0U), m_srcLlId(0U), m_complete(true), @@ -109,7 +110,7 @@ void KMMFrame::generateMAC(uint8_t* kek, uint8_t* data) case KMM_MAC_FORMAT_CMAC: { // generate intermediate derived key - UInt8Array macKey = crypto.cryptAES_KMM_CMAC_KDF(kek, data, m_messageFullLength, m_messageNumber > 0U); + UInt8Array macKey = crypto.cryptAES_KMM_CMAC_KDF(kek, data, m_messageFullLength, m_hasMessageNumber); // generate MAC UInt8Array mac = crypto.cryptAES_KMM_CMAC(macKey.get(), data, m_messageFullLength); @@ -158,6 +159,7 @@ bool KMMFrame::decodeHeader(const uint8_t* data) m_respKind = (data[3U] >> 6U) & 0x03U; // Response Kind bool hasMN = ((data[3U] >> 4U) & 0x03U) == 0x02U; // Message Number Flag + m_hasMessageNumber = hasMN; m_macType = (data[3U] >> 2U) & 0x03U; // MAC Type bool done = (data[3U] & 0x01U) == 0x01U; // Done Flag @@ -169,6 +171,8 @@ bool KMMFrame::decodeHeader(const uint8_t* data) m_dstLlId = GET_UINT24(data, 4U); // Destination RSI m_srcLlId = GET_UINT24(data, 7U); // Source RSI + m_bodyOffset = 0U; + m_messageNumber = 0U; if (hasMN) { m_bodyOffset = 2U; m_messageNumber = GET_UINT16(data, 10U); // Message Number @@ -222,15 +226,19 @@ void KMMFrame::encodeHeader(uint8_t* data) SET_UINT16(m_messageLength, data, 1U); // Message Length m_messageFullLength = m_messageLength + 3U; + bool hasMN = m_hasMessageNumber || (m_messageNumber > 0U); + m_hasMessageNumber = hasMN; + data[3U] = ((m_respKind & 0x03U) << 6U) + // Response Kind - ((m_messageNumber > 0U) ? 0x20U : 0x00U) + // Message Number Flag + (hasMN ? 0x20U : 0x00U) + // Message Number Flag ((m_macType & 0x03U) << 2U) + // MAC Type ((!m_complete) ? 0x01U : 0x00U); // Done Flag SET_UINT24(m_dstLlId, data, 4U); // Destination RSI SET_UINT24(m_srcLlId, data, 7U); // Source RSI - if (m_messageNumber > 0U) { + m_bodyOffset = 0U; + if (hasMN) { SET_UINT16(m_messageNumber, data, 10U); // Message Number m_bodyOffset = 2U; } @@ -273,6 +281,7 @@ void KMMFrame::copy(const KMMFrame& data) m_complete = data.m_complete; m_messageNumber = data.m_messageNumber; + m_hasMessageNumber = data.m_hasMessageNumber; m_macAlgId = data.m_macAlgId; m_macKId = data.m_macKId; m_macType = data.m_macType; diff --git a/src/common/p25/kmm/KMMFrame.h b/src/common/p25/kmm/KMMFrame.h index ee391463..44cc9402 100644 --- a/src/common/p25/kmm/KMMFrame.h +++ b/src/common/p25/kmm/KMMFrame.h @@ -74,7 +74,7 @@ namespace p25 virtual uint32_t length() const { uint32_t len = KMM_FRAME_LENGTH; - if (m_messageNumber > 0U) + if (m_hasMessageNumber || m_messageNumber > 0U) len += 2U; if (m_macType == P25DEF::KMM_MAC::ENH_MAC) len += P25DEF::KMM_AES_MAC_LENGTH + 5U; @@ -154,6 +154,10 @@ namespace p25 * @brief Message Number. */ DECLARE_PROTECTED_PROPERTY(uint16_t, messageNumber, MessageNumber); + /** + * @brief Flag indicating whether the Message Number field is present. + */ + DECLARE_PROTECTED_PROPERTY(bool, hasMessageNumber, HasMessageNumber); /** * @brief Destination Logical link ID. diff --git a/src/common/p25/kmm/KMMRekeyCommand.cpp b/src/common/p25/kmm/KMMRekeyCommand.cpp index d463a3ae..abe2cd86 100644 --- a/src/common/p25/kmm/KMMRekeyCommand.cpp +++ b/src/common/p25/kmm/KMMRekeyCommand.cpp @@ -164,8 +164,6 @@ void KMMRekeyCommand::encode(uint8_t* data) DECLARE_UINT8_ARRAY(keyPayload, keysetItem.keyLength()); key.getKey(keyPayload); - Utils::dump(2U, "keyPayload", keyPayload, keysetItem.keyLength()); - ::memcpy(data + (25U + (m_bodyOffset + offset)), keyPayload, keysetItem.keyLength()); offset += 5U + keyNameLen + keysetItem.keyLength(); diff --git a/src/common/p25/lc/LC.cpp b/src/common/p25/lc/LC.cpp index d5de2fb7..a47eff11 100644 --- a/src/common/p25/lc/LC.cpp +++ b/src/common/p25/lc/LC.cpp @@ -574,16 +574,6 @@ bool LC::decodeVCH_MACPDU_IEMI(const uint8_t* data, bool sync) Utils::dump(2U, "P25, LC::decodeVCH_MACPDU_IEMI(), MAC PDU", raw, lengthBytes); #endif - // are we decoding a FACCH with scrambling? - if (m_p2DUID == P2_DUID::FACCH_SCRAMBLED) { - /* TODO: if scrambled handle scrambling */ - } - - // are we decoding a SACCH with scrambling? - if (m_p2DUID == P2_DUID::SACCH_SCRAMBLED) { - /* TODO: if scrambled handle scrambling */ - } - return decodeMACPDU(raw, P25_P2_IEMI_MAC_LENGTH_BITS); } @@ -691,16 +681,6 @@ bool LC::decodeVCH_MACPDU_OEMI(const uint8_t* data, bool sync) #endif } - // are we decoding a FACCH with scrambling? - if (m_p2DUID == P2_DUID::FACCH_SCRAMBLED) { - /* TODO: if scrambled handle scrambling */ - } - - // are we decoding a SACCH with scrambling? - if (m_p2DUID == P2_DUID::SACCH_SCRAMBLED) { - /* TODO: if scrambled handle scrambling */ - } - return decodeMACPDU(raw, sync ? P25_P2_SOEMI_MAC_LENGTH_BITS : P25_P2_IOEMI_MAC_LENGTH_BITS); } @@ -743,6 +723,7 @@ void LC::encodeVCH_MACPDU(uint8_t* data, bool sync) bool b = READ_BIT(raw, i); WRITE_BIT(data, n, b); } + } else { // encode RS (52,30,23) FEC m_rs.encode523023(raw); @@ -760,6 +741,7 @@ void LC::encodeVCH_MACPDU(uint8_t* data, bool sync) bool b = READ_BIT(raw, i); WRITE_BIT(data, n, b); } + } } diff --git a/src/common/p25/lc/LC.h b/src/common/p25/lc/LC.h index 0695a1aa..6ee85e8c 100644 --- a/src/common/p25/lc/LC.h +++ b/src/common/p25/lc/LC.h @@ -134,6 +134,7 @@ namespace p25 */ void encodeVCH_MACPDU(uint8_t* data, bool sync); + /** * @brief Helper to determine if the MFId is a standard MFId. * @returns bool True, if the MFId contained for this LC is standard, otherwise false. @@ -347,6 +348,7 @@ namespace p25 // User Alias data uint8_t* m_userAlias; + bool m_gotUserAliasPartA; bool m_gotUserAlias; @@ -398,6 +400,7 @@ namespace p25 * @param[in] raw */ void encodeP2_DUIDHamming(uint8_t* data, const uint8_t* raw); + }; } // namespace lc } // namespace p25 diff --git a/tests/crypto/P25_MAC_CMAC_Test.cpp b/tests/crypto/P25_MAC_CMAC_Test.cpp index 81eccafb..53852474 100644 --- a/tests/crypto/P25_MAC_CMAC_Test.cpp +++ b/tests/crypto/P25_MAC_CMAC_Test.cpp @@ -26,7 +26,7 @@ TEST_CASE("AES MAC CMAC Test", "[aes][mac_cmac]") { srand((unsigned int)time(NULL)); - // example data taken from TIA-102.AACA-C-2023 Section 14.3.5.1 + // example data taken from TIA-102.AACA-D Section 14.3 (CMAC with message number) // MAC TEK uint8_t macTek[] = @@ -38,8 +38,8 @@ TEST_CASE("AES MAC CMAC Test", "[aes][mac_cmac]") { // expected CMAC key uint8_t expectedCMAC[] = { - 0x5F, 0xB2, 0x91, 0xD0, 0x9E, 0xE3, 0x99, 0x1E, 0x13, 0x1A, 0x04, 0xB0, 0xE3, 0xA0, 0xBF, 0x58, - 0xB4, 0xA1, 0xCE, 0x46, 0x10, 0x48, 0xEB, 0x14, 0xB4, 0x97, 0xAE, 0x95, 0x22, 0xD0, 0x0D, 0x31 + 0xC2, 0x4C, 0x24, 0xE4, 0x1A, 0x89, 0xDB, 0x2D, 0xC1, 0x8E, 0xB8, 0x8A, 0x17, 0xE1, 0xA8, 0xF1, + 0xFB, 0x55, 0x46, 0x76, 0xAD, 0xE2, 0x44, 0x05, 0x2A, 0x1F, 0x5B, 0xAA, 0x6D, 0x6F, 0xDA, 0xDF }; // data block @@ -49,7 +49,7 @@ TEST_CASE("AES MAC CMAC Test", "[aes][mac_cmac]") { 0x01, 0x00, 0x01, 0x84, 0x28, 0x01, 0x00, 0x00, 0x00, 0x49, 0x83, 0x80, 0x28, 0x9C, 0xF6, 0x35, 0xFB, 0x68, 0xD3, 0x45, 0xD3, 0x4F, 0x62, 0xEF, 0x06, 0x3B, 0xA4, 0xE0, 0x5C, 0xAE, 0x47, 0x56, 0xE7, 0xD3, 0x04, 0x46, 0xD1, 0xF0, 0x7C, 0x6E, 0xB4, 0xE9, 0xE0, 0x84, 0x09, 0x45, 0x37, 0x23, - 0x72, 0xFB, 0x80, 0x21, 0x85, 0x22, 0x33, 0x41, 0xD9, 0x8A, 0x97, 0x08, 0x84, 0x2F, 0x62, 0x41 + 0x72, 0xFB, 0x80, 0xA2, 0xC1, 0xCC, 0xD1, 0x42, 0x01, 0x73, 0x8C, 0x08, 0x84, 0x2F, 0x62, 0x41 }; uint8_t expectedMAC[8U]; @@ -119,7 +119,7 @@ TEST_CASE("AES MAC CMAC Test", "[aes][mac_cmac]") { } } - UInt8Array mac = crypto.cryptAES_KMM_CMAC(expectedCMAC/* macKey.get()*/, dataBlock, fullLength); + UInt8Array mac = crypto.cryptAES_KMM_CMAC(macKey.get(), dataBlock, fullLength); Utils::dump(2U, "P25_MAC_CMAC_Crypto_Test, MAC", mac.get(), 8U); for (uint32_t i = 0; i < 8U; i++) { diff --git a/tests/p25/KMM_Rekey_CBC_Test.cpp b/tests/p25/KMM_Rekey_CBC_Test.cpp index 69840fdf..6f572dee 100644 --- a/tests/p25/KMM_Rekey_CBC_Test.cpp +++ b/tests/p25/KMM_Rekey_CBC_Test.cpp @@ -23,7 +23,7 @@ using namespace p25::kmm; #include #include -TEST_CASE("KMM ReKey Command CBC Test", "[p25][kmm_cbc]") { +TEST_CASE("KMM ReKey Command CBC Test", "[p25][kmm_cbc][cap]") { bool failed = false; INFO("P25 KMM ReKey Test"); diff --git a/tests/p25/KMM_Rekey_CMAC_Test.cpp b/tests/p25/KMM_Rekey_CMAC_Test.cpp index 89257bab..a774680b 100644 --- a/tests/p25/KMM_Rekey_CMAC_Test.cpp +++ b/tests/p25/KMM_Rekey_CMAC_Test.cpp @@ -9,11 +9,13 @@ */ #include "host/Defines.h" #include "common/p25/P25Defines.h" +#include "common/p25/Crypto.h" #include "common/p25/kmm/KMMRekeyCommand.h" #include "common/Log.h" #include "common/Utils.h" using namespace p25; +using namespace p25::crypto; using namespace p25::defines; using namespace p25::kmm; @@ -21,7 +23,7 @@ using namespace p25::kmm; #include #include -TEST_CASE("KMM ReKey Command CMAC Test", "[p25][kmm_cmac]") { +TEST_CASE("KMM ReKey Command CMAC Test", "[p25][kmm_cmac][cap]") { bool failed = false; INFO("P25 KMM ReKey Test"); @@ -42,7 +44,7 @@ TEST_CASE("KMM ReKey Command CMAC Test", "[p25][kmm_cmac]") { 0x01, 0x00, 0x01, 0x84, 0x28, 0x01, 0x00, 0x00, 0x00, 0x49, 0x83, 0x80, 0x28, 0x9C, 0xF6, 0x35, 0xFB, 0x68, 0xD3, 0x45, 0xD3, 0x4F, 0x62, 0xEF, 0x06, 0x3B, 0xA4, 0xE0, 0x5C, 0xAE, 0x47, 0x56, 0xE7, 0xD3, 0x04, 0x46, 0xD1, 0xF0, 0x7C, 0x6E, 0xB4, 0xE9, 0xE0, 0x84, 0x09, 0x45, 0x37, 0x23, - 0x72, 0xFB, 0x80, 0x21, 0x85, 0x22, 0x33, 0x41, 0xD9, 0x8A, 0x97, 0x08, 0x84, 0x2F, 0x62, 0x41 + 0x72, 0xFB, 0x80, 0xA2, 0xC1, 0xCC, 0xD1, 0x42, 0x01, 0x73, 0x8C, 0x08, 0x84, 0x2F, 0x62, 0x41 }; // Encrypted Key Frame @@ -104,3 +106,92 @@ TEST_CASE("KMM ReKey Command CMAC Test", "[p25][kmm_cmac]") { REQUIRE(failed==false); } + +TEST_CASE("KMM Hello CMAC Test (No Message Number)", "[p25][kmm_cmac][cap]") { + bool failed = false; + + // MAC TEK + uint8_t macTek[] = + { + 0x16, 0x85, 0x62, 0x45, 0x3B, 0x3E, 0x7F, 0x61, 0x8D, 0x68, 0xB3, 0x87, 0xE0, 0xB9, 0x97, 0xE1, + 0xFB, 0x0F, 0x26, 0x4F, 0xA8, 0x3B, 0x74, 0xE4, 0x3B, 0x17, 0x29, 0x17, 0xBD, 0x39, 0x33, 0x9F + }; + + // AACA-D Sec 14.3 Hello CMAC vector (no MN) + uint8_t expectedFrame[] = + { + 0x0C, 0x00, 0x15, 0x08, 0x64, 0x3B, 0xA8, 0x71, 0x2B, 0x1D, 0x00, 0x18, 0x21, 0x6A, 0xD9, 0x1E, + 0x3E, 0xD5, 0xAC, 0x08, 0x84, 0x2F, 0x62, 0x41 + }; + + uint8_t frameForMac[] = + { + 0x0C, 0x00, 0x15, 0x08, 0x64, 0x3B, 0xA8, 0x71, 0x2B, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x84, 0x2F, 0x62, 0x41 + }; + + P25Crypto crypto; + UInt8Array macKey = crypto.cryptAES_KMM_CMAC_KDF(macTek, frameForMac, (uint16_t)sizeof(frameForMac), false); + UInt8Array mac = crypto.cryptAES_KMM_CMAC(macKey.get(), frameForMac, (uint16_t)sizeof(frameForMac)); + + ::memcpy(frameForMac + 11U, mac.get(), 8U); + + for (uint32_t i = 0; i < sizeof(expectedFrame); i++) { + if (frameForMac[i] != expectedFrame[i]) { + ::LogError("T", "P25_KMM_Hello_CMAC_Test, INVALID AT IDX %d", i); + failed = true; + } + } + + REQUIRE(failed==false); +} + +TEST_CASE("KMM Rekey Encodes Message Number Zero When Present", "[p25][kmm_cmac][cap]") { + // Verify explicit MN presence works even when the message number value is zero. + KMMRekeyCommand outKmm = KMMRekeyCommand(); + + outKmm.setDecryptInfoFmt(KMM_DECRYPT_INSTRUCT_NONE); + outKmm.setSrcLLId(0x712B1DU); + outKmm.setDstLLId(0x643BA8U); + + outKmm.setMACType(KMM_MAC::ENH_MAC); + outKmm.setMACAlgId(ALGO_AES_256); + outKmm.setMACKId(0x2F62U); + outKmm.setMACFormat(KMM_MAC_FORMAT_CMAC); + + outKmm.setHasMessageNumber(true); + outKmm.setMessageNumber(0x0000U); + + outKmm.setAlgId(ALGO_AES_256); + outKmm.setKId(0x50BCU); + + KeysetItem ks; + ks.keysetId(1U); + ks.algId(ALGO_AES_256); + ks.keyLength(P25DEF::MAX_WRAPPED_ENC_KEY_LENGTH_BYTES); + + p25::kmm::KeyItem ki = p25::kmm::KeyItem(); + ki.keyFormat(0U); + ki.sln(0U); + ki.kId(0x4983U); + + uint8_t testWrappedKeyFrame[40U] = + { + 0x80, 0x28, 0x9C, 0xF6, 0x35, 0xFB, 0x68, 0xD3, 0x45, 0xD3, 0x4F, 0x62, 0xEF, 0x06, 0x3B, 0xA4, + 0xE0, 0x5C, 0xAE, 0x47, 0x56, 0xE7, 0xD3, 0x04, 0x46, 0xD1, 0xF0, 0x7C, 0x6E, 0xB4, 0xE9, 0xE0, + 0x84, 0x09, 0x45, 0x37, 0x23, 0x72, 0xFB, 0x80 + }; + ki.setKey(testWrappedKeyFrame, 40U); + ks.push_back(ki); + + std::vector keysets; + keysets.push_back(ks); + outKmm.setKeysets(keysets); + + UInt8Array kmmFrame = std::make_unique(outKmm.fullLength()); + outKmm.encode(kmmFrame.get()); + + REQUIRE((kmmFrame.get()[3U] & 0x30U) == 0x20U); + REQUIRE(kmmFrame.get()[10U] == 0x00U); + REQUIRE(kmmFrame.get()[11U] == 0x00U); +} diff --git a/tests/p25/P2_VCH_MACPDU_Test.cpp b/tests/p25/P2_VCH_MACPDU_Test.cpp index 415e7f4b..7393043f 100644 --- a/tests/p25/P2_VCH_MACPDU_Test.cpp +++ b/tests/p25/P2_VCH_MACPDU_Test.cpp @@ -24,7 +24,7 @@ using namespace p25::lc; #include #include -TEST_CASE("P25 Phase 2 VCH MAC PDU I-OEMI (RS 52,30,23) Test", "[p25][p2_vch_macpdu_ioemi]") { +TEST_CASE("P25 Phase 2 VCH MAC PDU I-OEMI (RS 52,30,23) Test", "[p25][p2_vch_macpdu_ioemi][cap]") { bool failed = false; INFO("P25 Phase 2 VCH MAC PDU I-OEMI RS (52,30,23) FEC Test"); @@ -102,7 +102,7 @@ TEST_CASE("P25 Phase 2 VCH MAC PDU I-OEMI (RS 52,30,23) Test", "[p25][p2_vch_mac REQUIRE(failed == false); } -TEST_CASE("P25 Phase 2 VCH MAC PDU S-OEMI (RS 45,26,20) Test", "[p25][p2_vch_macpdu_soemi]") { +TEST_CASE("P25 Phase 2 VCH MAC PDU S-OEMI (RS 45,26,20) Test", "[p25][p2_vch_macpdu_soemi][cap]") { bool failed = false; INFO("P25 Phase 2 VCH MAC PDU S-OEMI RS (45,26,20) FEC Test"); @@ -177,7 +177,7 @@ TEST_CASE("P25 Phase 2 VCH MAC PDU S-OEMI (RS 45,26,20) Test", "[p25][p2_vch_mac REQUIRE(failed == false); } -TEST_CASE("P25 Phase 2 VCH MAC PDU Round-Trip I-OEMI Test", "[p25][p2_vch_macpdu_roundtrip_ioemi]") { +TEST_CASE("P25 Phase 2 VCH MAC PDU Round-Trip I-OEMI Test", "[p25][p2_vch_macpdu_roundtrip_ioemi][cap]") { bool failed = false; INFO("P25 Phase 2 VCH MAC PDU I-OEMI Round-Trip Test"); @@ -231,7 +231,7 @@ TEST_CASE("P25 Phase 2 VCH MAC PDU Round-Trip I-OEMI Test", "[p25][p2_vch_macpdu REQUIRE(failed == false); } -TEST_CASE("P25 Phase 2 VCH MAC PDU Round-Trip S-OEMI Test", "[p25][p2_vch_macpdu_roundtrip_soemi]") { +TEST_CASE("P25 Phase 2 VCH MAC PDU Round-Trip S-OEMI Test", "[p25][p2_vch_macpdu_roundtrip_soemi][cap]") { bool failed = false; INFO("P25 Phase 2 VCH MAC PDU S-OEMI Round-Trip Test");