2 Generate Broadcom CFE seeds and passwords for many popular modem/router devices
4 Copyright 2015 TJ <hacker@iam.tj>
5 Licenced on the terms of the GNU General Public Licence version 3
9 gcc -o cfe_gen_pass cfe_generate_password.c
17 ./cfe_gen_pass [options]
19 This tool can generate passwords for use with many devices that contain
20 Broadcom Common Firmware Environment (CFE) bootbase which has a debug mode
21 that is enabled using the "ATEN 1 XXXXXXXX" command, where XXXXXXXX is an
22 eight digit hexadecimal 'password'.
24 It is NOT necessary to have the device generate a 'seed' using "ATSE [MODEL-ID]"
25 because this tool can generate the seed from the device's first (base) MAC address
26 *provided* the "ATSE" command has NOT been executed since the device last booted.
28 Access to the device's console via a serial UART port is required to enter the password.
30 So, for a device with base MAC address (reported by the CFE during boot) E.g:
32 CFE version 1.0.38-112.118 for BCM963268 (32bit,SP,BE)
34 Base MAC Address : ec:43:f6:46:c0:80
36 *** Press any key to stop auto run (1 seconds) ***
41 ./cfe_gen_pass -s ec:43:f6:46:c0:80 -p
43 MAC address: ec:43:f6:46:c0:80 Timestamp: 000000 Seed: 00000046c080 Password: 10f0a563
49 *** command status = 0
51 The tool can accept a timestamp as 6 hexadecimal characters (useful for testing the algorithm):
53 ./cfe_gen_pass -t 0FF020 -s ec:43:f6:46:c0:80 -p
55 MAC address: ec:43:f6:46:c0:80 Timestamp: 0FF020 Seed: 0FF02046c080 Password: 110f65a3
63 static const float VERSION = 1.1f;
64 static const size_t TIMESTAMP_SIZE = 6;
65 static const size_t SEED_SIZE = 12;
66 static const size_t PASSWORD_SIZE = 8;
67 static const size_t MESSAGE_SIZE = 128;
68 static const size_t MAC_ADDR_SIZE = 17;
73 fprintf(stderr, "%s\n",
76 " -s 00:01:02:03:04:05 create seed from MAC address\n"
77 " -t 000000 millisecond timestamp since boot\n"
78 " -p [SEED] generate password (with optional seed)\n\n"
79 " E.g. -s 01:02:03:04:05 \n"
80 " -s 01:02:03:04:05 -p\n"
86 pr_error_exit(unsigned int usage, const char *error, ...)
89 char error_message[MESSAGE_SIZE + 1];
93 va_start(args, error);
94 (void) vsnprintf(error_message, MESSAGE_SIZE + 1, error, args);
96 fprintf(stderr, "Error: %s\n", error_message);
98 if (usage) pr_usage();
103 static const unsigned int passwords[8] = {
115 generate_seed(char *mac, char *timestamp, char *seed)
117 unsigned int result = 0;
118 if (mac && strlen(mac) == MAC_ADDR_SIZE) {
120 char *mac_ptr = mac + 9;
121 size_t ts_len = strlen(timestamp);
122 for (i = 0; i < SEED_SIZE; ++i) {
123 /* if no timestamp assume CFE get_time() returned 0 and CFE g_pw_timestamp == 0x00000000 */
125 seed[i] = ts_len ? timestamp[i] : '0';
127 if (*mac_ptr == ':' || *mac_ptr == '-')
129 seed[i] = *mac_ptr++;
134 pr_error_exit(0, "MAC-ADDR should be %d characters, e.g: 00:01:02:03:04:05", MAC_ADDR_SIZE);
140 generate_pass(char *seed, char *password)
142 unsigned int result = 0;
144 if (seed && strlen(seed) == SEED_SIZE) {
145 unsigned int timestamp, byte, key, pass;
146 timestamp = byte = 0;
147 if(! sscanf(seed, "%06x", ×tamp))
148 pr_error_exit(1, "unable to parse seed's timestamp");
149 if (! sscanf(&seed[10], "%02x", &byte))
150 pr_error_exit(1, "unable to parse seed's MAC address");
152 pass = (passwords[key] + timestamp) ^ timestamp;
153 snprintf(password, PASSWORD_SIZE + 1, "%08x", pass);
156 pr_error_exit(0, "Seed should be %d hex characters", SEED_SIZE);
162 main(int argc, char **argv, char **env)
171 char *MAC_ADDR = NULL;
172 char timestamp[TIMESTAMP_SIZE + 1];
173 char seed[SEED_SIZE + 1];
174 char password[PASSWORD_SIZE + 1];
175 unsigned int opt_seed, opt_pass, opt_ts;
176 seed[0] = password[0] = 0;
177 seed[SEED_SIZE] = password[PASSWORD_SIZE] = timestamp[TIMESTAMP_SIZE] = 0;
178 opt_seed = opt_pass = opt_ts = 0;
179 strncpy(timestamp, "000000", TIMESTAMP_SIZE);
181 for (arg = 1; arg < (unsigned) argc; ++arg) {
182 size_t arg_len = strlen(argv[arg]);
184 if (argv[arg][0] == '-') {
185 switch (argv[arg][1]) {
196 fprintf(stderr, "Version: %0.2f\n", VERSION);
198 } else if (opt_seed == 1) {
199 MAC_ADDR = argv[arg];
201 } else if (opt_pass == 1 && opt_seed == 0) {
202 if (arg_len != SEED_SIZE)
203 pr_error_exit(1, "seed length must be %d characters", SEED_SIZE);
205 strncpy(seed, argv[arg], SEED_SIZE);
207 } else if (opt_ts == 1) {
208 if (arg_len != TIMESTAMP_SIZE)
209 pr_error_exit(1, "timestamp length must be %d characters", TIMESTAMP_SIZE);
211 strncpy(timestamp, argv[arg], TIMESTAMP_SIZE);
215 if (! opt_seed && ! opt_pass)
217 else if (opt_seed && opt_seed != 2)
218 pr_error_exit(1, "seed requires MAC-ADDRESS");
219 else if (! opt_seed && opt_pass && opt_pass != 2)
220 pr_error_exit(1, "password on its own requires a pre-generated seed");
221 else if (opt_seed && opt_pass && opt_pass != 1)
222 pr_error_exit(1, "generating seed and password; cannot also accept pre-generated seed");
223 else if (opt_ts == 1)
224 pr_error_exit(0, "missing timestamp; assuming 000000");
228 if (! generate_seed(MAC_ADDR, timestamp, seed))
229 pr_error_exit(1, "unable to generate seed; aborting");
231 if (! generate_pass(seed, password))
232 pr_error_exit(0, "unable to generate password");
234 if (opt_seed || opt_pass)
235 printf("MAC address: %s Timestamp: %s Seed: %s Password: %s\n", MAC_ADDR, timestamp, seed, password);