diff --git a/proto b/proto index 1a5afe8f5..f775ebe36 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 1a5afe8f567866981ac0cd0a75a95503064d33c2 +Subproject commit f775ebe369cd9bd92d954d46f76ea0a4ae62078c diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index 3399bd9ac..14774df3f 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -11,6 +11,12 @@ void CryptoEngine::setKey(size_t numBytes, const uint8_t *bytes) * * @param bytes is updated in place */ -void CryptoEngine::encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) {} +void CryptoEngine::encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) +{ + DEBUG_MSG("WARNING: noop encryption!\n"); +} -void CryptoEngine::decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) {} \ No newline at end of file +void CryptoEngine::decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) +{ + DEBUG_MSG("WARNING: noop decryption!\n"); +} \ No newline at end of file diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 7e9fc4486..992144b82 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -92,9 +92,9 @@ void MeshService::sendOurOwner(NodeNum dest, bool wantReplies) { MeshPacket *p = allocForSending(); p->to = dest; - p->payload.want_response = wantReplies; - p->payload.has_user = true; - User &u = p->payload.user; + p->decoded.want_response = wantReplies; + p->decoded.has_user = true; + User &u = p->decoded.user; u = owner; DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name); @@ -108,7 +108,7 @@ const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp) bool isCollision = mp->from == myNodeInfo.my_node_num; // we win if we have a lower macaddr - bool weWin = memcmp(&owner.macaddr, &mp->payload.user.macaddr, sizeof(owner.macaddr)) < 0; + bool weWin = memcmp(&owner.macaddr, &mp->decoded.user.macaddr, sizeof(owner.macaddr)) < 0; if (isCollision) { if (weWin) { @@ -134,7 +134,7 @@ const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp) sendOurOwner(mp->from); - String lcd = String("Joined: ") + mp->payload.user.long_name + "\n"; + String lcd = String("Joined: ") + mp->decoded.user.long_name + "\n"; screen.print(lcd.c_str()); } @@ -143,12 +143,12 @@ const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp) void MeshService::handleIncomingPosition(const MeshPacket *mp) { - if (mp->has_payload && mp->payload.has_position) { - DEBUG_MSG("handled incoming position time=%u\n", mp->payload.position.time); + if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.has_position) { + DEBUG_MSG("handled incoming position time=%u\n", mp->decoded.position.time); - if (mp->payload.position.time) { + if (mp->decoded.position.time) { struct timeval tv; - uint32_t secs = mp->payload.position.time; + uint32_t secs = mp->decoded.position.time; tv.tv_sec = secs; tv.tv_usec = 0; @@ -171,7 +171,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp) DEBUG_MSG("Ignoring incoming time, because we have a GPS\n"); } - if (mp->has_payload && mp->payload.has_user) { + if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.has_user) { mp = handleFromRadioUser(mp); } @@ -192,7 +192,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp) MeshPacket *copied = packetPool.allocCopy(*mp); assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages - if (mp->payload.want_response) + if (mp->decoded.want_response) sendNetworkPing(mp->from); } else { DEBUG_MSG("Not delivering vetoed User message\n"); @@ -257,12 +257,12 @@ void MeshService::sendToMesh(MeshPacket *p) // Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other // nodes shouldn't trust it anyways) Note: for now, we allow a device with a local GPS to include the time, so that gpsless // devices can get time. - if (p->has_payload && p->payload.has_position) { + if (p->which_payload == MeshPacket_decoded_tag && p->decoded.has_position) { if (!gps->isConnected) { - DEBUG_MSG("Stripping time %u from position send\n", p->payload.position.time); - p->payload.position.time = 0; + DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time); + p->decoded.position.time = 0; } else - DEBUG_MSG("Providing time to mesh %u\n", p->payload.position.time); + DEBUG_MSG("Providing time to mesh %u\n", p->decoded.position.time); } // If the phone sent a packet just to us, don't send it out into the network @@ -282,7 +282,7 @@ MeshPacket *MeshService::allocForSending() { MeshPacket *p = packetPool.allocZeroed(); - p->has_payload = true; + p->which_payload = MeshPacket_decoded_tag; // Assume payload is decoded at start. p->from = nodeDB.getNodeNum(); p->to = NODENUM_BROADCAST; p->id = generatePacketId(); @@ -312,10 +312,10 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies) // Update our local node info with our position (even if we don't decide to update anyone else) MeshPacket *p = allocForSending(); p->to = dest; - p->payload.has_position = true; - p->payload.position = node->position; - p->payload.want_response = wantReplies; - p->payload.position.time = getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid. + p->decoded.has_position = true; + p->decoded.position = node->position; + p->decoded.want_response = wantReplies; + p->decoded.position.time = getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid. sendToMesh(p); } @@ -325,9 +325,9 @@ int MeshService::onGPSChanged(void *unused) // Update our local node info with our position (even if we don't decide to update anyone else) MeshPacket *p = allocForSending(); - p->payload.has_position = true; + p->decoded.has_position = true; - Position &pos = p->payload.position; + Position &pos = p->decoded.position; // !zero or !zero lat/long means valid if (gps->latitude != 0 || gps->longitude != 0) { if (gps->altitude != 0) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 73b3391d6..50b4ca73c 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -274,8 +274,8 @@ size_t NodeDB::getNumOnlineNodes() /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw void NodeDB::updateFrom(const MeshPacket &mp) { - if (mp.has_payload) { - const SubPacket &p = mp.payload; + if (mp.which_payload == MeshPacket_decoded_tag) { + const SubPacket &p = mp.decoded; DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time); int oldNumNodes = *numNodes; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 18d6ec6fe..3ad60005c 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -107,7 +107,7 @@ size_t RadioInterface::beginSending(MeshPacket *p) assert(!sendingPacket); // DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad()); - assert(p->has_payload); + assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now lastTxStart = millis(); @@ -121,11 +121,8 @@ size_t RadioInterface::beginSending(MeshPacket *p) // if the sender nodenum is zero, that means uninitialized assert(h->from); - size_t numbytes = pb_encode_to_bytes(radiobuf + sizeof(PacketHeader), sizeof(radiobuf), SubPacket_fields, &p->payload) + - sizeof(PacketHeader); - - assert(numbytes <= MAX_RHPACKETLEN); + memcpy(radiobuf + sizeof(PacketHeader), p->encrypted.bytes, p->encrypted.size); sendingPacket = p; - return numbytes; + return p->encrypted.size + sizeof(PacketHeader); } \ No newline at end of file diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 64e6cd2a1..dee630e0c 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -289,24 +289,19 @@ void RadioLibInterface::handleReceiveInterrupt() } else { MeshPacket *mp = packetPool.allocZeroed(); - SubPacket *p = &mp->payload; - mp->from = h->from; mp->to = h->to; mp->id = h->id; addReceiveMetadata(mp); - if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p)) { - DEBUG_MSG("Invalid protobufs in received mesh packet, discarding.\n"); - packetPool.release(mp); - // rxBad++; not really a hw error - } else { - // parsing was successful, queue for our recipient - mp->has_payload = true; - DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id); + mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point + assert(payloadLen <= sizeof(mp->encrypted.bytes)); + memcpy(mp->encrypted.bytes, payload, payloadLen); + mp->encrypted.size = payloadLen; - deliverToReceiver(mp); - } + DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id); + + deliverToReceiver(mp); } } } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 6e5734e59..fe32a68a4 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -1,7 +1,11 @@ #include "Router.h" +#include "CryptoEngine.h" +#include "GPS.h" #include "configuration.h" #include "mesh-pb-constants.h" +CryptoEngine *crypto = new CryptoEngine(); + /** * Router todo * @@ -44,10 +48,30 @@ void Router::loop() /** * Send a packet on a suitable interface. This routine will * later free() the packet to pool. This routine is not allowed to stall. - * If the txmit queue is full it might return an error. + * If the txmit queue is full it might return an error. */ ErrorCode Router::send(MeshPacket *p) { + // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) + + assert(p->which_payload == MeshPacket_encrypted_tag || + p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now + + // First convert from protobufs to raw bytes + if (p->which_payload == MeshPacket_decoded_tag) { + static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union + + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded); + + assert(numbytes <= MAX_RHPACKETLEN); + crypto->encrypt(p->from, p->id, numbytes, bytes); + + // Copy back into the packet and set the variant type + memcpy(p->encrypted.bytes, bytes, numbytes); + p->encrypted.size = numbytes; + p->which_payload = MeshPacket_encrypted_tag; + } + if (iface) { // DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); return iface->send(p); @@ -58,8 +82,6 @@ ErrorCode Router::send(MeshPacket *p) } } -#include "GPS.h" - /** * Handle any packet that is received by an interface on this node. * Note: some packets may merely being passed through this node and will be forwarded elsewhere. @@ -70,7 +92,25 @@ void Router::handleReceived(MeshPacket *p) // Also, we should set the time from the ISR and it should have msec level resolution p->rx_time = getValidTime(); // store the arrival timestamp for the phone - DEBUG_MSG("Notifying observers of received packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - notifyPacketReceived.notifyObservers(p); + assert(p->which_payload == + MeshPacket_encrypted_tag); // I _think_ the only thing that pushes to us is raw devices that just received packets + + // Try to decrypt the packet if we can + static uint8_t bytes[MAX_RHPACKETLEN]; + memcpy(bytes, p->encrypted.bytes, + p->encrypted.size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf + crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); + + // Take those raw bytes and convert them back into a well structured protobuf we can understand + if (!pb_decode_from_bytes(bytes, p->encrypted.size, SubPacket_fields, &p->decoded)) { + DEBUG_MSG("Invalid protobufs in received mesh packet, discarding.\n"); + } else { + // parsing was successful, queue for our recipient + p->which_payload = MeshPacket_decoded_tag; + + DEBUG_MSG("Notifying observers of received packet fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); + notifyPacketReceived.notifyObservers(p); + } + packetPool.release(p); } \ No newline at end of file diff --git a/src/mesh/mesh.pb.h b/src/mesh/mesh.pb.h index ba2293a0a..da04b00cd 100644 --- a/src/mesh/mesh.pb.h +++ b/src/mesh/mesh.pb.h @@ -122,11 +122,15 @@ typedef struct _SubPacket { bool want_response; } SubPacket; +typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef struct _MeshPacket { int32_t from; int32_t to; - bool has_payload; - SubPacket payload; + pb_size_t which_payload; + union { + SubPacket decoded; + MeshPacket_encrypted_t encrypted; + }; uint32_t rx_time; uint32_t id; float rx_snr; @@ -193,7 +197,7 @@ typedef struct _ToRadio { #define User_init_default {"", "", "", {0}} #define RouteDiscovery_init_default {{{NULL}, NULL}} #define SubPacket_init_default {false, Position_init_default, false, Data_init_default, false, User_init_default, 0} -#define MeshPacket_init_default {0, 0, false, SubPacket_init_default, 0, 0, 0} +#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0}, ""} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} #define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -208,7 +212,7 @@ typedef struct _ToRadio { #define User_init_zero {"", "", "", {0}} #define RouteDiscovery_init_zero {{{NULL}, NULL}} #define SubPacket_init_zero {false, Position_init_zero, false, Data_init_zero, false, User_init_zero, 0} -#define MeshPacket_init_zero {0, 0, false, SubPacket_init_zero, 0, 0, 0} +#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0}, ""} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} #define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -269,9 +273,10 @@ typedef struct _ToRadio { #define SubPacket_data_tag 3 #define SubPacket_user_tag 4 #define SubPacket_want_response_tag 5 +#define MeshPacket_decoded_tag 3 +#define MeshPacket_encrypted_tag 8 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 -#define MeshPacket_payload_tag 3 #define MeshPacket_rx_time_tag 4 #define MeshPacket_id_tag 6 #define MeshPacket_rx_snr_tag 7 @@ -338,13 +343,14 @@ X(a, STATIC, SINGULAR, BOOL, want_response, 5) #define MeshPacket_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, INT32, from, 1) \ X(a, STATIC, SINGULAR, INT32, to, 2) \ -X(a, STATIC, OPTIONAL, MESSAGE, payload, 3) \ +X(a, STATIC, ONEOF, MESSAGE, (payload,decoded,decoded), 3) \ +X(a, STATIC, ONEOF, BYTES, (payload,encrypted,encrypted), 8) \ X(a, STATIC, SINGULAR, UINT32, rx_time, 4) \ X(a, STATIC, SINGULAR, UINT32, id, 6) \ X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL -#define MeshPacket_payload_MSGTYPE SubPacket +#define MeshPacket_payload_decoded_MSGTYPE SubPacket #define ChannelSettings_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, INT32, tx_power, 1) \ diff --git a/src/screen.cpp b/src/screen.cpp index 0b3f22fb2..c60907aa8 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -81,7 +81,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state MeshPacket &mp = devicestate.rx_text_message; NodeInfo *node = nodeDB.getNode(mp.from); // DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from, - // mp.payload.variant.data.payload.bytes); + // mp.decoded.variant.data.decoded.bytes); // Demo for drawStringMaxWidth: // with the third parameter you can define the width after which words will @@ -94,8 +94,8 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state // the max length of this buffer is much longer than we can possibly print static char tempBuf[96]; - assert(mp.payload.has_data); - snprintf(tempBuf, sizeof(tempBuf), " %s", mp.payload.data.payload.bytes); + assert(mp.decoded.has_data); + snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes); display->drawStringMaxWidth(4 + x, 10 + y, 128, tempBuf); }