From 62c79bf5c0a5ad574abd1e4a95026c69321577f2 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Mon, 29 Dec 2014 09:26:22 +0800 Subject: [PATCH] fernly: Add USB loader Add the fernly usb loader, imported from NuttX. Signed-off-by: Sean Cross --- Makefile | 6 +- fernly-usb-loader.c | 1423 +++++++++++++++++++++++++++++++++++++++++++ sha1.c | 388 ++++++++++++ sha1.h | 72 +++ 4 files changed, 1888 insertions(+), 1 deletion(-) create mode 100644 fernly-usb-loader.c create mode 100644 sha1.c create mode 100644 sha1.h diff --git a/Makefile b/Makefile index 5e04625..c335061 100644 --- a/Makefile +++ b/Makefile @@ -45,13 +45,17 @@ OBJ = $(addprefix $(BUILD)/, $(SRC_S:.S=.o) $(SRC_C:.c=.o)) all: $(BUILD)/firmware.bin \ $(BUILD)/loader.bin \ $(BUILD)/usb-loader.bin \ - $(BUILD)/fernly-loader + $(BUILD)/fernly-loader \ + $(BUILD)/fernly-usb-loader clean: $(RM) -rf $(BUILD) $(BUILD)/fernly-loader: fernly-loader.c $(CC) fernly-loader.c -o $@ +$(BUILD)/fernly-usb-loader: fernly-usb-loader.c sha1.c sha1.h + $(CC) fernly-usb-loader.c sha1.c -o $@ + $(BUILD)/loader.bin: $(BUILD)/loader.o objcopy -S -O binary $(BUILD)/loader.o $@ diff --git a/fernly-usb-loader.c b/fernly-usb-loader.c new file mode 100644 index 0000000..c0555a2 --- /dev/null +++ b/fernly-usb-loader.c @@ -0,0 +1,1423 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sha1.h" + +#define BAUDRATE B921600 +#define STAGE_2_WRITE_ALL_AT_ONCE 1 /* Write stage 2 in one write() */ +#define STAGE_2_WRITE_SIZE 1 +#define STAGE_3_WRITE_ALL_AT_ONCE 1 /* Write stage 3 in one write() */ +#define STAGE_3_WRITE_SIZE 1 +#define MONITOR_BOOT /* Whether to monitor serial, or call screen */ +#define FERNLY_USB_LOADER_ADDR 0x7000c000 + +#define ASSERT(x) do { if ((x)) exit(1); } while(0) + +static const uint32_t mtk_config_offset = 0x80000000; +static struct termios old_termios; +const char prompt[] = "fernly>"; + +enum mtk_commands { + mtk_cmd_old_write16 = 0xa1, + mtk_cmd_old_read16 = 0xa2, + mtk_checksum16 = 0xa4, + mtk_remap_before_jump_to_da = 0xa7, + mtk_jump_to_da = 0xa8, + mtk_send_da = 0xad, + mtk_jump_to_maui = 0xb7, + mtk_get_version = 0xb8, + mtk_close_usb_and_reset = 0xb9, + mtk_cmd_new_read16 = 0xd0, + mtk_cmd_new_read32 = 0xd1, + mtk_cmd_new_write16 = 0xd2, + mtk_cmd_new_write32 = 0xd4, +// mtk_jump_to_da = 0xd5, + mtk_jump_to_bl = 0xd6, + mtk_get_sec_conf = 0xd8, + mtk_send_cert = 0xe0, + mtk_get_me = 0xe1, /* Responds with 22 bytes */ + mtk_send_auth = 0xe2, + mtk_sla_flow = 0xe3, + mtk_send_root_cert = 0xe5, + mtk_do_security = 0xfe, + mtk_firmware_version = 0xff, +}; + +struct gfh_header { + uint32_t magic_ver; + uint16_t size; + uint16_t type; +}; + +struct gfh_file_info { + struct gfh_header header; + uint8_t id[12]; /* include '\0' */ + uint32_t file_ver; + uint16_t file_type; + uint8_t flash_dev; + uint8_t sig_type; + uint32_t load_addr; + uint32_t file_len; + uint32_t max_size; + uint32_t content_offset; + uint32_t sig_len; + uint32_t jump_offset; + uint32_t attr; +}; + +static const uint8_t mtk_banner[] = { 0xa0, 0x0a, 0x50, 0x05 }; +static const uint8_t mtk_banner_response[] = { 0x5f, 0xf5, 0xaf, 0xfa }; + +static void restore_termios(void) +{ + tcsetattr(1, TCSANOW, &old_termios); +} + +int print_hex_offset(const void *block, int count, int offset, uint32_t start) +{ + int byte; + const uint8_t *b = block; + count += offset; + b -= offset; + for ( ; offset < count; offset += 16) { + printf("%08x", start + offset); + + for (byte = 0; byte < 16; byte++) { + if (byte == 8) + printf(" "); + printf(" "); + if (offset + byte < count) + printf("%02x", b[offset + byte] & 0xff); + else + printf(" "); + } + + printf(" |"); + for (byte = 0; byte < 16 && byte + offset < count; byte++) + printf("%c", isprint(b[offset + byte]) ? + b[offset + byte] : + '.'); + printf("|\n"); + } + return 0; +} + +int print_hex(const void *block, int count, uint32_t start) +{ + return print_hex_offset(block, count, 0, start); +} + +static int fernvale_txrx(int fd, void *b, int size) { + uint8_t response[size]; + uint8_t *bfr = b; + int ret; + +// printf("Writing data: "); print_hex(bfr, size, 0); + ret = write(fd, bfr, size); + if (ret != size) { + if (ret == -1) + perror("Unable to write buffer"); + else + printf("Wanted to write %d bytes, but read %d\n", + size, ret); + return -1; + } + + ret = read(fd, response, size); + if (ret != size) { + if (ret == -1) + perror("Unable to read response"); + else + printf("Wanted to read %d bytes, but read %d (%x)\n", + size, ret, response[0]); + return -1; + } +// printf("Reading data: "); print_hex(response, size, 0); + + if (memcmp(bfr, response, size)) { + fprintf(stderr, "Error: Response differs from command\n"); + int i; + printf(" Expected: "); + for (i = 0; i < size; i++) + printf(" %02x", bfr[i] & 0xff); + printf("\n Received: "); + for (i = 0; i < size; i++) + printf(" %02x", response[i] & 0xff); + printf("\n"); + return -1; + } + return 0; +} + +int fernvale_send_cmd(int fd, uint8_t bfr) { + return fernvale_txrx(fd, &bfr, sizeof(bfr)); +} + +int fernvale_send_int16(int fd, uint16_t word) { + uint8_t bfr[2]; + bfr[0] = word >> 8; + bfr[1] = word >> 0; + return fernvale_txrx(fd, bfr, sizeof(bfr)); +} + +uint16_t fernvale_get_int8(int fd) { + uint8_t bfr; + int ret; + + ret = read(fd, &bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + perror("Unable to read 16 bits"); + return -1; + } + return bfr; +} + +int fernvale_get_int16(int fd) { + uint16_t bfr, out; + int ret; + + ret = read(fd, &bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + perror("Unable to read 16 bits"); + return -1; + } + out = ((bfr >> 8) & 0x00ff) + | ((bfr << 8) & 0xff00); + return out; +} + +uint32_t fernvale_get_int32(int fd) { + uint32_t bfr, out; + int ret; + + ret = read(fd, &bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + perror("Unable to read 32 bits"); + return -1; + } + + out = ((bfr >> 24) & 0x000000ff) + | ((bfr >> 8) & 0x0000ff00) + | ((bfr << 8) & 0x00ff0000) + | ((bfr << 24) & 0xff000000); + return out; +} + +static int fernvale_send_int32(int fd, uint32_t word) { + uint8_t bfr[4]; + bfr[0] = word >> 24; + bfr[1] = word >> 16; + bfr[2] = word >> 8; + bfr[3] = word >> 0; + return fernvale_txrx(fd, bfr, sizeof(bfr)); +} + +int fernvale_send_int8_no_response(int fd, uint8_t byte) { + + int ret; + ret = write(fd, &byte, sizeof(byte)); + if (ret != sizeof(byte)) { + if (ret == -1) + perror("Unable to write buffer"); + else + printf("Wanted to write %d bytes, but read %d\n", + sizeof(byte), ret); + return -1; + } + return 0; +} + +int fernvale_send_int16_no_response(int fd, uint32_t word) { + uint8_t bfr[2]; + int ret; + + bfr[0] = word >> 8; + bfr[1] = word >> 0; + + ret = write(fd, bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + if (ret == -1) + perror("Unable to write buffer"); + else + printf("Wanted to write %d bytes, but read %d\n", + sizeof(bfr), ret); + return -1; + } + return 0; +} + +int fernvale_send_int32_no_response(int fd, uint32_t word) { + uint8_t bfr[4]; + int ret; + + bfr[0] = word >> 24; + bfr[1] = word >> 16; + bfr[2] = word >> 8; + bfr[3] = word >> 0; + + ret = write(fd, bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + if (ret == -1) + perror("Unable to write buffer"); + else + printf("Wanted to write %d bytes, but read %d\n", + sizeof(bfr), ret); + return -1; + } + return 0; +} + +int fernvale_cmd_jump(int fd, uint32_t addr) { + int ret; + + ret = fernvale_send_cmd(fd, 0xd5); + if (ret) { + fprintf(stderr, "Unable to send jump command "); + return ret; + } + + ret = fernvale_send_int32(fd, addr); + if (ret) { + fprintf(stderr, "Unable to send address "); + return ret; + } + + ret = fernvale_get_int16(fd); + if (ret) { + fprintf(stderr, "Error while jumping: 0x%04x ", ret); + return ret; + } + + return 0; +} + +int fernvale_cmd_send_fd(int fd, uint32_t addr, int binfd) +{ + struct stat stats; + uint16_t checksum, checksum_calc; + uint16_t response; + //uint32_t signature_len = 1024; // Number of 32-bit words to send (?) + uint32_t signature_len = 2; // Size of the signature hash +// uint32_t unk1 = 0x00000001; + uint32_t size; + uint8_t *bfr; + + if (-1 == fstat(binfd, &stats)) { + perror("Unable to get file stats"); + close(binfd); + return -1; + } + + if (addr >= 0x70000000 && addr < 0x70006598) { + printf("warning: address is probably invalid "); + fflush(stdout); + } + + size = stats.st_size; + + bfr = malloc(size); + if (!bfr) { + perror("Unable to allocate xmit buffer"); + return -1; + } + + if (size != read(binfd, bfr, size)) { + perror("Unable to read file for sending"); + close(binfd); + free(bfr); + return -1; + } + + close(binfd); + + fernvale_send_cmd(fd, 0xd7); + fernvale_send_int32(fd, addr); + fernvale_send_int32(fd, size); + fernvale_send_int32(fd, signature_len); + + /* Not sure what this response is, but it's always 0 */ + response = fernvale_get_int16(fd); + if (response != 0) + printf("!! First response is 0x%04x, not 0 !!\n", response); + + bfr[size - 1] ^= 0xff; + response = write(fd, bfr, size); + if (response != size) { + if (response == -1) + perror("Unable to write file"); + else { + printf("Wanted to write %d bytes of file, got %d ", + size, response); + fflush(stdout); + } + free(bfr); + return -1; + } + + /* Calculate a checksum of the whole file */ + checksum = fernvale_get_int16(fd); + { + int i; + uint16_t *checksum_ptr = (uint16_t *)bfr; + checksum_calc = 0; + for (i = 0; i < stats.st_size; i += 2) + checksum_calc ^= *checksum_ptr++; + } + if (checksum == checksum_calc) + printf("checksum matches 0x%04x ", checksum); + else + printf("device checksum 0x%04x, but we calculated 0x%04x ", + checksum, checksum_calc); + + /* Not sure what this response is, but it's always 0 */ + response = fernvale_get_int16(fd); + if (response != 0) + printf("!! Final response is 0x%04x, not 0 !!\n", response); + + free(bfr); + return 0; +} + +int fernvale_send_bootloader(int fd, uint32_t addr, uint32_t stack, + uint32_t unk, const char *filename) { + + struct stat stats; + struct gfh_file_info *info; + uint16_t checksum, checksum_calc; + uint32_t size; + int ret; + int tmp; + int binfd; + + ret = 0; + + binfd = open(filename, O_RDONLY); + if (-1 == binfd) { + perror("Unable to open bootloader for sending"); + return -1; + } + + if (-1 == fstat(binfd, &stats)) { + perror("Unable to get file stats"); + close(binfd); + return -1; + } + + size = stats.st_size; + + uint8_t bfr[size]; + + if (size != read(binfd, bfr, size)) { + perror("Unable to read file for sending"); + close(binfd); + return -1; + } + + close(binfd); + + /* XXX PATCH BOOTLOADER */ + info = (struct gfh_file_info *)bfr; +#if 0 + if (info->sig_type == 2) { + //uint32_t buffer_size = size; + + printf("Patching bootloader signature... "); + fflush(stdout); + + /* Remove the previous signature length */ + size -= info->sig_len; + + /* Clear out old checksum */ + memset(bfr + size, 0, info->sig_len); + + /* Calculate SHA1 */ + SHA1Context sha; + SHA1Reset(&sha); + SHA1Input(&sha, bfr, size); + SHA1Result(&sha, bfr + size); + + /* Convert to SHA1 */ + info->sig_type = 1; + info->sig_len = 32; + size += info->sig_len; + info->file_len = size; + } +#endif + printf("Id: "); + int j; + for (j = 0; j < 12; j++) + printf("%c", info->id[j]); + printf("\n"); + printf("Version: %d\n", info->file_ver); + printf("Type: %d\n", info->file_type); + printf("Flash device: %d\n", info->flash_dev); + printf("File size: %d\n", info->file_len); + printf("Max size: %d\n", info->max_size); + printf("Signature type: %d\n", info->sig_type); + printf("Signature length: %d\n", info->sig_len); + printf("Load address: 0x%08x\n", info->load_addr); + printf("Content offset: %d\n", info->content_offset); + printf("Jump offset: %d\n", info->jump_offset); + printf("Attributes: %d\n", info->attr); + + printf("Hash:\n"); + print_hex(bfr + size - info->sig_len, info->sig_len, 0); + + fernvale_send_cmd(fd, 0xd9); + fernvale_send_int32(fd, addr); + fernvale_send_int32(fd, size); // Number of bytes + fernvale_send_int32(fd, stack); + fernvale_send_int32(fd, unk); + tmp = fernvale_get_int16(fd); + + if (tmp != 0) { + printf("Response 0xd9 (1) was not 0, was 0x%04x\n", tmp); + ret = -1; + } + + write(fd, bfr, size); + { + int i; + uint16_t *checksum_ptr = (uint16_t *)bfr; + checksum_calc = 0; + for (i = 0; i < sizeof(bfr); i += 2) + checksum_calc ^= *checksum_ptr++; + } + checksum = fernvale_get_int16(fd); + if (checksum == checksum_calc) + printf("Checksum matches: 0x%04x\n", checksum); + else + printf("Checksum differs. Received: 0x%04x Calculated: 0x%04x)\n", checksum, checksum_calc); + + tmp = fernvale_get_int16(fd); + if (tmp != 0) { + printf("Response 0xd9 (2) was not 0, was 0x%04x\n", tmp); + ret = -1; + } + + tmp = fernvale_get_int32(fd); + if (tmp != 0) { + printf("Response 0xd9 (4) was not 0, was 0x%08x\n", tmp); + ret = -1; + } + + return ret; +} + +static int fernvale_print_me(int fd) { + int ret; + uint32_t size; + uint16_t footer; + + ret = fernvale_send_cmd(fd, mtk_get_me); + if (ret) + return ret; + + size = fernvale_get_int32(fd); + + uint8_t bfr[size]; + + ret = read(fd, bfr, size); + if (ret != size) { + perror("Unable to read from ME buffer"); + return -1; + } + + footer = fernvale_get_int16(fd); + (void)footer; + + print_hex(bfr, size, 0); + + return 0; +} + +static int fernvale_print_sec_conf(int fd) { + int ret; + uint32_t size; + uint16_t footer; + + ret = fernvale_send_cmd(fd, mtk_get_sec_conf); + if (ret) + return ret; + + size = fernvale_get_int32(fd); + + uint8_t bfr[size]; + + ret = read(fd, bfr, size); + if (ret != size) { + perror("Unable to read from Sec Conf buffer"); + return -1; + } + + footer = fernvale_get_int16(fd); + (void)footer; + + if (size) + print_hex(bfr, size, 0); + else + printf("None.\n"); + + return 0; +} + +static int fernvale_send_do_security(int fd) { + return fernvale_send_cmd(fd, mtk_do_security); +} + +static int fernvale_security_version(int fd) { + int ret; + uint8_t bfr[1]; + + bfr[0] = mtk_firmware_version; + ret = write(fd, bfr, 1); + if (ret != 1) { + perror("Unable to write security character"); + return -1; + } + ret = read(fd, bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + if (ret == -1) + perror("Unable to read response"); + else { + printf("Wanted to read %d bytes, but got %d", 1, ret); + fflush(stdout); + } + return -1; + } + + if (ret == 0xff) + return 0; + + return bfr[0]; +} + +static int fernvale_hello(int fd) { + int i; + int ret; + uint8_t bfr[1]; + + for (i = 0; i < sizeof(mtk_banner); i++) { + bfr[0] = mtk_banner[i]; + ret = write(fd, bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + perror("Unable to write banner character"); + return -1; + } + + ret = read(fd, bfr, sizeof(bfr)); + if (ret != sizeof(bfr)) { + if (ret == -1) + perror("Unable to read response"); + else { + printf("Wanted to read %d bytes, but got %d ", + 1, ret); + fflush(stdout); + } + return -1; + } + + if (bfr[0] != mtk_banner_response[i]) { + fprintf(stderr, + "Invalid banner response for " + "character %d: 0x%02x (wanted 0x%02x) ", + i, bfr[0], mtk_banner_response[i]); + return -1; + } + } + + return 0; +} + +static int fernvale_memory_read(int fd, uint32_t addr, uint32_t count, + void *bfr) { + int ret; + uint8_t *b = bfr; + int i; + + ret = fernvale_send_cmd(fd, mtk_cmd_old_read16); + if (ret) + return ret; + + ret = fernvale_send_int32(fd, addr); + if (ret) + return ret; + + /* "Count" is in units of 16-bit words, not 8-bit bytes */ + ret = fernvale_send_int32(fd, count / 2); + if (ret) + return ret; + + ret = read(fd, bfr, count); + if (ret != count) { + if (ret == -1) + perror("Unable to read data"); + else + fprintf(stderr, "Wanted %d bytes, got %d bytes\n", + count, ret); + return -1; + } + + /* Swap bytes around as necessary */ + for (i = 0; i < count; i += 2) { + uint8_t t = b[i]; + b[i] = b[i + 1]; + b[i + 1] = t; + } + + return 0; +} + +int fernvale_memory_write(int fd, uint32_t addr, uint32_t count, + void *bfr) { + int ret; + uint8_t *b = bfr; + + if (count & 1) + count++; + + ret = fernvale_send_cmd(fd, mtk_cmd_old_write16); + if (ret) + return ret; + + ret = fernvale_send_int32(fd, addr); + if (ret) + return ret; + + /* "Count" is in units of 16-bit words, not 8-bit bytes */ + ret = fernvale_send_int32(fd, count / 2); + if (ret) + return ret; + + /* Doubly-swapped bytes */ + while (count > 3) { + uint16_t data; + + data = (b[2] << 8) | (b[3]); + + printf("Writing data: 0x%04x\n", data); + ret = fernvale_txrx(fd, &data, 2); + if (ret) { + perror("Unable to write data"); + return -1; + } + + data = (b[0] << 8) | (b[1]); + + printf("Writing data: 0x%04x\n", data); + ret = fernvale_txrx(fd, &data, 2); + if (ret) { + perror("Unable to write data"); + return -1; + } + b += 4; + count -= 4; + } + + return 0; +} + +int fernvale_write_reg16(int fd, uint32_t addr, uint16_t val) { + int ret; + + ret = fernvale_send_cmd(fd, mtk_cmd_old_write16); + if (ret) + return ret; + + ret = fernvale_send_int32(fd, addr); + if (ret) + return ret; + + /* "Count" is in units of 16-bit words, not 8-bit bytes */ + ret = fernvale_send_int32(fd, 1); + if (ret) + return ret; + + return fernvale_send_int16(fd, val); +} + +int fernvale_write_reg32(int fd, uint32_t addr, uint32_t val) { + int ret; + + ret = fernvale_send_cmd(fd, mtk_cmd_old_write16); + if (ret) + return ret; + + ret = fernvale_send_int32(fd, addr); + if (ret) + return ret; + + /* "Count" is in units of 16-bit words, not 8-bit bytes */ + ret = fernvale_send_int32(fd, 2); + if (ret) + return ret; + +// ret = fernvale_send_int32(fd, val); + fernvale_send_int16(fd, val >> 16); + fernvale_send_int16(fd, val); + return 0; +} + +uint16_t fernvale_read_reg16(int fd, uint32_t addr) { + uint16_t val; + fernvale_memory_read(fd, addr, 2, &val); + return val; +} + +uint32_t fernvale_read_reg32(int fd, uint32_t addr) { + uint32_t val; + fernvale_memory_read(fd, addr, 4, &val); + return val; +} + +int fernvale_reset(void) { + int fd; + uint8_t b; + + fd = open("/sys/class/gpio/gpio17/value", O_WRONLY); + b = '0'; + write(fd, &b, 1); + close(fd); + + usleep(250000); + + fd = open("/sys/class/gpio/gpio17/value", O_WRONLY); + b = '1'; + write(fd, &b, 1); + close(fd); + + return 0; +} + +int write_pattern(int fd) { + int i; + + for (i = 0; i < 16; i += 2) + fernvale_write_reg16(fd, 0x70000000 + i, i | ((i + 1) << 8)); + /* + bfr[i] = i; + for (i = 0; i < sizeof(bfr); i += 2) + fernvale_memory_write(fd, 0x70000000 + i, 2, bfr + i); + */ + +// return fernvale_memory_write(fd, 0x70000000, sizeof(bfr), bfr); + return 0; +} + +int read_pattern(int fd) { + uint8_t bfr[16]; + uint32_t offset = 0x70006600; + + for (; ; offset += sizeof(bfr)) { + if (fernvale_memory_read(fd, offset, sizeof(bfr), bfr)) + return -1; + print_hex(bfr, sizeof(bfr), offset); + } + + return 0; +} + +static uint16_t fernvale_read16(int fd, uint32_t addr) { + uint16_t ret; + uint16_t tmp; + int count = 1; + + fernvale_send_cmd(fd, mtk_cmd_new_read16); + fernvale_send_int32(fd, addr); + fernvale_send_int32(fd, count); + tmp = fernvale_get_int16(fd); + if (tmp != 0) + printf("Response read16 (1) was not 0, was 0x%04x\n", tmp); + ret = fernvale_get_int16(fd); + + tmp = fernvale_get_int16(fd); + if (tmp != 0) + printf("Response read16 (3) was not 0, was 0x%04x\n", tmp); + + return ret; +} + +static int fernvale_read32(int fd, uint32_t addr) { + int ret; + int tmp; + int count = 1; + + fernvale_send_cmd(fd, mtk_cmd_new_read32); + fernvale_send_int32(fd, addr); + fernvale_send_int32(fd, count); + + tmp = fernvale_get_int16(fd); + if (tmp != 0) + printf("Response read32 (1) was not 0, was 0x%04x\n", tmp); + + ret = fernvale_get_int32(fd); + + tmp = fernvale_get_int16(fd); + if (tmp != 0) + printf("Response read32 (3) was not 0, was 0x%04x\n", tmp); + + return ret; +} + +static int fernvale_write16(int fd, uint32_t addr, uint16_t val) { + int tmp; + int count = 1; + int ret = 0; + + fernvale_send_cmd(fd, mtk_cmd_new_write16); + fernvale_send_int32(fd, addr); + fernvale_send_int32(fd, count); + + tmp = fernvale_get_int16(fd); + if (tmp != 1) { + printf("Response write16 (1) was not 1, was 0x%04x\n", tmp); + ret = -1; + } + + fernvale_send_int16(fd, val); + + tmp = fernvale_get_int16(fd); + if (tmp != 1) { + printf("Response write16 (2) was not 1, was 0x%04x\n", tmp); + ret = -1; + } + + return ret; +} + +static int fernvale_write32(int fd, uint32_t addr, uint32_t val) { + int tmp; + int ret; + int type = 1; + + ret = 0; + + fernvale_send_cmd(fd, mtk_cmd_new_write32); + fernvale_send_int32(fd, addr); + fernvale_send_int32(fd, type); + + tmp = fernvale_get_int16(fd); + if (tmp != 1) { + printf("Response write32 (1) was not 1, was 0x%04x\n", tmp); + ret = -1; + } + + fernvale_send_int32(fd, val); + + tmp = fernvale_get_int16(fd); + if (tmp != 1) { + printf("Response write32 (2) was not 1, was 0x%04x\n", tmp); + ret = -1; + } + + return ret; +} + +int fernvale_set_serial(int serfd) { + int ret; + struct termios t; + + ret = tcgetattr(serfd, &t); + if (-1 == ret) { + perror("Failed to get attributes"); + exit(1); + } + cfsetispeed(&t, BAUDRATE); + cfsetospeed(&t, BAUDRATE); + cfmakeraw(&t); + ret = tcsetattr(serfd, TCSANOW, &t); + if (-1 == ret) { + perror("Failed to set attributes"); + exit(1); + } + + return 0; +} + +static int fernvale_wait_banner(int fd, const char *banner, int banner_size) { + //sleep(1); + //return 0; + tcdrain(fd); + uint8_t buf[banner_size]; + int tst; + int offset = 0; + int i; + + while (1 == read(fd, &buf[offset], 1)) { + + tst = (offset + 1) % sizeof(buf); + + i = 0; + while (tst != offset) { + if (banner[i] != buf[tst]) + break; + tst++; + i++; + tst %= sizeof(buf); + } + if ((tst == offset) && (banner[i] == buf[tst])) + return 0; + + offset++; + offset %= sizeof(buf); + } + return -1; +} + +static int fernvale_write_stage2(int serfd, int binfd) +{ + struct stat stats; + uint32_t bytes_left; + uint32_t bytes_written; + uint32_t bytes_total; + int ret; + + if (-1 == fstat(binfd, &stats)) { + perror("Unable to get file stats"); + exit(1); + } + + bytes_left = stats.st_size; + bytes_total = stats.st_size; + bytes_written = 0; + printf("%d bytes... ", bytes_total); + fflush(stdout); + { + uint8_t b; + + b = bytes_total & 0xff; + write(serfd, &b, 1); + + b = bytes_total >> 8 & 0xff; + write(serfd, &b, 1); + + b = bytes_total >> 16 & 0xff; + write(serfd, &b, 1); + + b = bytes_total >> 24 & 0xff; + write(serfd, &b, 1); + } + +#if (STAGE_2_WRITE_ALL_AT_ONCE) + char bfr[bytes_total]; + ret = read(binfd, bfr, sizeof(bfr)); + if (-1 == ret) { + perror("Unable to read data from payload file"); + return -1; + } + else if (ret != bytes_total) { + fprintf(stderr, "Shortened read (want: %d got: %d)\n", + bytes_total, ret); + return -1; + } + + ret = write(serfd, bfr, sizeof(bfr)); + if (-1 == ret) { + perror("Unable to write data to output"); + return -1; + } + else if (ret != bytes_total) { + fprintf(stderr, "Shortened write (want: %d got: %d)\n", + sizeof(bfr), ret); + return -1; + } + bytes_written = ret; +#else /* ! STAGE_2_WRITE_ALL_AT_ONCE */ + char bfr[STAGE_2_WRITE_SIZE]; + while (bytes_left) { + uint32_t bytes_to_write; + + bytes_to_write = sizeof(bfr); + if (bytes_left < bytes_to_write) + bytes_to_write = bytes_left; + + ret = read(binfd, bfr, bytes_to_write); + if (-1 == ret) { + perror("Unable to read data from payload file"); + return -1; + } + else if (ret != bytes_to_write) { + fprintf(stderr, "Shortened read (want: %d got: %d)\n", + bytes_to_write, ret); + return -1; + } + + ret = write(serfd, bfr, bytes_to_write); + if (-1 == ret) { + perror("Unable to write data to output"); + return -1; + } + else if (ret != bytes_to_write) { + fprintf(stderr, "Shortened write (want: %d got: %d)\n", + bytes_to_write, ret); + return -1; + } + + bytes_left -= bytes_to_write; + bytes_written += bytes_to_write; + + printf("%6d / %6d\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + bytes_written, bytes_total); + fflush(stdout); + } +#endif /* ! STAGE_2_WRITE_ALL_AT_ONCE */ + + printf("%6d / %6d ", bytes_written, bytes_total); + tcdrain(serfd); + + return 0; +} + +static int fernvale_write_stage3(int serfd, int binfd) +{ + struct stat stats; + uint32_t bytes_left, bytes_written, bytes_total; + int ret; + char cmd[128]; + + if (-1 == fstat(binfd, &stats)) { + perror("Unable to get file stats"); + exit(1); + } + + bytes_left = snprintf(cmd, sizeof(cmd) - 1, + "loadjmp 0 %d\n", (int)stats.st_size); + write(serfd, cmd, bytes_left); + read(serfd, cmd, sizeof(cmd)); + + bytes_left = stats.st_size; + bytes_total = stats.st_size; + bytes_written = 0; + + printf("%d bytes... ", bytes_total); + fflush(stdout); + +#if (STAGE_3_WRITE_ALL_AT_ONCE) + char bfr[bytes_total]; + ret = read(binfd, bfr, sizeof(bfr)); + if (-1 == ret) { + perror("Unable to read data from payload file"); + return -1; + } + else if (ret != bytes_total) { + fprintf(stderr, "Shortened read (want: %d got: %d)\n", + bytes_total, ret); + return -1; + } + + ret = write(serfd, bfr, sizeof(bfr)); + if (-1 == ret) { + perror("Unable to write data to output"); + return -1; + } + else if (ret != bytes_total) { + fprintf(stderr, "Shortened write (want: %d got: %d)\n", + sizeof(bfr), ret); + return -1; + } + bytes_written = ret; +#else /* ! STAGE_3_WRITE_ALL_AT_ONCE */ + char bfr[STAGE_3_WRITE_SIZE]; + while (bytes_left) { + uint32_t bytes_to_write; + + bytes_to_write = sizeof(bfr); + if (bytes_left < bytes_to_write) + bytes_to_write = bytes_left; + + ret = read(binfd, bfr, bytes_to_write); + if (-1 == ret) { + perror("Unable to read data from payload file"); + return -1; + } + else if (ret != bytes_to_write) { + fprintf(stderr, "Shortened read (want: %d got: %d)\n", + bytes_to_write, ret); + return -1; + } + + ret = write(serfd, bfr, bytes_to_write); + if (-1 == ret) { + perror("Unable to write data to output"); + return -1; + } + else if (ret != bytes_to_write) { + fprintf(stderr, "Shortened write (want: %d got: %d)\n", + bytes_to_write, ret); + return -1; + } + + bytes_left -= bytes_to_write; + bytes_written += bytes_to_write; + + printf("%6d / %6d\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", + bytes_written, bytes_total); + fflush(stdout); + } +#endif /* ! STAGE_3_WRITE_ALL_AT_ONCE */ + + printf("%6d / %6d ", bytes_written, bytes_total); + tcdrain(serfd); + + return 0; +} + +static void cmd_begin(const char *msg) { + printf(msg); + printf("... "); + fflush(stdout); +} + +static void cmd_end(void) { + printf("Ok\n"); +} + +static void cmd_end_fmt(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); +} + +int main(int argc, char **argv) { + int serfd, binfd, s1blfd, payloadfd = -1; + uint32_t ret; + + if ((argc != 4) && (argc != 5)) { + printf("Usage: %s [serial port] " + "[stage 1 bootloader] " + "[[stage 2 bootloader]] " + "[payload]\n", argv[0]); + printf("If you don't want a stage 2 bootloader, you may omit " + "it, and this program will jump straight to the " + "payload, loaded at offset 0x%08x.\n", + FERNLY_USB_LOADER_ADDR); + exit(1); + } + + serfd = open(argv[1], O_RDWR); + if (-1 == serfd) { + perror("Unable to open serial port"); + exit(1); + } + + s1blfd = open(argv[2], O_RDONLY); + if (-1 == s1blfd) { + perror("Unable to open stage 1 bootloader"); + exit(1); + } + + binfd = open(argv[3], O_RDONLY); + if (-1 == binfd) { + perror("Unable to open firmware file"); + exit(1); + } + + if (argc == 5) { + payloadfd = open(argv[4], O_RDONLY); + if (-1 == payloadfd) { + perror("Unable to open payload file"); + exit(1); + } + } + + cmd_begin("Setting serial port parameters"); + ASSERT(fernvale_set_serial(serfd)); + cmd_end(); + + cmd_begin("Initiating communication"); + ASSERT(fernvale_hello(serfd)); + cmd_end(); + + cmd_begin("Getting hardware version"); + cmd_end_fmt("0x%04x", fernvale_read_reg16(serfd, mtk_config_offset)); + + cmd_begin("Getting chip ID"); + cmd_end_fmt("0x%04x", fernvale_read_reg16(serfd, mtk_config_offset + 8)); + + cmd_begin("Getting boot config (low)"); + cmd_end_fmt("0x%04x", fernvale_read_reg16(serfd, 0xa0000000 + 0x10)); + + cmd_begin("Getting boot config (high)"); + cmd_end_fmt("0x%04x", fernvale_read_reg16(serfd, 0xa0000000 + 0x14)); + + cmd_begin("Getting hardware subcode"); + cmd_end_fmt("0x%04x", fernvale_read_reg16(serfd, mtk_config_offset + 12)); + + cmd_begin("Getting hardware version (again)"); + cmd_end_fmt("0x%04x", fernvale_read_reg16(serfd, mtk_config_offset)); + + cmd_begin("Getting chip firmware version"); + cmd_end_fmt("0x%04x", fernvale_read_reg16(serfd, mtk_config_offset + 4)); + + cmd_begin("Getting security version"); + cmd_end_fmt("v %d", fernvale_security_version(serfd)); + + cmd_begin("Enabling security (?!)"); + fernvale_send_do_security(serfd); + cmd_end(); + + cmd_begin("Reading ME"); + fernvale_print_me(serfd); + + cmd_begin("Disabling WDT"); + fernvale_write16(serfd, 0xa0030000, 0x2200); + cmd_end(); + + cmd_begin("Reading RTC Baseband Power Up (0xa0710000)"); + ret = fernvale_read16(serfd, 0xa0710000); + cmd_end_fmt("0x%04x", ret); + + cmd_begin("Reading RTC Power Key 1 (0xa0710050)"); + ret = fernvale_read16(serfd, 0xa0710050); + cmd_end_fmt("0x%04x", ret); + + cmd_begin("Reading RTC Power Key 2 (0xa0710054)"); + ret = fernvale_read16(serfd, 0xa0710054); + cmd_end_fmt("0x%04x", ret); + + /* Program RTC */ + cmd_begin("Setting seconds"); + fernvale_write16(serfd, 0xa0710010, 0); + cmd_end(); + + cmd_begin("Disabling alarm IRQs"); + fernvale_write16(serfd, 0xa0710008, 0); + cmd_end(); + + cmd_begin("Disabling RTC IRQ interval"); + fernvale_write16(serfd, 0xa071000c, 0); + cmd_end(); + + cmd_begin("Enabling transfers from core to RTC"); + fernvale_write16(serfd, 0xa0710074, 1); + cmd_end(); + + cmd_begin("Reading RTC Baseband Power Up (0xa0710000)"); + ret = fernvale_read16(serfd, 0xa0710000); + cmd_end_fmt("0x%04x", ret); + + cmd_begin("Getting security configuration"); + fernvale_print_sec_conf(serfd); + + cmd_begin("Getting PSRAM mapping"); + ret = fernvale_read32(serfd, 0xa0510000); + cmd_end_fmt("0x%04x", ret); + + cmd_begin("Disabling PSRAM -> ROM remapping"); + fernvale_write32(serfd, 0xa0510000, 2); + usleep(20000); + cmd_end(); + + cmd_begin("Checking PSRAM mapping"); + ret = fernvale_read32(serfd, 0xa0510000); + cmd_end_fmt("0x%04x", ret); + + cmd_begin("Checking on PSRAM mapping again"); + ret = fernvale_read32(serfd, 0xa0510000); + cmd_end_fmt("0x%04x", ret); + + cmd_begin("Updating PSRAM mapping again for some reason"); + fernvale_write32(serfd, 0xa0510000, 2); + usleep(50000); + cmd_end(); + + cmd_begin("Reading some fuses"); + fernvale_send_cmd(serfd, 0xd8); + cmd_end_fmt("0x%08x", fernvale_get_int32(serfd)); + fernvale_get_int16(serfd); + + cmd_begin("Enabling UART"); + ASSERT(fernvale_send_cmd(serfd, 0xdc)); + fernvale_send_int32(serfd, 115200); + ASSERT(ret = fernvale_get_int16(serfd)); + cmd_end_fmt("0x%04x", ret); + + cmd_begin("Loading Fernly USB loader"); + ASSERT(fernvale_cmd_send_fd(serfd, FERNLY_USB_LOADER_ADDR, s1blfd)); + cmd_end(); + + cmd_begin("Executing Ferly USB loader"); + ASSERT(fernvale_cmd_jump(serfd, FERNLY_USB_LOADER_ADDR)); + cmd_end(); + + cmd_begin("Waiting for Fernly USB loader banner"); + ASSERT(fernvale_wait_banner(serfd, ">", 1)); + cmd_end(); + + cmd_begin("Writing stage 2"); + ASSERT(fernvale_write_stage2(serfd, binfd)); + cmd_end(); + + if (payloadfd != -1) { + cmd_begin("Entering download mode"); + fernvale_wait_banner(serfd, prompt, strlen(prompt)); + cmd_end(); + + cmd_begin("Writing payload"); + fernvale_write_stage3(serfd, payloadfd); + cmd_end(); + } + +#ifdef MONITOR_BOOT + { + uint8_t bfr; + int ret; + struct termios t; + ret = tcgetattr(1, &t); + if (-1 == ret) { + perror("Failed to get attributes"); + exit(1); + } + old_termios = t; + atexit(restore_termios); + cfmakeraw(&t); + ret = tcsetattr(1, TCSANOW, &t); + if (-1 == ret) { + perror("Failed to set attributes"); + exit(1); + } + while (1) { + fd_set rfds; + FD_ZERO(&rfds); + + FD_SET(serfd, &rfds); + FD_SET(1, &rfds); + + select(serfd + 1, &rfds, NULL, NULL, NULL); + + if (FD_ISSET(serfd, &rfds)) { + if (1 != read(serfd, &bfr, 1)) + break; + if (bfr == 0x7f) { + char *txt = " \b"; + write(1, txt, 3); + } + else + write(1, &bfr, 1); + } + if (FD_ISSET(1, &rfds)) { + if (1 != read(1, &bfr, 1)) + break; + write(serfd, &bfr, 1); + } + } + } + return 0; +#else /* MONITOR_BOOT */ + close(serfd); + return execl("/usr/bin/screen", "screen", argv[1], "115200", NULL); +#endif +} diff --git a/sha1.c b/sha1.c new file mode 100644 index 0000000..e509a3f --- /dev/null +++ b/sha1.c @@ -0,0 +1,388 @@ + +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ +#include "sha1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +void SHA1PadMessage(SHA1Context *); +void SHA1ProcessMessageBlock(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result( SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + { + return shaNull; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + + + } + + for(i = 0; i < SHA1HashSize; ++i) + { + Message_Digest[i] = context->Intermediate_Hash[i>>2] + >> 8 * ( 3 - ( i & 0x03 ) ); + } + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input( SHA1Context *context, + const uint8_t *message_array, + unsigned length) +{ + if (!length) + { + return shaSuccess; + } + + if (!context || !message_array) + { + return shaNull; + } + + if (context->Computed) + { + context->Corrupted = shaStateError; + + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const uint32_t K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = context->Message_Block[t * 4] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = context->Length_High >> 24; + context->Message_Block[57] = context->Length_High >> 16; + context->Message_Block[58] = context->Length_High >> 8; + context->Message_Block[59] = context->Length_High; + context->Message_Block[60] = context->Length_Low >> 24; + context->Message_Block[61] = context->Length_Low >> 16; + context->Message_Block[62] = context->Length_Low >> 8; + context->Message_Block[63] = context->Length_Low; + + SHA1ProcessMessageBlock(context); +} diff --git a/sha1.h b/sha1.h new file mode 100644 index 0000000..45f7497 --- /dev/null +++ b/sha1.h @@ -0,0 +1,72 @@ +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#include +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typdef the following: + * name meaning + * uint32_t unsigned 32 bit integer + * uint8_t unsigned 8 bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + */ + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif +#define SHA1HashSize 20 + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + /* Index into message block array */ + int_least16_t Message_Block_Index; + uint8_t Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const uint8_t *, + unsigned int); +int SHA1Result( SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +#endif