/* Copyright (C) 2019 * swift project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, * or distributed except according to the terms contained in the LICENSE file. */ //! \file #ifndef BLACKCORE_AFV_CRYPTO_CRYPTODTO_SERIALIZER_H #define BLACKCORE_AFV_CRYPTO_CRYPTODTO_SERIALIZER_H #include "cryptodtochannel.h" #include "cryptodtomode.h" #include "cryptodtoheaderdto.h" #include "sodium.h" #include #include #include namespace BlackCore { namespace Afv { namespace Crypto { extern QHash gShortDtoNames; //! Crypto serializer class CryptoDtoSerializer { public: CryptoDtoSerializer(); template 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(headerBuffer.buffer().size()); const QByteArray dtoNameBuffer = T::getDtoName(); const QByteArray dtoShortName = T::getShortDtoName(); const quint16 dtoNameLength = static_cast(dtoShortName.size()); QBuffer dtoBuffer; dtoBuffer.open(QIODevice::WriteOnly); msgpack::pack(dtoBuffer, dto); dtoBuffer.close(); const quint16 dtoLength = static_cast(dtoBuffer.buffer().size()); if (header.Mode == CryptoDtoMode::AEAD_ChaCha20Poly1305) { QBuffer aePayloadBuffer; aePayloadBuffer.open(QIODevice::WriteOnly); aePayloadBuffer.write(reinterpret_cast(&dtoNameLength), sizeof(dtoNameLength)); aePayloadBuffer.write(dtoShortName); aePayloadBuffer.write(reinterpret_cast(&dtoLength), sizeof(dtoLength)); aePayloadBuffer.write(dtoBuffer.buffer()); aePayloadBuffer.close(); QBuffer adPayloadBuffer; adPayloadBuffer.open(QIODevice::WriteOnly); adPayloadBuffer.write(reinterpret_cast(&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(&id), sizeof(id)); nonceBuffer.write(reinterpret_cast(&header.Sequence), sizeof(header.Sequence)); nonceBuffer.close(); unsigned long long clen; QByteArray aeadPayload; aeadPayload.fill(0, static_cast(aePayloadBuffer.size() + crypto_aead_chacha20poly1305_IETF_ABYTES)); int result = crypto_aead_chacha20poly1305_ietf_encrypt(reinterpret_cast(aeadPayload.data()), &clen, reinterpret_cast(aePayloadBuffer.buffer().constData()), aePayloadBuffer.size(), reinterpret_cast(adPayloadBuffer.buffer().constData()), adPayloadBuffer.size(), nullptr, reinterpret_cast(nonce.constData()), reinterpret_cast(transmitKey.constData())); if (result != 0) { return {}; } QBuffer packetBuffer; packetBuffer.open(QIODevice::WriteOnly); packetBuffer.write(reinterpret_cast(&headerLength), sizeof(headerLength)); packetBuffer.write(headerBuffer.buffer()); packetBuffer.write(aeadPayload); packetBuffer.close(); return packetBuffer.buffer(); } return {}; } template 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 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(); 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); }; } // ns } // ns } // ns #endif // guard