From 9d749d20ae01c727e31e657e129e666a297202e2 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 11 Jun 2018 09:25:10 -0400 Subject: [PATCH] encrypted frames --- include/llarp/encrypted.hpp | 30 +++++++++ include/llarp/encrypted_ack.hpp | 14 +++++ include/llarp/encrypted_frame.hpp | 73 +++++++++++++++++----- include/llarp/messages/relay_commit.hpp | 9 +++ llarp/encrypted_frame.cpp | 81 ++++++++++++++++++++----- llarp/link_message.cpp | 6 +- llarp/relay_commit.cpp | 64 ++++++++++++++++++- 7 files changed, 242 insertions(+), 35 deletions(-) create mode 100644 include/llarp/encrypted.hpp create mode 100644 include/llarp/encrypted_ack.hpp diff --git a/include/llarp/encrypted.hpp b/include/llarp/encrypted.hpp new file mode 100644 index 000000000..8341b66f1 --- /dev/null +++ b/include/llarp/encrypted.hpp @@ -0,0 +1,30 @@ +#ifndef LLARP_ENCCRYPTED_HPP +#define LLARP_ENCCRYPTED_HPP + +#include + +namespace llarp +{ + /// encrypted buffer base type + struct Encrypted + { + Encrypted() = default; + Encrypted(const byte_t* buf, size_t sz); + Encrypted(size_t sz); + ~Encrypted(); + + llarp_buffer_t* + Buffer() + { + return &m_Buffer; + } + + byte_t* data = nullptr; + size_t size = 0; + + private: + llarp_buffer_t m_Buffer; + }; +} + +#endif \ No newline at end of file diff --git a/include/llarp/encrypted_ack.hpp b/include/llarp/encrypted_ack.hpp new file mode 100644 index 000000000..2fd157692 --- /dev/null +++ b/include/llarp/encrypted_ack.hpp @@ -0,0 +1,14 @@ +#ifndef LLARP_ENCRYPTED_ACK_HPP +#define LLARP_ENCRYPTED_ACK_HPP +#include +namespace llarp +{ + struct EncryptedAck : public Encrypted + { + bool + DecryptInPlace(const byte_t* symkey, const byte_t* nonce, + llarp_crypto* crypto); + }; +} + +#endif \ No newline at end of file diff --git a/include/llarp/encrypted_frame.hpp b/include/llarp/encrypted_frame.hpp index 7b8a08726..8bc97be5b 100644 --- a/include/llarp/encrypted_frame.hpp +++ b/include/llarp/encrypted_frame.hpp @@ -4,30 +4,73 @@ #include #include #include +#include namespace llarp { - struct EncryptedFrame + struct EncryptedFrame : public Encrypted { - EncryptedFrame(); - EncryptedFrame(const byte_t* buf, size_t sz); - ~EncryptedFrame(); + static constexpr size_t OverheadSize = sizeof(llarp_pubkey_t) + + sizeof(llarp_tunnel_nonce_t) + sizeof(llarp_shorthash_t); + + EncryptedFrame() = default; + EncryptedFrame(byte_t* buf, size_t sz) : Encrypted(buf, sz) + { + } + EncryptedFrame(size_t sz) : Encrypted(sz + OverheadSize) + { + } bool - DecryptInPlace(const byte_t* ourSecretKey, llarp_crypto* crypto); + DecryptInPlace(byte_t* seckey, llarp_crypto* crypto); + + bool + EncryptInPlace(byte_t* seckey, llarp_crypto* crypto); + }; + + /// TOOD: can only handle 1 frame at a time + template < typename User > + struct AsyncFrameEncrypter + { + typedef void (*EncryptHandler)(EncryptedFrame*, User*); - llarp_buffer_t* - Buffer() + static void + Encrypt(void* user) { - return &m_Buffer; + AsyncFrameEncrypter< User >* ctx = + static_cast< AsyncFrameEncrypter< User >* >(user); + + if(ctx->frame->EncryptInPlace(ctx->seckey, ctx->crypto)) + ctx->handler(ctx->frame, ctx->user); + else + { + delete ctx->frame; + ctx->handler(nullptr, ctx->user); + } } - private: - byte_t* m_Buf; - size_t m_Sz; - llarp_buffer_t m_Buffer; + llarp_crypto* crypto; + byte_t* secretkey; + EncryptHandler handler; + EncryptedFrame* frame; + User* user; + + AsyncFrameEncrypter(llarp_crypto* c, byte_t* seckey, EncryptHandler h) + : crypto(c), secretkey(seckey), handler(h) + { + } + + void + AsyncEncrypt(llarp_threadpool* worker, llarp_buffer_t buf, User* u) + { + frame = new EncryptedFrame(buf.sz); + memcpy(frame->data + EncryptedFrame::OverheadSize, buf.base, buf.sz); + user = u; + llarp_threadpool_queue_job(worker, {this, &Encrypt}); + } }; + /// TOOD: can only handle 1 frame at a time template < typename User > struct AsyncFrameDecrypter { @@ -43,10 +86,10 @@ namespace llarp ctx->result(ctx->target->Buffer(), ctx->context); else ctx->result(nullptr, ctx->context); + delete ctx->target; } - AsyncFrameDecrypter(llarp_crypto* c, const byte_t* secretkey, - DecryptHandler h) + AsyncFrameDecrypter(llarp_crypto* c, byte_t* secretkey, DecryptHandler h) : result(h), crypto(c), seckey(secretkey) { } @@ -54,7 +97,7 @@ namespace llarp DecryptHandler result; User* context; llarp_crypto* crypto; - const byte_t* seckey; + byte_t* seckey; EncryptedFrame* target; void AsyncDecrypt(llarp_threadpool* worker, EncryptedFrame* frame, User* user) diff --git a/include/llarp/messages/relay_commit.hpp b/include/llarp/messages/relay_commit.hpp index 9da43c78a..4def4d44f 100644 --- a/include/llarp/messages/relay_commit.hpp +++ b/include/llarp/messages/relay_commit.hpp @@ -1,6 +1,7 @@ #ifndef LLARP_RELAY_COMMIT_HPP #define LLARP_RELAY_COMMIT_HPP #include +#include #include #include #include @@ -56,6 +57,7 @@ namespace llarp struct LR_CommitMessage : public ILinkMessage { std::vector< EncryptedFrame > frames; + std::vector< EncryptedAck > acks; uint64_t version; LR_CommitMessage(const RouterID &from) : ILinkMessage(from) @@ -74,6 +76,13 @@ namespace llarp bool HandleMessage(llarp_router *router) const; + + private: + static bool + DecodeEncryptedFrame(list_reader *r, bool buf); + + bool + DecodeEncryptedFrameList(llarp_buffer_t *buf); }; } diff --git a/llarp/encrypted_frame.cpp b/llarp/encrypted_frame.cpp index 9276e61bb..457c2d903 100644 --- a/llarp/encrypted_frame.cpp +++ b/llarp/encrypted_frame.cpp @@ -1,31 +1,84 @@ #include +#include "logger.hpp" namespace llarp { - EncryptedFrame::EncryptedFrame() : m_Buf(nullptr), m_Sz(0) + Encrypted::Encrypted(const byte_t* buf, size_t sz) { + size = sz; + data = new byte_t[sz]; + if(buf) + memcpy(data, buf, sz); + m_Buffer.base = data; + m_Buffer.cur = data; + m_Buffer.sz = size; } - EncryptedFrame::EncryptedFrame(const byte_t* buf, size_t sz) + Encrypted::Encrypted(size_t sz) : Encrypted(nullptr, sz) { - m_Sz = sz; - m_Buf = new byte_t[m_Sz]; - memcpy(m_Buf, buf, sz); - m_Buffer.base = m_Buf; - m_Buffer.cur = m_Buf; - m_Buffer.sz = sz; } - EncryptedFrame::~EncryptedFrame() + Encrypted::~Encrypted() { - if(m_Buf) - delete[] m_Buf; + if(data) + delete[] data; } bool - EncryptedFrame::DecryptInPlace(const byte_t* ourSecretKey, - llarp_crypto* crypto) + EncryptedFrame::DecryptInPlace(byte_t* ourSecretKey, llarp_crypto* crypto) { - return false; + if(size <= OverheadSize) + { + llarp::Warn("encrypted frame too small, ", size, " <= ", OverheadSize); + return false; + } + // format of frame is + // <32 bytes keyed hash of following data> + // <32 bytes nonce> + // <32 bytes pubkey> + // + // + byte_t* hash = data; + byte_t* nonce = hash + sizeof(llarp_pubkey_t); + byte_t* otherPubkey = nonce + sizeof(llarp_tunnel_nonce_t); + byte_t* body = otherPubkey + sizeof(llarp_shorthash_t); + + // use dh_server becuase we are not the creator of this message + auto DH = crypto->dh_server; + auto Decrypt = crypto->xchacha20; + auto Digest = crypto->hmac; + + llarp_buffer_t buf; + buf.base = body; + buf.cur = buf.base; + buf.sz = size - OverheadSize; + + llarp_sharedkey_t shared; + llarp_shorthash_t digest; + + if(!DH(shared, otherPubkey, nonce, ourSecretKey)) + { + llarp::Error("DH failed"); + return false; + } + + if(!Digest(digest, buf, shared)) + { + llarp::Error("Digest failed"); + return false; + } + + if(memcmp(digest, hash, sizeof(llarp_shorthash_t))) + { + llarp::Error("message authentication failed"); + return false; + } + + if(!Decrypt(buf, shared, nonce)) + { + llarp::Error("decrypt failed"); + return false; + } + return true; } } \ No newline at end of file diff --git a/llarp/link_message.cpp b/llarp/link_message.cpp index b36d30862..226e66c33 100644 --- a/llarp/link_message.cpp +++ b/llarp/link_message.cpp @@ -33,19 +33,19 @@ namespace llarp // we are expecting the first key to be 'a' if(!llarp_buffer_eq(*key, "a")) { - llarp::Warn(__FILE__, "message has no message type"); + llarp::Warn("message has no message type"); return false; } if(!bencode_read_string(r->buffer, &strbuf)) { - llarp::Warn(__FILE__, "could not read value of message type"); + llarp::Warn("could not read value of message type"); return false; } // bad key size if(strbuf.sz != 1) { - llarp::Warn(__FILE__, "bad mesage type size: ", strbuf.sz); + llarp::Warn("bad mesage type size: ", strbuf.sz); return false; } // create the message to parse based off message type diff --git a/llarp/relay_commit.cpp b/llarp/relay_commit.cpp index 6c6940eb5..33da82450 100644 --- a/llarp/relay_commit.cpp +++ b/llarp/relay_commit.cpp @@ -11,15 +11,73 @@ namespace llarp bool LR_CommitMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf) { - // TODO: implement + if(llarp_buffer_eq(key, "c")) + { + return DecodeEncryptedFrameList(buf); + } return false; } + bool + LR_CommitMessage::DecodeEncryptedFrame(list_reader* l, bool item) + { + LR_CommitMessage* self = static_cast< LR_CommitMessage* >(l->user); + // end of list + if(!item) + { + bool success = self->frames.size() > 0; + if(!success) + llarp::Error("no encrypted frames read in LRCM"); + return success; + } + + llarp_buffer_t strbuf; + if(!bencode_read_string(l->buffer, &strbuf)) + return false; + + if(strbuf.sz <= EncryptedFrame::OverheadSize) + { + llarp::Error("Encrypted Frame In LRCM too short, ", strbuf.sz, + " <= ", EncryptedFrame::OverheadSize); + return false; + } + // emplace new frame + self->frames.emplace_back(strbuf.cur, strbuf.sz); + return true; + } + + bool + LR_CommitMessage::DecodeEncryptedFrameList(llarp_buffer_t* buf) + { + list_reader r; + r.user = this; + r.on_item = &DecodeEncryptedFrame; + return bencode_read_list(buf, &r); + } + bool LR_CommitMessage::BEncode(llarp_buffer_t* buf) const { - // TODO: implement - return false; + if(!bencode_start_dict(buf)) + return false; + // msg type + if(!bencode_write_bytestring(buf, "a", 1)) + return false; + if(!bencode_write_bytestring(buf, "c", 1)) + return false; + + // frames + if(!bencode_write_bytestring(buf, "c", 1)) + return false; + if(!bencode_start_list(buf)) + return false; + for(const auto& frame : frames) + if(!bencode_write_bytestring(buf, frame.data, frame.size)) + return false; + if(!bencode_end(buf)) + return false; + + return bencode_end(buf); } bool