├── .gitignore ├── Makefile ├── crypto.h ├── keymgr.h ├── hmac-sha1.h ├── nvs.c ├── slb2.h ├── nvs.h ├── flashtool.h ├── README.md ├── keymgr.c ├── simplegpt.py ├── aes.h ├── sha1.h ├── hmac-sha1.c ├── southbridge.h ├── sha1.c ├── flashtool.c ├── southbridge.c ├── aes.c └── crypto.c /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .vscode 3 | *.o 4 | flashtool 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # golden 2 | 3 | ODIR := build 4 | CFLAGS := -I/usr/include/ 5 | CFILES := $(wildcard *.c) 6 | OBJS := $(patsubst %.c, build/%.o, $(CFILES)) 7 | LIBS := 8 | 9 | TARGET = flashtool 10 | 11 | $(TARGET): $(ODIR) $(OBJS) 12 | gcc -g -o $(TARGET) $(ODIR)/*.o $(CFLAGS) $(LIBS) 13 | 14 | $(ODIR)/%.o: %.c 15 | gcc -g -c -o $@ $< $(CFLAGS) 16 | 17 | $(ODIR): 18 | @mkdir $@ 19 | 20 | .PHONY: clean 21 | clean: 22 | rm -f $(TARGET) build/* 23 | -------------------------------------------------------------------------------- /crypto.h: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #ifndef _CRYPTO_H 4 | #define _CRYPTO_H 5 | 6 | #include "flashtool.h" 7 | 8 | int aes128_cbc_encrypt(void *key, void *plaintext, void *ciphertext, int length, void *iv); 9 | int aes128_cbc_decrypt(void *key, void *ciphertext, void *plaintext, int length, void *iv); 10 | 11 | int aes128_cbc_iv_zero_encrypt(void *key, void *plaintext, void *ciphertext, int length); 12 | int aes128_cbc_iv_zero_decrypt(void *key, void *ciphertext, void *plaintext, int length); 13 | 14 | // credits to team molecule here, even though its a C+P from IDA lol 15 | int arzl_decompress(unsigned char *buffer, unsigned int buflen, const unsigned char *input, const unsigned char **endptr); 16 | int arzl_deobfuscate(unsigned char *buffer, int len, int version); 17 | 18 | #endif /* _CRYPTO_H */ 19 | -------------------------------------------------------------------------------- /keymgr.h: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #ifndef _KEYMGR_H 4 | #define _KEYMGR_H 5 | 6 | #include "flashtool.h" 7 | 8 | #define MAXIMUM_KEYS 4096 9 | 10 | /* 11 | ... key file format ... 12 | (all fields are little endian) 13 | numkeys - 32 bit integer 14 | [ 15 | keynamelen - 32 bit integer 16 | keyname - ASCII data for keynamelen 17 | keytype - 32 bit integer 18 | keydatalen - 32 bit integer 19 | keydata - raw key data for keydatalen 20 | ] foreach i in range(numkeys) 21 | */ 22 | 23 | #define KEY_TYPE_AES_128 0xA1 24 | #define KEY_TYPE_AES_192 0xA2 25 | #define KEY_TYPE_AES_256 0xA3 26 | 27 | #define KEY_TYPE_HMAC_SHA1 0xB1 28 | #define KEY_TYPE_RSA_2048_PRIV 0xB2 29 | #define KEY_TYPE_RSA_2048_PUB 0xB3 30 | #define KEY_TYPE_RSA_4096_PRIV 0xB2 31 | #define KEY_TYPE_RSA_4096_PUB 0xB3 32 | 33 | struct keymgr_state { 34 | char **keynames; 35 | int *keytypes; 36 | unsigned char **keydata; 37 | unsigned char *filedata; 38 | int numkeys; 39 | }; 40 | 41 | extern struct keymgr_state kmgrstate; 42 | 43 | int keymgr_loadkeys(const char *keyfile); 44 | void keymgr_cleanup(); 45 | void keymgr_printkeys(); 46 | unsigned char *keymgr_getkey(const char *keyname, int keytype); 47 | 48 | #endif /* _KEYMGR_H */ 49 | -------------------------------------------------------------------------------- /hmac-sha1.h: -------------------------------------------------------------------------------- 1 | /* hmac.h -- hashed message authentication codes 2 | Copyright (C) 2005 Free Software Foundation, Inc. 3 | This program is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; either version 2, or (at your option) 6 | any later version. 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with this program; if not, write to the Free Software Foundation, 13 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 14 | 15 | /* Written by Simon Josefsson. */ 16 | 17 | #ifndef HMAC_H 18 | # define HMAC_H 1 19 | 20 | #include 21 | 22 | /* Compute Hashed Message Authentication Code with SHA-1, over BUFFER 23 | data of BUFLEN bytes using the KEY of KEYLEN bytes, writing the 24 | output to pre-allocated 20 byte minimum RESBUF buffer. Return 0 on 25 | success. */ 26 | int 27 | hmac_sha1 (const void *key, size_t keylen, 28 | const void *in, size_t inlen, void *resbuf); 29 | 30 | #endif /* HMAC_H */ 31 | -------------------------------------------------------------------------------- /nvs.c: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #include "nvs.h" 4 | 5 | int nvs_read(unsigned char *flashdata, unsigned int bank, unsigned int block, unsigned int offset, int size, unsigned char *buffer) { 6 | if(bank != 0) { 7 | printf("error: invalid NVS bank number %i\n", bank); 8 | return 1; 9 | } 10 | 11 | if(block > 4) { 12 | printf("error: invalid NVS block number %i\n", block); 13 | return 1; 14 | } 15 | 16 | if(offset >= g_nvs_block_sizes[block]) { 17 | printf("error: invalid NVS offset 0x%X\n", offset); 18 | return 1; 19 | } 20 | 21 | memcpy(buffer, flashdata + g_nvs_block_offsets[block] + offset, size); 22 | 23 | return 0; 24 | } 25 | 26 | int nvs_write(unsigned char *flashdata, unsigned int bank, unsigned int block, unsigned int offset, int size, unsigned char *buffer) { 27 | if(bank != 0) { 28 | printf("error: invalid NVS bank number %i\n", bank); 29 | return 1; 30 | } 31 | 32 | if(block > 4) { 33 | printf("error: invalid NVS block number %i\n", block); 34 | return 1; 35 | } 36 | 37 | if(offset >= g_nvs_block_sizes[block]) { 38 | printf("error: invalid NVS offset 0x%X\n", offset); 39 | return 1; 40 | } 41 | 42 | memcpy(flashdata + g_nvs_block_offsets[block] + offset, buffer, size); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /slb2.h: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #ifndef _SLB2_H 4 | #define _SLB2_H 5 | 6 | // credits to skfu and iqd 7 | 8 | #include "flashtool.h" 9 | 10 | #define SLB2_MAGIC 0x32424C53 11 | 12 | struct slb2_entry { 13 | unsigned int block_offset; 14 | unsigned int file_size; 15 | unsigned int alignment[2]; 16 | char file_name[32]; 17 | } __attribute__((packed)); 18 | 19 | struct slb2_header { 20 | unsigned int magic; 21 | unsigned int version; 22 | unsigned int flags; 23 | unsigned int file_count; 24 | unsigned int block_count; 25 | unsigned int reserved[3]; 26 | struct slb2_entry entry_list[0]; 27 | } __attribute__((packed)); 28 | 29 | static void find_and_print_slb2_info(unsigned char *flashdata) { 30 | struct slb2_header *hdr; 31 | struct slb2_entry *entry; 32 | unsigned char *ptr; 33 | int i, k; 34 | 35 | ptr = (unsigned char *)flashdata; 36 | 37 | while(ptr < (unsigned char *)(flashdata + 0x2000000)) { 38 | if(*(unsigned int *)ptr == SLB2_MAGIC) { 39 | hdr = (struct slb2_header *)ptr; 40 | 41 | printf("* found slb2_header at 0x%llX\n", (unsigned long long)(ptr - flashdata)); 42 | 43 | for(k = 0; k < hdr->file_count; k++) { 44 | entry = &hdr->entry_list[k]; 45 | printf("\tfile_name: %s block_offset: 0x%X file_size 0x%X\n", entry->file_name, entry->block_offset, entry->file_size); 46 | } 47 | } 48 | 49 | ptr += 4; 50 | } 51 | 52 | printf("\n"); 53 | } 54 | 55 | #endif /* _SLB2_H */ 56 | -------------------------------------------------------------------------------- /nvs.h: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #ifndef _NVS_H 4 | #define _NVS_H 5 | 6 | #include "flashtool.h" 7 | 8 | // bank 0 and 1 9 | // bank 1 is the backup bank 10 | 11 | // bank 0 block offsets 12 | #define FLASH_BANK0_BLOCK0_OFFSET 0x1C4000 13 | #define FLASH_BANK0_BLOCK1_OFFSET 0x1C7000 14 | #define FLASH_BANK0_BLOCK2_OFFSET 0x1C8000 15 | #define FLASH_BANK0_BLOCK3_OFFSET 0x1C8800 16 | #define FLASH_BANK0_BLOCK4_OFFSET 0x1C9000 17 | static unsigned int g_nvs_block_offsets[5] = { 0x1C4000, 0x1C7000, 0x1C8000, 0x1C8800, 0x1C9000 }; 18 | 19 | // bank 0 block sizes 20 | #define FLASH_BANK0_BLOCK0_SIZE 0x3000 21 | #define FLASH_BANK0_BLOCK1_SIZE 0x1000 22 | #define FLASH_BANK0_BLOCK2_SIZE 0x800 23 | #define FLASH_BANK0_BLOCK3_SIZE 0x800 24 | #define FLASH_BANK0_BLOCK4_SIZE 0x3000 25 | static unsigned int g_nvs_block_sizes[5] = { 0x3000, 0x1000, 0x800, 0x800, 0x3000 }; 26 | 27 | // known NVS variables 28 | #define NVS_VAR_BLOCK0_MAC_ADDRESS 0x21 29 | #define NVS_VAR_BLOCK2_CONSOLE_INF0 0 30 | #define NVS_VAR_BLOCK4_ENABLE_UART 0x31F 31 | 32 | // variable structures 33 | struct nvs_console_info { 34 | char moboserial[14]; 35 | char _fill1[0x22]; 36 | char serial[10]; 37 | char _fill2[7]; 38 | char model[13]; 39 | } __attribute__((packed)); 40 | 41 | int nvs_read(unsigned char *flashdata, unsigned int bank, unsigned int block, unsigned int offset, int size, unsigned char *buffer); 42 | int nvs_write(unsigned char *flashdata, unsigned int bank, unsigned int block, unsigned int offset, int size, unsigned char *buffer); 43 | 44 | #endif /* _NVS_H */ 45 | -------------------------------------------------------------------------------- /flashtool.h: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #ifndef _FLASHTOOL_H 4 | #define _FLASHTOOL_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "aes.h" 14 | #include "sha1.h" 15 | #include "hmac-sha1.h" 16 | #include "crypto.h" 17 | #include "keymgr.h" 18 | 19 | #include "slb2.h" 20 | #include "nvs.h" 21 | #include "southbridge.h" 22 | 23 | #define FLASHTOOL_VERSION "v1.0" 24 | #define FLASHTOOL_CREDITS "golden" 25 | #define FLASHTOOL_KEYFILE "keyfile.bin" 26 | 27 | #define FLASH_BLOCK_SIZE 0x200 28 | #define FLASH_SIZE 0x2000000 29 | #define FLASH_NUMBLOCKS (FLASH_SIZE / FLASH_BLOCK_SIZE) 30 | 31 | #define MIN(a,b) (((a)<(b))?(a):(b)) 32 | #define MAX(a,b) (((a)>(b))?(a):(b)) 33 | 34 | struct consolemap_entry { 35 | char *model; // model sometimes has a component like B01 or B01X, leave that off 36 | char *southbridge; 37 | //char *keyfile; 38 | }; 39 | 40 | struct codename_entry { 41 | char *codename; 42 | char *realname; 43 | char *comment; 44 | }; 45 | 46 | extern int verbose; 47 | extern int noverify; 48 | extern struct consolemap_entry g_consolemap[]; 49 | extern struct codename_entry g_codenames[]; 50 | 51 | #define NUM_CONSOLES (sizeof(g_consolemap) / sizeof(g_consolemap[0])) 52 | #define NUM_CODENAMES (sizeof(g_codenames) / sizeof(g_codenames[0])) 53 | 54 | struct consolemap_entry *find_consolemap(char *model); 55 | struct codename_entry *find_codename(char *codename); 56 | 57 | void hexdump(unsigned char *data, int length, int newlines); 58 | int dumpbin(unsigned char *filename, unsigned char *data, int length); 59 | 60 | #endif /* _FLASHTOOL_H */ 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### PlayStation 4 Flash Tool by golden 2 | 3 | ``` 4 | ~ PlayStation 4 flash tool v1.0 | by golden ~ 5 | Usage: flashtool [option(s)] 6 | Examples: 7 | flashtool --extract dumps -i flashdump.bin 8 | flashtool --emcipl patchedipl.bin -k CXD44G.keys --input flashdump.bin --output flashout.bin 9 | flashtool --eapkbl patchedkbl.bin -k cec_h4x_sram_dmp_CXD36G.keys --input flashdump.bin --output flashout.bin 10 | flashtool -k CXD42G.keys -v -n --input flashdump.bin 11 | flashtool --extract dumps -n --input flashdump.bin 12 | flashtool --eapkern eapkern_hdd_enc.bin,eapkern_hdd_dec.bin 13 | Options: 14 | -h, --help show this help message 15 | -v, --verbose verbose output 16 | -i [flash], --input [flash] flash file input 17 | -o [flash], --output [flash] flash file output 18 | -n, --noverify do not verify the flash signatures 19 | -k, --keyfile override the default key file 20 | --extract [dir] extract files to directory 21 | --emcipl [emcipl] replace EMC IPL (initial program loader) 22 | --eapkbl [eapkbl] replace EAP KBL (kernel boot loader) 23 | --eapkern [input,output] decrypt the EAP kernel 24 | 25 | Everything you can replace in the flash is resigned when you replace it. 26 | Also, when the extract option is enabled, the files will be extracted after the replacement/resigning. 27 | !! This tool will never overwrite your existing flash dump file! You must specify an output. !! 28 | ``` 29 | 30 | __This release includes no keys and I will never release keys.__ 31 | 32 | You must create your own keyfile if you have keys. Look at `keymgr.h` for the format. 33 | Look at the fail0verflow article if you want to try and derive the keys yourself. 34 | There may be some bugs with this release. 35 | 36 | Shoutout to Team Molecule for ARZL decompress, zecoxao for some NVS information on the wiki, SKFU and iqd for SLB2, and many anonymous contributors! 37 | -------------------------------------------------------------------------------- /keymgr.c: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #include "keymgr.h" 4 | 5 | struct keymgr_state kmgrstate; 6 | 7 | int keymgr_loadkeys(const char *keyfile) { 8 | FILE *fkeyfile; 9 | long filesize; 10 | unsigned char *ptr; 11 | int i; 12 | int sz; 13 | 14 | fkeyfile = fopen(keyfile, "rb"); 15 | if(!fkeyfile) { 16 | printf("keymgr: invalid key file!\n"); 17 | return 1; 18 | } 19 | 20 | kmgrstate.keynames = (char **)malloc(MAXIMUM_KEYS * sizeof(char *)); 21 | kmgrstate.keytypes = (int *)malloc(MAXIMUM_KEYS * sizeof(int)); 22 | kmgrstate.keydata = (unsigned char **)malloc(MAXIMUM_KEYS * sizeof(char *)); 23 | 24 | fseek(fkeyfile, 0, SEEK_END); 25 | filesize = ftell(fkeyfile); 26 | fseek(fkeyfile, 0, SEEK_SET); 27 | 28 | kmgrstate.filedata = (char *)malloc(filesize); 29 | fread(kmgrstate.filedata, 1, filesize, fkeyfile); 30 | fclose(fkeyfile); 31 | 32 | // parse all the keys 33 | ptr = kmgrstate.filedata; 34 | kmgrstate.numkeys = *(unsigned int *)ptr; 35 | ptr += 4; 36 | 37 | for(i = 0; i < kmgrstate.numkeys; i++) { 38 | // name 39 | sz = *(unsigned int *)ptr; ptr += 4; 40 | kmgrstate.keynames[i] = ptr; ptr += sz; 41 | 42 | // keytype 43 | kmgrstate.keytypes[i] = *(unsigned int *)ptr; ptr += 4; 44 | 45 | // keydat 46 | sz = *(unsigned int *)ptr; ptr += 4; 47 | kmgrstate.keydata[i] = ptr; ptr += sz; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | void keymgr_cleanup() { 54 | if(kmgrstate.keynames) { 55 | free(kmgrstate.keynames); 56 | } 57 | 58 | if(kmgrstate.keytypes) { 59 | free(kmgrstate.keytypes); 60 | } 61 | 62 | if(kmgrstate.keydata) { 63 | free(kmgrstate.keydata); 64 | } 65 | 66 | if(kmgrstate.filedata) { 67 | free(kmgrstate.filedata); 68 | } 69 | } 70 | 71 | void keymgr_printkeys() { 72 | int i; 73 | 74 | printf("\nkey manager state:\n"); 75 | for(i = 0; i < kmgrstate.numkeys; i++) { 76 | printf("\tname: '%s' keytype: 0x%X\n", kmgrstate.keynames[i], kmgrstate.keytypes[i]); 77 | //hexdump(kmgrstate.keydata[i], 0x10); 78 | } 79 | printf("\n"); 80 | } 81 | 82 | unsigned char *keymgr_getkey(const char *keyname, int keytype) { 83 | int i; 84 | 85 | for(i = 0; i < kmgrstate.numkeys; i++) { 86 | if(!strcmp(kmgrstate.keynames[i], keyname) && kmgrstate.keytypes[i] == keytype) { 87 | return kmgrstate.keydata[i]; 88 | } 89 | } 90 | 91 | return NULL; 92 | } 93 | -------------------------------------------------------------------------------- /simplegpt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import collections 4 | import struct 5 | import sys 6 | import uuid 7 | 8 | # TODO use zlib.crc32 9 | 10 | # http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_table_header_.28LBA_1.29 11 | GPT_HEADER_FORMAT = """ 12 | 8s signature 13 | 4s revision 14 | L header_size 15 | L crc32 16 | 4x _ 17 | Q current_lba 18 | Q backup_lba 19 | Q first_usable_lba 20 | Q last_usable_lba 21 | 16s disk_guid 22 | Q part_entry_start_lba 23 | L num_part_entries 24 | L part_entry_size 25 | L crc32_part_array 26 | """ 27 | 28 | # http://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries_.28LBA_2.E2.80.9333.29 29 | GPT_PARTITION_FORMAT = """ 30 | 16s type 31 | 16s unique 32 | Q first_lba 33 | Q last_lba 34 | Q flags 35 | 72s name 36 | """ 37 | 38 | def _make_fmt(name, format, extras=[]): 39 | type_and_name = [l.split(None, 1) for l in format.strip().splitlines()] 40 | fmt = ''.join(t for (t,n) in type_and_name) 41 | fmt = '<'+fmt 42 | tupletype = collections.namedtuple(name, [n for (t,n) in type_and_name if n!='_']+extras) 43 | return (fmt, tupletype) 44 | 45 | class GPTError(Exception): 46 | pass 47 | 48 | def read_header(fp, lba_size=512): 49 | # skip MBR 50 | fp.seek(1*lba_size) 51 | fmt, GPTHeader = _make_fmt('GPTHeader', GPT_HEADER_FORMAT) 52 | data = fp.read(struct.calcsize(fmt)) 53 | header = GPTHeader._make(struct.unpack(fmt, data)) 54 | if header.signature != 'EFI PART': 55 | raise GPTError('Bad signature: %r' % header.signature) 56 | if header.revision != '\x00\x00\x01\x00': 57 | raise GPTError('Bad revision: %r' % header.revision) 58 | if header.header_size < 92: 59 | raise GPTError('Bad header size: %r' % header.header_size) 60 | # TODO check crc32 61 | header = header._replace( 62 | disk_guid=str(uuid.UUID(bytes_le=header.disk_guid)), 63 | ) 64 | return header 65 | 66 | def read_partitions(fp, header, lba_size=512): 67 | fp.seek(header.part_entry_start_lba * lba_size) 68 | fmt, GPTPartition = _make_fmt('GPTPartition', GPT_PARTITION_FORMAT, extras=['index']) 69 | for idx in xrange(1, 1+header.num_part_entries): 70 | data = fp.read(header.part_entry_size) 71 | if len(data) < struct.calcsize(fmt): 72 | raise GPTError('Short partition entry') 73 | part = GPTPartition._make(struct.unpack(fmt, data) + (idx,)) 74 | if part.type == 16*'\x00': 75 | continue 76 | part = part._replace( 77 | type=str(uuid.UUID(bytes_le=part.type)), 78 | unique=str(uuid.UUID(bytes_le=part.unique)), 79 | # do C-style string termination; otherwise you'll see a 80 | # long row of NILs for most names 81 | name=part.name.decode('utf-16').split('\0', 1)[0], 82 | ) 83 | yield part 84 | 85 | if __name__ == '__main__': 86 | header = read_header(sys.stdin) 87 | for part in read_partitions(sys.stdin, header): 88 | print part 89 | -------------------------------------------------------------------------------- /aes.h: -------------------------------------------------------------------------------- 1 | #ifndef _AES_H_ 2 | #define _AES_H_ 3 | 4 | #include 5 | 6 | // #define the macros below to 1/0 to enable/disable the mode of operation. 7 | // 8 | // CBC enables AES encryption in CBC-mode of operation. 9 | // CTR enables encryption in counter-mode. 10 | // ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. 11 | 12 | // The #ifndef-guard allows it to be configured before #include'ing or at compile time. 13 | #ifndef CBC 14 | #define CBC 1 15 | #endif 16 | 17 | #ifndef ECB 18 | #define ECB 1 19 | #endif 20 | 21 | #ifndef CTR 22 | #define CTR 0 23 | #endif 24 | 25 | 26 | #define AES128 1 27 | //#define AES192 1 28 | //#define AES256 1 29 | 30 | #define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only 31 | 32 | #if defined(AES256) && (AES256 == 1) 33 | #define AES_KEYLEN 32 34 | #define AES_keyExpSize 240 35 | #elif defined(AES192) && (AES192 == 1) 36 | #define AES_KEYLEN 24 37 | #define AES_keyExpSize 208 38 | #else 39 | #define AES_KEYLEN 16 // Key length in bytes 40 | #define AES_keyExpSize 176 41 | #endif 42 | 43 | struct AES_ctx 44 | { 45 | uint8_t RoundKey[AES_keyExpSize]; 46 | #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) 47 | uint8_t Iv[AES_BLOCKLEN]; 48 | #endif 49 | }; 50 | 51 | void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); 52 | #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) 53 | void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); 54 | void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); 55 | #endif 56 | 57 | #if defined(ECB) && (ECB == 1) 58 | // buffer size is exactly AES_BLOCKLEN bytes; 59 | // you need only AES_init_ctx as IV is not used in ECB 60 | // NB: ECB is considered insecure for most uses 61 | void AES_ECB_encrypt(struct AES_ctx* ctx, uint8_t* buf); 62 | void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf); 63 | 64 | #endif // #if defined(ECB) && (ECB == !) 65 | 66 | 67 | #if defined(CBC) && (CBC == 1) 68 | // buffer size MUST be mutile of AES_BLOCKLEN; 69 | // Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme 70 | // NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() 71 | // no IV should ever be reused with the same key 72 | void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); 73 | void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); 74 | 75 | #endif // #if defined(CBC) && (CBC == 1) 76 | 77 | 78 | #if defined(CTR) && (CTR == 1) 79 | 80 | // Same function for encrypting as for decrypting. 81 | // IV is incremented for every block, and used after encryption as XOR-compliment for output 82 | // Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme 83 | // NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() 84 | // no IV should ever be reused with the same key 85 | void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); 86 | 87 | #endif // #if defined(CTR) && (CTR == 1) 88 | 89 | 90 | #endif //_AES_H_ 91 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* Declarations of functions and data types used for SHA1 sum 2 | library functions. 3 | Copyright (C) 2000, 2001, 2003, 2005, 2006, 2008 4 | Free Software Foundation, Inc. 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of the GNU General Public License as published by the 8 | Free Software Foundation; either version 2, or (at your option) any 9 | later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software Foundation, 18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 19 | 20 | #ifndef SHA1_H 21 | # define SHA1_H 1 22 | 23 | # include 24 | # include 25 | 26 | #define SHA1_DIGEST_SIZE 20 27 | 28 | /* Structure to save state of computation between the single steps. */ 29 | struct sha1_ctx 30 | { 31 | uint32_t A; 32 | uint32_t B; 33 | uint32_t C; 34 | uint32_t D; 35 | uint32_t E; 36 | 37 | uint32_t total[2]; 38 | uint32_t buflen; 39 | uint32_t buffer[32]; 40 | }; 41 | 42 | 43 | /* Initialize structure containing state of computation. */ 44 | extern void sha1_init_ctx (struct sha1_ctx *ctx); 45 | 46 | /* Starting with the result of former calls of this function (or the 47 | initialization function update the context for the next LEN bytes 48 | starting at BUFFER. 49 | It is necessary that LEN is a multiple of 64!!! */ 50 | extern void sha1_process_block (const void *buffer, size_t len, 51 | struct sha1_ctx *ctx); 52 | 53 | /* Starting with the result of former calls of this function (or the 54 | initialization function update the context for the next LEN bytes 55 | starting at BUFFER. 56 | It is NOT required that LEN is a multiple of 64. */ 57 | extern void sha1_process_bytes (const void *buffer, size_t len, 58 | struct sha1_ctx *ctx); 59 | 60 | /* Process the remaining bytes in the buffer and put result from CTX 61 | in first 20 bytes following RESBUF. The result is always in little 62 | endian byte order, so that a byte-wise output yields to the wanted 63 | ASCII representation of the message digest. */ 64 | extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); 65 | 66 | 67 | /* Put result from CTX in first 20 bytes following RESBUF. The result is 68 | always in little endian byte order, so that a byte-wise output yields 69 | to the wanted ASCII representation of the message digest. */ 70 | extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); 71 | 72 | 73 | /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The 74 | result is always in little endian byte order, so that a byte-wise 75 | output yields to the wanted ASCII representation of the message 76 | digest. */ 77 | extern void *sha1_buffer (const char *buffer, size_t len, void *resblock); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /hmac-sha1.c: -------------------------------------------------------------------------------- 1 | /* hmac-sha1.c -- hashed message authentication codes 2 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2, or (at your option) 7 | any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software Foundation, 16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 17 | 18 | /* Written by Simon Josefsson. */ 19 | 20 | /* #include */ 21 | 22 | #include "hmac-sha1.h" 23 | #include "sha1.h" 24 | 25 | #include 26 | 27 | #define IPAD 0x36 28 | #define OPAD 0x5c 29 | 30 | void * 31 | memxor (void */*restrict*/ dest, const void */*restrict*/ src, size_t n) 32 | { 33 | char const *s = (char const*)src; 34 | char *d = (char*)dest; 35 | 36 | for (; n > 0; n--) 37 | *d++ ^= *s++; 38 | 39 | return dest; 40 | } 41 | 42 | /*! 43 | * @fn int hmac_sha1 (const void *key, size_t keylen, const void *in, size_t inlen, void *resbuf) 44 | * 45 | * @brief Compute Hashed Message Authentication Code with SHA-1 46 | * 47 | * @details Compute Hashed Message Authentication Code with SHA-1, over IN 48 | * data of INLEN bytes using the KEY of KEYLEN bytes, writing the 49 | * output to pre-allocated 20 byte minimum RESBUF buffer. Return 0 on 50 | * success 51 | * 52 | * @param[in] key key used to create the HMAC 53 | * @param[in] keylen length of key 54 | * @param[in] in input data to be hashed 55 | * @param[in] inlen length of input data 56 | * @param[out] resbuf buffer used to store resulting HMAC 57 | * @return 0 on success 58 | */ 59 | 60 | int 61 | hmac_sha1 (const void *key, size_t keylen, 62 | const void *in, size_t inlen, void *resbuf) 63 | { 64 | struct sha1_ctx inner; 65 | struct sha1_ctx outer; 66 | char optkeybuf[20]; 67 | char block[64]; 68 | char innerhash[20]; 69 | 70 | /* Reduce the key's size, so that it becomes <= 64 bytes large. */ 71 | 72 | if (keylen > 64) 73 | { 74 | struct sha1_ctx keyhash; 75 | 76 | sha1_init_ctx (&keyhash); 77 | sha1_process_bytes (key, keylen, &keyhash); 78 | sha1_finish_ctx (&keyhash, optkeybuf); 79 | 80 | key = optkeybuf; 81 | keylen = 20; 82 | } 83 | 84 | /* Compute INNERHASH from KEY and IN. */ 85 | 86 | sha1_init_ctx (&inner); 87 | 88 | memset (block, IPAD, sizeof (block)); 89 | memxor (block, key, keylen); 90 | 91 | sha1_process_block (block, 64, &inner); 92 | sha1_process_bytes (in, inlen, &inner); 93 | 94 | sha1_finish_ctx (&inner, innerhash); 95 | 96 | /* Compute result from KEY and INNERHASH. */ 97 | 98 | sha1_init_ctx (&outer); 99 | 100 | memset (block, OPAD, sizeof (block)); 101 | memxor (block, key, keylen); 102 | 103 | sha1_process_block (block, 64, &outer); 104 | sha1_process_bytes (innerhash, 20, &outer); 105 | 106 | sha1_finish_ctx (&outer, resbuf); 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /southbridge.h: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #ifndef _SOUTHBRIDGE_H 4 | #define _SOUTHBRIDGE_H 5 | 6 | #include "flashtool.h" 7 | 8 | // emc bootrom spits the string '0x86000003' on uart when there is an error with the flash? 9 | 10 | // These are all reversed from the EMC bootrom. I need to clean it up and rename stuff. 11 | struct flashheader0 { 12 | char branding[32]; // 0x00-0x20 13 | unsigned int unknown0; // 0x20-0x24 14 | unsigned int secondHeaderBlockNum1; // 0x24-0x28 15 | unsigned int secondHeaderBlockNum2; // 0x28-0x2C 16 | unsigned int unknown1; // 0x2C-0x30 17 | unsigned int unknown2; // 0x30-0x34 18 | unsigned int headerInfoBlockNum; // 0x34-0x38 19 | unsigned int unknown3; // 0x38-0x3C 20 | unsigned int unknown4; // 0x3C-0x40 21 | } __attribute__((packed)); 22 | 23 | struct flashheader1 { 24 | char branding[32]; // 0x00-0x20 25 | unsigned int unknown1; // 0x20-0x24 26 | unsigned int maxBlockNumber; // 0x24-0x28 27 | unsigned int unknown2; // 0x28-0x2C 28 | unsigned int unknown3; // 0x2C-0x30 29 | unsigned int dataBlockNumber; // 0x30-0x34 30 | unsigned int dataBlockLength; // 0x34-0x38 31 | unsigned int unknown4; // 0x38-0x3C 32 | unsigned int unknown5; // 0x3C-0x40 33 | } __attribute__((packed)); 34 | 35 | // bootloader header 36 | #define BLDR_MAGIC 0xD48FF9AA 37 | #define BLDR_TYPE_EMC 0x48 38 | #define BLDR_TYPE_EAP 0x68 39 | struct bldr_hdr { 40 | unsigned int magic; // 0x00-0x04 41 | unsigned char unknown1; // 0x05 42 | unsigned char unknown2; // 0x06 43 | unsigned char unknown3; // 0x07 44 | unsigned char type; // 0x08 /* 0x48: EMC | 0x68: EAP */ 45 | unsigned int hdr_len; // 0x08-0x0C 46 | unsigned int body_len; // 0x0C-0x10 47 | unsigned int load_addr_0; // 0x10-0x14 48 | unsigned int load_addr_1; // 0x14-0x18 49 | unsigned char fill_pattern[0x10]; // 0x18-0x28 50 | unsigned char key_seed[8]; // 0x28-0x30 51 | struct { 52 | unsigned char iplbodyaeskey[0x10]; // 0x30-0x40 53 | unsigned char iplbodyhmackey[0x10]; // 0x40-0x50 54 | unsigned char iplbodyhmac[0x14]; // 0x50-0x64 55 | unsigned char filler[8]; // 0x64-0x6C 56 | unsigned char headerhmac[0x14]; // 0x6C-0x80 57 | } crypteddata; // 0x30-0x80 58 | unsigned char bodystart; // 0x80 onwards 59 | } __attribute__((packed)); 60 | 61 | #define EAP_KERNEL_STORAGE_HEADER_MAGIC 0x12EBC95C 62 | struct eap_kernel_storage_hdr { 63 | unsigned int magic; // 0x00-0x04 64 | unsigned int unknown; /// 0x04-0x08 (version?) 65 | unsigned char iv[0x10]; // 0x08-0x18 66 | unsigned char hmacsha1[0x14]; // 0x18-0x2C 67 | } __attribute__((packed)); 68 | 69 | #define EAP_KERNEL_HEADER_MAGIC 0x4B726E00 70 | struct eap_kernel_hdr { 71 | unsigned int magic; 72 | unsigned int length; 73 | } __attribute__((packed)); 74 | 75 | struct bldr_hdr *flash_locate_emc_ipl(unsigned char *flashdata, int forcehdr); 76 | struct bldr_hdr *flash_locate_eap_kbl(unsigned char *flashdata); 77 | 78 | int verify_emc_ipl(unsigned char *flashdata); 79 | int decrypt_emc_ipl(unsigned char *flashdata, unsigned char **data, unsigned int *length); 80 | int replace_emc_ipl(unsigned char *flashdata, unsigned char *newipl, int length); 81 | 82 | int verify_eap_kbl(unsigned char *flashdata); 83 | int decrypt_eap_kbl(unsigned char *flashdata, unsigned char **data, unsigned int *length); 84 | int replace_eap_kbl(unsigned char *flashdata, unsigned char *newkbl, int length); 85 | 86 | int decrypt_decompress_eap_kernel(unsigned char *eapkernel, unsigned int eaplength, unsigned char **data, unsigned int *length); 87 | 88 | #endif /* _SOUTHBRIDGE_H */ 89 | -------------------------------------------------------------------------------- /sha1.c: -------------------------------------------------------------------------------- 1 | /* sha1.c - Functions to compute SHA1 message digest of files or 2 | memory blocks according to the NIST specification FIPS-180-1. 3 | 4 | Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2008 Free Software 5 | Foundation, Inc. 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of the GNU General Public License as published by the 9 | Free Software Foundation; either version 2, or (at your option) any 10 | later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software Foundation, 19 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 20 | 21 | /* Written by Scott G. Miller 22 | Credits: 23 | Robert Klep -- Expansion function fix 24 | */ 25 | 26 | /* #include */ 27 | 28 | #include "sha1.h" 29 | 30 | #include 31 | #include 32 | 33 | #ifdef WORDS_BIGENDIAN 34 | # define SWAP(n) (n) 35 | #else 36 | # define SWAP(n) \ 37 | (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) 38 | #endif 39 | 40 | #define BLOCKSIZE 4096 41 | #if BLOCKSIZE % 64 != 0 42 | # error "invalid BLOCKSIZE" 43 | #endif 44 | 45 | /* This array contains the bytes used to pad the buffer to the next 46 | 64-byte boundary. (RFC 1321, 3.1: Step 1) */ 47 | static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; 48 | 49 | /*! 50 | * @fn void sha1_init_ctx (struct sha1_ctx *ctx) 51 | * 52 | * @brief initialize a context with start constants 53 | * 54 | * @details Take a pointer to a 160 bit block of data (five 32 bit ints) and 55 | * initialize it to the start constants of the SHA1 algorithm. This 56 | * must be called before using hash in the call to sha1_hash. 57 | * 58 | * @param[out] ctx pointer to a context to be initialized 59 | */ 60 | void 61 | sha1_init_ctx (struct sha1_ctx *ctx) 62 | { 63 | ctx->A = 0x67452301; 64 | ctx->B = 0xefcdab89; 65 | ctx->C = 0x98badcfe; 66 | ctx->D = 0x10325476; 67 | ctx->E = 0xc3d2e1f0; 68 | 69 | ctx->total[0] = ctx->total[1] = 0; 70 | ctx->buflen = 0; 71 | } 72 | 73 | /*! 74 | * @fn static __inline__ void set_uint32 (char *cp, uint32_t v) 75 | * 76 | * @brief Copy the 4 byte value from v into the memory location pointed to 77 | by *cp 78 | * 79 | * @details Copy the 4 byte value from v into the memory location pointed to by 80 | * *cp, If your architecture allows unaligned access this is equivalent 81 | * to * (uint32_t *) cp = v 82 | * 83 | * @param[out] cp memory location to copy v into 84 | * @param[in] v 4 byte value to be copied 85 | */ 86 | static __inline__ void 87 | set_uint32 (char *cp, uint32_t v) 88 | { 89 | memcpy (cp, &v, sizeof v); 90 | } 91 | 92 | /*! 93 | * @fn void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) 94 | * 95 | * @brief Put result from CTX in first 20 bytes following RESBUF 96 | * 97 | * @details Put result from CTX in first 20 bytes following RESBUF. The result 98 | * must be in little endian byte order. 99 | * 100 | * @param[in] ctx context whose results will be copied 101 | * @param[out] resbuf result of copies saved in little endian byte order 102 | * @return resbuf 103 | */ 104 | void * 105 | sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) 106 | { 107 | char *r = (char*)resbuf; 108 | set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); 109 | set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); 110 | set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); 111 | set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); 112 | set_uint32 (r + 4 * sizeof ctx->E, SWAP (ctx->E)); 113 | 114 | return resbuf; 115 | } 116 | 117 | /*! 118 | * @fn void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) 119 | * 120 | * @brief Process the remaining bytes in the internal buffer and write 121 | the result to RESBUF. 122 | * 123 | * @details Process the remaining bytes in the internal buffer and the usual 124 | * prolog according to the standard and write the result to RESBUF. 125 | * 126 | * @param[in] ctx context to be used 127 | * @param[out] resbuf resultant SHA1 hash 128 | * @return resultant SHA1 hash 129 | */ 130 | void * 131 | sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) 132 | { 133 | /* Take yet unprocessed bytes into account. */ 134 | uint32_t bytes = ctx->buflen; 135 | size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; 136 | 137 | /* Now count remaining bytes. */ 138 | ctx->total[0] += bytes; 139 | if (ctx->total[0] < bytes) 140 | ++ctx->total[1]; 141 | 142 | /* Put the 64-bit file length in *bits* at the end of the buffer. */ 143 | ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); 144 | ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3); 145 | 146 | memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); 147 | 148 | /* Process last bytes. */ 149 | sha1_process_block (ctx->buffer, size * 4, ctx); 150 | 151 | return sha1_read_ctx (ctx, resbuf); 152 | } 153 | 154 | /* 155 | * @fn void *sha1_buffer (const char *buffer, size_t len, void *resblock) 156 | * 157 | * @brief Compute SHA1 message digest for LEN bytes beginning at BUFFER. 158 | * 159 | * @details Compute SHA1 message digest for LEN bytes beginning at BUFFER. The 160 | * result is always in little endian byte order, so that a byte-wise 161 | * output yields to the wanted ASCII representation of the message 162 | * digest. 163 | * 164 | * @param[in] buffer message to be hashed 165 | * @param[in] len length of buffer 166 | * @param[out] resblock resultant hash in little endian byte order 167 | * @return resultant hash in little endian byte order 168 | */ 169 | void * 170 | sha1_buffer (const char *buffer, size_t len, void *resblock) 171 | { 172 | struct sha1_ctx ctx; 173 | 174 | /* Initialize the computation context. */ 175 | sha1_init_ctx (&ctx); 176 | 177 | /* Process whole buffer but last len % 64 bytes. */ 178 | sha1_process_bytes (buffer, len, &ctx); 179 | 180 | /* Put result in desired memory area. */ 181 | return sha1_finish_ctx (&ctx, resblock); 182 | } 183 | 184 | /*! 185 | * @fn void sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) 186 | * 187 | * @brief update the context for the next LEN bytes starting at BUFFER. 188 | * 189 | * @details Starting with the result of former calls of this function (or the 190 | * initialization function) update the context for the next LEN bytes 191 | * starting at BUFFER. 192 | * It is NOT required that LEN is a multiple of 64. 193 | * 194 | * @param[in] buffer buffer used to update context values 195 | * @param[in] len length of buffer 196 | * @param[out] ctx context to be updated 197 | */ 198 | void 199 | sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) 200 | { 201 | /* When we already have some bits in our internal buffer concatenate 202 | both inputs first. */ 203 | if (ctx->buflen != 0) 204 | { 205 | size_t left_over = ctx->buflen; 206 | size_t add = 128 - left_over > len ? len : 128 - left_over; 207 | 208 | memcpy (&((char *) ctx->buffer)[left_over], buffer, add); 209 | ctx->buflen += add; 210 | 211 | if (ctx->buflen > 64) 212 | { 213 | sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); 214 | 215 | ctx->buflen &= 63; 216 | /* The regions in the following copy operation cannot overlap. */ 217 | memcpy (ctx->buffer, 218 | &((char *) ctx->buffer)[(left_over + add) & ~63], 219 | ctx->buflen); 220 | } 221 | 222 | buffer = (const char *) buffer + add; 223 | len -= add; 224 | } 225 | 226 | /* Process available complete blocks. */ 227 | if (len >= 64) 228 | { 229 | #if !_STRING_ARCH_unaligned 230 | # define alignof(type) offsetof (struct { char c; type x; }, x) 231 | # define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) 232 | if (UNALIGNED_P (buffer)) 233 | while (len > 64) 234 | { 235 | sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); 236 | buffer = (const char *) buffer + 64; 237 | len -= 64; 238 | } 239 | else 240 | #endif 241 | { 242 | sha1_process_block (buffer, len & ~63, ctx); 243 | buffer = (const char *) buffer + (len & ~63); 244 | len &= 63; 245 | } 246 | } 247 | 248 | /* Move remaining bytes in internal buffer. */ 249 | if (len > 0) 250 | { 251 | size_t left_over = ctx->buflen; 252 | 253 | memcpy (&((char *) ctx->buffer)[left_over], buffer, len); 254 | left_over += len; 255 | if (left_over >= 64) 256 | { 257 | sha1_process_block (ctx->buffer, 64, ctx); 258 | left_over -= 64; 259 | memcpy (ctx->buffer, &ctx->buffer[16], left_over); 260 | } 261 | ctx->buflen = left_over; 262 | } 263 | } 264 | 265 | /* --- Code below is the primary difference between md5.c and sha1.c --- */ 266 | 267 | /* SHA1 round constants */ 268 | #define K1 0x5a827999 269 | #define K2 0x6ed9eba1 270 | #define K3 0x8f1bbcdc 271 | #define K4 0xca62c1d6 272 | 273 | /* Round functions. Note that F2 is the same as F4. */ 274 | #define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) 275 | #define F2(B,C,D) (B ^ C ^ D) 276 | #define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) 277 | #define F4(B,C,D) (B ^ C ^ D) 278 | 279 | /*! 280 | * @fn void sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) 281 | * 282 | * @brief Process LEN bytes of BUFFER, accumulating context into CTX. 283 | * 284 | * @details Process LEN bytes of BUFFER, accumulating context into CTX. 285 | * It is assumed that LEN % 64 == 0. 286 | * Most of this code comes from GnuPG's cipher/sha1.c. 287 | * 288 | * @param[in] buffer buffer to be processed 289 | * @param[in] len length of buffer 290 | * @param[out] ctx context used to accumulate results 291 | */ 292 | 293 | void 294 | sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) 295 | { 296 | const uint32_t *words = (const uint32_t*)buffer; 297 | size_t nwords = len / sizeof (uint32_t); 298 | const uint32_t *endp = words + nwords; 299 | uint32_t x[16]; 300 | uint32_t a = ctx->A; 301 | uint32_t b = ctx->B; 302 | uint32_t c = ctx->C; 303 | uint32_t d = ctx->D; 304 | uint32_t e = ctx->E; 305 | 306 | /* First increment the byte count. RFC 1321 specifies the possible 307 | length of the file up to 2^64 bits. Here we only compute the 308 | number of bytes. Do a double word increment. */ 309 | ctx->total[0] += len; 310 | if (ctx->total[0] < len) 311 | ++ctx->total[1]; 312 | 313 | #define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n)))) 314 | 315 | #define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ 316 | ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ 317 | , (x[I&0x0f] = rol(tm, 1)) ) 318 | 319 | #define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ 320 | + F( B, C, D ) \ 321 | + K \ 322 | + M; \ 323 | B = rol( B, 30 ); \ 324 | } while(0) 325 | 326 | while (words < endp) 327 | { 328 | uint32_t tm; 329 | int t; 330 | for (t = 0; t < 16; t++) 331 | { 332 | x[t] = SWAP (*words); 333 | words++; 334 | } 335 | 336 | R( a, b, c, d, e, F1, K1, x[ 0] ); 337 | R( e, a, b, c, d, F1, K1, x[ 1] ); 338 | R( d, e, a, b, c, F1, K1, x[ 2] ); 339 | R( c, d, e, a, b, F1, K1, x[ 3] ); 340 | R( b, c, d, e, a, F1, K1, x[ 4] ); 341 | R( a, b, c, d, e, F1, K1, x[ 5] ); 342 | R( e, a, b, c, d, F1, K1, x[ 6] ); 343 | R( d, e, a, b, c, F1, K1, x[ 7] ); 344 | R( c, d, e, a, b, F1, K1, x[ 8] ); 345 | R( b, c, d, e, a, F1, K1, x[ 9] ); 346 | R( a, b, c, d, e, F1, K1, x[10] ); 347 | R( e, a, b, c, d, F1, K1, x[11] ); 348 | R( d, e, a, b, c, F1, K1, x[12] ); 349 | R( c, d, e, a, b, F1, K1, x[13] ); 350 | R( b, c, d, e, a, F1, K1, x[14] ); 351 | R( a, b, c, d, e, F1, K1, x[15] ); 352 | R( e, a, b, c, d, F1, K1, M(16) ); 353 | R( d, e, a, b, c, F1, K1, M(17) ); 354 | R( c, d, e, a, b, F1, K1, M(18) ); 355 | R( b, c, d, e, a, F1, K1, M(19) ); 356 | R( a, b, c, d, e, F2, K2, M(20) ); 357 | R( e, a, b, c, d, F2, K2, M(21) ); 358 | R( d, e, a, b, c, F2, K2, M(22) ); 359 | R( c, d, e, a, b, F2, K2, M(23) ); 360 | R( b, c, d, e, a, F2, K2, M(24) ); 361 | R( a, b, c, d, e, F2, K2, M(25) ); 362 | R( e, a, b, c, d, F2, K2, M(26) ); 363 | R( d, e, a, b, c, F2, K2, M(27) ); 364 | R( c, d, e, a, b, F2, K2, M(28) ); 365 | R( b, c, d, e, a, F2, K2, M(29) ); 366 | R( a, b, c, d, e, F2, K2, M(30) ); 367 | R( e, a, b, c, d, F2, K2, M(31) ); 368 | R( d, e, a, b, c, F2, K2, M(32) ); 369 | R( c, d, e, a, b, F2, K2, M(33) ); 370 | R( b, c, d, e, a, F2, K2, M(34) ); 371 | R( a, b, c, d, e, F2, K2, M(35) ); 372 | R( e, a, b, c, d, F2, K2, M(36) ); 373 | R( d, e, a, b, c, F2, K2, M(37) ); 374 | R( c, d, e, a, b, F2, K2, M(38) ); 375 | R( b, c, d, e, a, F2, K2, M(39) ); 376 | R( a, b, c, d, e, F3, K3, M(40) ); 377 | R( e, a, b, c, d, F3, K3, M(41) ); 378 | R( d, e, a, b, c, F3, K3, M(42) ); 379 | R( c, d, e, a, b, F3, K3, M(43) ); 380 | R( b, c, d, e, a, F3, K3, M(44) ); 381 | R( a, b, c, d, e, F3, K3, M(45) ); 382 | R( e, a, b, c, d, F3, K3, M(46) ); 383 | R( d, e, a, b, c, F3, K3, M(47) ); 384 | R( c, d, e, a, b, F3, K3, M(48) ); 385 | R( b, c, d, e, a, F3, K3, M(49) ); 386 | R( a, b, c, d, e, F3, K3, M(50) ); 387 | R( e, a, b, c, d, F3, K3, M(51) ); 388 | R( d, e, a, b, c, F3, K3, M(52) ); 389 | R( c, d, e, a, b, F3, K3, M(53) ); 390 | R( b, c, d, e, a, F3, K3, M(54) ); 391 | R( a, b, c, d, e, F3, K3, M(55) ); 392 | R( e, a, b, c, d, F3, K3, M(56) ); 393 | R( d, e, a, b, c, F3, K3, M(57) ); 394 | R( c, d, e, a, b, F3, K3, M(58) ); 395 | R( b, c, d, e, a, F3, K3, M(59) ); 396 | R( a, b, c, d, e, F4, K4, M(60) ); 397 | R( e, a, b, c, d, F4, K4, M(61) ); 398 | R( d, e, a, b, c, F4, K4, M(62) ); 399 | R( c, d, e, a, b, F4, K4, M(63) ); 400 | R( b, c, d, e, a, F4, K4, M(64) ); 401 | R( a, b, c, d, e, F4, K4, M(65) ); 402 | R( e, a, b, c, d, F4, K4, M(66) ); 403 | R( d, e, a, b, c, F4, K4, M(67) ); 404 | R( c, d, e, a, b, F4, K4, M(68) ); 405 | R( b, c, d, e, a, F4, K4, M(69) ); 406 | R( a, b, c, d, e, F4, K4, M(70) ); 407 | R( e, a, b, c, d, F4, K4, M(71) ); 408 | R( d, e, a, b, c, F4, K4, M(72) ); 409 | R( c, d, e, a, b, F4, K4, M(73) ); 410 | R( b, c, d, e, a, F4, K4, M(74) ); 411 | R( a, b, c, d, e, F4, K4, M(75) ); 412 | R( e, a, b, c, d, F4, K4, M(76) ); 413 | R( d, e, a, b, c, F4, K4, M(77) ); 414 | R( c, d, e, a, b, F4, K4, M(78) ); 415 | R( b, c, d, e, a, F4, K4, M(79) ); 416 | 417 | a = ctx->A += a; 418 | b = ctx->B += b; 419 | c = ctx->C += c; 420 | d = ctx->D += d; 421 | e = ctx->E += e; 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /flashtool.c: -------------------------------------------------------------------------------- 1 | // golden 2 | #include "flashtool.h" 3 | 4 | int verbose; 5 | int noverify; 6 | 7 | // any text with a ? is a wildcard 8 | struct consolemap_entry g_consolemap[] = { 9 | { "CUH-10??A B01", "CXD900025G" }, // Aeolia 10 | { "CUH-11??A B01", "CXD900025G" }, // Aeolia 11 | { "CUH-12??A B01X", "CXD900036G" }, // ?Aeolia? 12 | { "CUH-21??A", "CXD900042G" }, // ?Balaik? 13 | { "", "CXD900044G" }, // Belize 14 | { NULL, NULL } 15 | }; 16 | 17 | struct codename_entry g_codenames[] = { 18 | { "40000001", "BLNK", "syscon firmware" }, 19 | { "40000002", "BASE", "syscon firmware" }, 20 | { "40000003", "SYST", "syscon firmware" }, 21 | { "40010001", "PTCH", "syscon patch 1" }, 22 | { "40010002", "PTCH", "syscon patch 2" }, 23 | { "40020001", "USB", "USB-STAT firmware update" }, 24 | { "40030001", "CP", "CP firmware" }, 25 | { "80000001", "SAM_IPL", "SAMU initial program loader"}, 26 | { "80010001", "SAM_SECKRN", "SAMU secure kernel"}, 27 | { "80010002", "APU_FIRMS", "x86-kernel/vbios/gpufw"}, 28 | { "80010006", "SAM_ACMGR", "SAMU module"}, 29 | { "80010008", "SAM_AUTHMGR", "SAMU module"}, 30 | { "80010009", "SAM_IDMGR", "SAMU module"}, 31 | { "8001000A", "SAM_FSMMGR", "SAMU module"}, 32 | { "8001000B", "SAM_KEYMGR", "SAMU module"}, 33 | { "8001000C", "SAM_SERVICE", "SAMU module"}, 34 | { "C0000001", "EMC_IPL", "EMC initial program loader" }, 35 | { "C0010001", "EAP_KBL", "EAP kernel bootloader" }, 36 | { "C0020001", "TORUS_FW", "wifi/bluetooth soc firmware" }, 37 | { NULL, NULL, NULL } 38 | }; 39 | 40 | struct consolemap_entry *find_consolemap(char *model) { 41 | int i, k; 42 | int good; 43 | char *m; 44 | 45 | for(i = 0; i < NUM_CONSOLES; i++) { 46 | m = g_consolemap[i].model; 47 | 48 | // loop and take wildcard into account 49 | good = 0; 50 | for(k = 0; k < MIN(strlen(m), strlen(model)); k++) { 51 | if(m[k] == '?' || m[k] == model[k]) { 52 | good = 1; 53 | } else { 54 | good = 0; 55 | break; 56 | } 57 | } 58 | 59 | if(good) { 60 | return &g_consolemap[i]; 61 | } 62 | } 63 | 64 | return NULL; 65 | } 66 | 67 | struct codename_entry *find_codename(char *codename) { 68 | int i; 69 | 70 | for(i = 0; i < NUM_CODENAMES; i++) { 71 | if(!strcmp(g_codenames[i].codename, codename)) { 72 | return &g_codenames[i]; 73 | } 74 | } 75 | 76 | return NULL; 77 | } 78 | 79 | void hexdump(unsigned char *data, int length, int newlines) { 80 | int i, k; 81 | 82 | for(i = 0; i < length; i++) { 83 | printf("%02X ", data[i]); 84 | 85 | if(newlines) { 86 | if(i != 0 && (i + 1) % 16 == 0) { 87 | printf("\n"); 88 | } 89 | } 90 | } 91 | 92 | printf("\n"); 93 | } 94 | 95 | int dumpbin(unsigned char *filename, unsigned char *data, int length) { 96 | FILE *fp; 97 | 98 | fp = fopen(filename, "wb"); 99 | if(!fp) { 100 | return 1; 101 | } 102 | 103 | fwrite(data, 1, length, fp); 104 | fclose(fp); 105 | 106 | return 0; 107 | } 108 | 109 | int readbin(unsigned char *filename, unsigned char **data, int *length) { 110 | FILE *fp; 111 | unsigned char *ptr; 112 | long size; 113 | 114 | fp = fopen(filename, "rb"); 115 | if(!fp) { 116 | return 1; 117 | } 118 | 119 | fseek(fp, 0, SEEK_END); 120 | size = ftell(fp); 121 | fseek(fp, 0, SEEK_SET); 122 | 123 | ptr = (unsigned char *)malloc(size); 124 | if(!ptr) { 125 | return 1; 126 | } 127 | 128 | memset(ptr, 0, size); 129 | fread(ptr, 1, size, fp); 130 | fclose(fp); 131 | 132 | if(data) { 133 | *data = ptr; 134 | } else { 135 | free(ptr); 136 | } 137 | 138 | if(length) { 139 | *length = size; 140 | } 141 | 142 | return 0; 143 | } 144 | 145 | unsigned char *load_flashdump(char *flashfile) { 146 | FILE *fp; 147 | unsigned char *data; 148 | int length; 149 | 150 | printf("loading flash dump '%s' ...\n", flashfile); 151 | 152 | if(readbin(flashfile, &data, &length)) { 153 | return NULL; 154 | } 155 | 156 | if(length != FLASH_SIZE) { 157 | printf("warning: flash size mismatch. is your flash really 32MB?\n"); 158 | } 159 | 160 | return data; 161 | } 162 | 163 | int dump_console_info(unsigned char *flashdata, unsigned char *path) { 164 | struct nvs_console_info cinfo; 165 | char macaddress[6]; 166 | FILE *fp = NULL; 167 | int i; 168 | 169 | // read console info and mac address 170 | nvs_read(flashdata, 0, 2, NVS_VAR_BLOCK2_CONSOLE_INF0, sizeof(cinfo), (unsigned char *)&cinfo); 171 | nvs_read(flashdata, 0, 0, NVS_VAR_BLOCK0_MAC_ADDRESS, sizeof(macaddress), macaddress); 172 | 173 | fp = fopen(path, "w"); 174 | if(!fp) { 175 | return 1; 176 | } 177 | 178 | fprintf(fp, "motherboard serial: %.*s\n", (int)sizeof(cinfo.moboserial), cinfo.moboserial); 179 | fprintf(fp, "serial: %.*s\n", (int)sizeof(cinfo.serial), cinfo.serial); 180 | fprintf(fp, "model: %.*s\n", (int)sizeof(cinfo.model), cinfo.model); 181 | fprintf(fp, "mac address: "); 182 | for(i = 0; i < sizeof(macaddress); i++) { 183 | fprintf(fp, "%02X%c", macaddress[i] & 0xFF, (i == sizeof(macaddress) - 1) ? '\n' : ':'); 184 | } 185 | 186 | fprintf(fp, "\n"); 187 | 188 | fclose(fp); 189 | 190 | return 0; 191 | } 192 | 193 | void print_flashinfo(unsigned char *flashdata) { 194 | struct nvs_console_info cinfo; 195 | char macaddress[6]; 196 | int i; 197 | 198 | // read console info and mac address 199 | nvs_read(flashdata, 0, 2, NVS_VAR_BLOCK2_CONSOLE_INF0, sizeof(cinfo), (unsigned char *)&cinfo); 200 | nvs_read(flashdata, 0, 0, NVS_VAR_BLOCK0_MAC_ADDRESS, sizeof(macaddress), macaddress); 201 | 202 | printf("* motherboard serial: %.*s\n", (int)sizeof(cinfo.moboserial), cinfo.moboserial); 203 | printf("* serial: %.*s\n", (int)sizeof(cinfo.serial), cinfo.serial); 204 | printf("* model: %.*s\n", (int)sizeof(cinfo.model), cinfo.model); 205 | printf("* mac address: "); 206 | for(i = 0; i < sizeof(macaddress); i++) { 207 | printf("%02X%c", macaddress[i] & 0xFF, (i == sizeof(macaddress) - 1) ? '\n' : ':'); 208 | } 209 | 210 | printf("\n"); 211 | } 212 | 213 | int check_flashdump(unsigned char *flashdata) { 214 | printf("warning: verification of the flash data is only for EMC IPL and EAP KBL.\n"); 215 | return verify_emc_ipl(flashdata) == 1 || verify_eap_kbl(flashdata) == 1; 216 | } 217 | 218 | int extract_flashdump(unsigned char *flashdata, char *extractdir) { 219 | unsigned char *ptr; 220 | int len; 221 | char path[512]; 222 | 223 | printf("extracting flash to '%s' directory ...\n", extractdir); 224 | 225 | mkdir(extractdir, S_IRWXU); 226 | 227 | snprintf(path, sizeof(path), "%s/%s", extractdir, "emcipl.bin"); 228 | if(decrypt_emc_ipl(flashdata, &ptr, &len)) { 229 | return 1; 230 | } 231 | 232 | dumpbin(path, ptr, len); 233 | free(ptr); 234 | 235 | printf("extracted EMC IPL to '%s'!\n", path); 236 | 237 | snprintf(path, sizeof(path), "%s/%s", extractdir, "eapkbl.elf"); 238 | if(decrypt_eap_kbl(flashdata, &ptr, &len)) { 239 | return 1; 240 | } 241 | 242 | dumpbin(path, ptr, len); 243 | free(ptr); 244 | 245 | printf("extracted EAP KBL to '%s'!\n", path); 246 | 247 | snprintf(path, sizeof(path), "%s/%s", extractdir, "consoleinfo.txt"); 248 | dump_console_info(flashdata, path); 249 | 250 | printf("wrote console info to '%s'!\n", path); 251 | 252 | return 0; 253 | } 254 | 255 | int rawextract_flashdump(unsigned char *flashdata, char *extractdir) { 256 | struct bldr_hdr *emc_blhdr = flash_locate_emc_ipl(flashdata, 0); 257 | struct bldr_hdr *eap_blhdr = flash_locate_eap_kbl(flashdata); 258 | char path[512]; 259 | 260 | snprintf(path, sizeof(path), "%s/%s", extractdir, "emcipl.bin"); 261 | dumpbin(path, (unsigned char *)emc_blhdr, emc_blhdr->hdr_len + emc_blhdr->body_len); 262 | 263 | printf("raw extracted EMC IPL to '%s'!\n", path); 264 | 265 | snprintf(path, sizeof(path), "%s/%s", extractdir, "eapkbl.elf"); 266 | dumpbin(path, (unsigned char *)eap_blhdr, eap_blhdr->hdr_len + eap_blhdr->body_len); 267 | 268 | printf("raw extracted EAP KBL to '%s'!\n", path); 269 | 270 | snprintf(path, sizeof(path), "%s/%s", extractdir, "consoleinfo.txt"); 271 | dump_console_info(flashdata, path); 272 | 273 | printf("wrote console info to '%s'!\n", path); 274 | 275 | return 0; 276 | } 277 | 278 | void print_usage() { 279 | char strbuffer[1024]; 280 | 281 | printf("Usage: flashtool [option(s)]\n"); 282 | printf("Examples:\n"); 283 | printf("\tflashtool -k CXD42G.keys --extract dumps -i flashdump.bin\n"); 284 | printf("\tflashtool --emcipl patchedipl.bin -k CXD44G.keys --input flashdump.bin --output flashout.bin\n"); 285 | printf("\tflashtool --eapkbl patchedkbl.bin -k cec_h4x_sram_dmp_CXD36G.keys --input flashdump.bin --output flashout.bin\n"); 286 | printf("\tflashtool -k CXD42G.keys -v -n --input flashdump.bin\n"); 287 | printf("\tflashtool --extract dumps -n --input flashdump.bin\n"); 288 | printf("\tflashtool --eapkern eapkern_hdd_enc.bin,eapkern_hdd_dec.bin\n"); 289 | printf("Options:\n"); 290 | 291 | #define PRINT_OPTION(short, long, hasarg, arg, comment) if(hasarg) { \ 292 | snprintf(strbuffer, sizeof(strbuffer), "\t-%s [%s], --%s [%s]", short, arg, long, arg); \ 293 | } else { \ 294 | snprintf(strbuffer, sizeof(strbuffer), "\t-%s, --%s", short, long); \ 295 | } printf("%s %*s\n", strbuffer, (int)(80 - strlen(strbuffer)), comment); 296 | #define PRINT_LONG_OPTION(long, hasarg, arg, comment) if(hasarg) { \ 297 | snprintf(strbuffer, sizeof(strbuffer), "\t--%s [%s]", long, arg); \ 298 | } else { \ 299 | snprintf(strbuffer, sizeof(strbuffer), "\t--%s", long); \ 300 | } printf("%s %*s\n", strbuffer, (int)(80 - strlen(strbuffer)), comment); 301 | 302 | PRINT_OPTION("h", "help", 0, "", "show this help message") 303 | PRINT_OPTION("v", "verbose", 0, "", "verbose output") 304 | PRINT_OPTION("i", "input", 1, "flash", "flash file input") 305 | PRINT_OPTION("o", "output", 1, "flash", "flash file output") 306 | PRINT_OPTION("n", "noverify", 0, "", "do not verify the flash signatures") 307 | PRINT_OPTION("k", "keyfile", 0, "", "override the default key file") 308 | PRINT_LONG_OPTION("extract", 1, "dir", "extract files to directory") 309 | PRINT_LONG_OPTION("rawextract", 1, "dir", "raw extract files to directory") 310 | PRINT_LONG_OPTION("emcipl", 1, "emcipl", "replace EMC IPL (initial program loader)") 311 | PRINT_LONG_OPTION("eapkbl", 1, "eapkbl", "replace EAP KBL (kernel boot loader)") 312 | PRINT_LONG_OPTION("eapkern", 1, "input,output", "decrypt the EAP kernel") 313 | 314 | printf("\n"); 315 | printf("Everything you can replace in the flash is resigned when you replace it.\n"); 316 | printf("Also, when the extract option is enabled, the files will be extracted after the replacement/resigning.\n"); 317 | printf("!! This tool will never overwrite your existing flash dump file! You must specify an output. !!\n"); 318 | } 319 | 320 | int main(int argc, char **argv) { 321 | int i; 322 | char *flashfile = NULL; 323 | char *flashout = NULL; 324 | char *extractdir = NULL; 325 | char *rawextractdir = NULL; 326 | char *emcipl = NULL; 327 | char *eapkbl = NULL; 328 | char *eapkern = NULL; 329 | 330 | char *keyfile = FLASHTOOL_KEYFILE; 331 | unsigned char *flashdata = NULL; 332 | unsigned char *ptr = NULL, *ptr2 = NULL; 333 | unsigned int len, len2; 334 | 335 | printf("~ PlayStation 4 flash tool " FLASHTOOL_VERSION " | by " FLASHTOOL_CREDITS " ~\n"); 336 | 337 | if(argc == 1) { 338 | printf("try '%s --help' for more information\n", argv[0]); 339 | return 0; 340 | } 341 | 342 | // make sure this is zero 343 | verbose = 0; 344 | noverify = 0; 345 | 346 | for(i = 1; i < argc; i++) { 347 | char *opt = argv[i]; 348 | char *arg = (i == argc - 1) ? NULL : argv[i + 1]; 349 | 350 | if(opt[0] != '-') { 351 | printf("error: invalid argument syntax!\n"); 352 | return 1; 353 | } 354 | if(opt[0] == '-') { opt++; } 355 | if(opt[0] == '-') { opt++; } 356 | 357 | if(opt[0] == 'h' || !strcmp(opt, "help")) { 358 | print_usage(); 359 | return 1; 360 | } else if(opt[0] == 'v' || !strcmp(opt, "verbose")) { 361 | verbose = 1; 362 | } else if(opt[0] == 'i' || !strcmp(opt, "input")) { 363 | if(!arg) { 364 | printf("error: invalid flash input argument!\n"); 365 | return 1; 366 | } 367 | flashfile = arg; 368 | i++; 369 | } else if(opt[0] == 'o' || !strcmp(opt, "output")) { 370 | if(!arg) { 371 | printf("error: invalid flash output argument!\n"); 372 | return 1; 373 | } 374 | flashout = arg; 375 | i++; 376 | } else if(opt[0] == 'n' || !strcmp(opt, "noverify")) { 377 | noverify = 1; 378 | } else if(opt[0] == 'k' || !strcmp(opt, "keyfile")) { 379 | if(!arg) { 380 | printf("error: invalid keyfile argument!\n"); 381 | return 1; 382 | } 383 | keyfile = arg; 384 | printf("* changed keyfile to '%s'\n", keyfile); 385 | i++; 386 | } else if(!strcmp(opt, "extract")) { 387 | if(!arg) { 388 | printf("error: invalid extract directory argument!\n"); 389 | return 1; 390 | } 391 | extractdir = arg; 392 | i++; 393 | } else if(!strcmp(opt, "rawextract")) { 394 | if(!arg) { 395 | printf("error: invalid raw extract directory argument!\n"); 396 | return 1; 397 | } 398 | rawextractdir = arg; 399 | i++; 400 | } else if(!strcmp(opt, "emcipl")) { 401 | if(!arg) { 402 | printf("error: invalid emcipl argument!\n"); 403 | return 1; 404 | } 405 | emcipl = arg; 406 | i++; 407 | } else if(!strcmp(opt, "eapkbl")) { 408 | if(!arg) { 409 | printf("error: invalid eapkbl argument!\n"); 410 | return 1; 411 | } 412 | eapkbl = arg; 413 | i++; 414 | } else if(!strcmp(opt, "eapkern")) { 415 | if(!arg) { 416 | printf("error: invalid eapkern argument!\n"); 417 | return 1; 418 | } 419 | eapkern = arg; 420 | i++; 421 | } else { 422 | printf("error: unknown option '%s'\n", opt); 423 | printf("try '%s --help' for more information\n", argv[0]); 424 | return 1; 425 | } 426 | } 427 | 428 | if(eapkern) { 429 | char *comma = strstr(eapkern, ","); 430 | if(!comma) { 431 | printf("error: please use a comma between the input and output for EAP kernel decryption\n"); 432 | goto end; 433 | } 434 | 435 | comma[0] = '\0'; 436 | 437 | char *input = eapkern; 438 | char *output = comma + 1; 439 | 440 | if(readbin(input, &ptr, &len)) { 441 | printf("error: failed to read EAP kernel from file!\n"); 442 | goto end; 443 | } 444 | 445 | printf("attempting to decrypt EAP kernel '%s' to '%s' ...\n", input, output); 446 | printf("* keys may or not work on your console model/firmware version\n"); 447 | 448 | if(decrypt_decompress_eap_kernel(ptr, len, &ptr2, &len2)) { 449 | printf("error: failed to decrypt EAP kernel\n"); 450 | goto end; 451 | } 452 | 453 | dumpbin(output, ptr2, len2); 454 | 455 | printf("wrote decrypted EAP kernel\n"); 456 | 457 | free(ptr); 458 | free(ptr2); 459 | 460 | goto end; 461 | } 462 | 463 | if(!flashfile) { 464 | printf("error: please specify a PlayStation 4 flash file!\n"); 465 | goto end; 466 | } 467 | 468 | // load flash 469 | flashdata = load_flashdump(flashfile); 470 | if(!flashdata) { 471 | printf("error: invalid flash file!\n"); 472 | goto end; 473 | } 474 | 475 | print_flashinfo(flashdata); 476 | 477 | if(verbose) { 478 | find_and_print_slb2_info(flashdata); 479 | } 480 | 481 | // raw extract does not require a key file so do it before 482 | if(rawextractdir) { 483 | if(rawextract_flashdump(flashdata, rawextractdir)) { 484 | printf("error: raw extract failed!\n"); 485 | } 486 | 487 | goto end; 488 | } 489 | 490 | // load the keys 491 | printf("loading key file '%s' ...\n", keyfile); 492 | if(keymgr_loadkeys(keyfile)) { 493 | return 1; 494 | } 495 | 496 | if(verbose) { 497 | keymgr_printkeys(); 498 | } 499 | 500 | // check flash 501 | if(!noverify) { 502 | if(check_flashdump(flashdata)) { 503 | printf("error: invalid flash data detected!\n"); 504 | goto end; 505 | } 506 | } 507 | 508 | // replace emc ipl 509 | if(emcipl) { 510 | printf("replacing EMC IPL in flash dump with '%s' ...\n", emcipl); 511 | 512 | if(readbin(emcipl, &ptr, &len)) { 513 | printf("error: failed to read EMC IPL from file!\n"); 514 | goto end; 515 | } 516 | 517 | if(replace_emc_ipl(flashdata, ptr, len)) { 518 | printf("warning: failed to replace EMC IPL!\n"); 519 | } 520 | 521 | free(ptr); 522 | } 523 | 524 | // replace eap kbl 525 | if(eapkbl) { 526 | printf("replacing EAP KBL in flash dump with '%s' ...\n", eapkbl); 527 | 528 | if(readbin(eapkbl, &ptr, &len)) { 529 | printf("error: failed to read EAP KBL from file!\n"); 530 | goto end; 531 | } 532 | 533 | if(replace_eap_kbl(flashdata, ptr, len)) { 534 | printf("warning: failed to replace EAP KBL!\n"); 535 | } 536 | 537 | free(ptr); 538 | } 539 | 540 | // extract parts 541 | if(extractdir) { 542 | if(extract_flashdump(flashdata, extractdir)) { 543 | printf("error: failed during flash extraction!\n"); 544 | goto end; 545 | } 546 | } 547 | 548 | // write flashdata out 549 | if(flashout) { 550 | // enable uart ;) 551 | char uart = 1; 552 | nvs_write(flashdata, 0, 4, NVS_VAR_BLOCK4_ENABLE_UART, 1, &uart); 553 | 554 | if(verbose) { 555 | printf("* enabled uart in NVS region\n"); 556 | } 557 | 558 | dumpbin(flashout, flashdata, FLASH_SIZE); 559 | printf("wrote final flash to '%s'\n", flashout); 560 | } 561 | 562 | end: 563 | if(flashdata) { 564 | free(flashdata); 565 | } 566 | 567 | keymgr_cleanup(); 568 | 569 | return 0; 570 | } 571 | 572 | -------------------------------------------------------------------------------- /southbridge.c: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #include "southbridge.h" 4 | 5 | /* 6 | https://www.kernel.org/doc/readme/Documentation-arm-Marvell-README 7 | https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/syna.txt 8 | https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/marvell/ 9 | Sheeva PJ4 88sv581x "Flareon" 10 | CPUID 0x560f581x 11 | ARMv7, idivt, optional iWMMXt v2 12 | Sheeva PJ4B 88sv581x 13 | CPUID 0x561f581x 14 | ARMv7, idivt, optional iWMMXt v2 15 | Sheeva PJ4B-MP / PJ4C 16 | CPUID 0x562f584x 17 | ARMv7, idivt/idiva, LPAE, optional iWMMXt v2 and/or NEON 18 | */ 19 | 20 | struct bldr_hdr *flash_locate_emc_ipl(unsigned char *flashdata, int forcehdr) { 21 | // reversed from EMC bootrom 22 | // I want to start calling the first header the meta header and then the second header the main header. 23 | // I cannot tell if the two slots for booting are for updates or for testkit/devkit vs retail? 24 | struct flashheader0 *hdr0 = NULL; 25 | struct flashheader1 *hdr1 = NULL; 26 | struct bldr_hdr *blhdr = NULL; 27 | unsigned char flag; 28 | int blocknum; 29 | 30 | hdr0 = (struct flashheader0 *)flashdata; 31 | 32 | if(verbose) { 33 | printf("* flash branding '%s'\n", hdr0->branding); 34 | } 35 | 36 | blocknum = hdr0->secondHeaderBlockNum2; 37 | flag = *(unsigned int *)(flashdata + (hdr0->headerInfoBlockNum * 0x200)); 38 | if(!((flag >> 7) & 1)) { 39 | if(verbose && !forcehdr) { 40 | printf("* using header block num 1\n"); 41 | } 42 | 43 | blocknum = hdr0->secondHeaderBlockNum1; 44 | } else if(verbose && !forcehdr) { 45 | printf("* using header block num 2\n"); 46 | } 47 | 48 | hdr1 = (struct flashheader1 *)(flashdata + (blocknum * 0x200)); 49 | blhdr = (struct bldr_hdr *)(flashdata + ((blocknum + hdr1->dataBlockNumber) * 0x200)); 50 | 51 | if(blhdr->magic != BLDR_MAGIC) { 52 | printf("error: invalid EMC IPL bootloader header magic!\n"); 53 | return NULL; 54 | } 55 | 56 | if(blhdr->type != BLDR_TYPE_EMC) { 57 | printf("error: invalid EMC IPL bootloader header type!\n"); 58 | return NULL; 59 | } 60 | 61 | if(forcehdr == 1) { 62 | return (struct bldr_hdr *)(flashdata + ((hdr0->secondHeaderBlockNum1 + hdr1->dataBlockNumber) * 0x200)); 63 | } else if(forcehdr == 2) { 64 | return (struct bldr_hdr *)(flashdata + ((hdr0->secondHeaderBlockNum2 + hdr1->dataBlockNumber) * 0x200)); 65 | } 66 | 67 | return blhdr; 68 | } 69 | 70 | struct bldr_hdr *flash_locate_eap_kbl(unsigned char *flashdata) { 71 | struct bldr_hdr *blhdr = NULL; 72 | struct slb2_header *slbhdr = (struct slb2_header *)(flashdata + 0xC4000); 73 | struct slb2_entry *entry = NULL; 74 | int i; 75 | 76 | if(slbhdr->magic != SLB2_MAGIC) { 77 | printf("error: invalid KBL SLB2 magic!\n"); 78 | return NULL; 79 | } 80 | 81 | for(i = 0; i < slbhdr->file_count; i++) { 82 | entry = &slbhdr->entry_list[i]; 83 | 84 | if(!strcmp(entry->file_name, "C0010001") || !strcmp(entry->file_name, "eap_kbl")) { 85 | break; 86 | } 87 | } 88 | 89 | return (struct bldr_hdr *)(flashdata + 0xC4000 + (entry->block_offset << 9)); 90 | } 91 | 92 | int verify_emc_ipl(unsigned char *flashdata) { 93 | struct bldr_hdr *blhdr = flash_locate_emc_ipl(flashdata, 0); 94 | unsigned char *hdraeskey = keymgr_getkey("emciplaes", KEY_TYPE_AES_128); 95 | unsigned char *hdrhmackey = keymgr_getkey("emciplhmac", KEY_TYPE_HMAC_SHA1); 96 | 97 | if(verbose) { 98 | printf("* EMC IPL header aes key: "); 99 | hexdump(hdraeskey, 0x10, 0); 100 | 101 | printf("* EMC IPL header hmac-sha1 key: "); 102 | hexdump(hdrhmackey, 0x10, 0); 103 | } 104 | 105 | struct bldr_hdr dechdr; 106 | unsigned char *decbody = (unsigned char *)malloc(blhdr->body_len); 107 | char bodyhmac[0x14]; 108 | char hdrhmac[0x14]; 109 | 110 | // copy the header on to the stack, we dont want to modify anything 111 | memcpy(&dechdr, blhdr, blhdr->hdr_len); 112 | 113 | aes128_cbc_iv_zero_decrypt(hdraeskey, &blhdr->crypteddata, &dechdr.crypteddata, 0x50); 114 | 115 | hmac_sha1(dechdr.crypteddata.iplbodyhmackey, 0x10, &blhdr->bodystart, blhdr->body_len, bodyhmac); 116 | hmac_sha1(hdrhmackey, 0x10, (unsigned char *)&dechdr, 0x6C, hdrhmac); 117 | 118 | if(verbose) { 119 | printf("* flash EMC IPL body hmac-sha1: "); 120 | hexdump(dechdr.crypteddata.iplbodyhmac, 0x14, 0); 121 | 122 | printf("* calculated EMC IPL body hmac-sha1: "); 123 | hexdump(bodyhmac, 0x14, 0); 124 | 125 | printf("* flash EMC IPL header hmac-sha1: "); 126 | hexdump(dechdr.crypteddata.headerhmac, 0x14, 0); 127 | 128 | printf("* calculated EMC IPL header hmac-sha1: "); 129 | hexdump(hdrhmac, 0x14, 0); 130 | } 131 | 132 | // some checks that the rom will do 133 | unsigned char *h = (unsigned char *)&dechdr; 134 | int flag; 135 | 136 | // TODO: clean this all up and make it nice :P 137 | flag = *(unsigned short *)&h[6] >> 14 == 1; 138 | if(!flag) { 139 | flag = *(unsigned short *)&h[6] >> 14 == 2; 140 | } 141 | 142 | if(!flag) { 143 | printf("error: header flag part 1 invalid!\n"); 144 | return 1; 145 | } 146 | 147 | flag = (*(unsigned short *)&h[6] >> 12) & 3; 148 | if(flag == 0) { 149 | flag = *(unsigned short *)&h[8] == 0x80; 150 | } 151 | 152 | if(!flag || h[12] & 0x0F) { 153 | printf("error: header flag part 2 invalid!\n"); 154 | return 1; 155 | } 156 | 157 | if(dechdr.load_addr_1 < 0x100C00) { 158 | printf("error: invalid load address!\n"); 159 | return 1; 160 | } 161 | 162 | // TODO: add size checks also and other stuff 163 | 164 | free(decbody); 165 | 166 | return memcmp(bodyhmac, dechdr.crypteddata.iplbodyhmac, sizeof(bodyhmac)) + 167 | memcmp(hdrhmac, &dechdr.crypteddata.headerhmac, sizeof(bodyhmac)); 168 | } 169 | 170 | int decrypt_emc_ipl(unsigned char *flashdata, unsigned char **data, unsigned int *length) { 171 | struct bldr_hdr *blhdr = flash_locate_emc_ipl(flashdata, 0); 172 | unsigned char *hdraeskey = keymgr_getkey("emciplaes", KEY_TYPE_AES_128); 173 | 174 | if(verbose) { 175 | printf("* EMC IPL header aes key: "); 176 | hexdump(hdraeskey, 0x10, 0); 177 | } 178 | 179 | struct bldr_hdr dechdr; 180 | unsigned char *decbody = (unsigned char *)malloc(blhdr->body_len); 181 | 182 | // copy the header on to the stack, we dont want to modify anything 183 | memcpy(&dechdr, blhdr, blhdr->hdr_len); 184 | aes128_cbc_iv_zero_decrypt(hdraeskey, &blhdr->crypteddata, &dechdr.crypteddata, 0x50); 185 | aes128_cbc_iv_zero_decrypt(dechdr.crypteddata.iplbodyaeskey, &blhdr->bodystart, decbody, blhdr->body_len); 186 | 187 | if(data) { 188 | *data = decbody; 189 | } 190 | 191 | if(length) { 192 | *length = blhdr->body_len; 193 | } 194 | 195 | return 0; 196 | } 197 | 198 | int replace_emc_ipl(unsigned char *flashdata, unsigned char *newipl, int length) { 199 | struct bldr_hdr *blhdr = flash_locate_emc_ipl(flashdata, 0); 200 | unsigned char *hdraeskey = keymgr_getkey("emciplaes", KEY_TYPE_AES_128); 201 | unsigned char *hdrhmackey = keymgr_getkey("emciplhmac", KEY_TYPE_HMAC_SHA1); 202 | 203 | if(verbose) { 204 | printf("* EMC IPL header aes key: "); 205 | hexdump(hdraeskey, 0x10, 0); 206 | 207 | printf("* EMC IPL header hmac-sha1 key: "); 208 | hexdump(hdrhmackey, 0x10, 0); 209 | } 210 | 211 | char bodyhmac[0x14]; 212 | char hdrhmac[0x14]; 213 | 214 | // decrypt header 215 | aes128_cbc_iv_zero_decrypt(hdraeskey, &blhdr->crypteddata, &blhdr->crypteddata, 0x50); 216 | 217 | // encrypt body and replace it in flash 218 | if(verbose) { 219 | printf("* old EMC IPL body_len 0x%X\n", blhdr->body_len); 220 | printf("* new EMC IPL body_len 0x%X\n", length); 221 | } 222 | 223 | if(blhdr->body_len != length) { 224 | printf("warning: new EMC IPL has a different body length\n"); 225 | } 226 | 227 | blhdr->body_len = length; 228 | aes128_cbc_iv_zero_encrypt(blhdr->crypteddata.iplbodyaeskey, newipl, &blhdr->bodystart, blhdr->body_len); 229 | 230 | // replace body signature 231 | hmac_sha1(blhdr->crypteddata.iplbodyhmackey, 0x10, &blhdr->bodystart, blhdr->body_len, bodyhmac); 232 | 233 | if(verbose) { 234 | printf("* old EMC IPL body hmac-sha1: "); 235 | hexdump(blhdr->crypteddata.iplbodyhmac, 0x14, 0); 236 | 237 | printf("* new EMC IPL body hmac-sha1: "); 238 | hexdump(bodyhmac, 0x14, 0); 239 | } 240 | 241 | memcpy(blhdr->crypteddata.iplbodyhmac, bodyhmac, sizeof(bodyhmac)); 242 | 243 | // filler null 244 | memset(blhdr->crypteddata.filler, 0, 8); 245 | 246 | // replace header signature 247 | hmac_sha1(hdrhmackey, 0x10, (unsigned char *)blhdr, 0x6C, hdrhmac); 248 | 249 | if(verbose) { 250 | printf("* old EMC IPL header hmac-sha1: "); 251 | hexdump(blhdr->crypteddata.headerhmac, 0x14, 0); 252 | 253 | printf("* new EMC IPL header hmac-sha1: "); 254 | hexdump(hdrhmac, 0x14, 0); 255 | } 256 | 257 | memcpy(blhdr->crypteddata.headerhmac, hdrhmac, sizeof(hdrhmac)); 258 | 259 | // encrypt header 260 | aes128_cbc_iv_zero_encrypt(hdraeskey, &blhdr->crypteddata, &blhdr->crypteddata, 0x50); 261 | 262 | return 0; 263 | } 264 | 265 | int verify_eap_kbl(unsigned char *flashdata) { 266 | struct bldr_hdr *blhdr = flash_locate_eap_kbl(flashdata); 267 | unsigned char *hdraeskey = keymgr_getkey("eapkblaes", KEY_TYPE_AES_128); 268 | unsigned char *hdrhmackey = keymgr_getkey("eapkblhmac", KEY_TYPE_HMAC_SHA1); 269 | 270 | if(verbose) { 271 | printf("* EAP KBL header aes key: "); 272 | hexdump(hdraeskey, 0x10, 0); 273 | 274 | printf("* EAP KBL header hmac-sha1 key: "); 275 | hexdump(hdrhmackey, 0x10, 0); 276 | } 277 | 278 | struct bldr_hdr dechdr; 279 | unsigned char *decbody = (unsigned char *)malloc(blhdr->body_len); 280 | char bodyhmac[0x14]; 281 | char hdrhmac[0x14]; 282 | 283 | // copy the header on to the stack, we dont want to modify anything 284 | memcpy(&dechdr, blhdr, blhdr->hdr_len); 285 | 286 | aes128_cbc_iv_zero_decrypt(hdraeskey, &blhdr->crypteddata, &dechdr.crypteddata, 0x50); 287 | 288 | hmac_sha1(dechdr.crypteddata.iplbodyhmackey, 0x10, &blhdr->bodystart, blhdr->body_len, bodyhmac); 289 | hmac_sha1(hdrhmackey, 0x10, (unsigned char *)&dechdr, 0x6C, hdrhmac); 290 | 291 | if(verbose) { 292 | printf("* flash EAP KBL body hmac-sha1: "); 293 | hexdump(dechdr.crypteddata.iplbodyhmac, 0x14, 0); 294 | 295 | printf("* calculated EAP KBL body hmac-sha1: "); 296 | hexdump(bodyhmac, 0x14, 0); 297 | 298 | printf("* flash EAP KBL header hmac-sha1: "); 299 | hexdump(dechdr.crypteddata.headerhmac, 0x14, 0); 300 | 301 | printf("* calculated EAP KBL header hmac-sha1: "); 302 | hexdump(hdrhmac, 0x14, 0); 303 | } 304 | 305 | free(decbody); 306 | 307 | return memcmp(bodyhmac, dechdr.crypteddata.iplbodyhmac, sizeof(bodyhmac)) + 308 | memcmp(hdrhmac, &dechdr.crypteddata.headerhmac, sizeof(bodyhmac)); 309 | } 310 | 311 | int decrypt_eap_kbl(unsigned char *flashdata, unsigned char **data, unsigned int *length) { 312 | struct bldr_hdr *blhdr = flash_locate_eap_kbl(flashdata); 313 | unsigned char *hdraeskey = keymgr_getkey("eapkblaes", KEY_TYPE_AES_128); 314 | 315 | if(verbose) { 316 | printf("* EAP KBL header aes key: "); 317 | hexdump(hdraeskey, 0x10, 0); 318 | } 319 | 320 | struct bldr_hdr dechdr; 321 | unsigned char *decbody = (unsigned char *)malloc(blhdr->body_len); 322 | 323 | // copy the header on to the stack, we dont want to modify anything 324 | memcpy(&dechdr, blhdr, blhdr->hdr_len); 325 | aes128_cbc_iv_zero_decrypt(hdraeskey, &blhdr->crypteddata, &dechdr.crypteddata, 0x50); 326 | aes128_cbc_iv_zero_decrypt(dechdr.crypteddata.iplbodyaeskey, &blhdr->bodystart, decbody, blhdr->body_len); 327 | 328 | if(data) { 329 | *data = decbody; 330 | } 331 | 332 | if(length) { 333 | *length = blhdr->body_len; 334 | } 335 | 336 | return 0; 337 | } 338 | 339 | int replace_eap_kbl(unsigned char *flashdata, unsigned char *newkbl, int length) { 340 | struct bldr_hdr *blhdr = flash_locate_eap_kbl(flashdata); 341 | unsigned char *hdraeskey = keymgr_getkey("eapkblaes", KEY_TYPE_AES_128); 342 | unsigned char *hdrhmackey = keymgr_getkey("eapkblhmac", KEY_TYPE_HMAC_SHA1); 343 | 344 | if(verbose) { 345 | printf("* EAP KBL header aes key: "); 346 | hexdump(hdraeskey, 0x10, 0); 347 | 348 | printf("* EAP KBL header hmac-sha1 key: "); 349 | hexdump(hdrhmackey, 0x10, 0); 350 | } 351 | 352 | char bodyhmac[0x14]; 353 | char hdrhmac[0x14]; 354 | 355 | // decrypt header 356 | aes128_cbc_iv_zero_decrypt(hdraeskey, &blhdr->crypteddata, &blhdr->crypteddata, 0x50); 357 | 358 | // encrypt body and replace it in flash 359 | if(verbose) { 360 | printf("* old EAP KBL body_len 0x%X\n", blhdr->body_len); 361 | printf("* new EAP KBL body_len 0x%X\n", length); 362 | } 363 | 364 | if(blhdr->body_len != length) { 365 | printf("warning: new EAP KBL has a different body length\n"); 366 | } 367 | 368 | blhdr->body_len = length; 369 | aes128_cbc_iv_zero_encrypt(blhdr->crypteddata.iplbodyaeskey, newkbl, &blhdr->bodystart, blhdr->body_len); 370 | 371 | // replace body signature 372 | hmac_sha1(blhdr->crypteddata.iplbodyhmackey, 0x10, &blhdr->bodystart, blhdr->body_len, bodyhmac); 373 | 374 | if(verbose) { 375 | printf("* old EAP KBL body hmac-sha1: "); 376 | hexdump(blhdr->crypteddata.iplbodyhmac, 0x14, 0); 377 | 378 | printf("* new EAP KBL body hmac-sha1: "); 379 | hexdump(bodyhmac, 0x14, 0); 380 | } 381 | 382 | memcpy(blhdr->crypteddata.iplbodyhmac, bodyhmac, sizeof(bodyhmac)); 383 | 384 | // filler null 385 | memset(blhdr->crypteddata.filler, 0, 8); 386 | 387 | // replace header signature 388 | hmac_sha1(hdrhmackey, 0x10, (unsigned char *)blhdr, 0x6C, hdrhmac); 389 | 390 | if(verbose) { 391 | printf("* old EAP KBL header hmac-sha1: "); 392 | hexdump(blhdr->crypteddata.headerhmac, 0x14, 0); 393 | 394 | printf("* new EAP KBL header hmac-sha1: "); 395 | hexdump(hdrhmac, 0x14, 0); 396 | } 397 | 398 | memcpy(blhdr->crypteddata.headerhmac, hdrhmac, sizeof(hdrhmac)); 399 | 400 | // encrypt header 401 | aes128_cbc_iv_zero_encrypt(hdraeskey, &blhdr->crypteddata, &blhdr->crypteddata, 0x50); 402 | 403 | return 0; 404 | } 405 | 406 | // TODO: clean up all this bullshit 407 | unsigned int mersenne_twister(int *seed) { 408 | int var1; // r12 409 | int *var2; // r1 410 | unsigned int var3; // r4 411 | int var4; // r2 412 | int var5; // r5 413 | int var6; // r0 414 | unsigned int var7; // r4 415 | int *var8; // r5 416 | 417 | var1 = *seed; 418 | var2 = &seed[*seed + 1]; 419 | var3 = *var2; 420 | var4 = *seed + 1; 421 | if(*seed >= 623) { 422 | var5 = seed[1]; 423 | var4 = 0; 424 | } else { 425 | var5 = var2[1]; 426 | } 427 | *seed = var4; 428 | var6 = var3 ^ (var3 >> 11); 429 | var7 = (var3 & 0x80000000 | var5 & 0x7FFFFFFF) >> 1; 430 | if(var5 & 1 ) { 431 | var7 ^= 0x9908B0DF; 432 | } 433 | var8 = var2 - 227; 434 | if( var1 < 227 ) { 435 | var8 = var2 + 397; 436 | } 437 | *var2 = var7 ^ *var8; 438 | 439 | return var6 ^ (var6 << 7) & 0x9D2C5680 ^ ((var6 ^ (var6 << 7) & 0x9D2C5680) << 15) & 0xEFC60000 ^ ((var6 ^ (var6 << 7) & 0x9D2C5680 ^ ((var6 ^ (var6 << 7) & 0x9D2C5680) << 15) & 0xEFC60000) >> 18); 440 | } 441 | 442 | int mersenne_init(int *ptr, unsigned int seed) { 443 | int *v2; // r4 444 | signed int v3; // r0 445 | int v4; // r2 446 | unsigned int v5; // r1 447 | unsigned char *v6; // r3 448 | int v7; // r5 449 | signed int v8; // r5 450 | 451 | v2 = ptr; 452 | v3 = 1; 453 | v4 = 0; 454 | v2[1] = seed; 455 | do { 456 | v5 = seed ^ (seed >> 30); 457 | v6 = (unsigned char *)&v2[v4]; 458 | v7 = v4++ + 0x6C078965 * v5; 459 | seed = v3++ + 0x6C078965 * v5; 460 | *(unsigned int *)(v6 + 8) = v7 + 1; 461 | } while(v4 != 0x26F); 462 | 463 | v8 = 0x270; 464 | *v2 = 0; 465 | do { 466 | mersenne_twister(v2); 467 | --v8; 468 | } 469 | while(v8); 470 | 471 | return 0; 472 | } 473 | 474 | // these starting key values may be specific to a specific version and such? 475 | // I do believe they change them from time to time. 476 | // special thanks to you know who you are if your reading this! :) 477 | unsigned int random_seeds[0x271]; 478 | unsigned int eap_keys[8][4] = { 479 | /* even though these keys are technically public, I cannot post them! */ 480 | }; 481 | 482 | void init_eap_keys() { 483 | int i; 484 | 485 | mersenne_init(random_seeds, 486 | eap_keys[7][0] + eap_keys[3][0] + eap_keys[6][0] 487 | + 2 * (eap_keys[7][1] + eap_keys[3][1] + eap_keys[6][1]) 488 | + 3 * (eap_keys[7][2] + eap_keys[3][2] + eap_keys[6][2]) 489 | + 4 * (eap_keys[7][3] + eap_keys[3][3] + eap_keys[6][3] 490 | )); 491 | 492 | for(i = 0; i < 4; i++) { 493 | eap_keys[3][i] ^= mersenne_twister(random_seeds); 494 | eap_keys[7][i] ^= mersenne_twister(random_seeds); 495 | } 496 | 497 | mersenne_init(random_seeds, 498 | eap_keys[4][0] + eap_keys[5][0] + eap_keys[6][0] 499 | + 2 * (eap_keys[6][1] + eap_keys[5][1] + eap_keys[4][1]) 500 | + 3 * (eap_keys[5][2] + eap_keys[4][2] + eap_keys[6][2]) 501 | + 4 * (eap_keys[4][3] + eap_keys[5][3] + eap_keys[6][3]) 502 | ); 503 | 504 | for(i = 0; i < 4; i++) { 505 | eap_keys[4][i] ^= mersenne_twister(random_seeds); 506 | eap_keys[5][i] ^= mersenne_twister(random_seeds); 507 | } 508 | 509 | mersenne_init(random_seeds, 510 | eap_keys[0][0] + eap_keys[1][0] + eap_keys[2][0] 511 | + 2 * (eap_keys[1][1] + eap_keys[2][1] + eap_keys[0][1]) 512 | + 3 * (eap_keys[1][2] + eap_keys[2][2] + eap_keys[0][2]) 513 | + 4 * (eap_keys[2][3] + eap_keys[1][3] + eap_keys[0][3]) 514 | ); 515 | 516 | for(i = 0; i < 4; i++) { 517 | eap_keys[1][i] ^= mersenne_twister(random_seeds); 518 | eap_keys[2][i] ^= mersenne_twister(random_seeds); 519 | } 520 | } 521 | 522 | int decrypt_decompress_eap_kernel(unsigned char *eapkernel, unsigned int eaplength, unsigned char **data, unsigned int *length) { 523 | struct eap_kernel_storage_hdr *shdr = (struct eap_kernel_storage_hdr *)eapkernel; 524 | struct eap_kernel_hdr *hdr; 525 | unsigned char *ptr, *output; 526 | unsigned int len, outlen; 527 | 528 | if(shdr->magic != EAP_KERNEL_STORAGE_HEADER_MAGIC) { 529 | printf("error: invalid EAP kernel storage header magic\n"); 530 | return 1; 531 | } 532 | 533 | ptr = (unsigned char *)malloc(eaplength); 534 | if(!ptr) { 535 | printf("error: could not allocate memory for EAP kernel\n"); 536 | return 1; 537 | } 538 | 539 | memcpy(ptr, eapkernel, eaplength); 540 | 541 | memset(random_seeds, 0, sizeof(random_seeds)); 542 | init_eap_keys(); 543 | 544 | // decrypt 545 | len = 512 - 0x2C; 546 | len -= len % 0x10; 547 | aes128_cbc_decrypt(eap_keys[1], ptr + 0x2C, ptr + 0x2C, len, shdr->iv); 548 | hdr = (struct eap_kernel_hdr *)(ptr + 0x2C); 549 | 550 | if(hdr->magic != EAP_KERNEL_HEADER_MAGIC) { 551 | printf("error: invalid EAP kernel header magic\n"); 552 | return 1; 553 | } 554 | 555 | // decrypt 556 | len = hdr->length; 557 | len -= hdr->length % 0x10; 558 | aes128_cbc_decrypt(eap_keys[1], ptr + 0x2C, ptr + 0x2C, len, shdr->iv); 559 | 560 | printf("warning: EAP kernel decryption and decompression will remove the decompressor part of the EAP kernel loading\n"); 561 | 562 | // decompress 563 | output = (unsigned char *)malloc(len); 564 | outlen = len; 565 | do { 566 | outlen *= 2; // resize buffer 567 | output = realloc(output, outlen); 568 | len = arzl_decompress(output, outlen, ptr + 0x1D30, NULL); 569 | } while (len == 0x80560201); // out of space 570 | 571 | arzl_deobfuscate(output, len, 2); 572 | 573 | free(ptr); 574 | 575 | if(data) { 576 | *data = output; 577 | } else { 578 | free(output); 579 | } 580 | 581 | if(length) { 582 | *length = len; 583 | } 584 | 585 | return 0; 586 | } 587 | -------------------------------------------------------------------------------- /aes.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. 4 | Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. 5 | 6 | The implementation is verified against the test vectors in: 7 | National Institute of Standards and Technology Special Publication 800-38A 2001 ED 8 | 9 | ECB-AES128 10 | ---------- 11 | 12 | plain-text: 13 | 6bc1bee22e409f96e93d7e117393172a 14 | ae2d8a571e03ac9c9eb76fac45af8e51 15 | 30c81c46a35ce411e5fbc1191a0a52ef 16 | f69f2445df4f9b17ad2b417be66c3710 17 | 18 | key: 19 | 2b7e151628aed2a6abf7158809cf4f3c 20 | 21 | resulting cipher 22 | 3ad77bb40d7a3660a89ecaf32466ef97 23 | f5d3d58503b9699de785895a96fdbaaf 24 | 43b1cd7f598ece23881b00e3ed030688 25 | 7b0c785e27e8ad3f8223207104725dd4 26 | 27 | 28 | NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) 29 | You should pad the end of the string with zeros if this is not the case. 30 | For AES192/256 the key size is proportionally larger. 31 | 32 | */ 33 | 34 | 35 | /*****************************************************************************/ 36 | /* Includes: */ 37 | /*****************************************************************************/ 38 | #include 39 | #include // CBC mode, for memset 40 | #include "aes.h" 41 | 42 | /*****************************************************************************/ 43 | /* Defines: */ 44 | /*****************************************************************************/ 45 | // The number of columns comprising a state in AES. This is a constant in AES. Value=4 46 | #define Nb 4 47 | 48 | #if defined(AES256) && (AES256 == 1) 49 | #define Nk 8 50 | #define Nr 14 51 | #elif defined(AES192) && (AES192 == 1) 52 | #define Nk 6 53 | #define Nr 12 54 | #else 55 | #define Nk 4 // The number of 32 bit words in a key. 56 | #define Nr 10 // The number of rounds in AES Cipher. 57 | #endif 58 | 59 | // jcallan@github points out that declaring Multiply as a function 60 | // reduces code size considerably with the Keil ARM compiler. 61 | // See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 62 | #ifndef MULTIPLY_AS_A_FUNCTION 63 | #define MULTIPLY_AS_A_FUNCTION 0 64 | #endif 65 | 66 | 67 | 68 | 69 | /*****************************************************************************/ 70 | /* Private variables: */ 71 | /*****************************************************************************/ 72 | // state - array holding the intermediate results during decryption. 73 | typedef uint8_t state_t[4][4]; 74 | 75 | 76 | 77 | // The lookup-tables are marked const so they can be placed in read-only storage instead of RAM 78 | // The numbers below can be computed dynamically trading ROM for RAM - 79 | // This can be useful in (embedded) bootloader applications, where ROM is often limited. 80 | static const uint8_t sbox[256] = { 81 | //0 1 2 3 4 5 6 7 8 9 A B C D E F 82 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 83 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 84 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 85 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 86 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 87 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 88 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 89 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 90 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 91 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 92 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 93 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 94 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 95 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 96 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 97 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; 98 | 99 | static const uint8_t rsbox[256] = { 100 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 101 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 102 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 103 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 104 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 105 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 106 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 107 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 108 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 109 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 110 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 111 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 112 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 113 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 114 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 115 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; 116 | 117 | // The round constant word array, Rcon[i], contains the values given by 118 | // x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) 119 | static const uint8_t Rcon[11] = { 120 | 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; 121 | 122 | /* 123 | * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), 124 | * that you can remove most of the elements in the Rcon array, because they are unused. 125 | * 126 | * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon 127 | * 128 | * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), 129 | * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." 130 | */ 131 | 132 | 133 | /*****************************************************************************/ 134 | /* Private functions: */ 135 | /*****************************************************************************/ 136 | /* 137 | static uint8_t getSBoxValue(uint8_t num) 138 | { 139 | return sbox[num]; 140 | } 141 | */ 142 | #define getSBoxValue(num) (sbox[(num)]) 143 | /* 144 | static uint8_t getSBoxInvert(uint8_t num) 145 | { 146 | return rsbox[num]; 147 | } 148 | */ 149 | #define getSBoxInvert(num) (rsbox[(num)]) 150 | 151 | // This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. 152 | static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) 153 | { 154 | unsigned i, j, k; 155 | uint8_t tempa[4]; // Used for the column/row operations 156 | 157 | // The first round key is the key itself. 158 | for (i = 0; i < Nk; ++i) 159 | { 160 | RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; 161 | RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; 162 | RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; 163 | RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; 164 | } 165 | 166 | // All other round keys are found from the previous round keys. 167 | for (i = Nk; i < Nb * (Nr + 1); ++i) 168 | { 169 | { 170 | k = (i - 1) * 4; 171 | tempa[0]=RoundKey[k + 0]; 172 | tempa[1]=RoundKey[k + 1]; 173 | tempa[2]=RoundKey[k + 2]; 174 | tempa[3]=RoundKey[k + 3]; 175 | 176 | } 177 | 178 | if (i % Nk == 0) 179 | { 180 | // This function shifts the 4 bytes in a word to the left once. 181 | // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] 182 | 183 | // Function RotWord() 184 | { 185 | const uint8_t u8tmp = tempa[0]; 186 | tempa[0] = tempa[1]; 187 | tempa[1] = tempa[2]; 188 | tempa[2] = tempa[3]; 189 | tempa[3] = u8tmp; 190 | } 191 | 192 | // SubWord() is a function that takes a four-byte input word and 193 | // applies the S-box to each of the four bytes to produce an output word. 194 | 195 | // Function Subword() 196 | { 197 | tempa[0] = getSBoxValue(tempa[0]); 198 | tempa[1] = getSBoxValue(tempa[1]); 199 | tempa[2] = getSBoxValue(tempa[2]); 200 | tempa[3] = getSBoxValue(tempa[3]); 201 | } 202 | 203 | tempa[0] = tempa[0] ^ Rcon[i/Nk]; 204 | } 205 | #if defined(AES256) && (AES256 == 1) 206 | if (i % Nk == 4) 207 | { 208 | // Function Subword() 209 | { 210 | tempa[0] = getSBoxValue(tempa[0]); 211 | tempa[1] = getSBoxValue(tempa[1]); 212 | tempa[2] = getSBoxValue(tempa[2]); 213 | tempa[3] = getSBoxValue(tempa[3]); 214 | } 215 | } 216 | #endif 217 | j = i * 4; k=(i - Nk) * 4; 218 | RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; 219 | RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; 220 | RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; 221 | RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; 222 | } 223 | } 224 | 225 | void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) 226 | { 227 | KeyExpansion(ctx->RoundKey, key); 228 | } 229 | #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) 230 | void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) 231 | { 232 | KeyExpansion(ctx->RoundKey, key); 233 | memcpy (ctx->Iv, iv, AES_BLOCKLEN); 234 | } 235 | void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) 236 | { 237 | memcpy (ctx->Iv, iv, AES_BLOCKLEN); 238 | } 239 | #endif 240 | 241 | // This function adds the round key to state. 242 | // The round key is added to the state by an XOR function. 243 | static void AddRoundKey(uint8_t round,state_t* state,uint8_t* RoundKey) 244 | { 245 | uint8_t i,j; 246 | for (i = 0; i < 4; ++i) 247 | { 248 | for (j = 0; j < 4; ++j) 249 | { 250 | (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; 251 | } 252 | } 253 | } 254 | 255 | // The SubBytes Function Substitutes the values in the 256 | // state matrix with values in an S-box. 257 | static void SubBytes(state_t* state) 258 | { 259 | uint8_t i, j; 260 | for (i = 0; i < 4; ++i) 261 | { 262 | for (j = 0; j < 4; ++j) 263 | { 264 | (*state)[j][i] = getSBoxValue((*state)[j][i]); 265 | } 266 | } 267 | } 268 | 269 | // The ShiftRows() function shifts the rows in the state to the left. 270 | // Each row is shifted with different offset. 271 | // Offset = Row number. So the first row is not shifted. 272 | static void ShiftRows(state_t* state) 273 | { 274 | uint8_t temp; 275 | 276 | // Rotate first row 1 columns to left 277 | temp = (*state)[0][1]; 278 | (*state)[0][1] = (*state)[1][1]; 279 | (*state)[1][1] = (*state)[2][1]; 280 | (*state)[2][1] = (*state)[3][1]; 281 | (*state)[3][1] = temp; 282 | 283 | // Rotate second row 2 columns to left 284 | temp = (*state)[0][2]; 285 | (*state)[0][2] = (*state)[2][2]; 286 | (*state)[2][2] = temp; 287 | 288 | temp = (*state)[1][2]; 289 | (*state)[1][2] = (*state)[3][2]; 290 | (*state)[3][2] = temp; 291 | 292 | // Rotate third row 3 columns to left 293 | temp = (*state)[0][3]; 294 | (*state)[0][3] = (*state)[3][3]; 295 | (*state)[3][3] = (*state)[2][3]; 296 | (*state)[2][3] = (*state)[1][3]; 297 | (*state)[1][3] = temp; 298 | } 299 | 300 | static uint8_t xtime(uint8_t x) 301 | { 302 | return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); 303 | } 304 | 305 | // MixColumns function mixes the columns of the state matrix 306 | static void MixColumns(state_t* state) 307 | { 308 | uint8_t i; 309 | uint8_t Tmp, Tm, t; 310 | for (i = 0; i < 4; ++i) 311 | { 312 | t = (*state)[i][0]; 313 | Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; 314 | Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; 315 | Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; 316 | Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; 317 | Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; 318 | } 319 | } 320 | 321 | // Multiply is used to multiply numbers in the field GF(2^8) 322 | // Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary 323 | // The compiler seems to be able to vectorize the operation better this way. 324 | // See https://github.com/kokke/tiny-AES-c/pull/34 325 | #if MULTIPLY_AS_A_FUNCTION 326 | static uint8_t Multiply(uint8_t x, uint8_t y) 327 | { 328 | return (((y & 1) * x) ^ 329 | ((y>>1 & 1) * xtime(x)) ^ 330 | ((y>>2 & 1) * xtime(xtime(x))) ^ 331 | ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ 332 | ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ 333 | } 334 | #else 335 | #define Multiply(x, y) \ 336 | ( ((y & 1) * x) ^ \ 337 | ((y>>1 & 1) * xtime(x)) ^ \ 338 | ((y>>2 & 1) * xtime(xtime(x))) ^ \ 339 | ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ 340 | ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ 341 | 342 | #endif 343 | 344 | #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) 345 | // MixColumns function mixes the columns of the state matrix. 346 | // The method used to multiply may be difficult to understand for the inexperienced. 347 | // Please use the references to gain more information. 348 | static void InvMixColumns(state_t* state) 349 | { 350 | int i; 351 | uint8_t a, b, c, d; 352 | for (i = 0; i < 4; ++i) 353 | { 354 | a = (*state)[i][0]; 355 | b = (*state)[i][1]; 356 | c = (*state)[i][2]; 357 | d = (*state)[i][3]; 358 | 359 | (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); 360 | (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); 361 | (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); 362 | (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); 363 | } 364 | } 365 | 366 | 367 | // The SubBytes Function Substitutes the values in the 368 | // state matrix with values in an S-box. 369 | static void InvSubBytes(state_t* state) 370 | { 371 | uint8_t i, j; 372 | for (i = 0; i < 4; ++i) 373 | { 374 | for (j = 0; j < 4; ++j) 375 | { 376 | (*state)[j][i] = getSBoxInvert((*state)[j][i]); 377 | } 378 | } 379 | } 380 | 381 | static void InvShiftRows(state_t* state) 382 | { 383 | uint8_t temp; 384 | 385 | // Rotate first row 1 columns to right 386 | temp = (*state)[3][1]; 387 | (*state)[3][1] = (*state)[2][1]; 388 | (*state)[2][1] = (*state)[1][1]; 389 | (*state)[1][1] = (*state)[0][1]; 390 | (*state)[0][1] = temp; 391 | 392 | // Rotate second row 2 columns to right 393 | temp = (*state)[0][2]; 394 | (*state)[0][2] = (*state)[2][2]; 395 | (*state)[2][2] = temp; 396 | 397 | temp = (*state)[1][2]; 398 | (*state)[1][2] = (*state)[3][2]; 399 | (*state)[3][2] = temp; 400 | 401 | // Rotate third row 3 columns to right 402 | temp = (*state)[0][3]; 403 | (*state)[0][3] = (*state)[1][3]; 404 | (*state)[1][3] = (*state)[2][3]; 405 | (*state)[2][3] = (*state)[3][3]; 406 | (*state)[3][3] = temp; 407 | } 408 | #endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) 409 | 410 | // Cipher is the main function that encrypts the PlainText. 411 | static void Cipher(state_t* state, uint8_t* RoundKey) 412 | { 413 | uint8_t round = 0; 414 | 415 | // Add the First round key to the state before starting the rounds. 416 | AddRoundKey(0, state, RoundKey); 417 | 418 | // There will be Nr rounds. 419 | // The first Nr-1 rounds are identical. 420 | // These Nr-1 rounds are executed in the loop below. 421 | for (round = 1; round < Nr; ++round) 422 | { 423 | SubBytes(state); 424 | ShiftRows(state); 425 | MixColumns(state); 426 | AddRoundKey(round, state, RoundKey); 427 | } 428 | 429 | // The last round is given below. 430 | // The MixColumns function is not here in the last round. 431 | SubBytes(state); 432 | ShiftRows(state); 433 | AddRoundKey(Nr, state, RoundKey); 434 | } 435 | 436 | #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) 437 | static void InvCipher(state_t* state,uint8_t* RoundKey) 438 | { 439 | uint8_t round = 0; 440 | 441 | // Add the First round key to the state before starting the rounds. 442 | AddRoundKey(Nr, state, RoundKey); 443 | 444 | // There will be Nr rounds. 445 | // The first Nr-1 rounds are identical. 446 | // These Nr-1 rounds are executed in the loop below. 447 | for (round = (Nr - 1); round > 0; --round) 448 | { 449 | InvShiftRows(state); 450 | InvSubBytes(state); 451 | AddRoundKey(round, state, RoundKey); 452 | InvMixColumns(state); 453 | } 454 | 455 | // The last round is given below. 456 | // The MixColumns function is not here in the last round. 457 | InvShiftRows(state); 458 | InvSubBytes(state); 459 | AddRoundKey(0, state, RoundKey); 460 | } 461 | #endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) 462 | 463 | /*****************************************************************************/ 464 | /* Public functions: */ 465 | /*****************************************************************************/ 466 | #if defined(ECB) && (ECB == 1) 467 | 468 | 469 | void AES_ECB_encrypt(struct AES_ctx *ctx, uint8_t* buf) 470 | { 471 | // The next function call encrypts the PlainText with the Key using AES algorithm. 472 | Cipher((state_t*)buf, ctx->RoundKey); 473 | } 474 | 475 | void AES_ECB_decrypt(struct AES_ctx* ctx, uint8_t* buf) 476 | { 477 | // The next function call decrypts the PlainText with the Key using AES algorithm. 478 | InvCipher((state_t*)buf, ctx->RoundKey); 479 | } 480 | 481 | 482 | #endif // #if defined(ECB) && (ECB == 1) 483 | 484 | 485 | 486 | 487 | 488 | #if defined(CBC) && (CBC == 1) 489 | 490 | 491 | static void XorWithIv(uint8_t* buf, uint8_t* Iv) 492 | { 493 | uint8_t i; 494 | for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size 495 | { 496 | buf[i] ^= Iv[i]; 497 | } 498 | } 499 | 500 | void AES_CBC_encrypt_buffer(struct AES_ctx *ctx,uint8_t* buf, uint32_t length) 501 | { 502 | uintptr_t i; 503 | uint8_t *Iv = ctx->Iv; 504 | for (i = 0; i < length; i += AES_BLOCKLEN) 505 | { 506 | XorWithIv(buf, Iv); 507 | Cipher((state_t*)buf, ctx->RoundKey); 508 | Iv = buf; 509 | buf += AES_BLOCKLEN; 510 | //printf("Step %d - %d", i/16, i); 511 | } 512 | /* store Iv in ctx for next call */ 513 | memcpy(ctx->Iv, Iv, AES_BLOCKLEN); 514 | } 515 | 516 | void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) 517 | { 518 | uintptr_t i; 519 | uint8_t storeNextIv[AES_BLOCKLEN]; 520 | for (i = 0; i < length; i += AES_BLOCKLEN) 521 | { 522 | memcpy(storeNextIv, buf, AES_BLOCKLEN); 523 | InvCipher((state_t*)buf, ctx->RoundKey); 524 | XorWithIv(buf, ctx->Iv); 525 | memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); 526 | buf += AES_BLOCKLEN; 527 | } 528 | 529 | } 530 | 531 | #endif // #if defined(CBC) && (CBC == 1) 532 | 533 | 534 | 535 | #if defined(CTR) && (CTR == 1) 536 | 537 | /* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ 538 | void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) 539 | { 540 | uint8_t buffer[AES_BLOCKLEN]; 541 | 542 | unsigned i; 543 | int bi; 544 | for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) 545 | { 546 | if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ 547 | { 548 | 549 | memcpy(buffer, ctx->Iv, AES_BLOCKLEN); 550 | Cipher((state_t*)buffer,ctx->RoundKey); 551 | 552 | /* Increment Iv and handle overflow */ 553 | for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) 554 | { 555 | /* inc will owerflow */ 556 | if (ctx->Iv[bi] == 255) 557 | { 558 | ctx->Iv[bi] = 0; 559 | continue; 560 | } 561 | ctx->Iv[bi] += 1; 562 | break; 563 | } 564 | bi = 0; 565 | } 566 | 567 | buf[i] = (buf[i] ^ buffer[bi]); 568 | } 569 | } 570 | 571 | #endif // #if defined(CTR) && (CTR == 1) 572 | 573 | -------------------------------------------------------------------------------- /crypto.c: -------------------------------------------------------------------------------- 1 | // golden 2 | 3 | #include "crypto.h" 4 | 5 | int aes128_cbc_encrypt(void *key, void *plaintext, void *ciphertext, int length, void *iv) { 6 | struct AES_ctx ctx; 7 | 8 | unsigned char *temp = (unsigned char *)malloc(length); 9 | if(!temp) { 10 | return 1; 11 | } 12 | 13 | memcpy(temp, plaintext, length); 14 | 15 | AES_init_ctx_iv(&ctx, key, iv); 16 | AES_CBC_encrypt_buffer(&ctx, temp, length); 17 | 18 | memcpy(ciphertext, temp, length); 19 | free(temp); 20 | 21 | return 0; 22 | } 23 | 24 | int aes128_cbc_decrypt(void *key, void *ciphertext, void *plaintext, int length, void *iv) { 25 | struct AES_ctx ctx; 26 | 27 | unsigned char *temp = (unsigned char *)malloc(length); 28 | if(!temp) { 29 | return 1; 30 | } 31 | 32 | memcpy(temp, ciphertext, length); 33 | 34 | AES_init_ctx_iv(&ctx, key, iv); 35 | AES_CBC_decrypt_buffer(&ctx, temp, length); 36 | 37 | memcpy(plaintext, temp, length); 38 | free(temp); 39 | 40 | return 0; 41 | } 42 | 43 | int aes128_cbc_iv_zero_encrypt(void *key, void *plaintext, void *ciphertext, int length) { 44 | unsigned char zero_iv[16] = { 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 46 | }; 47 | 48 | return aes128_cbc_encrypt(key, plaintext, ciphertext, length, zero_iv); 49 | } 50 | 51 | int aes128_cbc_iv_zero_decrypt(void *key, void *ciphertext, void *plaintext, int length) { 52 | unsigned char zero_iv[16] = { 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 54 | }; 55 | 56 | return aes128_cbc_decrypt(key, ciphertext, plaintext, length, zero_iv); 57 | } 58 | 59 | int arzl_decompress(unsigned char *buffer, unsigned int buflen, const unsigned char *input, const unsigned char **endptr) { 60 | #define LOBYTE(x) (*(uint8_t *)&x) 61 | unsigned char *v5; // r5@1 62 | unsigned char v6; // r11@1 63 | int v7; // r4@1 64 | unsigned char *v8; // r1@2 65 | signed int v9; // r2@2 66 | unsigned int v10; // r3@2 67 | signed int v11; // r0@2 68 | unsigned int v12; // r7@3 69 | unsigned char *v13; // r8@3 70 | unsigned char *v14; // r7@4 71 | unsigned int v15; // r6@4 72 | int v16; // lr@5 73 | int v17; // r6@5 74 | unsigned char *i; // r8@9 75 | unsigned char *v19; // r7@10 76 | unsigned char *v20; // r12@10 77 | unsigned int v21; // r6@10 78 | int v22; // r10@11 79 | int v23; // r6@11 80 | int v25; // r10@22 81 | int v26; // lr@23 82 | unsigned int v27; // r3@24 83 | signed int v28; // r12@24 84 | const unsigned char *v29; // r9@24 85 | unsigned char v30; // zf@25 86 | unsigned int v31; // lr@25 87 | int v32; // r2@27 88 | int v33; // r6@29 89 | unsigned char *v34; // r6@30 90 | int v35; // r2@31 91 | unsigned char *v36; // r0@32 92 | unsigned int v37; // r2@32 93 | int v38; // lr@33 94 | int v39; // r2@33 95 | uint8_t v40; // cf@33 96 | signed int v41; // r10@37 97 | int v42; // r2@42 98 | unsigned int v43; // r9@43 99 | int v44; // r7@43 100 | int v45; // lr@51 101 | signed int v46; // r7@52 102 | unsigned int v47; // r10@56 103 | int v48; // r7@57 104 | int v49; // r7@58 105 | int v50; // r10@58 106 | unsigned char v51; // cf@58 107 | unsigned int v52; // r10@65 108 | int v53; // r7@66 109 | int v54; // r7@67 110 | int v55; // r10@67 111 | unsigned int v56; // r10@71 112 | int v57; // r7@72 113 | int v58; // r7@73 114 | int v59; // r10@73 115 | unsigned char v60; // cf@73 116 | signed int v61; // r7@83 117 | unsigned char *v62; // r9@84 118 | unsigned int v63; // r10@85 119 | int v64; // r2@85 120 | int v65; // lr@85 121 | signed int v66; // r0@87 122 | signed int v67; // r0@92 123 | int v68; // r6@96 124 | unsigned char *v69; // r12@96 125 | unsigned int v70; // r0@96 126 | int v71; // lr@97 127 | int v72; // r0@97 128 | unsigned char v73; // cf@97 129 | signed int v74; // r10@101 130 | int v75; // r0@101 131 | int v76; // r0@106 132 | unsigned int v77; // r9@107 133 | int v78; // r7@107 134 | int v79; // lr@115 135 | signed int v80; // r7@116 136 | unsigned int v81; // r10@120 137 | int v82; // r7@121 138 | int v83; // r7@122 139 | int v84; // r10@122 140 | unsigned char v85; // cf@122 141 | unsigned int v86; // r10@129 142 | int v87; // r7@130 143 | int v88; // r7@131 144 | int v89; // r10@131 145 | unsigned int v90; // r7@135 146 | int v91; // r6@136 147 | int v92; // r6@137 148 | int v93; // r7@137 149 | unsigned char v94; // cf@137 150 | unsigned char *v95; // r12@144 151 | unsigned char *v96; // r6@145 152 | int v97; // r0@145 153 | int v98; // lr@150 154 | int v99; // lr@151 155 | int v100; // r10@157 156 | const unsigned char *input_1; // [sp+4h] [bp-CE4h]@1 157 | int v104; // [sp+10h] [bp-CD8h]@32 158 | signed int v105; // [sp+10h] [bp-CD8h]@81 159 | signed int v106; // [sp+10h] [bp-CD8h]@92 160 | signed int v107; // [sp+14h] [bp-CD4h]@83 161 | int v108; // [sp+14h] [bp-CD4h]@96 162 | unsigned char v109[3240]; // [sp+18h] [bp-CD0h]@2 163 | 164 | v5 = &buffer[buflen]; 165 | input_1 = input; 166 | v6 = *input & 7; 167 | v7 = __builtin_bswap32(*(uint32_t *)(input + 1)); 168 | if ( !(*input & 0x80) ) 169 | { 170 | memset(v109, 16 * (8 - (((const uint8_t)*input >> 3) & 3)) & 0xF0, 3240); 171 | v8 = buffer; 172 | v9 = 0; 173 | v10 = -1; 174 | for ( v11 = 0; v8 != v5; *v20 = v22 ) 175 | { 176 | v12 = (v9 & 0xFFFFF8FF) | (((uint8_t)((uint64_t)v8) & 7) << 8); 177 | v9 = 1; 178 | v13 = &v109[255 * ((v12 >> v6) & 7)]; 179 | do 180 | { 181 | v14 = &v13[v9]; 182 | v15 = (uint8_t)v13[v9 - 1]; 183 | v9 *= 2; 184 | if ( !(v10 >> 24) ) 185 | { 186 | v10 <<= 8; 187 | v25 = (input_1++)[5]; 188 | v7 = v25 + (v7 << 8); 189 | } 190 | v16 = v15 * (v10 >> 8); 191 | v17 = v15 - (v15 >> 3); 192 | v10 -= v16; 193 | if ( v7 >= (unsigned int)v16 ) 194 | { 195 | v7 -= v16; 196 | } 197 | else 198 | { 199 | ++v9; 200 | LOBYTE(v17) = v17 + 31; 201 | v10 = v16; 202 | } 203 | *(v14 - 1) = v17; 204 | } 205 | while ( v9 <= 255 ); 206 | for ( i = v8; ; i = &v8[~(intptr_t)i] + (intptr_t)v95 ) 207 | { 208 | v19 = &v109[v11]; 209 | *i = v9; 210 | v8 = i + 1; 211 | v20 = &v109[v11 + 2920]; 212 | v21 = (uint8_t)*v20; 213 | if ( !(v10 >> 24) ) 214 | { 215 | v10 <<= 8; 216 | v26 = (input_1++)[5]; 217 | v7 = v26 + (v7 << 8); 218 | } 219 | v22 = v21 - (v21 >> 4); 220 | v23 = v21 * (v10 >> 8); 221 | if ( v7 >= (unsigned int)v23 ) 222 | break; 223 | v27 = v23; 224 | *v20 = v22 + 15; 225 | v28 = -1; 226 | v29 = input_1; 227 | while ( 1 ) 228 | { 229 | v30 = v27 >> 24 == 0; 230 | v31 = (uint8_t)v19[2928]; 231 | if ( !(v27 >> 24) ) 232 | { 233 | v27 <<= 8; 234 | v23 = (v29++)[5]; 235 | } 236 | v19 += 8; 237 | v32 = v31 * (v27 >> 8); 238 | if ( v30 ) 239 | v7 = v23 + (v7 << 8); 240 | v33 = v31 - (v31 >> 4); 241 | if ( v7 >= (unsigned int)v32 ) 242 | break; 243 | ++v28; 244 | v23 = v33 + 15; 245 | v27 = v31 * (v27 >> 8); 246 | v19[2920] = v23; 247 | if ( v28 == 6 ) 248 | { 249 | input_1 = v29; 250 | v34 = &v109[6]; 251 | v10 = v32; 252 | goto LABEL_32; 253 | } 254 | } 255 | v10 = v27 - v32; 256 | v7 -= v32; 257 | input_1 = v29; 258 | v19[2920] = v33; 259 | v34 = &v109[v28]; 260 | if ( v28 == -1 ) 261 | { 262 | v35 = 1; 263 | goto LABEL_82; 264 | } 265 | LABEL_32: 266 | v36 = &v109[32 * v28 | 8 * (((uint32_t)(uint64_t)v8 << v28) & 3) | (v11 & 7)]; 267 | v104 = v28 - 3; 268 | v37 = (uint8_t)v36[2984]; 269 | if ( !(v10 >> 24) ) 270 | { 271 | v10 <<= 8; 272 | v100 = (input_1++)[5]; 273 | v7 = v100 + (v7 << 8); 274 | } 275 | v38 = v37 - (v37 >> 4); 276 | v39 = v37 * (v10 >> 8); 277 | v40 = v7 >= (unsigned int)v39; 278 | if ( v7 >= (unsigned int)v39 ) 279 | { 280 | v10 -= v39; 281 | v7 -= v39; 282 | } 283 | else 284 | { 285 | LOBYTE(v38) = v38 + 15; 286 | v10 = v39; 287 | } 288 | if ( v40 ) 289 | { 290 | v41 = 4; 291 | v35 = 2; 292 | } 293 | else 294 | { 295 | v41 = 6; 296 | v35 = 3; 297 | } 298 | v36[2984] = v38; 299 | if ( v104 >= 0 ) 300 | { 301 | if ( v28 != 3 ) 302 | { 303 | if ( !(v10 >> 24) ) 304 | { 305 | v10 <<= 8; 306 | v42 = (input_1++)[5]; 307 | v7 = v42 + (v7 << 8); 308 | } 309 | v43 = (uint8_t)v38 - ((unsigned int)(uint8_t)v38 >> 4); 310 | v44 = (uint8_t)v38 * (v10 >> 8); 311 | if ( v7 >= (unsigned int)v44 ) 312 | v35 = v41; 313 | else 314 | v35 = v41 + 1; 315 | if ( v7 >= (unsigned int)v44 ) 316 | { 317 | v10 -= v44; 318 | v7 -= v44; 319 | } 320 | else 321 | { 322 | LOBYTE(v43) = v43 + 15; 323 | v10 = (uint8_t)v38 * (v10 >> 8); 324 | } 325 | v36[2984] = v43; 326 | if ( v104 != 1 ) 327 | { 328 | if ( !(v10 >> 24) ) 329 | { 330 | v10 <<= 8; 331 | v45 = (input_1++)[5]; 332 | v7 = v45 + (v7 << 8); 333 | } 334 | v46 = v28; 335 | do 336 | { 337 | v10 >>= 1; 338 | --v46; 339 | v35 = (v7 < v10) + 2 * v35; 340 | if ( v7 >= v10 ) 341 | v7 -= v10; 342 | } 343 | while ( v46 != 4 ); 344 | } 345 | } 346 | v47 = (uint8_t)v36[3008]; 347 | if ( !(v10 >> 24) ) 348 | { 349 | v10 <<= 8; 350 | v48 = (input_1++)[5]; 351 | v7 = v48 + (v7 << 8); 352 | } 353 | v49 = v47 - (v47 >> 4); 354 | v35 *= 2; 355 | v50 = v47 * (v10 >> 8); 356 | v51 = v7 >= (unsigned int)v50; 357 | if ( v7 >= (unsigned int)v50 ) 358 | { 359 | v10 -= v50; 360 | v7 -= v50; 361 | } 362 | else 363 | { 364 | ++v35; 365 | v10 = v50; 366 | } 367 | if ( !v51 ) 368 | LOBYTE(v49) = v49 + 15; 369 | v36[3008] = v49; 370 | } 371 | if ( v28 ) 372 | { 373 | v52 = (uint8_t)v36[2992]; 374 | if ( !(v10 >> 24) ) 375 | { 376 | v10 <<= 8; 377 | v53 = (input_1++)[5]; 378 | v7 = v53 + (v7 << 8); 379 | } 380 | v54 = v52 - (v52 >> 4); 381 | v35 *= 2; 382 | v55 = v52 * (v10 >> 8); 383 | if ( v7 >= (unsigned int)v55 ) 384 | { 385 | v10 -= v55; 386 | v7 -= v55; 387 | } 388 | else 389 | { 390 | LOBYTE(v54) = v54 + 15; 391 | ++v35; 392 | v10 = v55; 393 | } 394 | v36[2992] = v54; 395 | if ( v28 != 1 ) 396 | { 397 | v56 = (uint8_t)v36[3000]; 398 | if ( !(v10 >> 24) ) 399 | { 400 | v10 <<= 8; 401 | v57 = (input_1++)[5]; 402 | v7 = v57 + (v7 << 8); 403 | } 404 | v58 = v56 - (v56 >> 4); 405 | v35 *= 2; 406 | v59 = v56 * (v10 >> 8); 407 | v60 = v7 >= (unsigned int)v59; 408 | if ( v7 >= (unsigned int)v59 ) 409 | { 410 | v10 -= v59; 411 | v7 -= v59; 412 | } 413 | else 414 | { 415 | ++v35; 416 | v10 = v59; 417 | } 418 | if ( !v60 ) 419 | LOBYTE(v58) = v58 + 15; 420 | v36[3000] = v58; 421 | } 422 | } 423 | if ( v35 == 255 ) 424 | { 425 | if ( endptr ) 426 | *endptr = input_1 + 5; 427 | return v8 - buffer; 428 | } 429 | if ( v35 != 2 ) 430 | { 431 | v105 = 256; 432 | goto LABEL_83; 433 | } 434 | LABEL_82: 435 | v34 += 248; 436 | v105 = 64; 437 | LABEL_83: 438 | v61 = 8; 439 | v107 = v35; 440 | do 441 | { 442 | v62 = &v34[v61]; 443 | v61 *= 2; 444 | if ( !(v10 >> 24) ) 445 | { 446 | v10 <<= 8; 447 | v98 = (input_1++)[5]; 448 | v7 = v98 + (v7 << 8); 449 | } 450 | v63 = (uint8_t)v62[2033]; 451 | v64 = v63 * (v10 >> 8); 452 | v65 = v63 - (v63 >> 3); 453 | v10 -= v64; 454 | if ( v7 < (unsigned int)v64 ) 455 | { 456 | v61 += 8; 457 | LOBYTE(v65) = v65 + 31; 458 | } 459 | v66 = v61 - v105; 460 | if ( v7 >= (unsigned int)v64 ) 461 | v7 -= v64; 462 | else 463 | v10 = v64; 464 | v62[2033] = v65; 465 | } 466 | while ( v66 < 0 ); 467 | v9 = v107; 468 | if ( v61 != v105 ) 469 | { 470 | v67 = v66 >> 3; 471 | v106 = v67; 472 | if ( v107 <= 2 ) 473 | v67 = 0; 474 | if ( v107 > 2 ) 475 | v67 = 1; 476 | v68 = v106 - 1; 477 | v108 = v106 - 4; 478 | v69 = &v109[8 * ((v67 << (v106 - 1)) & 3) | 32 * (v106 - 1) | (v28 & 7)]; 479 | v70 = (uint8_t)v69[2344]; 480 | if ( !(v10 >> 24) ) 481 | { 482 | v10 <<= 8; 483 | v99 = (input_1++)[5]; 484 | v7 = v99 + (v7 << 8); 485 | } 486 | v71 = v70 - (v70 >> 4); 487 | v72 = v70 * (v10 >> 8); 488 | v73 = v7 >= (unsigned int)v72; 489 | if ( v7 >= (unsigned int)v72 ) 490 | { 491 | v10 -= v72; 492 | v7 -= v72; 493 | } 494 | else 495 | { 496 | LOBYTE(v71) = v71 + 15; 497 | v10 = v72; 498 | } 499 | if ( v73 ) 500 | { 501 | v74 = 4; 502 | v75 = 2; 503 | } 504 | else 505 | { 506 | v74 = 6; 507 | v75 = 3; 508 | } 509 | v69[2344] = v71; 510 | if ( v108 >= 0 ) 511 | { 512 | if ( v106 != 4 ) 513 | { 514 | if ( !(v10 >> 24) ) 515 | { 516 | v10 <<= 8; 517 | v76 = (input_1++)[5]; 518 | v7 = v76 + (v7 << 8); 519 | } 520 | v77 = (uint8_t)v71 - ((unsigned int)(uint8_t)v71 >> 4); 521 | v78 = (uint8_t)v71 * (v10 >> 8); 522 | if ( v7 >= (unsigned int)v78 ) 523 | v75 = v74; 524 | else 525 | v75 = v74 + 1; 526 | if ( v7 >= (unsigned int)v78 ) 527 | { 528 | v10 -= v78; 529 | v7 -= v78; 530 | } 531 | else 532 | { 533 | LOBYTE(v77) = v77 + 15; 534 | v10 = (uint8_t)v71 * (v10 >> 8); 535 | } 536 | v69[2344] = v77; 537 | if ( v108 != 1 ) 538 | { 539 | if ( !(v10 >> 24) ) 540 | { 541 | v10 <<= 8; 542 | v79 = (input_1++)[5]; 543 | v7 = v79 + (v7 << 8); 544 | } 545 | v80 = v106; 546 | do 547 | { 548 | v10 >>= 1; 549 | --v80; 550 | v75 = (v7 < v10) + 2 * v75; 551 | if ( v7 >= v10 ) 552 | v7 -= v10; 553 | } 554 | while ( v80 != 5 ); 555 | } 556 | } 557 | v81 = (uint8_t)v69[2368]; 558 | if ( !(v10 >> 24) ) 559 | { 560 | v10 <<= 8; 561 | v82 = (input_1++)[5]; 562 | v7 = v82 + (v7 << 8); 563 | } 564 | v83 = v81 - (v81 >> 4); 565 | v75 *= 2; 566 | v84 = v81 * (v10 >> 8); 567 | v85 = v7 >= (unsigned int)v84; 568 | if ( v7 >= (unsigned int)v84 ) 569 | { 570 | v10 -= v84; 571 | v7 -= v84; 572 | } 573 | else 574 | { 575 | ++v75; 576 | v10 = v84; 577 | } 578 | if ( !v85 ) 579 | LOBYTE(v83) = v83 + 15; 580 | v69[2368] = v83; 581 | } 582 | if ( v68 > 0 ) 583 | { 584 | v86 = (uint8_t)v69[2352]; 585 | if ( !(v10 >> 24) ) 586 | { 587 | v10 <<= 8; 588 | v87 = (input_1++)[5]; 589 | v7 = v87 + (v7 << 8); 590 | } 591 | v88 = v86 - (v86 >> 4); 592 | v75 *= 2; 593 | v89 = v86 * (v10 >> 8); 594 | if ( v7 >= (unsigned int)v89 ) 595 | { 596 | v10 -= v89; 597 | v7 -= v89; 598 | } 599 | else 600 | { 601 | LOBYTE(v88) = v88 + 15; 602 | ++v75; 603 | v10 = v89; 604 | } 605 | v69[2352] = v88; 606 | if ( v68 != 1 ) 607 | { 608 | v90 = (uint8_t)v69[2360]; 609 | if ( !(v10 >> 24) ) 610 | { 611 | v10 <<= 8; 612 | v91 = (input_1++)[5]; 613 | v7 = v91 + (v7 << 8); 614 | } 615 | v92 = v90 - (v90 >> 4); 616 | v75 *= 2; 617 | v93 = v90 * (v10 >> 8); 618 | v94 = v7 >= (unsigned int)v93; 619 | if ( v7 >= (unsigned int)v93 ) 620 | { 621 | v10 -= v93; 622 | v7 -= v93; 623 | } 624 | else 625 | { 626 | ++v75; 627 | v10 = v93; 628 | } 629 | if ( !v94 ) 630 | LOBYTE(v92) = v92 + 15; 631 | v69[2360] = v92; 632 | } 633 | } 634 | v66 = v75 - 1; 635 | } 636 | v95 = i + 1; 637 | if ( v8 - buffer <= (unsigned int)v66 ) 638 | return 0x80560200; 639 | v96 = &v8[v9]; 640 | v97 = ~v66; 641 | v40 = v5 >= &v8[v9]; 642 | v30 = v5 == &v8[v9]; 643 | LOBYTE(v9) = v8[v97]; 644 | if ( !(!v30 & v40) ) 645 | return 0x80560201; 646 | do 647 | { 648 | *(uint8_t *)v95++ = v9; 649 | v9 = *(uint8_t *)(v95 + v97); 650 | } 651 | while ( v95 != v96 ); 652 | v11 = 7; 653 | } 654 | v10 -= v23; 655 | if ( v11 ) 656 | --v11; 657 | else 658 | v11 = 0; 659 | v7 -= v23; 660 | } 661 | return 0x80560201; 662 | } 663 | if ( buflen < v7 ) 664 | return 0x80560201; 665 | memcpy(buffer, input + 5, __builtin_bswap32(*(uint32_t *)(input + 1))); 666 | if ( endptr ) 667 | *endptr = &input[v7 + 5]; 668 | return v7; 669 | } 670 | 671 | int arzl_deobfuscate(unsigned char *buffer, int len, int version) { 672 | unsigned char *buf; // r3@1 673 | unsigned char *bufend; // r12@1 674 | unsigned int data; // t1@3 MAPDST 675 | unsigned int change_stride; // r5@3 676 | unsigned char *buf_1; // r3@8 677 | unsigned int v10; // r4@8 678 | unsigned int v11; // r5@8 679 | unsigned int v12; // t1@12 680 | unsigned int v13; // r4@13 681 | unsigned int v14; // r4@14 682 | intptr_t offset; 683 | 684 | buf = buffer; 685 | bufend = &buffer[len]; 686 | if ( len ) 687 | { 688 | if ( version == 2 ) 689 | { 690 | do 691 | { 692 | data = *(uint32_t *)buf; 693 | buf += 4; 694 | change_stride = (data & 0xF800F800) >> 27; 695 | offset = (buf - buffer); 696 | if ( (data & 0xF800F800) == 0xF800F000 ) 697 | { 698 | v14 = (((data >> 16) & 0xFFC007FF) | ((data & 0x7FF) << 11)) - (offset >> 1); 699 | v14 = ((((v14 & 0x7FF) << 16) | 0xF800F000) & 0xFFFFF800) | ((v14 >> 11) & 0x7FF); 700 | *((uint32_t *)buf - 1) = v14; 701 | } 702 | else if ( (data & 0x8000FBF0) == 0x0000F2C0 ) 703 | { 704 | v14 = (data & 0xF0FFFFF0) | ((data & 0xF) << 24) | ((data >> 24) & 0xF); 705 | *((uint32_t *)buf - 1) = v14; 706 | } 707 | else if ( change_stride == 30 ) 708 | { 709 | buf -= 2; 710 | } 711 | } 712 | while ( bufend > buf ); 713 | } 714 | else if ( version == 1 ) 715 | { 716 | buf_1 = buffer + 4; 717 | v10 = *(uint32_t *)buffer; 718 | v11 = (*(uint32_t *)buffer & 0xF800F800) >> 27; 719 | if ( (*(uint32_t *)buffer & 0xF800F800) == 0xF800F000 ) 720 | goto LABEL_13; 721 | LABEL_9: 722 | if ( v11 == 30 ) 723 | buf_1 -= 2; 724 | while ( buf_1 < bufend ) 725 | { 726 | v12 = *(uint32_t *)buf_1; 727 | buf_1 += 4; 728 | v10 = v12; 729 | v11 = (v12 & 0xF800F800) >> 27; 730 | if ( (v12 & 0xF800F800) != 0xF800F000 ) 731 | goto LABEL_9; 732 | LABEL_13: 733 | v13 = (((v10 >> 16) & 0xFFC007FF) | ((v10 & 0x7FF) << 11)) + ((buf_1 - buffer) >> 1); 734 | *((uint32_t *)buf_1 - 1) = ((((v13 & 0x7FF) << 16) | 0xF800F000) & 0xFFFFF800) | ((v13 >> 11) & 0x7FF); 735 | } 736 | } 737 | else 738 | { 739 | do 740 | { 741 | data = *(uint32_t *)buf; 742 | buf += 4; 743 | change_stride = (data & 0xF800F800) >> 27; 744 | if ( (data & 0xF800F800) == 0xF800F000 ) 745 | { 746 | v14 = (((data >> 16) & 0xFFC007FF) | ((data & 0x7FF) << 11)) - ((buf - buffer) >> 1); 747 | *((uint32_t *)buf - 1) = ((((v14 & 0x7FF) << 16) | 0xF800F000) & 0xFFFFF800) | ((v14 >> 11) & 0x7FF); 748 | } 749 | else if ( change_stride == 30 ) 750 | { 751 | buf -= 2; 752 | } 753 | } 754 | while ( bufend > buf ); 755 | } 756 | } 757 | return len; 758 | } 759 | --------------------------------------------------------------------------------