stub encryptor seems nicely backwards compatible with old devices and apps

This commit is contained in:
geeksville 2020-05-09 17:51:20 -07:00
parent e6875d559c
commit 1cc24de787
9 changed files with 104 additions and 60 deletions

2
proto

@ -1 +1 @@
Subproject commit 1a5afe8f567866981ac0cd0a75a95503064d33c2 Subproject commit f775ebe369cd9bd92d954d46f76ea0a4ae62078c

View File

@ -11,6 +11,12 @@ void CryptoEngine::setKey(size_t numBytes, const uint8_t *bytes)
* *
* @param bytes is updated in place * @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) {} void CryptoEngine::decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes)
{
DEBUG_MSG("WARNING: noop decryption!\n");
}

View File

@ -92,9 +92,9 @@ void MeshService::sendOurOwner(NodeNum dest, bool wantReplies)
{ {
MeshPacket *p = allocForSending(); MeshPacket *p = allocForSending();
p->to = dest; p->to = dest;
p->payload.want_response = wantReplies; p->decoded.want_response = wantReplies;
p->payload.has_user = true; p->decoded.has_user = true;
User &u = p->payload.user; User &u = p->decoded.user;
u = owner; u = owner;
DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name); 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; bool isCollision = mp->from == myNodeInfo.my_node_num;
// we win if we have a lower macaddr // 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 (isCollision) {
if (weWin) { if (weWin) {
@ -134,7 +134,7 @@ const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp)
sendOurOwner(mp->from); 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()); screen.print(lcd.c_str());
} }
@ -143,12 +143,12 @@ const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp)
void MeshService::handleIncomingPosition(const MeshPacket *mp) void MeshService::handleIncomingPosition(const MeshPacket *mp)
{ {
if (mp->has_payload && mp->payload.has_position) { if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.has_position) {
DEBUG_MSG("handled incoming position time=%u\n", mp->payload.position.time); 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; struct timeval tv;
uint32_t secs = mp->payload.position.time; uint32_t secs = mp->decoded.position.time;
tv.tv_sec = secs; tv.tv_sec = secs;
tv.tv_usec = 0; 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"); 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); mp = handleFromRadioUser(mp);
} }
@ -192,7 +192,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
MeshPacket *copied = packetPool.allocCopy(*mp); MeshPacket *copied = packetPool.allocCopy(*mp);
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages 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); sendNetworkPing(mp->from);
} else { } else {
DEBUG_MSG("Not delivering vetoed User message\n"); 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 // 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 // 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. // 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) { if (!gps->isConnected) {
DEBUG_MSG("Stripping time %u from position send\n", p->payload.position.time); DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);
p->payload.position.time = 0; p->decoded.position.time = 0;
} else } 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 // 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(); 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->from = nodeDB.getNodeNum();
p->to = NODENUM_BROADCAST; p->to = NODENUM_BROADCAST;
p->id = generatePacketId(); 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) // Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = allocForSending(); MeshPacket *p = allocForSending();
p->to = dest; p->to = dest;
p->payload.has_position = true; p->decoded.has_position = true;
p->payload.position = node->position; p->decoded.position = node->position;
p->payload.want_response = wantReplies; p->decoded.want_response = wantReplies;
p->payload.position.time = getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid. p->decoded.position.time = getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid.
sendToMesh(p); 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) // Update our local node info with our position (even if we don't decide to update anyone else)
MeshPacket *p = allocForSending(); 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 // !zero or !zero lat/long means valid
if (gps->latitude != 0 || gps->longitude != 0) { if (gps->latitude != 0 || gps->longitude != 0) {
if (gps->altitude != 0) if (gps->altitude != 0)

View File

@ -274,8 +274,8 @@ size_t NodeDB::getNumOnlineNodes()
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void NodeDB::updateFrom(const MeshPacket &mp) void NodeDB::updateFrom(const MeshPacket &mp)
{ {
if (mp.has_payload) { if (mp.which_payload == MeshPacket_decoded_tag) {
const SubPacket &p = mp.payload; const SubPacket &p = mp.decoded;
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time); DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
int oldNumNodes = *numNodes; int oldNumNodes = *numNodes;

View File

@ -107,7 +107,7 @@ size_t RadioInterface::beginSending(MeshPacket *p)
assert(!sendingPacket); assert(!sendingPacket);
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad()); // 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(); lastTxStart = millis();
@ -121,11 +121,8 @@ size_t RadioInterface::beginSending(MeshPacket *p)
// if the sender nodenum is zero, that means uninitialized // if the sender nodenum is zero, that means uninitialized
assert(h->from); assert(h->from);
size_t numbytes = pb_encode_to_bytes(radiobuf + sizeof(PacketHeader), sizeof(radiobuf), SubPacket_fields, &p->payload) + memcpy(radiobuf + sizeof(PacketHeader), p->encrypted.bytes, p->encrypted.size);
sizeof(PacketHeader);
assert(numbytes <= MAX_RHPACKETLEN);
sendingPacket = p; sendingPacket = p;
return numbytes; return p->encrypted.size + sizeof(PacketHeader);
} }

View File

@ -289,20 +289,16 @@ void RadioLibInterface::handleReceiveInterrupt()
} else { } else {
MeshPacket *mp = packetPool.allocZeroed(); MeshPacket *mp = packetPool.allocZeroed();
SubPacket *p = &mp->payload;
mp->from = h->from; mp->from = h->from;
mp->to = h->to; mp->to = h->to;
mp->id = h->id; mp->id = h->id;
addReceiveMetadata(mp); addReceiveMetadata(mp);
if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p)) { mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
DEBUG_MSG("Invalid protobufs in received mesh packet, discarding.\n"); assert(payloadLen <= sizeof(mp->encrypted.bytes));
packetPool.release(mp); memcpy(mp->encrypted.bytes, payload, payloadLen);
// rxBad++; not really a hw error mp->encrypted.size = payloadLen;
} 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); DEBUG_MSG("Lora RX interrupt from=0x%x, id=%u\n", mp->from, mp->id);
deliverToReceiver(mp); deliverToReceiver(mp);
@ -310,7 +306,6 @@ void RadioLibInterface::handleReceiveInterrupt()
} }
} }
} }
}
/** start an immediate transmit */ /** start an immediate transmit */
void RadioLibInterface::startSend(MeshPacket *txp) void RadioLibInterface::startSend(MeshPacket *txp)

View File

@ -1,7 +1,11 @@
#include "Router.h" #include "Router.h"
#include "CryptoEngine.h"
#include "GPS.h"
#include "configuration.h" #include "configuration.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
CryptoEngine *crypto = new CryptoEngine();
/** /**
* Router todo * Router todo
* *
@ -48,6 +52,26 @@ void Router::loop()
*/ */
ErrorCode Router::send(MeshPacket *p) 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) { if (iface) {
// DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); // 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); 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. * 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. * 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 // 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 p->rx_time = getValidTime(); // store the arrival timestamp for the phone
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); 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); notifyPacketReceived.notifyObservers(p);
}
packetPool.release(p); packetPool.release(p);
} }

View File

@ -122,11 +122,15 @@ typedef struct _SubPacket {
bool want_response; bool want_response;
} SubPacket; } SubPacket;
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
typedef struct _MeshPacket { typedef struct _MeshPacket {
int32_t from; int32_t from;
int32_t to; int32_t to;
bool has_payload; pb_size_t which_payload;
SubPacket payload; union {
SubPacket decoded;
MeshPacket_encrypted_t encrypted;
};
uint32_t rx_time; uint32_t rx_time;
uint32_t id; uint32_t id;
float rx_snr; float rx_snr;
@ -193,7 +197,7 @@ typedef struct _ToRadio {
#define User_init_default {"", "", "", {0}} #define User_init_default {"", "", "", {0}}
#define RouteDiscovery_init_default {{{NULL}, NULL}} #define RouteDiscovery_init_default {{{NULL}, NULL}}
#define SubPacket_init_default {false, Position_init_default, false, Data_init_default, false, User_init_default, 0} #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 ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0}, ""}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} #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} #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 User_init_zero {"", "", "", {0}}
#define RouteDiscovery_init_zero {{{NULL}, NULL}} #define RouteDiscovery_init_zero {{{NULL}, NULL}}
#define SubPacket_init_zero {false, Position_init_zero, false, Data_init_zero, false, User_init_zero, 0} #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 ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0}, ""}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} #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} #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_data_tag 3
#define SubPacket_user_tag 4 #define SubPacket_user_tag 4
#define SubPacket_want_response_tag 5 #define SubPacket_want_response_tag 5
#define MeshPacket_decoded_tag 3
#define MeshPacket_encrypted_tag 8
#define MeshPacket_from_tag 1 #define MeshPacket_from_tag 1
#define MeshPacket_to_tag 2 #define MeshPacket_to_tag 2
#define MeshPacket_payload_tag 3
#define MeshPacket_rx_time_tag 4 #define MeshPacket_rx_time_tag 4
#define MeshPacket_id_tag 6 #define MeshPacket_id_tag 6
#define MeshPacket_rx_snr_tag 7 #define MeshPacket_rx_snr_tag 7
@ -338,13 +343,14 @@ X(a, STATIC, SINGULAR, BOOL, want_response, 5)
#define MeshPacket_FIELDLIST(X, a) \ #define MeshPacket_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, INT32, from, 1) \ X(a, STATIC, SINGULAR, INT32, from, 1) \
X(a, STATIC, SINGULAR, INT32, to, 2) \ 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, rx_time, 4) \
X(a, STATIC, SINGULAR, UINT32, id, 6) \ X(a, STATIC, SINGULAR, UINT32, id, 6) \
X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7)
#define MeshPacket_CALLBACK NULL #define MeshPacket_CALLBACK NULL
#define MeshPacket_DEFAULT NULL #define MeshPacket_DEFAULT NULL
#define MeshPacket_payload_MSGTYPE SubPacket #define MeshPacket_payload_decoded_MSGTYPE SubPacket
#define ChannelSettings_FIELDLIST(X, a) \ #define ChannelSettings_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, INT32, tx_power, 1) \ X(a, STATIC, SINGULAR, INT32, tx_power, 1) \

View File

@ -81,7 +81,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
MeshPacket &mp = devicestate.rx_text_message; MeshPacket &mp = devicestate.rx_text_message;
NodeInfo *node = nodeDB.getNode(mp.from); NodeInfo *node = nodeDB.getNode(mp.from);
// DEBUG_MSG("drawing text message from 0x%x: %s\n", 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: // Demo for drawStringMaxWidth:
// with the third parameter you can define the width after which words will // 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 // the max length of this buffer is much longer than we can possibly print
static char tempBuf[96]; static char tempBuf[96];
assert(mp.payload.has_data); assert(mp.decoded.has_data);
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.payload.data.payload.bytes); snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes);
display->drawStringMaxWidth(4 + x, 10 + y, 128, tempBuf); display->drawStringMaxWidth(4 + x, 10 + y, 128, tempBuf);
} }