Skip to content

Commit 69675e6

Browse files
committed
Enhance channel key handling: unify retrieval for Public and hashtag channels, and clarify key derivation process in documentation
1 parent 5408c73 commit 69675e6

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

.github/copilot-instructions.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,14 @@ Used by `startAutoCountdown()`, `startRxListeningCountdown()`, cooldown logic.
120120
### 2. Channel Hash & Decryption
121121
**Pre-computed at startup**:
122122
```javascript
123-
WARDRIVING_CHANNEL_KEY = await deriveChannelKey("#wardriving"); // PBKDF2 SHA-256
123+
WARDRIVING_CHANNEL_KEY = await deriveChannelKey("#wardriving"); // SHA-256 for hashtag channels
124124
WARDRIVING_CHANNEL_HASH = await computeChannelHash(key); // PSK channel identifier
125125
```
126+
127+
**Channel Key Types**:
128+
- **Hashtag channels** (`#wardriving`, `#testing`, `#ottawa`): Keys derived via SHA-256 of channel name
129+
- **Public channel** (`Public`, no hashtag): Uses fixed key `8b3387e9c5cdea6ac9e5edbaa115cd72` (default MeshCore channel)
130+
126131
Used for:
127132
- Repeater echo detection (match `channelHash` in received packets)
128133
- Message decryption (AES-ECB via aes-js library)

content/wardrive.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,16 @@ const ADVERT_HEADER = 0x11; // Header byte for ADVERT packets
6767

6868
// RX Packet Filter Configuration
6969
const MAX_RX_PATH_LENGTH = 9; // Maximum path length for RX packets (drop if exceeded to filter corrupted packets)
70-
const RX_ALLOWED_CHANNELS = ['#wardriving', '#public', '#testing', '#ottawa']; // Allowed channels for RX wardriving
70+
const RX_ALLOWED_CHANNELS = ['#wardriving', 'Public', '#testing', '#ottawa']; // Allowed channels for RX wardriving (Public uses fixed key, hashtag channels use SHA-256 derivation)
7171
const RX_PRINTABLE_THRESHOLD = 0.80; // Minimum printable character ratio for GRP_TXT (80%)
7272

73+
// Fixed key for Public channel (default MeshCore channel without hashtag)
74+
// This is a well-known key used by all MeshCore devices for the default Public channel
75+
const PUBLIC_CHANNEL_FIXED_KEY = new Uint8Array([
76+
0x8b, 0x33, 0x87, 0xe9, 0xc5, 0xcd, 0xea, 0x6a,
77+
0xc9, 0xe5, 0xed, 0xba, 0xa1, 0x15, 0xcd, 0x72
78+
]);
79+
7380
// Pre-computed channel hash and key for the wardriving channel
7481
// These will be computed once at startup and used for message correlation and decryption
7582
let WARDRIVING_CHANNEL_HASH = null;
@@ -94,7 +101,7 @@ let DEVICE_MODELS = [];
94101
// Initialize all allowed RX channels
95102
debugLog(`[INIT] Pre-computing hashes/keys for ${RX_ALLOWED_CHANNELS.length} allowed RX channels...`);
96103
for (const channelName of RX_ALLOWED_CHANNELS) {
97-
const key = await deriveChannelKey(channelName);
104+
const key = await getChannelKey(channelName);
98105
const hash = await computeChannelHash(key);
99106
RX_CHANNEL_MAP.set(hash, { name: channelName, key: key });
100107
debugLog(`[INIT] ${channelName} -> hash=0x${hash.toString(16).padStart(2, '0')}`);
@@ -1711,6 +1718,9 @@ async function primeGpsOnce() {
17111718
* This allows any hashtag channel to be used (e.g., #wardriving, #wardrive, #test).
17121719
* Channel names must start with # and contain only a-z, 0-9, and dashes.
17131720
*
1721+
* NOTE: This function is ONLY for hashtag channels. The "Public" channel (without hashtag)
1722+
* uses a fixed key defined in PUBLIC_CHANNEL_FIXED_KEY constant.
1723+
*
17141724
* Algorithm: sha256(channelName).subarray(0, 16)
17151725
*
17161726
* @param {string} channelName - The hashtag channel name (e.g., "#wardriving")
@@ -1758,6 +1768,21 @@ async function deriveChannelKey(channelName) {
17581768
return channelKey;
17591769
}
17601770

1771+
/**
1772+
* Get channel key for any channel (handles both Public and hashtag channels)
1773+
* Provides a unified interface for retrieving channel keys regardless of type
1774+
* @param {string} channelName - Channel name (e.g., "Public", "#wardriving", "#testing")
1775+
* @returns {Promise<Uint8Array>} The 16-byte channel key
1776+
*/
1777+
async function getChannelKey(channelName) {
1778+
if (channelName === 'Public') {
1779+
debugLog(`[CHANNEL] Using fixed key for Public channel`);
1780+
return PUBLIC_CHANNEL_FIXED_KEY;
1781+
} else {
1782+
return await deriveChannelKey(channelName);
1783+
}
1784+
}
1785+
17611786
// ---- Channel helpers ----
17621787
async function createWardriveChannel() {
17631788
if (!state.connection) throw new Error("Not connected");

0 commit comments

Comments
 (0)