forked from len0rd/rockbox
atjboottool: add support for FwuTail
Change-Id: Ib01a2ff92294dd0bb59439c23f26bc31eafa4a39
This commit is contained in:
parent
6e79c4cb7c
commit
7e42e90294
1 changed files with 60 additions and 6 deletions
|
@ -29,6 +29,11 @@
|
||||||
{ cprintf(RED, str_bad); return 1; } \
|
{ cprintf(RED, str_bad); return 1; } \
|
||||||
else { cprintf(RED, str_ok); }
|
else { cprintf(RED, str_ok); }
|
||||||
|
|
||||||
|
#define check_field_soft(v_exp, v_have, str_ok, str_bad) \
|
||||||
|
if((v_exp) != (v_have)) \
|
||||||
|
{ cprintf(RED, str_bad); } \
|
||||||
|
else { cprintf(RED, str_ok); }
|
||||||
|
|
||||||
#define FWU_SIG_SIZE 16
|
#define FWU_SIG_SIZE 16
|
||||||
#define FWU_BLOCK_SIZE 512
|
#define FWU_BLOCK_SIZE 512
|
||||||
|
|
||||||
|
@ -47,6 +52,19 @@ const uint8_t g_fwu_signature[FWU_SIG_SIZE] =
|
||||||
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x75
|
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x75
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct fwu_tail_t
|
||||||
|
{
|
||||||
|
uint8_t length; /* in blocks? it's always 1 */
|
||||||
|
uint8_t type; /* always 7 */
|
||||||
|
uint8_t reserved[14];
|
||||||
|
uint32_t fwu_checksum;
|
||||||
|
uint32_t flags; /* always 0x55aa55aa */
|
||||||
|
uint8_t desc[8]; /* always 'FwuTail' */
|
||||||
|
uint8_t fwu_crc_checksum[32]; /* always 0 */
|
||||||
|
uint8_t reserved2[444];
|
||||||
|
uint32_t fwutail_checksum;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct version_desc_t
|
struct version_desc_t
|
||||||
{
|
{
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
|
@ -727,6 +745,7 @@ static int get_key_fwu_v3(size_t size, uint8_t *buf, uint8_t *blockA, uint8_t *b
|
||||||
uint8_t ba = buf[0x1ee] & 0xf;
|
uint8_t ba = buf[0x1ee] & 0xf;
|
||||||
uint8_t bb = buf[0x1fe] & 0xf;
|
uint8_t bb = buf[0x1fe] & 0xf;
|
||||||
|
|
||||||
|
cprintf(BLUE, "Crypto\n");
|
||||||
cprintf_field(" Block A: ", "%d\n", ba + 2);
|
cprintf_field(" Block A: ", "%d\n", ba + 2);
|
||||||
cprintf_field(" Block B: ", "%d\n", ba + bb + 5);
|
cprintf_field(" Block B: ", "%d\n", ba + bb + 5);
|
||||||
|
|
||||||
|
@ -882,6 +901,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f
|
||||||
uint8_t blockA;
|
uint8_t blockA;
|
||||||
uint8_t blockB;
|
uint8_t blockB;
|
||||||
uint8_t keybuf[32];
|
uint8_t keybuf[32];
|
||||||
|
struct fwu_hdr_t *hdr = (void *)buf;
|
||||||
memset(keybuf, 0, sizeof(keybuf));
|
memset(keybuf, 0, sizeof(keybuf));
|
||||||
int ret = get_key_fwu_v3(*size, buf, &blockA, &blockB, keybuf, block);
|
int ret = get_key_fwu_v3(*size, buf, &blockA, &blockB, keybuf, block);
|
||||||
if(ret != 0)
|
if(ret != 0)
|
||||||
|
@ -890,6 +910,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f
|
||||||
size_t file_size = *size;
|
size_t file_size = *size;
|
||||||
/* the input buffer is reorganized based on two offsets (blockA and blockB),
|
/* the input buffer is reorganized based on two offsets (blockA and blockB),
|
||||||
* skip 2048 bytes of data used for crypto init */
|
* skip 2048 bytes of data used for crypto init */
|
||||||
|
*size = hdr->fw_size; /* use firmware size, not file size */
|
||||||
*size -= 2048;
|
*size -= 2048;
|
||||||
uint8_t *tmpbuf = malloc(*size);
|
uint8_t *tmpbuf = malloc(*size);
|
||||||
memset(tmpbuf, 0, *size);
|
memset(tmpbuf, 0, *size);
|
||||||
|
@ -919,12 +940,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f
|
||||||
rounds_to_perform = 1;
|
rounds_to_perform = 1;
|
||||||
/* the ATJ213x and ATJ2127 do not use the same encryption at this point, and I
|
/* the ATJ213x and ATJ2127 do not use the same encryption at this point, and I
|
||||||
* don't see any obvious way to tell which encryption is used (since they
|
* don't see any obvious way to tell which encryption is used (since they
|
||||||
* use the same version above). The only difference is that ATJ2127 images
|
* use the same version above). */
|
||||||
* I have seen have an extra 512 bytes at the end file (ie the actual file
|
|
||||||
* is 512 bytes larger than indicated by the header) but I don't know if this
|
|
||||||
* is the case for all files. Thus, unless the user force encryption mode,
|
|
||||||
* try both and see if one looks like an AFI file. To guess which one to use,
|
|
||||||
* decrypt the first sector and see if it looks like an AFI file */
|
|
||||||
bool is_atj2127 = false;
|
bool is_atj2127 = false;
|
||||||
if(mode == FWU_AUTO)
|
if(mode == FWU_AUTO)
|
||||||
{
|
{
|
||||||
|
@ -951,6 +967,17 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t fwu_checksum(void *buf, size_t size)
|
||||||
|
{
|
||||||
|
if(size % 4)
|
||||||
|
cprintf(GREY, "WARNING: checksum of buffer whose length is not a multiple of 4");
|
||||||
|
uint32_t *p = buf;
|
||||||
|
uint32_t sum = 0;
|
||||||
|
for(size_t i = 0; i < size / 4; i++)
|
||||||
|
sum += *p++;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode)
|
int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode)
|
||||||
{
|
{
|
||||||
struct fwu_hdr_t *hdr = (void *)buf;
|
struct fwu_hdr_t *hdr = (void *)buf;
|
||||||
|
@ -1010,6 +1037,33 @@ int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode)
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check whether the firmware has a FwuTail (as far as I know, there is no flag anywhere that
|
||||||
|
* indicates its presence or not) */
|
||||||
|
struct fwu_tail_t *tail = (void *)(buf + hdr->fw_size - sizeof(struct fwu_tail_t));
|
||||||
|
if(tail->flags == 0x55aa55aa && strcmp((char *)tail->desc, "FwuTail") == 0)
|
||||||
|
{
|
||||||
|
cprintf(BLUE, "Tail\n");
|
||||||
|
cprintf_field(" Length: ", "%d ", tail->length);
|
||||||
|
check_field_soft(tail->length, 1, "Ok\n", "Fail\n");
|
||||||
|
cprintf_field(" Type: ", "%d ", tail->type);
|
||||||
|
check_field_soft(tail->type, 7, "Ok\n", "Fail\n");
|
||||||
|
cprintf_field(" FW checksum: ", "%x ", tail->fwu_checksum);
|
||||||
|
check_field_soft(fwu_checksum(buf, hdr->fw_size - sizeof(struct fwu_tail_t)),
|
||||||
|
tail->fwu_checksum, "Ok\n", "Mismatch\n");
|
||||||
|
cprintf(GREEN, " FW CRC Checksum: ");
|
||||||
|
for(unsigned i = 0; i < sizeof(tail->fwu_crc_checksum); i++)
|
||||||
|
cprintf(YELLOW, "%02x", tail->fwu_crc_checksum[i]);
|
||||||
|
cprintf(RED, " Ignored (should be 0)\n");
|
||||||
|
cprintf_field(" Tail checksum: ", "%x ", tail->fwutail_checksum);
|
||||||
|
check_field_soft(fwu_checksum(tail, sizeof(struct fwu_tail_t) - 4),
|
||||||
|
tail->fwutail_checksum, "Ok\n", "Mismatch\n");
|
||||||
|
/* if it has a tail, the firmware size includes it, so we need to decrease it to avoid
|
||||||
|
* "decrypting" the tail and output garbage */
|
||||||
|
hdr->fw_size -= sizeof(struct fwu_tail_t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(BLUE, "Firmware does not seem to have a tail\n");
|
||||||
|
|
||||||
if(g_version[ver].version == 3)
|
if(g_version[ver].version == 3)
|
||||||
{
|
{
|
||||||
uint8_t block[512];
|
uint8_t block[512];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue