Skip to content

Commit 2a8df87

Browse files
committed
Implement session keys using
1 parent 4ddc3c3 commit 2a8df87

20 files changed

Lines changed: 1094 additions & 90 deletions

File tree

examples/companion_radio/DataStore.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,42 @@ bool DataStore::saveNonces(DataStoreHost* host) {
405405
return false;
406406
}
407407

408+
void DataStore::loadSessionKeys(DataStoreHost* host) {
409+
File file = openRead(_getContactsChannelsFS(), "/sess_keys");
410+
if (file) {
411+
uint8_t rec[71]; // 4-byte pub_key prefix + 1 flags + 2 nonce + 32 session_key + 32 prev_session_key
412+
while (file.read(rec, 71) == 71) {
413+
uint16_t nonce;
414+
memcpy(&nonce, &rec[5], 2);
415+
host->onSessionKeyLoaded(rec, rec[4], nonce, &rec[7], &rec[39]);
416+
}
417+
file.close();
418+
}
419+
}
420+
421+
bool DataStore::saveSessionKeys(DataStoreHost* host) {
422+
File file = openWrite(_getContactsChannelsFS(), "/sess_keys");
423+
if (file) {
424+
uint8_t pub_key_prefix[4];
425+
uint8_t flags;
426+
uint16_t nonce;
427+
uint8_t session_key[32];
428+
uint8_t prev_session_key[32];
429+
for (int idx = 0; idx < MAX_SESSION_KEYS; idx++) {
430+
if (host->getSessionKeyForSave(idx, pub_key_prefix, &flags, &nonce, session_key, prev_session_key)) {
431+
file.write(pub_key_prefix, 4);
432+
file.write(&flags, 1);
433+
file.write((uint8_t*)&nonce, 2);
434+
file.write(session_key, 32);
435+
file.write(prev_session_key, 32);
436+
}
437+
}
438+
file.close();
439+
return true;
440+
}
441+
return false;
442+
}
443+
408444
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
409445

410446
#define MAX_ADVERT_PKT_LEN (2 + 32 + PUB_KEY_SIZE + 4 + SIGNATURE_SIZE + MAX_ADVERT_DATA_SIZE)

examples/companion_radio/DataStore.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ class DataStoreHost {
1313
virtual bool getChannelForSave(uint8_t channel_idx, ChannelDetails& ch) =0;
1414
virtual bool onNonceLoaded(const uint8_t* pub_key_prefix, uint16_t nonce) { return false; }
1515
virtual bool getNonceForSave(int idx, uint8_t* pub_key_prefix, uint16_t* nonce) { return false; }
16+
virtual bool onSessionKeyLoaded(const uint8_t* pub_key_prefix, uint8_t flags, uint16_t nonce,
17+
const uint8_t* session_key, const uint8_t* prev_session_key) { return false; }
18+
virtual bool getSessionKeyForSave(int idx, uint8_t* pub_key_prefix, uint8_t* flags, uint16_t* nonce,
19+
uint8_t* session_key, uint8_t* prev_session_key) { return false; }
1620
};
1721

1822
class DataStore {
@@ -43,6 +47,8 @@ class DataStore {
4347
void saveChannels(DataStoreHost* host);
4448
void loadNonces(DataStoreHost* host);
4549
bool saveNonces(DataStoreHost* host);
50+
void loadSessionKeys(DataStoreHost* host);
51+
bool saveSessionKeys(DataStoreHost* host);
4652
void migrateToSecondaryFS();
4753
uint8_t getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]);
4854
bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], uint8_t len);

examples/companion_radio/MyMesh.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,8 @@ void MyMesh::begin(bool has_display) {
887887
if (dirty_reset) saveNonces(); // persist bumped nonces immediately
888888
next_nonce_persist = futureMillis(60000);
889889

890+
_store->loadSessionKeys(this);
891+
890892
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
891893
_store->loadChannels(this);
892894

@@ -1335,6 +1337,7 @@ void MyMesh::handleCmdFrame(size_t len) {
13351337
saveContacts();
13361338
}
13371339
if (isNonceDirty()) saveNonces();
1340+
saveSessionKeys();
13381341
board.reboot();
13391342
} else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) {
13401343
uint8_t reply[11];
@@ -1985,8 +1988,22 @@ void MyMesh::checkCLIRescueCmd() {
19851988

19861989
}
19871990

1991+
} else if (memcmp(cli_command, "rekey ", 6) == 0) {
1992+
const char* name_prefix = &cli_command[6];
1993+
ContactInfo* c = searchContactsByPrefix(name_prefix);
1994+
if (c) {
1995+
if (initiateSessionKeyNegotiation(*c)) {
1996+
Serial.print(" Session key negotiation started with: ");
1997+
Serial.println(c->name);
1998+
} else {
1999+
Serial.println(" Error: failed to initiate (no AEAD or pool full)");
2000+
}
2001+
} else {
2002+
Serial.println(" Error: contact not found");
2003+
}
19882004
} else if (strcmp(cli_command, "reboot") == 0) {
19892005
if (isNonceDirty()) saveNonces();
2006+
saveSessionKeys();
19902007
board.reboot(); // doesn't return
19912008
} else {
19922009
Serial.println(" Error: unknown command");
@@ -2038,11 +2055,14 @@ void MyMesh::loop() {
20382055
dirty_contacts_expiry = 0;
20392056
}
20402057

2041-
// periodic AEAD nonce persistence
2058+
// periodic AEAD nonce and session key persistence
20422059
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
20432060
if (isNonceDirty()) {
20442061
saveNonces();
20452062
}
2063+
if (isSessionKeysDirty()) {
2064+
saveSessionKeys();
2065+
}
20462066
next_nonce_persist = futureMillis(60000);
20472067
}
20482068

examples/companion_radio/MyMesh.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
156156
bool getChannelForSave(uint8_t channel_idx, ChannelDetails& ch) override { return getChannel(channel_idx, ch); }
157157
bool onNonceLoaded(const uint8_t* pub_key_prefix, uint16_t nonce) override { return applyLoadedNonce(pub_key_prefix, nonce); }
158158
bool getNonceForSave(int idx, uint8_t* pub_key_prefix, uint16_t* nonce) override { return getNonceEntry(idx, pub_key_prefix, nonce); }
159+
bool onSessionKeyLoaded(const uint8_t* pub_key_prefix, uint8_t flags, uint16_t nonce,
160+
const uint8_t* session_key, const uint8_t* prev_session_key) override {
161+
return applyLoadedSessionKey(pub_key_prefix, flags, nonce, session_key, prev_session_key);
162+
}
163+
bool getSessionKeyForSave(int idx, uint8_t* pub_key_prefix, uint8_t* flags, uint16_t* nonce,
164+
uint8_t* session_key, uint8_t* prev_session_key) override {
165+
return getSessionKeyEntry(idx, pub_key_prefix, flags, nonce, session_key, prev_session_key);
166+
}
159167

160168
void clearPendingReqs() {
161169
pending_login = pending_status = pending_telemetry = pending_discovery = pending_req = 0;
@@ -187,6 +195,8 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
187195
void saveChannels() { _store->saveChannels(this); }
188196
void saveContacts() { _store->saveContacts(this); }
189197
void saveNonces() { if (_store->saveNonces(this)) clearNonceDirty(); }
198+
void saveSessionKeys() { if (_store->saveSessionKeys(this)) clearSessionKeysDirty(); }
199+
void onSessionKeysUpdated() override { saveSessionKeys(); }
190200

191201
DataStore* _store;
192202
NodePrefs _prefs;

examples/simple_repeater/MyMesh.cpp

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -587,26 +587,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
587587
}
588588

589589
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
590-
int i = matching_peer_indexes[peer_idx];
591-
if (i >= 0 && i < acl.getNumClients())
592-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
593-
return 0;
590+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
594591
}
595592

596593
void MyMesh::onPeerAeadDetected(int peer_idx) {
597-
int i = matching_peer_indexes[peer_idx];
598-
if (i >= 0 && i < acl.getNumClients()) {
599-
auto c = acl.getClientByIdx(i);
600-
if (!(c->flags & CONTACT_FLAG_AEAD)) {
601-
c->flags |= CONTACT_FLAG_AEAD;
602-
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
603-
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
604-
if (c->aead_nonce == 0) c->aead_nonce = 1;
605-
}
594+
auto* c = acl.resolveClient(peer_idx, matching_peer_indexes);
595+
if (c && !(c->flags & CONTACT_FLAG_AEAD)) {
596+
c->flags |= CONTACT_FLAG_AEAD;
597+
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
598+
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
599+
if (c->aead_nonce == 0) c->aead_nonce = 1;
606600
}
607601
}
608602
}
609603

604+
const uint8_t* MyMesh::getPeerSessionKey(int peer_idx) {
605+
return acl.peerSessionKey(peer_idx, matching_peer_indexes);
606+
}
607+
const uint8_t* MyMesh::getPeerPrevSessionKey(int peer_idx) {
608+
return acl.peerPrevSessionKey(peer_idx, matching_peer_indexes);
609+
}
610+
void MyMesh::onSessionKeyDecryptSuccess(int peer_idx) {
611+
acl.peerSessionKeyDecryptSuccess(peer_idx, matching_peer_indexes);
612+
}
613+
const uint8_t* MyMesh::getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) {
614+
return acl.peerEncryptionKey(peer_idx, matching_peer_indexes, static_secret);
615+
}
616+
uint16_t MyMesh::getPeerEncryptionNonce(int peer_idx) {
617+
return acl.peerEncryptionNonce(peer_idx, matching_peer_indexes);
618+
}
619+
610620
static bool isShare(const mesh::Packet *packet) {
611621
if (packet->hasTransportCodes()) {
612622
return packet->transport_codes[0] == 0 && packet->transport_codes[1] == 0; // codes { 0, 0 } means 'send to nowhere'
@@ -641,20 +651,37 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
641651
memcpy(&timestamp, data, 4);
642652

643653
if (timestamp > client->last_timestamp) { // prevent replay attacks
644-
int reply_len = handleRequest(client, timestamp, &data[4], len - 4);
654+
int reply_len;
655+
bool use_static_secret = false;
656+
657+
// Intercept session key INIT before handleRequest
658+
if (data[4] == REQ_TYPE_SESSION_KEY_INIT && len >= 37) {
659+
memcpy(reply_data, &timestamp, 4);
660+
reply_data[4] = RESP_TYPE_SESSION_KEY_ACCEPT;
661+
int n = acl.handleSessionKeyInit(client, &data[5], &reply_data[5], getRNG());
662+
reply_len = (n > 0) ? 5 + n : 0;
663+
use_static_secret = true; // ACCEPT must use static secret (initiator doesn't have session key yet)
664+
} else {
665+
reply_len = handleRequest(client, timestamp, &data[4], len - 4);
666+
}
645667
if (reply_len == 0) return; // invalid command
646668

647669
client->last_timestamp = timestamp;
648670
client->last_activity = getRTCClock()->getCurrentTime();
649671

672+
// Session key ACCEPT must be encrypted with static ECDH secret + static nonce,
673+
// because the initiator hasn't derived the session key yet.
674+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
675+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
676+
650677
if (packet->isRouteFlood()) {
651678
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
652-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
653-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
679+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
680+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
654681
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
655682
} else {
656683
mesh::Packet *reply =
657-
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
684+
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
658685
if (reply) {
659686
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
660687
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -715,7 +742,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
715742
memcpy(temp, &timestamp, 4); // mostly an extra blob to help make packet_hash unique
716743
temp[4] = (TXT_TYPE_CLI_DATA << 2); // NOTE: legacy was: TXT_TYPE_PLAIN
717744

718-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
745+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
719746
if (reply) {
720747
if (client->out_path_len == OUT_PATH_UNKNOWN) {
721748
sendFlood(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize());
@@ -899,6 +926,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
899926
acl.load(_fs, self_id);
900927
acl.setRNG(getRNG());
901928
acl.loadNonces();
929+
acl.loadSessionKeys();
902930
bool dirty_reset = wasDirtyReset(board);
903931
acl.finalizeNonceLoad(dirty_reset);
904932
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -1317,6 +1345,7 @@ void MyMesh::loop() {
13171345
// persist dirty AEAD nonces
13181346
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
13191347
if (acl.isNonceDirty()) { acl.saveNonces(); }
1348+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
13201349
next_nonce_persist = futureMillis(60000);
13211350
}
13221351

examples/simple_repeater/MyMesh.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
171171
uint8_t getPeerFlags(int peer_idx) override;
172172
uint16_t getPeerNextAeadNonce(int peer_idx) override;
173173
void onPeerAeadDetected(int peer_idx) override;
174+
const uint8_t* getPeerSessionKey(int peer_idx) override;
175+
const uint8_t* getPeerPrevSessionKey(int peer_idx) override;
176+
void onSessionKeyDecryptSuccess(int peer_idx) override;
177+
const uint8_t* getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) override;
178+
uint16_t getPeerEncryptionNonce(int peer_idx) override;
174179
void onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len);
175180
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override;
176181
bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;

examples/simple_room_server/MyMesh.cpp

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void MyMesh::pushPostToClient(ClientInfo *client, PostInfo &post) {
7171
mesh::Utils::sha256((uint8_t *)&client->extra.room.pending_ack, 4, reply_data, len, client->id.pub_key, PUB_KEY_SIZE);
7272
client->extra.room.push_post_timestamp = post.post_timestamp;
7373

74-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, client->shared_secret, reply_data, len, acl.nextAeadNonceFor(*client));
74+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), reply_data, len, acl.getEncryptionNonce(*client));
7575
if (reply) {
7676
if (client->out_path_len == OUT_PATH_UNKNOWN) {
7777
unsigned long delay_millis = 0;
@@ -397,26 +397,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
397397
}
398398

399399
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
400-
int i = matching_peer_indexes[peer_idx];
401-
if (i >= 0 && i < acl.getNumClients())
402-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
403-
return 0;
400+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
404401
}
405402

406403
void MyMesh::onPeerAeadDetected(int peer_idx) {
407-
int i = matching_peer_indexes[peer_idx];
408-
if (i >= 0 && i < acl.getNumClients()) {
409-
auto c = acl.getClientByIdx(i);
410-
if (!(c->flags & CONTACT_FLAG_AEAD)) {
411-
c->flags |= CONTACT_FLAG_AEAD;
412-
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
413-
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
414-
if (c->aead_nonce == 0) c->aead_nonce = 1;
415-
}
404+
auto* c = acl.resolveClient(peer_idx, matching_peer_indexes);
405+
if (c && !(c->flags & CONTACT_FLAG_AEAD)) {
406+
c->flags |= CONTACT_FLAG_AEAD;
407+
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
408+
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
409+
if (c->aead_nonce == 0) c->aead_nonce = 1;
416410
}
417411
}
418412
}
419413

414+
const uint8_t* MyMesh::getPeerSessionKey(int peer_idx) {
415+
return acl.peerSessionKey(peer_idx, matching_peer_indexes);
416+
}
417+
const uint8_t* MyMesh::getPeerPrevSessionKey(int peer_idx) {
418+
return acl.peerPrevSessionKey(peer_idx, matching_peer_indexes);
419+
}
420+
void MyMesh::onSessionKeyDecryptSuccess(int peer_idx) {
421+
acl.peerSessionKeyDecryptSuccess(peer_idx, matching_peer_indexes);
422+
}
423+
const uint8_t* MyMesh::getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) {
424+
return acl.peerEncryptionKey(peer_idx, matching_peer_indexes, static_secret);
425+
}
426+
uint16_t MyMesh::getPeerEncryptionNonce(int peer_idx) {
427+
return acl.peerEncryptionNonce(peer_idx, matching_peer_indexes);
428+
}
429+
420430
void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret,
421431
uint8_t *data, size_t len) {
422432
int i = matching_peer_indexes[sender_idx];
@@ -510,7 +520,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
510520
// mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
511521
// PUB_KEY_SIZE);
512522

513-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
523+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
514524
if (reply) {
515525
if (client->out_path_len == OUT_PATH_UNKNOWN) {
516526
sendFlood(reply, delay_millis + SERVER_RESPONSE_DELAY, packet->getPathHashSize());
@@ -562,15 +572,30 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
562572
}
563573
}
564574
} else {
565-
int reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
575+
int reply_len;
576+
bool use_static_secret = false;
577+
578+
// Intercept session key INIT before handleRequest
579+
if (data[4] == REQ_TYPE_SESSION_KEY_INIT && len >= 37) {
580+
memcpy(reply_data, &sender_timestamp, 4);
581+
reply_data[4] = RESP_TYPE_SESSION_KEY_ACCEPT;
582+
int n = acl.handleSessionKeyInit(client, &data[5], &reply_data[5], getRNG());
583+
reply_len = (n > 0) ? 5 + n : 0;
584+
use_static_secret = true; // ACCEPT must use static secret (initiator doesn't have session key yet)
585+
} else {
586+
reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
587+
}
566588
if (reply_len > 0) { // valid command
589+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
590+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
591+
567592
if (packet->isRouteFlood()) {
568593
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
569-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
570-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
594+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
595+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
571596
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
572597
} else {
573-
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
598+
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
574599
if (reply) {
575600
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
576601
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -671,6 +696,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
671696
acl.load(_fs, self_id);
672697
acl.setRNG(getRNG());
673698
acl.loadNonces();
699+
acl.loadSessionKeys();
674700
bool dirty_reset = wasDirtyReset(board);
675701
acl.finalizeNonceLoad(dirty_reset);
676702
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -925,6 +951,7 @@ void MyMesh::loop() {
925951
// persist dirty AEAD nonces
926952
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
927953
if (acl.isNonceDirty()) { acl.saveNonces(); }
954+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
928955
next_nonce_persist = futureMillis(60000);
929956
}
930957

0 commit comments

Comments
 (0)