-
-
Save brianpow/66da580570a4f088b8eb942bf0307821 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* SHARP FOTA parser DEMO | |
* [email protected], All rights reserved | |
* | |
*/ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#ifdef __APPLE__ | |
#include <sys/malloc.h> | |
#include <stdlib.h> | |
#else | |
#include <malloc.h> | |
#endif | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <zlib.h> | |
#include <lzmadec.h> | |
// XXX: LE/BE | |
#define tou8(x) ((uint8_t)(x)) | |
#define tou32(x) ((uint32_t)(x)) | |
#define byte0(x) ((uint8_t)(tou32(x))) | |
#define byte1(x) ((uint8_t)(tou32(x) >> 8)) | |
#define byte2(x) ((uint8_t)(tou32(x) >> 16)) | |
#define byte3(x) ((uint8_t)(tou32(x) >> 24)) | |
#define read8(x) (*(uint8_t *)(x)) | |
#define write8(v, x) (*((uint8_t *)(x)) = (v)) | |
#define read32(x) (*((uint8_t *)(x)) | \ | |
(*((uint8_t *)(x) + 1) << 8) |\ | |
(*((uint8_t *)(x) + 2) << 16) |\ | |
(*((uint8_t *)(x) + 3) << 24)) | |
#define write32(v, x) ({ \ | |
*((uint8_t *)(x)) = byte0(v); \ | |
*((uint8_t *)((x) + 1)) = byte1(v); \ | |
*((uint8_t *)((x) + 2)) = byte2(v); \ | |
*((uint8_t *)((x) + 3)) = byte3(v); \ | |
v; \ | |
}) | |
#define ror(x, n, l) ((x >> n) | (x << (l - n))) | |
#define ror32(x, n) ror(((uint32_t)(x)), n, 32) | |
#define NR_DKEY_NSYS 0 | |
#define NR_DKEY_IMAG 1 | |
#define NR_DKEY_INFO 2 | |
#define NELEM(x) (sizeof(x) / sizeof(x[0])) | |
/* | |
struct ipl { | |
uint32_t crc32; // 0 | |
// from + 0x10 | |
uint32_t size; // 4 | |
// == 0x180 | |
uint8_t pad1[8]; | |
uint8_t fota_boot_mode; // 0x10 | |
uint8_t fota_rw_complete; // 0x11 | |
// == 3 and fota_mode == 0 | |
uint8_t fota_rw_type; // 0x12 | |
... | |
uint8_t delta_storage_type; // | |
uint8_t fs_storage_type; // 0x49 | |
// 0 == /fota | |
// 1 == /sdcard | |
... | |
uint8_t fota_path[0]; // 0x70 | |
... | |
uint8_t no_data; // 0x120 | |
// == 0 || == 6 => no data | |
// == 1 => dummy | |
}; | |
1 | |
2 => androidboot.fotainfo=1 | |
3 X => FOTA failed, will brick device | |
6 1 => FOTA completed | |
*/ | |
struct fota_hdr { | |
uint32_t body_crc; | |
uint32_t body_size; | |
uint32_t unk1; | |
uint32_t unk2; | |
uint32_t info_crc; // 0x10 | |
uint32_t info_size; // 0x14 | |
uint8_t magic[6]; // 0x18, SHFOTA | |
uint16_t nsegs; // number of fota segs | |
}; | |
struct fota_seg { | |
uint32_t encrypted_flag; | |
uint32_t encrypted_size; | |
uint32_t decrypted_size; | |
uint32_t decrypted_crc; | |
uint8_t unk[0x10]; | |
uint8_t data[0]; | |
}; | |
struct fota_seg_hdr { | |
uint32_t crc; | |
uint32_t size; | |
uint32_t upi_ver; // seems to be 0x00014050 | |
uint32_t scout_ver; // seems to be 0x00013880 | |
uint32_t flags1; | |
uint32_t flags2; | |
uint32_t field_18; | |
uint32_t field_1c; | |
uint32_t index_offset; // index data offset in unLZMAed data(strings starts from 0) | |
uint32_t index_size; // index size when LZMAed | |
uint16_t field_28; | |
uint16_t field_2a; | |
uint16_t files_field_2c; | |
uint16_t files_diff; | |
uint16_t files_opt; | |
uint16_t files_del; | |
uint16_t dirs_del; | |
uint16_t dirs_add; | |
uint16_t links_del; | |
uint16_t links_add; | |
uint16_t criticals_field_3c; | |
uint16_t criticals_field_3e; | |
}; | |
/* | |
FOTA segment structure: | |
struct fota_seg_hdr; | |
{ | |
uint32_t dst_crc; | |
uint32_t src_crc; | |
} * files_diff; | |
{ | |
uint32_t crc32; | |
} * files_field_2c; | |
{ | |
uint32_t crc32; | |
} * files_opt; // not good to LZMA it so leave outside? | |
LZMAed index { | |
{ | |
links_del; | |
files_del; | |
files_field_2c + files_diff; | |
dirs_add + files_opt; | |
file_attrs; | |
} strings; | |
{ | |
int32_t size_new; // >= 0, consumes 2 strings | |
// < 0, consumes 1 string | |
// & 0x3fffffff is real size | |
} * files_diff; | |
{ | |
int32_t size_new; | |
} * files_field_2c; | |
{ | |
uint32_t field_04; | |
} * files_opt; | |
{ | |
int32_t size_diff; | |
} * files_diff; | |
{ | |
uint32_t attr_off; | |
} * (files_diff + files_field_2c); | |
{ | |
uint32_t attr_off; | |
} * (files_opt + dirs_add + links_add); | |
{ | |
uint32_t delta_size; // XXX: NG!!! shoud start after LZMAed index but no matches. | |
} * files_diff; | |
{ | |
uint32_t delta_size; | |
} * files_opt; | |
}; | |
*/ | |
struct fota_decode_key { | |
uint32_t state[4]; | |
uint8_t (*x)[0x20]; | |
uint8_t *y; | |
uint8_t *z; | |
uint8_t (*w)[0x100]; | |
uint8_t *xft32; | |
uint8_t *n; | |
uint8_t *xft8; | |
}; | |
struct fota_keys { | |
char *device; | |
char *akey; | |
struct fota_decode_key *dkey; | |
}; | |
struct fota_cipher_state { | |
uint32_t x[40]; | |
uint32_t d[4][256]; | |
}; | |
static uint8_t fota_dkey_x_sh04f[0x80 * 3] = { | |
0x4e, 0x34, 0x9f, 0xf8, 0x53, 0x7d, 0x00, 0x65, 0x97, 0x52, 0xde, 0xee, 0xd4, 0x53, 0xf0, 0xbd, | |
0x9b, 0xa0, 0x62, 0x9a, 0xa4, 0xe1, 0xcd, 0x10, 0x63, 0x8a, 0x66, 0xcb, 0xdb, 0x5d, 0x76, 0x45, | |
0xb7, 0x30, 0x0a, 0xa2, 0x97, 0xf0, 0xeb, 0xd8, 0xa8, 0xe6, 0xd0, 0x12, 0x77, 0x39, 0xd3, 0x57, | |
0x07, 0xb4, 0x22, 0x66, 0x21, 0xca, 0xf7, 0xe5, 0xeb, 0xd7, 0xca, 0xbb, 0xbc, 0xa9, 0xc5, 0xbb, | |
0x2f, 0x3f, 0x78, 0x82, 0x76, 0xd0, 0xce, 0xa2, 0xf1, 0x10, 0x3f, 0x00, 0xff, 0xae, 0x48, 0x7a, | |
0x15, 0x21, 0x18, 0xcd, 0x0d, 0xa4, 0x8d, 0xb6, 0xc0, 0x7f, 0x5e, 0x58, 0xd6, 0x89, 0x9a, 0xde, | |
0xdd, 0xeb, 0x51, 0x61, 0x99, 0x26, 0x90, 0x0c, 0x9b, 0x58, 0x93, 0x7e, 0x15, 0xbb, 0x37, 0x6f, | |
0xed, 0x6e, 0xae, 0x97, 0x10, 0x78, 0x76, 0xcb, 0x09, 0x0a, 0x8c, 0x6a, 0xd2, 0x04, 0xdd, 0xf7, | |
0xea, 0xbb, 0xfd, 0x07, 0xa7, 0xf9, 0x1b, 0x5e, 0xce, 0x46, 0x35, 0x55, 0x61, 0x66, 0x88, 0x7f, | |
0xb8, 0x23, 0x4b, 0x8b, 0xd3, 0x4d, 0x9c, 0x6c, 0xef, 0xfe, 0xbb, 0xb8, 0x57, 0x22, 0x76, 0x4e, | |
0x7d, 0x37, 0xe4, 0x3c, 0x49, 0x52, 0x56, 0xe0, 0xb1, 0x63, 0x8b, 0x4d, 0x8a, 0xb9, 0x23, 0xef, | |
0x9e, 0xc9, 0x56, 0x73, 0xfe, 0x2b, 0xe6, 0xe1, 0x9a, 0xe5, 0x52, 0x0b, 0x0e, 0xec, 0x4d, 0x2b, | |
0xbf, 0xe8, 0x6e, 0xc8, 0x27, 0x38, 0x29, 0xd9, 0x6d, 0x36, 0xfe, 0x2d, 0x39, 0xbc, 0xf0, 0x0a, | |
0xc6, 0xe7, 0x39, 0x15, 0x39, 0x1a, 0x3c, 0x71, 0x31, 0x46, 0xbb, 0x2b, 0x9f, 0x69, 0x4a, 0xd6, | |
0xd8, 0x55, 0x04, 0x72, 0xe8, 0xb3, 0x7c, 0x93, 0x29, 0x47, 0xf7, 0xbf, 0x15, 0x76, 0xd8, 0x17, | |
0x59, 0x05, 0x5b, 0x39, 0x2a, 0x23, 0x86, 0x66, 0xdc, 0xaa, 0x5d, 0xe0, 0xb1, 0xa2, 0x56, 0x96, | |
0xef, 0x07, 0x0c, 0x03, 0x35, 0xcb, 0x37, 0x54, 0x0e, 0x1f, 0xdc, 0xc9, 0xc7, 0xef, 0xc1, 0x5d, | |
0x7e, 0xab, 0x24, 0xa9, 0x7c, 0x4d, 0xac, 0x06, 0xc5, 0x98, 0xa0, 0xf2, 0xec, 0x9d, 0x57, 0xb5, | |
0x2c, 0x84, 0xf0, 0x44, 0xb5, 0x89, 0x43, 0x65, 0x44, 0x45, 0x16, 0x14, 0xf6, 0x2f, 0x95, 0x25, | |
0x5e, 0x62, 0xfc, 0x2c, 0xd5, 0xa1, 0x97, 0x9a, 0x11, 0x98, 0xec, 0x28, 0xfa, 0x64, 0x37, 0x79, | |
0xb8, 0x56, 0x16, 0xfa, 0x11, 0xf4, 0x86, 0x0e, 0xf2, 0x41, 0x0e, 0x68, 0x4b, 0x3f, 0x3a, 0xb7, | |
0x20, 0xb1, 0x4b, 0x89, 0xde, 0x25, 0x2d, 0x69, 0xeb, 0x32, 0xa9, 0x4b, 0x80, 0xff, 0xdc, 0x2b, | |
0xbb, 0x04, 0xe8, 0xf0, 0xf0, 0x15, 0xe9, 0x96, 0x41, 0x9c, 0x2b, 0x8c, 0x6e, 0x26, 0x9a, 0x5b, | |
0xee, 0x21, 0x79, 0x89, 0x3e, 0xe3, 0x57, 0xbd, 0x79, 0xef, 0x3f, 0x23, 0x29, 0x74, 0x30, 0x12, | |
}; | |
static uint8_t fota_dkey_y_sh04f[0x10 * 3] = { | |
0x26, 0x2f, 0x27, 0xf4, 0xa2, 0xc5, 0x85, 0xbf, 0xcf, 0xd4, 0xd9, 0x7a, 0xbb, 0xfd, 0xd7, 0x57, | |
0x1a, 0x3e, 0x33, 0x21, 0x24, 0x28, 0xa1, 0x99, 0xb7, 0xc1, 0x23, 0x65, 0x98, 0x85, 0xdd, 0x6d, | |
0x95, 0x4d, 0x93, 0x65, 0x2f, 0x80, 0x2e, 0x32, 0x2f, 0x8e, 0x1f, 0x4d, 0x51, 0x0b, 0x39, 0x8f, | |
}; | |
static uint8_t fota_dkey_z_sh04f[0x20 * 3] = { | |
0x5c, 0x17, 0xcc, 0xed, 0xfb, 0xf2, 0x54, 0x47, 0x58, 0xdd, 0xd4, 0x4a, 0x06, 0xec, 0x9b, 0x59, | |
0xed, 0x39, 0xee, 0xf4, 0x9d, 0xe3, 0xfe, 0xdc, 0xe3, 0x56, 0x17, 0x78, 0x9a, 0xcd, 0x19, 0x78, | |
0xc4, 0x16, 0x2c, 0xb8, 0xda, 0x95, 0xb0, 0x67, 0x60, 0x8c, 0x73, 0x68, 0xbb, 0x9a, 0x27, 0xf8, | |
0x47, 0x81, 0x13, 0x92, 0xa5, 0x2c, 0x08, 0x0f, 0x52, 0xf0, 0x97, 0x12, 0x7e, 0x12, 0x81, 0xa3, | |
0x1b, 0x89, 0x6f, 0x1a, 0x34, 0x06, 0xe3, 0x3f, 0x80, 0x32, 0x6f, 0xaf, 0x37, 0x36, 0x25, 0x82, | |
0x24, 0x81, 0x4e, 0x2a, 0xfc, 0xc5, 0x5f, 0x9e, 0xee, 0x43, 0x28, 0xb9, 0x7b, 0x49, 0x4f, 0xdc, | |
}; | |
static uint8_t fota_dkey_w_sh04f[0x500] = { | |
0xf9, 0xe7, 0x79, 0x8f, 0x57, 0x26, 0xbd, 0xd2, 0x13, 0x87, 0xec, 0x03, 0x6a, 0xa4, 0xf8, 0x12, | |
0xc7, 0x0d, 0xac, 0x66, 0x9f, 0xc1, 0x11, 0x1b, 0xdb, 0x51, 0x2e, 0x56, 0x60, 0x05, 0x69, 0x4b, | |
0x40, 0x14, 0x8a, 0x0b, 0x8b, 0x07, 0x00, 0x92, 0x6e, 0x6f, 0xa1, 0x91, 0x49, 0xb1, 0x7b, 0x37, | |
0x5e, 0x86, 0x41, 0x25, 0xc6, 0x94, 0x8c, 0x3e, 0xdf, 0xc3, 0x97, 0x80, 0x45, 0x3c, 0x5a, 0x73, | |
0x39, 0x52, 0xae, 0x7c, 0x31, 0xd7, 0xb0, 0x85, 0x4c, 0x36, 0x9a, 0xdd, 0x53, 0x35, 0x72, 0xa8, | |
0xbe, 0x54, 0x65, 0xfc, 0xa6, 0x96, 0x16, 0x33, 0x70, 0x24, 0xa3, 0x3b, 0x22, 0x95, 0x93, 0x06, | |
0x75, 0x74, 0xb4, 0x27, 0x7e, 0xb5, 0x5d, 0xda, 0xf7, 0x34, 0x68, 0x6c, 0xad, 0x18, 0xe6, 0x21, | |
0x63, 0x3d, 0x84, 0xea, 0xbb, 0xcd, 0xa7, 0x09, 0xf0, 0x47, 0xe8, 0xd9, 0x2c, 0x38, 0xd0, 0x0c, | |
0xe4, 0xb2, 0x2a, 0xb7, 0x55, 0x5f, 0xa9, 0x5c, 0xfd, 0x9c, 0xe3, 0x29, 0x04, 0xa5, 0xc8, 0x0a, | |
0x48, 0xb3, 0xfe, 0x64, 0xf4, 0xd1, 0xce, 0xdc, 0x0e, 0x23, 0x6d, 0x20, 0x2b, 0xf1, 0xf6, 0xca, | |
0x77, 0xb9, 0x7d, 0x81, 0xba, 0x8d, 0x1c, 0x32, 0x1f, 0xa2, 0x99, 0x98, 0x02, 0xa0, 0x89, 0xc0, | |
0x9d, 0x82, 0xfb, 0x90, 0x42, 0xb6, 0x19, 0xe9, 0xeb, 0xbf, 0x58, 0x62, 0x17, 0x44, 0x0f, 0x15, | |
0x9e, 0x88, 0xd3, 0xe5, 0xaf, 0xaa, 0x30, 0xed, 0x59, 0x83, 0x01, 0x10, 0x46, 0xc4, 0xd8, 0xe0, | |
0xab, 0x76, 0xcc, 0xd6, 0x1d, 0x6b, 0x61, 0x1a, 0xbc, 0xcb, 0x7f, 0xf5, 0x7a, 0xde, 0x5b, 0xff, | |
0x08, 0xef, 0x9b, 0x4f, 0x3a, 0xf3, 0x8e, 0x2f, 0x71, 0x4d, 0xfa, 0x4e, 0xcf, 0x3f, 0x1e, 0xd4, | |
0x50, 0xe1, 0x43, 0xc2, 0xc9, 0xf2, 0xc5, 0xe2, 0x78, 0xb8, 0x67, 0x28, 0xee, 0xd5, 0x2d, 0x4a, | |
0xbf, 0x3e, 0xd8, 0xe1, 0x22, 0x01, 0x21, 0x66, 0x2f, 0xd9, 0xa7, 0x3a, 0x10, 0xc3, 0x12, 0xa5, | |
0x35, 0xdd, 0x7b, 0xa2, 0x6f, 0x02, 0x53, 0xe9, 0x59, 0x81, 0x5a, 0x68, 0x86, 0xfc, 0x95, 0x1a, | |
0x97, 0x1b, 0x0a, 0xf5, 0x36, 0xef, 0xe8, 0xbc, 0x54, 0xfd, 0x84, 0x26, 0x2c, 0xed, 0xeb, 0xc9, | |
0x17, 0x2e, 0x6a, 0x85, 0xa6, 0x11, 0x0d, 0x9b, 0xe4, 0x41, 0x0f, 0x4a, 0x76, 0xee, 0x38, 0xea, | |
0x80, 0x8d, 0x4c, 0x65, 0xf3, 0xf8, 0x8c, 0x00, 0x49, 0x4d, 0x04, 0x8b, 0xa9, 0x77, 0xcc, 0x4b, | |
0xcd, 0xe3, 0xb9, 0xda, 0xc1, 0x08, 0xd4, 0x44, 0xe0, 0x52, 0x09, 0x55, 0x7a, 0x94, 0xa1, 0x27, | |
0xce, 0x47, 0x39, 0x72, 0xa4, 0x7e, 0x1c, 0x06, 0xfa, 0x1f, 0x78, 0xd2, 0x62, 0x34, 0xb8, 0x71, | |
0xaf, 0xe5, 0x4e, 0x5b, 0x73, 0xb3, 0x40, 0x0e, 0x03, 0x42, 0x24, 0x57, 0xfe, 0x67, 0x31, 0xb5, | |
0xf4, 0xff, 0xbe, 0x64, 0xa3, 0x07, 0x29, 0xbb, 0xd0, 0xaa, 0x23, 0x6c, 0x75, 0xdf, 0xc7, 0xc6, | |
0xd7, 0x16, 0x48, 0x93, 0xde, 0xa8, 0xc2, 0x8a, 0x7c, 0xf9, 0x4f, 0x88, 0xdc, 0x15, 0x8f, 0x14, | |
0xb4, 0xab, 0x3b, 0x91, 0x79, 0xd3, 0xf6, 0xf2, 0xad, 0xf1, 0x9d, 0x20, 0x33, 0xd6, 0xca, 0xe6, | |
0x83, 0x46, 0x0b, 0x9a, 0x7f, 0xcf, 0x82, 0x5d, 0x19, 0x2b, 0xb1, 0x87, 0x9c, 0xbd, 0x51, 0x70, | |
0x96, 0xba, 0xdb, 0x25, 0xb0, 0x61, 0xc5, 0x74, 0x7d, 0x3f, 0xb6, 0x5e, 0x8e, 0x18, 0xac, 0x6d, | |
0xe7, 0x98, 0x1e, 0xa0, 0x05, 0x69, 0x3c, 0x9e, 0x99, 0xae, 0xc0, 0x92, 0xb2, 0xb7, 0x89, 0x37, | |
0xfb, 0x90, 0x60, 0xec, 0x6e, 0xcb, 0x6b, 0x45, 0x30, 0x28, 0x3d, 0x1d, 0xf0, 0x9f, 0x50, 0xe2, | |
0xd1, 0x2a, 0x32, 0xd5, 0x43, 0x13, 0x5c, 0x63, 0x5f, 0x0c, 0x58, 0xc4, 0x56, 0xf7, 0xc8, 0x2d, | |
0xca, 0x50, 0xfe, 0x0e, 0x59, 0x76, 0x39, 0xba, 0x60, 0xf1, 0xd2, 0x5c, 0x04, 0x01, 0x54, 0x51, | |
0xfa, 0xaf, 0xfb, 0x7c, 0x25, 0x57, 0x00, 0x3b, 0xd0, 0xa6, 0xc4, 0x40, 0x99, 0xce, 0x35, 0xda, | |
0x3f, 0xd3, 0x9a, 0x05, 0xab, 0xdd, 0x21, 0x1d, 0xe4, 0xe3, 0x75, 0xd4, 0xb3, 0x4b, 0x5d, 0xa4, | |
0x32, 0xde, 0xbc, 0x8c, 0x9f, 0xe6, 0x87, 0xe5, 0x4c, 0x4d, 0xa2, 0xf3, 0x27, 0xe1, 0x8b, 0xb0, | |
0x6d, 0x5b, 0x84, 0x1e, 0x24, 0xa0, 0x56, 0x5a, 0x1f, 0x9d, 0x88, 0xfc, 0xaa, 0xac, 0x1a, 0xd1, | |
0xbf, 0x1c, 0x44, 0x15, 0x17, 0x33, 0xcc, 0x69, 0x91, 0x14, 0xff, 0x4a, 0x90, 0x6b, 0xc5, 0xc1, | |
0x47, 0x6a, 0x62, 0xf0, 0xbd, 0x98, 0xa9, 0xe0, 0x18, 0xcb, 0xb6, 0xdf, 0xa3, 0xef, 0x4e, 0x43, | |
0xee, 0xf6, 0x5f, 0x2a, 0xbb, 0x09, 0x64, 0xb9, 0x2d, 0x19, 0x2e, 0xf7, 0xeb, 0xad, 0xe9, 0x83, | |
0x89, 0x9b, 0xe8, 0x08, 0x0f, 0x3a, 0x9e, 0x93, 0x74, 0xd5, 0x4f, 0x8d, 0x8e, 0x6c, 0x30, 0xec, | |
0x11, 0x96, 0x85, 0x07, 0x49, 0x2f, 0xc2, 0x38, 0x6f, 0x61, 0x42, 0xd8, 0x20, 0xfd, 0xed, 0xb4, | |
0x79, 0xb5, 0xe7, 0x80, 0xe2, 0x73, 0x28, 0x16, 0xf9, 0x45, 0x97, 0xc7, 0x13, 0xa5, 0xf5, 0x5e, | |
0x48, 0xd6, 0x2b, 0xc8, 0x7e, 0x7d, 0xc9, 0x31, 0xc0, 0x67, 0x41, 0x06, 0x3d, 0xb1, 0x8f, 0xd7, | |
0x65, 0x66, 0x8a, 0x7f, 0x12, 0x23, 0x58, 0xc3, 0x29, 0x70, 0x68, 0x0a, 0x95, 0x6e, 0xb7, 0x7a, | |
0x81, 0x92, 0xa8, 0x55, 0x71, 0x10, 0x0d, 0x9c, 0xf4, 0xae, 0xf8, 0x63, 0xdb, 0x36, 0xbe, 0x86, | |
0x7b, 0xea, 0x2c, 0xb8, 0x22, 0x1b, 0x78, 0xa7, 0x34, 0x77, 0x37, 0xd9, 0xc6, 0x3c, 0xa1, 0x0c, | |
0x3e, 0x46, 0x82, 0x0b, 0xcf, 0xcd, 0x02, 0x52, 0x94, 0xdc, 0x26, 0xb2, 0xf2, 0x72, 0x03, 0x53, | |
0x5e, 0x80, 0x87, 0x3e, 0xda, 0xab, 0xb5, 0xf9, 0xac, 0xc1, 0x10, 0x0a, 0xbf, 0x65, 0x50, 0x15, | |
0x4d, 0x6b, 0xe1, 0xd1, 0x1c, 0x8d, 0xa6, 0x14, 0x6e, 0x8e, 0xc0, 0x5c, 0xbd, 0xd9, 0x2b, 0xb4, | |
0x2f, 0x05, 0xdb, 0x83, 0x60, 0x63, 0x4f, 0xcb, 0x47, 0x41, 0xa1, 0xf7, 0x9e, 0x40, 0x49, 0x46, | |
0x8a, 0x35, 0x26, 0xfc, 0x9f, 0x4a, 0x67, 0xa8, 0x9c, 0x54, 0xed, 0x9b, 0x91, 0xaa, 0xf4, 0xc2, | |
0xea, 0xe0, 0x96, 0xcf, 0x24, 0xb6, 0x72, 0xe7, 0x6d, 0x44, 0xd2, 0x25, 0x7c, 0x64, 0x73, 0x1a, | |
0xff, 0xb7, 0xdd, 0x78, 0xef, 0xae, 0x23, 0xa0, 0x09, 0xb9, 0x84, 0x17, 0x19, 0x66, 0x13, 0x4c, | |
0x3d, 0x86, 0x56, 0xe3, 0xfb, 0x30, 0x99, 0x57, 0x11, 0xe4, 0x76, 0xee, 0x12, 0x7a, 0x9d, 0x88, | |
0x94, 0x16, 0xce, 0x04, 0xd5, 0x06, 0xa4, 0x22, 0x3b, 0x58, 0x32, 0xc3, 0x95, 0x29, 0x27, 0xfe, | |
0xa9, 0x02, 0xa7, 0x90, 0x8f, 0x5d, 0xa2, 0x68, 0xb0, 0xb1, 0x74, 0x2c, 0xd3, 0xe6, 0x07, 0x00, | |
0xbb, 0xbc, 0x0e, 0xf6, 0x4e, 0x01, 0xeb, 0xa3, 0xf1, 0x18, 0x89, 0x20, 0xca, 0xe9, 0x48, 0x8c, | |
0x0c, 0x98, 0xf0, 0x55, 0x62, 0x2a, 0x5a, 0x51, 0xc8, 0xfd, 0xec, 0x82, 0x79, 0x3c, 0x1f, 0x1b, | |
0xc7, 0xe8, 0x7e, 0x36, 0x34, 0x28, 0xc5, 0x4b, 0x6f, 0xfa, 0x1e, 0x8b, 0x7d, 0x70, 0xcd, 0x3a, | |
0x85, 0xa5, 0xdc, 0xc6, 0xba, 0xaf, 0xb2, 0x1d, 0x75, 0x39, 0xad, 0x2e, 0x0d, 0x71, 0x0b, 0xdf, | |
0xd7, 0x52, 0x0f, 0xf3, 0x2d, 0x3f, 0xb8, 0xb3, 0x59, 0x08, 0x5f, 0xd4, 0xf8, 0xbe, 0x77, 0x61, | |
0x38, 0xde, 0x69, 0x6c, 0x53, 0xd8, 0x92, 0x93, 0x21, 0x9a, 0x5b, 0xd6, 0x81, 0x33, 0x7f, 0xf5, | |
0x37, 0xf2, 0x03, 0x97, 0xe5, 0xcc, 0xe2, 0x6a, 0xc4, 0x45, 0x42, 0x31, 0xd0, 0x43, 0x7b, 0xc9, | |
0xc0, 0x06, 0xc3, 0xae, 0x85, 0xb3, 0xdd, 0x7e, 0x58, 0x2b, 0x72, 0x00, 0xc2, 0x77, 0x3a, 0x8d, | |
0xe3, 0xdf, 0x63, 0xb0, 0xa8, 0x9c, 0x8c, 0xed, 0x17, 0x59, 0x70, 0xab, 0x3d, 0x14, 0xbe, 0x29, | |
0xcd, 0x79, 0x8f, 0x87, 0xe6, 0xc7, 0x4e, 0x64, 0xcc, 0x03, 0x3b, 0x07, 0xda, 0x92, 0xd8, 0xcf, | |
0xea, 0x0d, 0x86, 0xe5, 0x55, 0xff, 0x54, 0xe0, 0x46, 0xbf, 0xba, 0x05, 0xbd, 0xf9, 0x6f, 0xe9, | |
0x7c, 0x31, 0x40, 0xdc, 0xca, 0x16, 0x94, 0x5f, 0x6a, 0xaf, 0xc4, 0x96, 0x73, 0x12, 0xb9, 0xd2, | |
0xf3, 0xf0, 0xfe, 0x51, 0xb1, 0xf6, 0x7f, 0xfb, 0x23, 0x01, 0xa6, 0x80, 0x97, 0xc6, 0xe8, 0x49, | |
0x4f, 0xa2, 0x32, 0xc8, 0xaa, 0x57, 0xc5, 0x81, 0xb8, 0x22, 0x45, 0x56, 0x08, 0x2e, 0x15, 0x2f, | |
0x75, 0x38, 0x1e, 0x25, 0xf2, 0x67, 0xd0, 0xef, 0x1c, 0xc9, 0x65, 0x71, 0x83, 0x8b, 0xfc, 0x1f, | |
0xd5, 0x35, 0xf8, 0xb2, 0x9f, 0x4d, 0xeb, 0xb7, 0x36, 0x90, 0x26, 0x18, 0x0e, 0xce, 0x30, 0x1d, | |
0x6d, 0x6c, 0xec, 0x9b, 0xc1, 0x9e, 0x0c, 0xb5, 0xd7, 0xee, 0x0b, 0xe1, 0x47, 0x44, 0xfa, 0x02, | |
0xb6, 0x6b, 0xf4, 0x69, 0xb4, 0x74, 0x19, 0xa9, 0x61, 0x04, 0x84, 0x60, 0x93, 0xe4, 0x1a, 0x13, | |
0x42, 0x8a, 0x37, 0xe7, 0x4c, 0x99, 0xa3, 0x82, 0x5b, 0xe2, 0x0a, 0x48, 0xfd, 0xcb, 0xd4, 0x11, | |
0xdb, 0x88, 0x7d, 0xad, 0xf5, 0x78, 0x53, 0x91, 0x9d, 0x9a, 0x21, 0xf1, 0x3f, 0xac, 0x10, 0x8e, | |
0x62, 0x28, 0x41, 0x2d, 0xd6, 0x24, 0xa5, 0xa4, 0x09, 0x68, 0x5a, 0x34, 0xa1, 0x27, 0x76, 0x3c, | |
0x4a, 0x2a, 0x43, 0xa0, 0x5d, 0x89, 0x98, 0xd9, 0x39, 0x5c, 0xf7, 0x6e, 0x50, 0x20, 0x7b, 0x5e, | |
0xd1, 0x7a, 0x0f, 0xd3, 0xde, 0x3e, 0xa7, 0x95, 0x1b, 0x66, 0xbc, 0x2c, 0x33, 0xbb, 0x4b, 0x52, | |
}; | |
static uint8_t fota_dkey_xft32_sh04f[0x20] = { | |
0x19, 0x07, 0x0d, 0x15, 0x1d, 0x1b, 0x0e, 0x0a, 0x00, 0x10, 0x0f, 0x05, 0x1c, 0x14, 0x17, 0x1e, | |
0x09, 0x04, 0x18, 0x12, 0x13, 0x1f, 0x08, 0x06, 0x1a, 0x01, 0x16, 0x03, 0x0c, 0x02, 0x11, 0x0b | |
}; | |
static uint8_t fota_dkey_n_sh04f[0x20] = { | |
0x08, 0x19, 0x1d, 0x1b, 0x11, 0x0b, 0x17, 0x01, 0x16, 0x10, 0x07, 0x1f, 0x1c, 0x02, 0x06, 0x0a, | |
0x09, 0x1e, 0x13, 0x14, 0x0d, 0x03, 0x1a, 0x0e, 0x12, 0x00, 0x18, 0x05, 0x0c, 0x04, 0x0f, 0x15, | |
}; | |
static uint8_t fota_dkey_xft8_sh04f[8] = { | |
0x01, 0x07, 0x02, 0x06, 0x00, 0x04, 0x03, 0x05, | |
}; | |
static struct fota_decode_key fota_dkey_sh04f[] = { | |
{ .state = { 0x2896ce0d, 0x4b8c0557, 0xdccea976, 0xa449fc6e, }, | |
.x = (void *)(fota_dkey_x_sh04f + 0x100), | |
.y = fota_dkey_y_sh04f, | |
.z = fota_dkey_z_sh04f + 0x40, | |
.w = (void *) fota_dkey_w_sh04f, | |
.xft32 = fota_dkey_xft32_sh04f, | |
.n = fota_dkey_n_sh04f, | |
.xft8 = fota_dkey_xft8_sh04f, | |
}, | |
{ .state = { 0x8562c12c, 0x03240411, 0x9109e6ef, 0xa8f5d356, }, | |
.x = (void *)(fota_dkey_x_sh04f + 0x80), | |
.y = fota_dkey_y_sh04f + 0x10, | |
.z = fota_dkey_z_sh04f + 0x20, | |
.w = (void *) fota_dkey_w_sh04f, | |
.xft32 = fota_dkey_xft32_sh04f, | |
.n = fota_dkey_n_sh04f, | |
.xft8 = fota_dkey_xft8_sh04f, | |
}, | |
{ .state = { 0x2f5510c8, 0x963a5561, 0xd2b0b24c, 0x4dcdf8e5, }, | |
.x = (void *) fota_dkey_x_sh04f, | |
.y = fota_dkey_y_sh04f + 0x20, | |
.z = fota_dkey_z_sh04f, | |
.w = (void *) fota_dkey_w_sh04f, | |
.xft32 = fota_dkey_xft32_sh04f, | |
.n = fota_dkey_n_sh04f, | |
.xft8 = fota_dkey_xft8_sh04f, | |
}, | |
}; | |
static struct fota_keys all_supported_devices[] = { | |
{ .device = "SH04F", .akey = "i1hR7Wh4d1E0RPG4", .dkey = fota_dkey_sh04f }, | |
{ .device = "306SH", .akey = "i1hR7Wh4d1E0RPG4", .dkey = fota_dkey_sh04f }, | |
{ .device = NULL }, | |
}; | |
static uint8_t fota_cipher_x7_tbl[16] = { | |
0x01, 0xef, 0x5b, 0x5b, 0x5b, 0xef, 0xef, 0x01, 0xef, 0x5b, 0x01, 0xef, 0xef, 0x01, 0xef, 0x5b, | |
}; | |
static uint8_t fota_cipher_x7_tbl_x2_0[] = { | |
0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38, | |
0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48, | |
0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82, | |
0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61, | |
0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1, | |
0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7, | |
0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71, | |
0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7, | |
0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90, | |
0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef, | |
0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64, | |
0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a, | |
0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d, | |
0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, | |
0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4, | |
0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0, | |
}; | |
static uint8_t fota_cipher_x7_tbl_x2_1[] = { | |
0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b, | |
0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f, | |
0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5, | |
0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51, | |
0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c, | |
0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8, | |
0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2, | |
0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17, | |
0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e, | |
0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9, | |
0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48, | |
0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64, | |
0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69, | |
0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc, | |
0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9, | |
0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91, | |
}; | |
static uint8_t *fota_cipher_x7_tbl_x2[] = { | |
fota_cipher_x7_tbl_x2_1, // 0 | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_0, | |
fota_cipher_x7_tbl_x2_0, | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_0, // 5 | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_0, | |
fota_cipher_x7_tbl_x2_0, | |
fota_cipher_x7_tbl_x2_0, // 10 | |
fota_cipher_x7_tbl_x2_0, | |
fota_cipher_x7_tbl_x2_0, | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_1, // 15 | |
fota_cipher_x7_tbl_x2_0, | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_1, | |
fota_cipher_x7_tbl_x2_0, | |
}; | |
static uint8_t fota_set_key_tbl[] = { | |
0x01, 0xa4, 0x55, 0x87, 0x5a, 0x58, 0xdb, 0x9e, 0xa4, 0x56, 0x82, 0xf3, 0x1e, 0xc6, 0x68, 0xe5, | |
0x02, 0xa1, 0xfc, 0xc1, 0x47, 0xae, 0x3d, 0x19, 0xa4, 0x55, 0x87, 0x5a, 0x58, 0xdb, 0x9e, 0x03, | |
}; | |
static void dump(const char *head, const void *data, size_t size) { | |
size_t i; | |
fprintf(stderr, "%s\n", head); | |
fflush(stderr); | |
for (i = 0; i < size; i++) { | |
if (i % 16 == 0) | |
fprintf(stderr, "%08x: ", (unsigned int) i); | |
fprintf(stderr, "%02x ", *((char *) data + i) & 0xff); | |
if ((i + 1) % 16 == 0) | |
fprintf(stderr, "\n"); | |
} | |
if (i % 16) | |
fprintf(stderr, "\n"); | |
fflush(stderr); | |
} | |
static uint32_t fota_cipher_x3(uint32_t a, uint32_t b, uint32_t c) { | |
uint32_t x; | |
x = 0; | |
while (b) { | |
if (b & 1) { | |
x ^= c; | |
x &= 0xff; | |
} | |
b >>= 1; | |
c <<= 1; | |
if (c & 0x100) | |
c ^= a; | |
} | |
return x; | |
} | |
static uint32_t fota_cipher_x7(uint32_t a, uint32_t b, uint32_t c, uint8_t x, uint8_t y, uint8_t z, uint8_t w) { | |
uint32_t val; | |
val = c; | |
if (a != 2) { | |
if (a != 3) | |
val = fota_cipher_x7_tbl_x2[b * 5][val] ^ w; | |
val = z ^ fota_cipher_x7_tbl_x2[b * 5 + 1][val]; | |
} | |
val = y ^ fota_cipher_x7_tbl_x2[b * 5 + 2][val]; | |
val = x ^ fota_cipher_x7_tbl_x2[b * 5 + 3][val]; | |
val = fota_cipher_x7_tbl_x2[b * 5 + 4][val]; | |
return (fota_cipher_x3(105, fota_cipher_x7_tbl[b], val)) | | |
(fota_cipher_x3(105, fota_cipher_x7_tbl[b + 4], val) << 8) | | |
(fota_cipher_x3(105, fota_cipher_x7_tbl[b + 8], val) << 16) | | |
(fota_cipher_x3(105, fota_cipher_x7_tbl[b + 12], val) << 24); | |
} | |
static uint32_t fota_cipher_x6(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) { | |
uint32_t x, y, z, w; | |
x = fota_cipher_x7(a, 0, b, c & 0xff, d & 0xff, e & 0xff, f & 0xff); | |
y = fota_cipher_x7(a, 1, b, (c & 0xff00) >> 8, (d >> 8) & 0xff, (e >> 8) & 0xff, (f >> 8) & 0xff); | |
z = fota_cipher_x7(a, 2, b, (c & 0xff0000) >> 16, (d >> 16) & 0xff, (e >> 16) & 0xff, (f >> 16) & 0xff); | |
w = fota_cipher_x7(a, 3, b, (c & 0xff000000) >> 24, (d >> 24) & 0xff, (e >> 24) & 0xff, (f >> 24) & 0xff); | |
return (x ^ y ^ z ^ w); | |
} | |
static void fota_cipher_set_key(struct fota_cipher_state *ctx, const char *key_data, size_t key_len) { | |
size_t i, n, r; | |
uint8_t seed[32]; | |
uint32_t rdom[4]; | |
uint32_t xdom[8]; | |
uint32_t x, y, z, val; | |
if (key_len > 32) | |
key_len = 32; | |
memset(seed, 0, sizeof(seed)); | |
for (i = 0; i < key_len; i++) | |
seed[i] = key_data[i]; | |
for (i = 0; i < 8; i++) | |
xdom[i] = read32(seed + i * 4); | |
if (key_len <= 16) | |
r = 2; | |
else if (key_len <= 24) | |
r = 3; | |
else | |
r = 4; | |
for (i = 0; i < 20; i++) { | |
x = fota_cipher_x6(r, i * 2, xdom[0], xdom[2], xdom[4], xdom[6]); | |
y = fota_cipher_x6(r, i * 2 + 1, xdom[1], xdom[3], xdom[5], xdom[7]); | |
ctx->x[i * 2] = x + ror32(y, 24); | |
ctx->x[i * 2 + 1] = ror32(ctx->x[i * 2] + ror32(y, 24), 23); | |
} | |
for (i = 0; i < r; i++) { | |
x = xdom[i * 2]; | |
y = xdom[i * 2 + 1]; | |
val = 0; | |
for (n = 0; n < 4; n++) { | |
z = fota_cipher_x3(77, byte0(x), fota_set_key_tbl[n * 8]); | |
z ^= fota_cipher_x3(77, byte1(x), fota_set_key_tbl[n * 8 + 1]); | |
z ^= fota_cipher_x3(77, byte2(x), fota_set_key_tbl[n * 8 + 2]); | |
z ^= fota_cipher_x3(77, byte3(x), fota_set_key_tbl[n * 8 + 3]); | |
z ^= fota_cipher_x3(77, byte0(y), fota_set_key_tbl[n * 8 + 4]); | |
z ^= fota_cipher_x3(77, byte1(y), fota_set_key_tbl[n * 8 + 5]); | |
z ^= fota_cipher_x3(77, byte2(y), fota_set_key_tbl[n * 8 + 6]); | |
z ^= fota_cipher_x3(77, byte3(y), fota_set_key_tbl[n * 8 + 7]); | |
val |= (z << (n * 8)); | |
} | |
rdom[r - i - 1] = val; | |
} | |
for (i = 0; i < 4; i++) { | |
for (n = 0; n < 256; n++) { | |
ctx->d[i][n] = fota_cipher_x7(r, i, n, rdom[0] >> 8 * i, rdom[1] >> 8 * i, rdom[2] >> 8 * i, rdom[3] >> 8 * i); | |
} | |
} | |
} | |
static void fota_cipher_decrypt_block(struct fota_cipher_state *ctx, const uint8_t *data, uint8_t *text, size_t size) { | |
size_t i, n; | |
uint32_t xdata[4]; | |
uint32_t x, y, z, w, p, q; | |
uint32_t a, b, c, d, A, B, C, D; | |
a = 0x8c70bfc7; | |
b = 0xd5f4202f; | |
c = 0x9160e1db; | |
d = 0x79ac7a5f; | |
for (i = 0; i < size; i += 16) { | |
for (n = 0; n < 4; n++) { | |
xdata[n] = read32(data + i + n * 4); | |
} | |
A = xdata[3]; | |
B = xdata[2]; | |
C = xdata[1]; | |
D = xdata[0]; | |
x = xdata[0] ^ ctx->x[4]; | |
y = xdata[1] ^ ctx->x[5]; | |
z = xdata[2] ^ ctx->x[6]; | |
w = xdata[3] ^ ctx->x[7]; | |
n = 0; | |
for (n = 0; n < 32; n += 4) { | |
p = ctx->d[0][byte3(y)] ^ ctx->d[1][byte0(y)] ^ ctx->d[2][byte1(y)] ^ ctx->d[3][byte2(y)]; | |
q = (ctx->d[3][byte3(x)] ^ ctx->d[2][byte2(x)] ^ ctx->d[1][byte1(x)] ^ ctx->d[0][byte0(x)]) + p; | |
z = ror32(z, 31) ^ (ctx->x[38 - n] + q); | |
w = ror32(w ^ (p + q + ctx->x[39 - n]), 1); | |
p = ctx->d[0][byte3(w)] ^ ctx->d[1][byte0(w)] ^ ctx->d[2][byte1(w)] ^ ctx->d[3][byte2(w)]; | |
q = (ctx->d[3][byte3(z)] ^ ctx->d[2][byte2(z)] ^ ctx->d[1][byte1(z)] ^ ctx->d[0][byte0(z)]) + p; | |
x = ror32(x, 31) ^ (ctx->x[36 - n] + q); | |
y = ror32(y ^ (p + q + ctx->x[37 - n]), 1); | |
} | |
xdata[0] = d ^ ctx->x[0] ^ z; | |
xdata[1] = c ^ ctx->x[1] ^ w; | |
xdata[2] = b ^ ctx->x[2] ^ x; | |
xdata[3] = a ^ ctx->x[3] ^ y; | |
for (n = 0; n < 4; n++) { | |
write32(xdata[n], text + n * 4); | |
} | |
a = A; | |
b = B; | |
c = C; | |
d = D; | |
} | |
} | |
static void fota_cipher_decrypt(struct fota_cipher_state *ctx, const uint8_t *data, uint8_t *text, size_t size) { | |
size_t i; | |
if (size & 0xf) { | |
size |= 0xf; | |
size += 1; | |
} | |
for (i = 0; i < size; i += 16) { | |
fota_cipher_decrypt_block(ctx, data + i, text + i, 16); | |
} | |
} | |
static uint32_t fota_adler32(uint32_t adler, const uint8_t *buf, size_t len) { | |
return adler32(adler, buf, len); | |
} | |
static uint32_t fota_crc32(uint32_t crc, const uint8_t *buf, size_t len) { | |
return crc32(crc, buf, len); | |
} | |
static void fota_decode(struct fota_decode_key *dkey, const void *data, void *text, size_t size) { | |
struct fota_decode_key dk, *pkey; | |
size_t n, left; | |
uint32_t i, j, o; | |
uint8_t temp[16]; | |
uint8_t m; | |
uint8_t old; | |
uint8_t x[4][0x20]; | |
uint8_t y[0x20]; | |
uint32_t z[4]; | |
uint32_t a, b, p, q, r, s, H, T; | |
uint32_t val, bit, tmp, xft; | |
dk = *dkey; | |
pkey = &dk; | |
if (size > 0xf) { | |
for (i = 0; i < 4; i++) { | |
for (j = 0; j < 0x20; j++) { | |
x[i][j] = pkey->x[i][j]; | |
} | |
} | |
} else { | |
memset(x, 0, 0x80); | |
} | |
memset(y, 0, 0x20); | |
memset(z, 0, 0x10); | |
p = 0; | |
q = 0; | |
r = 0; | |
s = 0; | |
H = 0; | |
T = 0; | |
for (n = 0; n < (size & 0xfffffff0); n += 16) { | |
if (p == q) { | |
if (T && (T % 256 == 0)) { | |
a = ((H * 3) & 0xff) >> 3; | |
b = (H * 3) & 7; | |
for (i = 0; i < 0x20; i++) { | |
y[i] = (dkey->z[((a + 1 + i) & 0x1f)] >> (8 - b)) | | |
(dkey->z[((a + i) & 0x1f)] << b); | |
} | |
for (i = 0; i < 4; i++) { | |
for (j = 0; j < 0x20; j++) { | |
x[i][j] = dkey->x[i][j] ^ y[j]; | |
} | |
} | |
H += 1; | |
} | |
a = ((T * 3) & 0xff) >> 3; | |
b = (T * 3) & 7; | |
for (i = 0; i < 4; i++) { | |
z[i] = (x[i][((a + 4) & 0x1f)] >> (8 - b)) | | |
(x[i][((a + 3) & 0x1f)] << b) | | |
(((x[i][((a + 2) & 0x1f)] >> (8 - b)) | (x[i][((a + 1) & 0x1f)] << b)) << 16) | | |
(((x[i][((a + 3) & 0x1f)] >> (8 - b)) | (x[i][((a + 2) & 0x1f)] << b)) << 8) | | |
(((x[i][a] << b) | (x[i][((a + 1) & 0x1f)] >> (8 - b))) << 24); | |
} | |
T += 1; | |
} | |
// support in-place decryption | |
memcpy(temp, data + n, 16); | |
for (i = 0, o = 0; i < 16; i += 4, o += 1) { | |
val = (dkey->w[o][temp[i]]) | | |
((dkey->w[o][temp[i + 1]]) << 8) | | |
((dkey->w[o][temp[i + 2]]) << 16) | | |
((dkey->w[o][temp[i + 3]]) << 24); | |
if (p == q) { | |
tmp = 0; | |
for (j = 0; j < 32; j++) { | |
bit = val & 1; | |
xft = pkey->xft32[j]; | |
if (xft >= r) | |
xft -= r; | |
else | |
xft += 32 - r; | |
val >>= 1; | |
tmp |= bit << xft; | |
} | |
val = tmp; | |
} | |
val ^= pkey->state[o] ^ z[o]; | |
write32(val, text + n + i); | |
pkey->state[o] = read32(temp + i); | |
} | |
if (p == q) { | |
r = s & 0x1f; | |
q = p + pkey->n[s] + 1; | |
s = (s + 1) & 0x1f; | |
} | |
p += 1; | |
} | |
left = size & 0xf; | |
if (left) { | |
if (size <= 0xf) { | |
r = 0; | |
m = 0; | |
for (i = 0; i < 16; i++) { | |
m ^= *((uint8_t *) &pkey->state[0] + i); | |
} | |
} else { | |
r = r & 7; | |
m = 0; | |
for (i = 0; i < 16; i++) { | |
m ^= temp[i]; | |
} | |
} | |
for (n = 0; n < left; n++) { | |
old = read8(data + (size & 0xfffffff0) + n); | |
if (!p || p == q) { | |
tmp = old; | |
val = 0; | |
for (i = 0; i < 8; i++) { | |
bit = tmp & 1; | |
xft = dkey->xft8[i]; | |
if (xft >= r) | |
xft -= r; | |
else | |
xft += 8 - r; | |
tmp >>= 1; | |
val |= bit << xft; | |
} | |
r = (r + 1) & 7; | |
} else { | |
val = old; | |
} | |
a = (n * 3) >> 3; | |
b = (n * 3) & 7; | |
write8( | |
((dkey->y[a + 1] >> (8 - b)) + (dkey->y[a] << b)) ^ m ^ dkey->w[4][val], | |
text + (size & 0xfffffff0) + n); | |
m = old; | |
} | |
} | |
} | |
static int fota_info_check(const void *data, size_t size) { | |
if (size < 0x98) | |
return -1; | |
if (memcmp(data + 0x80, "ESUS", 4) && | |
memcmp(data + 0x80, "ASBL", 4)) | |
return -1; | |
if (memcmp(data + 0x88, "NSUS", 4) && | |
memcmp(data + 0x88, "RECV", 4)) | |
return -1; | |
if (memcmp(data + 0x90, "IMAG", 4)) | |
return -1; | |
return 0; | |
} | |
static int fota_info_nr(const void *data, size_t size, const char *str) { | |
int i, f; | |
size_t n; | |
f = 0; | |
i = 0; | |
for (n = 0x80; n < size; n += 8) { | |
if (!memcmp(data + n, str, 4)) { | |
f = 1; | |
break; | |
} | |
i += 1; | |
} | |
return f ? i : -1; | |
} | |
static int file_read_all(const char *path, char **data, size_t *size) { | |
int rc, fd; | |
struct stat fs; | |
size_t nbrd; | |
rc = stat(path, &fs); | |
if (rc) | |
return rc; | |
*size = fs.st_size; | |
*data = malloc(fs.st_size); | |
if (*data == NULL) | |
return -1; | |
fd = open(path, O_RDONLY); | |
if (fd < 0) { | |
free(*data); | |
*data = NULL; | |
return -1; | |
} | |
nbrd = 0; | |
while (nbrd < fs.st_size) { | |
int tmp; | |
tmp = read(fd, *data + nbrd, fs.st_size - nbrd); | |
if (tmp < 0) { | |
if (errno == -EINTR) | |
continue; | |
break; | |
} | |
nbrd += tmp; | |
} | |
close(fd); | |
if (nbrd < fs.st_size) { | |
free(*data); | |
*data = NULL; | |
return -1; | |
} | |
return 0; | |
} | |
static int file_write_all(const char *path, const char *data, size_t size) { | |
int rc, fd; | |
size_t nbwr; | |
fd = open(path, O_CREAT | O_WRONLY, 0644); | |
if (fd < 0) | |
return -1; | |
nbwr = 0; | |
rc = ftruncate(fd, nbwr); | |
if (rc) | |
goto fail_truncate; | |
while (nbwr < size) { | |
int tmp; | |
tmp = write(fd, data + nbwr, size - nbwr); | |
if (tmp < 0) { | |
if (errno == -EINTR) | |
continue; | |
break; | |
} | |
nbwr += tmp; | |
} | |
fail_truncate: | |
close(fd); | |
return nbwr == size ? 0 : -1; | |
} | |
int main(int argc, char *argv[]) { | |
int ret, rc, ch, i, n; | |
size_t file_size; | |
char *file_data; | |
char temp_name[32]; | |
struct fota_hdr *fhdr; | |
char *pbgn, *pend; | |
struct fota_seg *fseg; | |
struct fota_seg_hdr *shdr; | |
size_t off; | |
struct fota_cipher_state fctx; | |
struct fota_keys *fk; | |
int nrdk; | |
int nr_nsus = -1, nr_imag = -1, nr_nsys = -1; | |
size_t count, chunk; | |
uint32_t sum; | |
char *device = NULL, *package = NULL; | |
if (argc < 2) | |
goto exit_usage; | |
while ((ch = getopt(argc, argv, "d:hp:")) != -1) { | |
switch (ch) { | |
case 'd': { | |
device = optarg; | |
break; | |
} | |
case 'p': { | |
package = optarg; | |
break; | |
} | |
case 'h': | |
default: { | |
exit_usage: | |
fprintf(stderr, "Usage:\n"); | |
fprintf(stderr, "%s -d <device> -p <package>\n", argv[0]); | |
fprintf(stderr, "Switches:\n"); | |
fprintf(stderr, "-d <device> // e.g., SH-04F\n"); | |
fprintf(stderr, "-p <package> // path/to/FOTA\n"); | |
return 1; | |
} | |
} | |
} | |
if (device == NULL || package == NULL) { | |
goto exit_usage; | |
} | |
for (i = 0; i < NELEM(all_supported_devices) - 1; i++) { | |
fk = &all_supported_devices[i]; | |
if (!strcasecmp(fk->device, device)) | |
break; | |
} | |
if (fk->device == NULL) { | |
fprintf(stderr, "Unknown device `%s\'.\n", device); | |
return 1; | |
} | |
rc = file_read_all(package, &file_data, &file_size); | |
if (rc) | |
return 1; | |
if (file_size < 64) { | |
fprintf(stderr, "Invalid FOTA size.\n"); | |
return 1; | |
} | |
fhdr = (struct fota_hdr *) file_data; | |
if (memcmp(fhdr->magic, "SHFOTA", 6)) { | |
fprintf(stderr, "Invalid FOTA header(magic).\n"); | |
return 1; | |
} | |
if (file_size - 8 != fhdr->body_size) { | |
fprintf(stderr, "Invalid FOTA header(body_size).\n"); | |
return 1; | |
} | |
if (!fhdr->info_size || | |
fhdr->info_size > 8 * (fhdr->nsegs + 23) || | |
fhdr->info_size > 0x898) { | |
fprintf(stderr, "Invalid FOTA header(info_size).\n"); | |
return 1; | |
} | |
sum = fota_adler32(0, (uint8_t *)(file_data + 8), fhdr->body_size); | |
if (sum != fhdr->body_crc) { | |
fprintf(stderr, "Invalid FOTA header(body_crc).\n"); | |
return 1; | |
} | |
sum = fota_adler32(0, (uint8_t *)(file_data + sizeof(struct fota_hdr)), fhdr->info_size); | |
if (sum != fhdr->info_crc) { | |
fprintf(stderr, "Invalid FOTA header(info_crc).\n"); | |
return 1; | |
} | |
ret = 1; | |
pbgn = file_data + sizeof(struct fota_hdr); | |
pend = file_data + file_size; | |
for (i = 0; i < fhdr->nsegs; i++) { | |
// | |
sum = 0; | |
fseg = (struct fota_seg *) pbgn; | |
// | |
if (!fseg->encrypted_flag) { | |
fprintf(stderr, "SEG #%02d: Invalid FOTA SEG(encrypted_flag).\n", i); | |
break; | |
} | |
// | |
if (i == 0) { | |
fota_cipher_set_key(&fctx, fk->akey, strlen(fk->akey)); | |
fota_cipher_decrypt(&fctx, fseg->data, fseg->data, fseg->encrypted_size); | |
fota_decode(&fk->dkey[NR_DKEY_INFO], fseg->data, fseg->data, fseg->encrypted_size); | |
rc = fota_info_check(fseg->data, fseg->decrypted_size); | |
if (rc) { | |
fprintf(stderr, "Invalid FOTA info.\n"); | |
break; | |
} | |
nr_nsus = fota_info_nr(fseg->data, fseg->decrypted_size, "NSUS"); | |
nr_imag = fota_info_nr(fseg->data, fseg->decrypted_size, "IMAG"); | |
nr_nsys = fota_info_nr(fseg->data, fseg->decrypted_size, "NSYS"); | |
} else { | |
nrdk = -1; | |
if (i == nr_imag) { | |
nrdk = NR_DKEY_IMAG; | |
} else if (i == nr_nsys) { | |
nrdk = NR_DKEY_NSYS; | |
} else { | |
fprintf(stderr, "SEG #%02d: fix me!!!\n", i); | |
} | |
if (nrdk >= 0) { | |
count = 0; | |
while (count < fseg->encrypted_size) { | |
chunk = fseg->encrypted_size - count; | |
if (chunk > 0x20000) | |
chunk = 0x20000; | |
fota_decode(&fk->dkey[nrdk], fseg->data + count, fseg->data + count, chunk); | |
count += chunk; | |
} | |
} | |
} | |
sum = fota_adler32(0, fseg->data, fseg->encrypted_size); | |
if (1) { | |
fprintf(stderr, "======== SEG #%02d ========\n", i); | |
fprintf(stderr, "File Offset: %08x\n", (int)(pbgn - file_data)); | |
fprintf(stderr, "Encrypted Flag: %d\n", fseg->encrypted_flag); | |
fprintf(stderr, "Encrypted Size: %08x\n", (int) fseg->encrypted_size); | |
fprintf(stderr, "Decrypted Size: %08x\n", (int) fseg->decrypted_size); | |
fprintf(stderr, "Expected CRC: %08x\n", (int) fseg->decrypted_crc); | |
fprintf(stderr, "Calculated CRC: %08x\n", (int) sum); | |
fprintf(stderr, "======== END #%02d ========\n", i); | |
} | |
if (sum != fseg->decrypted_crc) { | |
// break; | |
} | |
if (i == nr_nsys) { | |
n = 0; | |
off = 0; | |
for (;;) { | |
shdr = (struct fota_seg_hdr *)(fseg->data + off); | |
if (shdr->upi_ver != 0x00014050) { | |
fprintf(stderr, "SEG #%02d: %02d upi_ver %08x != %08x\n", i, n, shdr->upi_ver, 0x00014050); | |
break; | |
} | |
if (shdr->scout_ver != 0x00013880) { | |
fprintf(stderr, "SEG #%02d: %02d scout_ver %08x != %08x\n", i, n, shdr->scout_ver, 0x00013880); | |
break; | |
} | |
sum = fota_crc32(0, ((uint8_t *) shdr) + 4, shdr->size - 4); | |
if (sum != shdr->crc) { | |
fprintf(stderr, "SEG #%02d: %02d crc %08x != %08x\n", i, n, shdr->crc, sum); | |
break; | |
} | |
// FIXME: | |
if (n == 0) { | |
lzmadec_info li; | |
uint8_t *tmp; | |
void *x; | |
size_t l; | |
tmp = (uint8_t *)(shdr) + sizeof(*shdr) + | |
4 * (shdr->files_field_2c + 2 * shdr->files_diff + shdr->files_opt); | |
rc = lzmadec_buffer_info(&li, tmp, (uint8_t *)(shdr) + shdr->size - tmp); | |
l = li.uncompressed_size; | |
x = malloc(li.uncompressed_size); | |
lzmadec_buffer(x, &l, tmp, shdr->index_size); | |
file_write_all("fota_index.bin", x, l); | |
free(x); | |
} | |
n += 1; | |
off += shdr->size; | |
#if 0 | |
if (off & 3) { | |
off |= 3; | |
off += 1; | |
} | |
#endif | |
if (fseg->decrypted_size <= off) | |
break; | |
} | |
} | |
// | |
if (1) { | |
sprintf(temp_name, "fota_%02d.bin", i); | |
file_write_all(temp_name, (const char *) fseg->data, fseg->encrypted_size); | |
} | |
// | |
pbgn += sizeof(struct fota_seg) + fseg->encrypted_size; | |
if (pbgn > pend) { | |
fprintf(stderr, "Unexpected FOTA end.\n"); | |
break; | |
} | |
} | |
if (pbgn == pend && (i == fhdr->nsegs)) { | |
ret = 0; | |
} | |
if (file_data) | |
free(file_data); | |
return ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment