diff options
author | Nikita Burnashev <nikita.burnashev@gmail.com> | 2023-04-16 12:46:55 +0300 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2023-05-17 13:19:31 -0400 |
commit | e232f69214cfe0ad83e8a6051c58ef54754e59bb (patch) | |
tree | dfe36ac87d182c2e3f8f4a99ea74ad3492a1f1dd | |
parent | 72c0e49b41b0da4a43a4852771eed3767fc675ad (diff) | |
download | rockbox-e232f69214cfe0ad83e8a6051c58ef54754e59bb.tar.gz rockbox-e232f69214cfe0ad83e8a6051c58ef54754e59bb.zip |
atjboottool: gzipped fw files, option for big-endian fw, clarify ECIES in fwu
Added fw modifications required to unpack real world player dumps.
Documented more fwu header fields, magic numbers and finite field arithmetics (extended Euclidean for inverse, long division for reducing modulo field_poly).
v3 encryption used is standard RC4 with the key additionally ciphered by the Elliptic Curve Integrated Encryption Scheme.
Either sect233k1 (NIST K-233) or sect163r2 (NIST B-163) curves can be used, with the former overwhelmingly prevailing, being hardwired in SDK's maker.exe. Using a private/public key scheme is superfluous because both are stored in the firmware, with the added level of complexity likely serving the purpose of obfuscation. The private key is generated at random with each invokation.
None of KDF or MAC from ECIES are used, RC4 key is directly xored with the shared secret. The random number r used to calculate rG isn't stored, but that's unimportant since only krG == rkG is actually used in the encryption.
Change-Id: Ieacf8cc744bc90c7c5582dd724b2c10a41bfc191
-rw-r--r-- | utils/atj2137/atjboottool/Makefile | 2 | ||||
-rw-r--r-- | utils/atj2137/atjboottool/atj_tables.c | 18 | ||||
-rw-r--r-- | utils/atj2137/atjboottool/atj_tables.h | 20 | ||||
-rw-r--r-- | utils/atj2137/atjboottool/atjboottool.c | 37 | ||||
-rw-r--r-- | utils/atj2137/atjboottool/fw.c | 115 | ||||
-rw-r--r-- | utils/atj2137/atjboottool/fw.h | 2 | ||||
-rw-r--r-- | utils/atj2137/atjboottool/fwu.c | 628 |
7 files changed, 502 insertions, 320 deletions
diff --git a/utils/atj2137/atjboottool/Makefile b/utils/atj2137/atjboottool/Makefile index 8d96bcdde0..5414b4810e 100644 --- a/utils/atj2137/atjboottool/Makefile +++ b/utils/atj2137/atjboottool/Makefile | |||
@@ -2,7 +2,7 @@ DEFINES= | |||
2 | CC=gcc | 2 | CC=gcc |
3 | LD=gcc | 3 | LD=gcc |
4 | CFLAGS=-g -std=c99 -W -Wall $(DEFINES) | 4 | CFLAGS=-g -std=c99 -W -Wall $(DEFINES) |
5 | LDFLAGS= | 5 | LDFLAGS=-lz |
6 | BINS=atjboottool | 6 | BINS=atjboottool |
7 | 7 | ||
8 | all: $(BINS) | 8 | all: $(BINS) |
diff --git a/utils/atj2137/atjboottool/atj_tables.c b/utils/atj2137/atjboottool/atj_tables.c index 579e17d52b..e2bd976bfe 100644 --- a/utils/atj2137/atjboottool/atj_tables.c +++ b/utils/atj2137/atjboottool/atj_tables.c | |||
@@ -20,7 +20,7 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include <stdint.h> | 21 | #include <stdint.h> |
22 | 22 | ||
23 | uint8_t g_check_block_A_table[1024] = | 23 | uint8_t g_decode_A_table[1024] = |
24 | { | 24 | { |
25 | 0x16, 0x2b, 0x01, 0xe4, 0x0e, 0x3d, 0xc1, 0xdf, 0x0f, 0x35, 0x8f, 0xf5, 0xe2, | 25 | 0x16, 0x2b, 0x01, 0xe4, 0x0e, 0x3d, 0xc1, 0xdf, 0x0f, 0x35, 0x8f, 0xf5, 0xe2, |
26 | 0x48, 0xa0, 0x2e, 0x1c, 0x6a, 0x57, 0xea, 0x6d, 0x9a, 0xe2, 0x03, 0xec, 0xe8, | 26 | 0x48, 0xa0, 0x2e, 0x1c, 0x6a, 0x57, 0xea, 0x6d, 0x9a, 0xe2, 0x03, 0xec, 0xe8, |
@@ -109,45 +109,45 @@ uint8_t g_decode_B_table[20] = | |||
109 | 0xf8, 0xb4, 0x36, 0x41, 0xc5, 0x51, 0xaf | 109 | 0xf8, 0xb4, 0x36, 0x41, 0xc5, 0x51, 0xaf |
110 | }; | 110 | }; |
111 | 111 | ||
112 | uint32_t g_crypto_table[8] = | 112 | uint32_t g_sect233k1_G_x[8] = |
113 | { | 113 | { |
114 | 0xefad6126, 0x0a4c9d6e, 0x19c26bf5, 0x149563a4, 0x29f22ff4, 0x7e731af1, | 114 | 0xefad6126, 0x0a4c9d6e, 0x19c26bf5, 0x149563a4, 0x29f22ff4, 0x7e731af1, |
115 | 0x32ba853a, 0x00000172 | 115 | 0x32ba853a, 0x00000172 |
116 | }; | 116 | }; |
117 | 117 | ||
118 | uint32_t g_crypto_table2[8] = | 118 | uint32_t g_sect233k1_G_y[8] = |
119 | { | 119 | { |
120 | 0x56fae6a3, 0x56e0c110, 0xf18aeb9b, 0x27a8cd9b, 0x555a67c4, 0x19b7f70f, | 120 | 0x56fae6a3, 0x56e0c110, 0xf18aeb9b, 0x27a8cd9b, 0x555a67c4, 0x19b7f70f, |
121 | 0x537dece8, 0x000001db | 121 | 0x537dece8, 0x000001db |
122 | }; | 122 | }; |
123 | 123 | ||
124 | uint32_t g_crypto_key6[8] = | 124 | uint32_t g_sect233k1_b[8] = |
125 | { | 125 | { |
126 | 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 126 | 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
127 | 0x00000000, 0x00000000 | 127 | 0x00000000, 0x00000000 |
128 | }; | 128 | }; |
129 | 129 | ||
130 | uint32_t g_crypto_key3[6] = | 130 | uint32_t g_sect163r2_G_x[6] = |
131 | { | 131 | { |
132 | 0xe8343e36, 0xd4994637, 0xa0991168, 0x86a2d57e, 0xf0eba162, 0x00000003 | 132 | 0xe8343e36, 0xd4994637, 0xa0991168, 0x86a2d57e, 0xf0eba162, 0x00000003 |
133 | }; | 133 | }; |
134 | 134 | ||
135 | uint32_t g_crypto_key4[6] = | 135 | uint32_t g_sect163r2_G_y[6] = |
136 | { | 136 | { |
137 | 0x797324f1, 0xb11c5c0c, 0xa2cdd545, 0x71a0094f, 0xd51fbc6c, 0x00000000 | 137 | 0x797324f1, 0xb11c5c0c, 0xa2cdd545, 0x71a0094f, 0xd51fbc6c, 0x00000000 |
138 | }; | 138 | }; |
139 | 139 | ||
140 | uint32_t g_atj_ec163_a[6] = | 140 | uint32_t g_sect163r2_a[6] = |
141 | { | 141 | { |
142 | 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 | 142 | 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 |
143 | }; | 143 | }; |
144 | 144 | ||
145 | uint32_t g_crypto_key5[6] = | 145 | uint32_t g_sect163r2_b[6] = |
146 | { | 146 | { |
147 | 0x4a3205fd, 0x512f7874, 0x1481eb10, 0xb8c953ca, 0x0a601907, 0x00000002 | 147 | 0x4a3205fd, 0x512f7874, 0x1481eb10, 0xb8c953ca, 0x0a601907, 0x00000002 |
148 | }; | 148 | }; |
149 | 149 | ||
150 | uint32_t g_atj_ec233_a[8] = | 150 | uint32_t g_sect233k1_a[8] = |
151 | { | 151 | { |
152 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 152 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
153 | }; | 153 | }; |
diff --git a/utils/atj2137/atjboottool/atj_tables.h b/utils/atj2137/atjboottool/atj_tables.h index d5eb4ae5d4..5ed75d6ac4 100644 --- a/utils/atj2137/atjboottool/atj_tables.h +++ b/utils/atj2137/atjboottool/atj_tables.h | |||
@@ -21,15 +21,15 @@ | |||
21 | #ifndef __ATJ_TABLES__ | 21 | #ifndef __ATJ_TABLES__ |
22 | #define __ATJ_TABLES__ | 22 | #define __ATJ_TABLES__ |
23 | 23 | ||
24 | uint8_t g_check_block_A_table[1024]; | 24 | extern uint8_t g_decode_A_table[1024]; |
25 | uint8_t g_decode_B_table[20]; | 25 | extern uint8_t g_decode_B_table[20]; |
26 | uint32_t g_crypto_table[8]; | 26 | extern uint32_t g_sect233k1_G_x[8]; |
27 | uint32_t g_crypto_table2[8]; | 27 | extern uint32_t g_sect233k1_G_y[8]; |
28 | uint32_t g_crypto_key6[8]; | 28 | extern uint32_t g_sect233k1_b[8]; |
29 | uint32_t g_crypto_key3[6]; | 29 | extern uint32_t g_sect163r2_G_x[6]; |
30 | uint32_t g_crypto_key4[6]; | 30 | extern uint32_t g_sect163r2_G_y[6]; |
31 | uint32_t g_crypto_key5[6]; | 31 | extern uint32_t g_sect163r2_a[6]; |
32 | uint32_t g_atj_ec233_a[8]; | 32 | extern uint32_t g_sect163r2_b[6]; |
33 | uint32_t g_atj_ec163_a[6]; | 33 | extern uint32_t g_sect233k1_a[8]; |
34 | 34 | ||
35 | #endif // __ATJ_TABLES__ | 35 | #endif // __ATJ_TABLES__ |
diff --git a/utils/atj2137/atjboottool/atjboottool.c b/utils/atj2137/atjboottool/atjboottool.c index d0ad1b468b..b68ada980e 100644 --- a/utils/atj2137/atjboottool/atjboottool.c +++ b/utils/atj2137/atjboottool/atjboottool.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <stdarg.h> | 27 | #include <stdarg.h> |
28 | #include <ctype.h> | 28 | #include <ctype.h> |
29 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
30 | #include <zlib.h> | ||
30 | #include "misc.h" | 31 | #include "misc.h" |
31 | #include "fwu.h" | 32 | #include "fwu.h" |
32 | #include "afi.h" | 33 | #include "afi.h" |
@@ -100,7 +101,26 @@ static int unpack_afi_fw_cb(const char *filename, uint8_t *buf, size_t size) | |||
100 | FILE *f = fopen(name, "wb"); | 101 | FILE *f = fopen(name, "wb"); |
101 | if(f) | 102 | if(f) |
102 | { | 103 | { |
103 | fwrite(buf, size, 1, f); | 104 | if (0 != memcmp(buf, "\x1f\x8b\x8\0\0\0\0\0\0\xb", 10)) |
105 | fwrite(buf, size, 1, f); | ||
106 | else | ||
107 | { | ||
108 | uint8_t buf_out[8192]; | ||
109 | z_stream zs; | ||
110 | int err = Z_OK; | ||
111 | cprintf(GREEN, "inflating... "); | ||
112 | memset(&zs, 0, sizeof(zs)); | ||
113 | zs.next_in = buf + 10; | ||
114 | zs.avail_in = size - 10; | ||
115 | inflateInit2(&zs, -MAX_WBITS); /* raw */ | ||
116 | while (err == Z_OK) | ||
117 | { | ||
118 | zs.next_out = buf_out; | ||
119 | zs.avail_out = sizeof(buf_out); | ||
120 | err = inflate(&zs, Z_NO_FLUSH); | ||
121 | fwrite(buf_out, 1, sizeof(buf_out) - zs.avail_out, f); | ||
122 | } | ||
123 | } | ||
104 | fclose(f); | 124 | fclose(f); |
105 | cprintf(RED, "Ok\n"); | 125 | cprintf(RED, "Ok\n"); |
106 | return 0; | 126 | return 0; |
@@ -119,10 +139,10 @@ static int do_afi(uint8_t *buf, size_t size) | |||
119 | return afi_unpack(buf, size, &unpack_afi_fw_cb); | 139 | return afi_unpack(buf, size, &unpack_afi_fw_cb); |
120 | } | 140 | } |
121 | 141 | ||
122 | static int do_fw(uint8_t *buf, size_t size) | 142 | static int do_fw(uint8_t *buf, size_t size, bool big_endian) |
123 | { | 143 | { |
124 | build_out_prefix(".unpack", "", true); | 144 | build_out_prefix(".unpack", "", true); |
125 | return fw_unpack(buf, size, &unpack_afi_fw_cb); | 145 | return fw_unpack(buf, size, &unpack_afi_fw_cb, big_endian); |
126 | } | 146 | } |
127 | static void usage(void) | 147 | static void usage(void) |
128 | { | 148 | { |
@@ -135,6 +155,7 @@ static void usage(void) | |||
135 | printf(" --fwu Unpack a FWU firmware file\n"); | 155 | printf(" --fwu Unpack a FWU firmware file\n"); |
136 | printf(" --afi Unpack a AFI archive file\n"); | 156 | printf(" --afi Unpack a AFI archive file\n"); |
137 | printf(" --fw Unpack a FW archive file\n"); | 157 | printf(" --fw Unpack a FW archive file\n"); |
158 | printf(" --fw251 Big-endian FW archive used on Flip80251\n"); | ||
138 | printf(" --atj2127 Force ATJ2127 decryption mode\n"); | 159 | printf(" --atj2127 Force ATJ2127 decryption mode\n"); |
139 | printf("The default is to try to guess the format.\n"); | 160 | printf("The default is to try to guess the format.\n"); |
140 | printf("If several formats are specified, all are tried.\n"); | 161 | printf("If several formats are specified, all are tried.\n"); |
@@ -147,6 +168,7 @@ int main(int argc, char **argv) | |||
147 | bool try_fwu = false; | 168 | bool try_fwu = false; |
148 | bool try_afi = false; | 169 | bool try_afi = false; |
149 | bool try_fw = false; | 170 | bool try_fw = false; |
171 | bool big_endian = false; | ||
150 | enum fwu_mode_t fwu_mode = FWU_AUTO; | 172 | enum fwu_mode_t fwu_mode = FWU_AUTO; |
151 | 173 | ||
152 | while(1) | 174 | while(1) |
@@ -159,11 +181,12 @@ int main(int argc, char **argv) | |||
159 | {"fwu", no_argument, 0, 'u'}, | 181 | {"fwu", no_argument, 0, 'u'}, |
160 | {"afi", no_argument, 0, 'a'}, | 182 | {"afi", no_argument, 0, 'a'}, |
161 | {"fw", no_argument, 0, 'w'}, | 183 | {"fw", no_argument, 0, 'w'}, |
184 | {"fw251", no_argument, 0, 'b'}, | ||
162 | {"atj2127", no_argument, 0, '2'}, | 185 | {"atj2127", no_argument, 0, '2'}, |
163 | {0, 0, 0, 0} | 186 | {0, 0, 0, 0} |
164 | }; | 187 | }; |
165 | 188 | ||
166 | int c = getopt_long(argc, argv, "hdco:a2", long_options, NULL); | 189 | int c = getopt_long(argc, argv, "hdco:a2b", long_options, NULL); |
167 | if(c == -1) | 190 | if(c == -1) |
168 | break; | 191 | break; |
169 | switch(c) | 192 | switch(c) |
@@ -192,6 +215,10 @@ int main(int argc, char **argv) | |||
192 | case 'w': | 215 | case 'w': |
193 | try_fw = true; | 216 | try_fw = true; |
194 | break; | 217 | break; |
218 | case 'b': | ||
219 | try_fw = true; | ||
220 | big_endian = true; | ||
221 | break; | ||
195 | case '2': | 222 | case '2': |
196 | fwu_mode = FWU_ATJ2127; | 223 | fwu_mode = FWU_ATJ2127; |
197 | break; | 224 | break; |
@@ -238,7 +265,7 @@ int main(int argc, char **argv) | |||
238 | else if(try_afi || afi_check(buf, size)) | 265 | else if(try_afi || afi_check(buf, size)) |
239 | ret = do_afi(buf, size); | 266 | ret = do_afi(buf, size); |
240 | else if(try_fw || fw_check(buf, size)) | 267 | else if(try_fw || fw_check(buf, size)) |
241 | ret = do_fw(buf, size); | 268 | ret = do_fw(buf, size, big_endian); |
242 | else | 269 | else |
243 | { | 270 | { |
244 | cprintf(GREY, "No valid format found\n"); | 271 | cprintf(GREY, "No valid format found\n"); |
diff --git a/utils/atj2137/atjboottool/fw.c b/utils/atj2137/atjboottool/fw.c index 07ce4e2f31..114123813b 100644 --- a/utils/atj2137/atjboottool/fw.c +++ b/utils/atj2137/atjboottool/fw.c | |||
@@ -38,7 +38,7 @@ struct fw_entry_t | |||
38 | uint16_t version; | 38 | uint16_t version; |
39 | uint32_t block_offset; // offset shift by 9 | 39 | uint32_t block_offset; // offset shift by 9 |
40 | uint32_t size; | 40 | uint32_t size; |
41 | uint32_t unk; | 41 | uint32_t bytes; |
42 | uint32_t checksum; | 42 | uint32_t checksum; |
43 | } __attribute__((packed)); | 43 | } __attribute__((packed)); |
44 | 44 | ||
@@ -78,7 +78,8 @@ struct fw_hdr_f0_t | |||
78 | uint8_t sig[FW_SIG_SIZE]; | 78 | uint8_t sig[FW_SIG_SIZE]; |
79 | uint8_t res[12]; | 79 | uint8_t res[12]; |
80 | uint32_t checksum; | 80 | uint32_t checksum; |
81 | uint8_t res2[492]; | 81 | uint8_t res2[490]; |
82 | uint16_t header_checksum; | ||
82 | 83 | ||
83 | struct fw_entry_t entry[FW_ENTRIES]; | 84 | struct fw_entry_t entry[FW_ENTRIES]; |
84 | } __attribute__((packed)); | 85 | } __attribute__((packed)); |
@@ -97,14 +98,56 @@ static void build_filename_fw(char buf[16], struct fw_entry_t *ent) | |||
97 | { | 98 | { |
98 | int pos = 0; | 99 | int pos = 0; |
99 | for(int i = 0; i < 8 && ent->name[i] != ' '; i++) | 100 | for(int i = 0; i < 8 && ent->name[i] != ' '; i++) |
100 | buf[pos++] = ent->name[i]; | 101 | buf[pos++] = tolower(ent->name[i]); |
101 | buf[pos++] = '.'; | 102 | buf[pos++] = '.'; |
102 | for(int i = 0; i < 3 && ent->ext[i] != ' '; i++) | 103 | for(int i = 0; i < 3 && ent->ext[i] != ' '; i++) |
103 | buf[pos++] = ent->ext[i]; | 104 | buf[pos++] = tolower(ent->ext[i]); |
104 | buf[pos] = 0; | 105 | buf[pos] = 0; |
105 | } | 106 | } |
106 | 107 | ||
107 | int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb) | 108 | static inline uint32_t u32_endian_swap(uint32_t u32) |
109 | { | ||
110 | return ((u32 & 0xff000000u) >> 24) | | ||
111 | ((u32 & 0x00ff0000u) >> 8) | | ||
112 | ((u32 & 0x0000ff00u) << 8) | | ||
113 | ((u32 & 0x000000ffu) << 24); | ||
114 | } | ||
115 | |||
116 | static uint32_t big_endian_checksum(void *ptr, size_t size) | ||
117 | { | ||
118 | uint32_t crc = 0; | ||
119 | uint32_t *cp = ptr; | ||
120 | for(; size >= 4; size -= 4) | ||
121 | crc += u32_endian_swap(*cp++); | ||
122 | /* FIXME all observed sizes divisible by 4, unclear how to add remainder */ | ||
123 | return crc; | ||
124 | } | ||
125 | |||
126 | static inline uint16_t u16_endian_swap(uint16_t u16) | ||
127 | { | ||
128 | return ((u16 & 0xff00u) >> 8) | | ||
129 | ((u16 & 0x00ffu) << 8); | ||
130 | } | ||
131 | |||
132 | static uint16_t lfi_header_checksum(void *ptr, size_t size, bool big_endian) | ||
133 | { | ||
134 | uint16_t crc = 0; | ||
135 | uint16_t *cp = ptr; | ||
136 | if (big_endian) | ||
137 | { | ||
138 | for(; size >= 2; size -= 2) | ||
139 | crc += u16_endian_swap(*cp++); | ||
140 | return u16_endian_swap(crc); /* to make comparable with the stored one */ | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | for(; size >= 2; size -= 2) | ||
145 | crc += *cp++; | ||
146 | return crc; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb, bool big_endian) | ||
108 | { | 151 | { |
109 | struct fw_hdr_t *hdr = (void *)buf; | 152 | struct fw_hdr_t *hdr = (void *)buf; |
110 | 153 | ||
@@ -165,8 +208,32 @@ int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb) | |||
165 | } | 208 | } |
166 | else | 209 | else |
167 | { | 210 | { |
168 | /* struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; */ | 211 | struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; |
169 | cprintf(GREEN, " Header not dumped because format is unclear.\n"); | 212 | uint32_t chk; |
213 | if (big_endian) | ||
214 | chk = u32_endian_swap(big_endian_checksum(buf + 0x200, 0x1e00)); | ||
215 | else | ||
216 | chk = afi_checksum(buf + 0x200, 0x1e00); | ||
217 | cprintf_field(" Directory checksum: ", "0x%x ", hdr_f0->checksum); | ||
218 | if(chk != hdr_f0->checksum) | ||
219 | { | ||
220 | cprintf(RED, "Mismatch, 0x%x expected\n", chk); | ||
221 | return 1; | ||
222 | } | ||
223 | else | ||
224 | cprintf(RED, "Ok\n"); | ||
225 | |||
226 | uint16_t header_chk = lfi_header_checksum(buf, 510, big_endian); | ||
227 | cprintf_field(" Header checksum: ", "0x%x ", hdr_f0->header_checksum); | ||
228 | if(header_chk != hdr_f0->header_checksum) | ||
229 | { | ||
230 | cprintf(RED, "Mismatch, 0x%x expected\n", header_chk); | ||
231 | return 1; | ||
232 | } | ||
233 | else | ||
234 | cprintf(RED, "Ok\n"); | ||
235 | |||
236 | cprintf(GREEN, " Rest of header not dumped because format is unclear.\n"); | ||
170 | } | 237 | } |
171 | 238 | ||
172 | cprintf(BLUE, "Entries\n"); | 239 | cprintf(BLUE, "Entries\n"); |
@@ -175,15 +242,29 @@ int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb) | |||
175 | if(hdr->entry[i].name[0] == 0) | 242 | if(hdr->entry[i].name[0] == 0) |
176 | continue; | 243 | continue; |
177 | struct fw_entry_t *entry = &hdr->entry[i]; | 244 | struct fw_entry_t *entry = &hdr->entry[i]; |
245 | if (big_endian) | ||
246 | { | ||
247 | /* must be in-place for correct load checksum later */ | ||
248 | entry->block_offset = u32_endian_swap(entry->block_offset); | ||
249 | entry->size = u32_endian_swap(entry->size); | ||
250 | entry->checksum = u32_endian_swap(entry->checksum); | ||
251 | } | ||
178 | char filename[16]; | 252 | char filename[16]; |
179 | build_filename_fw(filename, entry); | 253 | build_filename_fw(filename, entry); |
180 | cprintf(RED, " %s\n", filename); | 254 | cprintf(RED, " %s\n", filename); |
181 | cprintf_field(" Attr: ", "%02x\n", entry->attr); | 255 | cprintf_field(" Attr: ", "%02x\n", entry->attr); |
182 | cprintf_field(" Offset: ", "0x%x\n", entry->block_offset << 9); | 256 | cprintf_field(" Offset: ", "0x%x\n", entry->block_offset << 9); |
183 | cprintf_field(" Size: ", "0x%x\n", entry->size); | 257 | cprintf_field(" Size: ", "0x%x\n", entry->size); |
184 | cprintf_field(" Unknown: ", "%x\n", entry->unk); | 258 | cprintf_field(" Bytes: ", "0x%x\n", entry->bytes); |
185 | cprintf_field(" Checksum: ", "0x%x ", entry->checksum); | 259 | cprintf_field(" Checksum: ", "0x%x ", entry->checksum); |
186 | uint32_t chk = afi_checksum(buf + (entry->block_offset << 9), entry->size); | 260 | if (entry->bytes == 0) |
261 | entry->bytes = entry->size; | ||
262 | memset(buf + (entry->block_offset << 9) + entry->bytes, 0, entry->size - entry->bytes); | ||
263 | uint32_t chk; | ||
264 | if (big_endian) | ||
265 | chk = big_endian_checksum(buf + (entry->block_offset << 9), entry->size); | ||
266 | else | ||
267 | chk = afi_checksum(buf + (entry->block_offset << 9), entry->size); | ||
187 | if(chk != entry->checksum) | 268 | if(chk != entry->checksum) |
188 | { | 269 | { |
189 | cprintf(RED, "Mismatch\n"); | 270 | cprintf(RED, "Mismatch\n"); |
@@ -191,11 +272,25 @@ int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb) | |||
191 | } | 272 | } |
192 | else | 273 | else |
193 | cprintf(RED, "Ok\n"); | 274 | cprintf(RED, "Ok\n"); |
194 | int ret = unpack_cb(filename, buf + (entry->block_offset << 9), entry->size); | 275 | int ret = unpack_cb(filename, buf + (entry->block_offset << 9), entry->bytes); |
195 | if(ret != 0) | 276 | if(ret != 0) |
196 | return ret; | 277 | return ret; |
197 | } | 278 | } |
198 | 279 | ||
280 | if (big_endian) | ||
281 | { | ||
282 | uint32_t load_checksum = *(uint32_t *)(buf + size - 4); | ||
283 | uint32_t load_chk = big_endian_checksum(buf, size - 512); | ||
284 | cprintf_field(" Load checksum: ", "0x%x ", load_checksum); | ||
285 | if(load_chk != load_checksum) | ||
286 | { | ||
287 | cprintf(RED, "Mismatch, 0x%x expected\n", load_chk); | ||
288 | return 1; | ||
289 | } | ||
290 | else | ||
291 | cprintf(RED, "Ok\n"); | ||
292 | } | ||
293 | |||
199 | return 0; | 294 | return 0; |
200 | } | 295 | } |
201 | 296 | ||
diff --git a/utils/atj2137/atjboottool/fw.h b/utils/atj2137/atjboottool/fw.h index 95f8087116..9047de4b6d 100644 --- a/utils/atj2137/atjboottool/fw.h +++ b/utils/atj2137/atjboottool/fw.h | |||
@@ -27,7 +27,7 @@ | |||
27 | * its name and content. If the callback returns a nonzero value, the function will stop and return | 27 | * its name and content. If the callback returns a nonzero value, the function will stop and return |
28 | * that value. Returns 0 on success */ | 28 | * that value. Returns 0 on success */ |
29 | typedef int (*fw_extract_callback_t)(const char *name, uint8_t *buf, size_t size); | 29 | typedef int (*fw_extract_callback_t)(const char *name, uint8_t *buf, size_t size); |
30 | int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t cb); | 30 | int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t cb, bool big_endian); |
31 | /* Check if a file looks like an AFI file */ | 31 | /* Check if a file looks like an AFI file */ |
32 | bool fw_check(uint8_t *buf, size_t size); | 32 | bool fw_check(uint8_t *buf, size_t size); |
33 | 33 | ||
diff --git a/utils/atj2137/atjboottool/fwu.c b/utils/atj2137/atjboottool/fwu.c index 4d09dd876e..c9f6c440fd 100644 --- a/utils/atj2137/atjboottool/fwu.c +++ b/utils/atj2137/atjboottool/fwu.c | |||
@@ -59,6 +59,46 @@ struct fwu_crypto_hdr_t | |||
59 | uint8_t key[32]; | 59 | uint8_t key[32]; |
60 | } __attribute__((packed)); | 60 | } __attribute__((packed)); |
61 | 61 | ||
62 | struct fwu_sector0_tail_t | ||
63 | { | ||
64 | uint8_t unk_2; | ||
65 | uint32_t unk_x808; | ||
66 | uint32_t unk_8; | ||
67 | uint8_t key_B[16]; | ||
68 | uint8_t guid[16]; | ||
69 | uint8_t unk_190; | ||
70 | uint8_t super_secret_xor[16]; | ||
71 | uint8_t timestamp[8]; | ||
72 | uint8_t unk_0; | ||
73 | uint8_t guid_filler[20]; | ||
74 | uint8_t unk_1; | ||
75 | uint8_t check[20]; | ||
76 | } __attribute__((packed)); | ||
77 | |||
78 | struct fwu_block_A_hdr_t | ||
79 | { | ||
80 | uint16_t block_A_size; | ||
81 | uint8_t unk_0_a; | ||
82 | uint8_t unk_1_a; | ||
83 | uint8_t key_B[16]; | ||
84 | uint8_t guid_filler[256]; | ||
85 | uint8_t ec_sz; | ||
86 | uint8_t unk_0_b; | ||
87 | uint32_t unk_5; | ||
88 | uint32_t unk_x505; | ||
89 | uint16_t unk_1_b; | ||
90 | uint8_t timestamp[8]; | ||
91 | } __attribute__((packed)); | ||
92 | |||
93 | struct fwu_block_B_hdr_t | ||
94 | { | ||
95 | uint16_t block_B_size; | ||
96 | uint8_t unk_1_a; | ||
97 | uint16_t unk_1_b; | ||
98 | uint8_t timestamp[8]; | ||
99 | uint16_t guid_filler_size; | ||
100 | } __attribute__((packed)); | ||
101 | |||
62 | struct fwu_tail_t | 102 | struct fwu_tail_t |
63 | { | 103 | { |
64 | uint8_t length; /* in blocks? it's always 1 */ | 104 | uint8_t length; /* in blocks? it's always 1 */ |
@@ -95,41 +135,32 @@ typedef struct ec_point_t | |||
95 | uint32_t *y; | 135 | uint32_t *y; |
96 | }ec_point_t; | 136 | }ec_point_t; |
97 | 137 | ||
98 | struct block_A_info_t | 138 | struct ec_info_t |
99 | { | 139 | { |
100 | int nr_bits; | 140 | int nr_bits; |
101 | uint16_t field_2; | 141 | int point_size; |
102 | int nr_words; | ||
103 | int nr_dwords_x12; | ||
104 | uint32_t *ec_a; // size | 142 | uint32_t *ec_a; // size |
105 | uint32_t *ptr7; // size | 143 | uint32_t *ec_b; // size |
106 | uint32_t *field_poly; // size | 144 | uint32_t *field_poly; // size |
107 | uint32_t size; | 145 | uint32_t size; |
108 | uint32_t field_1C; | 146 | ec_point_t pt_G; |
109 | ec_point_t ptr1; | 147 | ec_point_t pt_kG; // calculated ECIES public key |
110 | uint32_t *ptr3; // size | ||
111 | uint32_t *ptr4; // size | ||
112 | int nr_words2; | ||
113 | uint32_t field_bits; | 148 | uint32_t field_bits; |
114 | int nr_dwords_x8; | 149 | int size_x2; |
115 | int nr_bytes; | 150 | int nr_bytes; |
116 | int nr_bytes2; | ||
117 | int nr_dwords_m1; | 151 | int nr_dwords_m1; |
118 | int nr_dwords_x2_m1; | ||
119 | int nr_dwords_x2; | 152 | int nr_dwords_x2; |
153 | int nr_dwords_x2_m1; | ||
120 | int nr_dwords; | 154 | int nr_dwords; |
121 | uint32_t field_54; | ||
122 | uint32_t field_58; | ||
123 | }; | 155 | }; |
124 | 156 | ||
125 | struct block_A_info_t g_decode_A_info; | 157 | struct ec_info_t g_ec_info; |
126 | uint8_t g_subblock_A[0x128]; | 158 | struct fwu_block_A_hdr_t g_subblock_A; |
127 | uint8_t g_key_B[20]; | 159 | uint8_t g_key_B[20]; |
128 | uint8_t g_perm_B[258]; | 160 | uint8_t g_rc4_S[258]; |
129 | uint8_t g_crypto_info_byte; | 161 | uint8_t g_field_sz_byte; |
130 | uint8_t *g_decode_buffer; | 162 | ec_point_t g_public_key; // from block A |
131 | uint8_t *g_decode_buffer2; | 163 | uint32_t *g_private_key; // from block B |
132 | void *g_decode_buffer3; | ||
133 | 164 | ||
134 | #include "atj_tables.h" | 165 | #include "atj_tables.h" |
135 | #include <ctype.h> | 166 | #include <ctype.h> |
@@ -186,7 +217,7 @@ int get_version(uint8_t *buf, unsigned long size) | |||
186 | 217 | ||
187 | static int decode_block_A(uint8_t block[1020]) | 218 | static int decode_block_A(uint8_t block[1020]) |
188 | { | 219 | { |
189 | uint8_t *p = &g_check_block_A_table[32 * (block[998] & 0x1f)]; | 220 | uint8_t *p = &g_decode_A_table[32 * (block[998] & 31)]; |
190 | uint8_t key[32]; | 221 | uint8_t key[32]; |
191 | 222 | ||
192 | for(int i = 0; i < 20; i++) | 223 | for(int i = 0; i < 20; i++) |
@@ -197,50 +228,53 @@ static int decode_block_A(uint8_t block[1020]) | |||
197 | for(int i = 20; i < 32; i++) | 228 | for(int i = 20; i < 32; i++) |
198 | key[i] = key[i - 20]; | 229 | key[i] = key[i - 20]; |
199 | 230 | ||
200 | for(int i = 0; i < 992; i++) | 231 | for(int i = 0; i < 31 * 32; i++) |
201 | block[i] ^= key[i % 32] ^ g_check_block_A_table[i]; | 232 | block[i] ^= key[i % 32] ^ g_decode_A_table[i]; |
202 | 233 | ||
234 | // FIXME dereferencing block - 1 is undefined behavior in standard C | ||
203 | return check_block(block - 1, block + 1000, 1001); | 235 | return check_block(block - 1, block + 1000, 1001); |
204 | } | 236 | } |
205 | 237 | ||
206 | static void compute_perm(uint8_t *keybuf, size_t size, uint8_t perm[258]) | 238 | // https://en.wikipedia.org/wiki/RC4#Key-scheduling_algorithm_(KSA) |
239 | static void rc4_key_schedule(uint8_t *key, size_t keylength, uint8_t S[258]) | ||
207 | { | 240 | { |
208 | for(int i = 0; i < 256; i++) | 241 | for(int i = 0; i < 256; i++) |
209 | perm[i] = i; | 242 | S[i] = i; |
210 | perm[256] = perm[257] = 0; | 243 | S[256] = S[257] = 0; |
211 | uint8_t idx = 0; | 244 | uint8_t j = 0; |
212 | for(int i = 0; i < 256; i++) | 245 | for(int i = 0; i < 256; i++) |
213 | { | 246 | { |
214 | uint8_t v = perm[i]; | 247 | j = (j + S[i] + key[i % keylength]) % 256; |
215 | idx = (v + keybuf[i % size] + idx) % 256; | 248 | uint8_t tmp = S[i]; |
216 | perm[i] = perm[idx]; | 249 | S[i] = S[j]; |
217 | perm[idx] = v; | 250 | S[j] = tmp; |
218 | } | 251 | } |
219 | } | 252 | } |
220 | 253 | ||
221 | static void decode_perm(uint8_t *buf, size_t size, uint8_t perm[258]) | 254 | // https://en.wikipedia.org/wiki/RC4#Pseudo-random_generation_algorithm_(PRGA) |
255 | static void rc4_stream_cipher(uint8_t *buf, size_t size, uint8_t S[258]) | ||
222 | { | 256 | { |
223 | uint8_t idxa = perm[256]; | 257 | uint8_t i = S[256]; |
224 | uint8_t idxb = perm[257]; | 258 | uint8_t j = S[257]; |
225 | for(size_t i = 0; i < size; i++) | 259 | for(size_t k = 0; k < size; k++) |
226 | { | 260 | { |
227 | idxa = (idxa + 1) % 256; | 261 | i = (i + 1) % 256; |
228 | uint8_t v = perm[idxa]; | 262 | j = (j + S[i]) % 256; |
229 | idxb = (idxb + v) % 256; | 263 | uint8_t tmp = S[i]; |
230 | perm[idxa] = perm[idxb]; | 264 | S[i] = S[j]; |
231 | perm[idxb] = v; | 265 | S[j] = tmp; |
232 | buf[i] ^= perm[(v + perm[idxa]) % 256]; | 266 | buf[k] ^= S[(S[i] + S[j]) % 256]; |
233 | } | 267 | } |
234 | } | 268 | } |
235 | 269 | ||
236 | static void decode_block_with_perm(uint8_t *keybuf, int keysize, | 270 | static void rc4_cipher_block(uint8_t *keybuf, int keysize, |
237 | uint8_t *buf, int bufsize, uint8_t perm[258]) | 271 | uint8_t *buf, int bufsize, uint8_t S[258]) |
238 | { | 272 | { |
239 | compute_perm(keybuf, keysize, perm); | 273 | rc4_key_schedule(keybuf, keysize, S); |
240 | decode_perm(buf, bufsize, perm); | 274 | rc4_stream_cipher(buf, bufsize, S); |
241 | } | 275 | } |
242 | 276 | ||
243 | static void apply_perm(uint8_t *inbuf, uint8_t *outbuf, size_t size, int swap) | 277 | static void rc4_key_swap(uint8_t *inbuf, uint8_t *outbuf, size_t size, int swap) |
244 | { | 278 | { |
245 | memcpy(outbuf, inbuf, size); | 279 | memcpy(outbuf, inbuf, size); |
246 | int a = swap & 0xf; | 280 | int a = swap & 0xf; |
@@ -250,16 +284,16 @@ static void apply_perm(uint8_t *inbuf, uint8_t *outbuf, size_t size, int swap) | |||
250 | outbuf[b] = v; | 284 | outbuf[b] = v; |
251 | } | 285 | } |
252 | 286 | ||
253 | static void decode_block_with_swap(uint8_t keybuf[32], int swap, | 287 | static void rc4_key_swap_and_decode(uint8_t keybuf[32], int swap, |
254 | uint8_t *buf, int bufsize, uint8_t perm[258]) | 288 | uint8_t *buf, int bufsize, uint8_t S[258]) |
255 | { | 289 | { |
256 | uint8_t keybuf_interm[32]; | 290 | uint8_t keybuf_interm[32]; |
257 | 291 | ||
258 | apply_perm(keybuf, keybuf_interm, 32, swap); | 292 | rc4_key_swap(keybuf, keybuf_interm, 32, swap); |
259 | decode_block_with_perm(keybuf_interm, 32, buf, bufsize, perm); | 293 | rc4_cipher_block(keybuf_interm, 32, buf, bufsize, S); |
260 | } | 294 | } |
261 | 295 | ||
262 | static void clear_memory(void *buf, size_t size_dwords) | 296 | static void gf_zero(void *buf, size_t size_dwords) |
263 | { | 297 | { |
264 | memset(buf, 0, 4 * size_dwords); | 298 | memset(buf, 0, 4 * size_dwords); |
265 | } | 299 | } |
@@ -269,40 +303,35 @@ static void set_bit(int bit_pos, uint32_t *buf) | |||
269 | buf[bit_pos / 32] |= 1 << (bit_pos % 32); | 303 | buf[bit_pos / 32] |= 1 << (bit_pos % 32); |
270 | } | 304 | } |
271 | 305 | ||
272 | static int fill_decode_info(uint8_t sz) | 306 | static int fill_ec_info(uint8_t sz) |
273 | { | 307 | { |
274 | if(sz == 2) sz = 233; | 308 | if(sz == 2) sz = 233; |
275 | else if(sz == 3) sz = 163; | 309 | else if(sz == 3) sz = 163; |
276 | else return 1; | 310 | else return 1; |
277 | 311 | ||
278 | g_decode_A_info.nr_bits = sz; | 312 | g_ec_info.nr_bits = sz; |
279 | g_decode_A_info.nr_bytes2 = sz / 8 + (sz % 8 != 0); | 313 | g_ec_info.nr_bytes = sz / 8 + (sz % 8 != 0); |
280 | g_decode_A_info.nr_words = 2 * g_decode_A_info.nr_bytes2; | 314 | g_ec_info.point_size = 2 * g_ec_info.nr_bytes; |
281 | g_decode_A_info.nr_bytes = sz / 8 + (sz % 8 != 0); | 315 | g_ec_info.nr_dwords = sz / 32 + (sz % 32 != 0); |
282 | g_decode_A_info.nr_words2 = 2 * g_decode_A_info.nr_bytes2; | 316 | g_ec_info.size = 4 * g_ec_info.nr_dwords; |
283 | g_decode_A_info.nr_dwords = sz / 32 + (sz % 32 != 0); | 317 | g_ec_info.size_x2 = 8 * g_ec_info.nr_dwords; |
284 | g_decode_A_info.size = 4 * g_decode_A_info.nr_dwords; | 318 | g_ec_info.nr_dwords_m1 = g_ec_info.nr_dwords - 1; |
285 | g_decode_A_info.nr_dwords_x8 = 8 * g_decode_A_info.nr_dwords; | 319 | g_ec_info.nr_dwords_x2 = 2 * g_ec_info.nr_dwords; |
286 | g_decode_A_info.nr_dwords_m1 = g_decode_A_info.nr_dwords - 1; | 320 | g_ec_info.nr_dwords_x2_m1 = g_ec_info.nr_dwords_x2 - 1; |
287 | g_decode_A_info.nr_dwords_x2 = 2 * g_decode_A_info.nr_dwords; | 321 | g_ec_info.pt_G.x = malloc(4 * g_ec_info.nr_dwords); |
288 | g_decode_A_info.nr_dwords_x2_m1 = g_decode_A_info.nr_dwords_x2 - 1; | 322 | g_ec_info.pt_G.y = malloc(g_ec_info.size); |
289 | g_decode_A_info.nr_dwords_x12 = 12 * g_decode_A_info.nr_dwords; | 323 | g_ec_info.pt_kG.x = malloc(g_ec_info.size); |
290 | g_decode_A_info.ptr1.x = malloc(4 * g_decode_A_info.nr_dwords); | 324 | g_ec_info.pt_kG.y = malloc(g_ec_info.size); |
291 | g_decode_A_info.ptr1.y = malloc(g_decode_A_info.size); | 325 | g_ec_info.field_poly = malloc(g_ec_info.size); |
292 | g_decode_A_info.ptr3 = malloc(g_decode_A_info.size); | 326 | g_ec_info.ec_a = malloc(g_ec_info.size); |
293 | g_decode_A_info.ptr4 = malloc(g_decode_A_info.size); | 327 | g_ec_info.ec_b = malloc(g_ec_info.size); |
294 | g_decode_A_info.field_poly = malloc(g_decode_A_info.size); | 328 | |
295 | g_decode_A_info.ec_a = malloc(g_decode_A_info.size); | 329 | cprintf(BLUE, " Elliptic curve info:\n"); |
296 | g_decode_A_info.ptr7 = malloc(g_decode_A_info.size); | 330 | cprintf_field(" Field Bits: ", "%d\n", g_ec_info.nr_bits); |
297 | 331 | cprintf_field(" Field Bytes: ", "%d\n", g_ec_info.nr_bytes); | |
298 | cprintf(BLUE, " Decode Info:\n"); | 332 | cprintf_field(" Point Size: ", "%d\n", g_ec_info.point_size); |
299 | cprintf_field(" Nr Bits: ", "%d\n", g_decode_A_info.nr_bits); | 333 | cprintf_field(" Field DWords: ", "%d\n", g_ec_info.nr_dwords); |
300 | cprintf_field(" Nr Bytes: ", "%d\n", g_decode_A_info.nr_bytes); | 334 | cprintf_field(" Size: ", "%d\n", g_ec_info.size); |
301 | cprintf_field(" Nr Bytes 2: ", "%d\n", g_decode_A_info.nr_bytes2); | ||
302 | cprintf_field(" Nr Words: ", "%d\n", g_decode_A_info.nr_words); | ||
303 | cprintf_field(" Nr Words 2: ", "%d\n", g_decode_A_info.nr_words2); | ||
304 | cprintf_field(" Nr DWords: ", "%d\n", g_decode_A_info.nr_dwords); | ||
305 | cprintf_field(" Size: ", "%d\n", g_decode_A_info.size); | ||
306 | 335 | ||
307 | return 0; | 336 | return 0; |
308 | } | 337 | } |
@@ -313,29 +342,31 @@ static int process_block_A(uint8_t block[1024]) | |||
313 | int ret = decode_block_A(block + 4); | 342 | int ret = decode_block_A(block + 4); |
314 | cprintf(GREEN, " Check: "); | 343 | cprintf(GREEN, " Check: "); |
315 | check_field(ret, 0, "Pass\n", "Fail\n"); | 344 | check_field(ret, 0, "Pass\n", "Fail\n"); |
316 | print_hex("BlockA", block, 1024); | 345 | // print_hex("BlockA", block, 1024); |
317 | 346 | ||
318 | memcpy(g_subblock_A, block, sizeof(g_subblock_A)); | 347 | memcpy(&g_subblock_A, block, sizeof(g_subblock_A)); |
319 | ret = fill_decode_info(g_subblock_A[276]); | 348 | // assert(offsetof(struct fwu_block_A_hdr_t, ec_sz) == 276); |
349 | ret = fill_ec_info(g_subblock_A.ec_sz); | ||
320 | cprintf(GREEN, " Info: "); | 350 | cprintf(GREEN, " Info: "); |
321 | check_field(ret, 0, "Pass\n", "Fail\n"); | 351 | check_field(ret, 0, "Pass\n", "Fail\n"); |
322 | 352 | ||
323 | int tmp = 2 * g_decode_A_info.nr_bytes2 + 38; | 353 | int tmp = 2 * g_ec_info.nr_bytes + 38; |
324 | int offset = 1004 - tmp + 5; | 354 | int offset = 1004 - tmp + 5; |
325 | g_crypto_info_byte = block[offset - 1]; | 355 | g_field_sz_byte = block[offset - 1]; |
326 | g_decode_buffer = malloc(g_decode_A_info.size); | 356 | g_public_key.x = malloc(g_ec_info.size); |
327 | g_decode_buffer2 = malloc(g_decode_A_info.size); | 357 | g_public_key.y = malloc(g_ec_info.size); |
328 | 358 | ||
329 | memset(g_decode_buffer, 0, g_decode_A_info.size); | 359 | memset(g_public_key.x, 0, g_ec_info.size); |
330 | memset(g_decode_buffer2, 0, g_decode_A_info.size); | 360 | memset(g_public_key.y, 0, g_ec_info.size); |
331 | 361 | ||
332 | memcpy(g_decode_buffer, &block[offset], g_decode_A_info.nr_bytes2); | 362 | memcpy(g_public_key.x, &block[offset], g_ec_info.nr_bytes); |
333 | int offset2 = g_decode_A_info.nr_bytes2 + offset; | 363 | int offset2 = g_ec_info.nr_bytes + offset; |
334 | memcpy(g_decode_buffer2, &block[offset2], g_decode_A_info.nr_bytes2); | 364 | memcpy(g_public_key.y, &block[offset2], g_ec_info.nr_bytes); |
335 | 365 | ||
336 | 366 | ||
337 | cprintf_field(" Word: ", "%d ", *(uint16_t *)&g_subblock_A[286]); | 367 | // assert(offsetof(struct fwu_block_A_hdr_t, unk_1_b) == 286); |
338 | check_field(*(uint16_t *)&g_subblock_A[286], 1, "Ok\n", "Mismatch\n"); | 368 | cprintf_field(" Word: ", "%d ", g_subblock_A.unk_1_b); |
369 | check_field(g_subblock_A.unk_1_b, 1, "Ok\n", "Mismatch\n"); | ||
339 | 370 | ||
340 | return 0; | 371 | return 0; |
341 | } | 372 | } |
@@ -353,12 +384,12 @@ static void decode_key_B(uint8_t buf[20], uint8_t buf2[16], uint8_t key[20]) | |||
353 | static void decode_block_B(uint8_t *buf, uint8_t key[16], size_t size) | 384 | static void decode_block_B(uint8_t *buf, uint8_t key[16], size_t size) |
354 | { | 385 | { |
355 | decode_key_B(&buf[size], key, g_key_B); | 386 | decode_key_B(&buf[size], key, g_key_B); |
356 | decode_block_with_perm(g_key_B, 20, buf, size, g_perm_B); | 387 | rc4_cipher_block(g_key_B, 20, buf, size, g_rc4_S); |
357 | } | 388 | } |
358 | 389 | ||
359 | static int find_last_bit_set(uint32_t *buf, bool a) | 390 | static int find_last_bit_set(uint32_t *buf, bool a) |
360 | { | 391 | { |
361 | int i = a ? g_decode_A_info.nr_dwords_m1 : g_decode_A_info.nr_dwords_x2_m1; | 392 | int i = a ? g_ec_info.nr_dwords_m1 : g_ec_info.nr_dwords_x2_m1; |
362 | 393 | ||
363 | while(i >= 0 && buf[i] == 0) | 394 | while(i >= 0 && buf[i] == 0) |
364 | i--; | 395 | i--; |
@@ -370,15 +401,15 @@ static int find_last_bit_set(uint32_t *buf, bool a) | |||
370 | return -1; // unreachable | 401 | return -1; // unreachable |
371 | } | 402 | } |
372 | 403 | ||
373 | static void copy_memory(uint32_t *to, uint32_t *from) | 404 | static void gf_copy(uint32_t *to, uint32_t *from) |
374 | { | 405 | { |
375 | for(int i = 0; i < g_decode_A_info.nr_dwords; i++) | 406 | for(int i = 0; i < g_ec_info.nr_dwords; i++) |
376 | to[i] = from[i]; | 407 | to[i] = from[i]; |
377 | } | 408 | } |
378 | 409 | ||
379 | static void swap_memory(uint32_t *a, uint32_t *b) | 410 | static void gf_swap(uint32_t *a, uint32_t *b) |
380 | { | 411 | { |
381 | for(int i = 0; i < g_decode_A_info.nr_dwords; i++) | 412 | for(int i = 0; i < g_ec_info.nr_dwords; i++) |
382 | { | 413 | { |
383 | uint32_t c = a[i]; | 414 | uint32_t c = a[i]; |
384 | a[i] = b[i]; | 415 | a[i] = b[i]; |
@@ -388,11 +419,11 @@ static void swap_memory(uint32_t *a, uint32_t *b) | |||
388 | 419 | ||
389 | static void shift_left(uint32_t *buf, int nr_bits) | 420 | static void shift_left(uint32_t *buf, int nr_bits) |
390 | { | 421 | { |
391 | for(int i = g_decode_A_info.nr_dwords_m1; i >= 0; i--) | 422 | for(int i = g_ec_info.nr_dwords_m1; i >= 0; i--) |
392 | buf[i + (nr_bits / 32)] = buf[i]; | 423 | buf[i + (nr_bits / 32)] = buf[i]; |
393 | memset(buf, 0, 4 * (nr_bits / 32)); | 424 | memset(buf, 0, 4 * (nr_bits / 32)); |
394 | 425 | ||
395 | size_t size = g_decode_A_info.nr_dwords + (nr_bits + 31) / 32; | 426 | size_t size = g_ec_info.nr_dwords + (nr_bits + 31) / 32; |
396 | nr_bits = nr_bits % 32; | 427 | nr_bits = nr_bits % 32; |
397 | 428 | ||
398 | uint32_t acc = 0; | 429 | uint32_t acc = 0; |
@@ -407,9 +438,9 @@ static void shift_left(uint32_t *buf, int nr_bits) | |||
407 | } | 438 | } |
408 | } | 439 | } |
409 | 440 | ||
410 | static void xor_big(uint32_t *res, uint32_t *a, uint32_t *b) | 441 | static void gf_add_x2(uint32_t *res, uint32_t *a, uint32_t *b) |
411 | { | 442 | { |
412 | for(int i = 0; i < g_decode_A_info.nr_dwords_x2; i++) | 443 | for(int i = 0; i < g_ec_info.nr_dwords_x2; i++) |
413 | res[i] = a[i] ^ b[i]; | 444 | res[i] = a[i] ^ b[i]; |
414 | } | 445 | } |
415 | 446 | ||
@@ -433,39 +464,49 @@ static void print_poly(const char *name, uint32_t *poly, int nr_dwords) | |||
433 | cprintf(OFF, "\n"); | 464 | cprintf(OFF, "\n"); |
434 | } | 465 | } |
435 | 466 | ||
436 | static void gf_inverse(uint32_t *res, uint32_t *val) | 467 | /* https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Simple_algebraic_field_extensions |
468 | * invariant: p * s + a * t == r -> a * t == r (mod p) | ||
469 | * loop until only lowest bit set (r == 1) -> inverse in t */ | ||
470 | static void gf_inverse(uint32_t *newt, uint32_t *val) | ||
437 | { | 471 | { |
438 | uint32_t *tmp = malloc(g_decode_A_info.nr_dwords_x8); | 472 | uint32_t *tmp = malloc(g_ec_info.size_x2); |
439 | uint32_t *copy = malloc(g_decode_A_info.nr_dwords_x8); | 473 | uint32_t *r = malloc(g_ec_info.size_x2); |
440 | uint32_t *copy_arg = malloc(g_decode_A_info.nr_dwords_x8); | 474 | uint32_t *newr = malloc(g_ec_info.size_x2); |
441 | uint32_t *tmp2 = malloc(g_decode_A_info.nr_dwords_x8); | 475 | uint32_t *t = malloc(g_ec_info.size_x2); |
442 | clear_memory(tmp, g_decode_A_info.nr_dwords_x2); | 476 | gf_zero(tmp, g_ec_info.nr_dwords_x2); |
443 | clear_memory(res, g_decode_A_info.nr_dwords); | 477 | /* newt := 1 */ |
444 | *res = 1; | 478 | gf_zero(newt, g_ec_info.nr_dwords); |
445 | clear_memory(tmp2, g_decode_A_info.nr_dwords); | 479 | *newt = 1; |
446 | copy_memory(copy_arg, val); | 480 | /* t := 0 */ |
447 | copy_memory(copy, (uint32_t *)g_decode_A_info.field_poly); | 481 | gf_zero(t, g_ec_info.nr_dwords); |
448 | 482 | /* newr := a */ | |
449 | for(int i = find_last_bit_set(copy_arg, 1); i; i = find_last_bit_set(copy_arg, 1)) | 483 | gf_copy(newr, val); |
484 | /* r := p */ | ||
485 | gf_copy(r, g_ec_info.field_poly); | ||
486 | |||
487 | for(int i = find_last_bit_set(newr, 1); i; i = find_last_bit_set(newr, 1)) | ||
450 | { | 488 | { |
451 | int pos = i - find_last_bit_set(copy, 1); | 489 | /* pos := degree(newr) - degree(r) */ |
490 | int pos = i - find_last_bit_set(r, 1); | ||
452 | if(pos < 0) | 491 | if(pos < 0) |
453 | { | 492 | { |
454 | swap_memory(copy_arg, copy); | 493 | gf_swap(newr, r); |
455 | swap_memory(res, tmp2); | 494 | gf_swap(newt, t); |
456 | pos = -pos; | 495 | pos = -pos; |
457 | } | 496 | } |
458 | copy_memory(tmp, copy); | 497 | /* newr := newr - x^pos * r */ |
498 | gf_copy(tmp, r); | ||
459 | shift_left(tmp, pos); | 499 | shift_left(tmp, pos); |
460 | xor_big(copy_arg, copy_arg, tmp); | 500 | gf_add_x2(newr, newr, tmp); |
461 | copy_memory(tmp, tmp2); | 501 | /* newt := newt - x^pos * t */ |
502 | gf_copy(tmp, t); | ||
462 | shift_left(tmp, pos); | 503 | shift_left(tmp, pos); |
463 | xor_big(res, res, tmp); | 504 | gf_add_x2(newt, newt, tmp); |
464 | } | 505 | } |
465 | free(tmp); | 506 | free(tmp); |
466 | free(copy); | 507 | free(r); |
467 | free(copy_arg); | 508 | free(newr); |
468 | free(tmp2); | 509 | free(t); |
469 | } | 510 | } |
470 | 511 | ||
471 | static void shift_left_one(uint32_t *a) | 512 | static void shift_left_one(uint32_t *a) |
@@ -488,15 +529,15 @@ static void shift_left_one(uint32_t *a) | |||
488 | #if 1 | 529 | #if 1 |
489 | static void gf_mult(uint32_t *res, uint32_t *a2, uint32_t *a3) | 530 | static void gf_mult(uint32_t *res, uint32_t *a2, uint32_t *a3) |
490 | { | 531 | { |
491 | uint32_t *tmp2 = malloc(g_decode_A_info.nr_dwords_x8); | 532 | uint32_t *tmp2 = malloc(g_ec_info.size_x2); |
492 | clear_memory(tmp2, g_decode_A_info.nr_dwords_x2); | 533 | gf_zero(tmp2, g_ec_info.nr_dwords_x2); |
493 | copy_memory(tmp2, a3); | 534 | gf_copy(tmp2, a3); |
494 | 535 | ||
495 | int pos = g_decode_A_info.nr_dwords; | 536 | int pos = g_ec_info.nr_dwords; |
496 | uint32_t mask = 1; | 537 | uint32_t mask = 1; |
497 | for(int i = 0; i < 32; i++) | 538 | for(int i = 0; i < 32; i++) |
498 | { | 539 | { |
499 | for(int j = 0; j < g_decode_A_info.nr_dwords; j++) | 540 | for(int j = 0; j < g_ec_info.nr_dwords; j++) |
500 | { | 541 | { |
501 | if(a2[j] & mask) | 542 | if(a2[j] & mask) |
502 | for(int k = 0; k < pos; k++) | 543 | for(int k = 0; k < pos; k++) |
@@ -511,8 +552,8 @@ static void gf_mult(uint32_t *res, uint32_t *a2, uint32_t *a3) | |||
511 | #else | 552 | #else |
512 | static void gf_mult(uint32_t *res, uint32_t *a2, uint32_t *a3) | 553 | static void gf_mult(uint32_t *res, uint32_t *a2, uint32_t *a3) |
513 | { | 554 | { |
514 | for(int i = 0; i < 32 * g_decode_A_info.nr_dwords; i++) | 555 | for(int i = 0; i < 32 * g_ec_info.nr_dwords; i++) |
515 | for(int j = 0; j < 32 * g_decode_A_info.nr_dwords; j++) | 556 | for(int j = 0; j < 32 * g_ec_info.nr_dwords; j++) |
516 | { | 557 | { |
517 | int k = i + j; | 558 | int k = i + j; |
518 | uint32_t v1 = (a2[i / 32] >> (i % 32)) & 1; | 559 | uint32_t v1 = (a2[i / 32] >> (i % 32)) & 1; |
@@ -522,32 +563,35 @@ static void gf_mult(uint32_t *res, uint32_t *a2, uint32_t *a3) | |||
522 | } | 563 | } |
523 | #endif | 564 | #endif |
524 | 565 | ||
525 | static void gf_mod(uint32_t *inout, uint32_t *other) | 566 | // https://en.wikipedia.org/wiki/Polynomial_long_division#Pseudocode |
567 | static void gf_mod(uint32_t *r, uint32_t *field_poly) | ||
526 | { | 568 | { |
527 | uint32_t *tmp = malloc(g_decode_A_info.nr_dwords_x8); | 569 | uint32_t *tmp = malloc(g_ec_info.size_x2); |
528 | int v4 = g_decode_A_info.field_bits; | 570 | int deg_d = g_ec_info.field_bits; |
529 | int pos = find_last_bit_set(inout, 0); | 571 | int deg_r = find_last_bit_set(r, 0); |
530 | for(int i = pos - v4; i >= 0; i = find_last_bit_set(inout, 0) - v4) | 572 | /* i := degree(lead(r) / lead(d)) */ |
573 | for(int i = deg_r - deg_d; i >= 0; i = find_last_bit_set(r, 0) - deg_d) | ||
531 | { | 574 | { |
532 | clear_memory(tmp, g_decode_A_info.nr_dwords_x2); | 575 | /* r := r - x^i * d */ |
533 | copy_memory(tmp, other); | 576 | gf_zero(tmp, g_ec_info.nr_dwords_x2); |
577 | gf_copy(tmp, field_poly); | ||
534 | shift_left(tmp, i); | 578 | shift_left(tmp, i); |
535 | xor_big(inout, inout, tmp); | 579 | gf_add_x2(r, r, tmp); |
536 | } | 580 | } |
537 | free(tmp); | 581 | free(tmp); |
538 | } | 582 | } |
539 | 583 | ||
540 | static void gf_add(uint32_t *res, uint32_t *a, uint32_t *b) | 584 | static void gf_add(uint32_t *res, uint32_t *a, uint32_t *b) |
541 | { | 585 | { |
542 | for(int i = 0; i < g_decode_A_info.nr_dwords; i++) | 586 | for(int i = 0; i < g_ec_info.nr_dwords; i++) |
543 | res[i] = a[i] ^ b[i]; | 587 | res[i] = a[i] ^ b[i]; |
544 | } | 588 | } |
545 | 589 | ||
546 | static void print_point(const char *name, ec_point_t *ptr) | 590 | static void print_point(const char *name, ec_point_t *ptr) |
547 | { | 591 | { |
548 | cprintf(BLUE, "%s\n", name); | 592 | cprintf(BLUE, "%s\n", name); |
549 | print_poly(" x: ", ptr->x, g_decode_A_info.nr_dwords); | 593 | print_poly(" x: ", ptr->x, g_ec_info.nr_dwords); |
550 | print_poly(" y: ", ptr->y, g_decode_A_info.nr_dwords); | 594 | print_poly(" y: ", ptr->y, g_ec_info.nr_dwords); |
551 | } | 595 | } |
552 | 596 | ||
553 | static uint32_t g_gf_one[9] = | 597 | static uint32_t g_gf_one[9] = |
@@ -557,42 +601,42 @@ static uint32_t g_gf_one[9] = | |||
557 | 601 | ||
558 | static void ec_double(ec_point_t *point, ec_point_t *res) | 602 | static void ec_double(ec_point_t *point, ec_point_t *res) |
559 | { | 603 | { |
560 | uint32_t *v2 = malloc(g_decode_A_info.nr_dwords_x8); | 604 | uint32_t *v2 = malloc(g_ec_info.size_x2); |
561 | uint32_t *v3 = malloc(g_decode_A_info.nr_dwords_x8); | 605 | uint32_t *v3 = malloc(g_ec_info.size_x2); |
562 | uint32_t *v4 = malloc(g_decode_A_info.nr_dwords_x8); | 606 | uint32_t *v4 = malloc(g_ec_info.size_x2); |
563 | uint32_t *v5 = malloc(g_decode_A_info.nr_dwords_x8); | 607 | uint32_t *v5 = malloc(g_ec_info.size_x2); |
564 | uint32_t *v6 = malloc(g_decode_A_info.nr_dwords_x8); | 608 | uint32_t *v6 = malloc(g_ec_info.size_x2); |
565 | clear_memory(res->x, g_decode_A_info.nr_dwords); | 609 | gf_zero(res->x, g_ec_info.nr_dwords); |
566 | clear_memory(res->y, g_decode_A_info.nr_dwords); | 610 | gf_zero(res->y, g_ec_info.nr_dwords); |
567 | clear_memory(v3, g_decode_A_info.nr_dwords_x2); | 611 | gf_zero(v3, g_ec_info.nr_dwords_x2); |
568 | clear_memory(v6, g_decode_A_info.nr_dwords_x2); | 612 | gf_zero(v6, g_ec_info.nr_dwords_x2); |
569 | clear_memory(v4, g_decode_A_info.nr_dwords_x2); | 613 | gf_zero(v4, g_ec_info.nr_dwords_x2); |
570 | /* v4 := 1/x */ | 614 | /* v4 := 1/x */ |
571 | gf_inverse(v4, point->x); | 615 | gf_inverse(v4, point->x); |
572 | clear_memory(v5, g_decode_A_info.nr_dwords_x2); | 616 | gf_zero(v5, g_ec_info.nr_dwords_x2); |
573 | /* v5 := y/x */ | 617 | /* v5 := y/x */ |
574 | gf_mult(v5, v4, point->y); | 618 | gf_mult(v5, v4, point->y); |
575 | gf_mod(v5, g_decode_A_info.field_poly); | 619 | gf_mod(v5, g_ec_info.field_poly); |
576 | /* v2 := x + y/x (lambda) */ | 620 | /* v2 := x + y/x (lambda) */ |
577 | gf_add(v2, point->x, v5); | 621 | gf_add(v2, point->x, v5); |
578 | /* v4 := ec_a + lambda */ | 622 | /* v4 := ec_a + lambda */ |
579 | gf_add(v4, v2, g_decode_A_info.ec_a); | 623 | gf_add(v4, v2, g_ec_info.ec_a); |
580 | clear_memory(v3, g_decode_A_info.nr_dwords_x2); | 624 | gf_zero(v3, g_ec_info.nr_dwords_x2); |
581 | /* v3 := lambda^2 */ | 625 | /* v3 := lambda^2 */ |
582 | gf_mult(v3, v2, v2); | 626 | gf_mult(v3, v2, v2); |
583 | gf_mod(v3, g_decode_A_info.field_poly); | 627 | gf_mod(v3, g_ec_info.field_poly); |
584 | /* x' := lambda + lambda^2 + ec_a */ | 628 | /* x' := lambda + lambda^2 + ec_a */ |
585 | gf_add(res->x, v4, v3); | 629 | gf_add(res->x, v4, v3); |
586 | clear_memory(v5, g_decode_A_info.nr_dwords_x2); | 630 | gf_zero(v5, g_ec_info.nr_dwords_x2); |
587 | /* v4 := lambda + g_gf_one */ | 631 | /* v4 := lambda + g_gf_one */ |
588 | gf_add(v4, v2, g_gf_one); | 632 | gf_add(v4, v2, g_gf_one); |
589 | /* v5 := (lambda + 1) * x' = lambda.x' + x' */ | 633 | /* v5 := (lambda + 1) * x' = lambda.x' + x' */ |
590 | gf_mult(v5, v4, res->x); | 634 | gf_mult(v5, v4, res->x); |
591 | gf_mod(v5, g_decode_A_info.field_poly); | 635 | gf_mod(v5, g_ec_info.field_poly); |
592 | clear_memory(v6, g_decode_A_info.nr_dwords_x2); | 636 | gf_zero(v6, g_ec_info.nr_dwords_x2); |
593 | /* v6 := x1^2 */ | 637 | /* v6 := x1^2 */ |
594 | gf_mult(v6, point->x, point->x); | 638 | gf_mult(v6, point->x, point->x); |
595 | gf_mod(v6, g_decode_A_info.field_poly); | 639 | gf_mod(v6, g_ec_info.field_poly); |
596 | /* y' = (lambda + g_gf_one) * x + x^2 = x^2 + lambda.x + x */ | 640 | /* y' = (lambda + g_gf_one) * x + x^2 = x^2 + lambda.x + x */ |
597 | gf_add(res->y, v5, v6); | 641 | gf_add(res->y, v5, v6); |
598 | free(v2); | 642 | free(v2); |
@@ -604,31 +648,31 @@ static void ec_double(ec_point_t *point, ec_point_t *res) | |||
604 | 648 | ||
605 | static void ec_add(ec_point_t *a1, ec_point_t *a2, ec_point_t *res) | 649 | static void ec_add(ec_point_t *a1, ec_point_t *a2, ec_point_t *res) |
606 | { | 650 | { |
607 | uint32_t *v3 = malloc(g_decode_A_info.nr_dwords_x8); | 651 | uint32_t *v3 = malloc(g_ec_info.size_x2); |
608 | uint32_t *v4 = malloc(g_decode_A_info.nr_dwords_x8); | 652 | uint32_t *v4 = malloc(g_ec_info.size_x2); |
609 | uint32_t *v5 = malloc(g_decode_A_info.nr_dwords_x8); | 653 | uint32_t *v5 = malloc(g_ec_info.size_x2); |
610 | uint32_t *v6 = malloc(g_decode_A_info.nr_dwords_x8); | 654 | uint32_t *v6 = malloc(g_ec_info.size_x2); |
611 | uint32_t *v7 = malloc(g_decode_A_info.nr_dwords_x8); | 655 | uint32_t *v7 = malloc(g_ec_info.size_x2); |
612 | clear_memory(res->x, g_decode_A_info.nr_dwords); | 656 | gf_zero(res->x, g_ec_info.nr_dwords); |
613 | clear_memory(res->y, g_decode_A_info.nr_dwords); | 657 | gf_zero(res->y, g_ec_info.nr_dwords); |
614 | clear_memory(v4, g_decode_A_info.nr_dwords_x2); | 658 | gf_zero(v4, g_ec_info.nr_dwords_x2); |
615 | clear_memory(v7, g_decode_A_info.nr_dwords_x2); | 659 | gf_zero(v7, g_ec_info.nr_dwords_x2); |
616 | /* v5 = y1 + y2 */ | 660 | /* v5 = y1 + y2 */ |
617 | gf_add(v5, a1->y, a2->y); | 661 | gf_add(v5, a1->y, a2->y); |
618 | /* v6 = x1 + x2 */ | 662 | /* v6 = x1 + x2 */ |
619 | gf_add(v6, a1->x, a2->x); | 663 | gf_add(v6, a1->x, a2->x); |
620 | /* v7 = 1/(x1 + x2) */ | 664 | /* v7 = 1/(x1 + x2) */ |
621 | gf_inverse(v7, v6); | 665 | gf_inverse(v7, v6); |
622 | clear_memory(v3, g_decode_A_info.nr_dwords_x2); | 666 | gf_zero(v3, g_ec_info.nr_dwords_x2); |
623 | /* v3 = (y1 + y2) / (x1 + x2) (lambda) */ | 667 | /* v3 = (y1 + y2) / (x1 + x2) (lambda) */ |
624 | gf_mult(v3, v7, v5); | 668 | gf_mult(v3, v7, v5); |
625 | gf_mod(v3, g_decode_A_info.field_poly); | 669 | gf_mod(v3, g_ec_info.field_poly); |
626 | /* v5 = lambda + ec_a */ | 670 | /* v5 = lambda + ec_a */ |
627 | gf_add(v5, v3, g_decode_A_info.ec_a); | 671 | gf_add(v5, v3, g_ec_info.ec_a); |
628 | clear_memory(v4, g_decode_A_info.nr_dwords_x2); | 672 | gf_zero(v4, g_ec_info.nr_dwords_x2); |
629 | /* v4 = lambda^2 */ | 673 | /* v4 = lambda^2 */ |
630 | gf_mult(v4, v3, v3); | 674 | gf_mult(v4, v3, v3); |
631 | gf_mod(v4, g_decode_A_info.field_poly); | 675 | gf_mod(v4, g_ec_info.field_poly); |
632 | /* v7 = lambda^2 + lambda + ec_a */ | 676 | /* v7 = lambda^2 + lambda + ec_a */ |
633 | gf_add(v7, v5, v4); | 677 | gf_add(v7, v5, v4); |
634 | /* x' = ec_a + x1 + x2 + lambda + lambda^2 */ | 678 | /* x' = ec_a + x1 + x2 + lambda + lambda^2 */ |
@@ -637,10 +681,10 @@ static void ec_add(ec_point_t *a1, ec_point_t *a2, ec_point_t *res) | |||
637 | gf_add(v5, a1->x, res->x); | 681 | gf_add(v5, a1->x, res->x); |
638 | /* v6 = x' + y1 */ | 682 | /* v6 = x' + y1 */ |
639 | gf_add(v6, res->x, a1->y); | 683 | gf_add(v6, res->x, a1->y); |
640 | clear_memory(v7, g_decode_A_info.nr_dwords_x2); | 684 | gf_zero(v7, g_ec_info.nr_dwords_x2); |
641 | /* v7 = (x1 + x').lambda */ | 685 | /* v7 = (x1 + x').lambda */ |
642 | gf_mult(v7, v5, v3); | 686 | gf_mult(v7, v5, v3); |
643 | gf_mod(v7, g_decode_A_info.field_poly); | 687 | gf_mod(v7, g_ec_info.field_poly); |
644 | /* y' = (x1 + x').lambda + x' + y1 */ | 688 | /* y' = (x1 + x').lambda + x' + y1 */ |
645 | gf_add(res->y, v7, v6); | 689 | gf_add(res->y, v7, v6); |
646 | free(v3); | 690 | free(v3); |
@@ -654,17 +698,17 @@ static int ec_mult(uint32_t *n, ec_point_t *point, ec_point_t *res) | |||
654 | { | 698 | { |
655 | ec_point_t res_others; | 699 | ec_point_t res_others; |
656 | 700 | ||
657 | res_others.x = malloc(g_decode_A_info.size); | 701 | res_others.x = malloc(g_ec_info.size); |
658 | res_others.y = malloc(g_decode_A_info.size); | 702 | res_others.y = malloc(g_ec_info.size); |
659 | clear_memory(res->x, g_decode_A_info.nr_dwords); | 703 | gf_zero(res->x, g_ec_info.nr_dwords); |
660 | clear_memory(res->y, g_decode_A_info.nr_dwords); | 704 | gf_zero(res->y, g_ec_info.nr_dwords); |
661 | clear_memory(res_others.x, g_decode_A_info.nr_dwords); | 705 | gf_zero(res_others.x, g_ec_info.nr_dwords); |
662 | clear_memory(res_others.y, g_decode_A_info.nr_dwords); | 706 | gf_zero(res_others.y, g_ec_info.nr_dwords); |
663 | int pos = find_last_bit_set(n, 1); | 707 | int pos = find_last_bit_set(n, 1); |
664 | 708 | ||
665 | /* res_other := point */ | 709 | /* res_other := point */ |
666 | copy_memory(res_others.x, point->x); | 710 | gf_copy(res_others.x, point->x); |
667 | copy_memory(res_others.y, point->y); | 711 | gf_copy(res_others.y, point->y); |
668 | 712 | ||
669 | /* for all bit from SZ-1 downto 0 */ | 713 | /* for all bit from SZ-1 downto 0 */ |
670 | for(int bit = (pos % 32) - 1; bit >= 0; bit--) | 714 | for(int bit = (pos % 32) - 1; bit >= 0; bit--) |
@@ -672,15 +716,15 @@ static int ec_mult(uint32_t *n, ec_point_t *point, ec_point_t *res) | |||
672 | /* res := 2 * res_other */ | 716 | /* res := 2 * res_other */ |
673 | ec_double(&res_others, res); | 717 | ec_double(&res_others, res); |
674 | /* res_other := res = 2 * res_other */ | 718 | /* res_other := res = 2 * res_other */ |
675 | copy_memory(res_others.x, res->x); | 719 | gf_copy(res_others.x, res->x); |
676 | copy_memory(res_others.y, res->y); | 720 | gf_copy(res_others.y, res->y); |
677 | /* if bit of n is set */ | 721 | /* if bit of n is set */ |
678 | if(n[pos / 32] & (1 << bit)) | 722 | if(n[pos / 32] & (1 << bit)) |
679 | { | 723 | { |
680 | /* res := res_other + point */ | 724 | /* res := res_other + point */ |
681 | ec_add(&res_others, point, res); | 725 | ec_add(&res_others, point, res); |
682 | copy_memory(res_others.x, res->x); | 726 | gf_copy(res_others.x, res->x); |
683 | copy_memory(res_others.y, res->y); | 727 | gf_copy(res_others.y, res->y); |
684 | } | 728 | } |
685 | } | 729 | } |
686 | /* same but optimized */ | 730 | /* same but optimized */ |
@@ -689,18 +733,18 @@ static int ec_mult(uint32_t *n, ec_point_t *point, ec_point_t *res) | |||
689 | for(int bit = 31; bit >= 0; bit--) | 733 | for(int bit = 31; bit >= 0; bit--) |
690 | { | 734 | { |
691 | ec_double(&res_others, res); | 735 | ec_double(&res_others, res); |
692 | copy_memory(res_others.x, res->x); | 736 | gf_copy(res_others.x, res->x); |
693 | copy_memory(res_others.y, res->y); | 737 | gf_copy(res_others.y, res->y); |
694 | if(n[i] & (1 << bit)) | 738 | if(n[i] & (1 << bit)) |
695 | { | 739 | { |
696 | ec_add(&res_others, point, res); | 740 | ec_add(&res_others, point, res); |
697 | copy_memory(res_others.x, res->x); | 741 | gf_copy(res_others.x, res->x); |
698 | copy_memory(res_others.y, res->y); | 742 | gf_copy(res_others.y, res->y); |
699 | } | 743 | } |
700 | } | 744 | } |
701 | } | 745 | } |
702 | copy_memory(res->x, res_others.x); | 746 | gf_copy(res->x, res_others.x); |
703 | copy_memory(res->y, res_others.y); | 747 | gf_copy(res->y, res_others.y); |
704 | free(res_others.x); | 748 | free(res_others.x); |
705 | free(res_others.y); | 749 | free(res_others.y); |
706 | return 0; | 750 | return 0; |
@@ -709,7 +753,7 @@ static int ec_mult(uint32_t *n, ec_point_t *point, ec_point_t *res) | |||
709 | static void xor_with_point(uint8_t *buf, ec_point_t *point) | 753 | static void xor_with_point(uint8_t *buf, ec_point_t *point) |
710 | { | 754 | { |
711 | /* | 755 | /* |
712 | int sz = g_decode_A_info.nr_bytes2 - 1; | 756 | int sz = g_ec_info.nr_bytes - 1; |
713 | if(sz <= 32) | 757 | if(sz <= 32) |
714 | { | 758 | { |
715 | for(int i = 0; i < sz; i++) | 759 | for(int i = 0; i < sz; i++) |
@@ -723,39 +767,40 @@ static void xor_with_point(uint8_t *buf, ec_point_t *point) | |||
723 | */ | 767 | */ |
724 | uint8_t *ptrA = (uint8_t *)point->x; | 768 | uint8_t *ptrA = (uint8_t *)point->x; |
725 | uint8_t *ptrB = (uint8_t *)point->y; | 769 | uint8_t *ptrB = (uint8_t *)point->y; |
726 | int sz = MIN(g_decode_A_info.nr_bytes2 - 1, 32); | 770 | int sz = MIN(g_ec_info.nr_bytes - 1, 32); |
727 | for(int i = 0; i < sz; i++) | 771 | for(int i = 0; i < sz; i++) |
728 | buf[i] ^= ptrA[i]; | 772 | buf[i] ^= ptrA[i]; |
729 | for(int i = sz; i < 32; i++) | 773 | for(int i = sz; i < 32; i++) |
730 | buf[i] ^= ptrB[i - sz]; | 774 | buf[i] ^= ptrB[i - sz]; |
731 | } | 775 | } |
732 | 776 | ||
733 | static int crypto4(uint8_t *a1, ec_point_t *ptrs, uint32_t *a3) | 777 | // https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme#Formal_description_of_ECIES |
778 | static int xor_with_shared_secret(uint8_t *buf, ec_point_t *pt_rG, uint32_t *private_key) | ||
734 | { | 779 | { |
735 | ec_point_t ptrs_others; | 780 | ec_point_t shared_secret; |
736 | 781 | ||
737 | ptrs_others.x = malloc(g_decode_A_info.size); | 782 | shared_secret.x = malloc(g_ec_info.size); |
738 | ptrs_others.y = malloc(g_decode_A_info.size); | 783 | shared_secret.y = malloc(g_ec_info.size); |
739 | clear_memory(ptrs_others.x, g_decode_A_info.nr_dwords); | 784 | gf_zero(shared_secret.x, g_ec_info.nr_dwords); |
740 | clear_memory(ptrs_others.y, g_decode_A_info.nr_dwords); | 785 | gf_zero(shared_secret.y, g_ec_info.nr_dwords); |
741 | int ret = ec_mult(a3, ptrs, &ptrs_others); | 786 | int ret = ec_mult(private_key, pt_rG, &shared_secret); |
742 | if(ret == 0) | 787 | if(ret == 0) |
743 | xor_with_point(a1, &ptrs_others); | 788 | xor_with_point(buf, &shared_secret); |
744 | free(ptrs_others.x); | 789 | free(shared_secret.x); |
745 | free(ptrs_others.y); | 790 | free(shared_secret.y); |
746 | return ret; | 791 | return ret; |
747 | } | 792 | } |
748 | 793 | ||
749 | static int set_field_poly(uint32_t *field_poly, int field_sz) | 794 | static int set_field_poly(uint32_t *field_poly, int field_sz) |
750 | { | 795 | { |
751 | clear_memory(field_poly, g_decode_A_info.nr_dwords); | 796 | gf_zero(field_poly, g_ec_info.nr_dwords); |
752 | g_decode_A_info.field_bits = 0; | 797 | g_ec_info.field_bits = 0; |
753 | if(field_sz == 4) | 798 | if(field_sz == 4) |
754 | { | 799 | { |
755 | set_bit(0, field_poly); | 800 | set_bit(0, field_poly); |
756 | set_bit(74, field_poly); | 801 | set_bit(74, field_poly); |
757 | set_bit(233, field_poly); | 802 | set_bit(233, field_poly); |
758 | g_decode_A_info.field_bits = 233; | 803 | g_ec_info.field_bits = 233; |
759 | return 0; | 804 | return 0; |
760 | } | 805 | } |
761 | else if (field_sz == 5) | 806 | else if (field_sz == 5) |
@@ -765,31 +810,31 @@ static int set_field_poly(uint32_t *field_poly, int field_sz) | |||
765 | set_bit(6, field_poly); | 810 | set_bit(6, field_poly); |
766 | set_bit(7, field_poly); | 811 | set_bit(7, field_poly); |
767 | set_bit(163, field_poly); | 812 | set_bit(163, field_poly); |
768 | g_decode_A_info.field_bits = 163; | 813 | g_ec_info.field_bits = 163; |
769 | return 0; | 814 | return 0; |
770 | } | 815 | } |
771 | else | 816 | else |
772 | return 1; | 817 | return 1; |
773 | } | 818 | } |
774 | 819 | ||
775 | static int ec_init(ec_point_t *a1, char field_sz) | 820 | static int ec_init(ec_point_t *ec_G, char field_sz) |
776 | { | 821 | { |
777 | int ret = set_field_poly(g_decode_A_info.field_poly, field_sz); | 822 | int ret = set_field_poly(g_ec_info.field_poly, field_sz); |
778 | if(ret) return ret; | 823 | if(ret) return ret; |
779 | if(field_sz == 4) | 824 | if(field_sz == 4) |
780 | { | 825 | { |
781 | copy_memory(a1->x, g_crypto_table); | 826 | gf_copy(ec_G->x, g_sect233k1_G_x); |
782 | copy_memory(a1->y, g_crypto_table2); | 827 | gf_copy(ec_G->y, g_sect233k1_G_y); |
783 | copy_memory(g_decode_A_info.ec_a, g_atj_ec233_a); | 828 | gf_copy(g_ec_info.ec_a, g_sect233k1_a); // zero |
784 | copy_memory(g_decode_A_info.ptr7, g_crypto_key6); | 829 | gf_copy(g_ec_info.ec_b, g_sect233k1_b); // never used |
785 | return 0; | 830 | return 0; |
786 | } | 831 | } |
787 | else if(field_sz == 5 ) | 832 | else if(field_sz == 6 ) // yet to find even a single specimen |
788 | { | 833 | { |
789 | copy_memory(a1->x, g_crypto_key3); | 834 | gf_copy(ec_G->x, g_sect163r2_G_x); |
790 | copy_memory(a1->y, g_crypto_key4); | 835 | gf_copy(ec_G->y, g_sect163r2_G_y); |
791 | copy_memory(g_decode_A_info.ec_a, g_atj_ec163_a); | 836 | gf_copy(g_ec_info.ec_a, g_sect163r2_a); |
792 | copy_memory(g_decode_A_info.ptr7, g_crypto_key5); | 837 | gf_copy(g_ec_info.ec_b, g_sect163r2_b); |
793 | return 0; | 838 | return 0; |
794 | } | 839 | } |
795 | else | 840 | else |
@@ -805,19 +850,21 @@ static void create_guid(void *uid, int bit_size) | |||
805 | 850 | ||
806 | static int process_block_B(uint8_t block[512]) | 851 | static int process_block_B(uint8_t block[512]) |
807 | { | 852 | { |
853 | struct fwu_block_B_hdr_t *p_hdr = (void *)block; | ||
854 | |||
808 | cprintf(BLUE, "Block B\n"); | 855 | cprintf(BLUE, "Block B\n"); |
809 | decode_block_B(block + 3, g_subblock_A + 4, 489); | 856 | decode_block_B(block + 3, g_subblock_A.key_B, 492 - 3); |
810 | cprintf_field(" Word: ", "%d ", *(uint16_t *)(block + 3)); | 857 | cprintf_field(" Word: ", "%d ", p_hdr->unk_1_b); |
811 | check_field(*(uint16_t *)(block + 3), 1, "Ok\n", "Mismatch\n"); | 858 | check_field(p_hdr->unk_1_b, 1, "Ok\n", "Mismatch\n"); |
812 | 859 | ||
813 | int ret = check_block(block, block + 492, 492); | 860 | int ret = check_block(block, block + 492, 492); |
814 | cprintf(GREEN, " Check: "); | 861 | cprintf(GREEN, " Check: "); |
815 | check_field(ret, 0, "Pass\n", "Fail\n"); | 862 | check_field(ret, 0, "Pass\n", "Fail\n"); |
816 | 863 | ||
817 | g_decode_buffer3 = malloc(g_decode_A_info.size); | 864 | g_private_key = malloc(g_ec_info.size); |
818 | memset(g_decode_buffer3, 0, g_decode_A_info.size); | 865 | memset(g_private_key, 0, g_ec_info.size); |
819 | int offset = *(uint16_t *)(block + 13) + 16; | 866 | int offset = sizeof *p_hdr + p_hdr->guid_filler_size + 1; |
820 | memcpy(g_decode_buffer3, &block[offset], g_decode_A_info.nr_bytes2); | 867 | memcpy(g_private_key, &block[offset], g_ec_info.nr_bytes); |
821 | 868 | ||
822 | return 0; | 869 | return 0; |
823 | } | 870 | } |
@@ -832,22 +879,22 @@ static int get_key_fwu_v3(size_t size, uint8_t *buf, uint8_t *blockA, uint8_t *b | |||
832 | memset(smallblock, 0, sizeof(smallblock)); | 879 | memset(smallblock, 0, sizeof(smallblock)); |
833 | memset(bigblock, 0, sizeof(bigblock)); | 880 | memset(bigblock, 0, sizeof(bigblock)); |
834 | 881 | ||
835 | uint8_t ba = buf[0x1ee] & 0xf; | 882 | *blockA = buf[0x1ee] & 15; |
836 | uint8_t bb = buf[0x1fe] & 0xf; | 883 | *blockB = buf[0x1fe] & 15; |
884 | size_t offsetA = 512 * (1 + *blockA); | ||
885 | size_t offsetB = 512 * (1 + *blockB); | ||
837 | 886 | ||
838 | cprintf(BLUE, "Crypto\n"); | 887 | cprintf(BLUE, "Crypto\n"); |
839 | cprintf_field(" Block A: ", "%d\n", ba + 2); | 888 | cprintf_field(" Block A: ", "0x%zx\n", 512 + offsetA); |
840 | cprintf_field(" Block B: ", "%d\n", ba + bb + 5); | 889 | cprintf_field(" Block B: ", "0x%zx\n", 512 + offsetA + 1024 + offsetB); |
841 | 890 | ||
842 | *blockA = buf[494] & 0xf; | 891 | memcpy(bigblock, &buf[512 + offsetA], sizeof(bigblock)); |
843 | *blockB = buf[510] & 0xf; | ||
844 | memcpy(bigblock, &buf[512 * (*blockA + 2)], sizeof(bigblock)); | ||
845 | 892 | ||
846 | int ret = process_block_A(bigblock); | 893 | int ret = process_block_A(bigblock); |
847 | if(ret != 0) | 894 | if(ret != 0) |
848 | return ret; | 895 | return ret; |
849 | 896 | ||
850 | memcpy(smallblock, &buf[512 * (*blockA + *blockB + 5)], sizeof(smallblock)); | 897 | memcpy(smallblock, &buf[512 + offsetA + 1024 + offsetB], sizeof(smallblock)); |
851 | ret = process_block_B(smallblock); | 898 | ret = process_block_B(smallblock); |
852 | if(ret != 0) | 899 | if(ret != 0) |
853 | return ret; | 900 | return ret; |
@@ -859,64 +906,77 @@ static int get_key_fwu_v3(size_t size, uint8_t *buf, uint8_t *blockA, uint8_t *b | |||
859 | cprintf_field(" Byte: ", "%d ", crypto_hdr.unk); | 906 | cprintf_field(" Byte: ", "%d ", crypto_hdr.unk); |
860 | check_field(crypto_hdr.unk, 3, "Ok\n", "Mismatch\n"); | 907 | check_field(crypto_hdr.unk, 3, "Ok\n", "Mismatch\n"); |
861 | 908 | ||
862 | ec_point_t ptrs; | 909 | size_t offset = sizeof(struct fwu_hdr_t) + sizeof(struct fwu_crypto_hdr_t); |
863 | ptrs.x = malloc(g_decode_A_info.size); | 910 | ec_point_t pt_rG; |
864 | ptrs.y = malloc(g_decode_A_info.size); | 911 | pt_rG.x = malloc(g_ec_info.size); |
865 | memset(ptrs.x, 0, g_decode_A_info.size); | 912 | pt_rG.y = malloc(g_ec_info.size); |
866 | memset(ptrs.y, 0, g_decode_A_info.size); | 913 | memset(pt_rG.x, 0, g_ec_info.size); |
867 | memcpy(ptrs.x, buf + 91, g_decode_A_info.nr_bytes2); | 914 | memset(pt_rG.y, 0, g_ec_info.size); |
868 | memcpy(ptrs.y, buf + 91 + g_decode_A_info.nr_bytes2, g_decode_A_info.nr_bytes2); | 915 | memcpy(pt_rG.x, buf + offset, g_ec_info.nr_bytes); |
869 | 916 | memcpy(pt_rG.y, buf + offset + g_ec_info.nr_bytes, g_ec_info.nr_bytes); | |
870 | ret = ec_init(&g_decode_A_info.ptr1, g_crypto_info_byte); | 917 | |
871 | cprintf(GREEN, " Crypto bits copy: "); | 918 | ret = ec_init(&g_ec_info.pt_G, g_field_sz_byte); |
919 | cprintf(GREEN, " Elliptic curve init: "); | ||
872 | check_field(ret, 0, "Pass\n", "Fail\n"); | 920 | check_field(ret, 0, "Pass\n", "Fail\n"); |
873 | 921 | ||
874 | ret = crypto4(crypto_hdr.key, &ptrs, g_decode_buffer3); | 922 | ec_mult(g_private_key, &g_ec_info.pt_G, &g_ec_info.pt_kG); |
875 | cprintf(GREEN, " Crypto 4: "); | 923 | cprintf(GREEN, " Public key check: "); |
924 | if (memcmp(g_public_key.x, g_ec_info.pt_kG.x, g_ec_info.nr_bytes) || | ||
925 | memcmp(g_public_key.y, g_ec_info.pt_kG.y, g_ec_info.nr_bytes)) | ||
926 | { | ||
927 | cprintf(RED, "Fail\n"); | ||
928 | return 1; | ||
929 | } | ||
930 | else | ||
931 | cprintf(RED, "Pass\n"); | ||
932 | |||
933 | ret = xor_with_shared_secret(crypto_hdr.key, &pt_rG, g_private_key); | ||
934 | cprintf(GREEN, " ECIES decryption: "); | ||
876 | check_field(ret, 0, "Pass\n", "Fail\n"); | 935 | check_field(ret, 0, "Pass\n", "Fail\n"); |
877 | 936 | ||
878 | memcpy(keybuf, crypto_hdr.key, 32); | 937 | memcpy(keybuf, crypto_hdr.key, 32); |
879 | int offset = g_decode_A_info.nr_words + 91; | 938 | offset += g_ec_info.point_size; |
880 | 939 | ||
881 | decode_block_with_swap(keybuf, 0, &buf[offset], 512 - offset, g_perm_B); | 940 | rc4_key_swap_and_decode(keybuf, 0, &buf[offset], 512 - offset, g_rc4_S); |
882 | 941 | ||
883 | int pos = *(uint16_t *)&buf[offset]; | 942 | int pos = *(uint16_t *)&buf[offset]; |
884 | cprintf_field(" Word: ", "%d ", pos); | 943 | cprintf_field(" Filler size: ", "%d ", pos); |
885 | int tmp = g_decode_A_info.nr_words2 + 199; | 944 | int tmp = offset + sizeof(struct fwu_sector0_tail_t); |
886 | check_field(pos, 510 - tmp, "Ok\n", "Mismatch\n"); | 945 | check_field(pos, 510 - tmp, "Ok\n", "Mismatch\n"); |
887 | 946 | ||
888 | uint8_t midbuf[108]; | 947 | struct fwu_sector0_tail_t tail; |
889 | memcpy(midbuf, &buf[pos + offset + 2], sizeof(midbuf)); | 948 | memcpy(&tail, &buf[offset + 2 + pos], sizeof(tail)); |
890 | 949 | ||
891 | cprintf_field(" Byte: ", "%d ", midbuf[0]); | 950 | cprintf_field(" Byte: ", "%d ", tail.unk_2); |
892 | check_field(midbuf[0], 2, "Ok\n", "Invalid\n"); | 951 | check_field(tail.unk_2, 2, "Ok\n", "Invalid\n"); |
893 | cprintf_field(" DWord: ", "%d ", *(uint32_t *)&midbuf[1]); | 952 | cprintf_field(" DWord: ", "0x%x ", tail.unk_x808); |
894 | check_field(*(uint32_t *)&midbuf[1], 2056, "Ok\n", "Invalid\n"); | 953 | check_field(tail.unk_x808, 0x808, "Ok\n", "Invalid\n"); |
895 | cprintf_field(" DWord: ", "%d ", *(uint32_t *)&midbuf[5]); | 954 | cprintf_field(" DWord: ", "%d ", tail.unk_8); |
896 | check_field(*(uint32_t *)&midbuf[5], 8, "Ok\n", "Invalid\n"); | 955 | check_field(tail.unk_8, 8, "Ok\n", "Invalid\n"); |
897 | cprintf_field(" Byte: ", "%d ", midbuf[41]); | 956 | cprintf_field(" Byte: ", "%d ", tail.unk_190); |
898 | check_field(midbuf[41], 190, "Ok\n", "Invalid\n"); | 957 | check_field(tail.unk_190, 190, "Ok\n", "Invalid\n"); |
899 | 958 | ||
959 | /* encode super secret at random position in guid stream, never used */ | ||
900 | memset(blo, 0, 512); | 960 | memset(blo, 0, 512); |
901 | create_guid(smallblock, 3808); | 961 | create_guid(smallblock, 476 * 8); |
902 | memcpy(smallblock + 476, midbuf + 42, 16); | 962 | memcpy(smallblock + 476, tail.super_secret_xor, 16); |
903 | compute_checksum(smallblock, 492, blo + 492); | 963 | compute_checksum(smallblock, 492, blo + 492); |
904 | int bsz = blo[500]; | 964 | int bsz = blo[500]; |
905 | memcpy(blo, smallblock, bsz); | 965 | memcpy(blo, smallblock, bsz); |
906 | memcpy(blo + bsz, midbuf + 42, 16); | 966 | memcpy(blo + bsz, tail.super_secret_xor, 16); |
907 | memcpy(blo + bsz + 16, smallblock + bsz, 476 - bsz); | 967 | memcpy(blo + bsz + 16, smallblock + bsz, 476 - bsz); |
968 | rc4_cipher_block(blo + 492, 16, blo, 492, g_rc4_S); | ||
908 | 969 | ||
909 | decode_block_with_perm(blo + 492, 16, blo, 492, g_perm_B); | 970 | ret = check_block(buf + sizeof(struct fwu_hdr_t), tail.check, 492 - sizeof(struct fwu_hdr_t)); |
910 | ret = check_block(buf + 42, midbuf + 88, 450); | 971 | cprintf(GREEN, " Check: "); |
911 | cprintf(GREEN, " Decode block: "); | ||
912 | check_field(ret, 0, "Pass\n", "Fail\n"); | 972 | check_field(ret, 0, "Pass\n", "Fail\n"); |
913 | 973 | ||
914 | ret = memcmp(g_subblock_A + 4, midbuf + 9, 16); | 974 | ret = memcmp(g_subblock_A.key_B, tail.key_B, 16); |
915 | cprintf(GREEN, " Compare: "); | 975 | cprintf(GREEN, " Compare: "); |
916 | check_field(ret, 0, "Pass\n", "Fail\n"); | 976 | check_field(ret, 0, "Pass\n", "Fail\n"); |
917 | 977 | ||
918 | /* | 978 | /* |
919 | ret = memcmp(midbuf + 25, zero, sizeof(zero)); | 979 | ret = memcmp(tail.guid, zero, sizeof(zero)); |
920 | cprintf(GREEN, " Sanity: "); | 980 | cprintf(GREEN, " Sanity: "); |
921 | check_field(ret, 0, "Pass\n", "Fail\n"); | 981 | check_field(ret, 0, "Pass\n", "Fail\n"); |
922 | */ | 982 | */ |
@@ -1000,15 +1060,15 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f | |||
1000 | /* the input buffer is reorganized based on two offsets (blockA and blockB), | 1060 | /* the input buffer is reorganized based on two offsets (blockA and blockB), |
1001 | * skip 2048 bytes of data used for crypto init */ | 1061 | * skip 2048 bytes of data used for crypto init */ |
1002 | *size = hdr->fw_size; /* use firmware size, not file size */ | 1062 | *size = hdr->fw_size; /* use firmware size, not file size */ |
1003 | *size -= 2048; | 1063 | *size -= 512 + 1024 + 512; /* sector0 + blockA + blockB */ |
1004 | uint8_t *tmpbuf = malloc(*size); | 1064 | uint8_t *tmpbuf = malloc(*size); |
1005 | memset(tmpbuf, 0, *size); | 1065 | memset(tmpbuf, 0, *size); |
1006 | int offsetA = (blockA + 1) << 9; | 1066 | int offsetA = 512 * (1 + blockA); |
1007 | int offsetB = (blockB + 1) << 9; | 1067 | int offsetB = 512 * (1 + blockB); |
1008 | memcpy(tmpbuf, buf + 512, offsetA); | 1068 | memcpy(tmpbuf, buf + 512, offsetA); |
1009 | memcpy(tmpbuf + offsetA, buf + offsetA + 1536, offsetB); | 1069 | memcpy(tmpbuf + offsetA, buf + 512 + offsetA + 1024, offsetB); |
1010 | memcpy(tmpbuf + offsetA + offsetB, | 1070 | memcpy(tmpbuf + offsetA + offsetB, |
1011 | buf + offsetA + 1536 + offsetB + 512, *size - offsetA - offsetB); | 1071 | buf + 512 + offsetA + 1024 + offsetB + 512, *size - offsetA - offsetB); |
1012 | /* stolen from https://github.com/nfd/atj2127decrypt, I have no idea from where | 1072 | /* stolen from https://github.com/nfd/atj2127decrypt, I have no idea from where |
1013 | * he got this sequence of code. This code is really weird, I copy verbatim | 1073 | * he got this sequence of code. This code is really weird, I copy verbatim |
1014 | * his authors comment below. | 1074 | * his authors comment below. |
@@ -1048,8 +1108,8 @@ static int decrypt_fwu_v3(uint8_t *buf, size_t *size, uint8_t block[512], enum f | |||
1048 | atj2127_decrypt(buf, tmpbuf, *size, keybuf, rounds_to_perform); | 1108 | atj2127_decrypt(buf, tmpbuf, *size, keybuf, rounds_to_perform); |
1049 | else | 1109 | else |
1050 | { | 1110 | { |
1051 | compute_perm(keybuf, 32, g_perm_B); | 1111 | rc4_key_schedule(keybuf, 32, g_rc4_S); |
1052 | decode_perm(tmpbuf, *size, g_perm_B); | 1112 | rc4_stream_cipher(tmpbuf, *size, g_rc4_S); |
1053 | memcpy(buf, tmpbuf, *size); | 1113 | memcpy(buf, tmpbuf, *size); |
1054 | } | 1114 | } |
1055 | 1115 | ||
@@ -1102,7 +1162,7 @@ int fwu_decrypt(uint8_t *buf, size_t *size, enum fwu_mode_t mode) | |||
1102 | cprintf_field(" Block size: ", "%d ", hdr->block_size); | 1162 | cprintf_field(" Block size: ", "%d ", hdr->block_size); |
1103 | check_field(hdr->block_size, FWU_BLOCK_SIZE, "Ok\n", "Invalid\n"); | 1163 | check_field(hdr->block_size, FWU_BLOCK_SIZE, "Ok\n", "Invalid\n"); |
1104 | 1164 | ||
1105 | cprintf_field(" Version: ", "%x ", hdr->version); | 1165 | cprintf_field(" Version: ", "0x%x ", hdr->version); |
1106 | int ver = get_version(buf, *size); | 1166 | int ver = get_version(buf, *size); |
1107 | if(ver < 0) | 1167 | if(ver < 0) |
1108 | { | 1168 | { |