X-Git-Url: https://iam.tj/gitweb/gitweb.cgi?p=cfe_generate_password.git;a=blobdiff_plain;f=cfe_generate_password.c;h=b4ea73ce57853a9209485e2ef7bf5f0f3ac4af03;hp=049b15bf33b52b809706af03a685d5b41161b4e8;hb=HEAD;hpb=60b7984e0a8ce92e058e602da1235016a8fc0ede diff --git a/cfe_generate_password.c b/cfe_generate_password.c index 049b15b..b4ea73c 100644 --- a/cfe_generate_password.c +++ b/cfe_generate_password.c @@ -1,103 +1,111 @@ -/* - Generate Broadcom CFE seeds and passwords for many popular modem/router devices +static const char *title = \ +"Generate Broadcom CFE seeds and passwords for many popular modem/router devices" +; +static const float VERSION = 1.4f; - Copyright 2015 TJ - Licenced on the terms of the GNU General Public Licence version 3 +static const char *copyright = \ +"Copyright 2015-2016 TJ \n" +"Licenced on the terms of the GNU General Public Licence version 3\n" +; - To build: - - gcc -o cfe_gen_pass cfe_generate_password.c +static const char *help = \ +"This tool can generate passwords for use with many devices that contain Broadcom Common Firmware Environment (CFE) bootbase which has a debug mode that is enabled using the 'ATEN 1 XXXXXXXX' command, where XXXXXXXX is an eight digit hexadecimal 'password'.\n\n" - Or: +"It is NOT necessary to have the device generate a 'seed' using 'ATSE [MODEL-ID]' because this tool can generate the seed from the device's first (base) MAC address.\n\n" - make +"When the device generates a seed it combines the number of seconds since 1970-01-01 00:00:00 with the router MAC address. Both are encoded in a single 6-byte hexadecimal number\n\n" - To use: +"Each value is truncated to its 3 least significant bytes so, for example:\n\n" - ./cfe_gen_pass [options] +" $ date +%F.%T; echo \"obase=16;$(date +%s)\" | bc\n" +" 2016-03-26.23:06:32\n" +" 56F715F8\n\n" - This tool can generate passwords for use with many devices that contain - Broadcom Common Firmware Environment (CFE) bootbase which has a debug mode - that is enabled using the "ATEN 1 XXXXXXXX" command, where XXXXXXXX is an - eight digit hexadecimal 'password'. - - It is NOT necessary to have the device generate a 'seed' using "ATSE [MODEL-ID]" - because this tool can generate the seed from the device's first (base) MAC address - *provided* the "ATSE" command has NOT been executed since the device last booted. +"and MAC Address: EC:43:F6:46:C0:80\n\n" - Access to the device's console via a serial UART port is required to enter the password. +"becomes F715F8 concatenated with 46C080\n\n" - So, for a device with base MAC address (reported by the CFE during boot) E.g: +" CFE> ATSE DSL-2492GNAU-B1BC\n" +" F715F846C080 <<<< last 3 bytes of MAC address\n" +" ^^^^^^\n" +" seconds since 1970-01-01 00:00:00 (2016-03-26 23:06:32)\n\n" - CFE version 1.0.38-112.118 for BCM963268 (32bit,SP,BE) - ... - Base MAC Address : ec:43:f6:46:c0:80 - ... - *** Press any key to stop auto run (1 seconds) *** - CFE> +"*NOTE: the default seed after power-up is 000000 so no time value needs to be specifed if 'ATSE ' has not been executed on the device.\n\n" - Using this tool do: +"Access to the device's console via a serial UART port, or a network telnet/ssh session, is required to enter the password.\n\n" - ./cfe_gen_pass -s ec:43:f6:46:c0:80 -p +"So, for a device with base MAC address (reported by the CFE during boot) E.g:\n\n" - MAC address: ec:43:f6:46:c0:80 Timestamp: 000000 Seed: 00000046c080 Password: 10f0a563 +" CFE version 1.0.38-112.118 for BCM963268 (32bit,SP,BE)\n" +" ...\n" +" Base MAC Address : ec:43:f6:46:c0:80\n" +" ...\n" +" *** Press any key to stop auto run (1 seconds) ***\n" +" CFE>\n\n" - And on the device do: +"Using this tool do:\n\n" - CFE> ATEN 1 10f0a563 - OK - *** command status = 0 +" ./cfe_gen_pass -s ec:43:f6:46:c0:80 -p\n\n" - The tool can accept a timestamp as 6 hexadecimal characters (useful for testing the algorithm): +" MAC address: ec:43:f6:46:c0:80 Timestamp: 000000 Seed: 00000046c080 Password: 10f0a563\n\n" - ./cfe_gen_pass -t 0FF020 -s ec:43:f6:46:c0:80 -p +"And on the device do:\n\n" - MAC address: ec:43:f6:46:c0:80 Timestamp: 0FF020 Seed: 0FF02046c080 Password: 110f65a3 - */ +" CFE> ATEN 1 10f0a563\n" +" OK\n" +" *** command status = 0\n\n" + +"The tool can accept a timestamp as 8 hexadecimal characters (useful for testing the algorithm):\n\n" + +" ./cfe_gen_pass -t 56FA8C2B -s ec:43:f6:46:c0:80 -p\n\n" + +" MAC address: ec:43:f6:46:c0:80 Timestamp: 56FA8C2B (2016-03-29 14:07:39) Seed: FA8C2B46c080 Password: 1111bda5\n\n" +; #include #include -#include #include #include +#include -static const float VERSION = 1.0f; -static const unsigned int TIMESTAMP_SIZE = 6; -static const unsigned int SEED_SIZE = 12; -static const unsigned int PASSWORD_SIZE = 8; -static const unsigned int MESSAGE_SIZE = 128; +static const size_t TIMESTAMP_SIZE = 8; +static const size_t SEED_SIZE = 12; +static const size_t PASSWORD_SIZE = 8; +static const size_t MESSAGE_SIZE = 128; +static const size_t MAC_ADDR_SIZE = 17; +static const size_t DATESTRING_SIZE = 20; -void -pr_usage() +static void +pr_usage(int verbose) { - fprintf(stderr, "%s\n", + fprintf(stderr, "Usage:\n" - " -v show version\n" " -s 00:01:02:03:04:05 create seed from MAC address\n" - " -t 000000 millisecond timestamp since boot\n" - " -p [SEED] generate password (with optional seed)\n\n" - " E.g. -s 01:02:03:04:05 \n" - " -s 01:02:03:04:05 -p\n" - " -p 000000030405\n" + " -t [00000000] seconds since 1970-01-01 (defaults to NOW) \n" + " -p [SEED] generate password (with optional seed)\n" + " -h show additional help\n" + "\n" + "%s", + verbose ? help : "" ); } -void +static void pr_error_exit(unsigned int usage, const char *error, ...) { va_list args; - char error_message[MESSAGE_SIZE]; + char error_message[MESSAGE_SIZE + 1]; if (!error) return; va_start(args, error); - vsnprintf(error_message, MESSAGE_SIZE, error, args); + (void) vsnprintf(error_message, MESSAGE_SIZE + 1, error, args); va_end(args); fprintf(stderr, "Error: %s\n", error_message); - if (usage) pr_usage(); + if (usage) pr_usage(usage); - exit(1); + exit(EXIT_FAILURE); } static const unsigned int passwords[8] = { @@ -111,43 +119,47 @@ static const unsigned int passwords[8] = { 0xC621E14A }; -unsigned int +static unsigned int generate_seed(char *mac, char *timestamp, char *seed) { unsigned int result = 0; - if (mac && strlen(mac) == 17) { - unsigned int i; + if (mac && strlen(mac) == MAC_ADDR_SIZE) { + size_t i; char *mac_ptr = mac + 9; size_t ts_len = strlen(timestamp); - for (i = 0; i <= SEED_SIZE; ++i) { - /* if no timestamp assume CFE get_time() returned 0 and CFE g_pw_timestamp == 0x00000000 */ - if (i < 6) - seed[i] = ts_len ? timestamp[i] : '0'; - else { - if (*mac_ptr == ':' || *mac_ptr == '-') - ++mac_ptr; - seed[i] = *mac_ptr++; + if (ts_len == TIMESTAMP_SIZE) { + for (i = 0; i < SEED_SIZE; ++i) { + if (i < 6) // first half of seed is the truncated timestamp + seed[i] = timestamp[i+2]; + else { // second half is the truncated MAC address + if (*mac_ptr == ':' || *mac_ptr == '-') + ++mac_ptr; + seed[i] = *mac_ptr++; + } } - } - result = 1; + result = 1; + } else + pr_error_exit(0, "Timestamp ('%s') should be %d hexadecimal characters e.g: 56F715F8", timestamp, TIMESTAMP_SIZE); } else - pr_error_exit(0, "MAC-ADDR should be 17 characters, e.g: 00:01:02:03:04:05"); + pr_error_exit(0, "MAC-ADDR should be %d characters, e.g: 00:01:02:03:04:05", MAC_ADDR_SIZE); return result; } -unsigned int +static unsigned int generate_pass(char *seed, char *password) { unsigned int result = 0; - if (seed && strlen(seed) == 12) { - unsigned int timestamp = 0; - unsigned byte = 0; - sscanf(seed, "%06x", ×tamp); - sscanf(&seed[10], "%02x", &byte); - unsigned int key = byte & 0x07; - unsigned int pass = (passwords[key] + timestamp) ^ timestamp; + if (seed && strlen(seed) == SEED_SIZE) { + unsigned int timestamp, byte, key, pass; + timestamp = byte = 0; + if(! sscanf(seed, "%06x", ×tamp)) + pr_error_exit(1, "unable to parse seed's timestamp"); + if (! sscanf(&seed[10], "%02x", &byte)) + pr_error_exit(1, "unable to parse seed's MAC address"); + key = byte & 0x07; + pass = (passwords[key] + timestamp) ^ timestamp; snprintf(password, PASSWORD_SIZE + 1, "%08x", pass); result = 1; } else @@ -160,78 +172,100 @@ int main(int argc, char **argv, char **env) { int result = 0; - - if (argc == 1) { - pr_usage(); - } - else { - unsigned int arg; - char *MAC_ADDR = NULL; - char *MODEL = NULL; - char timestamp[TIMESTAMP_SIZE + 1]; - char seed[SEED_SIZE + 1]; - char password[PASSWORD_SIZE + 1]; - unsigned int opt_seed, opt_pass, opt_ts; - seed[0] = password[0] = 0; - seed[SEED_SIZE] = password[PASSWORD_SIZE] = timestamp[TIMESTAMP_SIZE] = 0; - opt_seed = opt_pass = opt_ts = 0; - strncpy(timestamp, "000000", TIMESTAMP_SIZE); - - for (arg = 1; arg < argc; ++arg) { - size_t arg_len = strlen(argv[arg]); - - if (argv[arg][0] == '-') { - switch (argv[arg][1]) { - case 's': - opt_seed = 1; - break; - case 'p': - opt_pass = 1; - break; - case 't': - opt_ts = 1; - break; - case 'v': - fprintf(stderr, "Version: %0.2f\n", VERSION); - } - } else if (opt_seed == 1) { - MAC_ADDR = argv[arg]; - ++opt_seed; - } else if (opt_pass == 1 && opt_seed == 0) { - if (arg_len != SEED_SIZE) - pr_error_exit(1, "seed length must be %d characters", SEED_SIZE); - - strncpy(seed, argv[arg], SEED_SIZE); - ++opt_pass; - } else if (opt_ts == 1) { - if (arg_len != TIMESTAMP_SIZE) - pr_error_exit(1, "timestamp length must be %d characters", TIMESTAMP_SIZE); - - strncpy(timestamp, argv[arg], TIMESTAMP_SIZE); - ++opt_ts; + unsigned int arg; + char *MAC_ADDR = NULL; + char timestamp[TIMESTAMP_SIZE + 1]; + char seed[SEED_SIZE + 1]; + char password[PASSWORD_SIZE + 1]; + char date_string[DATESTRING_SIZE + 1]; + unsigned int opt_seed, opt_pass, opt_ts; + time_t ts = 0; + struct tm *t = NULL; + seed[0] = password[0] = timestamp[0] = 0; + seed[SEED_SIZE] = password[PASSWORD_SIZE] = 0; + opt_seed = opt_pass = opt_ts = 0; + strncpy(timestamp, "00000000", TIMESTAMP_SIZE + 1); + + fprintf(stderr, "%s\nVersion: %0.2f\n%s\n", title, VERSION, copyright); + + for (arg = 1; arg < (unsigned) argc; ++arg) { + size_t arg_len = strlen(argv[arg]); + + if (argv[arg][0] == '-') { + switch (argv[arg][1]) { + case 's': + opt_seed = 1; + break; + case 'p': + opt_pass = 1; + break; + case 't': + opt_ts = 1; + break; + case 'h': + pr_usage(1); + exit(0); } + } else if (opt_seed == 1) { + MAC_ADDR = argv[arg]; + ++opt_seed; + } else if (opt_pass == 1 && opt_seed == 0) { + if (arg_len != SEED_SIZE) + pr_error_exit(1, "seed length must be %d characters", SEED_SIZE); + + strncpy(seed, argv[arg], SEED_SIZE); + ++opt_pass; + } else if (opt_ts == 1) { + if (arg_len != TIMESTAMP_SIZE) + pr_error_exit(1, "timestamp length must be %d hexadecimal characters", TIMESTAMP_SIZE); + + strncpy(timestamp, argv[arg], TIMESTAMP_SIZE); + ++opt_ts; } - if (! opt_seed && ! opt_pass) - pr_usage(); - else if (opt_seed && opt_seed != 2) - pr_error_exit(1, "seed requires MAC-ADDRESS"); - else if (! opt_seed && opt_pass && opt_pass != 2) - pr_error_exit(1, "password on its own requires a pre-generated seed"); - else if (opt_seed && opt_pass && opt_pass != 1) - pr_error_exit(1, "generating seed and password; cannot also accept pre-generated seed"); - else if (opt_ts == 1) - pr_error_exit(0, "missing timestamp; assuming 000000"); - - - if (opt_seed) - if (! generate_seed(MAC_ADDR, timestamp, seed)) - pr_error_exit(1, "unable to generate seed; aborting"); - if (opt_pass) - if (! generate_pass(seed, password)) - pr_error_exit(0, "unable to generate password"); - - printf("MAC address: %s Timestamp: %s Seed: %s Password: %s\n", MAC_ADDR, timestamp, seed, password); } + if (! opt_seed && ! opt_pass) { + pr_usage(0); + exit(0); + } + else if (opt_seed && opt_seed != 2) + pr_error_exit(1, "seed requires MAC-ADDRESS"); + else if (! opt_seed && opt_pass && opt_pass != 2) + pr_error_exit(1, "password on its own requires a pre-generated seed"); + else if (opt_seed && opt_pass && opt_pass != 1) + pr_error_exit(1, "generating seed and password; cannot also accept pre-generated seed"); + else if (opt_pass == 2 && opt_ts) + pr_error_exit(1, "seed already contains a timestamp; cannot over-ride it"); + else if (opt_ts == 1 || opt_pass == 2) { // no timestamp provided; use NOW + ts = time(NULL); + if (ts) + snprintf(timestamp, TIMESTAMP_SIZE + 1, "%08lX", ts); + } + + if (opt_pass == 2) { // try to figure out the correct date-time from the seed + // inherits the most significant 2 characters from the NOW time + strncpy(timestamp+2, seed, 6); + time_t tmp; + if (sscanf(timestamp, "%08lx", &tmp)) + if (tmp > ts-3600 && tmp < ts+3600) // timestamps are so close they must be for the same date + ts = tmp; + } + + if(opt_ts) { // ts needs to be valid to be converted to a time string + if(! sscanf(timestamp, "%08lx", &ts)) + pr_error_exit(1, "converting timestamp string ('%s') to number", timestamp); + } + t = gmtime(&ts); + strftime(date_string, DATESTRING_SIZE, "%F %T", t); + + if (opt_seed) + if (! generate_seed(MAC_ADDR, timestamp, seed)) + pr_error_exit(1, "unable to generate seed; aborting"); + if (opt_pass) + if (! generate_pass(seed, password)) + pr_error_exit(0, "unable to generate password"); + + if (opt_seed || opt_pass) + printf("MAC address: %s Timestamp: %s (%s) Seed: %s Password: %s\n", MAC_ADDR, timestamp, date_string, seed, password); return result; }