replace UDPSockets preshared AES-ECB implementation with a AES-CBC implementation;

pull/128/head
Bryan Biedenkapp 2 months ago
parent ac9eaa90c4
commit 794e8b71e5

@ -48,7 +48,8 @@ Socket::Socket(const std::string& address, uint16_t port) :
m_aes(nullptr),
m_isCryptoWrapped(false),
m_presharedKey(nullptr),
m_counter(0U)
m_counter(0U),
m_random()
{
m_aes = new crypto::AES(crypto::AESKeyLength::AES_256);
m_presharedKey = new uint8_t[AES_WRAPPED_PCKT_KEY_LEN];
@ -60,6 +61,10 @@ Socket::Socket(const std::string& address, uint16_t port) :
::LogError(LOG_NET, "Error from WSAStartup, err: %d", wsaRet);
}
#endif // defined(_WIN32)
std::random_device rd;
std::mt19937 mt(rd());
m_random = mt;
}
/* Initializes a new instance of the Socket class. */
@ -326,14 +331,19 @@ ssize_t Socket::read(uint8_t* buffer, uint32_t length, sockaddr_storage& address
uint16_t magic = GET_UINT16(buffer, 0U);
if (magic == AES_WRAPPED_PCKT_MAGIC) {
// prevent malicious packets that are too short
if (len < 2U + crypto::AES::BLOCK_BYTES_LEN) {
if (len < (2U + crypto::AES::BLOCK_BYTES_LEN + 16U)) {
LogError(LOG_NET, "Encrypted packet too short");
return -1;
}
uint32_t cryptedLen = (len - 2U) * sizeof(uint8_t);
uint32_t cryptedLen = (len - 18U) * sizeof(uint8_t);
uint8_t* cryptoBuffer = buffer + 2U;
// extract the IV from the end of the packet
uint8_t iv[16U];
::memset(iv, 0x00U, sizeof(iv));
::memcpy(iv, buffer + (len - 16U), 16U);
// 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);
@ -342,23 +352,23 @@ ssize_t Socket::read(uint8_t* buffer, uint32_t length, sockaddr_storage& address
// reallocate buffer and copy
cryptoBuffer = new uint8_t[cryptedLen];
::memset(cryptoBuffer, 0x00U, cryptedLen);
::memcpy(cryptoBuffer, buffer + 2U, len - 2U);
::memcpy(cryptoBuffer, buffer + 2U, len - 18U);
}
// Utils::dump(1U, "Socket::read(), crypted", cryptoBuffer, cryptedLen);
// decrypt
uint8_t* decrypted = m_aes->decryptECB(cryptoBuffer, cryptedLen, m_presharedKey);
uint8_t* decrypted = m_aes->decryptCBC(cryptoBuffer, cryptedLen, m_presharedKey, iv);
// Utils::dump(1U, "Socket::read(), decrypted", decrypted, cryptedLen);
// finalize, cleanup buffers and replace with new
if (decrypted != nullptr) {
::memset(buffer, 0x00U, len);
::memcpy(buffer, decrypted, len - 2U);
::memcpy(buffer, decrypted, cryptedLen);
delete[] decrypted;
len -= 2U;
len = cryptedLen;
} else {
delete[] decrypted;
return 0;
@ -427,25 +437,31 @@ bool Socket::write(const uint8_t* buffer, uint32_t length, const sockaddr_storag
::memcpy(cryptoBuffer, buffer, length);
}
// generate an initialization vector (IV) for CBC mode
uint8_t* iv = generateIV();
// encrypt
uint8_t* crypted = m_aes->encryptECB(cryptoBuffer, cryptedLen, m_presharedKey);
uint8_t* crypted = m_aes->encryptCBC(cryptoBuffer, cryptedLen, m_presharedKey, iv);
// Utils::dump(1U, "Socket::write(), crypted", crypted, cryptedLen);
// finalize, cleanup buffers and replace with new
out = std::unique_ptr<uint8_t[]>(new uint8_t[cryptedLen + 2U]);
out = std::unique_ptr<uint8_t[]>(new uint8_t[cryptedLen + 18U]);
delete[] cryptoBuffer;
if (crypted != nullptr) {
::memcpy(out.get() + 2U, crypted, cryptedLen);
SET_UINT16(AES_WRAPPED_PCKT_MAGIC, out.get(), 0U);
::memcpy(out.get() + 2U + cryptedLen, iv, 16U);
delete[] crypted;
length = cryptedLen + 2U;
delete[] iv;
length = cryptedLen + 18U;
} else {
if (lenWritten != nullptr) {
*lenWritten = -1;
}
delete[] crypted;
delete[] iv;
return false;
}
} else {
@ -613,8 +629,11 @@ bool Socket::write(BufferQueue* buffers, ssize_t* lenWritten) noexcept
::memcpy(cryptoBuffer, iov_buffer, length);
}
// generate an initialization vector (IV) for CBC mode
uint8_t* iv = generateIV();
// encrypt
uint8_t* crypted = m_aes->encryptECB(cryptoBuffer, cryptedLen, m_presharedKey);
uint8_t* crypted = m_aes->encryptCBC(cryptoBuffer, cryptedLen, m_presharedKey, iv);
delete[] cryptoBuffer;
if (crypted == nullptr) {
@ -628,18 +647,20 @@ bool Socket::write(BufferQueue* buffers, ssize_t* lenWritten) noexcept
// Utils::dump(1U, "Socket::write(), crypted", crypted, cryptedLen);
// finalize
DECLARE_UINT8_ARRAY(out, cryptedLen + 2U);
DECLARE_UINT8_ARRAY(out, cryptedLen + 18U);
::memcpy(out + 2U, crypted, cryptedLen);
SET_UINT16(AES_WRAPPED_PCKT_MAGIC, out, 0U);
::memcpy(out + 2U + cryptedLen, iv, 16U);
// cleanup buffers and replace with new
delete[] crypted;
delete[] iv;
crypted = nullptr;
delete[] iov_buffer;
iov_buffer = nullptr;
iov_buffer = new uint8_t[cryptedLen + 2U];
::memcpy(iov_buffer, out, cryptedLen + 2U);
iov_length = cryptedLen + 2U;
iov_buffer = new uint8_t[cryptedLen + 18U];
::memcpy(iov_buffer, out, cryptedLen + 18U);
iov_length = cryptedLen + 18U;
}
// skip if no IOV buffer
@ -1001,4 +1022,57 @@ void Socket::initAddr(const std::string& ipAddr, const int port, sockaddr_in& ad
}
addr.sin_port = htons(port);
}
}
/* Helper to step the linear feedback shift register (LFSR). */
uint64_t Socket::stepLFSR(uint64_t& lfsr)
{
uint64_t ovBit = (lfsr >> 63U) & 0x01U;
// compute feedback bit using polynomial: x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
uint64_t fbBit = ((lfsr >> 63U) ^ (lfsr >> 61U) ^ (lfsr >> 45U) ^ (lfsr >> 37U) ^
(lfsr >> 26U) ^ (lfsr >> 14U)) & 0x01U;
// shift LFSR left and insert feedback bit
lfsr = (lfsr << 1) | fbBit;
return ovBit;
}
/* Helper given to generate a new initial seed IV. */
uint8_t* Socket::generateIV()
{
uint8_t mi[9U];
for (uint8_t i = 0; i < 9U; i++) {
std::uniform_int_distribution<uint32_t> dist(0x00U, 0xFFU);
mi[i] = (uint8_t)dist(m_random);
}
uint8_t* iv = new uint8_t[16U];
::memset(iv, 0x00U, 16U);
// copy first 64-bits of the MI info LFSR
uint64_t lfsr = 0U;
for (uint8_t i = 0U; i < 8U; i++) {
lfsr = (lfsr << 8U) | mi[i];
}
uint64_t overflow = 0U;
for (uint8_t i = 0U; i < 64U; i++) {
overflow = (overflow << 1U) | stepLFSR(lfsr);
}
// copy expansion and LFSR into IV
for (int i = 7; i >= 0; i--) {
iv[i] = (uint8_t)(overflow & 0xFFU);
overflow >>= 8U;
}
for (int i = 15; i >= 8; i--) {
iv[i] = (uint8_t)(lfsr & 0xFFU);
lfsr >>= 8U;
}
return iv;
}

@ -26,6 +26,7 @@
#include <string>
#include <queue>
#include <random>
#if defined(_WIN32)
#pragma comment(lib, "Ws2_32.lib")
@ -347,6 +348,8 @@ namespace network
uint32_t m_counter;
std::mt19937 m_random;
/**
* @brief Internal helper to initialize the socket.
* @param domain Address family type.
@ -370,6 +373,19 @@ namespace network
* @param[out] addr Instance of sockaddr_storage socket address structure.
*/
static void initAddr(const std::string& ipAddr, const int port, sockaddr_in& addr);
/**
* @brief Helper to step the linear feedback shift register (LFSR).
* @note This uses the polynomial: x^64 + x^62 + x^46 + x^38 + x^27 + x^15 + 1
* @param lfsr Linear feedback shift register value.
* @return uint64_t The next LFSR value.
*/
uint64_t stepLFSR(uint64_t& lfsr);
/**
* @brief Helper given to generate a new initial seed IV.
* @returns Pointer to the newly generated IV.
*/
uint8_t* generateIV();
};
} // namespace udp
} // namespace network

@ -215,7 +215,7 @@ UDPDatagram* makeDatagram(const std::string& payload, const sockaddr_storage& ad
size_t encryptedLength(size_t payloadLength)
{
size_t padded = ((payloadLength + crypto::AES::BLOCK_BYTES_LEN - 1U) / crypto::AES::BLOCK_BYTES_LEN) * crypto::AES::BLOCK_BYTES_LEN;
return padded + 2U;
return padded + 18U;
}
/**

Loading…
Cancel
Save

Powered by TurnKey Linux.