[PATCH v2 04/15] Add code to read and decrypt OSTC3 firmware files
Anton Lundin
glance at acc.umu.se
Wed Dec 17 14:11:01 PST 2014
This code is inspired by JeanDo ostc-companion.
Reviewed-by: Jef Driesen <jef at libdivecomputer.org>
Signed-off-by: Anton Lundin <glance at acc.umu.se>
---
src/hw_ostc3.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c
index b78702c..a4885d4 100644
--- a/src/hw_ostc3.c
+++ b/src/hw_ostc3.c
@@ -21,6 +21,7 @@
#include <string.h> // memcmp, memcpy
#include <stdlib.h> // malloc, free
+#include <stdio.h> // FILE, fopen
#include <libdivecomputer/hw_ostc3.h>
@@ -30,6 +31,7 @@
#include "checksum.h"
#include "ringbuffer.h"
#include "array.h"
+#include "aes.h"
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable)
@@ -43,6 +45,7 @@
#define SZ_VERSION (SZ_CUSTOMTEXT + 4)
#define SZ_MEMORY 0x200000
#define SZ_CONFIG 4
+#define SZ_FIRMWARE 0x01E000 // 120KB
#define RB_LOGBOOK_SIZE 256
#define RB_LOGBOOK_COUNT 256
@@ -66,6 +69,21 @@ typedef struct hw_ostc3_device_t {
unsigned char fingerprint[5];
} hw_ostc3_device_t;
+typedef struct hw_ostc3_firmware_t {
+ unsigned char data[SZ_FIRMWARE];
+ unsigned int checksum;
+} hw_ostc3_firmware_t;
+
+// This key is used both for the Ostc3 and its cousin,
+// the Ostc Sport.
+// The Frog uses a similar protocol, and with another key.
+static const unsigned char ostc3_key[16] = {
+ 0xF1, 0xE9, 0xB0, 0x30,
+ 0x45, 0x6F, 0xBE, 0x55,
+ 0xFF, 0xE7, 0xF8, 0x31,
+ 0x13, 0x6C, 0xF2, 0xFE
+};
+
static dc_status_t hw_ostc3_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
static dc_status_t hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
static dc_status_t hw_ostc3_device_close (dc_device_t *abstract);
@@ -622,3 +640,121 @@ hw_ostc3_device_config_reset (dc_device_t *abstract)
return DC_STATUS_SUCCESS;
}
+
+// This is a variant of fletcher16 with 16 bit sum instead of 8bit
+// and modulo 256 instead of 255
+static unsigned int hw_ostc3_firmware_checksum(hw_ostc3_firmware_t *firmware)
+{
+ unsigned short low = 0;
+ unsigned short high = 0;
+ for(unsigned int i = 0;i < SZ_FIRMWARE;i++)
+ {
+ low += firmware->data[i];
+ high += low;
+ }
+ return (((unsigned int)high) << 16) + low;
+}
+
+static dc_status_t
+hw_ostc3_firmware_readline(FILE *fp, unsigned int addr, unsigned char data[], unsigned int size)
+{
+ unsigned char ascii[40];
+ // 1 byte :, 6 bytes addr, X*2 bytes hex -> X bytes data.
+ const unsigned line_size = size * 2 + 1 + 6 + 1;
+ unsigned char faddr_byte[3];
+ unsigned int faddr = 0;
+ if (line_size > sizeof(ascii))
+ return DC_STATUS_INVALIDARGS;
+ if (fread (ascii, sizeof(char), line_size, fp) != line_size)
+ return DC_STATUS_IO;
+ if (ascii[0] != ':')
+ return DC_STATUS_DATAFORMAT;
+ // Is it a CRLF file?
+ // Read away that trailing LF
+ if (ascii[line_size] == '\r')
+ if (fread (ascii + line_size, sizeof(char), 1, fp) != 1)
+ return DC_STATUS_DATAFORMAT;
+ if (array_convert_hex2bin(ascii + 1, 6, faddr_byte, sizeof(faddr_byte)) != 0) {
+ return DC_STATUS_DATAFORMAT;
+ }
+ faddr = array_uint24_be (faddr_byte);
+ if (faddr != addr)
+ return DC_STATUS_DATAFORMAT;
+ if (array_convert_hex2bin (ascii + 1 + 6, size*2, data, size) != 0)
+ return DC_STATUS_DATAFORMAT;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+hw_ostc3_firmware_readfile (hw_ostc3_firmware_t *firmware, dc_context_t *context, const char *filename)
+{
+ dc_status_t rc = DC_STATUS_SUCCESS;
+ FILE *fp;
+ unsigned char iv[16] = {0};
+ unsigned char tmpbuf[16] = {0};
+ unsigned char encrypted[16] = {0};
+ unsigned int bytes = 0, addr = 0, faddr = 0;
+ unsigned char checksum[4];
+
+ if (firmware == NULL) {
+ ERROR (context, "Invalid arguments.");
+ return DC_STATUS_INVALIDARGS;
+ }
+
+ // Initialize the buffers.
+ memset (firmware->data, 0xFF, sizeof (firmware->data));
+ firmware->checksum = 0;
+
+ fp = fopen (filename, "rb");
+ if (fp == NULL) {
+ ERROR (context, "Failed to open the file.");
+ return DC_STATUS_IO;
+ }
+
+ rc = hw_ostc3_firmware_readline(fp, 0, iv, sizeof(iv));
+ if (rc != DC_STATUS_SUCCESS) {
+ fclose (fp);
+ ERROR (context, "Failed to parse header.");
+ return rc;
+ }
+ bytes += 16;
+
+ // Load the iv for AES-FCB-mode
+ AES128_ECB_encrypt(iv, ostc3_key, tmpbuf);
+
+ for(addr = 0; addr < SZ_FIRMWARE; addr += 16, bytes += 16) {
+ rc = hw_ostc3_firmware_readline(fp, bytes, encrypted, sizeof(encrypted));
+ if (rc != DC_STATUS_SUCCESS) {
+ fclose (fp);
+ ERROR (context, "Failed to parse file data.");
+ return rc;
+ }
+
+ // Decrypt AES-FCB data
+ for(int i=0;i < 16;i++)
+ firmware->data[addr + i] = encrypted[i] ^ tmpbuf[i];
+
+ // Run the next round of encryption
+ AES128_ECB_encrypt(encrypted, ostc3_key, tmpbuf);
+ }
+
+ // This file format contains a tail with the checksum in
+ rc = hw_ostc3_firmware_readline(fp, bytes, checksum, sizeof(checksum));
+ if (rc != DC_STATUS_SUCCESS) {
+ fclose (fp);
+ ERROR (context, "Failed to parse file tail.");
+ return rc;
+ }
+ fclose(fp);
+
+ firmware->checksum = array_uint32_le(checksum);
+
+ if (firmware->checksum != hw_ostc3_firmware_checksum(firmware)) {
+ ERROR (context, "Failed to verify file checksum.");
+ return DC_STATUS_IO;
+ }
+
+ return DC_STATUS_SUCCESS;
+}
--
2.1.0
More information about the devel
mailing list