@@ -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 ;
@@ -403,26 +403,36 @@ uint8_t MyMesh::getPeerFlags(int peer_idx) {
403403}
404404
405405uint16_t MyMesh::getPeerNextAeadNonce (int peer_idx) {
406- int i = matching_peer_indexes[peer_idx];
407- if (i >= 0 && i < acl.getNumClients ())
408- return acl.nextAeadNonceFor (*acl.getClientByIdx (i));
409- return 0 ;
406+ return acl.peerNextAeadNonce (peer_idx, matching_peer_indexes);
410407}
411408
412409void MyMesh::onPeerAeadDetected (int peer_idx) {
413- int i = matching_peer_indexes[peer_idx];
414- if (i >= 0 && i < acl.getNumClients ()) {
415- auto c = acl.getClientByIdx (i);
416- if (!(c->flags & CONTACT_FLAG_AEAD )) {
417- c->flags |= CONTACT_FLAG_AEAD ;
418- if (c->aead_nonce == 0 ) { // no persisted nonce — seed from RNG to avoid deterministic start
419- getRNG ()->random ((uint8_t *)&c->aead_nonce , sizeof (c->aead_nonce ));
420- if (c->aead_nonce == 0 ) c->aead_nonce = 1 ;
421- }
410+ auto * c = acl.resolveClient (peer_idx, matching_peer_indexes);
411+ if (c && !(c->flags & CONTACT_FLAG_AEAD )) {
412+ c->flags |= CONTACT_FLAG_AEAD ;
413+ if (c->aead_nonce == 0 ) { // no persisted nonce — seed from RNG to avoid deterministic start
414+ getRNG ()->random ((uint8_t *)&c->aead_nonce , sizeof (c->aead_nonce ));
415+ if (c->aead_nonce == 0 ) c->aead_nonce = 1 ;
422416 }
423417 }
424418}
425419
420+ const uint8_t * MyMesh::getPeerSessionKey (int peer_idx) {
421+ return acl.peerSessionKey (peer_idx, matching_peer_indexes);
422+ }
423+ const uint8_t * MyMesh::getPeerPrevSessionKey (int peer_idx) {
424+ return acl.peerPrevSessionKey (peer_idx, matching_peer_indexes);
425+ }
426+ void MyMesh::onSessionKeyDecryptSuccess (int peer_idx) {
427+ acl.peerSessionKeyDecryptSuccess (peer_idx, matching_peer_indexes);
428+ }
429+ const uint8_t * MyMesh::getPeerEncryptionKey (int peer_idx, const uint8_t * static_secret) {
430+ return acl.peerEncryptionKey (peer_idx, matching_peer_indexes, static_secret);
431+ }
432+ uint16_t MyMesh::getPeerEncryptionNonce (int peer_idx) {
433+ return acl.peerEncryptionNonce (peer_idx, matching_peer_indexes);
434+ }
435+
426436void MyMesh::onPeerDataRecv (mesh::Packet *packet, uint8_t type, int sender_idx, const uint8_t *secret,
427437 uint8_t *data, size_t len) {
428438 int i = matching_peer_indexes[sender_idx];
@@ -516,7 +526,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
516526 // mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key,
517527 // PUB_KEY_SIZE);
518528
519- auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , secret , temp, 5 + text_len, acl.nextAeadNonceFor (*client));
529+ auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG , client->id , acl. getEncryptionKey (*client) , temp, 5 + text_len, acl.getEncryptionNonce (*client));
520530 if (reply) {
521531 if (client->out_path_len == OUT_PATH_UNKNOWN ) {
522532 sendFlood (reply, delay_millis + SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
@@ -568,15 +578,30 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
568578 }
569579 }
570580 } else {
571- int reply_len = handleRequest (client, sender_timestamp, &data[4 ], len - 4 );
581+ int reply_len;
582+ bool use_static_secret = false ;
583+
584+ // Intercept session key INIT before handleRequest
585+ if (data[4 ] == REQ_TYPE_SESSION_KEY_INIT && len >= 37 ) {
586+ memcpy (reply_data, &sender_timestamp, 4 );
587+ reply_data[4 ] = RESP_TYPE_SESSION_KEY_ACCEPT ;
588+ int n = acl.handleSessionKeyInit (client, &data[5 ], &reply_data[5 ], getRNG ());
589+ reply_len = (n > 0 ) ? 5 + n : 0 ;
590+ use_static_secret = true ; // ACCEPT must use static secret (initiator doesn't have session key yet)
591+ } else {
592+ reply_len = handleRequest (client, sender_timestamp, &data[4 ], len - 4 );
593+ }
572594 if (reply_len > 0 ) { // valid command
595+ const uint8_t * enc_key = use_static_secret ? secret : acl.getEncryptionKey (*client);
596+ uint16_t enc_nonce = use_static_secret ? acl.nextAeadNonceFor (*client) : acl.getEncryptionNonce (*client);
597+
573598 if (packet->isRouteFlood ()) {
574599 // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
575- mesh::Packet *path = createPathReturn (client->id , secret , packet->path , packet->path_len ,
576- PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, acl. nextAeadNonceFor (*client) );
600+ mesh::Packet *path = createPathReturn (client->id , enc_key , packet->path , packet->path_len ,
601+ PAYLOAD_TYPE_RESPONSE , reply_data, reply_len, enc_nonce );
577602 if (path) sendFlood (path, SERVER_RESPONSE_DELAY , packet->getPathHashSize ());
578603 } else {
579- mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , secret , reply_data, reply_len, acl. nextAeadNonceFor (*client) );
604+ mesh::Packet *reply = createDatagram (PAYLOAD_TYPE_RESPONSE , client->id , enc_key , reply_data, reply_len, enc_nonce );
580605 if (reply) {
581606 if (client->out_path_len != OUT_PATH_UNKNOWN ) { // we have an out_path, so send DIRECT
582607 sendDirect (reply, client->out_path , client->out_path_len , SERVER_RESPONSE_DELAY );
@@ -677,6 +702,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
677702 acl.load (_fs, self_id);
678703 acl.setRNG (getRNG ());
679704 acl.loadNonces ();
705+ acl.loadSessionKeys ();
680706 bool dirty_reset = wasDirtyReset (board);
681707 acl.finalizeNonceLoad (dirty_reset);
682708 if (dirty_reset) acl.saveNonces (); // persist bumped nonces immediately
@@ -932,6 +958,7 @@ void MyMesh::loop() {
932958 // persist dirty AEAD nonces
933959 if (next_nonce_persist && millisHasNowPassed (next_nonce_persist)) {
934960 if (acl.isNonceDirty ()) { acl.saveNonces (); }
961+ if (acl.isSessionKeysDirty ()) { acl.saveSessionKeys (); }
935962 next_nonce_persist = futureMillis (60000 );
936963 }
937964
0 commit comments