summaryrefslogtreecommitdiff
path: root/utils/atj2137/atjboottool
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-10-20 23:57:58 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2017-10-20 23:57:58 +0200
commit7e42e902947b951bc9ec9f5d6ba6ef6a6f2eb836 (patch)
tree5240906497b3604110e9fe5bf3f34bce1d6466ed /utils/atj2137/atjboottool
parent6e79c4cb7c6cb9679a7de9bbb26d6c4b12906a6b (diff)
downloadrockbox-7e42e902947b951bc9ec9f5d6ba6ef6a6f2eb836.tar.gz
rockbox-7e42e902947b951bc9ec9f5d6ba6ef6a6f2eb836.zip
atjboottool: add support for FwuTail
Change-Id: Ib01a2ff92294dd0bb59439c23f26bc31eafa4a39
Diffstat (limited to 'utils/atj2137/atjboottool')
-rw-r--r--utils/atj2137/atjboottool/fwu.c66
1 files changed, 60 insertions, 6 deletions
diff --git a/utils/atj2137/atjboottool/fwu.c b/utils/atj2137/atjboottool/fwu.c
index 44281af4f4..82ef28632a 100644
--- a/utils/atj2137/atjboottool/fwu.c
+++ b/utils/atj2137/atjboottool/fwu.c
@@ -29,6 +29,11 @@
29 { cprintf(RED, str_bad); return 1; } \ 29 { cprintf(RED, str_bad); return 1; } \
30 else { cprintf(RED, str_ok); } 30 else { cprintf(RED, str_ok); }
31 31
32#define check_field_soft(v_exp, v_have, str_ok, str_bad) \
33 if((v_exp) != (v_have)) \
34 { cprintf(RED, str_bad); } \
35 else { cprintf(RED, str_ok); }
36
32#define FWU_SIG_SIZE 16 37#define FWU_SIG_SIZE 16
33#define FWU_BLOCK_SIZE 512 38#define FWU_BLOCK_SIZE 512
34 39
@@ -47,6 +52,19 @@ const uint8_t g_fwu_signature[FWU_SIG_SIZE] =
47 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x75 52 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x75
48}; 53};
49 54
55struct fwu_tail_t
56{
57 uint8_t length; /* in blocks? it's always 1 */
58 uint8_t type; /* always 7 */
59 uint8_t reserved[14];
60 uint32_t fwu_checksum;
61 uint32_t flags; /* always 0x55aa55aa */
62 uint8_t desc[8]; /* always 'FwuTail' */
63 uint8_t fwu_crc_checksum[32]; /* always 0 */
64 uint8_t reserved2[444];
65 uint32_t fwutail_checksum;
66} __attribute__((packed));
67
50struct version_desc_t 68struct version_desc_t
51{ 69{
52 uint8_t version; 70 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
727 uint8_t ba = buf[0x1ee] & 0xf; 745 uint8_t ba = buf[0x1ee] & 0xf;
728 uint8_t bb = buf[0x1fe] & 0xf; 746 uint8_t bb = buf[0x1fe] & 0xf;
729 747
748 cprintf(BLUE, "Crypto\n");
730 cprintf_field(" Block A: ", "%d\n", ba + 2); 749 cprintf_field(" Block A: ", "%d\n", ba + 2);
731 cprintf_field(" Block B: ", "%d\n", ba + bb + 5); 750 cprintf_field(" Block B: ", "%d\n", ba + bb + 5);
732 751
@@ -882,6 +901,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f
882 uint8_t blockA; 901 uint8_t blockA;
883 uint8_t blockB; 902 uint8_t blockB;
884 uint8_t keybuf[32]; 903 uint8_t keybuf[32];
904 struct fwu_hdr_t *hdr = (void *)buf;
885 memset(keybuf, 0, sizeof(keybuf)); 905 memset(keybuf, 0, sizeof(keybuf));
886 int ret = get_key_fwu_v3(*size, buf, &blockA, &blockB, keybuf, block); 906 int ret = get_key_fwu_v3(*size, buf, &blockA, &blockB, keybuf, block);
887 if(ret != 0) 907 if(ret != 0)
@@ -890,6 +910,7 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f
890 size_t file_size = *size; 910 size_t file_size = *size;
891 /* the input buffer is reorganized based on two offsets (blockA and blockB), 911 /* the input buffer is reorganized based on two offsets (blockA and blockB),
892 * skip 2048 bytes of data used for crypto init */ 912 * skip 2048 bytes of data used for crypto init */
913 *size = hdr->fw_size; /* use firmware size, not file size */
893 *size -= 2048; 914 *size -= 2048;
894 uint8_t *tmpbuf = malloc(*size); 915 uint8_t *tmpbuf = malloc(*size);
895 memset(tmpbuf, 0, *size); 916 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
919 rounds_to_perform = 1; 940 rounds_to_perform = 1;
920 /* the ATJ213x and ATJ2127 do not use the same encryption at this point, and I 941 /* the ATJ213x and ATJ2127 do not use the same encryption at this point, and I
921 * don't see any obvious way to tell which encryption is used (since they 942 * don't see any obvious way to tell which encryption is used (since they
922 * use the same version above). The only difference is that ATJ2127 images 943 * use the same version above). */
923 * I have seen have an extra 512 bytes at the end file (ie the actual file
924 * is 512 bytes larger than indicated by the header) but I don't know if this
925 * is the case for all files. Thus, unless the user force encryption mode,
926 * try both and see if one looks like an AFI file. To guess which one to use,
927 * decrypt the first sector and see if it looks like an AFI file */
928 bool is_atj2127 = false; 944 bool is_atj2127 = false;
929 if(mode == FWU_AUTO) 945 if(mode == FWU_AUTO)
930 { 946 {
@@ -951,6 +967,17 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f
951 return 0; 967 return 0;
952} 968}
953 969
970uint32_t fwu_checksum(void *buf, size_t size)
971{
972 if(size % 4)
973 cprintf(GREY, "WARNING: checksum of buffer whose length is not a multiple of 4");
974 uint32_t *p = buf;
975 uint32_t sum = 0;
976 for(size_t i = 0; i < size / 4; i++)
977 sum += *p++;
978 return sum;
979}
980
954int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode) 981int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode)
955{ 982{
956 struct fwu_hdr_t *hdr = (void *)buf; 983 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)
1010 return 2; 1037 return 2;
1011 } 1038 }
1012 1039
1040 /* check whether the firmware has a FwuTail (as far as I know, there is no flag anywhere that
1041 * indicates its presence or not) */
1042 struct fwu_tail_t *tail = (void *)(buf + hdr->fw_size - sizeof(struct fwu_tail_t));
1043 if(tail->flags == 0x55aa55aa && strcmp((char *)tail->desc, "FwuTail") == 0)
1044 {
1045 cprintf(BLUE, "Tail\n");
1046 cprintf_field(" Length: ", "%d ", tail->length);
1047 check_field_soft(tail->length, 1, "Ok\n", "Fail\n");
1048 cprintf_field(" Type: ", "%d ", tail->type);
1049 check_field_soft(tail->type, 7, "Ok\n", "Fail\n");
1050 cprintf_field(" FW checksum: ", "%x ", tail->fwu_checksum);
1051 check_field_soft(fwu_checksum(buf, hdr->fw_size - sizeof(struct fwu_tail_t)),
1052 tail->fwu_checksum, "Ok\n", "Mismatch\n");
1053 cprintf(GREEN, " FW CRC Checksum: ");
1054 for(unsigned i = 0; i < sizeof(tail->fwu_crc_checksum); i++)
1055 cprintf(YELLOW, "%02x", tail->fwu_crc_checksum[i]);
1056 cprintf(RED, " Ignored (should be 0)\n");
1057 cprintf_field(" Tail checksum: ", "%x ", tail->fwutail_checksum);
1058 check_field_soft(fwu_checksum(tail, sizeof(struct fwu_tail_t) - 4),
1059 tail->fwutail_checksum, "Ok\n", "Mismatch\n");
1060 /* if it has a tail, the firmware size includes it, so we need to decrease it to avoid
1061 * "decrypting" the tail and output garbage */
1062 hdr->fw_size -= sizeof(struct fwu_tail_t);
1063 }
1064 else
1065 cprintf(BLUE, "Firmware does not seem to have a tail\n");
1066
1013 if(g_version[ver].version == 3) 1067 if(g_version[ver].version == 3)
1014 { 1068 {
1015 uint8_t block[512]; 1069 uint8_t block[512];