Skip to content

Commit d9859d1

Browse files
committed
Implement session keys using
1 parent 051b20a commit d9859d1

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
@@ -417,6 +417,42 @@ bool DataStore::saveNonces(DataStoreHost* host) {
417417
return false;
418418
}
419419

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

422458
#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
@@ -970,6 +970,8 @@ void MyMesh::begin(bool has_display) {
970970
if (dirty_reset) saveNonces(); // persist bumped nonces immediately
971971
next_nonce_persist = futureMillis(60000);
972972

973+
_store->loadSessionKeys(this);
974+
973975
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
974976
_store->loadChannels(this);
975977

@@ -1467,6 +1469,7 @@ void MyMesh::handleCmdFrame(size_t len) {
14671469
saveContacts();
14681470
}
14691471
if (isNonceDirty()) saveNonces();
1472+
saveSessionKeys();
14701473
board.reboot();
14711474
} else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) {
14721475
uint8_t reply[11];
@@ -2183,8 +2186,22 @@ void MyMesh::checkCLIRescueCmd() {
21832186

21842187
}
21852188

2189+
} else if (memcmp(cli_command, "rekey ", 6) == 0) {
2190+
const char* name_prefix = &cli_command[6];
2191+
ContactInfo* c = searchContactsByPrefix(name_prefix);
2192+
if (c) {
2193+
if (initiateSessionKeyNegotiation(*c)) {
2194+
Serial.print(" Session key negotiation started with: ");
2195+
Serial.println(c->name);
2196+
} else {
2197+
Serial.println(" Error: failed to initiate (no AEAD or pool full)");
2198+
}
2199+
} else {
2200+
Serial.println(" Error: contact not found");
2201+
}
21862202
} else if (strcmp(cli_command, "reboot") == 0) {
21872203
if (isNonceDirty()) saveNonces();
2204+
saveSessionKeys();
21882205
board.reboot(); // doesn't return
21892206
} else {
21902207
Serial.println(" Error: unknown command");
@@ -2236,11 +2253,14 @@ void MyMesh::loop() {
22362253
dirty_contacts_expiry = 0;
22372254
}
22382255

2239-
// periodic AEAD nonce persistence
2256+
// periodic AEAD nonce and session key persistence
22402257
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
22412258
if (isNonceDirty()) {
22422259
saveNonces();
22432260
}
2261+
if (isSessionKeysDirty()) {
2262+
saveSessionKeys();
2263+
}
22442264
next_nonce_persist = futureMillis(60000);
22452265
}
22462266

examples/companion_radio/MyMesh.h

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

165173
void clearPendingReqs() {
166174
pending_login = pending_status = pending_telemetry = pending_discovery = pending_req = 0;
@@ -206,6 +214,8 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
206214
void saveChannels() { _store->saveChannels(this); }
207215
void saveContacts();
208216
void saveNonces() { if (_store->saveNonces(this)) clearNonceDirty(); }
217+
void saveSessionKeys() { if (_store->saveSessionKeys(this)) clearSessionKeysDirty(); }
218+
void onSessionKeysUpdated() override { saveSessionKeys(); }
209219

210220
DataStore* _store;
211221
NodePrefs _prefs;

examples/simple_repeater/MyMesh.cpp

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

635635
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
636-
int i = matching_peer_indexes[peer_idx];
637-
if (i >= 0 && i < acl.getNumClients())
638-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
639-
return 0;
636+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
640637
}
641638

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

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

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

693715
client->last_timestamp = timestamp;
694716
client->last_activity = getRTCClock()->getCurrentTime();
695717

718+
// Session key ACCEPT must be encrypted with static ECDH secret + static nonce,
719+
// because the initiator hasn't derived the session key yet.
720+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
721+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
722+
696723
if (packet->isRouteFlood()) {
697724
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
698-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
699-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
725+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
726+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
700727
if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
701728
} else {
702729
mesh::Packet *reply =
703-
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
730+
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
704731
if (reply) {
705732
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
706733
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -761,7 +788,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
761788
memcpy(temp, &timestamp, 4); // mostly an extra blob to help make packet_hash unique
762789
temp[4] = (TXT_TYPE_CLI_DATA << 2); // NOTE: legacy was: TXT_TYPE_PLAIN
763790

764-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
791+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
765792
if (reply) {
766793
if (client->out_path_len == OUT_PATH_UNKNOWN) {
767794
sendFloodReply(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize());
@@ -962,6 +989,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
962989
acl.load(_fs, self_id);
963990
acl.setRNG(getRNG());
964991
acl.loadNonces();
992+
acl.loadSessionKeys();
965993
bool dirty_reset = wasDirtyReset(board);
966994
acl.finalizeNonceLoad(dirty_reset);
967995
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -1339,6 +1367,7 @@ void MyMesh::loop() {
13391367
// persist dirty AEAD nonces
13401368
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
13411369
if (acl.isNonceDirty()) { acl.saveNonces(); }
1370+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
13421371
next_nonce_persist = futureMillis(60000);
13431372
}
13441373

examples/simple_repeater/MyMesh.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
175175
uint8_t getPeerFlags(int peer_idx) override;
176176
uint16_t getPeerNextAeadNonce(int peer_idx) override;
177177
void onPeerAeadDetected(int peer_idx) override;
178+
const uint8_t* getPeerSessionKey(int peer_idx) override;
179+
const uint8_t* getPeerPrevSessionKey(int peer_idx) override;
180+
void onSessionKeyDecryptSuccess(int peer_idx) override;
181+
const uint8_t* getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) override;
182+
uint16_t getPeerEncryptionNonce(int peer_idx) override;
178183
void onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len);
179184
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override;
180185
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;
@@ -422,26 +422,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
422422
}
423423

424424
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
425-
int i = matching_peer_indexes[peer_idx];
426-
if (i >= 0 && i < acl.getNumClients())
427-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
428-
return 0;
425+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
429426
}
430427

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

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

538-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
548+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
539549
if (reply) {
540550
if (client->out_path_len == OUT_PATH_UNKNOWN) {
541551
sendFloodReply(reply, delay_millis + SERVER_RESPONSE_DELAY, packet->getPathHashSize());
@@ -587,15 +597,30 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
587597
}
588598
}
589599
} else {
590-
int reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
600+
int reply_len;
601+
bool use_static_secret = false;
602+
603+
// Intercept session key INIT before handleRequest
604+
if (data[4] == REQ_TYPE_SESSION_KEY_INIT && len >= 37) {
605+
memcpy(reply_data, &sender_timestamp, 4);
606+
reply_data[4] = RESP_TYPE_SESSION_KEY_ACCEPT;
607+
int n = acl.handleSessionKeyInit(client, &data[5], &reply_data[5], getRNG());
608+
reply_len = (n > 0) ? 5 + n : 0;
609+
use_static_secret = true; // ACCEPT must use static secret (initiator doesn't have session key yet)
610+
} else {
611+
reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
612+
}
591613
if (reply_len > 0) { // valid command
614+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
615+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
616+
592617
if (packet->isRouteFlood()) {
593618
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
594-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
595-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
619+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
620+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
596621
if (path) sendFloodReply(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
597622
} else {
598-
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
623+
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
599624
if (reply) {
600625
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
601626
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -708,6 +733,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
708733
region_map.load(_fs);
709734
acl.setRNG(getRNG());
710735
acl.loadNonces();
736+
acl.loadSessionKeys();
711737
bool dirty_reset = wasDirtyReset(board);
712738
acl.finalizeNonceLoad(dirty_reset);
713739
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -1061,6 +1087,7 @@ void MyMesh::loop() {
10611087
// persist dirty AEAD nonces
10621088
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
10631089
if (acl.isNonceDirty()) { acl.saveNonces(); }
1090+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
10641091
next_nonce_persist = futureMillis(60000);
10651092
}
10661093

0 commit comments

Comments
 (0)