mplement experimental support to AES-256 encrypt the network connection; cleanup some instances where buffers were not being cleaned up properly; cleanup some of the AESCrypto implementation; remove references to some little used compiler macros;

pull/48/head
Bryan Biedenkapp 2 years ago
parent 3e0c5148e4
commit 8ff7067eca

@ -45,6 +45,13 @@ network:
# FNE access password.
password: "PASSWORD"
# Flag indicating whether or not host endpoint networking is encrypted.
encrypted: false
# AES-256 32-byte Preshared Key
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# Maximum allowable DMR network jitter.
jitter: 360

@ -46,6 +46,13 @@ master:
# Flag indicating whether or not verbose debug logging is enabled.
debug: false
# Flag indicating whether or not master endpoint networking is encrypted.
encrypted: false
# AES-256 32-byte Preshared Key
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
# Flag indicating whether or not DMR traffic will be passed.
allowDMRTraffic: true
# Flag indicating whether or not P25 traffic will be passed.
@ -89,6 +96,13 @@ peers:
# Network Peer ID
peerId: 9000990
# Flag indicating whether or not peer endpoint networking is encrypted.
encrypted: false
# AES-256 32-byte Preshared Key
# (This field *must* be 32 hex bytes in length or 64 characters
# 0 - 9, A - F.)
presharedKey: "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"
#
rxFrequency: 0
#

@ -34,6 +34,8 @@
*/
#include "Defines.h"
#include "AESCrypto.h"
#include "Log.h"
#include "Utils.h"
using namespace crypto;
@ -272,15 +274,15 @@ static const uint8_t INV_CMDS[4][4] = { {14, 11, 13, 9}, {9, 14, 11, 13}, {13, 9
/// </summary>
AES::AES(const AESKeyLength keyLength) {
switch (keyLength) {
case AESKeyLength::AES_128:
case AESKeyLength::AES_128:
this->m_Nk = 4;
this->m_Nr = 10;
break;
case AESKeyLength::AES_192:
case AESKeyLength::AES_192:
this->m_Nk = 6;
this->m_Nr = 12;
break;
case AESKeyLength::AES_256:
case AESKeyLength::AES_256:
this->m_Nk = 8;
this->m_Nr = 14;
break;
@ -296,15 +298,18 @@ AES::AES(const AESKeyLength keyLength) {
/// <returns></returns>
uint8_t* AES::encryptECB(const uint8_t in[], uint32_t inLen, const uint8_t key[])
{
if (inLen % m_blockBytesLen != 0) {
throw std::length_error("Plaintext length must be divisible by " + std::to_string(m_blockBytesLen));
if (inLen % BLOCK_BYTES_LEN != 0) {
LogDebug(LOG_HOST, "AES::encryptECB() Plaintext length must be divisible by %u, inLen = %u", BLOCK_BYTES_LEN, inLen);
return nullptr;
}
uint8_t* out = new uint8_t[inLen];
::memset(out, 0x00U, inLen);
uint8_t* roundKeys = new uint8_t[4 * AES_NB * (m_Nr + 1)];
::memset(roundKeys, 0x00U, 4 * AES_NB * (m_Nr + 1));
keyExpansion(key, roundKeys);
for (uint32_t i = 0; i < inLen; i += m_blockBytesLen) {
for (uint32_t i = 0; i < inLen; i += BLOCK_BYTES_LEN) {
encryptBlock(in + i, out + i, roundKeys);
}
@ -321,15 +326,18 @@ uint8_t* AES::encryptECB(const uint8_t in[], uint32_t inLen, const uint8_t key[]
/// <returns></returns>
uint8_t* AES::decryptECB(const uint8_t in[], uint32_t inLen, const uint8_t key[])
{
if (inLen % m_blockBytesLen != 0) {
throw std::length_error("Plaintext length must be divisible by " + std::to_string(m_blockBytesLen));
if (inLen % BLOCK_BYTES_LEN != 0) {
LogDebug(LOG_HOST, "AES::decryptECB() Plaintext length must be divisible by %u, inLen = %u", BLOCK_BYTES_LEN, inLen);
return nullptr;
}
uint8_t* out = new uint8_t[inLen];
::memset(out, 0x00U, inLen);
uint8_t* roundKeys = new uint8_t[4 * AES_NB * (m_Nr + 1)];
::memset(roundKeys, 0x00U, 4 * AES_NB * (m_Nr + 1));
keyExpansion(key, roundKeys);
for (uint32_t i = 0; i < inLen; i += m_blockBytesLen) {
for (uint32_t i = 0; i < inLen; i += BLOCK_BYTES_LEN) {
decryptBlock(in + i, out + i, roundKeys);
}
@ -347,20 +355,23 @@ uint8_t* AES::decryptECB(const uint8_t in[], uint32_t inLen, const uint8_t key[]
/// <returns></returns>
uint8_t* AES::encryptCBC(const uint8_t in[], uint32_t inLen, const uint8_t key[], const uint8_t* iv)
{
if (inLen % m_blockBytesLen != 0) {
throw std::length_error("Plaintext length must be divisible by " + std::to_string(m_blockBytesLen));
if (inLen % BLOCK_BYTES_LEN != 0) {
LogDebug(LOG_HOST, "AES::encryptCBC() Plaintext length must be divisible by %u, inLen = %u", BLOCK_BYTES_LEN, inLen);
return nullptr;
}
uint8_t* out = new uint8_t[inLen];
uint8_t block[m_blockBytesLen];
::memset(out, 0x00U, inLen);
uint8_t block[BLOCK_BYTES_LEN];
uint8_t* roundKeys = new uint8_t[4 * AES_NB * (m_Nr + 1)];
::memset(roundKeys, 0x00U, 4 * AES_NB * (m_Nr + 1));
keyExpansion(key, roundKeys);
memcpy(block, iv, m_blockBytesLen);
for (uint32_t i = 0; i < inLen; i += m_blockBytesLen) {
xorBlocks(block, in + i, block, m_blockBytesLen);
memcpy(block, iv, BLOCK_BYTES_LEN);
for (uint32_t i = 0; i < inLen; i += BLOCK_BYTES_LEN) {
xorBlocks(block, in + i, block, BLOCK_BYTES_LEN);
encryptBlock(block, out + i, roundKeys);
memcpy(block, out + i, m_blockBytesLen);
memcpy(block, out + i, BLOCK_BYTES_LEN);
}
delete[] roundKeys;
@ -377,20 +388,23 @@ uint8_t* AES::encryptCBC(const uint8_t in[], uint32_t inLen, const uint8_t key[]
/// <returns></returns>
uint8_t* AES::decryptCBC(const uint8_t in[], uint32_t inLen, const uint8_t key[], const uint8_t *iv)
{
if (inLen % m_blockBytesLen != 0) {
throw std::length_error("Plaintext length must be divisible by " + std::to_string(m_blockBytesLen));
if (inLen % BLOCK_BYTES_LEN != 0) {
LogDebug(LOG_HOST, "AES::decryptCBC() Plaintext length must be divisible by %u, inLen = %u", BLOCK_BYTES_LEN, inLen);
return nullptr;
}
uint8_t* out = new uint8_t[inLen];
uint8_t block[m_blockBytesLen];
::memset(out, 0x00U, inLen);
uint8_t block[BLOCK_BYTES_LEN];
uint8_t* roundKeys = new uint8_t[4 * AES_NB * (m_Nr + 1)];
::memset(roundKeys, 0x00U, 4 * AES_NB * (m_Nr + 1));
keyExpansion(key, roundKeys);
memcpy(block, iv, m_blockBytesLen);
for (uint32_t i = 0; i < inLen; i += m_blockBytesLen) {
memcpy(block, iv, BLOCK_BYTES_LEN);
for (uint32_t i = 0; i < inLen; i += BLOCK_BYTES_LEN) {
decryptBlock(in + i, out + i, roundKeys);
xorBlocks(block, out + i, out + i, m_blockBytesLen);
memcpy(block, in + i, m_blockBytesLen);
xorBlocks(block, out + i, out + i, BLOCK_BYTES_LEN);
memcpy(block, in + i, BLOCK_BYTES_LEN);
}
delete[] roundKeys;
@ -407,21 +421,24 @@ uint8_t* AES::decryptCBC(const uint8_t in[], uint32_t inLen, const uint8_t key[]
/// <returns></returns>
uint8_t* AES::encryptCFB(const uint8_t in[], uint32_t inLen, const uint8_t key[], const uint8_t *iv)
{
if (inLen % m_blockBytesLen != 0) {
throw std::length_error("Plaintext length must be divisible by " + std::to_string(m_blockBytesLen));
if (inLen % BLOCK_BYTES_LEN != 0) {
LogDebug(LOG_HOST, "AES::encryptCFB() Plaintext length must be divisible by %u, inLen = %u", BLOCK_BYTES_LEN, inLen);
return nullptr;
}
uint8_t* out = new uint8_t[inLen];
uint8_t block[m_blockBytesLen];
uint8_t encryptedBlock[m_blockBytesLen];
::memset(out, 0x00U, inLen);
uint8_t block[BLOCK_BYTES_LEN];
uint8_t encryptedBlock[BLOCK_BYTES_LEN];
uint8_t* roundKeys = new uint8_t[4 * AES_NB * (m_Nr + 1)];
::memset(roundKeys, 0x00U, 4 * AES_NB * (m_Nr + 1));
keyExpansion(key, roundKeys);
memcpy(block, iv, m_blockBytesLen);
for (uint32_t i = 0; i < inLen; i += m_blockBytesLen) {
memcpy(block, iv, BLOCK_BYTES_LEN);
for (uint32_t i = 0; i < inLen; i += BLOCK_BYTES_LEN) {
encryptBlock(block, encryptedBlock, roundKeys);
xorBlocks(in + i, encryptedBlock, out + i, m_blockBytesLen);
memcpy(block, out + i, m_blockBytesLen);
xorBlocks(in + i, encryptedBlock, out + i, BLOCK_BYTES_LEN);
memcpy(block, out + i, BLOCK_BYTES_LEN);
}
delete[] roundKeys;
@ -438,21 +455,24 @@ uint8_t* AES::encryptCFB(const uint8_t in[], uint32_t inLen, const uint8_t key[]
/// <returns></returns>
uint8_t* AES::decryptCFB(const uint8_t in[], uint32_t inLen, const uint8_t key[], const uint8_t *iv)
{
if (inLen % m_blockBytesLen != 0) {
throw std::length_error("Plaintext length must be divisible by " + std::to_string(m_blockBytesLen));
if (inLen % BLOCK_BYTES_LEN != 0) {
LogDebug(LOG_HOST, "AES::decryptCFB() Plaintext length must be divisible by %u, inLen = %u", BLOCK_BYTES_LEN, inLen);
return nullptr;
}
uint8_t* out = new uint8_t[inLen];
uint8_t block[m_blockBytesLen];
uint8_t encryptedBlock[m_blockBytesLen];
::memset(out, 0x00U, inLen);
uint8_t block[BLOCK_BYTES_LEN];
uint8_t encryptedBlock[BLOCK_BYTES_LEN];
uint8_t* roundKeys = new uint8_t[4 * AES_NB * (m_Nr + 1)];
::memset(roundKeys, 0x00U, 4 * AES_NB * (m_Nr + 1));
keyExpansion(key, roundKeys);
memcpy(block, iv, m_blockBytesLen);
for (uint32_t i = 0; i < inLen; i += m_blockBytesLen) {
memcpy(block, iv, BLOCK_BYTES_LEN);
for (uint32_t i = 0; i < inLen; i += BLOCK_BYTES_LEN) {
encryptBlock(block, encryptedBlock, roundKeys);
xorBlocks(in + i, encryptedBlock, out + i, m_blockBytesLen);
memcpy(block, in + i, m_blockBytesLen);
xorBlocks(in + i, encryptedBlock, out + i, BLOCK_BYTES_LEN);
memcpy(block, in + i, BLOCK_BYTES_LEN);
}
delete[] roundKeys;
@ -633,7 +653,7 @@ void AES::xorWords(uint8_t* a, uint8_t* b, uint8_t* c)
/// </summary>
/// <param name="a"></param>
/// <param name="n"></param>
void AES::rcon(uint8_t *a, uint32_t n)
void AES::rCon(uint8_t *a, uint32_t n)
{
uint8_t c = 1;
for (uint32_t i = 0; i < n - 1; i++) {
@ -668,7 +688,7 @@ void AES::keyExpansion(const uint8_t key[], uint8_t w[]) {
if (i / 4 % m_Nk == 0) {
rotWord(temp);
subWord(temp);
this->rcon(rcon, i / (m_Nk * 4));
rCon(rcon, i / (m_Nk * 4));
xorWords(temp, rcon, temp);
} else if (m_Nk > 6 && i / 4 % m_Nk == 4) {
subWord(temp);

@ -74,9 +74,9 @@ namespace crypto
/// <summary></summary>
uint8_t* decryptCFB(const uint8_t in[], uint32_t inLen, const uint8_t key[], const uint8_t* iv);
private:
static constexpr uint32_t m_blockBytesLen = 4 * AES_NB * sizeof(uint8_t);
static constexpr uint32_t BLOCK_BYTES_LEN = 4 * AES_NB * sizeof(uint8_t);
private:
uint32_t m_Nk;
uint32_t m_Nr;
@ -96,7 +96,7 @@ namespace crypto
void rotWord(uint8_t* a);
void xorWords(uint8_t* a, uint8_t* b, uint8_t* c);
void rcon(uint8_t* a, uint32_t n);
void rCon(uint8_t* a, uint32_t n);
void keyExpansion(const uint8_t key[], uint8_t w[]);

@ -173,16 +173,9 @@ inline std::string strtoupper(const std::string value) {
#define new_unique(type, ...) std::unique_ptr<type>(new type(__VA_ARGS__))
/// <summary>Creates a named unique buffer.</summary>
#define __UNIQUE_BUFFER(name, type, length) \
std::unique_ptr<type[]> name = std::unique_ptr<type[]>(new type[length]); \
::memset(name.get(), 0x00U, length);
/// <summary>Unique uint8_t array.</summary>
typedef std::unique_ptr<uint8_t[]> UInt8Array;
/// <summary>Creates a named uint8_t array buffer.</summary>
#define __UNIQUE_UINT8_ARRAY(name, length) __UNIQUE_BUFFER(name, uint8_t, length)
// ---------------------------------------------------------------------------
// Class Declaration
// Implements various helper utilities.

@ -220,7 +220,8 @@ ulong64_t CSBK::toValue(const uint8_t* payload)
/// <returns></returns>
UInt8Array CSBK::fromValue(const ulong64_t value)
{
__UNIQUE_UINT8_ARRAY(payload, DMR_CSBK_LENGTH_BYTES - 4U);
UInt8Array payload = std::unique_ptr<uint8_t[]>(new uint8_t[DMR_CSBK_LENGTH_BYTES - 4U]);
::memset(payload.get(), 0x00U, DMR_CSBK_LENGTH_BYTES - 4U);
// split ulong64_t (8 byte) value into bytes
payload[0U] = (uint8_t)((value >> 56) & 0xFFU);

@ -136,7 +136,7 @@ UInt8Array FrameQueue::read(int& messageLength, sockaddr_storage& address, uint3
// copy message
messageLength = _fneHeader.getMessageLength();
__UNIQUE_UINT8_ARRAY(message, messageLength);
UInt8Array message = std::unique_ptr<uint8_t[]>(new uint8_t[messageLength]);
::memcpy(message.get(), buffer + (RTP_HEADER_LENGTH_BYTES + RTP_EXTENSION_HEADER_LENGTH_BYTES + RTP_FNE_HEADER_LENGTH_BYTES), messageLength);
uint16_t calc = edac::CRC::createCRC16(message.get(), messageLength * 8U);

@ -87,7 +87,7 @@ UInt8Array RawFrameQueue::read(int& messageLength, sockaddr_storage& address, ui
// copy message
messageLength = length;
__UNIQUE_UINT8_ARRAY(message, length);
UInt8Array message = std::unique_ptr<uint8_t[]>(new uint8_t[length]);
::memcpy(message.get(), buffer, length);
return message;

@ -57,8 +57,13 @@ UDPSocket::UDPSocket(const std::string& address, uint16_t port) :
m_address_save(address),
m_port_save(port),
m_isOpen(false),
m_aes(nullptr),
m_isCryptoWrapped(false),
m_presharedKey(nullptr),
m_counter(0U)
{
m_aes = new crypto::AES(crypto::AESKeyLength::AES_256);
m_presharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN];
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
@ -75,8 +80,13 @@ UDPSocket::UDPSocket(uint16_t port) :
m_address_save(),
m_port_save(port),
m_isOpen(false),
m_aes(nullptr),
m_isCryptoWrapped(false),
m_presharedKey(nullptr),
m_counter(0U)
{
m_aes = new crypto::AES(crypto::AESKeyLength::AES_256);
m_presharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN];
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
@ -90,7 +100,10 @@ UDPSocket::UDPSocket(uint16_t port) :
/// </summary>
UDPSocket::~UDPSocket()
{
/* stub */
if (m_aes != nullptr)
delete m_aes;
if (m_presharedKey != nullptr)
delete[] m_presharedKey;
}
/// <summary>
@ -233,6 +246,36 @@ int UDPSocket::read(uint8_t* buffer, uint32_t length, sockaddr_storage& address,
return -1;
}
// are we crypto wrapped?
if (m_isCryptoWrapped) {
// does the network packet contain the appropriate magic leader?
uint16_t magic = __GET_UINT16B(buffer, 0U);
if (magic == AES_WRAPPED_PCKT_MAGIC) {
uint32_t cryptedLen = (len - 2U) * sizeof(uint8_t);
// Utils::dump(1U, "UDPSocket::read() crypted", buffer + 2U, cryptedLen);
// decrypt
uint8_t* decrypted = m_aes->decryptECB(buffer + 2U, cryptedLen, m_presharedKey);
// Utils::dump(1U, "UDPSocket::read() decrypted", decrypted, cryptedLen);
// finalize, cleanup buffers and replace with new
if (decrypted != nullptr) {
::memset(buffer, 0x00U, len);
::memcpy(buffer, decrypted, len - 2U);
delete[] decrypted;
len -= 2U;
} else {
delete[] decrypted;
return 0;
}
}
else {
return 0; // this will effectively discard packets without the packet magic
}
}
m_counter++;
addrLen = size;
return len;
@ -254,11 +297,54 @@ bool UDPSocket::write(const uint8_t* buffer, uint32_t length, const sockaddr_sto
bool result = false;
UInt8Array out = nullptr;
// are we crypto wrapped?
if (m_isCryptoWrapped) {
uint32_t cryptedLen = length * sizeof(uint8_t);
uint8_t* cryptoBuffer = new uint8_t[length];
::memcpy(cryptoBuffer, buffer, length);
// do we need to pad the original buffer to be block aligned?
if (cryptedLen % crypto::AES::BLOCK_BYTES_LEN != 0) {
uint32_t alignment = crypto::AES::BLOCK_BYTES_LEN - (cryptedLen % crypto::AES::BLOCK_BYTES_LEN);
cryptedLen += alignment;
// reallocate buffer and copy
cryptoBuffer = new uint8_t[cryptedLen];
::memset(cryptoBuffer, 0x00U, cryptedLen);
::memcpy(cryptoBuffer, buffer, length);
}
// encrypt
uint8_t* crypted = m_aes->encryptECB(cryptoBuffer, cryptedLen, m_presharedKey);
// Utils::dump(1U, "UDPSocket::write() crypted", crypted, cryptedLen);
// finalize, cleanup buffers and replace with new
out = std::unique_ptr<uint8_t[]>(new uint8_t[cryptedLen + 2U]);
delete[] cryptoBuffer;
if (crypted != nullptr) {
::memcpy(out.get() + 2U, crypted, cryptedLen);
__SET_UINT16B(AES_WRAPPED_PCKT_MAGIC, out.get(), 0U);
delete[] crypted;
} else {
if (lenWritten != nullptr) {
*lenWritten = -1;
}
delete[] crypted;
return false;
}
} else {
out = std::unique_ptr<uint8_t[]>(new uint8_t[length]);
::memcpy(out.get(), buffer, length);
}
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
ssize_t sent = ::sendto(m_fd[i], (char*)buffer, length, 0, (sockaddr*)& address, addrLen);
ssize_t sent = ::sendto(m_fd[i], (char*)out.get(), length, 0, (sockaddr*)& address, addrLen);
if (sent < 0) {
LogError(LOG_NET, "Error returned from sendto, err: %d", errno);
@ -321,6 +407,53 @@ bool UDPSocket::write(BufferVector& buffers, int* lenWritten)
continue;
}
uint32_t length = buffers.at(i)->length;
if (buffers.at(i)->buffer == nullptr) {
LogError(LOG_NET, "discarding buffered message with len = %u, but deleted buffer?", length);
--size;
continue;
}
// are we crypto wrapped?
if (m_isCryptoWrapped) {
uint32_t cryptedLen = length * sizeof(uint8_t);
uint8_t* cryptoBuffer = buffers.at(i)->buffer;
// do we need to pad the original buffer to be block aligned?
if (cryptedLen % crypto::AES::BLOCK_BYTES_LEN != 0) {
uint32_t alignment = crypto::AES::BLOCK_BYTES_LEN - (cryptedLen % crypto::AES::BLOCK_BYTES_LEN);
cryptedLen += alignment;
// reallocate buffer and copy
cryptoBuffer = new uint8_t[cryptedLen];
::memset(cryptoBuffer, 0x00U, cryptedLen);
::memcpy(cryptoBuffer, buffers.at(i)->buffer, length);
}
// encrypt
uint8_t* crypted = m_aes->encryptECB(cryptoBuffer, cryptedLen, m_presharedKey);
delete[] cryptoBuffer;
if (crypted == nullptr) {
--size;
continue;
}
// Utils::dump(1U, "UDPSocket::write() crypted", crypted, cryptedLen);
// finalize
uint8_t out[cryptedLen + 2U];
::memcpy(out + 2U, crypted, cryptedLen);
__SET_UINT16B(AES_WRAPPED_PCKT_MAGIC, out, 0U);
// cleanup buffers and replace with new
delete[] crypted;
//delete buffers[i]->buffer;
buffers[i]->buffer = new uint8_t[cryptedLen + 2U];
::memcpy(buffers[i]->buffer, out, cryptedLen + 2U);
buffers[i]->length = cryptedLen + 2U;
}
chunks[i].iov_len = buffers.at(i)->length;
chunks[i].iov_base = buffers.at(i)->buffer;
sent += buffers.at(i)->length;
@ -393,6 +526,22 @@ void UDPSocket::close(const uint32_t index)
}
}
/// <summary>
/// Sets the preshared encryption key.
/// </summary>
/// <param name="presharedKey"></param>
void UDPSocket::setPresharedKey(const uint8_t* presharedKey)
{
if (presharedKey != nullptr) {
::memset(m_presharedKey, 0x00U, AES_WRAPPED_PCKT_KEY_LEN);
::memcpy(m_presharedKey, presharedKey, AES_WRAPPED_PCKT_KEY_LEN);
m_isCryptoWrapped = true;
} else {
::memset(m_presharedKey, 0x00U, AES_WRAPPED_PCKT_KEY_LEN);
m_isCryptoWrapped = false;
}
}
/// <summary>
/// Helper to lookup a hostname and resolve it to an IP address.
/// </summary>

@ -32,6 +32,7 @@
#define __UDP_SOCKET_H__
#include "common/Defines.h"
#include "common/AESCrypto.h"
#include <string>
#include <vector>
@ -50,6 +51,9 @@
#define UDP_SOCKET_MAX 1
#endif
#define AES_WRAPPED_PCKT_MAGIC 0xC0FEU
#define AES_WRAPPED_PCKT_KEY_LEN 32
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
@ -130,6 +134,9 @@ namespace network
/// <summary>Closes the UDP socket connection.</summary>
void close(const uint32_t index);
/// <summary>Sets the preshared encryption key.</summary>
void setPresharedKey(const uint8_t* presharedKey);
/// <summary>Flag indicating the UDP socket(s) are open.</summary>
bool isOpen() const { return m_isOpen; }
@ -159,6 +166,10 @@ namespace network
uint32_t m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
crypto::AES* m_aes;
bool m_isCryptoWrapped;
uint8_t* m_presharedKey;
uint32_t m_counter;
};
} // namespace network

@ -150,7 +150,8 @@ ulong64_t TDULC::toValue(const uint8_t* payload)
/// <returns></returns>
UInt8Array TDULC::fromValue(const ulong64_t value)
{
__UNIQUE_UINT8_ARRAY(payload, P25_TDULC_PAYLOAD_LENGTH_BYTES);
UInt8Array payload = std::unique_ptr<uint8_t[]>(new uint8_t[P25_TDULC_PAYLOAD_LENGTH_BYTES]);
::memset(payload.get(), 0x00U, P25_TDULC_PAYLOAD_LENGTH_BYTES);
// split ulong64_t (8 byte) value into bytes
payload[0U] = (uint8_t)((value >> 56) & 0xFFU);

@ -195,7 +195,8 @@ ulong64_t TSBK::toValue(const uint8_t* payload)
/// <returns></returns>
UInt8Array TSBK::fromValue(const ulong64_t value)
{
__UNIQUE_UINT8_ARRAY(payload, P25_TSBK_LENGTH_BYTES - 4U);
UInt8Array payload = std::unique_ptr<uint8_t[]>(new uint8_t[P25_TSBK_LENGTH_BYTES - 4U]);
::memset(payload.get(), 0x00U, P25_TSBK_LENGTH_BYTES - 4U);
// split ulong64_t (8 byte) value into bytes
payload[0U] = (uint8_t)((value >> 56) & 0xFFU);

@ -395,6 +395,38 @@ bool HostFNE::createMasterNetwork()
bool verbose = masterConf["verbose"].as<bool>(false);
bool debug = masterConf["debug"].as<bool>(false);
bool encrypted = masterConf["encrypted"].as<bool>(false);
std::string key = masterConf["presharedKey"].as<std::string>();
uint8_t presharedKey[AES_WRAPPED_PCKT_KEY_LEN];
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 master network 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();
::memset(presharedKey, 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};
presharedKey[i] = (uint8_t)::strtoul(t, NULL, 16);
keyPtr += 2 * sizeof(char);
}
}
else {
LogWarning(LOG_HOST, "Invalid characters in the master network preshared encryption key. Encryption disabled.");
encrypted = false;
}
}
else {
LogWarning(LOG_HOST, "Invalid master network preshared encryption key length, key should be 32 hex pairs, or 64 characters. Encryption disabled.");
encrypted = false;
}
}
if (id > 999999999U) {
::LogError(LOG_HOST, "Network Peer ID cannot be greater then 999999999.");
return false;
@ -421,6 +453,8 @@ bool HostFNE::createMasterNetwork()
LogInfo(" Parrot Repeat Delay: %u ms", parrotDelay);
LogInfo(" Parrot Grant Demand: %s", parrotGrantDemand ? "yes" : "no");
LogInfo(" Encrypted: %s", encrypted ? "yes" : "no");
if (verbose) {
LogInfo(" Verbose: yes");
}
@ -447,6 +481,10 @@ bool HostFNE::createMasterNetwork()
return false;
}
if (encrypted) {
m_network->setPresharedKey(presharedKey);
}
return true;
}
@ -468,6 +506,38 @@ bool HostFNE::createPeerNetworks()
uint32_t id = peerConf["peerId"].as<uint32_t>(1001U);
bool debug = peerConf["debug"].as<bool>(false);
bool encrypted = peerConf["encrypted"].as<bool>(false);
std::string key = peerConf["presharedKey"].as<std::string>();
uint8_t presharedKey[AES_WRAPPED_PCKT_KEY_LEN];
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 peer network 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();
::memset(presharedKey, 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};
presharedKey[i] = (uint8_t)::strtoul(t, NULL, 16);
keyPtr += 2 * sizeof(char);
}
}
else {
LogWarning(LOG_HOST, "Invalid characters in the peer network preshared encryption key. Encryption disabled.");
encrypted = false;
}
}
else {
LogWarning(LOG_HOST, "Invalid peer network preshared encryption key length, key should be 32 hex pairs, or 64 characters. Encryption disabled.");
encrypted = false;
}
}
std::string identity = peerConf["identity"].as<std::string>();
uint32_t rxFrequency = peerConf["rxFrequency"].as<uint32_t>(0U);
uint32_t txFrequency = peerConf["txFrequency"].as<uint32_t>(0U);
@ -475,7 +545,7 @@ bool HostFNE::createPeerNetworks()
float longitude = peerConf["longitude"].as<float>(0.0F);
std::string location = peerConf["location"].as<std::string>();
::LogInfoEx(LOG_HOST, "Peer ID %u Master Address %s Master Port %u Identity %s Enabled %u", id, masterAddress.c_str(), masterPort, identity.c_str(), enabled);
::LogInfoEx(LOG_HOST, "Peer ID %u Master Address %s Master Port %u Identity %s Enabled %u Encrypted %u", id, masterAddress.c_str(), masterPort, identity.c_str(), enabled, encrypted);
if (id > 999999999U) {
::LogError(LOG_HOST, "Network Peer ID cannot be greater then 999999999.");
@ -485,6 +555,9 @@ bool HostFNE::createPeerNetworks()
// initialize networking
network::PeerNetwork* network = new PeerNetwork(masterAddress, masterPort, 0U, id, password, true, debug, m_dmrEnabled, m_p25Enabled, m_nxdnEnabled, true, true, m_allowActivityTransfer, m_allowDiagnosticTransfer, false);
network->setMetadata(identity, rxFrequency, txFrequency, 0.0F, 0.0F, 0, 0, 0, latitude, longitude, 0, location);
if (encrypted) {
m_network->setPresharedKey(presharedKey);
}
network->enable(enabled);
if (enabled) {

@ -124,6 +124,14 @@ void FNENetwork::setLookups(lookups::RadioIdLookup* ridLookup, lookups::Talkgrou
m_tidLookup = tidLookup;
}
/// <summary>
/// Sets endpoint preshared encryption key.
/// </summary>
void FNENetwork::setPresharedKey(const uint8_t* presharedKey)
{
m_socket->setPresharedKey(presharedKey);
}
/// <summary>
/// Updates the timer by the passed number of milliseconds.
/// </summary>

@ -170,6 +170,8 @@ namespace network
/// <summary>Sets the instances of the Radio ID and Talkgroup Rules lookup tables.</summary>
void setLookups(lookups::RadioIdLookup* ridLookup, lookups::TalkgroupRulesLookup* tidLookup);
/// <summary>Sets endpoint preshared encryption key.</summary>
void setPresharedKey(const uint8_t* presharedKey);
/// <summary>Updates the timer by the passed number of milliseconds.</summary>
void clock(uint32_t ms);

@ -686,6 +686,38 @@ bool Host::createNetwork()
bool updateLookup = networkConf["updateLookups"].as<bool>(false);
bool debug = networkConf["debug"].as<bool>(false);
bool encrypted = networkConf["encrypted"].as<bool>(false);
std::string key = networkConf["presharedKey"].as<std::string>();
uint8_t presharedKey[AES_WRAPPED_PCKT_KEY_LEN];
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 network 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();
::memset(presharedKey, 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};
presharedKey[i] = (uint8_t)::strtoul(t, NULL, 16);
keyPtr += 2 * sizeof(char);
}
}
else {
LogWarning(LOG_HOST, "Invalid characters in the network preshared encryption key. Encryption disabled.");
encrypted = false;
}
}
else {
LogWarning(LOG_HOST, "Invalid network preshared encryption key length, key should be 32 hex pairs, or 64 characters. Encryption disabled.");
encrypted = false;
}
}
if (id > 999999999U) {
::LogError(LOG_HOST, "Network Peer ID cannot be greater then 999999999.");
return false;
@ -722,6 +754,8 @@ bool Host::createNetwork()
LogInfo(" Allow Diagnostic Log Transfer: %s", allowDiagnosticTransfer ? "yes" : "no");
LogInfo(" Update Lookups: %s", updateLookup ? "yes" : "no");
LogInfo(" Encrypted: %s", encrypted ? "yes" : "no");
if (debug) {
LogInfo(" Debug: yes");
}
@ -746,6 +780,9 @@ bool Host::createNetwork()
if (restApiEnable) {
m_network->setRESTAPIData(restApiPassword, restApiPort);
}
if (encrypted) {
m_network->setPresharedKey(presharedKey);
}
m_network->enable(true);
bool ret = m_network->open();

@ -214,6 +214,14 @@ void Network::setRESTAPIData(const std::string& password, uint16_t port)
m_restApiPort = port;
}
/// <summary>
/// Sets endpoint preshared encryption key.
/// </summary>
void Network::setPresharedKey(const uint8_t* presharedKey)
{
m_socket->setPresharedKey(presharedKey);
}
/// <summary>
/// Updates the timer by the passed number of milliseconds.
/// </summary>

@ -68,6 +68,8 @@ namespace network
uint8_t channelId, uint32_t channelNo, uint32_t power, float latitude, float longitude, int height, const std::string& location);
/// <summary>Sets REST API configuration settings from the modem.</summary>
void setRESTAPIData(const std::string& password, uint16_t port);
/// <summary>Sets endpoint preshared encryption key.</summary>
void setPresharedKey(const uint8_t* presharedKey);
/// <summary>Updates the timer by the passed number of milliseconds.</summary>
void clock(uint32_t ms);

@ -1703,5 +1703,7 @@ void Control::generateLLA_AM1_Parameters()
LogMessage(LOG_P25, "P25, generated LLA AM1 parameters");
}
// cleanup
delete[] KS;
delete aes;
}

@ -639,6 +639,9 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len, std::unique_ptr<lc::
}
}
// cleanup buffers
delete[] XRES1;
if (!authFailed) {
writeRF_TSDU_U_Reg_Rsp(srcId, tsbk->getSysId());
}

@ -0,0 +1,83 @@
/**
* Digital Voice Modem - Host Software (Test Suite)
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software / Test Suite
*
*/
/*
* Copyright (C) 2023 Bryan Biedenkapp N2PLL
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#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 Test]") {
SECTION("AES_Crypto_Test") {
bool failed = false;
INFO("AES Crypto 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[48] =
{
0x90, 0x56, 0x00, 0x00, 0x2D, 0x75, 0xE6, 0x8D, 0x00, 0x89, 0x69, 0xCF, 0x00, 0xFE, 0x00, 0x04,
0x4F, 0xC7, 0x60, 0xFF, 0x30, 0x3E, 0x2B, 0xAD, 0x00, 0x89, 0x69, 0xCF, 0x00, 0x00, 0x00, 0x08,
0x52, 0x50, 0x54, 0x4C, 0x00, 0x89, 0x69, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// perform crypto
AES* aes = new AES(AESKeyLength::AES_256);
Utils::dump(2U, "AES_Crypto_Test, Message", message, 48);
uint8_t* crypted = aes->encryptECB(message, 48 * sizeof(uint8_t), K);
Utils::dump(2U, "AES_Crypto_Test, Encrypted", crypted, 48);
uint8_t* decrypted = aes->decryptECB(crypted, 48 * sizeof(uint8_t), K);
Utils::dump(2U, "AES_Crypto_Test, Decrypted", decrypted, 48);
for (uint32_t i = 0; i < 48U; i++) {
if (decrypted[i] != message[i]) {
::LogDebug("T", "AES_Crypto_Test, INVALID AT IDX %d\n", i);
failed = true;
}
}
delete aes;
REQUIRE(failed==false);
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.