A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

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

authored by

Nikita Burnashev and committed by
Solomon Peachy
e232f692 72c0e49b

+499 -317
+1 -1
utils/atj2137/atjboottool/Makefile
··· 2 2 CC=gcc 3 3 LD=gcc 4 4 CFLAGS=-g -std=c99 -W -Wall $(DEFINES) 5 - LDFLAGS= 5 + LDFLAGS=-lz 6 6 BINS=atjboottool 7 7 8 8 all: $(BINS)
+9 -9
utils/atj2137/atjboottool/atj_tables.c
··· 20 20 ****************************************************************************/ 21 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 25 0x16, 0x2b, 0x01, 0xe4, 0x0e, 0x3d, 0xc1, 0xdf, 0x0f, 0x35, 0x8f, 0xf5, 0xe2, 26 26 0x48, 0xa0, 0x2e, 0x1c, 0x6a, 0x57, 0xea, 0x6d, 0x9a, 0xe2, 0x03, 0xec, 0xe8, ··· 109 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 114 0xefad6126, 0x0a4c9d6e, 0x19c26bf5, 0x149563a4, 0x29f22ff4, 0x7e731af1, 115 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 120 0x56fae6a3, 0x56e0c110, 0xf18aeb9b, 0x27a8cd9b, 0x555a67c4, 0x19b7f70f, 121 121 0x537dece8, 0x000001db 122 122 }; 123 123 124 - uint32_t g_crypto_key6[8] = 124 + uint32_t g_sect233k1_b[8] = 125 125 { 126 126 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 127 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 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 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 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 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 152 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 153 153 };
+10 -10
utils/atj2137/atjboottool/atj_tables.h
··· 21 21 #ifndef __ATJ_TABLES__ 22 22 #define __ATJ_TABLES__ 23 23 24 - uint8_t g_check_block_A_table[1024]; 25 - uint8_t g_decode_B_table[20]; 26 - uint32_t g_crypto_table[8]; 27 - uint32_t g_crypto_table2[8]; 28 - uint32_t g_crypto_key6[8]; 29 - uint32_t g_crypto_key3[6]; 30 - uint32_t g_crypto_key4[6]; 31 - uint32_t g_crypto_key5[6]; 32 - uint32_t g_atj_ec233_a[8]; 33 - uint32_t g_atj_ec163_a[6]; 24 + extern uint8_t g_decode_A_table[1024]; 25 + extern uint8_t g_decode_B_table[20]; 26 + extern uint32_t g_sect233k1_G_x[8]; 27 + extern uint32_t g_sect233k1_G_y[8]; 28 + extern uint32_t g_sect233k1_b[8]; 29 + extern uint32_t g_sect163r2_G_x[6]; 30 + extern uint32_t g_sect163r2_G_y[6]; 31 + extern uint32_t g_sect163r2_a[6]; 32 + extern uint32_t g_sect163r2_b[6]; 33 + extern uint32_t g_sect233k1_a[8]; 34 34 35 35 #endif // __ATJ_TABLES__
+32 -5
utils/atj2137/atjboottool/atjboottool.c
··· 27 27 #include <stdarg.h> 28 28 #include <ctype.h> 29 29 #include <sys/stat.h> 30 + #include <zlib.h> 30 31 #include "misc.h" 31 32 #include "fwu.h" 32 33 #include "afi.h" ··· 100 101 FILE *f = fopen(name, "wb"); 101 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 124 fclose(f); 105 125 cprintf(RED, "Ok\n"); 106 126 return 0; ··· 119 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 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 147 static void usage(void) 128 148 { ··· 135 155 printf(" --fwu Unpack a FWU firmware file\n"); 136 156 printf(" --afi Unpack a AFI archive file\n"); 137 157 printf(" --fw Unpack a FW archive file\n"); 158 + printf(" --fw251 Big-endian FW archive used on Flip80251\n"); 138 159 printf(" --atj2127 Force ATJ2127 decryption mode\n"); 139 160 printf("The default is to try to guess the format.\n"); 140 161 printf("If several formats are specified, all are tried.\n"); ··· 147 168 bool try_fwu = false; 148 169 bool try_afi = false; 149 170 bool try_fw = false; 171 + bool big_endian = false; 150 172 enum fwu_mode_t fwu_mode = FWU_AUTO; 151 173 152 174 while(1) ··· 159 181 {"fwu", no_argument, 0, 'u'}, 160 182 {"afi", no_argument, 0, 'a'}, 161 183 {"fw", no_argument, 0, 'w'}, 184 + {"fw251", no_argument, 0, 'b'}, 162 185 {"atj2127", no_argument, 0, '2'}, 163 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 190 if(c == -1) 168 191 break; 169 192 switch(c) ··· 191 214 break; 192 215 case 'w': 193 216 try_fw = true; 217 + break; 218 + case 'b': 219 + try_fw = true; 220 + big_endian = true; 194 221 break; 195 222 case '2': 196 223 fwu_mode = FWU_ATJ2127; ··· 238 265 else if(try_afi || afi_check(buf, size)) 239 266 ret = do_afi(buf, size); 240 267 else if(try_fw || fw_check(buf, size)) 241 - ret = do_fw(buf, size); 268 + ret = do_fw(buf, size, big_endian); 242 269 else 243 270 { 244 271 cprintf(GREY, "No valid format found\n");
+105 -10
utils/atj2137/atjboottool/fw.c
··· 38 38 uint16_t version; 39 39 uint32_t block_offset; // offset shift by 9 40 40 uint32_t size; 41 - uint32_t unk; 41 + uint32_t bytes; 42 42 uint32_t checksum; 43 43 } __attribute__((packed)); 44 44 ··· 78 78 uint8_t sig[FW_SIG_SIZE]; 79 79 uint8_t res[12]; 80 80 uint32_t checksum; 81 - uint8_t res2[492]; 81 + uint8_t res2[490]; 82 + uint16_t header_checksum; 82 83 83 84 struct fw_entry_t entry[FW_ENTRIES]; 84 85 } __attribute__((packed)); ··· 97 98 { 98 99 int pos = 0; 99 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 102 buf[pos++] = '.'; 102 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 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 152 struct fw_hdr_t *hdr = (void *)buf; 110 153 ··· 165 208 } 166 209 else 167 210 { 168 - /* struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; */ 169 - cprintf(GREEN, " Header not dumped because format is unclear.\n"); 211 + struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; 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 239 cprintf(BLUE, "Entries\n"); ··· 175 242 if(hdr->entry[i].name[0] == 0) 176 243 continue; 177 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 252 char filename[16]; 179 253 build_filename_fw(filename, entry); 180 254 cprintf(RED, " %s\n", filename); 181 255 cprintf_field(" Attr: ", "%02x\n", entry->attr); 182 256 cprintf_field(" Offset: ", "0x%x\n", entry->block_offset << 9); 183 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 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 268 if(chk != entry->checksum) 188 269 { 189 270 cprintf(RED, "Mismatch\n"); ··· 191 272 } 192 273 else 193 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 276 if(ret != 0) 196 277 return ret; 278 + } 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"); 197 292 } 198 293 199 294 return 0;
+1 -1
utils/atj2137/atjboottool/fw.h
··· 27 27 * its name and content. If the callback returns a nonzero value, the function will stop and return 28 28 * that value. Returns 0 on success */ 29 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 31 /* Check if a file looks like an AFI file */ 32 32 bool fw_check(uint8_t *buf, size_t size); 33 33
+341 -281
utils/atj2137/atjboottool/fwu.c
··· 59 59 uint8_t key[32]; 60 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 102 struct fwu_tail_t 63 103 { 64 104 uint8_t length; /* in blocks? it's always 1 */ ··· 95 135 uint32_t *y; 96 136 }ec_point_t; 97 137 98 - struct block_A_info_t 138 + struct ec_info_t 99 139 { 100 140 int nr_bits; 101 - uint16_t field_2; 102 - int nr_words; 103 - int nr_dwords_x12; 141 + int point_size; 104 142 uint32_t *ec_a; // size 105 - uint32_t *ptr7; // size 143 + uint32_t *ec_b; // size 106 144 uint32_t *field_poly; // size 107 145 uint32_t size; 108 - uint32_t field_1C; 109 - ec_point_t ptr1; 110 - uint32_t *ptr3; // size 111 - uint32_t *ptr4; // size 112 - int nr_words2; 146 + ec_point_t pt_G; 147 + ec_point_t pt_kG; // calculated ECIES public key 113 148 uint32_t field_bits; 114 - int nr_dwords_x8; 149 + int size_x2; 115 150 int nr_bytes; 116 - int nr_bytes2; 117 151 int nr_dwords_m1; 152 + int nr_dwords_x2; 118 153 int nr_dwords_x2_m1; 119 - int nr_dwords_x2; 120 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; 126 - uint8_t g_subblock_A[0x128]; 157 + struct ec_info_t g_ec_info; 158 + struct fwu_block_A_hdr_t g_subblock_A; 127 159 uint8_t g_key_B[20]; 128 - uint8_t g_perm_B[258]; 129 - uint8_t g_crypto_info_byte; 130 - uint8_t *g_decode_buffer; 131 - uint8_t *g_decode_buffer2; 132 - void *g_decode_buffer3; 160 + uint8_t g_rc4_S[258]; 161 + uint8_t g_field_sz_byte; 162 + ec_point_t g_public_key; // from block A 163 + uint32_t *g_private_key; // from block B 133 164 134 165 #include "atj_tables.h" 135 166 #include <ctype.h> ··· 186 217 187 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 221 uint8_t key[32]; 191 222 192 223 for(int i = 0; i < 20; i++) ··· 197 228 for(int i = 20; i < 32; i++) 198 229 key[i] = key[i - 20]; 199 230 200 - for(int i = 0; i < 992; i++) 201 - block[i] ^= key[i % 32] ^ g_check_block_A_table[i]; 231 + for(int i = 0; i < 31 * 32; 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 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 241 for(int i = 0; i < 256; i++) 209 - perm[i] = i; 210 - perm[256] = perm[257] = 0; 211 - uint8_t idx = 0; 242 + S[i] = i; 243 + S[256] = S[257] = 0; 244 + uint8_t j = 0; 212 245 for(int i = 0; i < 256; i++) 213 246 { 214 - uint8_t v = perm[i]; 215 - idx = (v + keybuf[i % size] + idx) % 256; 216 - perm[i] = perm[idx]; 217 - perm[idx] = v; 247 + j = (j + S[i] + key[i % keylength]) % 256; 248 + uint8_t tmp = S[i]; 249 + S[i] = S[j]; 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]; 224 - uint8_t idxb = perm[257]; 225 - for(size_t i = 0; i < size; i++) 257 + uint8_t i = S[256]; 258 + uint8_t j = S[257]; 259 + for(size_t k = 0; k < size; k++) 226 260 { 227 - idxa = (idxa + 1) % 256; 228 - uint8_t v = perm[idxa]; 229 - idxb = (idxb + v) % 256; 230 - perm[idxa] = perm[idxb]; 231 - perm[idxb] = v; 232 - buf[i] ^= perm[(v + perm[idxa]) % 256]; 261 + i = (i + 1) % 256; 262 + j = (j + S[i]) % 256; 263 + uint8_t tmp = S[i]; 264 + S[i] = S[j]; 265 + S[j] = tmp; 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, 237 - uint8_t *buf, int bufsize, uint8_t perm[258]) 270 + static void rc4_cipher_block(uint8_t *keybuf, int keysize, 271 + uint8_t *buf, int bufsize, uint8_t S[258]) 238 272 { 239 - compute_perm(keybuf, keysize, perm); 240 - decode_perm(buf, bufsize, perm); 273 + rc4_key_schedule(keybuf, keysize, S); 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 279 memcpy(outbuf, inbuf, size); 246 280 int a = swap & 0xf; ··· 250 284 outbuf[b] = v; 251 285 } 252 286 253 - static void decode_block_with_swap(uint8_t keybuf[32], int swap, 254 - uint8_t *buf, int bufsize, uint8_t perm[258]) 287 + static void rc4_key_swap_and_decode(uint8_t keybuf[32], int swap, 288 + uint8_t *buf, int bufsize, uint8_t S[258]) 255 289 { 256 290 uint8_t keybuf_interm[32]; 257 291 258 - apply_perm(keybuf, keybuf_interm, 32, swap); 259 - decode_block_with_perm(keybuf_interm, 32, buf, bufsize, perm); 292 + rc4_key_swap(keybuf, keybuf_interm, 32, swap); 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 298 memset(buf, 0, 4 * size_dwords); 265 299 } ··· 269 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 308 if(sz == 2) sz = 233; 275 309 else if(sz == 3) sz = 163; 276 310 else return 1; 277 311 278 - g_decode_A_info.nr_bits = sz; 279 - g_decode_A_info.nr_bytes2 = sz / 8 + (sz % 8 != 0); 280 - g_decode_A_info.nr_words = 2 * g_decode_A_info.nr_bytes2; 281 - g_decode_A_info.nr_bytes = sz / 8 + (sz % 8 != 0); 282 - g_decode_A_info.nr_words2 = 2 * g_decode_A_info.nr_bytes2; 283 - g_decode_A_info.nr_dwords = sz / 32 + (sz % 32 != 0); 284 - g_decode_A_info.size = 4 * g_decode_A_info.nr_dwords; 285 - g_decode_A_info.nr_dwords_x8 = 8 * g_decode_A_info.nr_dwords; 286 - g_decode_A_info.nr_dwords_m1 = g_decode_A_info.nr_dwords - 1; 287 - g_decode_A_info.nr_dwords_x2 = 2 * g_decode_A_info.nr_dwords; 288 - g_decode_A_info.nr_dwords_x2_m1 = g_decode_A_info.nr_dwords_x2 - 1; 289 - g_decode_A_info.nr_dwords_x12 = 12 * g_decode_A_info.nr_dwords; 290 - g_decode_A_info.ptr1.x = malloc(4 * g_decode_A_info.nr_dwords); 291 - g_decode_A_info.ptr1.y = malloc(g_decode_A_info.size); 292 - g_decode_A_info.ptr3 = malloc(g_decode_A_info.size); 293 - g_decode_A_info.ptr4 = malloc(g_decode_A_info.size); 294 - g_decode_A_info.field_poly = malloc(g_decode_A_info.size); 295 - g_decode_A_info.ec_a = malloc(g_decode_A_info.size); 296 - g_decode_A_info.ptr7 = malloc(g_decode_A_info.size); 312 + g_ec_info.nr_bits = sz; 313 + g_ec_info.nr_bytes = sz / 8 + (sz % 8 != 0); 314 + g_ec_info.point_size = 2 * g_ec_info.nr_bytes; 315 + g_ec_info.nr_dwords = sz / 32 + (sz % 32 != 0); 316 + g_ec_info.size = 4 * g_ec_info.nr_dwords; 317 + g_ec_info.size_x2 = 8 * g_ec_info.nr_dwords; 318 + g_ec_info.nr_dwords_m1 = g_ec_info.nr_dwords - 1; 319 + g_ec_info.nr_dwords_x2 = 2 * g_ec_info.nr_dwords; 320 + g_ec_info.nr_dwords_x2_m1 = g_ec_info.nr_dwords_x2 - 1; 321 + g_ec_info.pt_G.x = malloc(4 * g_ec_info.nr_dwords); 322 + g_ec_info.pt_G.y = malloc(g_ec_info.size); 323 + g_ec_info.pt_kG.x = malloc(g_ec_info.size); 324 + g_ec_info.pt_kG.y = malloc(g_ec_info.size); 325 + g_ec_info.field_poly = malloc(g_ec_info.size); 326 + g_ec_info.ec_a = malloc(g_ec_info.size); 327 + g_ec_info.ec_b = malloc(g_ec_info.size); 297 328 298 - cprintf(BLUE, " Decode Info:\n"); 299 - cprintf_field(" Nr Bits: ", "%d\n", g_decode_A_info.nr_bits); 300 - cprintf_field(" Nr Bytes: ", "%d\n", g_decode_A_info.nr_bytes); 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); 329 + cprintf(BLUE, " Elliptic curve info:\n"); 330 + cprintf_field(" Field Bits: ", "%d\n", g_ec_info.nr_bits); 331 + cprintf_field(" Field Bytes: ", "%d\n", g_ec_info.nr_bytes); 332 + cprintf_field(" Point Size: ", "%d\n", g_ec_info.point_size); 333 + cprintf_field(" Field DWords: ", "%d\n", g_ec_info.nr_dwords); 334 + cprintf_field(" Size: ", "%d\n", g_ec_info.size); 306 335 307 336 return 0; 308 337 } ··· 313 342 int ret = decode_block_A(block + 4); 314 343 cprintf(GREEN, " Check: "); 315 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)); 319 - ret = fill_decode_info(g_subblock_A[276]); 347 + memcpy(&g_subblock_A, block, sizeof(g_subblock_A)); 348 + // assert(offsetof(struct fwu_block_A_hdr_t, ec_sz) == 276); 349 + ret = fill_ec_info(g_subblock_A.ec_sz); 320 350 cprintf(GREEN, " Info: "); 321 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 354 int offset = 1004 - tmp + 5; 325 - g_crypto_info_byte = block[offset - 1]; 326 - g_decode_buffer = malloc(g_decode_A_info.size); 327 - g_decode_buffer2 = malloc(g_decode_A_info.size); 355 + g_field_sz_byte = block[offset - 1]; 356 + g_public_key.x = malloc(g_ec_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); 330 - memset(g_decode_buffer2, 0, g_decode_A_info.size); 359 + memset(g_public_key.x, 0, g_ec_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); 333 - int offset2 = g_decode_A_info.nr_bytes2 + offset; 334 - memcpy(g_decode_buffer2, &block[offset2], g_decode_A_info.nr_bytes2); 362 + memcpy(g_public_key.x, &block[offset], g_ec_info.nr_bytes); 363 + int offset2 = g_ec_info.nr_bytes + offset; 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]); 338 - check_field(*(uint16_t *)&g_subblock_A[286], 1, "Ok\n", "Mismatch\n"); 367 + // assert(offsetof(struct fwu_block_A_hdr_t, unk_1_b) == 286); 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 371 return 0; 341 372 } ··· 353 384 static void decode_block_B(uint8_t *buf, uint8_t key[16], size_t size) 354 385 { 355 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 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 394 while(i >= 0 && buf[i] == 0) 364 395 i--; ··· 370 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 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 414 uint32_t c = a[i]; 384 415 a[i] = b[i]; ··· 388 419 389 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 423 buf[i + (nr_bits / 32)] = buf[i]; 393 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 427 nr_bits = nr_bits % 32; 397 428 398 429 uint32_t acc = 0; ··· 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 444 res[i] = a[i] ^ b[i]; 414 445 } 415 446 ··· 433 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); 439 - uint32_t *copy = malloc(g_decode_A_info.nr_dwords_x8); 440 - uint32_t *copy_arg = malloc(g_decode_A_info.nr_dwords_x8); 441 - uint32_t *tmp2 = malloc(g_decode_A_info.nr_dwords_x8); 442 - clear_memory(tmp, g_decode_A_info.nr_dwords_x2); 443 - clear_memory(res, g_decode_A_info.nr_dwords); 444 - *res = 1; 445 - clear_memory(tmp2, g_decode_A_info.nr_dwords); 446 - copy_memory(copy_arg, val); 447 - copy_memory(copy, (uint32_t *)g_decode_A_info.field_poly); 472 + uint32_t *tmp = malloc(g_ec_info.size_x2); 473 + uint32_t *r = malloc(g_ec_info.size_x2); 474 + uint32_t *newr = malloc(g_ec_info.size_x2); 475 + uint32_t *t = malloc(g_ec_info.size_x2); 476 + gf_zero(tmp, g_ec_info.nr_dwords_x2); 477 + /* newt := 1 */ 478 + gf_zero(newt, g_ec_info.nr_dwords); 479 + *newt = 1; 480 + /* t := 0 */ 481 + gf_zero(t, g_ec_info.nr_dwords); 482 + /* newr := a */ 483 + gf_copy(newr, val); 484 + /* r := p */ 485 + gf_copy(r, g_ec_info.field_poly); 448 486 449 - for(int i = find_last_bit_set(copy_arg, 1); i; i = find_last_bit_set(copy_arg, 1)) 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 491 if(pos < 0) 453 492 { 454 - swap_memory(copy_arg, copy); 455 - swap_memory(res, tmp2); 493 + gf_swap(newr, r); 494 + gf_swap(newt, t); 456 495 pos = -pos; 457 496 } 458 - copy_memory(tmp, copy); 497 + /* newr := newr - x^pos * r */ 498 + gf_copy(tmp, r); 459 499 shift_left(tmp, pos); 460 - xor_big(copy_arg, copy_arg, tmp); 461 - copy_memory(tmp, tmp2); 500 + gf_add_x2(newr, newr, tmp); 501 + /* newt := newt - x^pos * t */ 502 + gf_copy(tmp, t); 462 503 shift_left(tmp, pos); 463 - xor_big(res, res, tmp); 504 + gf_add_x2(newt, newt, tmp); 464 505 } 465 506 free(tmp); 466 - free(copy); 467 - free(copy_arg); 468 - free(tmp2); 507 + free(r); 508 + free(newr); 509 + free(t); 469 510 } 470 511 471 512 static void shift_left_one(uint32_t *a) ··· 488 529 #if 1 489 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); 492 - clear_memory(tmp2, g_decode_A_info.nr_dwords_x2); 493 - copy_memory(tmp2, a3); 532 + uint32_t *tmp2 = malloc(g_ec_info.size_x2); 533 + gf_zero(tmp2, g_ec_info.nr_dwords_x2); 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 537 uint32_t mask = 1; 497 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 542 if(a2[j] & mask) 502 543 for(int k = 0; k < pos; k++) ··· 511 552 #else 512 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++) 515 - for(int j = 0; j < 32 * g_decode_A_info.nr_dwords; j++) 555 + for(int i = 0; i < 32 * g_ec_info.nr_dwords; i++) 556 + for(int j = 0; j < 32 * g_ec_info.nr_dwords; j++) 516 557 { 517 558 int k = i + j; 518 559 uint32_t v1 = (a2[i / 32] >> (i % 32)) & 1; ··· 522 563 } 523 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); 528 - int v4 = g_decode_A_info.field_bits; 529 - int pos = find_last_bit_set(inout, 0); 530 - for(int i = pos - v4; i >= 0; i = find_last_bit_set(inout, 0) - v4) 569 + uint32_t *tmp = malloc(g_ec_info.size_x2); 570 + int deg_d = g_ec_info.field_bits; 571 + int deg_r = find_last_bit_set(r, 0); 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); 533 - copy_memory(tmp, other); 575 + /* r := r - x^i * d */ 576 + gf_zero(tmp, g_ec_info.nr_dwords_x2); 577 + gf_copy(tmp, field_poly); 534 578 shift_left(tmp, i); 535 - xor_big(inout, inout, tmp); 579 + gf_add_x2(r, r, tmp); 536 580 } 537 581 free(tmp); 538 582 } 539 583 540 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 587 res[i] = a[i] ^ b[i]; 544 588 } 545 589 546 590 static void print_point(const char *name, ec_point_t *ptr) 547 591 { 548 592 cprintf(BLUE, "%s\n", name); 549 - print_poly(" x: ", ptr->x, g_decode_A_info.nr_dwords); 550 - print_poly(" y: ", ptr->y, g_decode_A_info.nr_dwords); 593 + print_poly(" x: ", ptr->x, g_ec_info.nr_dwords); 594 + print_poly(" y: ", ptr->y, g_ec_info.nr_dwords); 551 595 } 552 596 553 597 static uint32_t g_gf_one[9] = ··· 557 601 558 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); 561 - uint32_t *v3 = malloc(g_decode_A_info.nr_dwords_x8); 562 - uint32_t *v4 = malloc(g_decode_A_info.nr_dwords_x8); 563 - uint32_t *v5 = malloc(g_decode_A_info.nr_dwords_x8); 564 - uint32_t *v6 = malloc(g_decode_A_info.nr_dwords_x8); 565 - clear_memory(res->x, g_decode_A_info.nr_dwords); 566 - clear_memory(res->y, g_decode_A_info.nr_dwords); 567 - clear_memory(v3, g_decode_A_info.nr_dwords_x2); 568 - clear_memory(v6, g_decode_A_info.nr_dwords_x2); 569 - clear_memory(v4, g_decode_A_info.nr_dwords_x2); 604 + uint32_t *v2 = malloc(g_ec_info.size_x2); 605 + uint32_t *v3 = malloc(g_ec_info.size_x2); 606 + uint32_t *v4 = malloc(g_ec_info.size_x2); 607 + uint32_t *v5 = malloc(g_ec_info.size_x2); 608 + uint32_t *v6 = malloc(g_ec_info.size_x2); 609 + gf_zero(res->x, g_ec_info.nr_dwords); 610 + gf_zero(res->y, g_ec_info.nr_dwords); 611 + gf_zero(v3, g_ec_info.nr_dwords_x2); 612 + gf_zero(v6, g_ec_info.nr_dwords_x2); 613 + gf_zero(v4, g_ec_info.nr_dwords_x2); 570 614 /* v4 := 1/x */ 571 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 617 /* v5 := y/x */ 574 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 620 /* v2 := x + y/x (lambda) */ 577 621 gf_add(v2, point->x, v5); 578 622 /* v4 := ec_a + lambda */ 579 - gf_add(v4, v2, g_decode_A_info.ec_a); 580 - clear_memory(v3, g_decode_A_info.nr_dwords_x2); 623 + gf_add(v4, v2, g_ec_info.ec_a); 624 + gf_zero(v3, g_ec_info.nr_dwords_x2); 581 625 /* v3 := lambda^2 */ 582 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 628 /* x' := lambda + lambda^2 + ec_a */ 585 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 631 /* v4 := lambda + g_gf_one */ 588 632 gf_add(v4, v2, g_gf_one); 589 633 /* v5 := (lambda + 1) * x' = lambda.x' + x' */ 590 634 gf_mult(v5, v4, res->x); 591 - gf_mod(v5, g_decode_A_info.field_poly); 592 - clear_memory(v6, g_decode_A_info.nr_dwords_x2); 635 + gf_mod(v5, g_ec_info.field_poly); 636 + gf_zero(v6, g_ec_info.nr_dwords_x2); 593 637 /* v6 := x1^2 */ 594 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 640 /* y' = (lambda + g_gf_one) * x + x^2 = x^2 + lambda.x + x */ 597 641 gf_add(res->y, v5, v6); 598 642 free(v2); ··· 604 648 605 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); 608 - uint32_t *v4 = malloc(g_decode_A_info.nr_dwords_x8); 609 - uint32_t *v5 = malloc(g_decode_A_info.nr_dwords_x8); 610 - uint32_t *v6 = malloc(g_decode_A_info.nr_dwords_x8); 611 - uint32_t *v7 = malloc(g_decode_A_info.nr_dwords_x8); 612 - clear_memory(res->x, g_decode_A_info.nr_dwords); 613 - clear_memory(res->y, g_decode_A_info.nr_dwords); 614 - clear_memory(v4, g_decode_A_info.nr_dwords_x2); 615 - clear_memory(v7, g_decode_A_info.nr_dwords_x2); 651 + uint32_t *v3 = malloc(g_ec_info.size_x2); 652 + uint32_t *v4 = malloc(g_ec_info.size_x2); 653 + uint32_t *v5 = malloc(g_ec_info.size_x2); 654 + uint32_t *v6 = malloc(g_ec_info.size_x2); 655 + uint32_t *v7 = malloc(g_ec_info.size_x2); 656 + gf_zero(res->x, g_ec_info.nr_dwords); 657 + gf_zero(res->y, g_ec_info.nr_dwords); 658 + gf_zero(v4, g_ec_info.nr_dwords_x2); 659 + gf_zero(v7, g_ec_info.nr_dwords_x2); 616 660 /* v5 = y1 + y2 */ 617 661 gf_add(v5, a1->y, a2->y); 618 662 /* v6 = x1 + x2 */ 619 663 gf_add(v6, a1->x, a2->x); 620 664 /* v7 = 1/(x1 + x2) */ 621 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 667 /* v3 = (y1 + y2) / (x1 + x2) (lambda) */ 624 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 670 /* v5 = lambda + ec_a */ 627 - gf_add(v5, v3, g_decode_A_info.ec_a); 628 - clear_memory(v4, g_decode_A_info.nr_dwords_x2); 671 + gf_add(v5, v3, g_ec_info.ec_a); 672 + gf_zero(v4, g_ec_info.nr_dwords_x2); 629 673 /* v4 = lambda^2 */ 630 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 676 /* v7 = lambda^2 + lambda + ec_a */ 633 677 gf_add(v7, v5, v4); 634 678 /* x' = ec_a + x1 + x2 + lambda + lambda^2 */ ··· 637 681 gf_add(v5, a1->x, res->x); 638 682 /* v6 = x' + y1 */ 639 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 685 /* v7 = (x1 + x').lambda */ 642 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 688 /* y' = (x1 + x').lambda + x' + y1 */ 645 689 gf_add(res->y, v7, v6); 646 690 free(v3); ··· 654 698 { 655 699 ec_point_t res_others; 656 700 657 - res_others.x = malloc(g_decode_A_info.size); 658 - res_others.y = malloc(g_decode_A_info.size); 659 - clear_memory(res->x, g_decode_A_info.nr_dwords); 660 - clear_memory(res->y, g_decode_A_info.nr_dwords); 661 - clear_memory(res_others.x, g_decode_A_info.nr_dwords); 662 - clear_memory(res_others.y, g_decode_A_info.nr_dwords); 701 + res_others.x = malloc(g_ec_info.size); 702 + res_others.y = malloc(g_ec_info.size); 703 + gf_zero(res->x, g_ec_info.nr_dwords); 704 + gf_zero(res->y, g_ec_info.nr_dwords); 705 + gf_zero(res_others.x, g_ec_info.nr_dwords); 706 + gf_zero(res_others.y, g_ec_info.nr_dwords); 663 707 int pos = find_last_bit_set(n, 1); 664 708 665 709 /* res_other := point */ 666 - copy_memory(res_others.x, point->x); 667 - copy_memory(res_others.y, point->y); 710 + gf_copy(res_others.x, point->x); 711 + gf_copy(res_others.y, point->y); 668 712 669 713 /* for all bit from SZ-1 downto 0 */ 670 714 for(int bit = (pos % 32) - 1; bit >= 0; bit--) ··· 672 716 /* res := 2 * res_other */ 673 717 ec_double(&res_others, res); 674 718 /* res_other := res = 2 * res_other */ 675 - copy_memory(res_others.x, res->x); 676 - copy_memory(res_others.y, res->y); 719 + gf_copy(res_others.x, res->x); 720 + gf_copy(res_others.y, res->y); 677 721 /* if bit of n is set */ 678 722 if(n[pos / 32] & (1 << bit)) 679 723 { 680 724 /* res := res_other + point */ 681 725 ec_add(&res_others, point, res); 682 - copy_memory(res_others.x, res->x); 683 - copy_memory(res_others.y, res->y); 726 + gf_copy(res_others.x, res->x); 727 + gf_copy(res_others.y, res->y); 684 728 } 685 729 } 686 730 /* same but optimized */ ··· 689 733 for(int bit = 31; bit >= 0; bit--) 690 734 { 691 735 ec_double(&res_others, res); 692 - copy_memory(res_others.x, res->x); 693 - copy_memory(res_others.y, res->y); 736 + gf_copy(res_others.x, res->x); 737 + gf_copy(res_others.y, res->y); 694 738 if(n[i] & (1 << bit)) 695 739 { 696 740 ec_add(&res_others, point, res); 697 - copy_memory(res_others.x, res->x); 698 - copy_memory(res_others.y, res->y); 741 + gf_copy(res_others.x, res->x); 742 + gf_copy(res_others.y, res->y); 699 743 } 700 744 } 701 745 } 702 - copy_memory(res->x, res_others.x); 703 - copy_memory(res->y, res_others.y); 746 + gf_copy(res->x, res_others.x); 747 + gf_copy(res->y, res_others.y); 704 748 free(res_others.x); 705 749 free(res_others.y); 706 750 return 0; ··· 709 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 757 if(sz <= 32) 714 758 { 715 759 for(int i = 0; i < sz; i++) ··· 723 767 */ 724 768 uint8_t *ptrA = (uint8_t *)point->x; 725 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 771 for(int i = 0; i < sz; i++) 728 772 buf[i] ^= ptrA[i]; 729 773 for(int i = sz; i < 32; i++) 730 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); 738 - ptrs_others.y = malloc(g_decode_A_info.size); 739 - clear_memory(ptrs_others.x, g_decode_A_info.nr_dwords); 740 - clear_memory(ptrs_others.y, g_decode_A_info.nr_dwords); 741 - int ret = ec_mult(a3, ptrs, &ptrs_others); 782 + shared_secret.x = malloc(g_ec_info.size); 783 + shared_secret.y = malloc(g_ec_info.size); 784 + gf_zero(shared_secret.x, g_ec_info.nr_dwords); 785 + gf_zero(shared_secret.y, g_ec_info.nr_dwords); 786 + int ret = ec_mult(private_key, pt_rG, &shared_secret); 742 787 if(ret == 0) 743 - xor_with_point(a1, &ptrs_others); 744 - free(ptrs_others.x); 745 - free(ptrs_others.y); 788 + xor_with_point(buf, &shared_secret); 789 + free(shared_secret.x); 790 + free(shared_secret.y); 746 791 return ret; 747 792 } 748 793 749 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); 752 - g_decode_A_info.field_bits = 0; 796 + gf_zero(field_poly, g_ec_info.nr_dwords); 797 + g_ec_info.field_bits = 0; 753 798 if(field_sz == 4) 754 799 { 755 800 set_bit(0, field_poly); 756 801 set_bit(74, field_poly); 757 802 set_bit(233, field_poly); 758 - g_decode_A_info.field_bits = 233; 803 + g_ec_info.field_bits = 233; 759 804 return 0; 760 805 } 761 806 else if (field_sz == 5) ··· 765 810 set_bit(6, field_poly); 766 811 set_bit(7, field_poly); 767 812 set_bit(163, field_poly); 768 - g_decode_A_info.field_bits = 163; 813 + g_ec_info.field_bits = 163; 769 814 return 0; 770 815 } 771 816 else 772 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 823 if(ret) return ret; 779 824 if(field_sz == 4) 780 825 { 781 - copy_memory(a1->x, g_crypto_table); 782 - copy_memory(a1->y, g_crypto_table2); 783 - copy_memory(g_decode_A_info.ec_a, g_atj_ec233_a); 784 - copy_memory(g_decode_A_info.ptr7, g_crypto_key6); 826 + gf_copy(ec_G->x, g_sect233k1_G_x); 827 + gf_copy(ec_G->y, g_sect233k1_G_y); 828 + gf_copy(g_ec_info.ec_a, g_sect233k1_a); // zero 829 + gf_copy(g_ec_info.ec_b, g_sect233k1_b); // never used 785 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); 790 - copy_memory(a1->y, g_crypto_key4); 791 - copy_memory(g_decode_A_info.ec_a, g_atj_ec163_a); 792 - copy_memory(g_decode_A_info.ptr7, g_crypto_key5); 834 + gf_copy(ec_G->x, g_sect163r2_G_x); 835 + gf_copy(ec_G->y, g_sect163r2_G_y); 836 + gf_copy(g_ec_info.ec_a, g_sect163r2_a); 837 + gf_copy(g_ec_info.ec_b, g_sect163r2_b); 793 838 return 0; 794 839 } 795 840 else ··· 805 850 806 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 855 cprintf(BLUE, "Block B\n"); 809 - decode_block_B(block + 3, g_subblock_A + 4, 489); 810 - cprintf_field(" Word: ", "%d ", *(uint16_t *)(block + 3)); 811 - check_field(*(uint16_t *)(block + 3), 1, "Ok\n", "Mismatch\n"); 856 + decode_block_B(block + 3, g_subblock_A.key_B, 492 - 3); 857 + cprintf_field(" Word: ", "%d ", p_hdr->unk_1_b); 858 + check_field(p_hdr->unk_1_b, 1, "Ok\n", "Mismatch\n"); 812 859 813 860 int ret = check_block(block, block + 492, 492); 814 861 cprintf(GREEN, " Check: "); 815 862 check_field(ret, 0, "Pass\n", "Fail\n"); 816 863 817 - g_decode_buffer3 = malloc(g_decode_A_info.size); 818 - memset(g_decode_buffer3, 0, g_decode_A_info.size); 819 - int offset = *(uint16_t *)(block + 13) + 16; 820 - memcpy(g_decode_buffer3, &block[offset], g_decode_A_info.nr_bytes2); 864 + g_private_key = malloc(g_ec_info.size); 865 + memset(g_private_key, 0, g_ec_info.size); 866 + int offset = sizeof *p_hdr + p_hdr->guid_filler_size + 1; 867 + memcpy(g_private_key, &block[offset], g_ec_info.nr_bytes); 821 868 822 869 return 0; 823 870 } ··· 832 879 memset(smallblock, 0, sizeof(smallblock)); 833 880 memset(bigblock, 0, sizeof(bigblock)); 834 881 835 - uint8_t ba = buf[0x1ee] & 0xf; 836 - uint8_t bb = buf[0x1fe] & 0xf; 882 + *blockA = buf[0x1ee] & 15; 883 + *blockB = buf[0x1fe] & 15; 884 + size_t offsetA = 512 * (1 + *blockA); 885 + size_t offsetB = 512 * (1 + *blockB); 837 886 838 887 cprintf(BLUE, "Crypto\n"); 839 - cprintf_field(" Block A: ", "%d\n", ba + 2); 840 - cprintf_field(" Block B: ", "%d\n", ba + bb + 5); 888 + cprintf_field(" Block A: ", "0x%zx\n", 512 + offsetA); 889 + cprintf_field(" Block B: ", "0x%zx\n", 512 + offsetA + 1024 + offsetB); 841 890 842 - *blockA = buf[494] & 0xf; 843 - *blockB = buf[510] & 0xf; 844 - memcpy(bigblock, &buf[512 * (*blockA + 2)], sizeof(bigblock)); 891 + memcpy(bigblock, &buf[512 + offsetA], sizeof(bigblock)); 845 892 846 893 int ret = process_block_A(bigblock); 847 894 if(ret != 0) 848 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 898 ret = process_block_B(smallblock); 852 899 if(ret != 0) 853 900 return ret; ··· 859 906 cprintf_field(" Byte: ", "%d ", crypto_hdr.unk); 860 907 check_field(crypto_hdr.unk, 3, "Ok\n", "Mismatch\n"); 861 908 862 - ec_point_t ptrs; 863 - ptrs.x = malloc(g_decode_A_info.size); 864 - ptrs.y = malloc(g_decode_A_info.size); 865 - memset(ptrs.x, 0, g_decode_A_info.size); 866 - memset(ptrs.y, 0, g_decode_A_info.size); 867 - memcpy(ptrs.x, buf + 91, g_decode_A_info.nr_bytes2); 868 - memcpy(ptrs.y, buf + 91 + g_decode_A_info.nr_bytes2, g_decode_A_info.nr_bytes2); 909 + size_t offset = sizeof(struct fwu_hdr_t) + sizeof(struct fwu_crypto_hdr_t); 910 + ec_point_t pt_rG; 911 + pt_rG.x = malloc(g_ec_info.size); 912 + pt_rG.y = malloc(g_ec_info.size); 913 + memset(pt_rG.x, 0, g_ec_info.size); 914 + memset(pt_rG.y, 0, g_ec_info.size); 915 + memcpy(pt_rG.x, buf + offset, g_ec_info.nr_bytes); 916 + memcpy(pt_rG.y, buf + offset + g_ec_info.nr_bytes, g_ec_info.nr_bytes); 869 917 870 - ret = ec_init(&g_decode_A_info.ptr1, g_crypto_info_byte); 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 920 check_field(ret, 0, "Pass\n", "Fail\n"); 873 921 874 - ret = crypto4(crypto_hdr.key, &ptrs, g_decode_buffer3); 875 - cprintf(GREEN, " Crypto 4: "); 922 + ec_mult(g_private_key, &g_ec_info.pt_G, &g_ec_info.pt_kG); 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 935 check_field(ret, 0, "Pass\n", "Fail\n"); 877 936 878 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 942 int pos = *(uint16_t *)&buf[offset]; 884 - cprintf_field(" Word: ", "%d ", pos); 885 - int tmp = g_decode_A_info.nr_words2 + 199; 943 + cprintf_field(" Filler size: ", "%d ", pos); 944 + int tmp = offset + sizeof(struct fwu_sector0_tail_t); 886 945 check_field(pos, 510 - tmp, "Ok\n", "Mismatch\n"); 887 946 888 - uint8_t midbuf[108]; 889 - memcpy(midbuf, &buf[pos + offset + 2], sizeof(midbuf)); 947 + struct fwu_sector0_tail_t tail; 948 + memcpy(&tail, &buf[offset + 2 + pos], sizeof(tail)); 890 949 891 - cprintf_field(" Byte: ", "%d ", midbuf[0]); 892 - check_field(midbuf[0], 2, "Ok\n", "Invalid\n"); 893 - cprintf_field(" DWord: ", "%d ", *(uint32_t *)&midbuf[1]); 894 - check_field(*(uint32_t *)&midbuf[1], 2056, "Ok\n", "Invalid\n"); 895 - cprintf_field(" DWord: ", "%d ", *(uint32_t *)&midbuf[5]); 896 - check_field(*(uint32_t *)&midbuf[5], 8, "Ok\n", "Invalid\n"); 897 - cprintf_field(" Byte: ", "%d ", midbuf[41]); 898 - check_field(midbuf[41], 190, "Ok\n", "Invalid\n"); 950 + cprintf_field(" Byte: ", "%d ", tail.unk_2); 951 + check_field(tail.unk_2, 2, "Ok\n", "Invalid\n"); 952 + cprintf_field(" DWord: ", "0x%x ", tail.unk_x808); 953 + check_field(tail.unk_x808, 0x808, "Ok\n", "Invalid\n"); 954 + cprintf_field(" DWord: ", "%d ", tail.unk_8); 955 + check_field(tail.unk_8, 8, "Ok\n", "Invalid\n"); 956 + cprintf_field(" Byte: ", "%d ", tail.unk_190); 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 960 memset(blo, 0, 512); 901 - create_guid(smallblock, 3808); 902 - memcpy(smallblock + 476, midbuf + 42, 16); 961 + create_guid(smallblock, 476 * 8); 962 + memcpy(smallblock + 476, tail.super_secret_xor, 16); 903 963 compute_checksum(smallblock, 492, blo + 492); 904 964 int bsz = blo[500]; 905 965 memcpy(blo, smallblock, bsz); 906 - memcpy(blo + bsz, midbuf + 42, 16); 966 + memcpy(blo + bsz, tail.super_secret_xor, 16); 907 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); 910 - ret = check_block(buf + 42, midbuf + 88, 450); 911 - cprintf(GREEN, " Decode block: "); 970 + ret = check_block(buf + sizeof(struct fwu_hdr_t), tail.check, 492 - sizeof(struct fwu_hdr_t)); 971 + cprintf(GREEN, " Check: "); 912 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 975 cprintf(GREEN, " Compare: "); 916 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 980 cprintf(GREEN, " Sanity: "); 921 981 check_field(ret, 0, "Pass\n", "Fail\n"); 922 982 */ ··· 1000 1060 /* the input buffer is reorganized based on two offsets (blockA and blockB), 1001 1061 * skip 2048 bytes of data used for crypto init */ 1002 1062 *size = hdr->fw_size; /* use firmware size, not file size */ 1003 - *size -= 2048; 1063 + *size -= 512 + 1024 + 512; /* sector0 + blockA + blockB */ 1004 1064 uint8_t *tmpbuf = malloc(*size); 1005 1065 memset(tmpbuf, 0, *size); 1006 - int offsetA = (blockA + 1) << 9; 1007 - int offsetB = (blockB + 1) << 9; 1066 + int offsetA = 512 * (1 + blockA); 1067 + int offsetB = 512 * (1 + blockB); 1008 1068 memcpy(tmpbuf, buf + 512, offsetA); 1009 - memcpy(tmpbuf + offsetA, buf + offsetA + 1536, offsetB); 1069 + memcpy(tmpbuf + offsetA, buf + 512 + offsetA + 1024, offsetB); 1010 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 1072 /* stolen from https://github.com/nfd/atj2127decrypt, I have no idea from where 1013 1073 * he got this sequence of code. This code is really weird, I copy verbatim 1014 1074 * his authors comment below. ··· 1048 1108 atj2127_decrypt(buf, tmpbuf, *size, keybuf, rounds_to_perform); 1049 1109 else 1050 1110 { 1051 - compute_perm(keybuf, 32, g_perm_B); 1052 - decode_perm(tmpbuf, *size, g_perm_B); 1111 + rc4_key_schedule(keybuf, 32, g_rc4_S); 1112 + rc4_stream_cipher(tmpbuf, *size, g_rc4_S); 1053 1113 memcpy(buf, tmpbuf, *size); 1054 1114 } 1055 1115 ··· 1102 1162 cprintf_field(" Block size: ", "%d ", hdr->block_size); 1103 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 1166 int ver = get_version(buf, *size); 1107 1167 if(ver < 0) 1108 1168 {