@@ -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 ;
@@ -420,26 +420,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
420420}
421421
422422uint16_t MyMesh::getPeerNextAeadNonce (int peer_idx) {
423- int i = matching_peer_indexes[peer_idx];
424- if (i >= 0 && i < acl.getNumClients ())
425- return acl.nextAeadNonceFor (*acl.getClientByIdx (i));
426- return 0 ;
423+ return acl.peerNextAeadNonce (peer_idx, matching_peer_indexes);
427424}
428425
429426void MyMesh::onPeerAeadDetected (int peer_idx) {
430- int i = matching_peer_indexes[peer_idx];
431- if (i >= 0 && i < acl.getNumClients ()) {
432- auto c = acl.getClientByIdx (i);
433- if (!(c->flags & CONTACT_FLAG_AEAD )) {
434- c->flags |= CONTACT_FLAG_AEAD ;
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- }
427+ auto * c = acl.resolveClient (peer_idx, matching_peer_indexes);
428+ if (c && !(c->flags & CONTACT_FLAG_AEAD )) {
429+ c->flags |= CONTACT_FLAG_AEAD ;
430+ if (c->aead_nonce == 0 ) { // no persisted nonce — seed from RNG to avoid deterministic start
431+ getRNG ()->random ((uint8_t *)&c->aead_nonce , sizeof (c->aead_nonce ));
432+ if (c->aead_nonce == 0 ) c->aead_nonce = 1 ;
439433 }
440434 }
441435}
442436
437+ const uint8_t * MyMesh::getPeerSessionKey (int peer_idx) {
438+ return acl.peerSessionKey (peer_idx, matching_peer_indexes);
439+ }
440+ const uint8_t * MyMesh::getPeerPrevSessionKey (int peer_idx) {
441+ return acl.peerPrevSessionKey (peer_idx, matching_peer_indexes);
442+ }
443+ void MyMesh::onSessionKeyDecryptSuccess (int peer_idx) {
444+ acl.peerSessionKeyDecryptSuccess (peer_idx, matching_peer_indexes);
445+ }
446+ const uint8_t * MyMesh::getPeerEncryptionKey (int peer_idx, const uint8_t * static_secret) {
447+ return acl.peerEncryptionKey (peer_idx, matching_peer_indexes, static_secret);
448+ }
449+ uint16_t MyMesh::getPeerEncryptionNonce (int peer_idx) {
450+ return acl.peerEncryptionNonce (peer_idx, matching_peer_indexes);
451+ }
452+
443453void MyMesh::onPeerDataRecv (mesh::Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret,
444454 uint8_t *data, size_t len) {
445455 int i = matching_peer_indexes[sender_idx];
@@ -533,7 +543,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
533543 // mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
534544 // PUB_KEY_SIZE);
535545
536- auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , secret , temp, 5 + text_len, acl.nextAeadNonceFor (*client));
546+ auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , acl. getEncryptionKey (*client) , temp, 5 + text_len, acl.getEncryptionNonce (*client));
537547 if (reply) {
538548 if (client->out_path_len == OUT_PATH_UNKNOWN ) {
539549 sendFloodReply (reply, delay_millis + SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
@@ -585,15 +595,30 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
585595 }
586596 }
587597 } else {
588- int reply_len = handleRequest (client, sender_timestamp, &data[4 ], len - 4 );
598+ int reply_len;
599+ bool use_static_secret = false ;
600+
601+ // Intercept session key INIT before handleRequest
602+ if (data[4 ] == REQ_TYPE_SESSION_KEY_INIT && len >= 37 ) {
603+ memcpy (reply_data, &sender_timestamp, 4 );
604+ reply_data[4 ] = RESP_TYPE_SESSION_KEY_ACCEPT ;
605+ int n = acl.handleSessionKeyInit (client, &data[5 ], &reply_data[5 ], getRNG ());
606+ reply_len = (n > 0 ) ? 5 + n : 0 ;
607+ use_static_secret = true ; // ACCEPT must use static secret (initiator doesn't have session key yet)
608+ } else {
609+ reply_len = handleRequest (client, sender_timestamp, &data[4 ], len - 4 );
610+ }
589611 if (reply_len > 0 ) { // valid command
612+ const uint8_t * enc_key = use_static_secret ? secret : acl.getEncryptionKey (*client);
613+ uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor (*client) : acl.getEncryptionNonce (*client);
614+
590615 if (packet->isRouteFlood ()) {
591616 // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
592- mesh::Packet *path = createPathReturn (client->id , secret , packet->path , packet->path_len ,
593- PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, acl. nextAeadNonceFor (*client) );
617+ mesh::Packet *path = createPathReturn (client->id , enc_key , packet->path , packet->path_len ,
618+ PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, enc_nonce );
594619 if (path) sendFloodReply (path, SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
595620 } else {
596- mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , secret , reply_data, reply_len, acl. nextAeadNonceFor (*client) );
621+ mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , enc_key , reply_data, reply_len, enc_nonce );
597622 if (reply) {
598623 if (client->out_path_len != OUT_PATH_UNKNOWN ) { // we have an out_path, so send DIRECT
599624 sendDirect (reply, client->out_path , client->out_path_len , SERVER_RESPONSE_DELAY );
@@ -701,6 +726,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
701726 region_map.load (_fs);
702727 acl.setRNG (getRNG ());
703728 acl.loadNonces ();
729+ acl.loadSessionKeys ();
704730 bool dirty_reset = wasDirtyReset (board);
705731 acl.finalizeNonceLoad (dirty_reset);
706732 if (dirty_reset) acl.saveNonces (); // persist bumped nonces immediately
@@ -1053,6 +1079,7 @@ void MyMesh::loop() {
10531079 // persist dirty AEAD nonces
10541080 if (next_nonce_persist && millisHasNowPassed (next_nonce_persist)) {
10551081 if (acl.isNonceDirty ()) { acl.saveNonces (); }
1082+ if (acl.isSessionKeysDirty ()) { acl.saveSessionKeys (); }
10561083 next_nonce_persist = futureMillis (60000 );
10571084 }
10581085
0 commit comments