+/*
+ Generate Broadcom CFE seeds and passwords for many popular modem/router devices
+
+ Copyright 2015 TJ <hacker@iam.tj>
+ Licenced on the terms of the GNU General Public Licence version 3
+
+ To build:
+
+ gcc -o cfe_gen_pass cfe_generate_password.c
+
+ Or:
+
+ make
+
+ To use:
+
+ ./cfe_gen_pass [options]
+
+ 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.
+
+ Access to the device's console via a serial UART port is required to enter the password.
+
+ So, for a device with base MAC address (reported by the CFE during boot) E.g:
+
+ 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>
+
+ Using this tool do:
+
+ ./cfe_gen_pass -s ec:43:f6:46:c0:80 -p
+
+ MAC address: ec:43:f6:46:c0:80 Timestamp: 000000 Seed: 00000046c080 Password: 10f0a563
+
+ And on the device do:
+
+ CFE> ATEN 1 10f0a563
+ OK
+ *** command status = 0
+
+ The tool can accept a timestamp as 6 hexadecimal characters (useful for testing the algorithm):
+
+ ./cfe_gen_pass -t 0FF020 -s ec:43:f6:46:c0:80 -p
+
+ MAC address: ec:43:f6:46:c0:80 Timestamp: 0FF020 Seed: 0FF02046c080 Password: 110f65a3
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+
+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;
+
+void
+pr_usage()
+{
+ fprintf(stderr, "%s\n",
+ "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"
+ );
+}
+
+void
+pr_error_exit(unsigned int usage, const char *error, ...)
+{
+ va_list args;
+ char error_message[MESSAGE_SIZE];
+
+ if (!error) return;
+
+ va_start(args, error);
+ vsnprintf(error_message, MESSAGE_SIZE, error, args);
+ va_end(args);
+ fprintf(stderr, "Error: %s\n", error_message);
+
+ if (usage) pr_usage();
+
+ exit(1);
+}
+
+static const unsigned int passwords[8] = {
+ 0x10F0A563,
+ 0x887852B1,
+ 0xC43C2958,
+ 0x621E14AC,
+ 0x310F0A56,
+ 0x1887852B,
+ 0x8C43C295,
+ 0xC621E14A
+};
+
+unsigned int
+generate_seed(char *mac, char *timestamp, char *seed)
+{
+ unsigned int result = 0;
+ if (mac && strlen(mac) == 17) {
+ unsigned int 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++;
+ }
+ }
+ result = 1;
+ } else
+ pr_error_exit(0, "MAC-ADDR should be 17 characters, e.g: 00:01:02:03:04:05");
+
+ return result;
+}
+
+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;
+ snprintf(password, PASSWORD_SIZE + 1, "%08x", pass);
+ result = 1;
+ } else
+ pr_error_exit(0, "Seed should be %d hex characters", SEED_SIZE);
+
+ return result;
+}
+
+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;
+ }
+ }
+ 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);
+ }
+
+ return result;
+}
+