meshcore-hashtag-cracker 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jack Kingsman <jack@jackkingsman.me>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # MeshCore GroupText Hashtag Room Cracker
2
+
3
+ Standalone library for cracking MeshCore GroupText packets from hashtag rooms using WebGPU-accelerated brute force (with fallbacks for our non-GPU brethren).
4
+
5
+ **Note:** This tool is designed exclusively for cracking public hashtag rooms (e.g., `#general`, `#test`). It does not support private rooms or other MeshCore encryption schemes (or, rather, it will attempt to crack them, but nearly certainly fail)
6
+
7
+ This is an LLM-developed library and has borne out its correctness in various application uses, but caution should still be applied in any mission-critical contexts.
8
+
9
+ ## Features
10
+
11
+ - WebGPU-accelerated brute force (100M+ keys/second on modern GPUs)
12
+ - Dictionary attack support with external wordlist
13
+ - Configurable timestamp and UTF-8 filters
14
+ - Progress callbacks with ETA
15
+ - Resume support for interrupted searches
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install meshcore-cracker
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```typescript
26
+ import { GroupTextCracker } from 'meshcore-cracker';
27
+
28
+ const cracker = new GroupTextCracker();
29
+
30
+ // Example GroupText packet (hex string, no spaces or 0x prefix)
31
+ const packetHex = '150013752F15A1BF3C018EB1FC4F26B5FAEB417BB0F1AE8FF07655484EBAA05CB9A927D689';
32
+
33
+ const result = await cracker.crack(packetHex, {
34
+ maxLength: 6,
35
+ });
36
+
37
+ if (result.found) {
38
+ console.log(`Room: #${result.roomName}`);
39
+ console.log(`Key: ${result.key}`);
40
+ console.log(`Message: ${result.decryptedMessage}`);
41
+ }
42
+
43
+ cracker.destroy();
44
+ ```
45
+
46
+ **Output:**
47
+ ```
48
+ Room: #aa
49
+ Key: e147f36926b7b509af9b41b65304dc30
50
+ Message: foo
51
+ ```
52
+
53
+ ### Options
54
+
55
+ ```typescript
56
+ const result = await cracker.crack(packetHex, {
57
+ maxLength: 8, // Max room name length to try (default: 8)
58
+ startingLength: 1, // Min room name length to try (default: 1)
59
+ useDictionary: true, // Try dictionary words first (default: true)
60
+ useTimestampFilter: true, // Reject old timestamps (default: true)
61
+ validSeconds: 2592000, // Timestamp window in seconds (default: 30 days)
62
+ useUtf8Filter: true, // Reject invalid UTF-8 (default: true)
63
+ forceCpu: false, // Force CPU mode, skip GPU (default: false)
64
+ startFrom: 'abc', // Resume from position (optional)
65
+ });
66
+ ```
67
+
68
+ For detailed API documentation, see [API.md](./API.md).
69
+
70
+ ## Browser Requirements
71
+
72
+ - WebGPU support (Chrome 113+, Edge 113+, or other Chromium-based browsers)
73
+ - HTTPS connection for non-localhost hostnames (falls back gracefully with an error if WebGPU is not available)
74
+
75
+ ## Performance
76
+
77
+ Typical performance on modern hardware:
78
+ - **GPU (RTX 3080)**: ~500M keys/second
79
+ - **GPU (integrated)**: ~50M keys/second
80
+
81
+ Search space by room name length:
82
+ | Length | Candidates | Time @ 100M/s |
83
+ |--------|------------|---------------|
84
+ | 1 | 36 | instant |
85
+ | 2 | 1,296 | instant |
86
+ | 3 | 47,952 | instant |
87
+ | 4 | 1,774,224 | <1s |
88
+ | 5 | 65,646,288 | <1s |
89
+ | 6 | 2,428,912,656 | ~24s |
90
+ | 7 | 89,869,768,272 | ~15min |
91
+ | 8 | 3,325,181,426,064 | ~9h |
92
+
93
+ ## Development
94
+
95
+ ```bash
96
+ # Install dependencies
97
+ npm install
98
+
99
+ # Build
100
+ npm run build
101
+
102
+ # Run tests
103
+ npm test
104
+
105
+ # Run tests in watch mode
106
+ npm run test:watch
107
+ ```
108
+
109
+ ## License
110
+
111
+ MIT
package/dist/core.d.ts ADDED
@@ -0,0 +1,69 @@
1
+ export declare const CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
2
+ export declare const CHARS_LEN: number;
3
+ export declare const CHARS_WITH_DASH: string;
4
+ export declare const PUBLIC_ROOM_NAME = "[[public room]]";
5
+ export declare const PUBLIC_KEY = "8b3387e9c5cdea6ac9e5edbaa115cd72";
6
+ export declare const DEFAULT_VALID_SECONDS: number;
7
+ /**
8
+ * Convert room name to (length, index) for resuming/skipping.
9
+ * Index encoding: LSB-first (first character = least significant digit).
10
+ */
11
+ export declare function roomNameToIndex(name: string): {
12
+ length: number;
13
+ index: number;
14
+ } | null;
15
+ /**
16
+ * Convert (length, index) to room name.
17
+ * Index encoding: LSB-first (first character = least significant digit).
18
+ */
19
+ export declare function indexToRoomName(length: number, idx: number): string | null;
20
+ /**
21
+ * Derive 128-bit key from room name using SHA256.
22
+ * Room names are prefixed with '#' before hashing.
23
+ */
24
+ export declare function deriveKeyFromRoomName(roomName: string): string;
25
+ /**
26
+ * Compute channel hash (first byte of SHA256(key)).
27
+ */
28
+ export declare function getChannelHash(keyHex: string): string;
29
+ /**
30
+ * Verify MAC using HMAC-SHA256 with 32-byte padded key.
31
+ */
32
+ export declare function verifyMac(ciphertext: string, cipherMac: string, keyHex: string): boolean;
33
+ /**
34
+ * Count valid room names for a given length.
35
+ * Accounts for dash rules (no start/end dash, no consecutive dashes).
36
+ */
37
+ export declare function countNamesForLength(len: number): number;
38
+ /**
39
+ * Check if timestamp is within the validity window.
40
+ * @param timestamp - Unix timestamp to validate
41
+ * @param validSeconds - Validity window in seconds (default: 30 days)
42
+ * @param now - Current time for testing (default: current time)
43
+ */
44
+ export declare function isTimestampValid(timestamp: number, validSeconds?: number, now?: number): boolean;
45
+ /**
46
+ * Check for valid UTF-8 (no replacement characters).
47
+ */
48
+ export declare function isValidUtf8(text: string): boolean;
49
+ /**
50
+ * Room name generator - iterates through all valid room names.
51
+ */
52
+ export declare class RoomNameGenerator {
53
+ private length;
54
+ private indices;
55
+ private done;
56
+ private currentInLength;
57
+ private totalForLength;
58
+ current(): string;
59
+ getLength(): number;
60
+ getCurrentInLength(): number;
61
+ getTotalForLength(): number;
62
+ getRemainingInLength(): number;
63
+ isDone(): boolean;
64
+ next(): boolean;
65
+ private isValid;
66
+ nextValid(): boolean;
67
+ skipTo(targetLength: number, targetIndex: number): void;
68
+ }
69
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,KAAK,yCAAyC,CAAC;AAC5D,eAAO,MAAM,SAAS,QAAe,CAAC;AACtC,eAAO,MAAM,eAAe,QAAc,CAAC;AAG3C,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAClD,eAAO,MAAM,UAAU,qCAAqC,CAAC;AAG7D,eAAO,MAAM,qBAAqB,QAAoB,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA+BtF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B1E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKxF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBvD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,YAAY,GAAE,MAA8B,EAC5C,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAGT;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,cAAc,CAAa;IAEnC,OAAO,IAAI,MAAM;IAIjB,SAAS,IAAI,MAAM;IAInB,kBAAkB,IAAI,MAAM;IAI5B,iBAAiB,IAAI,MAAM;IAI3B,oBAAoB,IAAI,MAAM;IAI9B,MAAM,IAAI,OAAO;IAIjB,IAAI,IAAI,OAAO;IA6Cf,OAAO,CAAC,OAAO;IAcf,SAAS,IAAI,OAAO;IAWpB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;CAiBxD"}
package/dist/core.js ADDED
@@ -0,0 +1,244 @@
1
+ // Core logic for MeshCore packet cracker - pure functions
2
+ import SHA256 from 'crypto-js/sha256';
3
+ import HmacSHA256 from 'crypto-js/hmac-sha256';
4
+ import Hex from 'crypto-js/enc-hex';
5
+ // Room name character set
6
+ export const CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789';
7
+ export const CHARS_LEN = CHARS.length; // 36
8
+ export const CHARS_WITH_DASH = CHARS + '-';
9
+ // Public room special case
10
+ export const PUBLIC_ROOM_NAME = '[[public room]]';
11
+ export const PUBLIC_KEY = '8b3387e9c5cdea6ac9e5edbaa115cd72';
12
+ // Default timestamp validity window (30 days in seconds)
13
+ export const DEFAULT_VALID_SECONDS = 30 * 24 * 60 * 60;
14
+ /**
15
+ * Convert room name to (length, index) for resuming/skipping.
16
+ * Index encoding: LSB-first (first character = least significant digit).
17
+ */
18
+ export function roomNameToIndex(name) {
19
+ if (!name || name.length === 0) {
20
+ return null;
21
+ }
22
+ const length = name.length;
23
+ let index = 0;
24
+ let multiplier = 1;
25
+ // Process from left to right (first char is LSB, matching indexToRoomName)
26
+ for (let i = 0; i < length; i++) {
27
+ const c = name[i];
28
+ const charIdx = CHARS_WITH_DASH.indexOf(c);
29
+ if (charIdx === -1) {
30
+ return null;
31
+ } // Invalid character
32
+ const isFirst = i === 0;
33
+ const isLast = i === length - 1;
34
+ const charCount = isFirst || isLast ? 36 : 37;
35
+ // Dash not allowed at start/end
36
+ if ((isFirst || isLast) && charIdx === 36) {
37
+ return null;
38
+ }
39
+ index += charIdx * multiplier;
40
+ multiplier *= charCount;
41
+ }
42
+ return { length, index };
43
+ }
44
+ /**
45
+ * Convert (length, index) to room name.
46
+ * Index encoding: LSB-first (first character = least significant digit).
47
+ */
48
+ export function indexToRoomName(length, idx) {
49
+ if (length <= 0) {
50
+ return null;
51
+ }
52
+ let result = '';
53
+ let remaining = idx;
54
+ let prevWasDash = false;
55
+ for (let i = 0; i < length; i++) {
56
+ const isFirst = i === 0;
57
+ const isLast = i === length - 1;
58
+ const charCount = isFirst || isLast ? 36 : 37;
59
+ const charIdx = remaining % charCount;
60
+ remaining = Math.floor(remaining / charCount);
61
+ const isDash = charIdx === 36;
62
+ if (isDash && prevWasDash) {
63
+ return null;
64
+ } // Invalid: consecutive dashes
65
+ prevWasDash = isDash;
66
+ result += CHARS_WITH_DASH[charIdx];
67
+ }
68
+ return result;
69
+ }
70
+ /**
71
+ * Derive 128-bit key from room name using SHA256.
72
+ * Room names are prefixed with '#' before hashing.
73
+ */
74
+ export function deriveKeyFromRoomName(roomName) {
75
+ if (roomName === PUBLIC_ROOM_NAME) {
76
+ return PUBLIC_KEY;
77
+ }
78
+ const hash = SHA256(roomName);
79
+ return hash.toString(Hex).substring(0, 32);
80
+ }
81
+ /**
82
+ * Compute channel hash (first byte of SHA256(key)).
83
+ */
84
+ export function getChannelHash(keyHex) {
85
+ const hash = SHA256(Hex.parse(keyHex));
86
+ return hash.toString(Hex).substring(0, 2);
87
+ }
88
+ /**
89
+ * Verify MAC using HMAC-SHA256 with 32-byte padded key.
90
+ */
91
+ export function verifyMac(ciphertext, cipherMac, keyHex) {
92
+ const paddedKey = keyHex.padEnd(64, '0');
93
+ const hmac = HmacSHA256(Hex.parse(ciphertext), Hex.parse(paddedKey));
94
+ const computed = hmac.toString(Hex).substring(0, 4).toLowerCase();
95
+ return computed === cipherMac.toLowerCase();
96
+ }
97
+ /**
98
+ * Count valid room names for a given length.
99
+ * Accounts for dash rules (no start/end dash, no consecutive dashes).
100
+ */
101
+ export function countNamesForLength(len) {
102
+ if (len === 1) {
103
+ return CHARS_LEN;
104
+ }
105
+ if (len === 2) {
106
+ return CHARS_LEN * CHARS_LEN;
107
+ }
108
+ // For length >= 3: first and last are CHARS (36), middle follows no-consecutive-dash rule
109
+ // Middle length = len - 2
110
+ // Use DP: count sequences of length k with no consecutive dashes
111
+ // endsWithNonDash[k], endsWithDash[k]
112
+ let endsNonDash = CHARS_LEN; // length 1 middle
113
+ let endsDash = 1;
114
+ for (let i = 2; i <= len - 2; i++) {
115
+ const newEndsNonDash = (endsNonDash + endsDash) * CHARS_LEN;
116
+ const newEndsDash = endsNonDash; // dash can only follow non-dash
117
+ endsNonDash = newEndsNonDash;
118
+ endsDash = newEndsDash;
119
+ }
120
+ const middleCount = len > 2 ? endsNonDash + endsDash : 1;
121
+ return CHARS_LEN * middleCount * CHARS_LEN;
122
+ }
123
+ /**
124
+ * Check if timestamp is within the validity window.
125
+ * @param timestamp - Unix timestamp to validate
126
+ * @param validSeconds - Validity window in seconds (default: 30 days)
127
+ * @param now - Current time for testing (default: current time)
128
+ */
129
+ export function isTimestampValid(timestamp, validSeconds = DEFAULT_VALID_SECONDS, now) {
130
+ const currentTime = now ?? Math.floor(Date.now() / 1000);
131
+ return timestamp <= currentTime && timestamp >= currentTime - validSeconds;
132
+ }
133
+ /**
134
+ * Check for valid UTF-8 (no replacement characters).
135
+ */
136
+ export function isValidUtf8(text) {
137
+ return !text.includes('\uFFFD');
138
+ }
139
+ /**
140
+ * Room name generator - iterates through all valid room names.
141
+ */
142
+ export class RoomNameGenerator {
143
+ constructor() {
144
+ this.length = 1;
145
+ this.indices = [0];
146
+ this.done = false;
147
+ this.currentInLength = 0;
148
+ this.totalForLength = CHARS_LEN;
149
+ }
150
+ current() {
151
+ return this.indices.map((i) => (i === CHARS_LEN ? '-' : CHARS[i])).join('');
152
+ }
153
+ getLength() {
154
+ return this.length;
155
+ }
156
+ getCurrentInLength() {
157
+ return this.currentInLength;
158
+ }
159
+ getTotalForLength() {
160
+ return this.totalForLength;
161
+ }
162
+ getRemainingInLength() {
163
+ return this.totalForLength - this.currentInLength;
164
+ }
165
+ isDone() {
166
+ return this.done;
167
+ }
168
+ next() {
169
+ if (this.done) {
170
+ return false;
171
+ }
172
+ this.currentInLength++;
173
+ // Increment with carry, respecting dash rules
174
+ let pos = this.length - 1;
175
+ while (pos >= 0) {
176
+ const isFirst = pos === 0;
177
+ const isLast = pos === this.length - 1;
178
+ const maxVal = isFirst || isLast ? CHARS_LEN - 1 : CHARS_LEN; // CHARS_LEN = dash index
179
+ if (this.indices[pos] < maxVal) {
180
+ this.indices[pos]++;
181
+ // Check dash rule: no consecutive dashes
182
+ if (this.indices[pos] === CHARS_LEN && pos > 0 && this.indices[pos - 1] === CHARS_LEN) {
183
+ // Would create consecutive dashes, continue incrementing
184
+ continue;
185
+ }
186
+ // Reset all positions after this one
187
+ for (let i = pos + 1; i < this.length; i++) {
188
+ this.indices[i] = 0;
189
+ }
190
+ // Validate: check no consecutive dashes in reset portion
191
+ if (this.isValid()) {
192
+ return true;
193
+ }
194
+ continue;
195
+ }
196
+ pos--;
197
+ }
198
+ // Overflow - increase length
199
+ this.length++;
200
+ this.indices = new Array(this.length).fill(0);
201
+ this.currentInLength = 0;
202
+ this.totalForLength = countNamesForLength(this.length);
203
+ return true;
204
+ }
205
+ isValid() {
206
+ for (let i = 0; i < this.length; i++) {
207
+ const isDash = this.indices[i] === CHARS_LEN;
208
+ if (isDash && (i === 0 || i === this.length - 1)) {
209
+ return false;
210
+ }
211
+ if (isDash && i > 0 && this.indices[i - 1] === CHARS_LEN) {
212
+ return false;
213
+ }
214
+ }
215
+ return true;
216
+ }
217
+ // Skip invalid combinations efficiently
218
+ nextValid() {
219
+ do {
220
+ if (!this.next()) {
221
+ return false;
222
+ }
223
+ } while (!this.isValid());
224
+ return true;
225
+ }
226
+ // Skip to a specific (length, index) position
227
+ // Index encoding: first char is LSB (consistent with indexToRoomName)
228
+ skipTo(targetLength, targetIndex) {
229
+ this.length = targetLength;
230
+ this.indices = new Array(targetLength).fill(0);
231
+ this.totalForLength = countNamesForLength(targetLength);
232
+ // Convert index to indices array (LSB first = position 0)
233
+ let remaining = targetIndex;
234
+ for (let i = 0; i < targetLength; i++) {
235
+ const isFirst = i === 0;
236
+ const isLast = i === targetLength - 1;
237
+ const charCount = isFirst || isLast ? CHARS_LEN : CHARS_LEN + 1;
238
+ this.indices[i] = remaining % charCount;
239
+ remaining = Math.floor(remaining / charCount);
240
+ }
241
+ this.currentInLength = targetIndex;
242
+ }
243
+ }
244
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * CPU-based brute force implementation.
3
+ * Much slower than GPU but works everywhere.
4
+ */
5
+ export declare class CpuBruteForce {
6
+ /**
7
+ * Run a batch of candidates on CPU.
8
+ * Returns indices of candidates that match the channel hash and MAC.
9
+ */
10
+ runBatch(targetChannelHash: number, nameLength: number, batchOffset: number, batchSize: number, ciphertextHex?: string, targetMacHex?: string): number[];
11
+ destroy(): void;
12
+ }
13
+ //# sourceMappingURL=cpu-bruteforce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpu-bruteforce.d.ts","sourceRoot":"","sources":["../src/cpu-bruteforce.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,qBAAa,aAAa;IACxB;;;OAGG;IACH,QAAQ,CACN,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,MAAM,EACtB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,EAAE;IAoCX,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,45 @@
1
+ // CPU-based brute force key cracking for MeshCore packets
2
+ // Fallback for environments without WebGPU support
3
+ import { indexToRoomName, deriveKeyFromRoomName, getChannelHash, verifyMac, } from './core';
4
+ /**
5
+ * CPU-based brute force implementation.
6
+ * Much slower than GPU but works everywhere.
7
+ */
8
+ export class CpuBruteForce {
9
+ /**
10
+ * Run a batch of candidates on CPU.
11
+ * Returns indices of candidates that match the channel hash and MAC.
12
+ */
13
+ runBatch(targetChannelHash, nameLength, batchOffset, batchSize, ciphertextHex, targetMacHex) {
14
+ const matches = [];
15
+ const targetHashHex = targetChannelHash.toString(16).padStart(2, '0');
16
+ const verifyMacEnabled = !!(ciphertextHex && targetMacHex);
17
+ for (let i = 0; i < batchSize; i++) {
18
+ const nameIdx = batchOffset + i;
19
+ const roomName = indexToRoomName(nameLength, nameIdx);
20
+ if (!roomName) {
21
+ continue; // Invalid index (e.g., consecutive dashes)
22
+ }
23
+ // Derive key from room name (with # prefix)
24
+ const key = deriveKeyFromRoomName('#' + roomName);
25
+ // Check channel hash
26
+ const channelHash = getChannelHash(key);
27
+ if (channelHash !== targetHashHex) {
28
+ continue;
29
+ }
30
+ // Channel hash matches - verify MAC if enabled
31
+ if (verifyMacEnabled) {
32
+ if (!verifyMac(ciphertextHex, targetMacHex, key)) {
33
+ continue;
34
+ }
35
+ }
36
+ // Found a match
37
+ matches.push(nameIdx);
38
+ }
39
+ return matches;
40
+ }
41
+ destroy() {
42
+ // No resources to clean up for CPU implementation
43
+ }
44
+ }
45
+ //# sourceMappingURL=cpu-bruteforce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpu-bruteforce.js","sourceRoot":"","sources":["../src/cpu-bruteforce.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,mDAAmD;AAEnD,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,SAAS,GACV,MAAM,QAAQ,CAAC;AAEhB;;;GAGG;AACH,MAAM,OAAO,aAAa;IACxB;;;OAGG;IACH,QAAQ,CACN,iBAAyB,EACzB,UAAkB,EAClB,WAAmB,EACnB,SAAiB,EACjB,aAAsB,EACtB,YAAqB;QAErB,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACtE,MAAM,gBAAgB,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,YAAY,CAAC,CAAC;QAE3D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,WAAW,GAAG,CAAC,CAAC;YAChC,MAAM,QAAQ,GAAG,eAAe,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAEtD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,SAAS,CAAC,2CAA2C;YACvD,CAAC;YAED,4CAA4C;YAC5C,MAAM,GAAG,GAAG,qBAAqB,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC;YAElD,qBAAqB;YACrB,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,WAAW,KAAK,aAAa,EAAE,CAAC;gBAClC,SAAS;YACX,CAAC;YAED,+CAA+C;YAC/C,IAAI,gBAAgB,EAAE,CAAC;gBACrB,IAAI,CAAC,SAAS,CAAC,aAAc,EAAE,YAAa,EAAE,GAAG,CAAC,EAAE,CAAC;oBACnD,SAAS;gBACX,CAAC;YACH,CAAC;YAED,gBAAgB;YAChB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,kDAAkD;IACpD,CAAC;CACF"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * GroupTextCracker - Standalone MeshCore GroupText packet cracker
3
+ *
4
+ * Cracks encrypted GroupText packets by trying room names until the
5
+ * correct encryption key is found.
6
+ */
7
+ import type { CrackOptions, CrackResult, ProgressCallback, DecodedPacket } from './types';
8
+ /**
9
+ * Main cracker class for MeshCore GroupText packets.
10
+ */
11
+ export declare class GroupTextCracker {
12
+ private gpuInstance;
13
+ private cpuInstance;
14
+ private wordlist;
15
+ private abortFlag;
16
+ private useTimestampFilter;
17
+ private useUtf8Filter;
18
+ private validSeconds;
19
+ private useCpu;
20
+ /**
21
+ * Load a wordlist from a URL for dictionary attacks.
22
+ * The wordlist should be a text file with one word per line.
23
+ *
24
+ * @param url - URL to fetch the wordlist from
25
+ */
26
+ loadWordlist(url: string): Promise<void>;
27
+ /**
28
+ * Set the wordlist directly from an array of words.
29
+ *
30
+ * @param words - Array of room names to try
31
+ */
32
+ setWordlist(words: string[]): void;
33
+ /**
34
+ * Abort the current cracking operation.
35
+ * The crack() method will return with aborted: true.
36
+ */
37
+ abort(): void;
38
+ /**
39
+ * Check if WebGPU is available in the current environment.
40
+ */
41
+ isGpuAvailable(): boolean;
42
+ /**
43
+ * Decode a packet and extract the information needed for cracking.
44
+ *
45
+ * @param packetHex - The packet data as a hex string
46
+ * @returns Decoded packet info or null if not a GroupText packet
47
+ */
48
+ decodePacket(packetHex: string): Promise<DecodedPacket | null>;
49
+ /**
50
+ * Crack a GroupText packet to find the room name and decrypt the message.
51
+ *
52
+ * @param packetHex - The packet data as a hex string
53
+ * @param options - Cracking options
54
+ * @param onProgress - Optional callback for progress updates
55
+ * @returns The cracking result
56
+ */
57
+ crack(packetHex: string, options?: CrackOptions, onProgress?: ProgressCallback): Promise<CrackResult>;
58
+ /**
59
+ * Clean up resources.
60
+ * Call this when you're done using the cracker.
61
+ */
62
+ destroy(): void;
63
+ }
64
+ //# sourceMappingURL=cracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cracker.d.ts","sourceRoot":"","sources":["../src/cracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAkB,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAe1G;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,MAAM,CAAS;IAEvB;;;;;OAKG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB9C;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAMlC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB;;;;;OAKG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA8BpE;;;;;;;OAOG;IACG,KAAK,CACT,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,YAAY,EACtB,UAAU,CAAC,EAAE,gBAAgB,GAC5B,OAAO,CAAC,WAAW,CAAC;IAsRvB;;;OAGG;IACH,OAAO,IAAI,IAAI;CAUhB"}