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 +21 -0
- package/README.md +111 -0
- package/dist/core.d.ts +69 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +244 -0
- package/dist/core.js.map +1 -0
- package/dist/cpu-bruteforce.d.ts +13 -0
- package/dist/cpu-bruteforce.d.ts.map +1 -0
- package/dist/cpu-bruteforce.js +45 -0
- package/dist/cpu-bruteforce.js.map +1 -0
- package/dist/cracker.d.ts +64 -0
- package/dist/cracker.d.ts.map +1 -0
- package/dist/cracker.js +358 -0
- package/dist/cracker.js.map +1 -0
- package/dist/gpu-bruteforce.d.ts +34 -0
- package/dist/gpu-bruteforce.d.ts.map +1 -0
- package/dist/gpu-bruteforce.js +645 -0
- package/dist/gpu-bruteforce.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
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
|
package/dist/core.js.map
ADDED
|
@@ -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"}
|