Skip to content

Commit 0186856

Browse files
committed
Implement session keys using
1 parent d1c79eb commit 0186856

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
@@ -413,6 +413,42 @@ bool DataStore::saveNonces(DataStoreHost* host) {
413413
return false;
414414
}
415415

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

418454
#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
@@ -967,6 +967,8 @@ void MyMesh::begin(bool has_display) {
967967
if (dirty_reset) saveNonces(); // persist bumped nonces immediately
968968
next_nonce_persist = futureMillis(60000);
969969

970+
_store->loadSessionKeys(this);
971+
970972
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
971973
_store->loadChannels(this);
972974

@@ -1464,6 +1466,7 @@ void MyMesh::handleCmdFrame(size_t len) {
14641466
saveContacts();
14651467
}
14661468
if (isNonceDirty()) saveNonces();
1469+
saveSessionKeys();
14671470
board.reboot();
14681471
} else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) {
14691472
uint8_t reply[11];
@@ -2161,8 +2164,22 @@ void MyMesh::checkCLIRescueCmd() {
21612164

21622165
}
21632166

2167+
} else if (memcmp(cli_command, "rekey ", 6) == 0) {
2168+
const char* name_prefix = &cli_command[6];
2169+
ContactInfo* c = searchContactsByPrefix(name_prefix);
2170+
if (c) {
2171+
if (initiateSessionKeyNegotiation(*c)) {
2172+
Serial.print(" Session key negotiation started with: ");
2173+
Serial.println(c->name);
2174+
} else {
2175+
Serial.println(" Error: failed to initiate (no AEAD or pool full)");
2176+
}
2177+
} else {
2178+
Serial.println(" Error: contact not found");
2179+
}
21642180
} else if (strcmp(cli_command, "reboot") == 0) {
21652181
if (isNonceDirty()) saveNonces();
2182+
saveSessionKeys();
21662183
board.reboot(); // doesn't return
21672184
} else {
21682185
Serial.println(" Error: unknown command");
@@ -2214,11 +2231,14 @@ void MyMesh::loop() {
22142231
dirty_contacts_expiry = 0;
22152232
}
22162233

2217-
// periodic AEAD nonce persistence
2234+
// periodic AEAD nonce and session key persistence
22182235
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
22192236
if (isNonceDirty()) {
22202237
saveNonces();
22212238
}
2239+
if (isSessionKeysDirty()) {
2240+
saveSessionKeys();
2241+
}
22222242
next_nonce_persist = futureMillis(60000);
22232243
}
22242244

examples/companion_radio/MyMesh.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,14 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
160160
bool getChannelForSave(uint8_t channel_idx, ChannelDetails& ch) override { return getChannel(channel_idx, ch); }
161161
bool onNonceLoaded(const uint8_t* pub_key_prefix, uint16_t nonce) override { return applyLoadedNonce(pub_key_prefix, nonce); }
162162
bool getNonceForSave(int idx, uint8_t* pub_key_prefix, uint16_t* nonce) override { return getNonceEntry(idx, pub_key_prefix, nonce); }
163+
bool onSessionKeyLoaded(const uint8_t* pub_key_prefix, uint8_t flags, uint16_t nonce,
164+
const uint8_t* session_key, const uint8_t* prev_session_key) override {
165+
return applyLoadedSessionKey(pub_key_prefix, flags, nonce, session_key, prev_session_key);
166+
}
167+
bool getSessionKeyForSave(int idx, uint8_t* pub_key_prefix, uint8_t* flags, uint16_t* nonce,
168+
uint8_t* session_key, uint8_t* prev_session_key) override {
169+
return getSessionKeyEntry(idx, pub_key_prefix, flags, nonce, session_key, prev_session_key);
170+
}
163171

164172
void clearPendingReqs() {
165173
pending_login = pending_status = pending_telemetry = pending_discovery = pending_req = 0;
@@ -202,6 +210,8 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
202210
void saveChannels() { _store->saveChannels(this); }
203211
void saveContacts() { _store->saveContacts(this); }
204212
void saveNonces() { if (_store->saveNonces(this)) clearNonceDirty(); }
213+
void saveSessionKeys() { if (_store->saveSessionKeys(this)) clearSessionKeysDirty(); }
214+
void onSessionKeysUpdated() override { saveSessionKeys(); }
205215

206216
DataStore* _store;
207217
NodePrefs _prefs;

examples/simple_repeater/MyMesh.cpp

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

633633
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
634-
int i = matching_peer_indexes[peer_idx];
635-
if (i >= 0 && i < acl.getNumClients())
636-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
637-
return 0;
634+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
638635
}
639636

640637
void MyMesh::onPeerAeadDetected(int peer_idx) {
641-
int i = matching_peer_indexes[peer_idx];
642-
if (i >= 0 && i < acl.getNumClients()) {
643-
auto c = acl.getClientByIdx(i);
644-
if (!(c->flags & CONTACT_FLAG_AEAD)) {
645-
c->flags |= CONTACT_FLAG_AEAD;
646-
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
647-
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
648-
if (c->aead_nonce == 0) c->aead_nonce = 1;
649-
}
638+
auto* c = acl.resolveClient(peer_idx, matching_peer_indexes);
639+
if (c && !(c->flags & CONTACT_FLAG_AEAD)) {
640+
c->flags |= CONTACT_FLAG_AEAD;
641+
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
642+
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
643+
if (c->aead_nonce == 0) c->aead_nonce = 1;
650644
}
651645
}
652646
}
653647

648+
const uint8_t* MyMesh::getPeerSessionKey(int peer_idx) {
649+
return acl.peerSessionKey(peer_idx, matching_peer_indexes);
650+
}
651+
const uint8_t* MyMesh::getPeerPrevSessionKey(int peer_idx) {
652+
return acl.peerPrevSessionKey(peer_idx, matching_peer_indexes);
653+
}
654+
void MyMesh::onSessionKeyDecryptSuccess(int peer_idx) {
655+
acl.peerSessionKeyDecryptSuccess(peer_idx, matching_peer_indexes);
656+
}
657+
const uint8_t* MyMesh::getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) {
658+
return acl.peerEncryptionKey(peer_idx, matching_peer_indexes, static_secret);
659+
}
660+
uint16_t MyMesh::getPeerEncryptionNonce(int peer_idx) {
661+
return acl.peerEncryptionNonce(peer_idx, matching_peer_indexes);
662+
}
663+
654664
static bool isShare(const mesh::Packet *packet) {
655665
if (packet->hasTransportCodes()) {
656666
return packet->transport_codes[0] == 0 && packet->transport_codes[1] == 0; // codes { 0, 0 } means 'send to nowhere'
@@ -685,20 +695,37 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
685695
memcpy(&timestamp, data, 4);
686696

687697
if (timestamp > client->last_timestamp) { // prevent replay attacks
688-
int reply_len = handleRequest(client, timestamp, &data[4], len - 4);
698+
int reply_len;
699+
bool use_static_secret = false;
700+
701+
// Intercept session key INIT before handleRequest
702+
if (data[4] == REQ_TYPE_SESSION_KEY_INIT && len >= 37) {
703+
memcpy(reply_data, &timestamp, 4);
704+
reply_data[4] = RESP_TYPE_SESSION_KEY_ACCEPT;
705+
int n = acl.handleSessionKeyInit(client, &data[5], &reply_data[5], getRNG());
706+
reply_len = (n > 0) ? 5 + n : 0;
707+
use_static_secret = true; // ACCEPT must use static secret (initiator doesn't have session key yet)
708+
} else {
709+
reply_len = handleRequest(client, timestamp, &data[4], len - 4);
710+
}
689711
if (reply_len == 0) return; // invalid command
690712

691713
client->last_timestamp = timestamp;
692714
client->last_activity = getRTCClock()->getCurrentTime();
693715

716+
// Session key ACCEPT must be encrypted with static ECDH secret + static nonce,
717+
// because the initiator hasn't derived the session key yet.
718+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
719+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
720+
694721
if (packet->isRouteFlood()) {
695722
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
696-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
697-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
723+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
724+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
698725
if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
699726
} else {
700727
mesh::Packet *reply =
701-
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
728+
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
702729
if (reply) {
703730
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
704731
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -759,7 +786,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
759786
memcpy(temp, &timestamp, 4); // mostly an extra blob to help make packet_hash unique
760787
temp[4] = (TXT_TYPE_CLI_DATA << 2); // NOTE: legacy was: TXT_TYPE_PLAIN
761788

762-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
789+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
763790
if (reply) {
764791
if (client->out_path_len == OUT_PATH_UNKNOWN) {
765792
sendFloodReply(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize());
@@ -955,6 +982,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
955982
acl.load(_fs, self_id);
956983
acl.setRNG(getRNG());
957984
acl.loadNonces();
985+
acl.loadSessionKeys();
958986
bool dirty_reset = wasDirtyReset(board);
959987
acl.finalizeNonceLoad(dirty_reset);
960988
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -1333,6 +1361,7 @@ void MyMesh::loop() {
13331361
// persist dirty AEAD nonces
13341362
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
13351363
if (acl.isNonceDirty()) { acl.saveNonces(); }
1364+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
13361365
next_nonce_persist = futureMillis(60000);
13371366
}
13381367

examples/simple_repeater/MyMesh.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
172172
uint8_t getPeerFlags(int peer_idx) override;
173173
uint16_t getPeerNextAeadNonce(int peer_idx) override;
174174
void onPeerAeadDetected(int peer_idx) override;
175+
const uint8_t* getPeerSessionKey(int peer_idx) override;
176+
const uint8_t* getPeerPrevSessionKey(int peer_idx) override;
177+
void onSessionKeyDecryptSuccess(int peer_idx) override;
178+
const uint8_t* getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) override;
179+
uint16_t getPeerEncryptionNonce(int peer_idx) override;
175180
void onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len);
176181
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override;
177182
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;
@@ -420,26 +420,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
420420
}
421421

422422
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
423-
int i = matching_peer_indexes[peer_idx];
424-
if (i >= 0 && i < acl.getNumClients())
425-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
426-
return 0;
423+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
427424
}
428425

429426
void MyMesh::onPeerAeadDetected(int peer_idx) {
430-
int i = matching_peer_indexes[peer_idx];
431-
if (i >= 0 && i < acl.getNumClients()) {
432-
auto c = acl.getClientByIdx(i);
433-
if (!(c->flags & CONTACT_FLAG_AEAD)) {
434-
c->flags |= CONTACT_FLAG_AEAD;
435-
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
436-
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
437-
if (c->aead_nonce == 0) c->aead_nonce = 1;
438-
}
427+
auto* c = acl.resolveClient(peer_idx, matching_peer_indexes);
428+
if (c && !(c->flags & CONTACT_FLAG_AEAD)) {
429+
c->flags |= CONTACT_FLAG_AEAD;
430+
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
431+
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
432+
if (c->aead_nonce == 0) c->aead_nonce = 1;
439433
}
440434
}
441435
}
442436

437+
const uint8_t* MyMesh::getPeerSessionKey(int peer_idx) {
438+
return acl.peerSessionKey(peer_idx, matching_peer_indexes);
439+
}
440+
const uint8_t* MyMesh::getPeerPrevSessionKey(int peer_idx) {
441+
return acl.peerPrevSessionKey(peer_idx, matching_peer_indexes);
442+
}
443+
void MyMesh::onSessionKeyDecryptSuccess(int peer_idx) {
444+
acl.peerSessionKeyDecryptSuccess(peer_idx, matching_peer_indexes);
445+
}
446+
const uint8_t* MyMesh::getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) {
447+
return acl.peerEncryptionKey(peer_idx, matching_peer_indexes, static_secret);
448+
}
449+
uint16_t MyMesh::getPeerEncryptionNonce(int peer_idx) {
450+
return acl.peerEncryptionNonce(peer_idx, matching_peer_indexes);
451+
}
452+
443453
void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret,
444454
uint8_t *data, size_t len) {
445455
int i = matching_peer_indexes[sender_idx];
@@ -533,7 +543,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
533543
// mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
534544
// PUB_KEY_SIZE);
535545

536-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
546+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
537547
if (reply) {
538548
if (client->out_path_len == OUT_PATH_UNKNOWN) {
539549
sendFloodReply(reply, delay_millis + SERVER_RESPONSE_DELAY, packet->getPathHashSize());
@@ -585,15 +595,30 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
585595
}
586596
}
587597
} else {
588-
int reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
598+
int reply_len;
599+
bool use_static_secret = false;
600+
601+
// Intercept session key INIT before handleRequest
602+
if (data[4] == REQ_TYPE_SESSION_KEY_INIT && len >= 37) {
603+
memcpy(reply_data, &sender_timestamp, 4);
604+
reply_data[4] = RESP_TYPE_SESSION_KEY_ACCEPT;
605+
int n = acl.handleSessionKeyInit(client, &data[5], &reply_data[5], getRNG());
606+
reply_len = (n > 0) ? 5 + n : 0;
607+
use_static_secret = true; // ACCEPT must use static secret (initiator doesn't have session key yet)
608+
} else {
609+
reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
610+
}
589611
if (reply_len > 0) { // valid command
612+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
613+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
614+
590615
if (packet->isRouteFlood()) {
591616
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
592-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
593-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
617+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
618+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
594619
if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
595620
} else {
596-
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
621+
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
597622
if (reply) {
598623
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
599624
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -701,6 +726,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
701726
region_map.load(_fs);
702727
acl.setRNG(getRNG());
703728
acl.loadNonces();
729+
acl.loadSessionKeys();
704730
bool dirty_reset = wasDirtyReset(board);
705731
acl.finalizeNonceLoad(dirty_reset);
706732
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -1053,6 +1079,7 @@ void MyMesh::loop() {
10531079
// persist dirty AEAD nonces
10541080
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
10551081
if (acl.isNonceDirty()) { acl.saveNonces(); }
1082+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
10561083
next_nonce_persist = futureMillis(60000);
10571084
}
10581085

0 commit comments

Comments
 (0)