implement support to encrypt any TEK data with a preshared key;

pull/121/merge
Bryan Biedenkapp 4 days ago
parent 562fb3cc67
commit 82f0c0c375

@ -70,6 +70,11 @@ network:
# 0 - 9, A - F.)
presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# AES-256 32-byte Preshared Key for peer-based key requests
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
kmfPresharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# Flag indicating whether or not the host diagnostic log will be sent to the network.
allowDiagnosticTransfer: true

@ -98,6 +98,11 @@ network:
# 0 - 9, A - F.)
presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# AES-256 32-byte Preshared Key for peer-based key requests
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
kmfPresharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# Maximum allowable DMR network jitter.
jitter: 360

@ -184,6 +184,12 @@ master:
# Flag indicating whether or not P25 OTAR KMF services will allow RID 0 (broadcast) key requests.
# NOTE: This is used for peer key requests (NOT OTAR REQUESTS).
kmfAllowRID0: false
# Flag indicating whether or not P25 OTAR KMF services will encrypt peer-based key requests.
kmfEncKeyRequest: false
# AES-256 32-byte Preshared Key for peer-based key requests
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
kmfPresharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# Flag indicating whether or not verbose debug logging for P25 OTAR KMF services is enabled.
kmfDebug: false

@ -70,6 +70,11 @@ network:
# 0 - 9, A - F.)
presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# AES-256 32-byte Preshared Key for peer-based key requests
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
kmfPresharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# Flag indicating whether or not the host diagnostic log will be sent to the network.
allowDiagnosticTransfer: true

@ -1309,6 +1309,44 @@ bool HostBridge::createNetwork()
}
}
bool kmfEncrypted = false;
uint8_t kmfPresharedKey[AES_WRAPPED_PCKT_KEY_LEN];
::memset(kmfPresharedKey, 0x00U, AES_WRAPPED_PCKT_KEY_LEN);
// scope is intentional
{
std::string key = networkConf["kmfPresharedKey"].as<std::string>();
if (!key.empty()) {
if (key.size() == 32) {
// bryanb: shhhhhhh....dirty nasty hacks
key = key.append(key); // since the key is 32 characters (16 hex pairs), double it on itself for 64 characters (32 hex pairs)
LogWarning(LOG_HOST, "Half-length KMF preshared encryption key detected, doubling key on itself.");
}
if (key.size() == 64) {
if ((key.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string::npos)) {
const char* keyPtr = key.c_str();
for (uint8_t i = 0; i < AES_WRAPPED_PCKT_KEY_LEN; i++) {
char t[4] = {keyPtr[0], keyPtr[1], 0};
kmfPresharedKey[i] = (uint8_t)::strtoul(t, NULL, 16);
keyPtr += 2 * sizeof(char);
}
kmfEncrypted = true;
}
else {
LogWarning(LOG_HOST, "Invalid characters in the KMF preshared encryption key. Encryption disabled.");
kmfEncrypted = false;
}
}
else {
LogWarning(LOG_HOST, "Invalid KMF preshared encryption key length, key should be 32 hex pairs, or 64 characters. Encryption disabled.");
kmfEncrypted = false;
}
}
}
if (id > 999999999U) {
::LogError(LOG_HOST, "Network Peer ID cannot be greater then 999999999.");
return false;
@ -1324,6 +1362,8 @@ bool HostBridge::createNetwork()
LogInfo(" Local: random");
LogInfo(" Encrypted: %s", encrypted ? "yes" : "no");
LogInfo(" KMF Encrypted: %s", kmfEncrypted ? "yes" : "no");
LogInfo(" Source ID: %u", m_srcId);
LogInfo(" Destination ID: %u", m_dstId);
LogInfo(" DMR Slot: %u", m_slot);
@ -1371,6 +1411,10 @@ bool HostBridge::createNetwork()
m_network->setPresharedKey(presharedKey);
}
if (kmfEncrypted) {
m_network->setKMFPresharedKey(kmfPresharedKey);
}
m_network->enable(true);
bool ret = m_network->open();
if (!ret) {

@ -98,6 +98,9 @@ namespace network
const uint32_t HA_PARAMS_ENTRY_LEN = 20U;
/** @brief KMM Decryption Instruction - Encrypted Peer Key Response */
const uint8_t KMM_DECRYPT_PEER_ENC = 0x80U;
/**
* @brief Network Peer Connection Status
* @ingroup network_core

@ -11,6 +11,7 @@
#include "common/edac/SHA256.h"
#include "common/p25/kmm/KMMFactory.h"
#include "common/json/json.h"
#include "common/AESCrypto.h"
#include "common/Log.h"
#include "common/Utils.h"
#include "network/Network.h"
@ -62,6 +63,7 @@ Network::Network(const std::string& address, uint16_t port, uint16_t localPort,
m_ridLookup(nullptr),
m_tidLookup(nullptr),
m_salt(nullptr),
m_kmfPresharedKey(nullptr),
m_retryTimer(1000U, DEFAULT_RETRY_TIME),
m_retryCount(0U),
m_maxRetryCount(MAX_RETRY_BEFORE_RECONNECT),
@ -76,6 +78,7 @@ Network::Network(const std::string& address, uint16_t port, uint16_t localPort,
m_promiscuousPeer(false),
m_userHandleProtocol(false),
m_neverDisableOnACLNAK(false),
m_passKeysWithNoPresharedKey(false),
m_peerConnectedCallback(nullptr),
m_peerDisconnectedCallback(nullptr),
m_dmrInCallCallback(nullptr),
@ -109,6 +112,10 @@ Network::Network(const std::string& address, uint16_t port, uint16_t localPort,
Network::~Network()
{
if (m_kmfPresharedKey != nullptr) {
delete[] m_kmfPresharedKey;
m_kmfPresharedKey = nullptr;
}
delete[] m_salt;
delete[] m_rxDMRStreamId;
delete[] m_rxP25P2StreamId;
@ -230,6 +237,14 @@ void Network::setPresharedKey(const uint8_t* presharedKey)
m_socket->setPresharedKey(presharedKey);
}
/* Sets endpoint preshared encryption key. */
void Network::setKMFPresharedKey(const uint8_t* presharedKey)
{
m_kmfPresharedKey = new uint8_t[P25DEF::MAX_ENC_KEY_LENGTH_BYTES];
memcpy(m_kmfPresharedKey, presharedKey, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
}
/* Updates the timer by the passed number of milliseconds. */
void Network::clock(uint32_t ms)
@ -1103,6 +1118,50 @@ void Network::clock(uint32_t ms)
LogInfoEx(LOG_NET, "PEER %u, master reported enc. key, algId = $%02X, kID = $%04X", m_peerId,
ks.algId(), ki.kId());
if (!m_passKeysWithNoPresharedKey && (modifyKey->getDecryptInfoFmt() == KMM_DECRYPT_PEER_ENC)) {
// if the to decrypt the key with a preshared key, do that now
if (m_kmfPresharedKey != nullptr) {
uint8_t encryptedKey[P25DEF::MAX_ENC_KEY_LENGTH_BYTES];
::memset(encryptedKey, 0x00U, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
ki.getKey(encryptedKey);
uint8_t* key = nullptr;
crypto::AES aes = crypto::AES(crypto::AESKeyLength::AES_256);
key = aes.decryptECB(encryptedKey, P25DEF::MAX_ENC_KEY_LENGTH_BYTES, m_kmfPresharedKey);
uint32_t keyLength = P25DEF::MAX_ENC_KEY_LENGTH_BYTES;
switch (ks.algId()) {
case P25DEF::ALGO_DES:
keyLength = P25DEF::DES_ENC_KEY_LENGTH_BYTES;
break;
case P25DEF::ALGO_ARC4:
keyLength = P25DEF::ARC4_ENC_KEY_LENGTH_BYTES;
break;
case P25DEF::ALGO_AES_256:
break;
default:
LogWarning(LOG_NET, "PEER %u, unknown algorithm ID $%02X, unable to determine key length", m_peerId, ks.algId());
break;
}
if (m_debug)
Utils::dump(1U, "Network::clock(), Key", key, keyLength);
if (key != nullptr) {
ki.setKey(key, keyLength);
ks.keyLength(keyLength);
delete[] key;
}
} else {
if (modifyKey->getDecryptInfoFmt() == KMM_DECRYPT_PEER_ENC) {
LogInfoEx(LOG_NET, "PEER %u, received encrypted enc. key, but no preshared key available, algId = $%02X, kID = $%04X", m_peerId,
ks.algId(), ki.kId());
break;
}
}
}
// fire off key response callback if we have one
if (m_keyRespCallback != nullptr) {
m_keyRespCallback(ki, ks.algId(), ks.keyLength());
@ -1270,6 +1329,46 @@ void Network::clock(uint32_t ms)
LogInfoEx(LOG_NET, "PEER %u, master reported LLA enc. key, algId = $%02X, kID = $%04X", m_peerId,
ks.algId(), ki.kId());
if (!m_passKeysWithNoPresharedKey && (modifyKey->getDecryptInfoFmt() == KMM_DECRYPT_PEER_ENC)) {
// if the to decrypt the key with a preshared key, do that now
if (m_kmfPresharedKey != nullptr) {
uint8_t encryptedKey[P25DEF::MAX_ENC_KEY_LENGTH_BYTES];
::memset(encryptedKey, 0x00U, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
ki.getKey(encryptedKey);
uint8_t* key = nullptr;
crypto::AES aes = crypto::AES(crypto::AESKeyLength::AES_256);
key = aes.decryptECB(encryptedKey, P25DEF::MAX_ENC_KEY_LENGTH_BYTES, m_kmfPresharedKey);
uint32_t keyLength = P25DEF::MAX_ENC_KEY_LENGTH_BYTES;
switch (ks.algId()) {
case P25DEF::ALGO_AES_128:
keyLength = P25DEF::AES_128_ENC_KEY_LENGTH_BYTES;
break;
case P25DEF::ALGO_AES_256:
default:
LogWarning(LOG_NET, "PEER %u, unknown algorithm ID $%02X, unable to determine key length", m_peerId, ks.algId());
break;
}
if (m_debug)
Utils::dump(1U, "Network::clock(), Key", key, keyLength);
if (key != nullptr) {
ki.setKey(key, keyLength);
ks.keyLength(keyLength);
delete[] key;
}
} else {
if (modifyKey->getDecryptInfoFmt() == KMM_DECRYPT_PEER_ENC) {
LogInfoEx(LOG_NET, "PEER %u, received encrypted LLA enc. key, but no preshared key available, algId = $%02X, kID = $%04X", m_peerId,
ks.algId(), ki.kId());
break;
}
}
}
// fire off key response callback if we have one
if (m_llaKeyRespCallback != nullptr) {
m_llaKeyRespCallback(modifyKey->getDstLLId(), ki, ks.keyLength());

@ -219,6 +219,11 @@ namespace network
* @param presharedKey Encryption preshared key for networking.
*/
void setPresharedKey(const uint8_t* presharedKey);
/**
* @brief Sets endpoint preshared encryption key for peer key requets.
* @param presharedKey Encryption preshared key for networking.
*/
void setKMFPresharedKey(const uint8_t* presharedKey);
/**
* @brief Updates the timer by the passed number of milliseconds.
@ -329,6 +334,8 @@ namespace network
uint8_t* m_salt;
uint8_t* m_kmfPresharedKey;
Timer m_retryTimer;
uint8_t m_retryCount;
uint8_t m_maxRetryCount;
@ -364,6 +371,10 @@ namespace network
* @brief Flag indicating this peer will not disable networking services on a master ACL NAK.
*/
bool m_neverDisableOnACLNAK;
/**
* @brief Flag indicating this peer will pass encryption keys without a preshared key set.
*/
bool m_passKeysWithNoPresharedKey;
/**
* @brief Peer Connected Function Callback.

@ -170,6 +170,10 @@ namespace p25
const uint8_t AUTH_KEY_LENGTH_BYTES = 16U;
const uint8_t MAX_ENC_KEY_LENGTH_BYTES = 32U;
const uint8_t AES_256_ENC_KEY_LENGTH_BYTES = 32U;
const uint8_t AES_128_ENC_KEY_LENGTH_BYTES = 16U;
const uint8_t DES_ENC_KEY_LENGTH_BYTES = 8U;
const uint8_t ARC4_ENC_KEY_LENGTH_BYTES = 5U;
const uint8_t MAX_WRAPPED_ENC_KEY_LENGTH_BYTES = 40U;
const uint8_t KMM_AES_MAC_LENGTH = 8U;
const uint8_t KMM_DES_MAC_LENGTH = 4U;

@ -71,6 +71,9 @@ PeerNetwork::PeerNetwork(const std::string& address, uint16_t port, uint16_t loc
// never disable peer network services on ACL NAK from master
m_neverDisableOnACLNAK = true;
// allow passing encryption keys without a preshared key set
m_passKeysWithNoPresharedKey = true;
// FNE peer network manually handle protocol packets
m_userHandleProtocol = true;

@ -12,6 +12,7 @@
#include "common/p25/kmm/KMMFactory.h"
#include "common/json/json.h"
#include "common/zlib/Compression.h"
#include "common/AESCrypto.h"
#include "common/Log.h"
#include "common/StopWatch.h"
#include "common/Utils.h"
@ -98,6 +99,7 @@ TrafficNetwork::TrafficNetwork(HostFNE* host, const std::string& address, uint16
m_address(address),
m_port(port),
m_password(password),
m_encryptedTrafficConn(false),
m_isReplica(false),
m_dmrEnabled(dmr),
m_p25Enabled(p25),
@ -110,6 +112,8 @@ TrafficNetwork::TrafficNetwork(HostFNE* host, const std::string& address, uint16
m_parrotOverrideSrcId(0U),
m_kmfServicesEnabled(false),
m_kmfAllowRID0(false),
m_kmfEncKeyRequest(false),
m_kmfPresharedKey(nullptr),
m_ridLookup(nullptr),
m_tidLookup(nullptr),
m_peerListLookup(nullptr),
@ -313,6 +317,43 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions)
#endif // ENABLE_SSL
m_kmfAllowRID0 = conf["kmfAllowRID0"].as<bool>(false);
// scope is intentional
{
bool encrypted = conf["kmfEncKeyRequest"].as<bool>(false);
std::string key = conf["kmfPresharedKey"].as<std::string>();
if (!key.empty()) {
if (key.size() == 32) {
// bryanb: shhhhhhh....dirty nasty hacks
key = key.append(key); // since the key is 32 characters (16 hex pairs), double it on itself for 64 characters (32 hex pairs)
LogWarning(LOG_HOST, "Half-length KMF preshared encryption key detected, doubling key on itself.");
}
if (key.size() == 64) {
if ((key.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string::npos)) {
const char* keyPtr = key.c_str();
m_kmfPresharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN];
::memset(m_kmfPresharedKey, 0x00U, AES_WRAPPED_PCKT_KEY_LEN);
for (uint8_t i = 0; i < AES_WRAPPED_PCKT_KEY_LEN; i++) {
char t[4] = {keyPtr[0], keyPtr[1], 0};
m_kmfPresharedKey[i] = (uint8_t)::strtoul(t, NULL, 16);
keyPtr += 2 * sizeof(char);
}
}
else {
LogWarning(LOG_HOST, "Invalid characters in the KMF preshared encryption key. Encryption disabled.");
encrypted = false;
}
}
else {
LogWarning(LOG_HOST, "Invalid KMF preshared encryption key length, key should be 32 hex pairs, or 64 characters. Encryption disabled.");
encrypted = false;
}
}
m_kmfEncKeyRequest = encrypted;
}
m_callCollisionTimeout = conf["callCollisionTimeout"].as<uint32_t>(5U);
m_restrictGrantToAffOnly = conf["restrictGrantToAffiliatedOnly"].as<bool>(false);
@ -447,6 +488,10 @@ void TrafficNetwork::setOptions(yaml::Node& conf, bool printOptions)
LogInfo(" P25 OTAR KMF Listening Address: %s", m_address.c_str());
LogInfo(" P25 OTAR KMF Listening Port: %u", kmfOtarPort);
LogInfo(" P25 KMF Allow RID 0 Requests: %s", m_kmfAllowRID0 ? "yes" : "no");
LogInfo(" P25 KMF Peer Request Encrypted: %s", m_kmfEncKeyRequest ? "yes" : "no");
if (!m_encryptedTrafficConn && !m_kmfEncKeyRequest) {
LogWarning(LOG_MASTER, "Peers can make key requests, but the encrypted traffic connection is not enabled and KMF requests are not encrypted! Key requests will be sent in the clear.");
}
LogInfo(" High Availability Enabled: %s", m_haEnabled ? "yes" : "no");
if (m_haEnabled) {
LogInfo(" Advertised HA WAN IP: %s", m_advertisedHAAddress.c_str());
@ -471,6 +516,10 @@ void TrafficNetwork::setLookups(lookups::RadioIdLookup* ridLookup, lookups::Talk
void TrafficNetwork::setPresharedKey(const uint8_t* presharedKey)
{
if (presharedKey != nullptr) {
m_encryptedTrafficConn = true;
}
m_socket->setPresharedKey(presharedKey);
}
@ -1920,12 +1969,32 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req)
LogInfoEx(LOG_MASTER, "PEER %u (%s) local enc. key, algId = $%02X, kID = $%04X", peerId, connection->identWithQualifier().c_str(),
modifyKey->getAlgId(), modifyKey->getKId());
// if configured to encrypt the key with a preshared key, do that now
if (network->m_kmfEncKeyRequest) {
uint8_t* encryptedKey = nullptr;
if (network->m_kmfPresharedKey != nullptr) {
crypto::AES aes = crypto::AES(crypto::AESKeyLength::AES_256);
encryptedKey = aes.encryptECB(key, P25DEF::MAX_ENC_KEY_LENGTH_BYTES, network->m_kmfPresharedKey);
if (encryptedKey != nullptr) {
::memcpy(key, encryptedKey, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
keyLength = P25DEF::MAX_ENC_KEY_LENGTH_BYTES;
delete[] encryptedKey;
}
}
if (network->m_debug) {
LogDebugEx(LOG_HOST, "TrafficNetwork::threadedNetworkRx()", "keyLength = %u", keyLength);
Utils::dump(1U, "TrafficNetwork::taskNetworkRx(), Encrypted Key", key, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
}
}
// build response buffer
uint8_t buffer[DATA_PACKET_LENGTH];
::memset(buffer, 0x00U, DATA_PACKET_LENGTH);
KMMModifyKey modifyKeyRsp = KMMModifyKey();
modifyKeyRsp.setDecryptInfoFmt(KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setDecryptInfoFmt(network->m_kmfEncKeyRequest ? KMM_DECRYPT_PEER_ENC : KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setAlgId(modifyKey->getAlgId());
modifyKeyRsp.setKId(0U);
@ -2024,10 +2093,11 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req)
{
KMMModifyKey* modifyKey = static_cast<KMMModifyKey*>(frame.get());
LogDebugEx(LOG_MASTER, "TrafficNetwork::taskNetworkRx()", "PEER %u (%s) LLA enc. key request received, dstLLId = %u, algId = %u, kId = %u", peerId, connection->identWithQualifier().c_str(), modifyKey->getDstLLId(), modifyKey->getAlgId(), modifyKey->getKId());
if (modifyKey->getAlgId() == ALGO_AES_128 && modifyKey->getDstLLId() > 0U) {
LogDebugEx(LOG_MASTER, "TrafficNetwork::taskNetworkRx()", "PEER %u (%s) LLA enc. key request received", peerId, connection->identWithQualifier().c_str());
if (network->m_debug)
LogDebugEx(LOG_MASTER, "TrafficNetwork::taskNetworkRx()", "PEER %u (%s) LLA enc. key request received, dstLLId = %u, algId = %u, kId = %u", peerId, connection->identWithQualifier().c_str(),
modifyKey->getDstLLId(), modifyKey->getAlgId(), modifyKey->getKId());
uint32_t requestingRid = modifyKey->getDstLLId();
LogInfoEx(LOG_MASTER, "PEER %u (%s) requested LLA enc. key, rsi = %u", peerId, connection->identWithQualifier().c_str(),
@ -2039,20 +2109,40 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req)
::memset(key, 0x00U, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
uint8_t keyLength = keyItem.getKey(key);
//if (network->m_debug) {
if (network->m_debug) {
LogDebugEx(LOG_HOST, "TrafficNetwork::threadedNetworkRx()", "keyLength = %u", keyLength);
Utils::dump(1U, "TrafficNetwork::taskNetworkRx(), Key", key, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
//}
}
LogInfoEx(LOG_MASTER, "PEER %u (%s) local enc. key, algId = $%02X, rsi = %u", peerId, connection->identWithQualifier().c_str(),
modifyKey->getAlgId(), requestingRid);
// if configured to encrypt the key with a preshared key, do that now
if (network->m_kmfEncKeyRequest) {
uint8_t* encryptedKey = nullptr;
if (network->m_kmfPresharedKey != nullptr) {
crypto::AES aes = crypto::AES(crypto::AESKeyLength::AES_256);
encryptedKey = aes.encryptECB(key, P25DEF::MAX_ENC_KEY_LENGTH_BYTES, network->m_kmfPresharedKey);
if (encryptedKey != nullptr) {
::memcpy(key, encryptedKey, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
keyLength = P25DEF::MAX_ENC_KEY_LENGTH_BYTES;
delete[] encryptedKey;
}
}
if (network->m_debug) {
LogDebugEx(LOG_HOST, "TrafficNetwork::threadedNetworkRx()", "keyLength = %u", keyLength);
Utils::dump(1U, "TrafficNetwork::taskNetworkRx(), Encrypted Key", key, P25DEF::MAX_ENC_KEY_LENGTH_BYTES);
}
}
// build response buffer
uint8_t buffer[DATA_PACKET_LENGTH];
::memset(buffer, 0x00U, DATA_PACKET_LENGTH);
KMMModifyKey modifyKeyRsp = KMMModifyKey();
modifyKeyRsp.setDecryptInfoFmt(KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setDecryptInfoFmt(network->m_kmfEncKeyRequest ? KMM_DECRYPT_PEER_ENC : KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setAlgId(modifyKey->getAlgId());
modifyKeyRsp.setKId(0U);
modifyKeyRsp.setSrcLLId(WUID_FNE);
@ -3620,7 +3710,7 @@ void TrafficNetwork::processTEKResponse(p25::kmm::KeyItem* rspKi, uint8_t algId,
::memset(buffer, 0x00U, DATA_PACKET_LENGTH);
KMMModifyKey modifyKeyRsp = KMMModifyKey();
modifyKeyRsp.setDecryptInfoFmt(KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setDecryptInfoFmt(m_kmfEncKeyRequest ? KMM_DECRYPT_PEER_ENC : KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setAlgId(algId);
modifyKeyRsp.setKId(0U);
@ -3688,7 +3778,7 @@ void TrafficNetwork::processLLAResponse(uint32_t srcId, p25::kmm::KeyItem* rspKi
::memset(buffer, 0x00U, DATA_PACKET_LENGTH);
KMMModifyKey modifyKeyRsp = KMMModifyKey();
modifyKeyRsp.setDecryptInfoFmt(KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setDecryptInfoFmt(m_kmfEncKeyRequest ? KMM_DECRYPT_PEER_ENC : KMM_DECRYPT_INSTRUCT_NONE);
modifyKeyRsp.setAlgId(ALGO_AES_128);
modifyKeyRsp.setKId(0U);
modifyKeyRsp.setSrcLLId(WUID_FNE);
@ -3714,6 +3804,8 @@ void TrafficNetwork::processLLAResponse(uint32_t srcId, p25::kmm::KeyItem* rspKi
RTP_END_OF_CALL_SEQ, createStreamId());
peersToRemove.push_back(peerId);
} else {
LogError(LOG_PEER, "upstream master LLA enc. key, peerId = %u, requestingRSI = %u, rsi = %u -- mismatch!", entry.first, requestingRid, srcId);
}
}

@ -316,6 +316,8 @@ namespace network
std::string m_password;
bool m_encryptedTrafficConn;
bool m_isReplica;
bool m_dmrEnabled;
@ -331,6 +333,8 @@ namespace network
bool m_kmfServicesEnabled;
bool m_kmfAllowRID0;
bool m_kmfEncKeyRequest;
uint8_t* m_kmfPresharedKey;
lookups::RadioIdLookup* m_ridLookup;
lookups::TalkgroupRulesLookup* m_tidLookup;
@ -351,7 +355,7 @@ namespace network
static std::timed_mutex s_keyQueueMutex;
std::unordered_map<uint32_t, uint16_t> m_peerReplicaKeyQueue;
static std::timed_mutex s_llaKeyQueueMutex;
std::unordered_map<uint32_t, uint16_t> m_peerReplicaLLAKeyQueue;
std::unordered_map<uint32_t, uint32_t> m_peerReplicaLLAKeyQueue;
fne_lookups::AffiliationLookup* m_globalAff;

@ -907,6 +907,44 @@ bool Host::createNetwork()
}
}
bool kmfEncrypted = false;
uint8_t kmfPresharedKey[AES_WRAPPED_PCKT_KEY_LEN];
::memset(kmfPresharedKey, 0x00U, AES_WRAPPED_PCKT_KEY_LEN);
// scope is intentional
{
std::string key = networkConf["kmfPresharedKey"].as<std::string>();
if (!key.empty()) {
if (key.size() == 32) {
// bryanb: shhhhhhh....dirty nasty hacks
key = key.append(key); // since the key is 32 characters (16 hex pairs), double it on itself for 64 characters (32 hex pairs)
LogWarning(LOG_HOST, "Half-length KMF preshared encryption key detected, doubling key on itself.");
}
if (key.size() == 64) {
if ((key.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string::npos)) {
const char* keyPtr = key.c_str();
for (uint8_t i = 0; i < AES_WRAPPED_PCKT_KEY_LEN; i++) {
char t[4] = {keyPtr[0], keyPtr[1], 0};
kmfPresharedKey[i] = (uint8_t)::strtoul(t, NULL, 16);
keyPtr += 2 * sizeof(char);
}
kmfEncrypted = true;
}
else {
LogWarning(LOG_HOST, "Invalid characters in the KMF preshared encryption key. Encryption disabled.");
kmfEncrypted = false;
}
}
else {
LogWarning(LOG_HOST, "Invalid KMF preshared encryption key length, key should be 32 hex pairs, or 64 characters. Encryption disabled.");
kmfEncrypted = false;
}
}
}
if (id > 999999999U) {
::LogError(LOG_HOST, "Network Peer ID cannot be greater then 999999999.");
return false;
@ -959,6 +997,7 @@ bool Host::createNetwork()
LogInfo(" Save Network Lookups: %s", saveLookup ? "yes" : "no");
LogInfo(" Encrypted: %s", encrypted ? "yes" : "no");
LogInfo(" KMF Encrypted: %s", kmfEncrypted ? "yes" : "no");
if (packetDump) {
LogInfo(" Packet Dump: yes");
@ -1006,6 +1045,10 @@ bool Host::createNetwork()
m_network->setPresharedKey(presharedKey);
}
if (kmfEncrypted) {
m_network->setKMFPresharedKey(kmfPresharedKey);
}
m_network->enable(true);
bool ret = m_network->open();
if (!ret) {

@ -519,6 +519,44 @@ bool HostPatch::createNetwork()
}
}
bool kmfEncrypted = false;
uint8_t kmfPresharedKey[AES_WRAPPED_PCKT_KEY_LEN];
::memset(kmfPresharedKey, 0x00U, AES_WRAPPED_PCKT_KEY_LEN);
// scope is intentional
{
std::string key = networkConf["kmfPresharedKey"].as<std::string>();
if (!key.empty()) {
if (key.size() == 32) {
// bryanb: shhhhhhh....dirty nasty hacks
key = key.append(key); // since the key is 32 characters (16 hex pairs), double it on itself for 64 characters (32 hex pairs)
LogWarning(LOG_HOST, "Half-length KMF preshared encryption key detected, doubling key on itself.");
}
if (key.size() == 64) {
if ((key.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string::npos)) {
const char* keyPtr = key.c_str();
for (uint8_t i = 0; i < AES_WRAPPED_PCKT_KEY_LEN; i++) {
char t[4] = {keyPtr[0], keyPtr[1], 0};
kmfPresharedKey[i] = (uint8_t)::strtoul(t, NULL, 16);
keyPtr += 2 * sizeof(char);
}
kmfEncrypted = true;
}
else {
LogWarning(LOG_HOST, "Invalid characters in the KMF preshared encryption key. Encryption disabled.");
kmfEncrypted = false;
}
}
else {
LogWarning(LOG_HOST, "Invalid KMF preshared encryption key length, key should be 32 hex pairs, or 64 characters. Encryption disabled.");
kmfEncrypted = false;
}
}
}
if (id > 999999999U) {
::LogError(LOG_HOST, "Network Peer ID cannot be greater then 999999999.");
return false;
@ -534,6 +572,7 @@ bool HostPatch::createNetwork()
LogInfo(" Local: random");
LogInfo(" Encrypted: %s", encrypted ? "yes" : "no");
LogInfo(" KMF Encrypted: %s", kmfEncrypted ? "yes" : "no");
LogInfo(" Source TGID: %u", m_srcTGId);
LogInfo(" Source DMR Slot: %u", m_srcSlot);
@ -587,6 +626,10 @@ bool HostPatch::createNetwork()
m_network->setPresharedKey(presharedKey);
}
if (kmfEncrypted) {
m_network->setKMFPresharedKey(kmfPresharedKey);
}
m_network->enable(true);
bool ret = m_network->open();
if (!ret) {

@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital Voice Modem - Test Suite
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
*
*/
#include "host/Defines.h"
#include "common/AESCrypto.h"
#include "common/Log.h"
#include "common/Utils.h"
using namespace crypto;
#include <catch2/catch_test_macros.hpp>
#include <stdlib.h>
#include <time.h>
TEST_CASE("AES Crypto Block Test", "[aes][crypto_blocktest]") {
bool failed = false;
INFO("AES Crypto Block Test");
srand((unsigned int)time(NULL));
// key (K)
uint8_t K[32] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
// message
uint8_t message[32] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
// perform crypto
AES* aes = new AES(AESKeyLength::AES_256);
Utils::dump(2U, "AES_Crypto_BlockTest, Message", message, 32);
uint8_t* crypted = aes->encryptECB(message, 32 * sizeof(uint8_t), K);
Utils::dump(2U, "AES_Crypto_BlockTest, Encrypted", crypted, 32);
uint8_t* decrypted = aes->decryptECB(crypted, 32 * sizeof(uint8_t), K);
Utils::dump(2U, "AES_Crypto_BlockTest, Decrypted", decrypted, 32);
for (uint32_t i = 0; i < 32U; i++) {
if (decrypted[i] != message[i]) {
::LogError("T", "AES_Crypto_BlockTest, INVALID AT IDX %d", i);
failed = true;
}
}
delete aes;
REQUIRE(failed==false);
}
Loading…
Cancel
Save

Powered by TurnKey Linux.