@@ -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
424424uint16_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
431428void 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+
445455void 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