add proper support for P25 P2 MAC scrambling; fix and enhance message number following for KMM frames; correct and fix CMAC rekey calculations;

pull/121/merge
Bryan Biedenkapp 3 weeks ago
parent f4154c462e
commit 391e0068af

@ -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) UInt8Array P25Crypto::cryptAES_KMM_CMAC_KDF(const uint8_t* kek, const uint8_t* msg, uint16_t msgLen, bool hasMN)
{ {
#if defined(ENABLE_SSL) #if defined(ENABLE_SSL)
(void)msgLen;
// O T A R M A C // O T A R M A C
uint8_t label[8U] = { 0x4FU, 0x54U, 0x41U, 0x52U, 0x20U, 0x4DU, 0x41U, 0x43U }; 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; 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; size_t len;
uint8_t tempBuf[TEMP_BUFFER_LEN]; uint8_t tempBuf[TEMP_BUFFER_LEN];
::memset(tempBuf, 0x00U, 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(); ERR_load_crypto_strings();
// create a library context (required for OpenSSL 3.0+) // 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; return nullptr;
} }
// load the KDF algorithm // fetch the HMAC implementation for SP800-108 PRF
EVP_KDF* kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL); EVP_MAC* hmac = EVP_MAC_fetch(libCtx, "HMAC", NULL);
if (!kdf) { if (!hmac) {
LogError(LOG_P25, "EVP_KDF_fetch(), failed to load OpenSSL KDF algorithm: %s", ERR_error_string(ERR_get_error(), NULL)); LogError(LOG_P25, "EVP_MAC_fetch(), failed to fetch OpenSSL HMAC: %s", ERR_error_string(ERR_get_error(), NULL));
OSSL_LIB_CTX_free(libCtx); OSSL_LIB_CTX_free(libCtx);
return nullptr; return nullptr;
} }
// create a context for the MAC operation // create a context for the HMAC operation
EVP_KDF_CTX* ctx = EVP_KDF_CTX_new(kdf); EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(hmac);
if (!ctx) { if (!ctx) {
LogError(LOG_P25, "EVP_KDF_CTX_new(), failed to create a OpenSSL KDF context: %s", ERR_error_string(ERR_get_error(), NULL)); LogError(LOG_P25, "EVP_MAC_CTX_new(), failed to create OpenSSL HMAC context: %s", ERR_error_string(ERR_get_error(), NULL));
EVP_KDF_free(kdf); EVP_MAC_free(hmac);
OSSL_LIB_CTX_free(libCtx); OSSL_LIB_CTX_free(libCtx);
return nullptr; 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 params[] = {
OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC, "HMAC", 0), OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "SHA256", 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_END OSSL_PARAM_END
}; };
// derive MAC key if (!EVP_MAC_init(ctx, kek, MAX_ENC_KEY_LENGTH_BYTES, params)) {
if (EVP_KDF_derive(ctx, tempBuf, MAX_ENC_KEY_LENGTH_BYTES, params) <= 0) { LogError(LOG_P25, "EVP_MAC_init(), failed to initialize HMAC-SHA-256: %s", ERR_error_string(ERR_get_error(), NULL));
LogError(LOG_P25, "EVP_KDF_derive(), failed to derive MAC key: %s", ERR_error_string(ERR_get_error(), NULL)); EVP_MAC_CTX_free(ctx);
EVP_KDF_CTX_free(ctx); EVP_MAC_free(hmac);
EVP_KDF_free(kdf);
OSSL_LIB_CTX_free(libCtx); OSSL_LIB_CTX_free(libCtx);
return nullptr; return nullptr;
} }
EVP_KDF_CTX_free(ctx); if (!EVP_MAC_update(ctx, kdfInput, inputOffset)) {
EVP_KDF_free(kdf); LogError(LOG_P25, "EVP_MAC_update(), failed to update HMAC input: %s", ERR_error_string(ERR_get_error(), NULL));
OSSL_LIB_CTX_free(libCtx); EVP_MAC_CTX_free(ctx);
EVP_MAC_free(hmac);
OSSL_LIB_CTX_free(libCtx);
return nullptr;
}
/** DEBUG REMOVEME */ if (!EVP_MAC_final(ctx, tempBuf, &len, TEMP_BUFFER_LEN)) {
Utils::dump(2U, "tempBuf", tempBuf, 128U); LogError(LOG_P25, "EVP_MAC_final(), failed to finalize HMAC output: %s", ERR_error_string(ERR_get_error(), NULL));
/** DEBUG REMOVEME */ 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<uint8_t[]>(new uint8_t[MAX_ENC_KEY_LENGTH_BYTES]); UInt8Array wrappedKey = std::unique_ptr<uint8_t[]>(new uint8_t[MAX_ENC_KEY_LENGTH_BYTES]);
::memset(wrappedKey.get(), 0x00U, MAX_ENC_KEY_LENGTH_BYTES); ::memset(wrappedKey.get(), 0x00U, MAX_ENC_KEY_LENGTH_BYTES);

@ -42,6 +42,7 @@ KMMFrame::KMMFrame() :
m_macKId(0U), m_macKId(0U),
m_macFormat(0U), m_macFormat(0U),
m_messageNumber(0U), m_messageNumber(0U),
m_hasMessageNumber(false),
m_dstLlId(0U), m_dstLlId(0U),
m_srcLlId(0U), m_srcLlId(0U),
m_complete(true), m_complete(true),
@ -109,7 +110,7 @@ void KMMFrame::generateMAC(uint8_t* kek, uint8_t* data)
case KMM_MAC_FORMAT_CMAC: case KMM_MAC_FORMAT_CMAC:
{ {
// generate intermediate derived key // 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 // generate MAC
UInt8Array mac = crypto.cryptAES_KMM_CMAC(macKey.get(), data, m_messageFullLength); 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 m_respKind = (data[3U] >> 6U) & 0x03U; // Response Kind
bool hasMN = ((data[3U] >> 4U) & 0x03U) == 0x02U; // Message Number Flag bool hasMN = ((data[3U] >> 4U) & 0x03U) == 0x02U; // Message Number Flag
m_hasMessageNumber = hasMN;
m_macType = (data[3U] >> 2U) & 0x03U; // MAC Type m_macType = (data[3U] >> 2U) & 0x03U; // MAC Type
bool done = (data[3U] & 0x01U) == 0x01U; // Done Flag 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_dstLlId = GET_UINT24(data, 4U); // Destination RSI
m_srcLlId = GET_UINT24(data, 7U); // Source RSI m_srcLlId = GET_UINT24(data, 7U); // Source RSI
m_bodyOffset = 0U;
m_messageNumber = 0U;
if (hasMN) { if (hasMN) {
m_bodyOffset = 2U; m_bodyOffset = 2U;
m_messageNumber = GET_UINT16(data, 10U); // Message Number 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 SET_UINT16(m_messageLength, data, 1U); // Message Length
m_messageFullLength = m_messageLength + 3U; m_messageFullLength = m_messageLength + 3U;
bool hasMN = m_hasMessageNumber || (m_messageNumber > 0U);
m_hasMessageNumber = hasMN;
data[3U] = ((m_respKind & 0x03U) << 6U) + // Response Kind 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_macType & 0x03U) << 2U) + // MAC Type
((!m_complete) ? 0x01U : 0x00U); // Done Flag ((!m_complete) ? 0x01U : 0x00U); // Done Flag
SET_UINT24(m_dstLlId, data, 4U); // Destination RSI SET_UINT24(m_dstLlId, data, 4U); // Destination RSI
SET_UINT24(m_srcLlId, data, 7U); // Source 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 SET_UINT16(m_messageNumber, data, 10U); // Message Number
m_bodyOffset = 2U; m_bodyOffset = 2U;
} }
@ -273,6 +281,7 @@ void KMMFrame::copy(const KMMFrame& data)
m_complete = data.m_complete; m_complete = data.m_complete;
m_messageNumber = data.m_messageNumber; m_messageNumber = data.m_messageNumber;
m_hasMessageNumber = data.m_hasMessageNumber;
m_macAlgId = data.m_macAlgId; m_macAlgId = data.m_macAlgId;
m_macKId = data.m_macKId; m_macKId = data.m_macKId;
m_macType = data.m_macType; m_macType = data.m_macType;

@ -74,7 +74,7 @@ namespace p25
virtual uint32_t length() const virtual uint32_t length() const
{ {
uint32_t len = KMM_FRAME_LENGTH; uint32_t len = KMM_FRAME_LENGTH;
if (m_messageNumber > 0U) if (m_hasMessageNumber || m_messageNumber > 0U)
len += 2U; len += 2U;
if (m_macType == P25DEF::KMM_MAC::ENH_MAC) if (m_macType == P25DEF::KMM_MAC::ENH_MAC)
len += P25DEF::KMM_AES_MAC_LENGTH + 5U; len += P25DEF::KMM_AES_MAC_LENGTH + 5U;
@ -154,6 +154,10 @@ namespace p25
* @brief Message Number. * @brief Message Number.
*/ */
DECLARE_PROTECTED_PROPERTY(uint16_t, messageNumber, MessageNumber); 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. * @brief Destination Logical link ID.

@ -164,8 +164,6 @@ void KMMRekeyCommand::encode(uint8_t* data)
DECLARE_UINT8_ARRAY(keyPayload, keysetItem.keyLength()); DECLARE_UINT8_ARRAY(keyPayload, keysetItem.keyLength());
key.getKey(keyPayload); key.getKey(keyPayload);
Utils::dump(2U, "keyPayload", keyPayload, keysetItem.keyLength());
::memcpy(data + (25U + (m_bodyOffset + offset)), keyPayload, keysetItem.keyLength()); ::memcpy(data + (25U + (m_bodyOffset + offset)), keyPayload, keysetItem.keyLength());
offset += 5U + keyNameLen + keysetItem.keyLength(); offset += 5U + keyNameLen + keysetItem.keyLength();

@ -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); Utils::dump(2U, "P25, LC::decodeVCH_MACPDU_IEMI(), MAC PDU", raw, lengthBytes);
#endif #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); 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 #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); 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); bool b = READ_BIT(raw, i);
WRITE_BIT(data, n, b); WRITE_BIT(data, n, b);
} }
} else { } else {
// encode RS (52,30,23) FEC // encode RS (52,30,23) FEC
m_rs.encode523023(raw); m_rs.encode523023(raw);
@ -760,6 +741,7 @@ void LC::encodeVCH_MACPDU(uint8_t* data, bool sync)
bool b = READ_BIT(raw, i); bool b = READ_BIT(raw, i);
WRITE_BIT(data, n, b); WRITE_BIT(data, n, b);
} }
} }
} }

@ -134,6 +134,7 @@ namespace p25
*/ */
void encodeVCH_MACPDU(uint8_t* data, bool sync); void encodeVCH_MACPDU(uint8_t* data, bool sync);
/** /**
* @brief Helper to determine if the MFId is a standard MFId. * @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. * @returns bool True, if the MFId contained for this LC is standard, otherwise false.
@ -347,6 +348,7 @@ namespace p25
// User Alias data // User Alias data
uint8_t* m_userAlias; uint8_t* m_userAlias;
bool m_gotUserAliasPartA; bool m_gotUserAliasPartA;
bool m_gotUserAlias; bool m_gotUserAlias;
@ -398,6 +400,7 @@ namespace p25
* @param[in] raw * @param[in] raw
*/ */
void encodeP2_DUIDHamming(uint8_t* data, const uint8_t* raw); void encodeP2_DUIDHamming(uint8_t* data, const uint8_t* raw);
}; };
} // namespace lc } // namespace lc
} // namespace p25 } // namespace p25

@ -26,7 +26,7 @@ TEST_CASE("AES MAC CMAC Test", "[aes][mac_cmac]") {
srand((unsigned int)time(NULL)); 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 // MAC TEK
uint8_t macTek[] = uint8_t macTek[] =
@ -38,8 +38,8 @@ TEST_CASE("AES MAC CMAC Test", "[aes][mac_cmac]") {
// expected CMAC key // expected CMAC key
uint8_t expectedCMAC[] = uint8_t expectedCMAC[] =
{ {
0x5F, 0xB2, 0x91, 0xD0, 0x9E, 0xE3, 0x99, 0x1E, 0x13, 0x1A, 0x04, 0xB0, 0xE3, 0xA0, 0xBF, 0x58, 0xC2, 0x4C, 0x24, 0xE4, 0x1A, 0x89, 0xDB, 0x2D, 0xC1, 0x8E, 0xB8, 0x8A, 0x17, 0xE1, 0xA8, 0xF1,
0xB4, 0xA1, 0xCE, 0x46, 0x10, 0x48, 0xEB, 0x14, 0xB4, 0x97, 0xAE, 0x95, 0x22, 0xD0, 0x0D, 0x31 0xFB, 0x55, 0x46, 0x76, 0xAD, 0xE2, 0x44, 0x05, 0x2A, 0x1F, 0x5B, 0xAA, 0x6D, 0x6F, 0xDA, 0xDF
}; };
// data block // 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, 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, 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, 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]; 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); Utils::dump(2U, "P25_MAC_CMAC_Crypto_Test, MAC", mac.get(), 8U);
for (uint32_t i = 0; i < 8U; i++) { for (uint32_t i = 0; i < 8U; i++) {

@ -23,7 +23,7 @@ using namespace p25::kmm;
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
TEST_CASE("KMM ReKey Command CBC Test", "[p25][kmm_cbc]") { TEST_CASE("KMM ReKey Command CBC Test", "[p25][kmm_cbc][cap]") {
bool failed = false; bool failed = false;
INFO("P25 KMM ReKey Test"); INFO("P25 KMM ReKey Test");

@ -9,11 +9,13 @@
*/ */
#include "host/Defines.h" #include "host/Defines.h"
#include "common/p25/P25Defines.h" #include "common/p25/P25Defines.h"
#include "common/p25/Crypto.h"
#include "common/p25/kmm/KMMRekeyCommand.h" #include "common/p25/kmm/KMMRekeyCommand.h"
#include "common/Log.h" #include "common/Log.h"
#include "common/Utils.h" #include "common/Utils.h"
using namespace p25; using namespace p25;
using namespace p25::crypto;
using namespace p25::defines; using namespace p25::defines;
using namespace p25::kmm; using namespace p25::kmm;
@ -21,7 +23,7 @@ using namespace p25::kmm;
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
TEST_CASE("KMM ReKey Command CMAC Test", "[p25][kmm_cmac]") { TEST_CASE("KMM ReKey Command CMAC Test", "[p25][kmm_cmac][cap]") {
bool failed = false; bool failed = false;
INFO("P25 KMM ReKey Test"); 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, 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, 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, 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 // Encrypted Key Frame
@ -104,3 +106,92 @@ TEST_CASE("KMM ReKey Command CMAC Test", "[p25][kmm_cmac]") {
REQUIRE(failed==false); 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<KeysetItem> keysets;
keysets.push_back(ks);
outKmm.setKeysets(keysets);
UInt8Array kmmFrame = std::make_unique<uint8_t[]>(outKmm.fullLength());
outKmm.encode(kmmFrame.get());
REQUIRE((kmmFrame.get()[3U] & 0x30U) == 0x20U);
REQUIRE(kmmFrame.get()[10U] == 0x00U);
REQUIRE(kmmFrame.get()[11U] == 0x00U);
}

@ -24,7 +24,7 @@ using namespace p25::lc;
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
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; bool failed = false;
INFO("P25 Phase 2 VCH MAC PDU I-OEMI RS (52,30,23) FEC Test"); 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); 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; bool failed = false;
INFO("P25 Phase 2 VCH MAC PDU S-OEMI RS (45,26,20) FEC Test"); 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); 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; bool failed = false;
INFO("P25 Phase 2 VCH MAC PDU I-OEMI Round-Trip Test"); 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); 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; bool failed = false;
INFO("P25 Phase 2 VCH MAC PDU S-OEMI Round-Trip Test"); INFO("P25 Phase 2 VCH MAC PDU S-OEMI Round-Trip Test");

Loading…
Cancel
Save

Powered by TurnKey Linux.