@@ -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 ;
@@ -422,7 +422,7 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
422422uint16_t MyMesh::getPeerNextAeadNonce (int peer_idx) {
423423 int i = matching_peer_indexes[peer_idx];
424424 if (i >= 0 && i < acl.getNumClients ())
425- return acl.getClientByIdx (i)-> nextAeadNonce ( );
425+ return acl.nextAeadNonceFor (*acl. getClientByIdx (i));
426426 return 0 ;
427427}
428428
@@ -432,7 +432,10 @@ void MyMesh::onPeerAeadDetected(int peer_idx) {
432432 auto c = acl.getClientByIdx (i);
433433 if (!(c->flags & CONTACT_FLAG_AEAD )) {
434434 c->flags |= CONTACT_FLAG_AEAD ;
435- getRNG ()->random ((uint8_t *)&c->aead_nonce , sizeof (c->aead_nonce ));
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+ }
436439 }
437440 }
438441}
@@ -530,7 +533,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
530533 // mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
531534 // PUB_KEY_SIZE);
532535
533- auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , secret, temp, 5 + text_len, client-> nextAeadNonce ( ));
536+ auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , secret, temp, 5 + text_len, acl. nextAeadNonceFor (*client ));
534537 if (reply) {
535538 if (client->out_path_len == OUT_PATH_UNKNOWN ) {
536539 sendFloodReply (reply, delay_millis + SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
@@ -587,10 +590,10 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
587590 if (packet->isRouteFlood ()) {
588591 // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
589592 mesh::Packet *path = createPathReturn (client->id , secret, packet->path , packet->path_len ,
590- PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, client-> nextAeadNonce ( ));
593+ PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, acl. nextAeadNonceFor (*client ));
591594 if (path) sendFloodReply (path, SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
592595 } else {
593- mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , secret, reply_data, reply_len, client-> nextAeadNonce ( ));
596+ mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , secret, reply_data, reply_len, acl. nextAeadNonceFor (*client ));
594597 if (reply) {
595598 if (client->out_path_len != OUT_PATH_UNKNOWN ) { // we have an out_path, so send DIRECT
596599 sendDirect (reply, client->out_path , client->out_path_len , SERVER_RESPONSE_DELAY );
@@ -645,6 +648,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
645648 uptime_millis = 0 ;
646649 next_local_advert = next_flood_advert = 0 ;
647650 dirty_contacts_expiry = 0 ;
651+ next_nonce_persist = 0 ;
648652 _logging = false ;
649653 region_load_active = false ;
650654 set_radio_at = revert_radio_at = 0 ;
@@ -695,6 +699,12 @@ void MyMesh::begin(FILESYSTEM *fs) {
695699
696700 acl.load (_fs, self_id);
697701 region_map.load (_fs);
702+ acl.setRNG (getRNG ());
703+ acl.loadNonces ();
704+ bool dirty_reset = wasDirtyReset (board);
705+ acl.finalizeNonceLoad (dirty_reset);
706+ if (dirty_reset) acl.saveNonces (); // persist bumped nonces immediately
707+ next_nonce_persist = futureMillis (60000 );
698708
699709 // establish default-scope
700710 {
@@ -1040,6 +1050,12 @@ void MyMesh::loop() {
10401050 dirty_contacts_expiry = 0 ;
10411051 }
10421052
1053+ // persist dirty AEAD nonces
1054+ if (next_nonce_persist && millisHasNowPassed (next_nonce_persist)) {
1055+ if (acl.isNonceDirty ()) { acl.saveNonces (); }
1056+ next_nonce_persist = futureMillis (60000 );
1057+ }
1058+
10431059 // TODO: periodically check for OLD/inactive entries in known_clients[], and evict
10441060
10451061 // update uptime
0 commit comments