#include "ch32v30x_rtc.h" #include "lib/config.h" #include "lib/ed25519/ed_25519.h" #include "meshcore/meshframing.h" #include "meshcore/packets/encrypted.h" #include "meshcore/packetstructs.h" #include "anonymous.h" #include "util/hexdump.h" #include #define TAG "Anonymous" void sendAnonymousRequest (const NodeEntry *targetNode, const uint8_t *password, uint32_t sync) { uint8_t passwordLen = strlen ((const char *)password); FrameStruct frame; frame.path.pathLen = 0; uint8_t offset = 0; // 1. Frame header frame.header = ((targetNode->path.pathLen > 0) ? ROUTE_TYPE_DIRECT : ROUTE_TYPE_FLOOD) | PAYLOAD_TYPE_ANON_REQ | PAYLOAD_VERSION_0; // 2. Payload header (unencrypted) frame.payload[offset++] = targetNode->pubKey[0]; memcpy (frame.payload + offset, persistent.pubkey, 32); offset += 32; // 3. Build plaintext payload uint8_t plaintext[32]; uint8_t p = 0; uint32_t last_seen_rt = RTC_GetCounter(); plaintext[p++] = (last_seen_rt >> 0) & 0xFF; plaintext[p++] = (last_seen_rt >> 8) & 0xFF; plaintext[p++] = (last_seen_rt >> 16) & 0xFF; plaintext[p++] = (last_seen_rt >> 24) & 0xFF; if (targetNode->type == NODE_TYPE_ROOM_SERVER) { plaintext[p++] = (sync >> 0) & 0xFF; plaintext[p++] = (sync >> 8) & 0xFF; plaintext[p++] = (sync >> 16) & 0xFF; plaintext[p++] = (sync >> 24) & 0xFF; } if (passwordLen > 16) { passwordLen = 16; } memcpy (plaintext + p, password, passwordLen); p += passwordLen; size_t outputLen; // 4. Encrypt + MAC encrypt_then_mac ( targetNode->secret, 32, plaintext, p, frame.payload + offset, &outputLen); offset += outputLen; // 5. Finalize and send frame.payloadLen = offset; memcpy (&(frame.path), &(targetNode->path), sizeof (frame.path)); hexdump ("Anon payload", frame.payload, frame.payloadLen); LoRaTransmit (&frame); } void printAnonRequest (const AnonymousRequestPayload *req, int isRoomServer) { if (!req) return; printf ("AnonymousRequestPayload at %p\n", (void *)req); printf (" destination hash: 0x%02X\n", req->destinationHash); printf (" sender pubKey: "); for (int i = 0; i < sizeof (req->pubKey); i++) { printf ("%02X", req->pubKey[i]); } printf ("\n"); printf (" cipher MAC: 0x%04X\n", req->cipherMAC); printf (" decrypted payload (%u bytes):\n", req->payloadLen); uint8_t index = 0; // timestamp (first 4 bytes) if (req->payloadLen >= 4) { uint32_t timestamp = req->payload[index++]; timestamp |= req->payload[index++] << 8; timestamp |= req->payload[index++] << 16; timestamp |= req->payload[index++] << 24; printf (" timestamp: %u\n", timestamp); } // room server sync timestamp if (isRoomServer && req->payloadLen >= index + 4) { uint32_t syncTimestamp = req->payload[index++]; syncTimestamp |= req->payload[index++] << 8; syncTimestamp |= req->payload[index++] << 16; syncTimestamp |= req->payload[index++] << 24; printf (" sync timestamp: %u\n", syncTimestamp); } // remaining bytes = password if (index < req->payloadLen) { uint8_t passwordLen = req->payloadLen - index; if (passwordLen > 16) passwordLen = 16; passwordLen = strnlen (&(req->payload[index]), passwordLen); printf (" password: "); for (uint8_t i = 0; i < passwordLen; i++) { printf ("%c", req->payload[i + index]); } printf ("\n"); } } size_t strnlen (const char *s, size_t maxLen) { size_t len = 0; while (len < maxLen && s[len] != '\0') { len++; } return len; } void decodeAnonReq (const FrameStruct *frame) { uint8_t index = 0; AnonymousRequestPayload anonReq; anonReq.destinationHash = frame->payload[index++]; memcpy (anonReq.pubKey, &(frame->payload[index]), sizeof (anonReq.pubKey)); index += sizeof (anonReq.pubKey); anonReq.cipherMAC = frame->payload[index]; anonReq.cipherMAC |= frame->payload[index + 1] << 8; NodeEntry *foundNode = getNode (anonReq.pubKey[0]); if (foundNode == NULL) { foundNode = getNextNode(); strcpy (foundNode->name, "Anonymous node"); memcpy (foundNode->pubKey, anonReq.pubKey, sizeof (foundNode->pubKey)); ed25519_key_exchange ((unsigned char *)foundNode->secret, anonReq.pubKey, persistent.privkey); foundNode->gps_latitude = 0; foundNode->gps_longitude = 0; foundNode->type = 0; foundNode->last_seen_lt = RTC_GetCounter(); MESH_LOGI (TAG, "New anonymous node created: %s", foundNode->name); } else { MESH_LOGD (TAG, "Existing node found for pubKey[0]=0x%02X", anonReq.pubKey[0]); } mac_then_decrypt (foundNode->secret, 32, &(frame->payload[index]), frame->payloadLen - index, anonReq.payload); anonReq.payloadLen = frame->payloadLen - index - 2; hexdump ("AnonReq payload", anonReq.payload, anonReq.payloadLen); uint8_t index2 = 0; foundNode->last_seen_rt = anonReq.payload[index2++]; foundNode->last_seen_rt |= anonReq.payload[index2++] << 8; foundNode->last_seen_rt |= anonReq.payload[index2++] << 16; foundNode->last_seen_rt |= anonReq.payload[index2++] << 24; if (persistent.nodeType == NODE_TYPE_ROOM_SERVER) { foundNode->sync_timestamp = anonReq.payload[index2++]; foundNode->sync_timestamp |= anonReq.payload[index2++] << 8; foundNode->sync_timestamp |= anonReq.payload[index2++] << 16; foundNode->sync_timestamp |= anonReq.payload[index2++] << 24; } printAnonRequest (&anonReq, persistent.nodeType == NODE_TYPE_ROOM_SERVER); uint8_t passwordLen = anonReq.payloadLen - index2; if (passwordLen > 16) { passwordLen = 16; } passwordLen = strnlen (&(anonReq.payload[index2]), passwordLen); MESH_LOGI (TAG, "Password len is %d.", passwordLen); uint8_t passwordBuf[16]; memcpy (passwordBuf, &(anonReq.payload[index2]), passwordLen); if (memcmp (passwordBuf, persistent.password, passwordLen) == 0) { foundNode->authenticated = 1; MESH_LOGI (TAG, "Password correct, node %s authenticated.", foundNode->name); MESH_LOGI (TAG, "Login response sent to node %s.", foundNode->name); } else { MESH_LOGW (TAG, "Password incorrect for node %s.", foundNode->name); } Response resp; resp.tag = RTC_GetCounter(); uint8_t index3 = 0; uint32_t randOut = rand(); resp.data[index3++] = RESP_SERVER_LOGIN_OK; resp.data[index3++] = 0; // legacy resp.data[index3++] = foundNode->authenticated; // isadmin resp.data[index3++] = foundNode->authenticated ? PERM_ACL_ADMIN : PERM_ACL_GUEST; // permissions resp.data[index3++] = randOut & 0xFF; resp.data[index3++] = (randOut >> 8) & 0xFF; resp.data[index3++] = (randOut >> 16) & 0xFF; resp.data[index3++] = (randOut >> 24) & 0xFF; resp.data[index3++] = FIRMWARE_VER_LEVEL; resp.dataLen = index3; if ((frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_FLOOD || (frame->header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) { sendPathBack (foundNode, &(frame->path)); } sendEncryptedResponse (foundNode, &resp); }