mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-05 09:15:34 +08:00
AFV initial commit
This commit is contained in:
committed by
Mat Sutcliffe
parent
7030302e73
commit
b5a2f2ad13
128
src/blackcore/afv/crypto/cryptodtochannel.cpp
Normal file
128
src/blackcore/afv/crypto/cryptodtochannel.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include "cryptodtochannel.h"
|
||||
|
||||
CryptoDtoChannel::CryptoDtoChannel(QString channelTag, const QByteArray &aeadReceiveKey, const QByteArray &aeadTransmitKey, int receiveSequenceHistorySize)
|
||||
{
|
||||
ChannelTag = channelTag;
|
||||
m_aeadReceiveKey = aeadReceiveKey;
|
||||
m_aeadTransmitKey = aeadTransmitKey;
|
||||
|
||||
receiveSequenceSizeMaxSize = receiveSequenceHistorySize;
|
||||
if (receiveSequenceSizeMaxSize < 1)
|
||||
receiveSequenceSizeMaxSize = 1;
|
||||
receiveSequenceHistory = new uint[receiveSequenceSizeMaxSize];
|
||||
receiveSequenceHistoryDepth = 0;
|
||||
}
|
||||
|
||||
CryptoDtoChannel::CryptoDtoChannel(CryptoDtoChannelConfigDto channelConfig, int receiveSequenceHistorySize)
|
||||
{
|
||||
ChannelTag = channelConfig.channelTag;
|
||||
m_aeadReceiveKey = channelConfig.aeadReceiveKey;
|
||||
m_aeadTransmitKey = channelConfig.aeadTransmitKey;
|
||||
hmacKey = channelConfig.hmacKey;
|
||||
|
||||
receiveSequenceSizeMaxSize = receiveSequenceHistorySize;
|
||||
if (receiveSequenceSizeMaxSize < 1)
|
||||
receiveSequenceSizeMaxSize = 1;
|
||||
receiveSequenceHistory = new uint[receiveSequenceSizeMaxSize];
|
||||
receiveSequenceHistoryDepth = 0;
|
||||
}
|
||||
|
||||
QByteArray CryptoDtoChannel::getTransmitKey(CryptoDtoMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CryptoDtoMode::AEAD_ChaCha20Poly1305: return m_aeadTransmitKey;
|
||||
case CryptoDtoMode::Undefined:
|
||||
case CryptoDtoMode::None:
|
||||
qFatal("GetTransmitKey called with wrong argument.");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QByteArray CryptoDtoChannel::getTransmitKey(CryptoDtoMode mode, uint &sequenceToSend)
|
||||
{
|
||||
sequenceToSend = transmitSequence;
|
||||
transmitSequence++;
|
||||
LastTransmitUtc = QDateTime::currentDateTimeUtc();
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case CryptoDtoMode::AEAD_ChaCha20Poly1305: return m_aeadTransmitKey;
|
||||
case CryptoDtoMode::Undefined:
|
||||
case CryptoDtoMode::None:
|
||||
qFatal("GetTransmitKey called with wrong argument.");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QString CryptoDtoChannel::getChannelTag() const
|
||||
{
|
||||
return ChannelTag;
|
||||
}
|
||||
|
||||
QByteArray CryptoDtoChannel::getReceiveKey(CryptoDtoMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case CryptoDtoMode::AEAD_ChaCha20Poly1305: return m_aeadReceiveKey;
|
||||
case CryptoDtoMode::Undefined:
|
||||
case CryptoDtoMode::None:
|
||||
qFatal("getReceiveKey called with wrong argument.");
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool CryptoDtoChannel::checkReceivedSequence(uint sequenceReceived)
|
||||
{
|
||||
if (contains(sequenceReceived))
|
||||
{
|
||||
// Duplication or replay attack
|
||||
return false;
|
||||
}
|
||||
|
||||
if (receiveSequenceHistoryDepth < receiveSequenceSizeMaxSize) //If the buffer has been filled...
|
||||
{
|
||||
receiveSequenceHistory[receiveSequenceHistoryDepth++] = sequenceReceived;
|
||||
}
|
||||
else
|
||||
{
|
||||
int minIndex;
|
||||
uint minValue = getMin(minIndex);
|
||||
if (sequenceReceived < minValue) { return false; } // Possible replay attack
|
||||
receiveSequenceHistory[minIndex] = sequenceReceived;
|
||||
}
|
||||
|
||||
LastReceiveUtc = QDateTime::currentDateTimeUtc();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoDtoChannel::contains(uint sequence)
|
||||
{
|
||||
for (int i = 0; i < receiveSequenceHistoryDepth; i++)
|
||||
{
|
||||
if (receiveSequenceHistory[i] == sequence)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint CryptoDtoChannel::getMin(int &minIndex)
|
||||
{
|
||||
uint minValue = std::numeric_limits<uint>::max();
|
||||
minIndex = -1;
|
||||
int index = -1;
|
||||
|
||||
for (int i = 0; i < receiveSequenceHistoryDepth; i++)
|
||||
{
|
||||
index++;
|
||||
if (receiveSequenceHistory[i] <= minValue)
|
||||
{
|
||||
minValue = receiveSequenceHistory[i];
|
||||
minIndex = index;
|
||||
}
|
||||
}
|
||||
return minValue;
|
||||
}
|
||||
47
src/blackcore/afv/crypto/cryptodtochannel.h
Normal file
47
src/blackcore/afv/crypto/cryptodtochannel.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef CRYPTODTOCHANNEL_H
|
||||
#define CRYPTODTOCHANNEL_H
|
||||
|
||||
#include "blackcore/afv/dto.h"
|
||||
#include "cryptodtomode.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QByteArray>
|
||||
|
||||
#include <limits>
|
||||
|
||||
class CryptoDtoChannel
|
||||
{
|
||||
public:
|
||||
|
||||
CryptoDtoChannel(QString channelTag, const QByteArray &aeadReceiveKey, const QByteArray &aeadTransmitKey, int receiveSequenceHistorySize = 10);
|
||||
CryptoDtoChannel(CryptoDtoChannelConfigDto channelConfig, int receiveSequenceHistorySize = 10);
|
||||
|
||||
QByteArray getTransmitKey(CryptoDtoMode mode);
|
||||
QByteArray getTransmitKey(CryptoDtoMode mode, uint &sequenceToSend);
|
||||
QString getChannelTag() const;
|
||||
QByteArray getReceiveKey(CryptoDtoMode mode);
|
||||
|
||||
bool checkReceivedSequence(uint sequenceReceived);
|
||||
|
||||
private:
|
||||
bool contains(uint sequence);
|
||||
uint getMin(int &minIndex);
|
||||
|
||||
|
||||
QByteArray m_aeadTransmitKey;
|
||||
uint transmitSequence = 0;
|
||||
|
||||
QByteArray m_aeadReceiveKey;
|
||||
|
||||
uint *receiveSequenceHistory;
|
||||
int receiveSequenceHistoryDepth;
|
||||
int receiveSequenceSizeMaxSize;
|
||||
|
||||
QByteArray hmacKey;
|
||||
|
||||
QString ChannelTag;
|
||||
QDateTime LastTransmitUtc;
|
||||
QDateTime LastReceiveUtc;
|
||||
};
|
||||
|
||||
#endif // CRYPTODTOCHANNEL_H
|
||||
17
src/blackcore/afv/crypto/cryptodtoheaderdto.h
Normal file
17
src/blackcore/afv/crypto/cryptodtoheaderdto.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef CRYPTODTOHEADERDTO_H
|
||||
#define CRYPTODTOHEADERDTO_H
|
||||
|
||||
#include "cryptodtomode.h"
|
||||
#include "msgpack.hpp"
|
||||
#include <QString>
|
||||
#include <cstdint>
|
||||
|
||||
struct CryptoDtoHeaderDto
|
||||
{
|
||||
std::string ChannelTag;
|
||||
uint64_t Sequence;
|
||||
CryptoDtoMode Mode;
|
||||
MSGPACK_DEFINE(ChannelTag, Sequence, Mode)
|
||||
};
|
||||
|
||||
#endif // CRYPTODTOHEADERDTO_H
|
||||
15
src/blackcore/afv/crypto/cryptodtomode.h
Normal file
15
src/blackcore/afv/crypto/cryptodtomode.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef CRYPTODTOMODE_H
|
||||
#define CRYPTODTOMODE_H
|
||||
|
||||
#include "msgpack.hpp"
|
||||
|
||||
enum class CryptoDtoMode
|
||||
{
|
||||
Undefined = 0,
|
||||
None = 1,
|
||||
AEAD_ChaCha20Poly1305 = 2
|
||||
};
|
||||
|
||||
MSGPACK_ADD_ENUM(CryptoDtoMode);
|
||||
|
||||
#endif // CRYPTODTOMODE_H
|
||||
72
src/blackcore/afv/crypto/cryptodtoserializer.cpp
Normal file
72
src/blackcore/afv/crypto/cryptodtoserializer.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "cryptodtoserializer.h"
|
||||
|
||||
CryptoDtoSerializer::CryptoDtoSerializer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CryptoDtoSerializer::Deserializer CryptoDtoSerializer::deserialize(CryptoDtoChannel &channel, const QByteArray &bytes, bool loopback)
|
||||
{
|
||||
return Deserializer(channel, bytes, loopback);
|
||||
}
|
||||
|
||||
CryptoDtoSerializer::Deserializer::Deserializer(CryptoDtoChannel &channel, const QByteArray &bytes, bool loopback)
|
||||
{
|
||||
QByteArray data(bytes);
|
||||
QBuffer buffer(&data);
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
|
||||
buffer.read((char *)&headerLength, sizeof(headerLength));
|
||||
|
||||
QByteArray headerBuffer = buffer.read(headerLength);
|
||||
|
||||
msgpack::object_handle oh = msgpack::unpack(headerBuffer.data(), headerBuffer.size());
|
||||
header = oh.get().as<CryptoDtoHeaderDto>();
|
||||
|
||||
if(header.Mode == CryptoDtoMode::AEAD_ChaCha20Poly1305)
|
||||
{
|
||||
int aeLength = buffer.size() - (2 + headerLength);
|
||||
const QByteArray aePayloadBuffer = buffer.read(aeLength);
|
||||
|
||||
const QByteArray adBuffer = data.left(2 + headerLength);
|
||||
|
||||
QByteArray nonce;
|
||||
nonce.fill(0, crypto_aead_chacha20poly1305_IETF_NPUBBYTES);
|
||||
QBuffer nonceBuffer(&nonce);
|
||||
nonceBuffer.open(QIODevice::WriteOnly);
|
||||
uint32_t id = 0;
|
||||
nonceBuffer.write(reinterpret_cast<const char *>(&id), sizeof(id));
|
||||
nonceBuffer.write(reinterpret_cast<const char *>(&header.Sequence), sizeof(header.Sequence));
|
||||
nonceBuffer.close();
|
||||
|
||||
QByteArray decryptedPayload;
|
||||
unsigned long long mlen = 500;
|
||||
decryptedPayload.fill(0, mlen);
|
||||
|
||||
QByteArray key;
|
||||
if (loopback) { key = channel.getTransmitKey(CryptoDtoMode::AEAD_ChaCha20Poly1305); }
|
||||
else { key = channel.getReceiveKey(CryptoDtoMode::AEAD_ChaCha20Poly1305); }
|
||||
int result = crypto_aead_chacha20poly1305_ietf_decrypt(reinterpret_cast<unsigned char *>(decryptedPayload.data()), &mlen, nullptr,
|
||||
reinterpret_cast<const unsigned char *>(aePayloadBuffer.constData()), aePayloadBuffer.size(),
|
||||
reinterpret_cast<const unsigned char *>(adBuffer.constData()), adBuffer.size(),
|
||||
reinterpret_cast<const unsigned char *>(nonce.constData()),
|
||||
reinterpret_cast<const unsigned char *>(key.constData()));
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
decryptedPayload.resize(mlen);
|
||||
|
||||
// Fix this:
|
||||
// if (! channel.checkReceivedSequence(header.Sequence)) { }
|
||||
|
||||
QBuffer decryptedPayloadBuffer(&decryptedPayload);
|
||||
decryptedPayloadBuffer.open(QIODevice::ReadOnly);
|
||||
decryptedPayloadBuffer.read((char *)&dtoNameLength, sizeof(dtoNameLength));
|
||||
dtoNameBuffer = decryptedPayloadBuffer.read(dtoNameLength);
|
||||
|
||||
decryptedPayloadBuffer.read((char *)&dataLength, sizeof(dataLength));
|
||||
dataBuffer = decryptedPayloadBuffer.read(dataLength);
|
||||
verified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
132
src/blackcore/afv/crypto/cryptodtoserializer.h
Normal file
132
src/blackcore/afv/crypto/cryptodtoserializer.h
Normal file
@@ -0,0 +1,132 @@
|
||||
#ifndef CRYPTODTOSERIALIZER_H
|
||||
#define CRYPTODTOSERIALIZER_H
|
||||
|
||||
#include "cryptodtochannel.h"
|
||||
#include "cryptodtomode.h"
|
||||
#include "cryptodtoheaderdto.h"
|
||||
#include "sodium.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QBuffer>
|
||||
#include <QtDebug>
|
||||
|
||||
extern QHash<QByteArray, QByteArray> gShortDtoNames;
|
||||
|
||||
class CryptoDtoSerializer
|
||||
{
|
||||
public:
|
||||
CryptoDtoSerializer();
|
||||
|
||||
template<typename T>
|
||||
static QByteArray Serialize(const QString &channelTag, CryptoDtoMode mode, const QByteArray &transmitKey, uint sequenceToBeSent, T dto)
|
||||
{
|
||||
const CryptoDtoHeaderDto header = { channelTag.toStdString(), sequenceToBeSent, mode };
|
||||
|
||||
QBuffer headerBuffer;
|
||||
headerBuffer.open(QIODevice::WriteOnly);
|
||||
msgpack::pack(headerBuffer, header);
|
||||
headerBuffer.close();
|
||||
const quint16 headerLength = static_cast<quint16>(headerBuffer.buffer().size());
|
||||
|
||||
const QByteArray dtoNameBuffer = T::getDtoName();
|
||||
const QByteArray dtoShortName = T::getShortDtoName();
|
||||
const quint16 dtoNameLength = static_cast<quint16>(dtoShortName.size());
|
||||
|
||||
QBuffer dtoBuffer;
|
||||
dtoBuffer.open(QIODevice::WriteOnly);
|
||||
msgpack::pack(dtoBuffer, dto);
|
||||
dtoBuffer.close();
|
||||
const quint16 dtoLength = static_cast<quint16>(dtoBuffer.buffer().size());
|
||||
|
||||
if(header.Mode == CryptoDtoMode::AEAD_ChaCha20Poly1305)
|
||||
{
|
||||
QBuffer aePayloadBuffer;
|
||||
aePayloadBuffer.open(QIODevice::WriteOnly);
|
||||
aePayloadBuffer.write(reinterpret_cast<const char *>(&dtoNameLength), sizeof(dtoNameLength));
|
||||
aePayloadBuffer.write(dtoShortName);
|
||||
aePayloadBuffer.write(reinterpret_cast<const char *>(&dtoLength), sizeof(dtoLength));
|
||||
aePayloadBuffer.write(dtoBuffer.buffer());
|
||||
aePayloadBuffer.close();
|
||||
|
||||
QBuffer adPayloadBuffer;
|
||||
adPayloadBuffer.open(QIODevice::WriteOnly);
|
||||
adPayloadBuffer.write(reinterpret_cast<const char *>(&headerLength), sizeof(headerLength));
|
||||
adPayloadBuffer.write(headerBuffer.buffer());
|
||||
adPayloadBuffer.close();
|
||||
|
||||
QByteArray nonce;
|
||||
nonce.fill(0, crypto_aead_chacha20poly1305_IETF_NPUBBYTES);
|
||||
QBuffer nonceBuffer(&nonce);
|
||||
nonceBuffer.open(QIODevice::WriteOnly);
|
||||
uint32_t id = 0;
|
||||
nonceBuffer.write(reinterpret_cast<const char *>(&id), sizeof(id));
|
||||
nonceBuffer.write(reinterpret_cast<const char *>(&header.Sequence), sizeof(header.Sequence));
|
||||
nonceBuffer.close();
|
||||
|
||||
unsigned long long clen;
|
||||
QByteArray aeadPayload;
|
||||
aeadPayload.fill(0, static_cast<int>(aePayloadBuffer.size() + crypto_aead_chacha20poly1305_IETF_ABYTES));
|
||||
int result = crypto_aead_chacha20poly1305_ietf_encrypt(reinterpret_cast<unsigned char*>(aeadPayload.data()),
|
||||
&clen,
|
||||
reinterpret_cast<const unsigned char*>(aePayloadBuffer.buffer().constData()), aePayloadBuffer.size(),
|
||||
reinterpret_cast<const unsigned char*>(adPayloadBuffer.buffer().constData()), adPayloadBuffer.size(),
|
||||
nullptr,
|
||||
reinterpret_cast<const unsigned char*>(nonce.constData()),
|
||||
reinterpret_cast<const unsigned char*>(transmitKey.constData()));
|
||||
if (result != 0) { return {}; }
|
||||
|
||||
QBuffer packetBuffer;
|
||||
packetBuffer.open(QIODevice::WriteOnly);
|
||||
packetBuffer.write(reinterpret_cast<const char *>(&headerLength), sizeof(headerLength));
|
||||
packetBuffer.write(headerBuffer.buffer());
|
||||
packetBuffer.write(aeadPayload);
|
||||
packetBuffer.close();
|
||||
|
||||
return packetBuffer.buffer();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static QByteArray Serialize(CryptoDtoChannel &channel, CryptoDtoMode mode, T dto)
|
||||
{
|
||||
uint sequenceToSend = 0;
|
||||
QByteArray transmitKey = channel.getTransmitKey(mode, sequenceToSend);
|
||||
return Serialize(channel.getChannelTag(), mode, transmitKey, sequenceToSend++, dto);
|
||||
}
|
||||
|
||||
struct Deserializer
|
||||
{
|
||||
Deserializer(CryptoDtoChannel &channel, const QByteArray &bytes, bool loopback);
|
||||
|
||||
template<typename T>
|
||||
T getDto()
|
||||
{
|
||||
if (! verified) return {};
|
||||
if (dtoNameBuffer == T::getDtoName() || dtoNameBuffer == T::getShortDtoName())
|
||||
{
|
||||
msgpack::object_handle oh2 = msgpack::unpack(dataBuffer.data(), dataBuffer.size());
|
||||
msgpack::object obj = oh2.get();
|
||||
T dto = obj.as<T>();
|
||||
return dto;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
quint16 headerLength;
|
||||
CryptoDtoHeaderDto header;
|
||||
|
||||
quint16 dtoNameLength;
|
||||
QByteArray dtoNameBuffer;
|
||||
|
||||
quint16 dataLength;
|
||||
QByteArray dataBuffer;
|
||||
|
||||
bool verified = false;
|
||||
};
|
||||
|
||||
static Deserializer deserialize(CryptoDtoChannel &channel, const QByteArray &bytes, bool loopback);
|
||||
};
|
||||
|
||||
#endif // CRYPTODTOSERIALIZER_H
|
||||
Reference in New Issue
Block a user