@@ -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 ;
@@ -397,26 +397,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
397397}
398398
399399uint16_t MyMesh::getPeerNextAeadNonce (int peer_idx) {
400- int i = matching_peer_indexes[peer_idx];
401- if (i >= 0 && i < acl.getNumClients ())
402- return acl.nextAeadNonceFor (*acl.getClientByIdx (i));
403- return 0 ;
400+ return acl.peerNextAeadNonce (peer_idx, matching_peer_indexes);
404401}
405402
406403void MyMesh::onPeerAeadDetected (int peer_idx) {
407- int i = matching_peer_indexes[peer_idx];
408- if (i >= 0 && i < acl.getNumClients ()) {
409- auto c = acl.getClientByIdx (i);
410- if (!(c->flags & CONTACT_FLAG_AEAD )) {
411- c->flags |= CONTACT_FLAG_AEAD ;
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- }
404+ auto * c = acl.resolveClient (peer_idx, matching_peer_indexes);
405+ if (c && !(c->flags & CONTACT_FLAG_AEAD )) {
406+ c->flags |= CONTACT_FLAG_AEAD ;
407+ if (c->aead_nonce == 0 ) { // no persisted nonce — seed from RNG to avoid deterministic start
408+ getRNG ()->random ((uint8_t *)&c->aead_nonce , sizeof (c->aead_nonce ));
409+ if (c->aead_nonce == 0 ) c->aead_nonce = 1 ;
416410 }
417411 }
418412}
419413
414+ const uint8_t * MyMesh::getPeerSessionKey (int peer_idx) {
415+ return acl.peerSessionKey (peer_idx, matching_peer_indexes);
416+ }
417+ const uint8_t * MyMesh::getPeerPrevSessionKey (int peer_idx) {
418+ return acl.peerPrevSessionKey (peer_idx, matching_peer_indexes);
419+ }
420+ void MyMesh::onSessionKeyDecryptSuccess (int peer_idx) {
421+ acl.peerSessionKeyDecryptSuccess (peer_idx, matching_peer_indexes);
422+ }
423+ const uint8_t * MyMesh::getPeerEncryptionKey (int peer_idx, const uint8_t * static_secret) {
424+ return acl.peerEncryptionKey (peer_idx, matching_peer_indexes, static_secret);
425+ }
426+ uint16_t MyMesh::getPeerEncryptionNonce (int peer_idx) {
427+ return acl.peerEncryptionNonce (peer_idx, matching_peer_indexes);
428+ }
429+
420430void MyMesh::onPeerDataRecv (mesh::Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret,
421431 uint8_t *data, size_t len) {
422432 int i = matching_peer_indexes[sender_idx];
@@ -510,7 +520,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
510520 // mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
511521 // PUB_KEY_SIZE);
512522
513- auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , secret , temp, 5 + text_len, acl.nextAeadNonceFor (*client));
523+ auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , acl. getEncryptionKey (*client) , temp, 5 + text_len, acl.getEncryptionNonce (*client));
514524 if (reply) {
515525 if (client->out_path_len == OUT_PATH_UNKNOWN ) {
516526 sendFlood (reply, delay_millis + SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
@@ -562,15 +572,30 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
562572 }
563573 }
564574 } else {
565- int reply_len = handleRequest (client, sender_timestamp, &data[4 ], len - 4 );
575+ int reply_len;
576+ bool use_static_secret = false ;
577+
578+ // Intercept session key INIT before handleRequest
579+ if (data[4 ] == REQ_TYPE_SESSION_KEY_INIT && len >= 37 ) {
580+ memcpy (reply_data, &sender_timestamp, 4 );
581+ reply_data[4 ] = RESP_TYPE_SESSION_KEY_ACCEPT ;
582+ int n = acl.handleSessionKeyInit (client, &data[5 ], &reply_data[5 ], getRNG ());
583+ reply_len = (n > 0 ) ? 5 + n : 0 ;
584+ use_static_secret = true ; // ACCEPT must use static secret (initiator doesn't have session key yet)
585+ } else {
586+ reply_len = handleRequest (client, sender_timestamp, &data[4 ], len - 4 );
587+ }
566588 if (reply_len > 0 ) { // valid command
589+ const uint8_t * enc_key = use_static_secret ? secret : acl.getEncryptionKey (*client);
590+ uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor (*client) : acl.getEncryptionNonce (*client);
591+
567592 if (packet->isRouteFlood ()) {
568593 // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
569- mesh::Packet *path = createPathReturn (client->id , secret , packet->path , packet->path_len ,
570- PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, acl. nextAeadNonceFor (*client) );
594+ mesh::Packet *path = createPathReturn (client->id , enc_key , packet->path , packet->path_len ,
595+ PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, enc_nonce );
571596 if (path) sendFlood (path, SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
572597 } else {
573- mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , secret , reply_data, reply_len, acl. nextAeadNonceFor (*client) );
598+ mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , enc_key , reply_data, reply_len, enc_nonce );
574599 if (reply) {
575600 if (client->out_path_len != OUT_PATH_UNKNOWN ) { // we have an out_path, so send DIRECT
576601 sendDirect (reply, client->out_path , client->out_path_len , SERVER_RESPONSE_DELAY );
@@ -671,6 +696,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
671696 acl.load (_fs, self_id);
672697 acl.setRNG (getRNG ());
673698 acl.loadNonces ();
699+ acl.loadSessionKeys ();
674700 bool dirty_reset = wasDirtyReset (board);
675701 acl.finalizeNonceLoad (dirty_reset);
676702 if (dirty_reset) acl.saveNonces (); // persist bumped nonces immediately
@@ -925,6 +951,7 @@ void MyMesh::loop() {
925951 // persist dirty AEAD nonces
926952 if (next_nonce_persist && millisHasNowPassed (next_nonce_persist)) {
927953 if (acl.isNonceDirty ()) { acl.saveNonces (); }
954+ if (acl.isSessionKeysDirty ()) { acl.saveSessionKeys (); }
928955 next_nonce_persist = futureMillis (60000 );
929956 }
930957
0 commit comments