Skip to content

Commit be32746

Browse files
committed
Implement session keys using
1 parent 1e2a1e1 commit be32746

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
@@ -409,6 +409,42 @@ bool DataStore::saveNonces(DataStoreHost* host) {
409409
return false;
410410
}
411411

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

414450
#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
@@ -938,6 +938,8 @@ void MyMesh::begin(bool has_display) {
938938
if (dirty_reset) saveNonces(); // persist bumped nonces immediately
939939
next_nonce_persist = futureMillis(60000);
940940

941+
_store->loadSessionKeys(this);
942+
941943
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
942944
_store->loadChannels(this);
943945

@@ -1429,6 +1431,7 @@ void MyMesh::handleCmdFrame(size_t len) {
14291431
saveContacts();
14301432
}
14311433
if (isNonceDirty()) saveNonces();
1434+
saveSessionKeys();
14321435
board.reboot();
14331436
} else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) {
14341437
uint8_t reply[11];
@@ -2083,8 +2086,22 @@ void MyMesh::checkCLIRescueCmd() {
20832086

20842087
}
20852088

2089+
} else if (memcmp(cli_command, "rekey ", 6) == 0) {
2090+
const char* name_prefix = &cli_command[6];
2091+
ContactInfo* c = searchContactsByPrefix(name_prefix);
2092+
if (c) {
2093+
if (initiateSessionKeyNegotiation(*c)) {
2094+
Serial.print(" Session key negotiation started with: ");
2095+
Serial.println(c->name);
2096+
} else {
2097+
Serial.println(" Error: failed to initiate (no AEAD or pool full)");
2098+
}
2099+
} else {
2100+
Serial.println(" Error: contact not found");
2101+
}
20862102
} else if (strcmp(cli_command, "reboot") == 0) {
20872103
if (isNonceDirty()) saveNonces();
2104+
saveSessionKeys();
20882105
board.reboot(); // doesn't return
20892106
} else {
20902107
Serial.println(" Error: unknown command");
@@ -2136,11 +2153,14 @@ void MyMesh::loop() {
21362153
dirty_contacts_expiry = 0;
21372154
}
21382155

2139-
// periodic AEAD nonce persistence
2156+
// periodic AEAD nonce and session key persistence
21402157
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
21412158
if (isNonceDirty()) {
21422159
saveNonces();
21432160
}
2161+
if (isSessionKeysDirty()) {
2162+
saveSessionKeys();
2163+
}
21442164
next_nonce_persist = futureMillis(60000);
21452165
}
21462166

examples/companion_radio/MyMesh.h

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

163171
void clearPendingReqs() {
164172
pending_login = pending_status = pending_telemetry = pending_discovery = pending_req = 0;
@@ -190,6 +198,8 @@ class MyMesh : public BaseChatMesh, public DataStoreHost {
190198
void saveChannels() { _store->saveChannels(this); }
191199
void saveContacts() { _store->saveContacts(this); }
192200
void saveNonces() { if (_store->saveNonces(this)) clearNonceDirty(); }
201+
void saveSessionKeys() { if (_store->saveSessionKeys(this)) clearSessionKeysDirty(); }
202+
void onSessionKeysUpdated() override { saveSessionKeys(); }
193203

194204
DataStore* _store;
195205
NodePrefs _prefs;

examples/simple_repeater/MyMesh.cpp

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

620620
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
621-
int i = matching_peer_indexes[peer_idx];
622-
if (i >= 0 && i < acl.getNumClients())
623-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
624-
return 0;
621+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
625622
}
626623

627624
void MyMesh::onPeerAeadDetected(int peer_idx) {
628-
int i = matching_peer_indexes[peer_idx];
629-
if (i >= 0 && i < acl.getNumClients()) {
630-
auto c = acl.getClientByIdx(i);
631-
if (!(c->flags & CONTACT_FLAG_AEAD)) {
632-
c->flags |= CONTACT_FLAG_AEAD;
633-
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
634-
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
635-
if (c->aead_nonce == 0) c->aead_nonce = 1;
636-
}
625+
auto* c = acl.resolveClient(peer_idx, matching_peer_indexes);
626+
if (c && !(c->flags & CONTACT_FLAG_AEAD)) {
627+
c->flags |= CONTACT_FLAG_AEAD;
628+
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
629+
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
630+
if (c->aead_nonce == 0) c->aead_nonce = 1;
637631
}
638632
}
639633
}
640634

635+
const uint8_t* MyMesh::getPeerSessionKey(int peer_idx) {
636+
return acl.peerSessionKey(peer_idx, matching_peer_indexes);
637+
}
638+
const uint8_t* MyMesh::getPeerPrevSessionKey(int peer_idx) {
639+
return acl.peerPrevSessionKey(peer_idx, matching_peer_indexes);
640+
}
641+
void MyMesh::onSessionKeyDecryptSuccess(int peer_idx) {
642+
acl.peerSessionKeyDecryptSuccess(peer_idx, matching_peer_indexes);
643+
}
644+
const uint8_t* MyMesh::getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) {
645+
return acl.peerEncryptionKey(peer_idx, matching_peer_indexes, static_secret);
646+
}
647+
uint16_t MyMesh::getPeerEncryptionNonce(int peer_idx) {
648+
return acl.peerEncryptionNonce(peer_idx, matching_peer_indexes);
649+
}
650+
641651
static bool isShare(const mesh::Packet *packet) {
642652
if (packet->hasTransportCodes()) {
643653
return packet->transport_codes[0] == 0 && packet->transport_codes[1] == 0; // codes { 0, 0 } means 'send to nowhere'
@@ -672,20 +682,37 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
672682
memcpy(&timestamp, data, 4);
673683

674684
if (timestamp > client->last_timestamp) { // prevent replay attacks
675-
int reply_len = handleRequest(client, timestamp, &data[4], len - 4);
685+
int reply_len;
686+
bool use_static_secret = false;
687+
688+
// Intercept session key INIT before handleRequest
689+
if (data[4] == REQ_TYPE_SESSION_KEY_INIT && len >= 37) {
690+
memcpy(reply_data, &timestamp, 4);
691+
reply_data[4] = RESP_TYPE_SESSION_KEY_ACCEPT;
692+
int n = acl.handleSessionKeyInit(client, &data[5], &reply_data[5], getRNG());
693+
reply_len = (n > 0) ? 5 + n : 0;
694+
use_static_secret = true; // ACCEPT must use static secret (initiator doesn't have session key yet)
695+
} else {
696+
reply_len = handleRequest(client, timestamp, &data[4], len - 4);
697+
}
676698
if (reply_len == 0) return; // invalid command
677699

678700
client->last_timestamp = timestamp;
679701
client->last_activity = getRTCClock()->getCurrentTime();
680702

703+
// Session key ACCEPT must be encrypted with static ECDH secret + static nonce,
704+
// because the initiator hasn't derived the session key yet.
705+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
706+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
707+
681708
if (packet->isRouteFlood()) {
682709
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
683-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
684-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
710+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
711+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
685712
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
686713
} else {
687714
mesh::Packet *reply =
688-
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
715+
createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
689716
if (reply) {
690717
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
691718
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -746,7 +773,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
746773
memcpy(temp, &timestamp, 4); // mostly an extra blob to help make packet_hash unique
747774
temp[4] = (TXT_TYPE_CLI_DATA << 2); // NOTE: legacy was: TXT_TYPE_PLAIN
748775

749-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
776+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
750777
if (reply) {
751778
if (client->out_path_len == OUT_PATH_UNKNOWN) {
752779
sendFlood(reply, CLI_REPLY_DELAY_MILLIS, packet->getPathHashSize());
@@ -938,6 +965,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
938965
acl.load(_fs, self_id);
939966
acl.setRNG(getRNG());
940967
acl.loadNonces();
968+
acl.loadSessionKeys();
941969
bool dirty_reset = wasDirtyReset(board);
942970
acl.finalizeNonceLoad(dirty_reset);
943971
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -1367,6 +1395,7 @@ void MyMesh::loop() {
13671395
// persist dirty AEAD nonces
13681396
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
13691397
if (acl.isNonceDirty()) { acl.saveNonces(); }
1398+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
13701399
next_nonce_persist = futureMillis(60000);
13711400
}
13721401

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;
@@ -403,26 +403,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
403403
}
404404

405405
uint16_t MyMesh::getPeerNextAeadNonce(int peer_idx) {
406-
int i = matching_peer_indexes[peer_idx];
407-
if (i >= 0 && i < acl.getNumClients())
408-
return acl.nextAeadNonceFor(*acl.getClientByIdx(i));
409-
return 0;
406+
return acl.peerNextAeadNonce(peer_idx, matching_peer_indexes);
410407
}
411408

412409
void MyMesh::onPeerAeadDetected(int peer_idx) {
413-
int i = matching_peer_indexes[peer_idx];
414-
if (i >= 0 && i < acl.getNumClients()) {
415-
auto c = acl.getClientByIdx(i);
416-
if (!(c->flags & CONTACT_FLAG_AEAD)) {
417-
c->flags |= CONTACT_FLAG_AEAD;
418-
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
419-
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
420-
if (c->aead_nonce == 0) c->aead_nonce = 1;
421-
}
410+
auto* c = acl.resolveClient(peer_idx, matching_peer_indexes);
411+
if (c && !(c->flags & CONTACT_FLAG_AEAD)) {
412+
c->flags |= CONTACT_FLAG_AEAD;
413+
if (c->aead_nonce == 0) { // no persisted nonce — seed from RNG to avoid deterministic start
414+
getRNG()->random((uint8_t*)&c->aead_nonce, sizeof(c->aead_nonce));
415+
if (c->aead_nonce == 0) c->aead_nonce = 1;
422416
}
423417
}
424418
}
425419

420+
const uint8_t* MyMesh::getPeerSessionKey(int peer_idx) {
421+
return acl.peerSessionKey(peer_idx, matching_peer_indexes);
422+
}
423+
const uint8_t* MyMesh::getPeerPrevSessionKey(int peer_idx) {
424+
return acl.peerPrevSessionKey(peer_idx, matching_peer_indexes);
425+
}
426+
void MyMesh::onSessionKeyDecryptSuccess(int peer_idx) {
427+
acl.peerSessionKeyDecryptSuccess(peer_idx, matching_peer_indexes);
428+
}
429+
const uint8_t* MyMesh::getPeerEncryptionKey(int peer_idx, const uint8_t* static_secret) {
430+
return acl.peerEncryptionKey(peer_idx, matching_peer_indexes, static_secret);
431+
}
432+
uint16_t MyMesh::getPeerEncryptionNonce(int peer_idx) {
433+
return acl.peerEncryptionNonce(peer_idx, matching_peer_indexes);
434+
}
435+
426436
void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret,
427437
uint8_t *data, size_t len) {
428438
int i = matching_peer_indexes[sender_idx];
@@ -516,7 +526,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
516526
// mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
517527
// PUB_KEY_SIZE);
518528

519-
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len, acl.nextAeadNonceFor(*client));
529+
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, acl.getEncryptionKey(*client), temp, 5 + text_len, acl.getEncryptionNonce(*client));
520530
if (reply) {
521531
if (client->out_path_len == OUT_PATH_UNKNOWN) {
522532
sendFlood(reply, delay_millis + SERVER_RESPONSE_DELAY, packet->getPathHashSize());
@@ -568,15 +578,30 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
568578
}
569579
}
570580
} else {
571-
int reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
581+
int reply_len;
582+
bool use_static_secret = false;
583+
584+
// Intercept session key INIT before handleRequest
585+
if (data[4] == REQ_TYPE_SESSION_KEY_INIT && len >= 37) {
586+
memcpy(reply_data, &sender_timestamp, 4);
587+
reply_data[4] = RESP_TYPE_SESSION_KEY_ACCEPT;
588+
int n = acl.handleSessionKeyInit(client, &data[5], &reply_data[5], getRNG());
589+
reply_len = (n > 0) ? 5 + n : 0;
590+
use_static_secret = true; // ACCEPT must use static secret (initiator doesn't have session key yet)
591+
} else {
592+
reply_len = handleRequest(client, sender_timestamp, &data[4], len - 4);
593+
}
572594
if (reply_len > 0) { // valid command
595+
const uint8_t* enc_key = use_static_secret ? secret : acl.getEncryptionKey(*client);
596+
uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor(*client) : acl.getEncryptionNonce(*client);
597+
573598
if (packet->isRouteFlood()) {
574599
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
575-
mesh::Packet *path = createPathReturn(client->id, secret, packet->path, packet->path_len,
576-
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, acl.nextAeadNonceFor(*client));
600+
mesh::Packet *path = createPathReturn(client->id, enc_key, packet->path, packet->path_len,
601+
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len, enc_nonce);
577602
if (path) sendFlood(path, SERVER_RESPONSE_DELAY, packet->getPathHashSize());
578603
} else {
579-
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len, acl.nextAeadNonceFor(*client));
604+
mesh::Packet *reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, enc_key, reply_data, reply_len, enc_nonce);
580605
if (reply) {
581606
if (client->out_path_len != OUT_PATH_UNKNOWN) { // we have an out_path, so send DIRECT
582607
sendDirect(reply, client->out_path, client->out_path_len, SERVER_RESPONSE_DELAY);
@@ -677,6 +702,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
677702
acl.load(_fs, self_id);
678703
acl.setRNG(getRNG());
679704
acl.loadNonces();
705+
acl.loadSessionKeys();
680706
bool dirty_reset = wasDirtyReset(board);
681707
acl.finalizeNonceLoad(dirty_reset);
682708
if (dirty_reset) acl.saveNonces(); // persist bumped nonces immediately
@@ -932,6 +958,7 @@ void MyMesh::loop() {
932958
// persist dirty AEAD nonces
933959
if (next_nonce_persist && millisHasNowPassed(next_nonce_persist)) {
934960
if (acl.isNonceDirty()) { acl.saveNonces(); }
961+
if (acl.isSessionKeysDirty()) { acl.saveSessionKeys(); }
935962
next_nonce_persist = futureMillis(60000);
936963
}
937964

0 commit comments

Comments
 (0)