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
*/
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();
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)

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
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;

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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
*
@ -48,6 +52,26 @@ void Router::loop()
*/
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);
}

View File

@ -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) \

View File

@ -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);
}