Public Access
LoRa Scanner: MeshCore by default, and its public channel read
The MeshCore preset is the default for a new device, in the Settings and in the radio before the Scanner is opened. The setting now accepts it: it only took the 7 Meshtastic presets, so MeshCore picked in the App was not saved. Messages on MeshCore's public channel are decrypted with the channel's published key (AES-128, checked with 2 bytes of HMAC-SHA256): the row shows who says they sent it and the start of the text, the details the sender, the time and the whole text. Other channels and private messages stay encrypted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "aes128.h"
|
||||
#include "meshcore_channel.h"
|
||||
#include "meshcore_packet.h"
|
||||
#include "packet_view.h"
|
||||
#include "scan_presets.h"
|
||||
@@ -187,9 +189,67 @@ void test_discover_as_heard() {
|
||||
TEST_ASSERT_EQUAL_STRING("It heard the search at 11.2 dB SNR", lines[4].c_str());
|
||||
}
|
||||
|
||||
void test_aes128_decrypts_the_standard_block() { // FIPS 197, appendix C.1
|
||||
uint8_t key[16], in[16] = {0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a}, out[16];
|
||||
for (int i = 0; i < 16; ++i) key[i] = static_cast<uint8_t>(i);
|
||||
Aes128(key).decryptBlock(in, out);
|
||||
for (int i = 0; i < 16; ++i) TEST_ASSERT_EQUAL_HEX8(i * 0x11, out[i]);
|
||||
}
|
||||
|
||||
// Messages on the public channel, relayed twice, encrypted and signed with openssl:
|
||||
// "Alice: hello from Brussels" and "Zo\xc3\xa9: \xc3\xa7a va ?", both sent at 1791575000.
|
||||
static const uint8_t kHello[] = {0x15, 0x02, 0xa3, 0x7f, 0x11, 0x20, 0x14, 0x90, 0xb7, 0xe1, 0x1d, 0x46, 0x5f,
|
||||
0x3f, 0xac, 0x4f, 0x98, 0xa8, 0xc6, 0x07, 0x79, 0x4c, 0x96, 0x19, 0x5e, 0x54,
|
||||
0x60, 0x67, 0x2b, 0x2e, 0xec, 0x0e, 0xe4, 0x6a, 0xbc, 0x8b, 0x51, 0x38, 0xfd};
|
||||
static const uint8_t kAccents[] = {0x15, 0x02, 0xa3, 0x7f, 0x11, 0x19, 0xdd, 0x85, 0x58, 0xc5, 0x73, 0x2d, 0x55,
|
||||
0x4d, 0xf4, 0xfd, 0x02, 0x47, 0xdc, 0xfa, 0xa2, 0xce, 0x3b, 0xcb, 0xb1, 0x8e,
|
||||
0x8f, 0x66, 0xc7, 0xd6, 0x61, 0x30, 0x3c, 0xbe, 0x29, 0xd7, 0xb8, 0x08, 0x26};
|
||||
|
||||
void test_public_channel_message() {
|
||||
TEST_ASSERT_EQUAL_HEX8(kPublicChannelHash, channelHash(channel(0)));
|
||||
Packet p;
|
||||
ChannelText t;
|
||||
TEST_ASSERT_TRUE(parsePacket(kHello, sizeof kHello, p));
|
||||
TEST_ASSERT_TRUE(readChannelText(p, t));
|
||||
TEST_ASSERT_EQUAL_STRING("Public", t.channel);
|
||||
TEST_ASSERT_EQUAL_UINT32(1791575000, t.timestamp);
|
||||
TEST_ASSERT_EQUAL_STRING("Alice", t.sender.c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("hello from Brussels", t.text.c_str());
|
||||
|
||||
TEST_ASSERT_TRUE(parsePacket(kAccents, sizeof kAccents, p));
|
||||
TEST_ASSERT_TRUE(readChannelText(p, t));
|
||||
TEST_ASSERT_EQUAL_STRING("Zo?", t.sender.c_str()); // one '?' for a character outside ASCII
|
||||
TEST_ASSERT_EQUAL_STRING("?a va ?", t.text.c_str());
|
||||
|
||||
// One bit wrong and the check fails: nothing is made up from it.
|
||||
std::vector<uint8_t> bad(kHello, kHello + sizeof kHello);
|
||||
bad[20] ^= 1;
|
||||
TEST_ASSERT_TRUE(parsePacket(bad.data(), bad.size(), p));
|
||||
TEST_ASSERT_FALSE(readChannelText(p, t));
|
||||
// Another channel with the same first byte, or not whole blocks: left encrypted.
|
||||
bad.assign(kHello, kHello + sizeof kHello - 1);
|
||||
TEST_ASSERT_TRUE(parsePacket(bad.data(), bad.size(), p));
|
||||
TEST_ASSERT_FALSE(readChannelText(p, t));
|
||||
}
|
||||
|
||||
void test_public_channel_message_shown() {
|
||||
lora::PacketSummary s{kHello, sizeof kHello, -97, 6.2f, true, lora::Protocol::MeshCore};
|
||||
std::string row = lora::row(s, "21:45:07");
|
||||
TEST_ASSERT_EQUAL_STRING("21:45:07 -97 6.2 Alice: hello from 2h", row.c_str());
|
||||
TEST_ASSERT_LESS_OR_EQUAL(38, row.size());
|
||||
auto lines = lora::headerLines(kHello, sizeof kHello, lora::Protocol::MeshCore);
|
||||
TEST_ASSERT_EQUAL_size_t(5, lines.size());
|
||||
TEST_ASSERT_EQUAL_STRING("MeshCore channel message, flood", lines[0].c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("Through a3 7f", lines[1].c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("On the Public channel, from Alice", lines[2].c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("Sent 2026-10-09 19:43:20 UTC", lines[3].c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("hello from Brussels", lines[4].c_str());
|
||||
}
|
||||
|
||||
void test_scan_presets() {
|
||||
TEST_ASSERT_EQUAL_size_t(8, lora::scanPresetCount());
|
||||
lora::ScanPreset p = lora::scanPreset(0); // the default stays first: it is stored by number
|
||||
TEST_ASSERT_EQUAL_STRING("MeshCore", lora::scanPreset(lora::kDefaultScanPreset).name);
|
||||
lora::ScanPreset p = lora::scanPreset(0); // the order stays: a preset is stored by number
|
||||
TEST_ASSERT_EQUAL_STRING("LongFast", p.name);
|
||||
TEST_ASSERT_EQUAL_UINT32(869525000u, p.frequencyHz);
|
||||
TEST_ASSERT_EQUAL_HEX8(0x2B, p.syncWord);
|
||||
@@ -218,6 +278,9 @@ int main() {
|
||||
RUN_TEST(test_rows);
|
||||
RUN_TEST(test_detail_lines);
|
||||
RUN_TEST(test_discover_as_heard);
|
||||
RUN_TEST(test_aes128_decrypts_the_standard_block);
|
||||
RUN_TEST(test_public_channel_message);
|
||||
RUN_TEST(test_public_channel_message_shown);
|
||||
RUN_TEST(test_scan_presets);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user