@@ -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, client-> nextAeadNonce ( ));
74+ auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , client->shared_secret , reply_data, len, acl. nextAeadNonceFor (*client ));
7575 if (reply) {
7676 if (client->out_path_len == OUT_PATH_UNKNOWN ) {
7777 unsigned long delay_millis = 0 ;
@@ -399,7 +399,7 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
399399uint16_t MyMesh::getPeerNextAeadNonce (int peer_idx) {
400400 int i = matching_peer_indexes[peer_idx];
401401 if (i >= 0 && i < acl.getNumClients ())
402- return acl.getClientByIdx (i)-> nextAeadNonce ( );
402+ return acl.nextAeadNonceFor (*acl. getClientByIdx (i));
403403 return 0 ;
404404}
405405
@@ -409,7 +409,10 @@ void MyMesh::onPeerAeadDetected(int peer_idx) {
409409 auto c = acl.getClientByIdx (i);
410410 if (!(c->flags & CONTACT_FLAG_AEAD )) {
411411 c->flags |= CONTACT_FLAG_AEAD ;
412- getRNG ()->random ((uint8_t *)&c->aead_nonce , sizeof (c->aead_nonce ));
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+ }
413416 }
414417 }
415418}
@@ -507,7 +510,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
507510 // mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
508511 // PUB_KEY_SIZE);
509512
510- auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , secret, temp, 5 + text_len, client-> nextAeadNonce ( ));
513+ auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , secret, temp, 5 + text_len, acl. nextAeadNonceFor (*client ));
511514 if (reply) {
512515 if (client->out_path_len == OUT_PATH_UNKNOWN ) {
513516 sendFlood (reply, delay_millis + SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
@@ -564,10 +567,10 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
564567 if (packet->isRouteFlood ()) {
565568 // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
566569 mesh::Packet *path = createPathReturn (client->id , secret, packet->path , packet->path_len ,
567- PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, client-> nextAeadNonce ( ));
570+ PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, acl. nextAeadNonceFor (*client ));
568571 if (path) sendFlood (path, SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
569572 } else {
570- mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , secret, reply_data, reply_len, client-> nextAeadNonce ( ));
573+ mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , secret, reply_data, reply_len, acl. nextAeadNonceFor (*client ));
571574 if (reply) {
572575 if (client->out_path_len != OUT_PATH_UNKNOWN ) { // we have an out_path, so send DIRECT
573576 sendDirect (reply, client->out_path , client->out_path_len , SERVER_RESPONSE_DELAY );
@@ -619,6 +622,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
619622 uptime_millis = 0 ;
620623 next_local_advert = next_flood_advert = 0 ;
621624 dirty_contacts_expiry = 0 ;
625+ next_nonce_persist = 0 ;
622626 _logging = false ;
623627 set_radio_at = revert_radio_at = 0 ;
624628
@@ -665,6 +669,12 @@ void MyMesh::begin(FILESYSTEM *fs) {
665669 _cli.loadPrefs (_fs);
666670
667671 acl.load (_fs, self_id);
672+ acl.setRNG (getRNG ());
673+ acl.loadNonces ();
674+ bool dirty_reset = wasDirtyReset (board);
675+ acl.finalizeNonceLoad (dirty_reset);
676+ if (dirty_reset) acl.saveNonces (); // persist bumped nonces immediately
677+ next_nonce_persist = futureMillis (60000 );
668678
669679 radio_set_params (_prefs.freq , _prefs.bw , _prefs.sf , _prefs.cr );
670680 radio_set_tx_power (_prefs.tx_power_dbm );
@@ -912,6 +922,12 @@ void MyMesh::loop() {
912922 dirty_contacts_expiry = 0 ;
913923 }
914924
925+ // persist dirty AEAD nonces
926+ if (next_nonce_persist && millisHasNowPassed (next_nonce_persist)) {
927+ if (acl.isNonceDirty ()) { acl.saveNonces (); }
928+ next_nonce_persist = futureMillis (60000 );
929+ }
930+
915931 // TODO: periodically check for OLD/inactive entries in known_clients[], and evict
916932
917933 // update uptime
0 commit comments