├── parentool ├── Makefile └── main.c ├── ctrtool ├── info.h ├── filepath.h ├── Makefile ├── types.h ├── lzss.h ├── utils.h ├── firm.h ├── ncsd.h ├── stream.h ├── tik.h ├── cia.h ├── keyset.h ├── ivfc.h ├── exefs.h ├── tinyxml │ ├── tinyxmlerror.cpp │ ├── tinystr.cpp │ └── tinystr.h ├── filepath.c ├── tmd.h ├── ncch.h ├── romfs.h ├── polarssl │ ├── padlock.h │ ├── aes.h │ ├── sha2.h │ ├── config.h │ └── rsa.h ├── settings.h ├── stream.c ├── tik.c ├── ctr.h ├── utils.c ├── exheader.h ├── ncsd.c ├── lzss.c ├── windows │ ├── getopt1.c │ └── getopt.h ├── tmd.c ├── cwav.h ├── ivfc.c ├── settings.c ├── firm.c ├── keyset.cpp ├── ctr.c ├── cia.c ├── exefs.c ├── ctrtool.vcproj ├── romfs.c └── main.c └── idaloader ├── README └── ctr_ldr.py /parentool/Makefile: -------------------------------------------------------------------------------- 1 | OBJS = main.o 2 | LIBS = 3 | CXXFLAGS = -I. 4 | CFLAGS = -Wall -I. 5 | OUTPUT = parentool 6 | CC = gcc 7 | 8 | main: $(OBJS) 9 | g++ -o $(OUTPUT) $(LIBS) $(OBJS) 10 | 11 | 12 | clean: 13 | rm -rf $(OUTPUT) $(OBJS) 14 | -------------------------------------------------------------------------------- /ctrtool/info.h: -------------------------------------------------------------------------------- 1 | #ifndef _INFO_H_ 2 | #define _INFO_H_ 3 | 4 | #include "types.h" 5 | #include "keyset.h" 6 | 7 | typedef struct 8 | { 9 | FILE* file; 10 | keyset* keys; 11 | u32 offset; 12 | const u8* blob; 13 | u32 blobsize; 14 | } infocontext; 15 | 16 | #endif // _INFO_H_ 17 | -------------------------------------------------------------------------------- /ctrtool/filepath.h: -------------------------------------------------------------------------------- 1 | #ifndef _FILEPATH_H_ 2 | #define _FILEPATH_H_ 3 | 4 | #include "types.h" 5 | #include "utils.h" 6 | 7 | typedef struct 8 | { 9 | char pathname[MAX_PATH]; 10 | int valid; 11 | } filepath; 12 | 13 | void filepath_init(filepath* fpath); 14 | void filepath_copy(filepath* fpath, filepath* copy); 15 | void filepath_append_utf16(filepath* fpath, const u8* name); 16 | void filepath_append(filepath* fpath, const char* format, ...); 17 | void filepath_set(filepath* fpath, const char* path); 18 | const char* filepath_get(filepath* fpath); 19 | 20 | #endif // _FILEPATH_H_ 21 | -------------------------------------------------------------------------------- /ctrtool/Makefile: -------------------------------------------------------------------------------- 1 | OBJS = keyset.o main.o ctr.o ncsd.o cia.o tik.o tmd.o filepath.o lzss.o exheader.o exefs.o ncch.o utils.o settings.o firm.o cwav.o stream.o romfs.o ivfc.o 2 | POLAR_OBJS = polarssl/aes.o polarssl/bignum.o polarssl/rsa.o polarssl/sha2.o 3 | TINYXML_OBJS = tinyxml/tinystr.o tinyxml/tinyxml.o tinyxml/tinyxmlerror.o tinyxml/tinyxmlparser.o 4 | LIBS = -lstdc++ 5 | CXXFLAGS = -I. 6 | CFLAGS = -Wall -I. 7 | OUTPUT = ctrtool 8 | CC = gcc 9 | 10 | main: $(OBJS) $(POLAR_OBJS) $(TINYXML_OBJS) 11 | g++ -o $(OUTPUT) $(LIBS) $(OBJS) $(POLAR_OBJS) $(TINYXML_OBJS) 12 | 13 | 14 | clean: 15 | rm -rf $(OUTPUT) $(OBJS) $(POLAR_OBJS) $(TINYXML_OBJS) 16 | -------------------------------------------------------------------------------- /idaloader/README: -------------------------------------------------------------------------------- 1 | ctr_ldr.py -- a FIRM/NCCH Loader for IDA 2 | === 3 | ___ 4 | 5 | You will need a recent-ish IDA with IDAPython and construct (http://construct.wikispaces.com) 6 | 7 | To install construct you probably want to grab setuptools (http://pypi.python.org/pypi/setuptools/) 8 | 9 | Just follow this easy 8-step walkthrough: 10 | 11 | * run setuptools installer (if you dont have setuptools already) 12 | * extract construct tarball, run python setup.py install 13 | * copy ctr_ldr.py to ida/loaders 14 | * dump firmware from 3ds 15 | * decrypt it 16 | * load 'er up in IDA 17 | * ???? 18 | * PROFIT!! 19 | 20 | Enjoy kids! 21 | 22 | -- blasty 23 | 24 | -------------------------------------------------------------------------------- /ctrtool/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef unsigned char u8; 7 | typedef unsigned short u16; 8 | typedef unsigned int u32; 9 | typedef unsigned long long u64; 10 | 11 | typedef signed char s8; 12 | typedef signed short s16; 13 | typedef signed int s32; 14 | typedef signed long long s64; 15 | 16 | enum flags 17 | { 18 | ExtractFlag = (1<<0), 19 | InfoFlag = (1<<1), 20 | PlainFlag = (1<<2), 21 | VerboseFlag = (1<<3), 22 | VerifyFlag = (1<<4), 23 | RawFlag = (1<<5), 24 | ShowKeysFlag = (1<<6) 25 | }; 26 | 27 | 28 | 29 | enum validstate 30 | { 31 | Unchecked = 0, 32 | Good = 1, 33 | Fail = 2, 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /ctrtool/lzss.h: -------------------------------------------------------------------------------- 1 | #ifndef _LZSS_H_ 2 | #define _LZSS_H_ 3 | 4 | #include "types.h" 5 | #include "settings.h" 6 | 7 | typedef struct 8 | { 9 | FILE* file; 10 | u32 offset; 11 | u32 size; 12 | settings* usersettings; 13 | } lzss_context; 14 | 15 | void lzss_init(lzss_context* ctx); 16 | void lzss_process(lzss_context* ctx, u32 actions); 17 | void lzss_set_offset(lzss_context* ctx, u32 offset); 18 | void lzss_set_size(lzss_context* ctx, u32 size); 19 | void lzss_set_file(lzss_context* ctx, FILE* file); 20 | void lzss_set_usersettings(lzss_context* ctx, settings* usersettings); 21 | 22 | u32 lzss_get_decompressed_size(u8* compressed, u32 compressedsize); 23 | int lzss_decompress(u8* compressed, u32 compressedsize, u8* decompressed, u32 decompressedsize); 24 | 25 | 26 | #endif // _LZSS_H_ 27 | -------------------------------------------------------------------------------- /ctrtool/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_H_ 2 | #define _UTILS_H_ 3 | 4 | #include "types.h" 5 | 6 | #ifdef _WIN32 7 | #define PATH_SEPERATOR '\\' 8 | #else 9 | #define PATH_SEPERATOR '/' 10 | #endif 11 | 12 | #ifndef MAX_PATH 13 | #define MAX_PATH 255 14 | #endif 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | u32 align(u32 offset, u32 alignment); 21 | u64 align64(u64 offset, u32 alignment); 22 | u64 getle64(const u8* p); 23 | u32 getle32(const u8* p); 24 | u32 getle16(const u8* p); 25 | u64 getbe64(const u8* p); 26 | u32 getbe32(const u8* p); 27 | u32 getbe16(const u8* p); 28 | void putle16(u8* p, u16 n); 29 | void putle32(u8* p, u32 n); 30 | 31 | void readkeyfile(u8* key, const char* keyfname); 32 | void memdump(FILE* fout, const char* prefix, const u8* data, u32 size); 33 | void hexdump(void *ptr, int buflen); 34 | int key_load(char *name, u8 *out_buf); 35 | 36 | int makedir(const char* dir); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif // _UTILS_H_ 43 | -------------------------------------------------------------------------------- /ctrtool/firm.h: -------------------------------------------------------------------------------- 1 | #ifndef _FIRM_H_ 2 | #define _FIRM_H_ 3 | 4 | #include "types.h" 5 | #include "info.h" 6 | #include "ctr.h" 7 | #include "filepath.h" 8 | #include "settings.h" 9 | 10 | 11 | typedef struct 12 | { 13 | u8 offset[4]; 14 | u8 address[4]; 15 | u8 size[4]; 16 | u8 type[4]; 17 | u8 hash[32]; 18 | } firm_sectionheader; 19 | 20 | 21 | 22 | 23 | typedef struct 24 | { 25 | u8 magic[4]; 26 | u8 reserved1[4]; 27 | u8 entrypointarm11[4]; 28 | u8 entrypointarm9[4]; 29 | u8 reserved2[0x30]; 30 | firm_sectionheader section[4]; 31 | u8 signature[0x100]; 32 | } firm_header; 33 | 34 | typedef struct 35 | { 36 | FILE* file; 37 | settings* usersettings; 38 | u32 offset; 39 | u32 size; 40 | firm_header header; 41 | ctr_sha256_context sha; 42 | int hashcheck[4]; 43 | int headersigcheck; 44 | } firm_context; 45 | 46 | void firm_init(firm_context* ctx); 47 | void firm_set_file(firm_context* ctx, FILE* file); 48 | void firm_set_offset(firm_context* ctx, u32 offset); 49 | void firm_set_size(firm_context* ctx, u32 size); 50 | void firm_set_usersettings(firm_context* ctx, settings* usersettings); 51 | void firm_process(firm_context* ctx, u32 actions); 52 | void firm_print(firm_context* ctx); 53 | void firm_save(firm_context* ctx, u32 index, u32 flags); 54 | int firm_verify(firm_context* ctx, u32 flags); 55 | void firm_signature_verify(firm_context* ctx); 56 | 57 | #endif // _FIRM_H_ 58 | -------------------------------------------------------------------------------- /ctrtool/ncsd.h: -------------------------------------------------------------------------------- 1 | #ifndef _NCSD_H_ 2 | #define _NCSD_H_ 3 | 4 | #include "types.h" 5 | #include "keyset.h" 6 | #include "settings.h" 7 | #include "ncch.h" 8 | 9 | typedef struct 10 | { 11 | u32 offset; 12 | u32 size; 13 | } ncsd_partition_geometry; 14 | 15 | typedef struct 16 | { 17 | u8 signature[0x100]; 18 | u8 magic[4]; 19 | u8 mediasize[4]; 20 | u8 mediaid[8]; 21 | u8 partitionfstype[8]; 22 | u8 partitioncrypttype[8]; 23 | ncsd_partition_geometry partitiongeometry[8]; 24 | u8 extendedheaderhash[0x20]; 25 | u8 additionalheadersize[4]; 26 | u8 sectorzerooffset[4]; 27 | u8 flags[8]; 28 | u8 partitionid[0x40]; 29 | u8 reserved[0x30]; 30 | } ctr_ncsdheader; 31 | 32 | 33 | typedef struct 34 | { 35 | FILE* file; 36 | u32 offset; 37 | u32 size; 38 | ctr_ncsdheader header; 39 | settings* usersettings; 40 | int headersigcheck; 41 | ncch_context ncch; 42 | } ncsd_context; 43 | 44 | 45 | void ncsd_init(ncsd_context* ctx); 46 | void ncsd_set_offset(ncsd_context* ctx, u32 offset); 47 | void ncsd_set_size(ncsd_context* ctx, u32 size); 48 | void ncsd_set_file(ncsd_context* ctx, FILE* file); 49 | void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings); 50 | int ncsd_signature_verify(const void* blob, rsakey2048* key); 51 | void ncsd_process(ncsd_context* ctx, u32 actions); 52 | void ncsd_print(ncsd_context* ctx); 53 | unsigned int ncsd_get_mediaunit_size(ncsd_context* ctx); 54 | 55 | #endif // _NCSD_H_ 56 | -------------------------------------------------------------------------------- /ctrtool/stream.h: -------------------------------------------------------------------------------- 1 | #ifndef __STREAM_H__ 2 | #define __STREAM_H__ 3 | 4 | #include 5 | #include "types.h" 6 | 7 | typedef struct 8 | { 9 | FILE* infile; 10 | u32 infileposition; 11 | u8* inbuffer; 12 | u32 inbuffersize; 13 | u32 inbufferavailable; 14 | u32 inbufferpos; 15 | } stream_in_context; 16 | 17 | typedef struct 18 | { 19 | FILE* outfile; 20 | u8* outbuffer; 21 | u32 outbuffersize; 22 | u32 outbufferpos; 23 | } stream_out_context; 24 | 25 | // create/destroy 26 | void stream_in_init(stream_in_context* ctx); 27 | void stream_in_allocate(stream_in_context* ctx, u32 buffersize, FILE* file); 28 | void stream_in_destroy(stream_in_context* ctx); 29 | void stream_out_init(stream_out_context* ctx); 30 | void stream_out_allocate(stream_out_context* ctx, u32 buffersize, FILE* file); 31 | void stream_out_destroy(stream_out_context* ctx); 32 | 33 | // read/write operations 34 | int stream_in_byte(stream_in_context* ctx, u8* byte); 35 | void stream_in_seek(stream_in_context* ctx, u32 position); 36 | void stream_in_reseek(stream_in_context* ctx); 37 | 38 | int stream_out_byte(stream_out_context* ctx, u8 byte); 39 | int stream_out_buffer(stream_out_context* ctx, const void* buffer, u32 size); 40 | int stream_out_flush(stream_out_context* ctx); 41 | void stream_out_seek(stream_out_context* ctx, u32 position); 42 | void stream_out_skip(stream_out_context* ctx, u32 size); 43 | void stream_out_position(stream_out_context* ctx, u32* position); 44 | 45 | #endif // __STREAM_H__ 46 | -------------------------------------------------------------------------------- /ctrtool/tik.h: -------------------------------------------------------------------------------- 1 | #ifndef __TIK_H__ 2 | #define __TIK_H__ 3 | 4 | #include "types.h" 5 | #include "keyset.h" 6 | #include "ctr.h" 7 | #include "settings.h" 8 | 9 | typedef struct 10 | { 11 | u8 enable_timelimit[4]; 12 | u8 timelimit_seconds[4]; 13 | } timelimit_entry; 14 | 15 | typedef struct 16 | { 17 | u8 sig_type[4]; 18 | u8 signature[0x100]; 19 | u8 padding1[0x3c]; 20 | u8 issuer[0x40]; 21 | u8 ecdsa[0x3c]; 22 | u8 padding2[0x03]; 23 | u8 encrypted_title_key[0x10]; 24 | u8 unknown; 25 | u8 ticket_id[8]; 26 | u8 console_id[4]; 27 | u8 title_id[8]; 28 | u8 sys_access[2]; 29 | u8 ticket_version[2]; 30 | u8 time_mask[4]; 31 | u8 permit_mask[4]; 32 | u8 title_export; 33 | u8 commonkey_idx; 34 | u8 unknown_buf[0x30]; 35 | u8 content_permissions[0x40]; 36 | u8 padding0[2]; 37 | 38 | timelimit_entry timelimits[8]; 39 | } eticket; 40 | 41 | typedef struct 42 | { 43 | FILE* file; 44 | u32 offset; 45 | u32 size; 46 | u8 titlekey[16]; 47 | eticket tik; 48 | ctr_aes_context aes; 49 | settings* usersettings; 50 | } tik_context; 51 | 52 | void tik_init(tik_context* ctx); 53 | void tik_set_file(tik_context* ctx, FILE* file); 54 | void tik_set_offset(tik_context* ctx, u32 offset); 55 | void tik_set_size(tik_context* ctx, u32 size); 56 | void tik_set_usersettings(tik_context* ctx, settings* usersettings); 57 | void tik_get_decrypted_titlekey(tik_context* ctx, u8 decryptedkey[0x10]); 58 | void tik_get_titleid(tik_context* ctx, u8 titleid[8]); 59 | void tik_get_iv(tik_context* ctx, u8 iv[0x10]); 60 | void tik_decrypt_titlekey(tik_context* ctx, u8 decryptedkey[0x10]); 61 | void tik_print(tik_context* ctx); 62 | void tik_process(tik_context* ctx, u32 actions); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /ctrtool/cia.h: -------------------------------------------------------------------------------- 1 | #ifndef _CIA_H_ 2 | #define _CIA_H_ 3 | 4 | #include "types.h" 5 | #include "filepath.h" 6 | #include "tik.h" 7 | #include "tmd.h" 8 | #include "ctr.h" 9 | #include "settings.h" 10 | 11 | typedef enum 12 | { 13 | CIATYPE_CERTS, 14 | CIATYPE_TMD, 15 | CIATYPE_TIK, 16 | CIATYPE_CONTENT, 17 | CIATYPE_META, 18 | } cia_types; 19 | 20 | typedef struct 21 | { 22 | u8 headersize[4]; 23 | u8 type[2]; 24 | u8 version[2]; 25 | u8 certsize[4]; 26 | u8 ticketsize[4]; 27 | u8 tmdsize[4]; 28 | u8 metasize[4]; 29 | u8 contentsize[8]; 30 | u8 contentindex[0x2000]; 31 | } ctr_ciaheader; 32 | 33 | typedef struct 34 | { 35 | FILE* file; 36 | u32 offset; 37 | u32 size; 38 | u8 titlekey[16]; 39 | u8 iv[16]; 40 | ctr_ciaheader header; 41 | ctr_aes_context aes; 42 | settings* usersettings; 43 | 44 | tik_context tik; 45 | tmd_context tmd; 46 | 47 | u32 sizeheader; 48 | u32 sizecert; 49 | u32 sizetik; 50 | u32 sizetmd; 51 | u32 sizecontent; 52 | u32 sizemeta; 53 | 54 | u32 offsetcerts; 55 | u32 offsettik; 56 | u32 offsettmd; 57 | u32 offsetcontent; 58 | u32 offsetmeta; 59 | } cia_context; 60 | 61 | void cia_init(cia_context* ctx); 62 | void cia_set_file(cia_context* ctx, FILE* file); 63 | void cia_set_offset(cia_context* ctx, u32 offset); 64 | void cia_set_size(cia_context* ctx, u32 size); 65 | void cia_set_usersettings(cia_context* ctx, settings* usersettings); 66 | void cia_print(cia_context* ctx); 67 | void cia_save(cia_context* ctx, u32 type, u32 flags); 68 | void cia_process(cia_context* ctx, u32 actions); 69 | void cia_save_blob(cia_context *ctx, char *out_path, u32 offset, u32 size, int do_cbc); 70 | void cia_verify_contents(cia_context *ctx); 71 | 72 | #endif // _CIA_H_ 73 | -------------------------------------------------------------------------------- /ctrtool/keyset.h: -------------------------------------------------------------------------------- 1 | #ifndef _KEYSET_H_ 2 | #define _KEYSET_H_ 3 | 4 | #include "types.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | typedef enum 11 | { 12 | KEY_ERR_LEN_MISMATCH, 13 | KEY_ERR_INVALID_NODE, 14 | KEY_OK 15 | } keystatus; 16 | 17 | typedef enum 18 | { 19 | RSAKEY_INVALID, 20 | RSAKEY_PRIV, 21 | RSAKEY_PUB 22 | } rsakeytype; 23 | 24 | typedef struct 25 | { 26 | unsigned char n[256]; 27 | unsigned char e[3]; 28 | unsigned char d[256]; 29 | unsigned char p[128]; 30 | unsigned char q[128]; 31 | unsigned char dp[128]; 32 | unsigned char dq[128]; 33 | unsigned char qp[128]; 34 | rsakeytype keytype; 35 | } rsakey2048; 36 | 37 | typedef struct 38 | { 39 | unsigned char data[16]; 40 | int valid; 41 | } key128; 42 | 43 | typedef struct 44 | { 45 | key128 commonkey; 46 | key128 ncchkey; 47 | key128 ncchfixedsystemkey; 48 | rsakey2048 ncsdrsakey; 49 | rsakey2048 ncchrsakey; 50 | rsakey2048 ncchdescrsakey; 51 | rsakey2048 firmrsakey; 52 | } keyset; 53 | 54 | void keyset_init(keyset* keys); 55 | int keyset_load(keyset* keys, const char* fname, int verbose); 56 | void keyset_merge(keyset* keys, keyset* src); 57 | void keyset_set_commonkey(keyset* keys, unsigned char* keydata); 58 | void keyset_parse_commonkey(keyset* keys, char* keytext, int keylen); 59 | void keyset_set_ncchkey(keyset* keys, unsigned char* keydata); 60 | void keyset_parse_ncchkey(keyset* keys, char* keytext, int keylen); 61 | void keyset_set_ncchfixedsystemkey(keyset* keys, unsigned char* keydata); 62 | void keyset_parse_ncchfixedsystemkey(keyset* keys, char* keytext, int keylen); 63 | void keyset_dump(keyset* keys); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | 70 | #endif // _KEYSET_H_ 71 | -------------------------------------------------------------------------------- /parentool/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | unsigned int calculate_master_key(unsigned char* generator) 7 | { 8 | uint32_t table[0x100]; 9 | uint32_t data; 10 | uint32_t i, j; 11 | uint32_t y; 12 | uint8_t x; 13 | uint64_t yll; 14 | uint32_t yhi; 15 | 16 | for(i=0; i<0x100; i++) 17 | { 18 | data = i; 19 | for(j=0; j<4; j++) 20 | { 21 | if (data & 1) 22 | data = 0xEDBA6320 ^ (data>>1); 23 | else 24 | data = data>>1; 25 | 26 | if (data & 1) 27 | data = 0xEDBA6320 ^ (data>>1); 28 | else 29 | data = data>>1; 30 | } 31 | 32 | table[i] = data; 33 | } 34 | 35 | y = 0xFFFFFFFF; 36 | x = generator[0]; 37 | for(i=0; i<4; i++) 38 | { 39 | x ^= y; 40 | y = table[x] ^ (y>>8); 41 | x = generator[1+i*2] ^ y; 42 | y = table[x] ^ (y>>8); 43 | x = generator[2+i*2]; 44 | } 45 | 46 | y ^= 0xAAAA; 47 | y += 0x1657; 48 | 49 | yll = y; 50 | yll = (yll+1) * 0xA7C5AC47ULL; 51 | yhi = (yll>>48); 52 | yhi *= 0xFFFFF3CB; 53 | y += (yhi<<5); 54 | 55 | return y; 56 | } 57 | 58 | int main(int argc, const char* argv[]) 59 | { 60 | unsigned char generator[9] = {0}; 61 | unsigned int servicecode, month, day, masterkey; 62 | 63 | if (argc != 4) 64 | { 65 | printf("usage: \n"); 66 | exit(1); 67 | } 68 | 69 | servicecode = strtoul(argv[1], 0, 10); 70 | month = strtoul(argv[2], 0, 10); 71 | day = strtoul(argv[3], 0, 10); 72 | 73 | servicecode %= 10000; 74 | month %= 100; 75 | day %= 100; 76 | sprintf((char*)generator, "%02d%02d%04d", month, day, servicecode); 77 | 78 | masterkey = calculate_master_key(generator); 79 | 80 | printf("Master key is %05d\n", masterkey); 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /ctrtool/ivfc.h: -------------------------------------------------------------------------------- 1 | #ifndef __IVFC_H__ 2 | #define __IVFC_H__ 3 | 4 | #include "types.h" 5 | #include "settings.h" 6 | 7 | #define IVFC_MAX_LEVEL 4 8 | #define IVFC_MAX_BUFFERSIZE 0x4000 9 | 10 | typedef struct 11 | { 12 | u8 magic[4]; 13 | u8 id[4]; 14 | } ivfc_header; 15 | 16 | typedef struct 17 | { 18 | u8 logicaloffset[8]; 19 | u8 hashdatasize[8]; 20 | u8 blocksize[4]; 21 | u8 reserved[4]; 22 | } ivfc_levelheader; 23 | 24 | typedef struct 25 | { 26 | u64 dataoffset; 27 | u64 datasize; 28 | u64 hashoffset; 29 | u32 hashblocksize; 30 | int hashcheck; 31 | } ivfc_level; 32 | 33 | typedef struct 34 | { 35 | u8 masterhashsize[4]; 36 | ivfc_levelheader level1; 37 | ivfc_levelheader level2; 38 | ivfc_levelheader level3; 39 | u8 reserved[4]; 40 | u8 optionalsize[4]; 41 | } ivfc_header_romfs; 42 | 43 | typedef struct 44 | { 45 | FILE* file; 46 | u32 offset; 47 | u32 size; 48 | settings* usersettings; 49 | 50 | ivfc_header header; 51 | ivfc_header_romfs romfsheader; 52 | 53 | u32 levelcount; 54 | ivfc_level level[IVFC_MAX_LEVEL]; 55 | u64 bodyoffset; 56 | u64 bodysize; 57 | u8 buffer[IVFC_MAX_BUFFERSIZE]; 58 | } ivfc_context; 59 | 60 | void ivfc_init(ivfc_context* ctx); 61 | void ivfc_process(ivfc_context* ctx, u32 actions); 62 | void ivfc_set_offset(ivfc_context* ctx, u32 offset); 63 | void ivfc_set_size(ivfc_context* ctx, u32 size); 64 | void ivfc_set_file(ivfc_context* ctx, FILE* file); 65 | void ivfc_set_usersettings(ivfc_context* ctx, settings* usersettings); 66 | void ivfc_verify(ivfc_context* ctx, u32 flags); 67 | void ivfc_print(ivfc_context* ctx); 68 | 69 | void ivfc_read(ivfc_context* ctx, u32 offset, u32 size, u8* buffer); 70 | void ivfc_hash(ivfc_context* ctx, u32 offset, u32 size, u8* hash); 71 | 72 | #endif // __IVFC_H__ 73 | -------------------------------------------------------------------------------- /ctrtool/exefs.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXEFS_H_ 2 | #define _EXEFS_H_ 3 | 4 | #include "types.h" 5 | #include "info.h" 6 | #include "ctr.h" 7 | #include "filepath.h" 8 | #include "settings.h" 9 | 10 | 11 | typedef struct 12 | { 13 | u8 name[8]; 14 | u8 offset[4]; 15 | u8 size[4]; 16 | } exefs_sectionheader; 17 | 18 | 19 | typedef struct 20 | { 21 | exefs_sectionheader section[8]; 22 | u8 reserved[0x80]; 23 | u8 hashes[8][0x20]; 24 | } exefs_header; 25 | 26 | typedef struct 27 | { 28 | FILE* file; 29 | settings* usersettings; 30 | u8 partitionid[8]; 31 | u8 counter[16]; 32 | u8 key[16]; 33 | u32 offset; 34 | u32 size; 35 | exefs_header header; 36 | ctr_aes_context aes; 37 | ctr_sha256_context sha; 38 | int hashcheck[8]; 39 | int compressedflag; 40 | int encrypted; 41 | } exefs_context; 42 | 43 | void exefs_init(exefs_context* ctx); 44 | void exefs_set_file(exefs_context* ctx, FILE* file); 45 | void exefs_set_offset(exefs_context* ctx, u32 offset); 46 | void exefs_set_size(exefs_context* ctx, u32 size); 47 | void exefs_set_usersettings(exefs_context* ctx, settings* usersettings); 48 | void exefs_set_partitionid(exefs_context* ctx, u8 partitionid[8]); 49 | void exefs_set_counter(exefs_context* ctx, u8 counter[16]); 50 | void exefs_set_compressedflag(exefs_context* ctx, int compressedflag); 51 | void exefs_set_key(exefs_context* ctx, u8 key[16]); 52 | void exefs_set_encrypted(exefs_context* ctx, u32 encrypted); 53 | void exefs_read_header(exefs_context* ctx, u32 flags); 54 | void exefs_calculate_hash(exefs_context* ctx, u8 hash[32]); 55 | void exefs_process(exefs_context* ctx, u32 actions); 56 | void exefs_print(exefs_context* ctx); 57 | void exefs_save(exefs_context* ctx, u32 index, u32 flags); 58 | int exefs_verify(exefs_context* ctx, u32 index, u32 flags); 59 | void exefs_determine_key(exefs_context* ctx, u32 actions); 60 | #endif // _EXEFS_H_ 61 | -------------------------------------------------------------------------------- /ctrtool/tinyxml/tinyxmlerror.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any 7 | damages arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any 10 | purpose, including commercial applications, and to alter it and 11 | redistribute it freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must 14 | not claim that you wrote the original software. If you use this 15 | software in a product, an acknowledgment in the product documentation 16 | would be appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and 19 | must not be misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | */ 24 | 25 | #include "tinyxml/tinyxml.h" 26 | 27 | // The goal of the seperate error file is to make the first 28 | // step towards localization. tinyxml (currently) only supports 29 | // english error messages, but the could now be translated. 30 | // 31 | // It also cleans up the code a bit. 32 | // 33 | 34 | const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = 35 | { 36 | "No error", 37 | "Error", 38 | "Failed to open file", 39 | "Error parsing Element.", 40 | "Failed to read Element name", 41 | "Error reading Element value.", 42 | "Error reading Attributes.", 43 | "Error: empty tag.", 44 | "Error reading end tag.", 45 | "Error parsing Unknown.", 46 | "Error parsing Comment.", 47 | "Error parsing Declaration.", 48 | "Error document empty.", 49 | "Error null (0) or unexpected EOF found in input stream.", 50 | "Error parsing CDATA.", 51 | "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", 52 | }; 53 | -------------------------------------------------------------------------------- /ctrtool/filepath.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "types.h" 6 | #include "filepath.h" 7 | 8 | void filepath_init(filepath* fpath) 9 | { 10 | fpath->valid = 0; 11 | } 12 | 13 | void filepath_copy(filepath* fpath, filepath* copy) 14 | { 15 | if (copy != 0 && copy->valid) 16 | memcpy(fpath, copy, sizeof(filepath)); 17 | else 18 | memset(fpath, 0, sizeof(filepath)); 19 | } 20 | 21 | void filepath_append_utf16(filepath* fpath, const u8* name) 22 | { 23 | u32 size; 24 | 25 | 26 | if (fpath->valid == 0) 27 | return; 28 | 29 | size = strlen(fpath->pathname); 30 | 31 | if (size > 0 && size < (MAX_PATH-1)) 32 | { 33 | if (fpath->pathname[size-1] != PATH_SEPERATOR) 34 | fpath->pathname[size++] = PATH_SEPERATOR; 35 | } 36 | 37 | while(size < (MAX_PATH-1)) 38 | { 39 | u8 lo = *name++; 40 | u8 hi = *name++; 41 | u16 code = (hi<<8) | lo; 42 | 43 | if (code == 0) 44 | break; 45 | 46 | // convert non-ANSI to '#', because unicode support is too much work 47 | if (code > 0x7F) 48 | code = '#'; 49 | 50 | fpath->pathname[size++] = code; 51 | } 52 | 53 | fpath->pathname[size] = 0; 54 | 55 | if (size >= (MAX_PATH-1)) 56 | fpath->valid = 0; 57 | } 58 | 59 | void filepath_append(filepath* fpath, const char* format, ...) 60 | { 61 | char tmppath[MAX_PATH]; 62 | va_list args; 63 | 64 | if (fpath->valid == 0) 65 | return; 66 | 67 | memset(tmppath, 0, MAX_PATH); 68 | 69 | va_start(args, format); 70 | vsprintf(tmppath, format, args); 71 | va_end(args); 72 | 73 | strcat(fpath->pathname, "/"); 74 | strcat(fpath->pathname, tmppath); 75 | } 76 | 77 | void filepath_set(filepath* fpath, const char* path) 78 | { 79 | fpath->valid = 1; 80 | memset(fpath->pathname, 0, MAX_PATH); 81 | strncpy(fpath->pathname, path, MAX_PATH); 82 | } 83 | 84 | const char* filepath_get(filepath* fpath) 85 | { 86 | if (fpath->valid == 0) 87 | return 0; 88 | else 89 | return fpath->pathname; 90 | } 91 | -------------------------------------------------------------------------------- /ctrtool/tmd.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMD_H_ 2 | #define _TMD_H_ 3 | 4 | #include "types.h" 5 | #include "settings.h" 6 | 7 | #define TMD_MAX_CONTENTS 64 8 | 9 | typedef enum 10 | { 11 | TMD_RSA_2048_SHA256 = 0x00010004, 12 | TMD_RSA_4096_SHA256 = 0x00010003, 13 | TMD_RSA_2048_SHA1 = 0x00010001, 14 | TMD_RSA_4096_SHA1 = 0x00010000 15 | } ctr_tmdtype; 16 | 17 | 18 | typedef struct 19 | { 20 | unsigned char padding[60]; 21 | unsigned char issuer[64]; 22 | unsigned char version; 23 | unsigned char ca_crl_version; 24 | unsigned char signer_crl_version; 25 | unsigned char padding2; 26 | unsigned char systemversion[8]; 27 | unsigned char titleid[8]; 28 | unsigned char titletype[4]; 29 | unsigned char groupid[2]; 30 | unsigned char padding3[62]; 31 | unsigned char accessrights[4]; 32 | unsigned char titleversion[2]; 33 | unsigned char contentcount[2]; 34 | unsigned char bootcontent[2]; 35 | unsigned char padding4[2]; 36 | unsigned char hash[32]; 37 | unsigned char contentinfo[36*64]; 38 | } ctr_tmd_body; 39 | 40 | typedef struct 41 | { 42 | unsigned char index[2]; 43 | unsigned char commandcount[2]; 44 | unsigned char unk[32]; 45 | } ctr_tmd_contentinfo; 46 | 47 | 48 | typedef struct 49 | { 50 | unsigned char id[4]; 51 | unsigned char index[2]; 52 | unsigned char type[2]; 53 | unsigned char size[8]; 54 | unsigned char hash[32]; 55 | } ctr_tmd_contentchunk; 56 | 57 | 58 | typedef struct 59 | { 60 | unsigned char signaturetype[4]; 61 | unsigned char signature[256]; 62 | } ctr_tmd_header_2048; 63 | 64 | typedef struct 65 | { 66 | unsigned char signaturetype[4]; 67 | unsigned char signature[512]; 68 | } ctr_tmd_header_4096; 69 | 70 | typedef struct 71 | { 72 | FILE* file; 73 | u32 offset; 74 | u32 size; 75 | u8* buffer; 76 | u8 content_hash_stat[64]; 77 | settings* usersettings; 78 | } tmd_context; 79 | 80 | 81 | 82 | #ifdef __cplusplus 83 | extern "C" { 84 | #endif 85 | 86 | void tmd_init(tmd_context* ctx); 87 | void tmd_set_file(tmd_context* ctx, FILE* file); 88 | void tmd_set_offset(tmd_context* ctx, u32 offset); 89 | void tmd_set_size(tmd_context* ctx, u32 size); 90 | void tmd_set_usersettings(tmd_context* ctx, settings* usersettings); 91 | void tmd_print(tmd_context* ctx); 92 | void tmd_process(tmd_context* ctx, u32 actions); 93 | ctr_tmd_body *tmd_get_body(tmd_context *ctx); 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #endif // _TMD_H_ 100 | -------------------------------------------------------------------------------- /ctrtool/ncch.h: -------------------------------------------------------------------------------- 1 | #ifndef _NCCH_H_ 2 | #define _NCCH_H_ 3 | 4 | #include 5 | #include "types.h" 6 | #include "keyset.h" 7 | #include "filepath.h" 8 | #include "ctr.h" 9 | #include "exefs.h" 10 | #include "exheader.h" 11 | #include "settings.h" 12 | 13 | typedef enum 14 | { 15 | NCCHTYPE_EXHEADER = 1, 16 | NCCHTYPE_EXEFS = 2, 17 | NCCHTYPE_ROMFS = 3, 18 | } ctr_ncchtypes; 19 | 20 | typedef struct 21 | { 22 | u8 signature[0x100]; 23 | u8 magic[4]; 24 | u8 contentsize[4]; 25 | u8 partitionid[8]; 26 | u8 makercode[2]; 27 | u8 version[2]; 28 | u8 reserved0[4]; 29 | u8 programid[8]; 30 | u8 tempflag; 31 | u8 reserved1[0x2f]; 32 | u8 productcode[0x10]; 33 | u8 extendedheaderhash[0x20]; 34 | u8 extendedheadersize[4]; 35 | u8 reserved2[4]; 36 | u8 flags[8]; 37 | u8 plainregionoffset[4]; 38 | u8 plainregionsize[4]; 39 | u8 reserved3[8]; 40 | u8 exefsoffset[4]; 41 | u8 exefssize[4]; 42 | u8 exefshashregionsize[4]; 43 | u8 reserved4[4]; 44 | u8 romfsoffset[4]; 45 | u8 romfssize[4]; 46 | u8 romfshashregionsize[4]; 47 | u8 reserved5[4]; 48 | u8 exefssuperblockhash[0x20]; 49 | u8 romfssuperblockhash[0x20]; 50 | } ctr_ncchheader; 51 | 52 | 53 | typedef struct 54 | { 55 | FILE* file; 56 | u8 key[16]; 57 | u32 encrypted; 58 | u32 offset; 59 | u32 size; 60 | settings* usersettings; 61 | ctr_ncchheader header; 62 | ctr_aes_context aes; 63 | exefs_context exefs; 64 | exheader_context exheader; 65 | int exefshashcheck; 66 | int romfshashcheck; 67 | int exheaderhashcheck; 68 | int headersigcheck; 69 | u32 extractsize; 70 | u32 extractflags; 71 | } ncch_context; 72 | 73 | void ncch_init(ncch_context* ctx); 74 | void ncch_process(ncch_context* ctx, u32 actions); 75 | void ncch_set_offset(ncch_context* ctx, u32 offset); 76 | void ncch_set_size(ncch_context* ctx, u32 size); 77 | void ncch_set_file(ncch_context* ctx, FILE* file); 78 | void ncch_set_usersettings(ncch_context* ctx, settings* usersettings); 79 | u32 ncch_get_exefs_offset(ncch_context* ctx); 80 | u32 ncch_get_exefs_size(ncch_context* ctx); 81 | u32 ncch_get_romfs_offset(ncch_context* ctx); 82 | u32 ncch_get_romfs_size(ncch_context* ctx); 83 | u32 ncch_get_exheader_offset(ncch_context* ctx); 84 | u32 ncch_get_exheader_size(ncch_context* ctx); 85 | void ncch_print(ncch_context* ctx); 86 | int ncch_signature_verify(ncch_context* ctx, rsakey2048* key); 87 | void ncch_verify(ncch_context* ctx, u32 flags); 88 | void ncch_save(ncch_context* ctx, u32 type, u32 flags); 89 | int ncch_extract_prepare(ncch_context* ctx, u32 type, u32 flags); 90 | int ncch_extract_buffer(ncch_context* ctx, u8* buffer, u32 buffersize, u32* outsize); 91 | u32 ncch_get_mediaunit_size(ncch_context* ctx); 92 | void ncch_get_counter(ncch_context* ctx, u8 counter[16], u8 type); 93 | void ncch_determine_key(ncch_context* ctx, u32 actions); 94 | #endif // _NCCH_H_ 95 | -------------------------------------------------------------------------------- /ctrtool/romfs.h: -------------------------------------------------------------------------------- 1 | #ifndef __ROMFS_H__ 2 | #define __ROMFS_H__ 3 | 4 | #include "types.h" 5 | #include "info.h" 6 | #include "ctr.h" 7 | #include "filepath.h" 8 | #include "settings.h" 9 | #include "ivfc.h" 10 | 11 | #define ROMFS_MAXNAMESIZE 254 // limit set by ctrtool 12 | 13 | typedef struct 14 | { 15 | u8 magic[4]; 16 | } romfs_header; 17 | 18 | typedef struct 19 | { 20 | u8 offset[4]; 21 | u8 size[4]; 22 | } romfs_sectionheader; 23 | 24 | typedef struct 25 | { 26 | u8 headersize[4]; 27 | romfs_sectionheader section[4]; 28 | u8 dataoffset[4]; 29 | } romfs_infoheader; 30 | 31 | 32 | typedef struct 33 | { 34 | u8 parentoffset[4]; 35 | u8 siblingoffset[4]; 36 | u8 childoffset[4]; 37 | u8 fileoffset[4]; 38 | u8 weirdoffset[4]; // this one is weird. it always points to a dir entry, but seems unrelated to the romfs structure. 39 | u8 namesize[4]; 40 | u8 name[ROMFS_MAXNAMESIZE]; 41 | } romfs_direntry; 42 | 43 | typedef struct 44 | { 45 | u8 parentdiroffset[4]; 46 | u8 siblingoffset[4]; 47 | u8 dataoffset[8]; 48 | u8 datasize[8]; 49 | u8 weirdoffset[4]; // this one is also weird. it always points to a file entry, but seems unrelated to the romfs structure. 50 | u8 namesize[4]; 51 | u8 name[ROMFS_MAXNAMESIZE]; 52 | } romfs_fileentry; 53 | 54 | 55 | typedef struct 56 | { 57 | FILE* file; 58 | settings* usersettings; 59 | u32 offset; 60 | u32 size; 61 | romfs_header header; 62 | romfs_infoheader infoheader; 63 | u8* dirblock; 64 | u32 dirblocksize; 65 | u8* fileblock; 66 | u32 fileblocksize; 67 | u32 datablockoffset; 68 | u32 infoblockoffset; 69 | romfs_direntry direntry; 70 | romfs_fileentry fileentry; 71 | ivfc_context ivfc; 72 | } romfs_context; 73 | 74 | void romfs_init(romfs_context* ctx); 75 | void romfs_set_file(romfs_context* ctx, FILE* file); 76 | void romfs_set_offset(romfs_context* ctx, u32 offset); 77 | void romfs_set_size(romfs_context* ctx, u32 size); 78 | void romfs_set_usersettings(romfs_context* ctx, settings* usersettings); 79 | void romfs_test(romfs_context* ctx); 80 | int romfs_dirblock_read(romfs_context* ctx, u32 diroffset, u32 dirsize, void* buffer); 81 | int romfs_dirblock_readentry(romfs_context* ctx, u32 diroffset, romfs_direntry* entry); 82 | int romfs_fileblock_read(romfs_context* ctx, u32 fileoffset, u32 filesize, void* buffer); 83 | int romfs_fileblock_readentry(romfs_context* ctx, u32 fileoffset, romfs_fileentry* entry); 84 | void romfs_visit_dir(romfs_context* ctx, u32 diroffset, u32 depth, u32 actions, filepath* rootpath); 85 | void romfs_visit_file(romfs_context* ctx, u32 fileoffset, u32 depth, u32 actions, filepath* rootpath); 86 | void romfs_extract_datafile(romfs_context* ctx, u64 offset, u64 size, filepath* path); 87 | void romfs_process(romfs_context* ctx, u32 actions); 88 | void romfs_print(romfs_context* ctx); 89 | 90 | #endif // __ROMFS_H__ 91 | -------------------------------------------------------------------------------- /ctrtool/tinyxml/tinystr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any 6 | damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it and 10 | redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must 13 | not claim that you wrote the original software. If you use this 14 | software in a product, an acknowledgment in the product documentation 15 | would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and 18 | must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | */ 23 | 24 | 25 | #ifndef TIXML_USE_STL 26 | 27 | #include "tinyxml/tinystr.h" 28 | 29 | // Error value for find primitive 30 | const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); 31 | 32 | 33 | // Null rep. 34 | TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; 35 | 36 | 37 | void TiXmlString::reserve (size_type cap) 38 | { 39 | if (cap > capacity()) 40 | { 41 | TiXmlString tmp; 42 | tmp.init(length(), cap); 43 | memcpy(tmp.start(), data(), length()); 44 | swap(tmp); 45 | } 46 | } 47 | 48 | 49 | TiXmlString& TiXmlString::assign(const char* str, size_type len) 50 | { 51 | size_type cap = capacity(); 52 | if (len > cap || cap > 3*(len + 8)) 53 | { 54 | TiXmlString tmp; 55 | tmp.init(len); 56 | memcpy(tmp.start(), str, len); 57 | swap(tmp); 58 | } 59 | else 60 | { 61 | memmove(start(), str, len); 62 | set_size(len); 63 | } 64 | return *this; 65 | } 66 | 67 | 68 | TiXmlString& TiXmlString::append(const char* str, size_type len) 69 | { 70 | size_type newsize = length() + len; 71 | if (newsize > capacity()) 72 | { 73 | reserve (newsize + capacity()); 74 | } 75 | memmove(finish(), str, len); 76 | set_size(newsize); 77 | return *this; 78 | } 79 | 80 | 81 | TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) 82 | { 83 | TiXmlString tmp; 84 | tmp.reserve(a.length() + b.length()); 85 | tmp += a; 86 | tmp += b; 87 | return tmp; 88 | } 89 | 90 | TiXmlString operator + (const TiXmlString & a, const char* b) 91 | { 92 | TiXmlString tmp; 93 | TiXmlString::size_type b_len = static_cast( strlen(b) ); 94 | tmp.reserve(a.length() + b_len); 95 | tmp += a; 96 | tmp.append(b, b_len); 97 | return tmp; 98 | } 99 | 100 | TiXmlString operator + (const char* a, const TiXmlString & b) 101 | { 102 | TiXmlString tmp; 103 | TiXmlString::size_type a_len = static_cast( strlen(a) ); 104 | tmp.reserve(a_len + b.length()); 105 | tmp.append(a, a_len); 106 | tmp += b; 107 | return tmp; 108 | } 109 | 110 | 111 | #endif // TIXML_USE_STL 112 | -------------------------------------------------------------------------------- /ctrtool/polarssl/padlock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file padlock.h 3 | * 4 | * Copyright (C) 2006-2010, Brainspark B.V. 5 | * 6 | * This file is part of PolarSSL (http://www.polarssl.org) 7 | * Lead Maintainer: Paul Bakker 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | #ifndef POLARSSL_PADLOCK_H 26 | #define POLARSSL_PADLOCK_H 27 | 28 | #include "polarssl/aes.h" 29 | 30 | #if defined(POLARSSL_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) 31 | 32 | #ifndef POLARSSL_HAVE_X86 33 | #define POLARSSL_HAVE_X86 34 | #endif 35 | 36 | #define PADLOCK_RNG 0x000C 37 | #define PADLOCK_ACE 0x00C0 38 | #define PADLOCK_PHE 0x0C00 39 | #define PADLOCK_PMM 0x3000 40 | 41 | #define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15)) 42 | 43 | #define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED -0x08E0 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | /** 50 | * \brief PadLock detection routine 51 | * 52 | * \param The feature to detect 53 | * 54 | * \return 1 if CPU has support for the feature, 0 otherwise 55 | */ 56 | int padlock_supports( int feature ); 57 | 58 | /** 59 | * \brief PadLock AES-ECB block en(de)cryption 60 | * 61 | * \param ctx AES context 62 | * \param mode AES_ENCRYPT or AES_DECRYPT 63 | * \param input 16-byte input block 64 | * \param output 16-byte output block 65 | * 66 | * \return 0 if success, 1 if operation failed 67 | */ 68 | int padlock_xcryptecb( aes_context *ctx, 69 | int mode, 70 | const unsigned char input[16], 71 | unsigned char output[16] ); 72 | 73 | /** 74 | * \brief PadLock AES-CBC buffer en(de)cryption 75 | * 76 | * \param ctx AES context 77 | * \param mode AES_ENCRYPT or AES_DECRYPT 78 | * \param length length of the input data 79 | * \param iv initialization vector (updated after use) 80 | * \param input buffer holding the input data 81 | * \param output buffer holding the output data 82 | * 83 | * \return 0 if success, 1 if operation failed 84 | */ 85 | int padlock_xcryptcbc( aes_context *ctx, 86 | int mode, 87 | int length, 88 | unsigned char iv[16], 89 | const unsigned char *input, 90 | unsigned char *output ); 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | 96 | #endif /* HAVE_X86 */ 97 | 98 | #endif /* padlock.h */ 99 | -------------------------------------------------------------------------------- /ctrtool/settings.h: -------------------------------------------------------------------------------- 1 | #ifndef _SETTINGS_H_ 2 | #define _SETTINGS_H_ 3 | 4 | #include "types.h" 5 | #include "keyset.h" 6 | #include "filepath.h" 7 | 8 | typedef struct 9 | { 10 | keyset keys; 11 | filepath exefspath; 12 | filepath exefsdirpath; 13 | filepath firmdirpath; 14 | filepath romfspath; 15 | filepath romfsdirpath; 16 | filepath exheaderpath; 17 | filepath certspath; 18 | filepath contentpath; 19 | filepath tikpath; 20 | filepath tmdpath; 21 | filepath metapath; 22 | filepath lzsspath; 23 | filepath wavpath; 24 | unsigned int mediaunitsize; 25 | int ignoreprogramid; 26 | int listromfs; 27 | u32 cwavloopcount; 28 | } settings; 29 | 30 | void settings_init(settings* usersettings); 31 | filepath* settings_get_lzss_path(settings* usersettings); 32 | filepath* settings_get_exefs_path(settings* usersettings); 33 | filepath* settings_get_romfs_path(settings* usersettings); 34 | filepath* settings_get_exheader_path(settings* usersettings); 35 | filepath* settings_get_certs_path(settings* usersettings); 36 | filepath* settings_get_tik_path(settings* usersettings); 37 | filepath* settings_get_tmd_path(settings* usersettings); 38 | filepath* settings_get_meta_path(settings* usersettings); 39 | filepath* settings_get_content_path(settings* usersettings); 40 | filepath* settings_get_exefs_dir_path(settings* usersettings); 41 | filepath* settings_get_romfs_dir_path(settings* usersettings); 42 | filepath* settings_get_firm_dir_path(settings* usersettings); 43 | filepath* settings_get_wav_path(settings* usersettings); 44 | unsigned int settings_get_mediaunit_size(settings* usersettings); 45 | unsigned char* settings_get_ncch_key(settings* usersettings); 46 | unsigned char* settings_get_ncch_fixedsystemkey(settings* usersettings); 47 | unsigned char* settings_get_common_key(settings* usersettings); 48 | int settings_get_ignore_programid(settings* usersettings); 49 | int settings_get_list_romfs_files(settings* usersettings); 50 | int settings_get_cwav_loopcount(settings* usersettings); 51 | 52 | void settings_set_lzss_path(settings* usersettings, const char* path); 53 | void settings_set_exefs_path(settings* usersettings, const char* path); 54 | void settings_set_romfs_path(settings* usersettings, const char* path); 55 | void settings_set_exheader_path(settings* usersettings, const char* path); 56 | void settings_set_certs_path(settings* usersettings, const char* path); 57 | void settings_set_tik_path(settings* usersettings, const char* path); 58 | void settings_set_tmd_path(settings* usersettings, const char* path); 59 | void settings_set_meta_path(settings* usersettings, const char* path); 60 | void settings_set_content_path(settings* usersettings, const char* path); 61 | void settings_set_exefs_dir_path(settings* usersettings, const char* path); 62 | void settings_set_romfs_dir_path(settings* usersettings, const char* path); 63 | void settings_set_firm_dir_path(settings* usersettings, const char* path); 64 | void settings_set_wav_path(settings* usersettings, const char* path); 65 | void settings_set_mediaunit_size(settings* usersettings, unsigned int size); 66 | void settings_set_ignore_programid(settings* usersettings, int enable); 67 | void settings_set_list_romfs_files(settings* usersettings, int enable); 68 | void settings_set_cwav_loopcount(settings* usersettings, u32 loopcount); 69 | 70 | #endif // _SETTINGS_H_ 71 | -------------------------------------------------------------------------------- /ctrtool/stream.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | #include "types.h" 7 | #include "stream.h" 8 | 9 | 10 | void stream_in_init(stream_in_context* ctx) 11 | { 12 | memset(ctx, 0, sizeof(stream_in_context)); 13 | } 14 | 15 | void stream_out_init(stream_out_context* ctx) 16 | { 17 | memset(ctx, 0, sizeof(stream_out_context)); 18 | } 19 | 20 | void stream_in_allocate(stream_in_context* ctx, u32 buffersize, FILE* file) 21 | { 22 | ctx->inbuffer = malloc(buffersize); 23 | ctx->inbuffersize = buffersize; 24 | ctx->infile = file; 25 | ctx->infileposition = 0; 26 | } 27 | 28 | void stream_out_allocate(stream_out_context* ctx, u32 buffersize, FILE* file) 29 | { 30 | ctx->outbuffer = malloc(buffersize); 31 | ctx->outbuffersize = buffersize; 32 | ctx->outfile = file; 33 | } 34 | 35 | void stream_in_destroy(stream_in_context* ctx) 36 | { 37 | free(ctx->inbuffer); 38 | ctx->inbuffer = 0; 39 | } 40 | 41 | void stream_out_destroy(stream_out_context* ctx) 42 | { 43 | free(ctx->outbuffer); 44 | ctx->outbuffer = 0; 45 | } 46 | 47 | int stream_in_byte(stream_in_context* ctx, u8* byte) 48 | { 49 | if (ctx->inbufferpos >= ctx->inbufferavailable) 50 | { 51 | size_t readbytes = fread(ctx->inbuffer, 1, ctx->inbuffersize, ctx->infile); 52 | if (readbytes <= 0) 53 | return 0; 54 | 55 | ctx->inbufferavailable = readbytes; 56 | ctx->inbufferpos = 0; 57 | ctx->infileposition += readbytes; 58 | } 59 | 60 | *byte = ctx->inbuffer[ctx->inbufferpos++]; 61 | return 1; 62 | } 63 | 64 | void stream_in_seek(stream_in_context* ctx, u32 position) 65 | { 66 | fseek(ctx->infile, position, SEEK_SET); 67 | ctx->infileposition = position; 68 | ctx->inbufferpos = 0; 69 | ctx->inbufferavailable = 0; 70 | } 71 | 72 | void stream_in_reseek(stream_in_context* ctx) 73 | { 74 | fseek(ctx->infile, ctx->infileposition, SEEK_SET); 75 | } 76 | 77 | 78 | void stream_out_seek(stream_out_context* ctx, u32 position) 79 | { 80 | stream_out_flush(ctx); 81 | 82 | fseek(ctx->outfile, position, SEEK_SET); 83 | } 84 | 85 | void stream_out_skip(stream_out_context* ctx, u32 size) 86 | { 87 | stream_out_flush(ctx); 88 | 89 | fseek(ctx->outfile, size, SEEK_CUR); 90 | } 91 | 92 | int stream_out_byte(stream_out_context* ctx, u8 byte) 93 | { 94 | if (ctx->outbufferpos >= ctx->outbuffersize) 95 | { 96 | if (stream_out_flush(ctx) == 0) 97 | return 0; 98 | } 99 | 100 | ctx->outbuffer[ctx->outbufferpos++] = byte; 101 | return 1; 102 | } 103 | 104 | int stream_out_buffer(stream_out_context* ctx, const void* buffer, u32 size) 105 | { 106 | u32 i; 107 | 108 | for(i=0; ioutbufferpos > 0) 120 | { 121 | size_t writtenbytes = fwrite(ctx->outbuffer, 1, ctx->outbufferpos, ctx->outfile); 122 | if (writtenbytes < 0) 123 | return 0; 124 | 125 | 126 | ctx->outbufferpos = 0; 127 | } 128 | return 1; 129 | } 130 | 131 | void stream_out_position(stream_out_context* ctx, u32* position) 132 | { 133 | stream_out_flush(ctx); 134 | 135 | *position = ftell(ctx->outfile); 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /ctrtool/tik.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "tik.h" 6 | #include "ctr.h" 7 | #include "utils.h" 8 | 9 | void tik_init(tik_context* ctx) 10 | { 11 | memset(ctx, 0, sizeof(tik_context)); 12 | } 13 | 14 | void tik_set_file(tik_context* ctx, FILE* file) 15 | { 16 | ctx->file = file; 17 | } 18 | 19 | void tik_set_offset(tik_context* ctx, u32 offset) 20 | { 21 | ctx->offset = offset; 22 | } 23 | 24 | void tik_set_size(tik_context* ctx, u32 size) 25 | { 26 | ctx->size = size; 27 | } 28 | 29 | void tik_set_usersettings(tik_context* ctx, settings* usersettings) 30 | { 31 | ctx->usersettings = usersettings; 32 | } 33 | 34 | void tik_get_decrypted_titlekey(tik_context* ctx, u8 decryptedkey[0x10]) 35 | { 36 | memcpy(decryptedkey, ctx->titlekey, 16); 37 | } 38 | 39 | void tik_get_titleid(tik_context* ctx, u8 titleid[8]) 40 | { 41 | memcpy(titleid, ctx->tik.title_id, 8); 42 | } 43 | 44 | void tik_get_iv(tik_context* ctx, u8 iv[16]) 45 | { 46 | memset(iv, 0, 16); 47 | memcpy(iv, ctx->tik.title_id, 8); 48 | } 49 | 50 | void tik_decrypt_titlekey(tik_context* ctx, u8 decryptedkey[0x10]) 51 | { 52 | u8 iv[16]; 53 | u8* key = settings_get_common_key(ctx->usersettings); 54 | 55 | memset(decryptedkey, 0, 0x10); 56 | 57 | if (!key) 58 | { 59 | fprintf(stdout, "Warning, could not read common key.\n"); 60 | } 61 | else 62 | { 63 | memset(iv, 0, 0x10); 64 | memcpy(iv, ctx->tik.title_id, 8); 65 | 66 | ctr_init_cbc_decrypt(&ctx->aes, key, iv); 67 | ctr_decrypt_cbc(&ctx->aes, ctx->tik.encrypted_title_key, decryptedkey, 0x10); 68 | } 69 | } 70 | 71 | void tik_process(tik_context* ctx, u32 actions) 72 | { 73 | if (ctx->size < sizeof(eticket)) 74 | { 75 | fprintf(stderr, "Error, ticket size too small\n"); 76 | goto clean; 77 | } 78 | 79 | fseek(ctx->file, ctx->offset, SEEK_SET); 80 | fread((u8*)&ctx->tik, 1, sizeof(eticket), ctx->file); 81 | 82 | tik_decrypt_titlekey(ctx, ctx->titlekey); 83 | 84 | if (actions & InfoFlag) 85 | { 86 | tik_print(ctx); 87 | } 88 | 89 | clean: 90 | return; 91 | } 92 | 93 | void tik_print(tik_context* ctx) 94 | { 95 | int i; 96 | eticket* tik = &ctx->tik; 97 | 98 | fprintf(stdout, "\nTicket content:\n"); 99 | fprintf(stdout, 100 | "Signature Type: %08x\n" 101 | "Issuer: %s\n", 102 | getle32(tik->sig_type), tik->issuer 103 | ); 104 | 105 | fprintf(stdout, "Signature:\n"); 106 | hexdump(tik->signature, 0x100); 107 | fprintf(stdout, "\n"); 108 | 109 | memdump(stdout, "Encrypted Titlekey: ", tik->encrypted_title_key, 0x10); 110 | 111 | if (settings_get_common_key(ctx->usersettings)) 112 | memdump(stdout, "Decrypted Titlekey: ", ctx->titlekey, 0x10); 113 | 114 | memdump(stdout, "Ticket ID: ", tik->ticket_id, 0x08); 115 | fprintf(stdout, "Ticket Version: %d\n", getle16(tik->ticket_version)); 116 | memdump(stdout, "Title ID: ", tik->title_id, 0x08); 117 | fprintf(stdout, "Common Key Index: %d\n", tik->commonkey_idx); 118 | 119 | fprintf(stdout, "Content permission map:\n"); 120 | for(i = 0; i < 0x40; i++) { 121 | printf(" %02x", tik->content_permissions[i]); 122 | 123 | if ((i+1) % 8 == 0) 124 | printf("\n"); 125 | } 126 | printf("\n"); 127 | } 128 | -------------------------------------------------------------------------------- /ctrtool/ctr.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTR_H_ 2 | #define _CTR_H_ 3 | 4 | #include "polarssl/aes.h" 5 | #include "polarssl/rsa.h" 6 | #include "polarssl/sha2.h" 7 | #include "types.h" 8 | #include "keyset.h" 9 | 10 | #define MAGIC_NCCH 0x4843434E 11 | #define MAGIC_NCSD 0x4453434E 12 | #define MAGIC_FIRM 0x4D524946 13 | #define MAGIC_CWAV 0x56415743 14 | #define MAGIC_IVFC 0x43465649 15 | 16 | #define SIZE_128MB (128 * 1024 * 1024) 17 | 18 | typedef enum 19 | { 20 | FILETYPE_UNKNOWN = 0, 21 | FILETYPE_CCI, 22 | FILETYPE_CXI, 23 | FILETYPE_CIA, 24 | FILETYPE_EXHEADER, 25 | FILETYPE_TMD, 26 | FILETYPE_LZSS, 27 | FILETYPE_FIRM, 28 | FILETYPE_CWAV, 29 | FILETYPE_ROMFS 30 | } ctr_filetypes; 31 | 32 | typedef struct 33 | { 34 | u8 ctr[16]; 35 | u8 iv[16]; 36 | aes_context aes; 37 | } ctr_aes_context; 38 | 39 | typedef struct 40 | { 41 | rsa_context rsa; 42 | } ctr_rsa_context; 43 | 44 | typedef struct 45 | { 46 | sha2_context sha; 47 | } ctr_sha256_context; 48 | 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | void ctr_set_iv( ctr_aes_context* ctx, 55 | u8 iv[16] ); 56 | 57 | void ctr_add_counter( ctr_aes_context* ctx, 58 | u32 carry ); 59 | 60 | void ctr_set_counter( ctr_aes_context* ctx, 61 | u8 ctr[16] ); 62 | 63 | 64 | void ctr_init_counter( ctr_aes_context* ctx, 65 | u8 key[16], 66 | u8 ctr[16] ); 67 | 68 | 69 | void ctr_crypt_counter_block( ctr_aes_context* ctx, 70 | u8 input[16], 71 | u8 output[16] ); 72 | 73 | 74 | void ctr_crypt_counter( ctr_aes_context* ctx, 75 | u8* input, 76 | u8* output, 77 | u32 size ); 78 | 79 | 80 | void ctr_init_cbc_encrypt( ctr_aes_context* ctx, 81 | u8 key[16], 82 | u8 iv[16] ); 83 | 84 | void ctr_init_cbc_decrypt( ctr_aes_context* ctx, 85 | u8 key[16], 86 | u8 iv[16] ); 87 | 88 | void ctr_encrypt_cbc( ctr_aes_context* ctx, 89 | u8* input, 90 | u8* output, 91 | u32 size ); 92 | 93 | void ctr_decrypt_cbc( ctr_aes_context* ctx, 94 | u8* input, 95 | u8* output, 96 | u32 size ); 97 | 98 | void ctr_rsa_init_key_pubmodulus( rsakey2048* key, 99 | u8 modulus[0x100] ); 100 | 101 | void ctr_rsa_init_key_pub( rsakey2048* key, 102 | u8 modulus[0x100], 103 | u8 exponent[3] ); 104 | 105 | int ctr_rsa_init( ctr_rsa_context* ctx, 106 | rsakey2048* key ); 107 | 108 | 109 | void ctr_rsa_free( ctr_rsa_context* ctx ); 110 | 111 | int ctr_rsa_verify_hash( const u8 signature[0x100], 112 | const u8 hash[0x20], 113 | rsakey2048* key); 114 | 115 | int ctr_rsa_sign_hash( const u8 hash[0x20], 116 | u8 signature[0x100], 117 | rsakey2048* key ); 118 | 119 | int ctr_rsa_public( const u8 signature[0x100], 120 | u8 output[0x100], 121 | rsakey2048* key ); 122 | 123 | void ctr_sha_256( const u8* data, 124 | u32 size, 125 | u8 hash[0x20] ); 126 | 127 | int ctr_sha_256_verify( const u8* data, 128 | u32 size, 129 | const u8 checkhash[0x20] ); 130 | 131 | 132 | void ctr_sha_256_init( ctr_sha256_context* ctx ); 133 | 134 | void ctr_sha_256_update( ctr_sha256_context* ctx, 135 | const u8* data, 136 | u32 size ); 137 | 138 | 139 | void ctr_sha_256_finish( ctr_sha256_context* ctx, 140 | u8 hash[0x20] ); 141 | 142 | #ifdef __cplusplus 143 | } 144 | #endif 145 | 146 | #endif // _CTR_H_ 147 | -------------------------------------------------------------------------------- /ctrtool/utils.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "utils.h" 5 | 6 | #ifdef _WIN32 7 | #include 8 | #else 9 | #include 10 | #include 11 | #endif 12 | 13 | 14 | u32 align(u32 offset, u32 alignment) 15 | { 16 | u32 mask = ~(alignment-1); 17 | 18 | return (offset + (alignment-1)) & mask; 19 | } 20 | 21 | u64 align64(u64 offset, u32 alignment) 22 | { 23 | u64 mask = ~(alignment-1); 24 | 25 | return (offset + (alignment-1)) & mask; 26 | } 27 | 28 | u64 getle64(const u8* p) 29 | { 30 | u64 n = p[0]; 31 | 32 | n |= (u64)p[1]<<8; 33 | n |= (u64)p[2]<<16; 34 | n |= (u64)p[3]<<24; 35 | n |= (u64)p[4]<<32; 36 | n |= (u64)p[5]<<40; 37 | n |= (u64)p[6]<<48; 38 | n |= (u64)p[7]<<56; 39 | return n; 40 | } 41 | 42 | u64 getbe64(const u8* p) 43 | { 44 | u64 n = 0; 45 | 46 | n |= (u64)p[0]<<56; 47 | n |= (u64)p[1]<<48; 48 | n |= (u64)p[2]<<40; 49 | n |= (u64)p[3]<<32; 50 | n |= (u64)p[4]<<24; 51 | n |= (u64)p[5]<<16; 52 | n |= (u64)p[6]<<8; 53 | n |= (u64)p[7]<<0; 54 | return n; 55 | } 56 | 57 | u32 getle32(const u8* p) 58 | { 59 | return (p[0]<<0) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); 60 | } 61 | 62 | u32 getbe32(const u8* p) 63 | { 64 | return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | (p[3]<<0); 65 | } 66 | 67 | u32 getle16(const u8* p) 68 | { 69 | return (p[0]<<0) | (p[1]<<8); 70 | } 71 | 72 | u32 getbe16(const u8* p) 73 | { 74 | return (p[0]<<8) | (p[1]<<0); 75 | } 76 | 77 | void putle16(u8* p, u16 n) 78 | { 79 | p[0] = n; 80 | p[1] = n>>8; 81 | } 82 | 83 | void putle32(u8* p, u32 n) 84 | { 85 | p[0] = n; 86 | p[1] = n>>8; 87 | p[2] = n>>16; 88 | p[3] = n>>24; 89 | } 90 | 91 | 92 | void readkeyfile(u8* key, const char* keyfname) 93 | { 94 | FILE* f = fopen(keyfname, "rb"); 95 | u32 keysize = 0; 96 | 97 | if (0 == f) 98 | { 99 | fprintf(stdout, "Error opening key file\n"); 100 | goto clean; 101 | } 102 | 103 | fseek(f, 0, SEEK_END); 104 | keysize = ftell(f); 105 | fseek(f, 0, SEEK_SET); 106 | 107 | if (keysize != 16) 108 | { 109 | fprintf(stdout, "Error key size mismatch, got %d, expected %d\n", keysize, 16); 110 | goto clean; 111 | } 112 | 113 | if (16 != fread(key, 1, 16, f)) 114 | { 115 | fprintf(stdout, "Error reading key file\n"); 116 | goto clean; 117 | } 118 | 119 | clean: 120 | if (f) 121 | fclose(f); 122 | } 123 | 124 | void hexdump(void *ptr, int buflen) 125 | { 126 | u8 *buf = (u8*)ptr; 127 | int i, j; 128 | 129 | for (i=0; i= 0x20 && buf[i+j] <= 0x7e) ? buf[i+j] : '.'); 151 | } 152 | } 153 | printf("\n"); 154 | } 155 | } 156 | 157 | void memdump(FILE* fout, const char* prefix, const u8* data, u32 size) 158 | { 159 | u32 i; 160 | u32 prefixlen = strlen(prefix); 161 | u32 offs = 0; 162 | u32 line = 0; 163 | while(size) 164 | { 165 | u32 max = 32; 166 | 167 | if (max > size) 168 | max = size; 169 | 170 | if (line==0) 171 | fprintf(fout, "%s", prefix); 172 | else 173 | fprintf(fout, "%*s", prefixlen, ""); 174 | 175 | 176 | for(i=0; i 5 | #include "types.h" 6 | #include "ctr.h" 7 | #include "settings.h" 8 | 9 | typedef struct 10 | { 11 | u8 reserved[5]; 12 | u8 flag; 13 | u8 remasterversion[2]; 14 | } exheader_systeminfoflags; 15 | 16 | typedef struct 17 | { 18 | u8 address[4]; 19 | u8 nummaxpages[4]; 20 | u8 codesize[4]; 21 | } exheader_codesegmentinfo; 22 | 23 | typedef struct 24 | { 25 | u8 name[8]; 26 | exheader_systeminfoflags flags; 27 | exheader_codesegmentinfo text; 28 | u8 stacksize[4]; 29 | exheader_codesegmentinfo ro; 30 | u8 reserved[4]; 31 | exheader_codesegmentinfo data; 32 | u8 bsssize[4]; 33 | } exheader_codesetinfo; 34 | 35 | typedef struct 36 | { 37 | u8 programid[0x30][8]; 38 | } exheader_dependencylist; 39 | 40 | typedef struct 41 | { 42 | u8 savedatasize[4]; 43 | u8 reserved[4]; 44 | u8 jumpid[8]; 45 | u8 reserved2[0x30]; 46 | } exheader_systeminfo; 47 | 48 | typedef struct 49 | { 50 | u8 extsavedataid[8]; 51 | u8 systemsavedataid[8]; 52 | u8 reserved[8]; 53 | u8 accessinfo[7]; 54 | u8 otherattributes; 55 | } exheader_storageinfo; 56 | 57 | typedef struct 58 | { 59 | u8 programid[8]; 60 | u8 flags[8]; 61 | u8 resourcelimitdescriptor[0x10][2]; 62 | exheader_storageinfo storageinfo; 63 | u8 serviceaccesscontrol[0x20][8]; 64 | u8 reserved[0x1f]; 65 | u8 resourcelimitcategory; 66 | } exheader_arm11systemlocalcaps; 67 | 68 | typedef struct 69 | { 70 | u8 descriptors[28][4]; 71 | u8 reserved[0x10]; 72 | } exheader_arm11kernelcapabilities; 73 | 74 | typedef struct 75 | { 76 | u8 descriptors[15]; 77 | u8 descversion; 78 | } exheader_arm9accesscontrol; 79 | 80 | typedef struct 81 | { 82 | // systemcontrol info { 83 | // coreinfo { 84 | exheader_codesetinfo codesetinfo; 85 | exheader_dependencylist deplist; 86 | // } 87 | exheader_systeminfo systeminfo; 88 | // } 89 | // accesscontrolinfo { 90 | exheader_arm11systemlocalcaps arm11systemlocalcaps; 91 | exheader_arm11kernelcapabilities arm11kernelcaps; 92 | exheader_arm9accesscontrol arm9accesscontrol; 93 | // } 94 | struct { 95 | u8 signature[0x100]; 96 | u8 ncchpubkeymodulus[0x100]; 97 | exheader_arm11systemlocalcaps arm11systemlocalcaps; 98 | exheader_arm11kernelcapabilities arm11kernelcaps; 99 | exheader_arm9accesscontrol arm9accesscontrol; 100 | } accessdesc; 101 | } exheader_header; 102 | 103 | typedef struct 104 | { 105 | int haveread; 106 | FILE* file; 107 | settings* usersettings; 108 | u8 partitionid[8]; 109 | u8 programid[8]; 110 | u8 counter[16]; 111 | u8 key[16]; 112 | u32 offset; 113 | u32 size; 114 | exheader_header header; 115 | ctr_aes_context aes; 116 | ctr_rsa_context rsa; 117 | int compressedflag; 118 | int encrypted; 119 | int validprogramid; 120 | int validpriority; 121 | int validaffinitymask; 122 | int validsignature; 123 | } exheader_context; 124 | 125 | void exheader_init(exheader_context* ctx); 126 | void exheader_set_file(exheader_context* ctx, FILE* file); 127 | void exheader_set_offset(exheader_context* ctx, u32 offset); 128 | void exheader_set_size(exheader_context* ctx, u32 size); 129 | void exheader_set_partitionid(exheader_context* ctx, u8 partitionid[8]); 130 | void exheader_set_counter(exheader_context* ctx, u8 counter[16]); 131 | void exheader_set_programid(exheader_context* ctx, u8 programid[8]); 132 | void exheader_set_encrypted(exheader_context* ctx, u32 encrypted); 133 | void exheader_set_key(exheader_context* ctx, u8 key[16]); 134 | void exheader_set_usersettings(exheader_context* ctx, settings* usersettings); 135 | int exheader_get_compressedflag(exheader_context* ctx); 136 | void exheader_read(exheader_context* ctx, u32 actions); 137 | int exheader_process(exheader_context* ctx, u32 actions); 138 | void exheader_print(exheader_context* ctx); 139 | void exheader_verify(exheader_context* ctx); 140 | int exheader_programid_valid(exheader_context* ctx); 141 | void exheader_determine_key(exheader_context* ctx, u32 actions); 142 | 143 | #endif // _EXHEADER_H_ 144 | -------------------------------------------------------------------------------- /ctrtool/ncsd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "types.h" 5 | #include "ncsd.h" 6 | #include "utils.h" 7 | #include "ctr.h" 8 | 9 | 10 | void ncsd_init(ncsd_context* ctx) 11 | { 12 | memset(ctx, 0, sizeof(ncsd_context)); 13 | } 14 | 15 | void ncsd_set_offset(ncsd_context* ctx, u32 offset) 16 | { 17 | ctx->offset = offset; 18 | } 19 | 20 | void ncsd_set_file(ncsd_context* ctx, FILE* file) 21 | { 22 | ctx->file = file; 23 | } 24 | 25 | void ncsd_set_size(ncsd_context* ctx, u32 size) 26 | { 27 | ctx->size = size; 28 | } 29 | 30 | void ncsd_set_usersettings(ncsd_context* ctx, settings* usersettings) 31 | { 32 | ctx->usersettings = usersettings; 33 | } 34 | 35 | int ncsd_signature_verify(const void* blob, rsakey2048* key) 36 | { 37 | u8* message = (u8*)blob + 0x100; 38 | u8* sig = (u8*)blob; 39 | u8 hash[0x20]; 40 | 41 | ctr_sha_256(message, 0x100, hash); 42 | return ctr_rsa_verify_hash(sig, hash, key); 43 | } 44 | 45 | void ncsd_process(ncsd_context* ctx, u32 actions) 46 | { 47 | fseek(ctx->file, ctx->offset, SEEK_SET); 48 | fread(&ctx->header, 1, 0x200, ctx->file); 49 | 50 | if (getle32(ctx->header.magic) != MAGIC_NCSD) 51 | { 52 | fprintf(stdout, "Error, NCSD segment corrupted\n"); 53 | return; 54 | } 55 | 56 | 57 | if (actions & VerifyFlag) 58 | { 59 | if (ctx->usersettings) 60 | ctx->headersigcheck = ncsd_signature_verify(&ctx->header, &ctx->usersettings->keys.ncsdrsakey); 61 | } 62 | 63 | if (actions & InfoFlag) 64 | ncsd_print(ctx); 65 | 66 | ncch_set_file(&ctx->ncch, ctx->file); 67 | ncch_set_offset(&ctx->ncch, 0x4000); 68 | ncch_set_size(&ctx->ncch, ctx->size - 0x4000); 69 | ncch_set_usersettings(&ctx->ncch, ctx->usersettings); 70 | ncch_process(&ctx->ncch, actions); 71 | } 72 | 73 | unsigned int ncsd_get_mediaunit_size(ncsd_context* ctx) 74 | { 75 | unsigned int mediaunitsize = settings_get_mediaunit_size(ctx->usersettings); 76 | 77 | if (mediaunitsize == 0) 78 | mediaunitsize = 1<<(9+ctx->header.flags[6]); 79 | 80 | return mediaunitsize; 81 | } 82 | 83 | void ncsd_print(ncsd_context* ctx) 84 | { 85 | char magic[5]; 86 | ctr_ncsdheader* header = &ctx->header; 87 | unsigned int i; 88 | unsigned int mediaunitsize = ncsd_get_mediaunit_size(ctx); 89 | 90 | 91 | memcpy(magic, header->magic, 4); 92 | magic[4] = 0; 93 | 94 | fprintf(stdout, "Header: %s\n", magic); 95 | if (ctx->headersigcheck == Unchecked) 96 | memdump(stdout, "Signature: ", header->signature, 0x100); 97 | else if (ctx->headersigcheck == Good) 98 | memdump(stdout, "Signature (GOOD): ", header->signature, 0x100); 99 | else 100 | memdump(stdout, "Signature (FAIL): ", header->signature, 0x100); 101 | fprintf(stdout, "Media size: 0x%08x\n", getle32(header->mediasize)); 102 | fprintf(stdout, "Media id: %016llx\n", getle64(header->mediaid)); 103 | //memdump(stdout, "Partition FS type: ", header->partitionfstype, 8); 104 | //memdump(stdout, "Partition crypt type: ", header->partitioncrypttype, 8); 105 | //memdump(stdout, "Partition offset/size: ", header->partitionoffsetandsize, 0x40); 106 | fprintf(stdout, "\n"); 107 | for(i=0; i<8; i++) 108 | { 109 | u32 partitionoffset = header->partitiongeometry[i].offset * mediaunitsize; 110 | u32 partitionsize = header->partitiongeometry[i].size * mediaunitsize; 111 | 112 | if (partitionsize != 0) 113 | { 114 | fprintf(stdout, "Partition %d \n", i); 115 | memdump(stdout, " Id: ", header->partitionid+i*8, 8); 116 | fprintf(stdout, " Area: 0x%08X-0x%08X\n", partitionoffset, partitionoffset+partitionsize); 117 | fprintf(stdout, " Filesystem: %02X\n", header->partitionfstype[i]); 118 | fprintf(stdout, " Encryption: %02X\n", header->partitioncrypttype[i]); 119 | fprintf(stdout, "\n"); 120 | } 121 | } 122 | memdump(stdout, "Extended header hash: ", header->extendedheaderhash, 0x20); 123 | memdump(stdout, "Additional header size: ", header->additionalheadersize, 4); 124 | memdump(stdout, "Sector zero offset: ", header->sectorzerooffset, 4); 125 | memdump(stdout, "Flags: ", header->flags, 8); 126 | fprintf(stdout, " > Mediaunit size: 0x%X\n", mediaunitsize); 127 | 128 | } 129 | -------------------------------------------------------------------------------- /ctrtool/polarssl/aes.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file aes.h 3 | * 4 | * Copyright (C) 2006-2010, Brainspark B.V. 5 | * 6 | * This file is part of PolarSSL (http://www.polarssl.org) 7 | * Lead Maintainer: Paul Bakker 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | #ifndef POLARSSL_AES_H 26 | #define POLARSSL_AES_H 27 | 28 | #define AES_ENCRYPT 1 29 | #define AES_DECRYPT 0 30 | 31 | #define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0800 32 | #define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0810 33 | 34 | /** 35 | * \brief AES context structure 36 | */ 37 | typedef struct 38 | { 39 | int nr; /*!< number of rounds */ 40 | unsigned long *rk; /*!< AES round keys */ 41 | unsigned long buf[68]; /*!< unaligned data */ 42 | } 43 | aes_context; 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | /** 50 | * \brief AES key schedule (encryption) 51 | * 52 | * \param ctx AES context to be initialized 53 | * \param key encryption key 54 | * \param keysize must be 128, 192 or 256 55 | * 56 | * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH 57 | */ 58 | int aes_setkey_enc( aes_context *ctx, const unsigned char *key, int keysize ); 59 | 60 | /** 61 | * \brief AES key schedule (decryption) 62 | * 63 | * \param ctx AES context to be initialized 64 | * \param key decryption key 65 | * \param keysize must be 128, 192 or 256 66 | * 67 | * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH 68 | */ 69 | int aes_setkey_dec( aes_context *ctx, const unsigned char *key, int keysize ); 70 | 71 | /** 72 | * \brief AES-ECB block encryption/decryption 73 | * 74 | * \param ctx AES context 75 | * \param mode AES_ENCRYPT or AES_DECRYPT 76 | * \param input 16-byte input block 77 | * \param output 16-byte output block 78 | * 79 | * \return 0 if successful 80 | */ 81 | int aes_crypt_ecb( aes_context *ctx, 82 | int mode, 83 | const unsigned char input[16], 84 | unsigned char output[16] ); 85 | 86 | /** 87 | * \brief AES-CBC buffer encryption/decryption 88 | * Length should be a multiple of the block 89 | * size (16 bytes) 90 | * 91 | * \param ctx AES context 92 | * \param mode AES_ENCRYPT or AES_DECRYPT 93 | * \param length length of the input data 94 | * \param iv initialization vector (updated after use) 95 | * \param input buffer holding the input data 96 | * \param output buffer holding the output data 97 | * 98 | * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH 99 | */ 100 | int aes_crypt_cbc( aes_context *ctx, 101 | int mode, 102 | int length, 103 | unsigned char iv[16], 104 | const unsigned char *input, 105 | unsigned char *output ); 106 | 107 | /** 108 | * \brief AES-CFB128 buffer encryption/decryption. 109 | * 110 | * \param ctx AES context 111 | * \param mode AES_ENCRYPT or AES_DECRYPT 112 | * \param length length of the input data 113 | * \param iv_off offset in IV (updated after use) 114 | * \param iv initialization vector (updated after use) 115 | * \param input buffer holding the input data 116 | * \param output buffer holding the output data 117 | * 118 | * \return 0 if successful 119 | */ 120 | int aes_crypt_cfb128( aes_context *ctx, 121 | int mode, 122 | int length, 123 | int *iv_off, 124 | unsigned char iv[16], 125 | const unsigned char *input, 126 | unsigned char *output ); 127 | 128 | /** 129 | * \brief Checkup routine 130 | * 131 | * \return 0 if successful, or 1 if the test failed 132 | */ 133 | int aes_self_test( int verbose ); 134 | 135 | #ifdef __cplusplus 136 | } 137 | #endif 138 | 139 | #endif /* aes.h */ 140 | -------------------------------------------------------------------------------- /ctrtool/lzss.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "types.h" 5 | #include "utils.h" 6 | #include "lzss.h" 7 | 8 | void lzss_init(lzss_context* ctx) 9 | { 10 | memset(ctx, 0, sizeof(lzss_context)); 11 | } 12 | 13 | void lzss_set_usersettings(lzss_context* ctx, settings* usersettings) 14 | { 15 | ctx->usersettings = usersettings; 16 | } 17 | 18 | void lzss_set_offset(lzss_context* ctx, u32 offset) 19 | { 20 | ctx->offset = offset; 21 | } 22 | 23 | void lzss_set_size(lzss_context* ctx, u32 size) 24 | { 25 | ctx->size = size; 26 | } 27 | 28 | void lzss_set_file(lzss_context* ctx, FILE* file) 29 | { 30 | ctx->file = file; 31 | } 32 | 33 | 34 | void lzss_process(lzss_context* ctx, u32 actions) 35 | { 36 | unsigned int compressedsize; 37 | unsigned char* compressedbuffer = 0; 38 | unsigned int decompressedsize; 39 | unsigned char* decompressedbuffer = 0; 40 | FILE* fout = 0; 41 | 42 | 43 | fseek(ctx->file, ctx->offset, SEEK_SET); 44 | 45 | 46 | if (actions & ExtractFlag) 47 | { 48 | 49 | filepath* path = settings_get_lzss_path(ctx->usersettings); 50 | 51 | if (path == 0 || path->valid == 0) 52 | goto clean; 53 | 54 | fout = fopen(path->pathname, "wb"); 55 | if (0 == fout) 56 | { 57 | fprintf(stdout, "Error opening out file %s\n", path->pathname); 58 | goto clean; 59 | } 60 | compressedsize = ctx->size; 61 | compressedbuffer = malloc(compressedsize); 62 | if (1 != fread(compressedbuffer, compressedsize, 1, ctx->file)) 63 | { 64 | fprintf(stdout, "Error read input file\n"); 65 | goto clean; 66 | } 67 | 68 | decompressedsize = lzss_get_decompressed_size(compressedbuffer, compressedsize); 69 | decompressedbuffer = malloc(decompressedsize); 70 | 71 | printf("Compressed: %d\n", compressedsize); 72 | printf("Decompressed: %d\n", decompressedsize); 73 | 74 | if (decompressedbuffer == 0) 75 | { 76 | fprintf(stdout, "Error allocating memory\n"); 77 | goto clean; 78 | } 79 | 80 | if (0 == lzss_decompress(compressedbuffer, compressedsize, decompressedbuffer, decompressedsize)) 81 | goto clean; 82 | 83 | printf("Saving decompressed lzss blob to %s...\n", path->pathname); 84 | if (decompressedsize != fwrite(decompressedbuffer, 1, decompressedsize, fout)) 85 | { 86 | fprintf(stdout, "Error writing output file\n"); 87 | goto clean; 88 | } 89 | } 90 | 91 | clean: 92 | free(decompressedbuffer); 93 | free(compressedbuffer); 94 | if (fout) 95 | fclose(fout); 96 | } 97 | 98 | 99 | u32 lzss_get_decompressed_size(u8* compressed, u32 compressedsize) 100 | { 101 | u8* footer = compressed + compressedsize - 8; 102 | 103 | //u32 buffertopandbottom = getle32(footer+0); 104 | u32 originalbottom = getle32(footer+4); 105 | 106 | return originalbottom + compressedsize; 107 | } 108 | 109 | int lzss_decompress(u8* compressed, u32 compressedsize, u8* decompressed, u32 decompressedsize) 110 | { 111 | u8* footer = compressed + compressedsize - 8; 112 | u32 buffertopandbottom = getle32(footer+0); 113 | //u32 originalbottom = getle32(footer+4); 114 | u32 i, j; 115 | u32 out = decompressedsize; 116 | u32 index = compressedsize - ((buffertopandbottom>>24)&0xFF); 117 | u32 segmentoffset; 118 | u32 segmentsize; 119 | u8 control; 120 | u32 stopindex = compressedsize - (buffertopandbottom&0xFFFFFF); 121 | 122 | memset(decompressed, 0, decompressedsize); 123 | memcpy(decompressed, compressed, compressedsize); 124 | 125 | 126 | while(index > stopindex) 127 | { 128 | control = compressed[--index]; 129 | 130 | 131 | for(i=0; i<8; i++) 132 | { 133 | if (index <= stopindex) 134 | break; 135 | 136 | if (index <= 0) 137 | break; 138 | 139 | if (out <= 0) 140 | break; 141 | 142 | if (control & 0x80) 143 | { 144 | if (index < 2) 145 | { 146 | fprintf(stderr, "Error, compression out of bounds\n"); 147 | goto clean; 148 | } 149 | 150 | index -= 2; 151 | 152 | segmentoffset = compressed[index] | (compressed[index+1]<<8); 153 | segmentsize = ((segmentoffset >> 12)&15)+3; 154 | segmentoffset &= 0x0FFF; 155 | segmentoffset += 2; 156 | 157 | 158 | if (out < segmentsize) 159 | { 160 | fprintf(stderr, "Error, compression out of bounds\n"); 161 | goto clean; 162 | } 163 | 164 | for(j=0; j= decompressedsize) 169 | { 170 | fprintf(stderr, "Error, compression out of bounds\n"); 171 | goto clean; 172 | } 173 | 174 | data = decompressed[out+segmentoffset]; 175 | decompressed[--out] = data; 176 | } 177 | } 178 | else 179 | { 180 | if (out < 1) 181 | { 182 | fprintf(stderr, "Error, compression out of bounds\n"); 183 | goto clean; 184 | } 185 | decompressed[--out] = compressed[--index]; 186 | } 187 | 188 | control <<= 1; 189 | } 190 | } 191 | 192 | return 1; 193 | clean: 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /ctrtool/polarssl/sha2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file sha2.h 3 | * 4 | * Copyright (C) 2006-2010, Brainspark B.V. 5 | * 6 | * This file is part of PolarSSL (http://www.polarssl.org) 7 | * Lead Maintainer: Paul Bakker 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | #ifndef POLARSSL_SHA2_H 26 | #define POLARSSL_SHA2_H 27 | 28 | /** 29 | * \brief SHA-256 context structure 30 | */ 31 | typedef struct 32 | { 33 | unsigned long total[2]; /*!< number of bytes processed */ 34 | unsigned long state[8]; /*!< intermediate digest state */ 35 | unsigned char buffer[64]; /*!< data block being processed */ 36 | 37 | unsigned char ipad[64]; /*!< HMAC: inner padding */ 38 | unsigned char opad[64]; /*!< HMAC: outer padding */ 39 | int is224; /*!< 0 => SHA-256, else SHA-224 */ 40 | } 41 | sha2_context; 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | /** 48 | * \brief SHA-256 context setup 49 | * 50 | * \param ctx context to be initialized 51 | * \param is224 0 = use SHA256, 1 = use SHA224 52 | */ 53 | void sha2_starts( sha2_context *ctx, int is224 ); 54 | 55 | /** 56 | * \brief SHA-256 process buffer 57 | * 58 | * \param ctx SHA-256 context 59 | * \param input buffer holding the data 60 | * \param ilen length of the input data 61 | */ 62 | void sha2_update( sha2_context *ctx, const unsigned char *input, int ilen ); 63 | 64 | /** 65 | * \brief SHA-256 final digest 66 | * 67 | * \param ctx SHA-256 context 68 | * \param output SHA-224/256 checksum result 69 | */ 70 | void sha2_finish( sha2_context *ctx, unsigned char output[32] ); 71 | 72 | /** 73 | * \brief Output = SHA-256( input buffer ) 74 | * 75 | * \param input buffer holding the data 76 | * \param ilen length of the input data 77 | * \param output SHA-224/256 checksum result 78 | * \param is224 0 = use SHA256, 1 = use SHA224 79 | */ 80 | void sha2( const unsigned char *input, int ilen, 81 | unsigned char output[32], int is224 ); 82 | 83 | /** 84 | * \brief Output = SHA-256( file contents ) 85 | * 86 | * \param path input file name 87 | * \param output SHA-224/256 checksum result 88 | * \param is224 0 = use SHA256, 1 = use SHA224 89 | * 90 | * \return 0 if successful, 1 if fopen failed, 91 | * or 2 if fread failed 92 | */ 93 | int sha2_file( const char *path, unsigned char output[32], int is224 ); 94 | 95 | /** 96 | * \brief SHA-256 HMAC context setup 97 | * 98 | * \param ctx HMAC context to be initialized 99 | * \param key HMAC secret key 100 | * \param keylen length of the HMAC key 101 | * \param is224 0 = use SHA256, 1 = use SHA224 102 | */ 103 | void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, int keylen, 104 | int is224 ); 105 | 106 | /** 107 | * \brief SHA-256 HMAC process buffer 108 | * 109 | * \param ctx HMAC context 110 | * \param input buffer holding the data 111 | * \param ilen length of the input data 112 | */ 113 | void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, int ilen ); 114 | 115 | /** 116 | * \brief SHA-256 HMAC final digest 117 | * 118 | * \param ctx HMAC context 119 | * \param output SHA-224/256 HMAC checksum result 120 | */ 121 | void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ); 122 | 123 | /** 124 | * \brief SHA-256 HMAC context reset 125 | * 126 | * \param ctx HMAC context to be reset 127 | */ 128 | void sha2_hmac_reset( sha2_context *ctx ); 129 | 130 | /** 131 | * \brief Output = HMAC-SHA-256( hmac key, input buffer ) 132 | * 133 | * \param key HMAC secret key 134 | * \param keylen length of the HMAC key 135 | * \param input buffer holding the data 136 | * \param ilen length of the input data 137 | * \param output HMAC-SHA-224/256 result 138 | * \param is224 0 = use SHA256, 1 = use SHA224 139 | */ 140 | void sha2_hmac( const unsigned char *key, int keylen, 141 | const unsigned char *input, int ilen, 142 | unsigned char output[32], int is224 ); 143 | 144 | /** 145 | * \brief Checkup routine 146 | * 147 | * \return 0 if successful, or 1 if the test failed 148 | */ 149 | int sha2_self_test( int verbose ); 150 | 151 | #ifdef __cplusplus 152 | } 153 | #endif 154 | 155 | #endif /* sha2.h */ 156 | -------------------------------------------------------------------------------- /ctrtool/windows/getopt1.c: -------------------------------------------------------------------------------- 1 | /* getopt_long and getopt_long_only entry points for GNU getopt. 2 | Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 3 | Free Software Foundation, Inc. 4 | This file is part of the GNU C Library. 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Library General Public License as 8 | published by the Free Software Foundation; either version 2 of the 9 | License, or (at your option) any later version. 10 | 11 | The GNU C Library 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 GNU 14 | Library General Public License for more details. 15 | 16 | You should have received a copy of the GNU Library General Public 17 | License along with the GNU C Library; see the file COPYING.LIB. If not, 18 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 | Boston, MA 02111-1307, USA. */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include "getopt.h" 26 | 27 | #if !defined __STDC__ || !__STDC__ 28 | /* This is a separate conditional since some stdc systems 29 | reject `defined (const)'. */ 30 | #ifndef const 31 | #define const 32 | #endif 33 | #endif 34 | 35 | #include 36 | 37 | /* Comment out all this code if we are using the GNU C Library, and are not 38 | actually compiling the library itself. This code is part of the GNU C 39 | Library, but also included in many other GNU distributions. Compiling 40 | and linking in this code is a waste when using the GNU C library 41 | (especially if it is a shared library). Rather than having every GNU 42 | program understand `configure --with-gnu-libc' and omit the object files, 43 | it is simpler to just do this in the source for each such file. */ 44 | 45 | #define GETOPT_INTERFACE_VERSION 2 46 | #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 47 | #include 48 | #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION 49 | #define ELIDE_CODE 50 | #endif 51 | #endif 52 | 53 | #ifndef ELIDE_CODE 54 | 55 | 56 | /* This needs to come after some library #include 57 | to get __GNU_LIBRARY__ defined. */ 58 | #ifdef __GNU_LIBRARY__ 59 | #include 60 | #endif 61 | 62 | #ifndef NULL 63 | #define NULL 0 64 | #endif 65 | 66 | int 67 | getopt_long (argc, argv, options, long_options, opt_index) 68 | int argc; 69 | char **argv; 70 | const char *options; 71 | const struct option *long_options; 72 | int *opt_index; 73 | { 74 | return _getopt_internal (argc, argv, options, long_options, opt_index, 0); 75 | } 76 | 77 | /* Like getopt_long, but '-' as well as '--' can indicate a long option. 78 | If an option that starts with '-' (not '--') doesn't match a long option, 79 | but does match a short option, it is parsed as a short option 80 | instead. */ 81 | 82 | int 83 | getopt_long_only (argc, argv, options, long_options, opt_index) 84 | int argc; 85 | char *const *argv; 86 | const char *options; 87 | const struct option *long_options; 88 | int *opt_index; 89 | { 90 | return _getopt_internal (argc, argv, options, long_options, opt_index, 1); 91 | } 92 | 93 | 94 | #endif /* Not ELIDE_CODE. */ 95 | 96 | #ifdef TEST 97 | 98 | #include 99 | 100 | int 101 | main (argc, argv) 102 | int argc; 103 | char **argv; 104 | { 105 | int c; 106 | int digit_optind = 0; 107 | 108 | while (1) 109 | { 110 | int this_option_optind = optind ? optind : 1; 111 | int option_index = 0; 112 | static struct option long_options[] = 113 | { 114 | {"add", 1, 0, 0}, 115 | {"append", 0, 0, 0}, 116 | {"delete", 1, 0, 0}, 117 | {"verbose", 0, 0, 0}, 118 | {"create", 0, 0, 0}, 119 | {"file", 1, 0, 0}, 120 | {0, 0, 0, 0} 121 | }; 122 | 123 | c = getopt_long (argc, argv, "abc:d:0123456789", 124 | long_options, &option_index); 125 | if (c == -1) 126 | break; 127 | 128 | switch (c) 129 | { 130 | case 0: 131 | printf ("option %s", long_options[option_index].name); 132 | if (optarg) 133 | printf (" with arg %s", optarg); 134 | printf ("\n"); 135 | break; 136 | 137 | case '0': 138 | case '1': 139 | case '2': 140 | case '3': 141 | case '4': 142 | case '5': 143 | case '6': 144 | case '7': 145 | case '8': 146 | case '9': 147 | if (digit_optind != 0 && digit_optind != this_option_optind) 148 | printf ("digits occur in two different argv-elements.\n"); 149 | digit_optind = this_option_optind; 150 | printf ("option %c\n", c); 151 | break; 152 | 153 | case 'a': 154 | printf ("option a\n"); 155 | break; 156 | 157 | case 'b': 158 | printf ("option b\n"); 159 | break; 160 | 161 | case 'c': 162 | printf ("option c with value `%s'\n", optarg); 163 | break; 164 | 165 | case 'd': 166 | printf ("option d with value `%s'\n", optarg); 167 | break; 168 | 169 | case '?': 170 | break; 171 | 172 | default: 173 | printf ("?? getopt returned character code 0%o ??\n", c); 174 | } 175 | } 176 | 177 | if (optind < argc) 178 | { 179 | printf ("non-option ARGV-elements: "); 180 | while (optind < argc) 181 | printf ("%s ", argv[optind++]); 182 | printf ("\n"); 183 | } 184 | 185 | exit (0); 186 | } 187 | 188 | #endif /* TEST */ 189 | -------------------------------------------------------------------------------- /ctrtool/tmd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tmd.h" 6 | #include "utils.h" 7 | 8 | 9 | void tmd_init(tmd_context* ctx) 10 | { 11 | memset(ctx, 0, sizeof(tmd_context)); 12 | } 13 | 14 | void tmd_set_file(tmd_context* ctx, FILE* file) 15 | { 16 | ctx->file = file; 17 | } 18 | 19 | void tmd_set_offset(tmd_context* ctx, u32 offset) 20 | { 21 | ctx->offset = offset; 22 | } 23 | 24 | void tmd_set_size(tmd_context* ctx, u32 size) 25 | { 26 | ctx->size = size; 27 | } 28 | 29 | void tmd_set_usersettings(tmd_context* ctx, settings* usersettings) 30 | { 31 | ctx->usersettings = usersettings; 32 | } 33 | 34 | void tmd_process(tmd_context* ctx, u32 actions) 35 | { 36 | if (ctx->buffer == 0) 37 | ctx->buffer = malloc(ctx->size); 38 | 39 | if (ctx->buffer) 40 | { 41 | fseek(ctx->file, ctx->offset, SEEK_SET); 42 | fread(ctx->buffer, 1, ctx->size, ctx->file); 43 | 44 | if (actions & InfoFlag) 45 | { 46 | tmd_print(ctx); 47 | } 48 | } 49 | } 50 | 51 | ctr_tmd_body *tmd_get_body(tmd_context *ctx) 52 | { 53 | unsigned int type = getbe32(ctx->buffer); 54 | ctr_tmd_body *body = NULL; 55 | 56 | if (type == TMD_RSA_2048_SHA256 || type == TMD_RSA_2048_SHA1) 57 | { 58 | body = (ctr_tmd_body*)(ctx->buffer + sizeof(ctr_tmd_header_2048)); 59 | } 60 | else if (type == TMD_RSA_4096_SHA256 || type == TMD_RSA_4096_SHA1) 61 | { 62 | body = (ctr_tmd_body*)(ctx->buffer + sizeof(ctr_tmd_header_4096)); 63 | } 64 | 65 | return body; 66 | } 67 | 68 | const char* tmd_get_type_string(unsigned int type) 69 | { 70 | switch(type) 71 | { 72 | case TMD_RSA_2048_SHA256: return "RSA 2048 - SHA256"; 73 | case TMD_RSA_4096_SHA256: return "RSA 4096 - SHA256"; 74 | case TMD_RSA_2048_SHA1: return "RSA 2048 - SHA1"; 75 | case TMD_RSA_4096_SHA1: return "RSA 4096 - SHA1"; 76 | default: 77 | return "unknown"; 78 | } 79 | } 80 | 81 | void tmd_print(tmd_context* ctx) 82 | { 83 | unsigned int type = getbe32(ctx->buffer); 84 | ctr_tmd_header_4096* header4096 = 0; 85 | ctr_tmd_header_2048* header2048 = 0; 86 | ctr_tmd_body* body = 0; 87 | unsigned int contentcount = 0; 88 | unsigned int i; 89 | 90 | if (type == TMD_RSA_2048_SHA256 || type == TMD_RSA_2048_SHA1) 91 | { 92 | header2048 = (ctr_tmd_header_2048*)ctx->buffer; 93 | } 94 | else if (type == TMD_RSA_4096_SHA256 || type == TMD_RSA_4096_SHA1) 95 | { 96 | header4096 = (ctr_tmd_header_4096*)ctx->buffer; 97 | } 98 | else 99 | { 100 | return; 101 | } 102 | 103 | body = tmd_get_body(ctx); 104 | 105 | contentcount = getbe16(body->contentcount); 106 | 107 | fprintf(stdout, "\nTMD header:\n"); 108 | fprintf(stdout, "Signature type: %s\n", tmd_get_type_string(type)); 109 | fprintf(stdout, "Issuer: %s\n", body->issuer); 110 | fprintf(stdout, "Version: %d\n", body->version); 111 | fprintf(stdout, "CA CRL version: %d\n", body->ca_crl_version); 112 | fprintf(stdout, "Signer CRL version: %d\n", body->signer_crl_version); 113 | memdump(stdout, "System version: ", body->systemversion, 8); 114 | memdump(stdout, "Title id: ", body->titleid, 8); 115 | fprintf(stdout, "Title type: %08x\n", getbe32(body->titletype)); 116 | fprintf(stdout, "Group id: %04x\n", getbe16(body->groupid)); 117 | fprintf(stdout, "Access rights: %08x\n", getbe32(body->accessrights)); 118 | fprintf(stdout, "Title version: %04x\n", getbe16(body->titleversion)); 119 | fprintf(stdout, "Content count: %04x\n", getbe16(body->contentcount)); 120 | fprintf(stdout, "Boot content: %04x\n", getbe16(body->bootcontent)); 121 | memdump(stdout, "Hash: ", body->hash, 32); 122 | 123 | fprintf(stdout, "\nTMD content info:\n"); 124 | for(i = 0; i < TMD_MAX_CONTENTS; i++) 125 | { 126 | ctr_tmd_contentinfo* info = (ctr_tmd_contentinfo*)(body->contentinfo + sizeof(ctr_tmd_contentinfo)*i); 127 | 128 | if (getbe16(info->commandcount) == 0) 129 | continue; 130 | 131 | fprintf(stdout, "Content index: %04x\n", getbe16(info->index)); 132 | fprintf(stdout, "Command count: %04x\n", getbe16(info->commandcount)); 133 | memdump(stdout, "Unknown: ", info->unk, 32); 134 | } 135 | fprintf(stdout, "\nTMD contents:\n"); 136 | for(i = 0; i < contentcount; i++) 137 | { 138 | ctr_tmd_contentchunk* chunk = (ctr_tmd_contentchunk*)(body->contentinfo + 36*64 + i*48); 139 | unsigned short type = getbe16(chunk->type); 140 | 141 | fprintf(stdout, "Content id: %08x\n", getbe32(chunk->id)); 142 | fprintf(stdout, "Content index: %04x\n", getbe16(chunk->index)); 143 | fprintf(stdout, "Content type: %04x", getbe16(chunk->type)); 144 | if (type) 145 | { 146 | fprintf(stdout, " "); 147 | if (type & 1) 148 | fprintf(stdout, "[encrypted]"); 149 | if (type & 2) 150 | fprintf(stdout, "[disc]"); 151 | if (type & 4) 152 | fprintf(stdout, "[cfm]"); 153 | if (type & 0x4000) 154 | fprintf(stdout, "[optional]"); 155 | if (type & 0x8000) 156 | fprintf(stdout, "[shared]"); 157 | } 158 | fprintf(stdout, "\n"); 159 | fprintf(stdout, "Content size: %016llx\n", getbe64(chunk->size)); 160 | 161 | switch(ctx->content_hash_stat[getbe16(chunk->index)]) { 162 | case 1: memdump(stdout, "Content hash [OK]: ", chunk->hash, 32); break; 163 | case 2: memdump(stdout, "Content hash [FAIL]: ", chunk->hash, 32); break; 164 | default: memdump(stdout, "Content hash: ", chunk->hash, 32); break; 165 | } 166 | 167 | fprintf(stdout, "\n"); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /ctrtool/cwav.h: -------------------------------------------------------------------------------- 1 | #ifndef _CWAV_H_ 2 | #define _CWAV_H_ 3 | 4 | #include 5 | #include "types.h" 6 | #include "settings.h" 7 | #include "stream.h" 8 | 9 | #define CWAV_ENCODING_PCM8 0 10 | #define CWAV_ENCODING_PCM16 1 11 | #define CWAV_ENCODING_DSPADPCM 2 12 | #define CWAV_ENCODING_IMAADPCM 3 13 | 14 | typedef struct 15 | { 16 | u8 idtype[2]; 17 | u8 padding[2]; 18 | u8 offset[4]; 19 | } cwav_reference; 20 | 21 | typedef struct 22 | { 23 | u8 idtype[2]; 24 | u8 padding[2]; 25 | u8 offset[4]; 26 | u8 size[4]; 27 | } cwav_sizedreference; 28 | 29 | 30 | typedef struct 31 | { 32 | u8 magic[4]; 33 | u8 byteordermark[2]; 34 | u8 headersize[2]; 35 | u8 version[4]; 36 | u8 totalsize[4]; 37 | u8 datablocks[2]; 38 | u8 reserved[2]; 39 | cwav_sizedreference infoblockref; 40 | cwav_sizedreference datablockref; 41 | } cwav_header; 42 | 43 | typedef struct 44 | { 45 | u8 magic[4]; 46 | u8 size[4]; 47 | u8 encoding; 48 | u8 looped; 49 | u8 padding[2]; 50 | u8 samplerate[4]; 51 | u8 loopstart[4]; 52 | u8 loopend[4]; 53 | u8 reserved[4]; 54 | u8 channelcount[4]; 55 | } cwav_infoheader; 56 | 57 | typedef struct 58 | { 59 | cwav_reference sampleref; 60 | cwav_reference codecref; 61 | u8 reserved[4]; 62 | } cwav_channelinfo; 63 | 64 | typedef struct 65 | { 66 | u8 coef[16][2]; 67 | u8 scale[2]; 68 | u8 yn1[2]; 69 | u8 yn2[2]; 70 | u8 loopscale[2]; 71 | u8 loopyn1[2]; 72 | u8 loopyn2[2]; 73 | } cwav_dspadpcminfo; 74 | 75 | typedef struct 76 | { 77 | u8 data[2]; 78 | u8 tableindex; 79 | u8 padding; 80 | u8 loopdata[2]; 81 | u8 looptableindex; 82 | u8 looppadding; 83 | } cwav_imaadpcminfo; 84 | 85 | 86 | typedef struct 87 | { 88 | s16 yn1; 89 | s16 yn2; 90 | u32 sampleoffset; 91 | s16* samplebuffer; 92 | stream_in_context instreamctx; 93 | } cwav_dspadpcmchannelstate; 94 | 95 | typedef struct 96 | { 97 | cwav_dspadpcmchannelstate* channelstate; 98 | s16* samplebuffer; 99 | u32 samplecountavailable; 100 | u32 samplecountcapacity; 101 | u32 samplecountremaining; 102 | } cwav_dspadpcmstate; 103 | 104 | typedef struct 105 | { 106 | s16 data; 107 | u8 tableindex; 108 | u32 sampleoffset; 109 | s16* samplebuffer; 110 | stream_in_context instreamctx; 111 | } cwav_imaadpcmchannelstate; 112 | 113 | typedef struct 114 | { 115 | cwav_imaadpcmchannelstate* channelstate; 116 | s16* samplebuffer; 117 | u32 samplecountavailable; 118 | u32 samplecountcapacity; 119 | u32 samplecountremaining; 120 | } cwav_imaadpcmstate; 121 | 122 | typedef struct 123 | { 124 | u32 sampleoffset; 125 | s16* samplebuffer; 126 | stream_in_context instreamctx; 127 | } cwav_pcmchannelstate; 128 | 129 | typedef struct 130 | { 131 | cwav_pcmchannelstate* channelstate; 132 | s16* samplebuffer; 133 | u32 samplecountavailable; 134 | u32 samplecountcapacity; 135 | u32 samplecountremaining; 136 | } cwav_pcmstate; 137 | 138 | 139 | typedef struct 140 | { 141 | cwav_reference inforef; 142 | cwav_channelinfo info; 143 | cwav_dspadpcminfo infodspadpcm; 144 | cwav_imaadpcminfo infoimaadpcm; 145 | } cwav_channel; 146 | 147 | typedef struct 148 | { 149 | u8 chunkid[4]; 150 | u8 chunksize[4]; 151 | u8 format[4]; 152 | u8 subchunk1id[4]; 153 | u8 subchunk1size[4]; 154 | u8 audioformat[2]; 155 | u8 numchannels[2]; 156 | u8 samplerate[4]; 157 | u8 byterate[4]; 158 | u8 blockalign[2]; 159 | u8 bitspersample[2]; 160 | u8 subchunk2id[4]; 161 | u8 subchunk2size[4]; 162 | } wav_pcm_header; 163 | 164 | typedef struct 165 | { 166 | FILE* file; 167 | settings* usersettings; 168 | u32 offset; 169 | u32 size; 170 | u32 channelcount; 171 | cwav_header header; 172 | cwav_infoheader infoheader; 173 | cwav_channel* channel; 174 | } cwav_context; 175 | 176 | void cwav_init(cwav_context* ctx); 177 | void cwav_set_file(cwav_context* ctx, FILE* file); 178 | void cwav_set_offset(cwav_context* ctx, u32 offset); 179 | void cwav_set_size(cwav_context* ctx, u32 size); 180 | void cwav_set_usersettings(cwav_context* ctx, settings* usersettings); 181 | void cwav_process(cwav_context* ctx, u32 actions); 182 | void cwav_dspadpcm_init(cwav_dspadpcmstate* state); 183 | int cwav_dspadpcm_allocate(cwav_dspadpcmstate* state, cwav_context* ctx); 184 | int cwav_dspadpcm_setup(cwav_dspadpcmstate* state, cwav_context* ctx, int isloop); 185 | int cwav_dspadpcm_decode(cwav_dspadpcmstate* state, cwav_context* ctx); 186 | int cwav_dspadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx); 187 | void cwav_dspadpcm_destroy(cwav_dspadpcmstate* state); 188 | void cwav_imaadpcm_init(cwav_imaadpcmstate* state); 189 | int cwav_imaadpcm_allocate(cwav_imaadpcmstate* state, cwav_context* ctx); 190 | int cwav_imaadpcm_setup(cwav_imaadpcmstate* state, cwav_context* ctx, int isloop); 191 | int cwav_imaadpcm_decode(cwav_imaadpcmstate* state, cwav_context* ctx); 192 | int cwav_imaadpcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx); 193 | u8 cwav_imaadpcm_clamp_tableindex(u8 tableindex, int inc); 194 | void cwav_imaadpcm_destroy(cwav_imaadpcmstate* state); 195 | void cwav_pcm_init(cwav_pcmstate* state); 196 | int cwav_pcm_allocate(cwav_pcmstate* state, cwav_context* ctx); 197 | int cwav_pcm_setup(cwav_pcmstate* state, cwav_context* ctx, int isloop); 198 | int cwav_pcm_decode(cwav_pcmstate* state, cwav_context* ctx); 199 | int cwav_pcm_decode_to_wav(cwav_context* ctx, stream_out_context* outstreamctx); 200 | void cwav_pcm_destroy(cwav_pcmstate* state); 201 | void cwav_write_wav_header(cwav_context* ctx, stream_out_context* outstreamctx, u32 size); 202 | int cwav_save_to_wav(cwav_context* ctx, const char* filepath); 203 | void cwav_print(cwav_context* ctx); 204 | 205 | #endif // _CWAV_H_ 206 | -------------------------------------------------------------------------------- /ctrtool/ivfc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "types.h" 5 | #include "utils.h" 6 | #include "ivfc.h" 7 | #include "ctr.h" 8 | 9 | void ivfc_init(ivfc_context* ctx) 10 | { 11 | memset(ctx, 0, sizeof(ivfc_context)); 12 | } 13 | 14 | void ivfc_set_usersettings(ivfc_context* ctx, settings* usersettings) 15 | { 16 | ctx->usersettings = usersettings; 17 | } 18 | 19 | void ivfc_set_offset(ivfc_context* ctx, u32 offset) 20 | { 21 | ctx->offset = offset; 22 | } 23 | 24 | void ivfc_set_size(ivfc_context* ctx, u32 size) 25 | { 26 | ctx->size = size; 27 | } 28 | 29 | void ivfc_set_file(ivfc_context* ctx, FILE* file) 30 | { 31 | ctx->file = file; 32 | } 33 | 34 | 35 | void ivfc_process(ivfc_context* ctx, u32 actions) 36 | { 37 | 38 | 39 | fseek(ctx->file, ctx->offset, SEEK_SET); 40 | fread(&ctx->header, 1, sizeof(ivfc_header), ctx->file); 41 | 42 | if (getle32(ctx->header.magic) != MAGIC_IVFC) 43 | { 44 | fprintf(stdout, "Error, IVFC segment corrupted\n"); 45 | return; 46 | } 47 | 48 | if (getle32(ctx->header.id) == 0x10000) 49 | { 50 | fread(&ctx->romfsheader, 1, sizeof(ivfc_header_romfs), ctx->file); 51 | 52 | ctx->levelcount = 3; 53 | 54 | ctx->level[2].hashblocksize = 1 << getle32(ctx->romfsheader.level3.blocksize); 55 | ctx->level[1].hashblocksize = 1 << getle32(ctx->romfsheader.level2.blocksize); 56 | ctx->level[0].hashblocksize = 1 << getle32(ctx->romfsheader.level1.blocksize); 57 | ctx->level[0].hashoffset = 0x60; 58 | 59 | ctx->bodyoffset = align64(ctx->level[0].hashoffset + getle32(ctx->romfsheader.masterhashsize), ctx->level[2].hashblocksize); 60 | ctx->bodysize = getle64(ctx->romfsheader.level3.hashdatasize); 61 | 62 | ctx->level[2].dataoffset = ctx->bodyoffset; 63 | ctx->level[2].datasize = align64(ctx->bodysize, ctx->level[2].hashblocksize); 64 | 65 | ctx->level[1].hashoffset = align64(ctx->bodyoffset + ctx->bodysize, ctx->level[2].hashblocksize); 66 | ctx->level[2].hashoffset = ctx->level[1].hashoffset + getle64(ctx->romfsheader.level2.logicaloffset) - getle64(ctx->romfsheader.level1.logicaloffset); 67 | 68 | ctx->level[1].dataoffset = ctx->level[2].hashoffset; 69 | ctx->level[1].datasize = align64(getle64(ctx->romfsheader.level2.hashdatasize), ctx->level[1].hashblocksize); 70 | 71 | ctx->level[0].dataoffset = ctx->level[1].hashoffset; 72 | ctx->level[0].datasize = align64(getle64(ctx->romfsheader.level1.hashdatasize), ctx->level[0].hashblocksize); 73 | } 74 | 75 | if (actions & VerifyFlag) 76 | ivfc_verify(ctx, actions); 77 | 78 | if (actions & InfoFlag) 79 | ivfc_print(ctx); 80 | 81 | } 82 | 83 | void ivfc_verify(ivfc_context* ctx, u32 flags) 84 | { 85 | u32 i, j; 86 | u32 blockcount; 87 | 88 | for(i=0; ilevelcount; i++) 89 | { 90 | ivfc_level* level = ctx->level + i; 91 | 92 | level->hashcheck = Fail; 93 | } 94 | 95 | for(i=0; ilevelcount; i++) 96 | { 97 | ivfc_level* level = ctx->level + i; 98 | 99 | blockcount = level->datasize / level->hashblocksize; 100 | if (blockcount * level->hashblocksize != level->datasize) 101 | { 102 | fprintf(stderr, "Error, IVFC block size mismatch\n"); 103 | return; 104 | } 105 | 106 | level->hashcheck = Good; 107 | 108 | for(j=0; jdataoffset + level->hashblocksize * j, level->hashblocksize, calchash); 115 | ivfc_read(ctx, level->hashoffset + 0x20 * j, 0x20, testhash); 116 | 117 | if (memcmp(calchash, testhash, 0x20) != 0) 118 | level->hashcheck = Fail; 119 | } 120 | } 121 | } 122 | 123 | void ivfc_read(ivfc_context* ctx, u32 offset, u32 size, u8* buffer) 124 | { 125 | if ( (offset > ctx->size) || (offset+size > ctx->size) ) 126 | { 127 | fprintf(stderr, "Error, IVFC offset out of range (offset=0x%08x, size=0x%08x)\n", offset, size); 128 | return; 129 | } 130 | 131 | fseek(ctx->file, ctx->offset + offset, SEEK_SET); 132 | if (size != fread(buffer, 1, size, ctx->file)) 133 | { 134 | fprintf(stderr, "Error, IVFC could not read file\n"); 135 | return; 136 | } 137 | } 138 | 139 | void ivfc_hash(ivfc_context* ctx, u32 offset, u32 size, u8* hash) 140 | { 141 | if (size > IVFC_MAX_BUFFERSIZE) 142 | { 143 | fprintf(stderr, "Error, IVFC hash block size too big.\n"); 144 | return; 145 | } 146 | 147 | ivfc_read(ctx, offset, size, ctx->buffer); 148 | 149 | ctr_sha_256(ctx->buffer, size, hash); 150 | } 151 | 152 | void ivfc_print(ivfc_context* ctx) 153 | { 154 | u32 i; 155 | ivfc_header* header = &ctx->header; 156 | 157 | fprintf(stdout, "\nIVFC:\n"); 158 | 159 | fprintf(stdout, "Header: %c%c%c%c\n", header->magic[0], header->magic[1], header->magic[2], header->magic[3]); 160 | fprintf(stdout, "Id: %08x\n", getle32(header->id)); 161 | 162 | for(i=0; ilevelcount; i++) 163 | { 164 | ivfc_level* level = ctx->level + i; 165 | 166 | fprintf(stdout, "\n"); 167 | if (level->hashcheck == Unchecked) 168 | fprintf(stdout, "Level %d: \n", i); 169 | else 170 | fprintf(stdout, "Level %d (%s): \n", i, level->hashcheck == Good? "GOOD" : "FAIL"); 171 | fprintf(stdout, " Data offset: 0x%016llx\n", ctx->offset + level->dataoffset); 172 | fprintf(stdout, " Data size: 0x%016llx\n", level->datasize); 173 | fprintf(stdout, " Hash offset: 0x%016llx\n", ctx->offset + level->hashoffset); 174 | fprintf(stdout, " Hash block size: 0x%08x\n", level->hashblocksize); 175 | } 176 | } 177 | 178 | u64 ivfc_get_body_offset(ivfc_context* ctx) 179 | { 180 | return ctx->bodyoffset; 181 | } 182 | 183 | u64 ivfc_get_body_size(ivfc_context* ctx) 184 | { 185 | return ctx->bodysize; 186 | } 187 | 188 | -------------------------------------------------------------------------------- /ctrtool/settings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "settings.h" 4 | 5 | void settings_init(settings* usersettings) 6 | { 7 | memset(usersettings, 0, sizeof(settings)); 8 | } 9 | 10 | filepath* settings_get_wav_path(settings* usersettings) 11 | { 12 | if (usersettings) 13 | return &usersettings->wavpath; 14 | else 15 | return 0; 16 | } 17 | 18 | filepath* settings_get_lzss_path(settings* usersettings) 19 | { 20 | if (usersettings) 21 | return &usersettings->lzsspath; 22 | else 23 | return 0; 24 | } 25 | 26 | filepath* settings_get_exefs_path(settings* usersettings) 27 | { 28 | if (usersettings) 29 | return &usersettings->exefspath; 30 | else 31 | return 0; 32 | } 33 | 34 | filepath* settings_get_romfs_path(settings* usersettings) 35 | { 36 | if (usersettings) 37 | return &usersettings->romfspath; 38 | else 39 | return 0; 40 | } 41 | 42 | filepath* settings_get_exheader_path(settings* usersettings) 43 | { 44 | if (usersettings) 45 | return &usersettings->exheaderpath; 46 | else 47 | return 0; 48 | } 49 | 50 | filepath* settings_get_exefs_dir_path(settings* usersettings) 51 | { 52 | if (usersettings) 53 | return &usersettings->exefsdirpath; 54 | else 55 | return 0; 56 | } 57 | 58 | filepath* settings_get_romfs_dir_path(settings* usersettings) 59 | { 60 | if (usersettings) 61 | return &usersettings->romfsdirpath; 62 | else 63 | return 0; 64 | } 65 | 66 | filepath* settings_get_firm_dir_path(settings* usersettings) 67 | { 68 | if (usersettings) 69 | return &usersettings->firmdirpath; 70 | else 71 | return 0; 72 | } 73 | 74 | 75 | filepath* settings_get_certs_path(settings* usersettings) 76 | { 77 | if (usersettings) 78 | return &usersettings->certspath; 79 | else 80 | return 0; 81 | } 82 | 83 | filepath* settings_get_tik_path(settings* usersettings) 84 | { 85 | if (usersettings) 86 | return &usersettings->tikpath; 87 | else 88 | return 0; 89 | } 90 | 91 | filepath* settings_get_tmd_path(settings* usersettings) 92 | { 93 | if (usersettings) 94 | return &usersettings->tmdpath; 95 | else 96 | return 0; 97 | } 98 | 99 | filepath* settings_get_meta_path(settings* usersettings) 100 | { 101 | if (usersettings) 102 | return &usersettings->metapath; 103 | else 104 | return 0; 105 | } 106 | 107 | filepath* settings_get_content_path(settings* usersettings) 108 | { 109 | if (usersettings) 110 | return &usersettings->contentpath; 111 | else 112 | return 0; 113 | } 114 | 115 | unsigned int settings_get_mediaunit_size(settings* usersettings) 116 | { 117 | if (usersettings) 118 | return usersettings->mediaunitsize; 119 | else 120 | return 0; 121 | } 122 | 123 | unsigned char* settings_get_ncch_key(settings* usersettings) 124 | { 125 | if (usersettings && usersettings->keys.ncchkey.valid) 126 | return usersettings->keys.ncchkey.data; 127 | else 128 | return 0; 129 | } 130 | 131 | unsigned char* settings_get_ncch_fixedsystemkey(settings* usersettings) 132 | { 133 | if (usersettings && usersettings->keys.ncchfixedsystemkey.valid) 134 | return usersettings->keys.ncchfixedsystemkey.data; 135 | else 136 | return 0; 137 | } 138 | 139 | unsigned char* settings_get_common_key(settings* usersettings) 140 | { 141 | if (usersettings && usersettings->keys.commonkey.valid) 142 | return usersettings->keys.commonkey.data; 143 | else 144 | return 0; 145 | } 146 | 147 | 148 | int settings_get_ignore_programid(settings* usersettings) 149 | { 150 | if (usersettings) 151 | return usersettings->ignoreprogramid; 152 | else 153 | return 0; 154 | } 155 | 156 | int settings_get_list_romfs_files(settings* usersettings) 157 | { 158 | if (usersettings) 159 | return usersettings->listromfs; 160 | else 161 | return 0; 162 | } 163 | 164 | int settings_get_cwav_loopcount(settings* usersettings) 165 | { 166 | if (usersettings) 167 | return usersettings->cwavloopcount; 168 | else 169 | return 0; 170 | } 171 | 172 | void settings_set_wav_path(settings* usersettings, const char* path) 173 | { 174 | filepath_set(&usersettings->wavpath, path); 175 | } 176 | 177 | void settings_set_lzss_path(settings* usersettings, const char* path) 178 | { 179 | filepath_set(&usersettings->lzsspath, path); 180 | } 181 | 182 | void settings_set_exefs_path(settings* usersettings, const char* path) 183 | { 184 | filepath_set(&usersettings->exefspath, path); 185 | } 186 | 187 | void settings_set_romfs_path(settings* usersettings, const char* path) 188 | { 189 | filepath_set(&usersettings->romfspath, path); 190 | } 191 | 192 | void settings_set_firm_dir_path(settings* usersettings, const char* path) 193 | { 194 | filepath_set(&usersettings->firmdirpath, path); 195 | } 196 | 197 | 198 | void settings_set_exheader_path(settings* usersettings, const char* path) 199 | { 200 | filepath_set(&usersettings->exheaderpath, path); 201 | } 202 | 203 | void settings_set_certs_path(settings* usersettings, const char* path) 204 | { 205 | filepath_set(&usersettings->certspath, path); 206 | } 207 | 208 | void settings_set_tik_path(settings* usersettings, const char* path) 209 | { 210 | filepath_set(&usersettings->tikpath, path); 211 | } 212 | 213 | void settings_set_tmd_path(settings* usersettings, const char* path) 214 | { 215 | filepath_set(&usersettings->tmdpath, path); 216 | } 217 | 218 | void settings_set_meta_path(settings* usersettings, const char* path) 219 | { 220 | filepath_set(&usersettings->metapath, path); 221 | } 222 | 223 | void settings_set_content_path(settings* usersettings, const char* path) 224 | { 225 | filepath_set(&usersettings->contentpath, path); 226 | } 227 | 228 | void settings_set_exefs_dir_path(settings* usersettings, const char* path) 229 | { 230 | filepath_set(&usersettings->exefsdirpath, path); 231 | } 232 | 233 | void settings_set_romfs_dir_path(settings* usersettings, const char* path) 234 | { 235 | filepath_set(&usersettings->romfsdirpath, path); 236 | } 237 | 238 | void settings_set_mediaunit_size(settings* usersettings, unsigned int size) 239 | { 240 | usersettings->mediaunitsize = size; 241 | } 242 | 243 | void settings_set_ignore_programid(settings* usersettings, int enable) 244 | { 245 | usersettings->ignoreprogramid = enable; 246 | } 247 | 248 | void settings_set_list_romfs_files(settings* usersettings, int enable) 249 | { 250 | usersettings->listromfs = enable; 251 | } 252 | 253 | void settings_set_cwav_loopcount(settings* usersettings, u32 loopcount) 254 | { 255 | usersettings->cwavloopcount = loopcount; 256 | } 257 | -------------------------------------------------------------------------------- /ctrtool/firm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "types.h" 6 | #include "firm.h" 7 | #include "utils.h" 8 | 9 | void firm_init(firm_context* ctx) 10 | { 11 | memset(ctx, 0, sizeof(firm_context)); 12 | } 13 | 14 | void firm_set_file(firm_context* ctx, FILE* file) 15 | { 16 | ctx->file = file; 17 | } 18 | 19 | void firm_set_offset(firm_context* ctx, u32 offset) 20 | { 21 | ctx->offset = offset; 22 | } 23 | 24 | void firm_set_size(firm_context* ctx, u32 size) 25 | { 26 | ctx->size = size; 27 | } 28 | 29 | void firm_set_usersettings(firm_context* ctx, settings* usersettings) 30 | { 31 | ctx->usersettings = usersettings; 32 | } 33 | 34 | void firm_save(firm_context* ctx, u32 index, u32 flags) 35 | { 36 | firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + index); 37 | u32 offset; 38 | u32 size; 39 | u32 address; 40 | FILE* fout; 41 | filepath outpath; 42 | u8 buffer[16 * 1024]; 43 | 44 | 45 | offset = getle32(section->offset); 46 | size = getle32(section->size); 47 | address = getle32(section->address); 48 | filepath_copy(&outpath, settings_get_firm_dir_path(ctx->usersettings)); 49 | filepath_append(&outpath, "firm_%d_%08X.bin", index, address); 50 | 51 | if (size == 0 || outpath.valid == 0) 52 | return; 53 | 54 | if (size >= ctx->size) 55 | { 56 | fprintf(stderr, "Error, firm section %d size invalid\n", index); 57 | return; 58 | } 59 | 60 | fout = fopen(outpath.pathname, "wb"); 61 | if (fout == 0) 62 | { 63 | fprintf(stderr, "Error, failed to create file %s\n", outpath.pathname); 64 | goto clean; 65 | } 66 | 67 | 68 | 69 | fseek(ctx->file, ctx->offset + offset, SEEK_SET); 70 | fprintf(stdout, "Saving section %d to %s...\n", index, outpath.pathname); 71 | 72 | while(size) 73 | { 74 | u32 max = sizeof(buffer); 75 | if (max > size) 76 | max = size; 77 | 78 | if (max != fread(buffer, 1, max, ctx->file)) 79 | { 80 | fprintf(stdout, "Error reading input file\n"); 81 | goto clean; 82 | } 83 | 84 | if (max != fwrite(buffer, 1, max, fout)) 85 | { 86 | fprintf(stdout, "Error writing output file\n"); 87 | goto clean; 88 | } 89 | 90 | size -= max; 91 | } 92 | 93 | 94 | clean: 95 | return; 96 | } 97 | 98 | 99 | void firm_process(firm_context* ctx, u32 actions) 100 | { 101 | u32 i; 102 | 103 | fseek(ctx->file, ctx->offset, SEEK_SET); 104 | fread(&ctx->header, 1, sizeof(firm_header), ctx->file); 105 | 106 | if (getle32(ctx->header.magic) != MAGIC_FIRM) 107 | { 108 | fprintf(stdout, "Error, FIRM segment corrupted\n"); 109 | return; 110 | } 111 | 112 | 113 | if (actions & VerifyFlag) 114 | { 115 | firm_verify(ctx, actions); 116 | firm_signature_verify(ctx); 117 | } 118 | 119 | if (actions & InfoFlag) 120 | { 121 | firm_print(ctx); 122 | } 123 | 124 | if (actions & ExtractFlag) 125 | { 126 | filepath* dirpath = settings_get_firm_dir_path(ctx->usersettings); 127 | 128 | if (dirpath && dirpath->valid) 129 | { 130 | makedir(dirpath->pathname); 131 | for(i=0; i<4; i++) 132 | firm_save(ctx, i, actions); 133 | } 134 | } 135 | } 136 | 137 | int firm_verify(firm_context* ctx, u32 flags) 138 | { 139 | unsigned int i; 140 | u32 offset; 141 | u32 size; 142 | u8 buffer[16 * 1024]; 143 | u8 hash[0x20]; 144 | 145 | 146 | for(i=0; i<4; i++) 147 | { 148 | firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i); 149 | 150 | 151 | offset = getle32(section->offset); 152 | size = getle32(section->size); 153 | 154 | if (size == 0) 155 | return 0; 156 | 157 | fseek(ctx->file, ctx->offset + offset, SEEK_SET); 158 | 159 | ctr_sha_256_init(&ctx->sha); 160 | 161 | while(size) 162 | { 163 | u32 max = sizeof(buffer); 164 | if (max > size) 165 | max = size; 166 | 167 | if (max != fread(buffer, 1, max, ctx->file)) 168 | { 169 | fprintf(stdout, "Error reading input file\n"); 170 | goto clean; 171 | } 172 | 173 | ctr_sha_256_update(&ctx->sha, buffer, max); 174 | 175 | size -= max; 176 | } 177 | 178 | ctr_sha_256_finish(&ctx->sha, hash); 179 | 180 | 181 | if (memcmp(hash, section->hash, 0x20) == 0) 182 | ctx->hashcheck[i] = Good; 183 | else 184 | ctx->hashcheck[i] = Fail; 185 | } 186 | 187 | 188 | clean: 189 | return 0; 190 | } 191 | 192 | 193 | void firm_signature_verify(firm_context* ctx) 194 | { 195 | u8 hash[0x20]; 196 | 197 | if (ctx->usersettings) 198 | { 199 | ctr_sha_256(ctx->header.magic, 0x100, hash); 200 | ctx->headersigcheck = ctr_rsa_verify_hash(ctx->header.signature, hash, &ctx->usersettings->keys.firmrsakey); 201 | } 202 | } 203 | 204 | 205 | void firm_print(firm_context* ctx) 206 | { 207 | u32 i; 208 | u32 address; 209 | u32 type; 210 | u32 offset; 211 | u32 size; 212 | u32 entrypointarm11 = getle32(ctx->header.entrypointarm11); 213 | u32 entrypointarm9 = getle32(ctx->header.entrypointarm9); 214 | 215 | fprintf(stdout, "\nFIRM:\n"); 216 | if (ctx->headersigcheck == Unchecked) 217 | memdump(stdout, "Signature: ", ctx->header.signature, 0x100); 218 | else if (ctx->headersigcheck == Good) 219 | memdump(stdout, "Signature (GOOD): ", ctx->header.signature, 0x100); 220 | else 221 | memdump(stdout, "Signature (FAIL): ", ctx->header.signature, 0x100); 222 | 223 | fprintf(stdout, "\n"); 224 | fprintf(stdout, "Entrypoint ARM9: 0x%08X\n", entrypointarm9); 225 | fprintf(stdout, "Entrypoint ARM11: 0x%08X\n", entrypointarm11); 226 | fprintf(stdout, "\n"); 227 | 228 | 229 | for(i=0; i<4; i++) 230 | { 231 | firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i); 232 | 233 | 234 | offset = getle32(section->offset); 235 | size = getle32(section->size); 236 | address = getle32(section->address); 237 | type = getle32(section->type); 238 | 239 | if (size) 240 | { 241 | fprintf(stdout, "Section %d \n", i); 242 | fprintf(stdout, " Type: %s\n", type==0? "ARM9" : type==1? "ARM11" : "UNKNOWN"); 243 | fprintf(stdout, " Address: 0x%08X\n", address); 244 | fprintf(stdout, " Offset: 0x%08X\n", offset); 245 | fprintf(stdout, " Size: 0x%08X\n", size); 246 | if (ctx->hashcheck[i] == Good) 247 | memdump(stdout, " Hash (GOOD): ", section->hash, 0x20); 248 | else if (ctx->hashcheck[i] == Fail) 249 | memdump(stdout, " Hash (FAIL): ", section->hash, 0x20); 250 | else 251 | memdump(stdout, " Hash: ", section->hash, 0x20); 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /ctrtool/windows/getopt.h: -------------------------------------------------------------------------------- 1 | /* Declarations for getopt. 2 | Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. 3 | This file is part of the GNU C Library. 4 | 5 | The GNU C Library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Library General Public License as 7 | published by the Free Software Foundation; either version 2 of the 8 | License, or (at your option) any later version. 9 | 10 | The GNU C Library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Library General Public License for more details. 14 | 15 | You should have received a copy of the GNU Library General Public 16 | License along with the GNU C Library; see the file COPYING.LIB. If not, 17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 | Boston, MA 02111-1307, USA. */ 19 | 20 | #ifndef _GETOPT_H 21 | 22 | #ifndef __need_getopt 23 | # define _GETOPT_H 1 24 | #endif 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | /* For communication from `getopt' to the caller. 32 | When `getopt' finds an option that takes an argument, 33 | the argument value is returned here. 34 | Also, when `ordering' is RETURN_IN_ORDER, 35 | each non-option ARGV-element is returned here. */ 36 | 37 | extern char *optarg; 38 | 39 | /* Index in ARGV of the next element to be scanned. 40 | This is used for communication to and from the caller 41 | and for communication between successive calls to `getopt'. 42 | 43 | On entry to `getopt', zero means this is the first call; initialize. 44 | 45 | When `getopt' returns -1, this is the index of the first of the 46 | non-option elements that the caller should itself scan. 47 | 48 | Otherwise, `optind' communicates from one call to the next 49 | how much of ARGV has been scanned so far. */ 50 | 51 | extern int optind; 52 | 53 | /* Callers store zero here to inhibit the error message `getopt' prints 54 | for unrecognized options. */ 55 | 56 | extern int opterr; 57 | 58 | /* Set to an option character which was unrecognized. */ 59 | 60 | extern int optopt; 61 | 62 | #ifndef __need_getopt 63 | /* Describe the long-named options requested by the application. 64 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 65 | of `struct option' terminated by an element containing a name which is 66 | zero. 67 | 68 | The field `has_arg' is: 69 | no_argument (or 0) if the option does not take an argument, 70 | required_argument (or 1) if the option requires an argument, 71 | optional_argument (or 2) if the option takes an optional argument. 72 | 73 | If the field `flag' is not NULL, it points to a variable that is set 74 | to the value given in the field `val' when the option is found, but 75 | left unchanged if the option is not found. 76 | 77 | To have a long-named option do something other than set an `int' to 78 | a compiled-in constant, such as set a value from `optarg', set the 79 | option's `flag' field to zero and its `val' field to a nonzero 80 | value (the equivalent single-letter option character, if there is 81 | one). For long options that have a zero `flag' field, `getopt' 82 | returns the contents of the `val' field. */ 83 | 84 | struct option { 85 | # if defined __STDC__ && __STDC__ 86 | const char *name; 87 | # else 88 | 89 | char *name; 90 | # endif 91 | /* has_arg can't be an enum because some compilers complain about 92 | type mismatches in all the code that assumes it is an int. */ 93 | int has_arg; 94 | int *flag; 95 | int val; 96 | }; 97 | 98 | /* Names for the values of the `has_arg' field of `struct option'. */ 99 | 100 | # define no_argument 0 101 | # define required_argument 1 102 | # define optional_argument 2 103 | #endif /* need getopt */ 104 | 105 | 106 | /* Get definitions and prototypes for functions to process the 107 | arguments in ARGV (ARGC of them, minus the program name) for 108 | options given in OPTS. 109 | 110 | Return the option character from OPTS just read. Return -1 when 111 | there are no more options. For unrecognized options, or options 112 | missing arguments, `optopt' is set to the option letter, and '?' is 113 | returned. 114 | 115 | The OPTS string is a list of characters which are recognized option 116 | letters, optionally followed by colons, specifying that that letter 117 | takes an argument, to be placed in `optarg'. 118 | 119 | If a letter in OPTS is followed by two colons, its argument is 120 | optional. This behavior is specific to the GNU `getopt'. 121 | 122 | The argument `--' causes premature termination of argument 123 | scanning, explicitly telling `getopt' that there are no more 124 | options. 125 | 126 | If OPTS begins with `--', then non-option arguments are treated as 127 | arguments to the option '\0'. This behavior is specific to the GNU 128 | `getopt'. */ 129 | 130 | #if defined __STDC__ && __STDC__ 131 | # ifdef __GNU_LIBRARY__ 132 | /* Many other libraries have conflicting prototypes for getopt, with 133 | differences in the consts, in stdlib.h. To avoid compilation 134 | errors, only prototype getopt for the GNU C library. */ 135 | extern int getopt (int __argc, char *const *__argv, const char *__shortopts); 136 | # else /* not __GNU_LIBRARY__ */ 137 | extern int getopt (); 138 | # endif /* __GNU_LIBRARY__ */ 139 | 140 | # ifndef __need_getopt 141 | 142 | extern int getopt_long (int argc, char ** argv, const char * shortopts, 143 | const struct option * longopts, int * longind); 144 | 145 | extern int getopt_long_only (int __argc, char *const *__argv, 146 | const char *__shortopts, 147 | const struct option *__longopts, int *__longind); 148 | 149 | /* Internal only. Users should not call this directly. */ 150 | extern int _getopt_internal (int __argc, char *const *__argv, 151 | const char *__shortopts, 152 | const struct option *__longopts, int *__longind, 153 | int __long_only); 154 | # endif 155 | #else /* not __STDC__ */ 156 | extern int getopt (); 157 | # ifndef __need_getopt 158 | extern int getopt_long (); 159 | extern int getopt_long_only (); 160 | 161 | extern int _getopt_internal (); 162 | # endif 163 | #endif /* __STDC__ */ 164 | 165 | #ifdef __cplusplus 166 | } 167 | #endif 168 | 169 | /* Make sure we later can get all the definitions and declarations. */ 170 | #undef __need_getopt 171 | 172 | #endif /* getopt.h */ 173 | -------------------------------------------------------------------------------- /ctrtool/keyset.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "keyset.h" 3 | #include "utils.h" 4 | #include "tinyxml/tinyxml.h" 5 | 6 | static void keyset_set_key128(key128* key, unsigned char* keydata); 7 | static void keyset_parse_key128(key128* key, char* keytext, int keylen); 8 | static int keyset_parse_key(const char* text, unsigned int textlen, unsigned char* key, unsigned int size, int* valid); 9 | static int keyset_load_rsakey2048(TiXmlElement* elem, rsakey2048* key); 10 | static int keyset_load_key128(TiXmlHandle node, key128* key); 11 | static int keyset_load_key(TiXmlHandle node, unsigned char* key, unsigned int maxsize, int* valid); 12 | 13 | static int ishex(char c) 14 | { 15 | if (c >= '0' && c <= '9') 16 | return 1; 17 | if (c >= 'A' && c <= 'F') 18 | return 1; 19 | if (c >= 'a' && c <= 'f') 20 | return 1; 21 | return 0; 22 | 23 | } 24 | 25 | static unsigned char hextobin(char c) 26 | { 27 | if (c >= '0' && c <= '9') 28 | return c-'0'; 29 | if (c >= 'A' && c <= 'F') 30 | return c-'A'+0xA; 31 | if (c >= 'a' && c <= 'f') 32 | return c-'a'+0xA; 33 | return 0; 34 | } 35 | 36 | void keyset_init(keyset* keys) 37 | { 38 | memset(keys, 0, sizeof(keyset)); 39 | } 40 | 41 | int keyset_load_key(TiXmlHandle node, unsigned char* key, unsigned int size, int* valid) 42 | { 43 | TiXmlElement* elem = node.ToElement(); 44 | 45 | if (valid) 46 | *valid = 0; 47 | 48 | if (!elem) 49 | return 0; 50 | 51 | const char* text = elem->GetText(); 52 | unsigned int textlen = strlen(text); 53 | 54 | int status = keyset_parse_key(text, textlen, key, size, valid); 55 | 56 | if (status == KEY_ERR_LEN_MISMATCH) 57 | { 58 | fprintf(stderr, "Error size mismatch for key \"%s/%s\"\n", elem->Parent()->Value(), elem->Value()); 59 | return 0; 60 | } 61 | 62 | return 1; 63 | } 64 | 65 | 66 | int keyset_parse_key(const char* text, unsigned int textlen, unsigned char* key, unsigned int size, int* valid) 67 | { 68 | unsigned int i, j; 69 | unsigned int hexcount = 0; 70 | 71 | 72 | if (valid) 73 | *valid = 0; 74 | 75 | for(i=0; idata, sizeof(key->data), &key->valid); 112 | } 113 | 114 | int keyset_load_rsakey2048(TiXmlHandle node, rsakey2048* key) 115 | { 116 | key->keytype = RSAKEY_INVALID; 117 | 118 | if (!keyset_load_key(node.FirstChild("N"), key->n, sizeof(key->n), 0)) 119 | goto clean; 120 | if (!keyset_load_key(node.FirstChild("E"), key->e, sizeof(key->e), 0)) 121 | goto clean; 122 | key->keytype = RSAKEY_PUB; 123 | 124 | if (!keyset_load_key(node.FirstChild("D"), key->d, sizeof(key->d), 0)) 125 | goto clean; 126 | if (!keyset_load_key(node.FirstChild("P"), key->p, sizeof(key->p), 0)) 127 | goto clean; 128 | if (!keyset_load_key(node.FirstChild("Q"), key->q, sizeof(key->q), 0)) 129 | goto clean; 130 | if (!keyset_load_key(node.FirstChild("DP"), key->dp, sizeof(key->dp), 0)) 131 | goto clean; 132 | if (!keyset_load_key(node.FirstChild("DQ"), key->dq, sizeof(key->dq), 0)) 133 | goto clean; 134 | if (!keyset_load_key(node.FirstChild("QP"), key->qp, sizeof(key->qp), 0)) 135 | goto clean; 136 | 137 | key->keytype = RSAKEY_PRIV; 138 | clean: 139 | return (key->keytype != RSAKEY_INVALID); 140 | } 141 | 142 | int keyset_load(keyset* keys, const char* fname, int verbose) 143 | { 144 | TiXmlDocument doc(fname); 145 | bool loadOkay = doc.LoadFile(); 146 | 147 | if (!loadOkay) 148 | { 149 | if (verbose) 150 | fprintf(stderr, "Could not load keyset file \"%s\", error: %s.\n", fname, doc.ErrorDesc() ); 151 | 152 | return 0; 153 | } 154 | 155 | TiXmlHandle root = doc.FirstChild("document"); 156 | 157 | keyset_load_rsakey2048(root.FirstChild("ncsdrsakey"), &keys->ncsdrsakey); 158 | keyset_load_rsakey2048(root.FirstChild("ncchrsakey"), &keys->ncchrsakey); 159 | keyset_load_rsakey2048(root.FirstChild("ncchdescrsakey"), &keys->ncchdescrsakey); 160 | keyset_load_rsakey2048(root.FirstChild("firmrsakey"), &keys->firmrsakey); 161 | keyset_load_key128(root.FirstChild("commonkey"), &keys->commonkey); 162 | keyset_load_key128(root.FirstChild("ncchkey"), &keys->ncchkey); 163 | keyset_load_key128(root.FirstChild("ncchfixedsystemkey"), &keys->ncchfixedsystemkey); 164 | 165 | 166 | return 1; 167 | } 168 | 169 | 170 | void keyset_merge(keyset* keys, keyset* src) 171 | { 172 | if (src->ncchkey.valid) 173 | keyset_set_key128(&keys->ncchkey, src->ncchkey.data); 174 | if (src->ncchfixedsystemkey.valid) 175 | keyset_set_key128(&keys->ncchfixedsystemkey, src->ncchfixedsystemkey.data); 176 | if (src->commonkey.valid) 177 | keyset_set_key128(&keys->commonkey, src->commonkey.data); 178 | } 179 | 180 | void keyset_set_key128(key128* key, unsigned char* keydata) 181 | { 182 | memcpy(key->data, keydata, 16); 183 | key->valid = 1; 184 | } 185 | 186 | void keyset_parse_key128(key128* key, char* keytext, int keylen) 187 | { 188 | keyset_parse_key(keytext, keylen, key->data, 16, &key->valid); 189 | } 190 | 191 | void keyset_set_commonkey(keyset* keys, unsigned char* keydata) 192 | { 193 | keyset_set_key128(&keys->commonkey, keydata); 194 | } 195 | 196 | void keyset_parse_commonkey(keyset* keys, char* keytext, int keylen) 197 | { 198 | keyset_parse_key128(&keys->commonkey, keytext, keylen); 199 | } 200 | 201 | void keyset_set_ncchkey(keyset* keys, unsigned char* keydata) 202 | { 203 | keyset_set_key128(&keys->ncchkey, keydata); 204 | } 205 | 206 | void keyset_parse_ncchkey(keyset* keys, char* keytext, int keylen) 207 | { 208 | keyset_parse_key128(&keys->ncchkey, keytext, keylen); 209 | } 210 | 211 | void keyset_set_ncchfixedsystemkey(keyset* keys, unsigned char* keydata) 212 | { 213 | keyset_set_key128(&keys->ncchfixedsystemkey, keydata); 214 | } 215 | 216 | void keyset_parse_ncchfixedsystemkey(keyset* keys, char* keytext, int keylen) 217 | { 218 | keyset_parse_key128(&keys->ncchfixedsystemkey, keytext, keylen); 219 | } 220 | 221 | void keyset_dump_rsakey(rsakey2048* key, const char* keytitle) 222 | { 223 | if (key->keytype == RSAKEY_INVALID) 224 | return; 225 | 226 | 227 | fprintf(stdout, "%s\n", keytitle); 228 | 229 | memdump(stdout, "Modulus: ", key->n, 256); 230 | memdump(stdout, "Exponent: ", key->e, 3); 231 | 232 | if (key->keytype == RSAKEY_PRIV) 233 | { 234 | memdump(stdout, "P: ", key->p, 128); 235 | memdump(stdout, "Q: ", key->q, 128); 236 | } 237 | fprintf(stdout, "\n"); 238 | } 239 | 240 | void keyset_dump_key128(key128* key, const char* keytitle) 241 | { 242 | if (key->valid) 243 | { 244 | fprintf(stdout, "%s\n", keytitle); 245 | memdump(stdout, "", key->data, 16); 246 | fprintf(stdout, "\n"); 247 | } 248 | } 249 | 250 | void keyset_dump(keyset* keys) 251 | { 252 | fprintf(stdout, "Current keyset: \n"); 253 | keyset_dump_key128(&keys->ncchkey, "NCCH KEY"); 254 | keyset_dump_key128(&keys->ncchfixedsystemkey, "NCCH FIXEDSYSTEMKEY"); 255 | keyset_dump_key128(&keys->commonkey, "COMMON KEY"); 256 | 257 | keyset_dump_rsakey(&keys->ncsdrsakey, "NCSD RSA KEY"); 258 | keyset_dump_rsakey(&keys->ncchdescrsakey, "NCCH DESC RSA KEY"); 259 | 260 | fprintf(stdout, "\n"); 261 | } 262 | 263 | -------------------------------------------------------------------------------- /idaloader/ctr_ldr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # CTR FIRM/NCCH IDA Loader by blasty 4 | # ================================== 5 | # requires construct and idapython. 6 | 7 | import sys 8 | import struct 9 | from idaapi import Choose 10 | import construct 11 | from construct import * 12 | 13 | def u8(name, len = 1): 14 | if len == 1: 15 | return ULInt8(name) 16 | else: 17 | return Bytes(name, len) 18 | 19 | def u16(name): 20 | return ULInt16(name) 21 | 22 | def u32(name): 23 | return ULInt32(name) 24 | 25 | def u64(name): 26 | return ULInt64(name) 27 | 28 | class media_unit_adapter(Adapter): 29 | def _encode(self, obj, context): 30 | return struct.pack(" addr:%08x nump:%08x size:%08x" % (text.address, text.num_maxpages, text.code_size) 248 | add_segm(0, text.address, text.address + text.code_size, ".text", "CODE") 249 | offs = 0x200 250 | mem2base(exefs[offs:], text.address, text.address + text.code_size) 251 | 252 | ro = exhdr.codeset_info.ro 253 | print " |_ .ro -> addr:%08x nump:%08x size:%08x" % (ro.address, ro.num_maxpages, ro.code_size) 254 | add_segm(0, ro.address, ro.address + ro.code_size, ".ro", "DATA") 255 | offs = 0x200 + text.code_size 256 | mem2base(exefs[offs:], ro.address, ro.address + ro.code_size) 257 | 258 | data = exhdr.codeset_info.data 259 | print " |_ .data -> addr:%08x nump:%08x size:%08x" % (data.address, data.num_maxpages, data.code_size) 260 | add_segm(0, data.address, data.address + data.code_size, ".data", "DATA") 261 | offs = 0x200 + text.code_size + ro.code_size 262 | mem2base(exefs[offs:], data.address, data.address + data.code_size) 263 | 264 | return 1 265 | 266 | def load_file(f, neflags, format): 267 | idaapi.set_processor_type("ARM", SETPROC_ALL|SETPROC_FATAL) 268 | tp = get_type(f) 269 | 270 | if tp == "NCCH": 271 | return load_ncch_file(f, 0) 272 | elif tp == "FIRM": 273 | return load_firm_file(f, 0) 274 | 275 | return 0 276 | -------------------------------------------------------------------------------- /ctrtool/polarssl/config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file config.h 3 | * 4 | * Copyright (C) 2006-2010, Brainspark B.V. 5 | * 6 | * This file is part of PolarSSL (http://www.polarssl.org) 7 | * Lead Maintainer: Paul Bakker 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | * 25 | * This set of compile-time options may be used to enable 26 | * or disable features selectively, and reduce the global 27 | * memory footprint. 28 | */ 29 | #ifndef POLARSSL_CONFIG_H 30 | #define POLARSSL_CONFIG_H 31 | 32 | #ifndef _CRT_SECURE_NO_DEPRECATE 33 | #define _CRT_SECURE_NO_DEPRECATE 1 34 | #endif 35 | 36 | /* 37 | * Uncomment if native integers are 8-bit wide. 38 | * 39 | #define POLARSSL_HAVE_INT8 40 | */ 41 | 42 | /* 43 | * Uncomment if native integers are 16-bit wide. 44 | * 45 | #define POLARSSL_HAVE_INT16 46 | */ 47 | 48 | /* 49 | * Uncomment if the compiler supports long long. 50 | * 51 | #define POLARSSL_HAVE_LONGLONG 52 | */ 53 | 54 | /* 55 | * Uncomment to enable the use of assembly code. 56 | * 57 | * Requires support for asm() in compiler. 58 | * 59 | * Used in: 60 | * library/timing.c 61 | * library/padlock.c 62 | * include/polarssl/bn_mul.h 63 | * 64 | */ 65 | //#define POLARSSL_HAVE_ASM 66 | 67 | /* 68 | * Uncomment if the CPU supports SSE2 (IA-32 specific). 69 | * 70 | #define POLARSSL_HAVE_SSE2 71 | */ 72 | 73 | /* 74 | * Enable all SSL/TLS debugging messages. 75 | */ 76 | #define POLARSSL_DEBUG_MSG 77 | 78 | /* 79 | * Enable the checkup functions (*_self_test). 80 | */ 81 | //#define POLARSSL_SELF_TEST 82 | 83 | /* 84 | * Enable run-time version information functions 85 | */ 86 | #define POLARSSL_VERSION_C 87 | 88 | /* 89 | * Enable the prime-number generation code. 90 | */ 91 | #define POLARSSL_GENPRIME 92 | 93 | /* 94 | * Uncomment this macro to store the AES tables in ROM. 95 | * 96 | #define POLARSSL_AES_ROM_TABLES 97 | */ 98 | 99 | /* 100 | * Module: library/aes.c 101 | * Caller: library/ssl_tls.c 102 | * 103 | * This module enables the following ciphersuites: 104 | * SSL_RSA_AES_128_SHA 105 | * SSL_RSA_AES_256_SHA 106 | * SSL_EDH_RSA_AES_256_SHA 107 | */ 108 | #define POLARSSL_AES_C 109 | 110 | /* 111 | * Module: library/arc4.c 112 | * Caller: library/ssl_tls.c 113 | * 114 | * This module enables the following ciphersuites: 115 | * SSL_RSA_RC4_128_MD5 116 | * SSL_RSA_RC4_128_SHA 117 | */ 118 | #define POLARSSL_ARC4_C 119 | 120 | /* 121 | * Module: library/base64.c 122 | * Caller: library/x509parse.c 123 | * 124 | * This module is required for X.509 support. 125 | */ 126 | #define POLARSSL_BASE64_C 127 | 128 | /* 129 | * Module: library/bignum.c 130 | * Caller: library/dhm.c 131 | * library/rsa.c 132 | * library/ssl_tls.c 133 | * library/x509parse.c 134 | * 135 | * This module is required for RSA and DHM support. 136 | */ 137 | #define POLARSSL_BIGNUM_C 138 | 139 | /* 140 | * Module: library/camellia.c 141 | * Caller: library/ssl_tls.c 142 | * 143 | * This module enabled the following cipher suites: 144 | * SSL_RSA_CAMELLIA_128_SHA 145 | * SSL_RSA_CAMELLIA_256_SHA 146 | * SSL_EDH_RSA_CAMELLIA_256_SHA 147 | */ 148 | #define POLARSSL_CAMELLIA_C 149 | 150 | /* 151 | * Module: library/certs.c 152 | * Caller: 153 | * 154 | * This module is used for testing (ssl_client/server). 155 | */ 156 | #define POLARSSL_CERTS_C 157 | 158 | /* 159 | * Module: library/debug.c 160 | * Caller: library/ssl_cli.c 161 | * library/ssl_srv.c 162 | * library/ssl_tls.c 163 | * 164 | * This module provides debugging functions. 165 | */ 166 | #define POLARSSL_DEBUG_C 167 | 168 | /* 169 | * Module: library/des.c 170 | * Caller: library/ssl_tls.c 171 | * 172 | * This module enables the following ciphersuites: 173 | * SSL_RSA_DES_168_SHA 174 | * SSL_EDH_RSA_DES_168_SHA 175 | */ 176 | #define POLARSSL_DES_C 177 | 178 | /* 179 | * Module: library/dhm.c 180 | * Caller: library/ssl_cli.c 181 | * library/ssl_srv.c 182 | * 183 | * This module enables the following ciphersuites: 184 | * SSL_EDH_RSA_DES_168_SHA 185 | * SSL_EDH_RSA_AES_256_SHA 186 | * SSL_EDH_RSA_CAMELLIA_256_SHA 187 | */ 188 | #define POLARSSL_DHM_C 189 | 190 | /* 191 | * Module: library/havege.c 192 | * Caller: 193 | * 194 | * This module enables the HAVEGE random number generator. 195 | */ 196 | #define POLARSSL_HAVEGE_C 197 | 198 | /* 199 | * Module: library/md2.c 200 | * Caller: library/x509parse.c 201 | * 202 | * Uncomment to enable support for (rare) MD2-signed X.509 certs. 203 | * 204 | #define POLARSSL_MD2_C 205 | */ 206 | 207 | /* 208 | * Module: library/md4.c 209 | * Caller: library/x509parse.c 210 | * 211 | * Uncomment to enable support for (rare) MD4-signed X.509 certs. 212 | * 213 | #define POLARSSL_MD4_C 214 | */ 215 | 216 | /* 217 | * Module: library/md5.c 218 | * Caller: library/ssl_tls.c 219 | * library/x509parse.c 220 | * 221 | * This module is required for SSL/TLS and X.509. 222 | */ 223 | #define POLARSSL_MD5_C 224 | 225 | /* 226 | * Module: library/net.c 227 | * Caller: 228 | * 229 | * This module provides TCP/IP networking routines. 230 | */ 231 | #define POLARSSL_NET_C 232 | 233 | /* 234 | * Module: library/padlock.c 235 | * Caller: library/aes.c 236 | * 237 | * This modules adds support for the VIA PadLock on x86. 238 | */ 239 | #define POLARSSL_PADLOCK_C 240 | 241 | /* 242 | * Module: library/rsa.c 243 | * Caller: library/ssl_cli.c 244 | * library/ssl_srv.c 245 | * library/ssl_tls.c 246 | * library/x509.c 247 | * 248 | * This module is required for SSL/TLS and MD5-signed certificates. 249 | */ 250 | #define POLARSSL_RSA_C 251 | 252 | /* 253 | * Module: library/sha1.c 254 | * Caller: library/ssl_cli.c 255 | * library/ssl_srv.c 256 | * library/ssl_tls.c 257 | * library/x509parse.c 258 | * 259 | * This module is required for SSL/TLS and SHA1-signed certificates. 260 | */ 261 | #define POLARSSL_SHA1_C 262 | 263 | /* 264 | * Module: library/sha2.c 265 | * Caller: 266 | * 267 | * This module adds support for SHA-224 and SHA-256. 268 | */ 269 | #define POLARSSL_SHA2_C 270 | 271 | /* 272 | * Module: library/sha4.c 273 | * Caller: 274 | * 275 | * This module adds support for SHA-384 and SHA-512. 276 | */ 277 | #define POLARSSL_SHA4_C 278 | 279 | /* 280 | * Module: library/ssl_cli.c 281 | * Caller: 282 | * 283 | * This module is required for SSL/TLS client support. 284 | */ 285 | #define POLARSSL_SSL_CLI_C 286 | 287 | /* 288 | * Module: library/ssl_srv.c 289 | * Caller: 290 | * 291 | * This module is required for SSL/TLS server support. 292 | */ 293 | #define POLARSSL_SSL_SRV_C 294 | 295 | /* 296 | * Module: library/ssl_tls.c 297 | * Caller: library/ssl_cli.c 298 | * library/ssl_srv.c 299 | * 300 | * This module is required for SSL/TLS. 301 | */ 302 | #define POLARSSL_SSL_TLS_C 303 | 304 | /* 305 | * Module: library/timing.c 306 | * Caller: library/havege.c 307 | * 308 | * This module is used by the HAVEGE random number generator. 309 | */ 310 | #define POLARSSL_TIMING_C 311 | 312 | /* 313 | * Module: library/x509parse.c 314 | * Caller: library/ssl_cli.c 315 | * library/ssl_srv.c 316 | * library/ssl_tls.c 317 | * 318 | * This module is required for X.509 certificate parsing. 319 | */ 320 | #define POLARSSL_X509_PARSE_C 321 | 322 | /* 323 | * Module: library/x509_write.c 324 | * Caller: 325 | * 326 | * This module is required for X.509 certificate writing. 327 | */ 328 | #define POLARSSL_X509_WRITE_C 329 | 330 | /* 331 | * Module: library/xtea.c 332 | * Caller: 333 | */ 334 | #define POLARSSL_XTEA_C 335 | 336 | #endif /* config.h */ 337 | -------------------------------------------------------------------------------- /ctrtool/ctr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "ctr.h" 7 | 8 | 9 | void ctr_set_iv( ctr_aes_context* ctx, 10 | u8 iv[16] ) 11 | { 12 | memcpy(ctx->iv, iv, 16); 13 | } 14 | 15 | void ctr_add_counter( ctr_aes_context* ctx, 16 | u32 carry ) 17 | { 18 | u32 counter[4]; 19 | u32 sum; 20 | int i; 21 | 22 | for(i=0; i<4; i++) 23 | counter[i] = (ctx->ctr[i*4+0]<<24) | (ctx->ctr[i*4+1]<<16) | (ctx->ctr[i*4+2]<<8) | (ctx->ctr[i*4+3]<<0); 24 | 25 | for(i=3; i>=0; i--) 26 | { 27 | sum = counter[i] + carry; 28 | 29 | if (sum < counter[i]) 30 | carry = 1; 31 | else 32 | carry = 0; 33 | 34 | counter[i] = sum; 35 | } 36 | 37 | for(i=0; i<4; i++) 38 | { 39 | ctx->ctr[i*4+0] = counter[i]>>24; 40 | ctx->ctr[i*4+1] = counter[i]>>16; 41 | ctx->ctr[i*4+2] = counter[i]>>8; 42 | ctx->ctr[i*4+3] = counter[i]>>0; 43 | } 44 | } 45 | 46 | void ctr_set_counter( ctr_aes_context* ctx, 47 | u8 ctr[16] ) 48 | { 49 | memcpy(ctx->ctr, ctr, 16); 50 | } 51 | 52 | 53 | void ctr_init_counter( ctr_aes_context* ctx, 54 | u8 key[16], 55 | u8 ctr[16] ) 56 | { 57 | aes_setkey_enc(&ctx->aes, key, 128); 58 | ctr_set_counter(ctx, ctr); 59 | } 60 | 61 | 62 | void ctr_crypt_counter_block( ctr_aes_context* ctx, 63 | u8 input[16], 64 | u8 output[16] ) 65 | { 66 | int i; 67 | u8 stream[16]; 68 | 69 | 70 | aes_crypt_ecb(&ctx->aes, AES_ENCRYPT, ctx->ctr, stream); 71 | 72 | 73 | if (input) 74 | { 75 | for(i=0; i<16; i++) 76 | { 77 | output[i] = stream[i] ^ input[i]; 78 | } 79 | } 80 | else 81 | { 82 | for(i=0; i<16; i++) 83 | output[i] = stream[i]; 84 | } 85 | 86 | ctr_add_counter(ctx, 1); 87 | } 88 | 89 | 90 | void ctr_crypt_counter( ctr_aes_context* ctx, 91 | u8* input, 92 | u8* output, 93 | u32 size ) 94 | { 95 | u8 stream[16]; 96 | u32 i; 97 | 98 | while(size >= 16) 99 | { 100 | ctr_crypt_counter_block(ctx, input, output); 101 | 102 | if (input) 103 | input += 16; 104 | if (output) 105 | output += 16; 106 | 107 | size -= 16; 108 | } 109 | 110 | if (size) 111 | { 112 | memset(stream, 0, 16); 113 | ctr_crypt_counter_block(ctx, stream, stream); 114 | 115 | if (input) 116 | { 117 | for(i=0; iaes, key, 128); 132 | ctr_set_iv(ctx, iv); 133 | } 134 | 135 | void ctr_init_cbc_decrypt( ctr_aes_context* ctx, 136 | u8 key[16], 137 | u8 iv[16] ) 138 | { 139 | aes_setkey_dec(&ctx->aes, key, 128); 140 | ctr_set_iv(ctx, iv); 141 | } 142 | 143 | void ctr_encrypt_cbc( ctr_aes_context* ctx, 144 | u8* input, 145 | u8* output, 146 | u32 size ) 147 | { 148 | aes_crypt_cbc(&ctx->aes, AES_ENCRYPT, size, ctx->iv, input, output); 149 | } 150 | 151 | void ctr_decrypt_cbc( ctr_aes_context* ctx, 152 | u8* input, 153 | u8* output, 154 | u32 size ) 155 | { 156 | aes_crypt_cbc(&ctx->aes, AES_DECRYPT, size, ctx->iv, input, output); 157 | } 158 | 159 | void ctr_sha_256( const u8* data, 160 | u32 size, 161 | u8 hash[0x20] ) 162 | { 163 | sha2(data, size, hash, 0); 164 | } 165 | 166 | int ctr_sha_256_verify( const u8* data, 167 | u32 size, 168 | const u8 checkhash[0x20] ) 169 | { 170 | u8 hash[0x20]; 171 | 172 | sha2(data, size, hash, 0); 173 | 174 | if (memcmp(hash, checkhash, 0x20) == 0) 175 | return Good; 176 | else 177 | return Fail; 178 | } 179 | 180 | void ctr_sha_256_init( ctr_sha256_context* ctx ) 181 | { 182 | sha2_starts(&ctx->sha, 0); 183 | } 184 | 185 | void ctr_sha_256_update( ctr_sha256_context* ctx, 186 | const u8* data, 187 | u32 size ) 188 | { 189 | sha2_update(&ctx->sha, data, size); 190 | } 191 | 192 | 193 | void ctr_sha_256_finish( ctr_sha256_context* ctx, 194 | u8 hash[0x20] ) 195 | { 196 | sha2_finish(&ctx->sha, hash); 197 | } 198 | 199 | 200 | void ctr_rsa_init_key_pubmodulus(rsakey2048* key, u8 modulus[0x100]) 201 | { 202 | u8 exponent[3] = {0x01, 0x00, 0x01}; 203 | 204 | ctr_rsa_init_key_pub(key, modulus, exponent); 205 | } 206 | 207 | void ctr_rsa_init_key_pub(rsakey2048* key, u8 modulus[0x100], u8 exponent[3]) 208 | { 209 | key->keytype = RSAKEY_PUB; 210 | memcpy(key->n, modulus, 0x100); 211 | memcpy(key->e, exponent, 3); 212 | } 213 | 214 | int ctr_rsa_init(ctr_rsa_context* ctx, rsakey2048* key) 215 | { 216 | rsa_init(&ctx->rsa, RSA_PKCS_V15, 0); 217 | ctx->rsa.len = 0x100; 218 | 219 | if (key->keytype == RSAKEY_INVALID) 220 | goto clean; 221 | 222 | if (mpi_read_binary(&ctx->rsa.N, key->n, sizeof(key->n))) 223 | goto clean; 224 | if (mpi_read_binary(&ctx->rsa.E, key->e, sizeof(key->e))) 225 | goto clean; 226 | if (rsa_check_pubkey(&ctx->rsa)) 227 | goto clean; 228 | 229 | if (key->keytype == RSAKEY_PRIV) 230 | { 231 | if (mpi_read_binary(&ctx->rsa.D, key->d, sizeof(key->d))) 232 | goto clean; 233 | if (mpi_read_binary(&ctx->rsa.P, key->p, sizeof(key->p))) 234 | goto clean; 235 | if (mpi_read_binary(&ctx->rsa.Q, key->q, sizeof(key->q))) 236 | goto clean; 237 | if (mpi_read_binary(&ctx->rsa.DP, key->dp, sizeof(key->dp))) 238 | goto clean; 239 | if (mpi_read_binary(&ctx->rsa.DQ, key->dq, sizeof(key->dq))) 240 | goto clean; 241 | if (mpi_read_binary(&ctx->rsa.QP, key->qp, sizeof(key->qp))) 242 | goto clean; 243 | if (rsa_check_privkey(&ctx->rsa)) 244 | goto clean; 245 | } 246 | 247 | return 1; 248 | clean: 249 | return 0; 250 | } 251 | 252 | int ctr_rsa_verify_hash(const u8 signature[0x100], const u8 hash[0x20], rsakey2048* key) 253 | { 254 | ctr_rsa_context ctx; 255 | u32 result; 256 | u8 output[0x100]; 257 | 258 | if (key->keytype == RSAKEY_INVALID) 259 | return Fail; 260 | 261 | ctr_rsa_init(&ctx, key); 262 | // memset(output, 0, 0x100); 263 | // result = ctr_rsa_public(signature, output, key); 264 | // printf("Result = %d\n", result); 265 | // memdump(stdout, "output: ", output, 0x100); 266 | 267 | result = rsa_pkcs1_verify(&ctx.rsa, RSA_PUBLIC, SIG_RSA_SHA256, 0x20, hash, (u8*)signature); 268 | 269 | ctr_rsa_free(&ctx); 270 | 271 | if (result == 0) 272 | return Good; 273 | else 274 | return Fail; 275 | } 276 | 277 | 278 | int ctr_rsa_sign_hash(const u8 hash[0x20], u8 signature[0x100], rsakey2048* key) 279 | { 280 | ctr_rsa_context ctx; 281 | u32 result; 282 | 283 | ctr_rsa_init(&ctx, key); 284 | 285 | result = rsa_pkcs1_verify(&ctx.rsa, RSA_PUBLIC, SIG_RSA_SHA256, 0x20, hash, (u8*)signature); 286 | result = rsa_pkcs1_sign(&ctx.rsa, RSA_PRIVATE, SIG_RSA_SHA256, 0x20, hash, signature); 287 | 288 | ctr_rsa_free(&ctx); 289 | 290 | if (result == 0) 291 | return 1; 292 | else 293 | return 0; 294 | } 295 | 296 | int ctr_rsa_public(const u8 signature[0x100], u8 output[0x100], rsakey2048* key) 297 | { 298 | ctr_rsa_context ctx; 299 | u32 result; 300 | 301 | ctr_rsa_init(&ctx, key); 302 | 303 | result = rsa_public(&ctx.rsa, signature, output); 304 | 305 | ctr_rsa_free(&ctx); 306 | 307 | if (result == 0) 308 | return 1; 309 | else 310 | return 0; 311 | } 312 | 313 | 314 | void ctr_rsa_free(ctr_rsa_context* ctx) 315 | { 316 | rsa_free(&ctx->rsa); 317 | } 318 | 319 | /* 320 | * Generate DP, DQ, QP based on private key 321 | */ 322 | #if 0 323 | static int ctr_rsa_key_init(ctr_rsa_context* ctx ) 324 | { 325 | int ret; 326 | mpi P1, Q1; 327 | 328 | mpi_init( &P1, &Q1, NULL ); 329 | 330 | MPI_CHK( mpi_sub_int( &P1, &ctx->rsa.P, 1 ) ); 331 | MPI_CHK( mpi_sub_int( &Q1, &ctx->rsa.Q, 1 ) ); 332 | 333 | /* 334 | * DP = D mod (P - 1) 335 | * DQ = D mod (Q - 1) 336 | * QP = Q^-1 mod P 337 | */ 338 | MPI_CHK( mpi_mod_mpi( &ctx->rsa.DP, &ctx->rsa.D, &P1 ) ); 339 | MPI_CHK( mpi_mod_mpi( &ctx->rsa.DQ, &ctx->rsa.D, &Q1 ) ); 340 | MPI_CHK( mpi_inv_mod( &ctx->rsa.QP, &ctx->rsa.Q, &ctx->rsa.P ) ); 341 | 342 | cleanup: 343 | 344 | mpi_free(&Q1, &P1, NULL ); 345 | 346 | if( ret != 0 ) 347 | { 348 | rsa_free( &ctx->rsa ); 349 | return( POLARSSL_ERR_RSA_KEY_GEN_FAILED | ret ); 350 | } 351 | 352 | return( 0 ); 353 | } 354 | #endif -------------------------------------------------------------------------------- /ctrtool/cia.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "types.h" 5 | #include "utils.h" 6 | #include "cia.h" 7 | 8 | 9 | void cia_init(cia_context* ctx) 10 | { 11 | memset(ctx, 0, sizeof(cia_context)); 12 | 13 | tik_init(&ctx->tik); 14 | tmd_init(&ctx->tmd); 15 | } 16 | 17 | void cia_set_file(cia_context* ctx, FILE* file) 18 | { 19 | ctx->file = file; 20 | } 21 | 22 | void cia_set_offset(cia_context* ctx, u32 offset) 23 | { 24 | ctx->offset = offset; 25 | } 26 | 27 | void cia_set_size(cia_context* ctx, u32 size) 28 | { 29 | ctx->size = size; 30 | } 31 | 32 | 33 | void cia_set_usersettings(cia_context* ctx, settings* usersettings) 34 | { 35 | ctx->usersettings = usersettings; 36 | } 37 | 38 | 39 | void cia_save(cia_context* ctx, u32 type, u32 flags) 40 | { 41 | u32 offset; 42 | u32 size; 43 | filepath* path = 0; 44 | ctr_tmd_body *body; 45 | ctr_tmd_contentchunk *chunk; 46 | int i; 47 | char tmpname[255]; 48 | 49 | switch(type) 50 | { 51 | case CIATYPE_CERTS: 52 | offset = ctx->offsetcerts; 53 | size = ctx->sizecert; 54 | path = settings_get_certs_path(ctx->usersettings); 55 | break; 56 | 57 | case CIATYPE_TIK: 58 | offset = ctx->offsettik; 59 | size = ctx->sizetik; 60 | path = settings_get_tik_path(ctx->usersettings); 61 | break; 62 | 63 | case CIATYPE_TMD: 64 | offset = ctx->offsettmd; 65 | size = ctx->sizetmd; 66 | path = settings_get_tmd_path(ctx->usersettings); 67 | break; 68 | 69 | case CIATYPE_CONTENT: 70 | offset = ctx->offsetcontent; 71 | size = ctx->sizecontent; 72 | path = settings_get_content_path(ctx->usersettings); 73 | 74 | break; 75 | 76 | case CIATYPE_META: 77 | offset = ctx->offsetmeta; 78 | size = ctx->sizemeta; 79 | path = settings_get_meta_path(ctx->usersettings);; 80 | break; 81 | 82 | default: 83 | fprintf(stderr, "Error, unknown CIA type specified\n"); 84 | return; 85 | break; 86 | } 87 | 88 | if (path == 0 || path->valid == 0) 89 | return; 90 | 91 | switch(type) 92 | { 93 | case CIATYPE_CERTS: fprintf(stdout, "Saving certs to %s\n", path->pathname); break; 94 | case CIATYPE_TIK: fprintf(stdout, "Saving tik to %s\n", path->pathname); break; 95 | case CIATYPE_TMD: fprintf(stdout, "Saving tmd to %s\n", path->pathname); break; 96 | case CIATYPE_CONTENT: 97 | 98 | body = tmd_get_body(&ctx->tmd); 99 | chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS)); 100 | 101 | for(i = 0; i < getbe16(body->contentcount); i++) { 102 | sprintf(tmpname, "%s.%04x.%08x", path->pathname, getbe16(chunk->index), getbe32(chunk->id)); 103 | fprintf(stdout, "Saving content #%04x to %s\n", getbe16(chunk->index), tmpname); 104 | 105 | ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff; 106 | ctx->iv[1] = getbe16(chunk->index) & 0xff; 107 | 108 | ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv); 109 | 110 | cia_save_blob(ctx, tmpname, offset, getbe64(chunk->size) & 0xffffffff, 1); 111 | 112 | offset += getbe64(chunk->size) & 0xffffffff; 113 | 114 | chunk++; 115 | } 116 | 117 | memset(ctx->iv, 0, 16); 118 | 119 | return; 120 | break; 121 | 122 | case CIATYPE_META: fprintf(stdout, "Saving meta to %s\n", path->pathname); break; 123 | } 124 | 125 | cia_save_blob(ctx, path->pathname, offset, size, 0); 126 | } 127 | 128 | void cia_save_blob(cia_context *ctx, char *out_path, u32 offset, u32 size, int do_cbc) 129 | { 130 | FILE *fout = 0; 131 | u8 buffer[16*1024]; 132 | 133 | fseek(ctx->file, ctx->offset + offset, SEEK_SET); 134 | 135 | 136 | fout = fopen(out_path, "wb"); 137 | if (fout == NULL) 138 | { 139 | fprintf(stdout, "Error opening out file %s\n", out_path); 140 | goto clean; 141 | } 142 | 143 | while(size) 144 | { 145 | u32 max = sizeof(buffer); 146 | if (max > size) 147 | max = size; 148 | 149 | if (max != fread(buffer, 1, max, ctx->file)) 150 | { 151 | fprintf(stdout, "Error reading file\n"); 152 | goto clean; 153 | } 154 | 155 | if (do_cbc == 1) 156 | ctr_decrypt_cbc(&ctx->aes, buffer, buffer, max); 157 | 158 | if (max != fwrite(buffer, 1, max, fout)) 159 | { 160 | fprintf(stdout, "Error writing file\n"); 161 | goto clean; 162 | } 163 | 164 | size -= max; 165 | } 166 | 167 | clean: 168 | if (fout) 169 | fclose(fout); 170 | } 171 | 172 | 173 | void cia_process(cia_context* ctx, u32 actions) 174 | { 175 | fseek(ctx->file, 0, SEEK_SET); 176 | 177 | if (fread(&ctx->header, 1, sizeof(ctr_ciaheader), ctx->file) != sizeof(ctr_ciaheader)) 178 | { 179 | fprintf(stderr, "Error reading CIA header\n"); 180 | goto clean; 181 | } 182 | 183 | ctx->sizeheader = getle32(ctx->header.headersize); 184 | ctx->sizecert = getle32(ctx->header.certsize); 185 | ctx->sizetik = getle32(ctx->header.ticketsize); 186 | ctx->sizetmd = getle32(ctx->header.tmdsize); 187 | ctx->sizecontent = (u32)getle64(ctx->header.contentsize); 188 | ctx->sizemeta = getle32(ctx->header.metasize); 189 | 190 | ctx->offsetcerts = align(ctx->sizeheader, 64); 191 | ctx->offsettik = align(ctx->offsetcerts + ctx->sizecert, 64); 192 | ctx->offsettmd = align(ctx->offsettik + ctx->sizetik, 64); 193 | ctx->offsetcontent = align(ctx->offsettmd + ctx->sizetmd, 64); 194 | ctx->offsetmeta = align(ctx->offsetcontent + ctx->sizecontent, 64); 195 | 196 | if (actions & InfoFlag) 197 | cia_print(ctx); 198 | 199 | 200 | tik_set_file(&ctx->tik, ctx->file); 201 | tik_set_offset(&ctx->tik, ctx->offsettik); 202 | tik_set_size(&ctx->tik, ctx->sizetik); 203 | tik_set_usersettings(&ctx->tik, ctx->usersettings); 204 | 205 | tik_process(&ctx->tik, actions); 206 | memset(ctx->iv, 0, 16); 207 | 208 | 209 | 210 | if (settings_get_common_key(ctx->usersettings)) 211 | tik_get_decrypted_titlekey(&ctx->tik, ctx->titlekey); 212 | 213 | tmd_set_file(&ctx->tmd, ctx->file); 214 | tmd_set_offset(&ctx->tmd, ctx->offsettmd); 215 | tmd_set_size(&ctx->tmd, ctx->sizetmd); 216 | tmd_set_usersettings(&ctx->tmd, ctx->usersettings); 217 | tmd_process(&ctx->tmd, actions); 218 | 219 | if (actions & VerifyFlag) 220 | { 221 | cia_verify_contents(ctx); 222 | } 223 | 224 | if (actions & InfoFlag || actions & VerifyFlag) 225 | tmd_print(&ctx->tmd); 226 | 227 | if (actions & ExtractFlag) 228 | { 229 | cia_save(ctx, CIATYPE_CERTS, actions); 230 | cia_save(ctx, CIATYPE_TMD, actions); 231 | cia_save(ctx, CIATYPE_TIK, actions); 232 | cia_save(ctx, CIATYPE_META, actions); 233 | cia_save(ctx, CIATYPE_CONTENT, actions); 234 | } 235 | 236 | clean: 237 | return; 238 | } 239 | 240 | void cia_verify_contents(cia_context *ctx) 241 | { 242 | ctr_tmd_body *body; 243 | ctr_tmd_contentchunk *chunk; 244 | u8 *verify_buf; 245 | u32 content_size=0; 246 | int i; 247 | 248 | // verify TMD content hashes, requires decryption .. 249 | body = tmd_get_body(&ctx->tmd); 250 | chunk = (ctr_tmd_contentchunk*)(body->contentinfo + (sizeof(ctr_tmd_contentinfo) * TMD_MAX_CONTENTS)); 251 | 252 | fseek(ctx->file, ctx->offset + ctx->offsetcontent, SEEK_SET); 253 | for(i = 0; i < getbe16(body->contentcount); i++) 254 | { 255 | content_size = getbe64(chunk->size) & 0xffffffff; 256 | 257 | ctx->iv[0] = (getbe16(chunk->index) >> 8) & 0xff; 258 | ctx->iv[1] = getbe16(chunk->index) & 0xff; 259 | 260 | ctr_init_cbc_decrypt(&ctx->aes, ctx->titlekey, ctx->iv); 261 | 262 | verify_buf = malloc(content_size); 263 | fread(verify_buf, content_size, 1, ctx->file); 264 | 265 | ctr_decrypt_cbc(&ctx->aes, verify_buf, verify_buf, content_size); 266 | 267 | if (ctr_sha_256_verify(verify_buf, content_size, chunk->hash) == Good) 268 | ctx->tmd.content_hash_stat[i] = 1; 269 | else 270 | ctx->tmd.content_hash_stat[i] = 2; 271 | 272 | free(verify_buf); 273 | 274 | chunk++; 275 | } 276 | } 277 | 278 | void cia_print(cia_context* ctx) 279 | { 280 | ctr_ciaheader* header = &ctx->header; 281 | 282 | fprintf(stdout, "Header size 0x%08x\n", getle32(header->headersize)); 283 | fprintf(stdout, "Type %04x\n", getle16(header->type)); 284 | fprintf(stdout, "Version %04x\n", getle16(header->version)); 285 | fprintf(stdout, "Certificates offset: 0x%08x\n", ctx->offsetcerts); 286 | fprintf(stdout, "Certificates size: 0x%04x\n", ctx->sizecert); 287 | fprintf(stdout, "Ticket offset: 0x%08x\n", ctx->offsettik); 288 | fprintf(stdout, "Ticket size 0x%04x\n", ctx->sizetik); 289 | fprintf(stdout, "TMD offset: 0x%08x\n", ctx->offsettmd); 290 | fprintf(stdout, "TMD size: 0x%04x\n", ctx->sizetmd); 291 | fprintf(stdout, "Meta offset: 0x%04x\n", ctx->offsetmeta); 292 | fprintf(stdout, "Meta size: 0x%04x\n", ctx->sizemeta); 293 | fprintf(stdout, "Content offset: 0x%08x\n", ctx->offsetcontent); 294 | fprintf(stdout, "Content size: 0x%016llx\n", getle64(header->contentsize)); 295 | } 296 | -------------------------------------------------------------------------------- /ctrtool/exefs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "types.h" 6 | #include "exefs.h" 7 | #include "utils.h" 8 | #include "ncch.h" 9 | #include "lzss.h" 10 | 11 | void exefs_init(exefs_context* ctx) 12 | { 13 | memset(ctx, 0, sizeof(exefs_context)); 14 | } 15 | 16 | void exefs_set_file(exefs_context* ctx, FILE* file) 17 | { 18 | ctx->file = file; 19 | } 20 | 21 | void exefs_set_offset(exefs_context* ctx, u32 offset) 22 | { 23 | ctx->offset = offset; 24 | } 25 | 26 | void exefs_set_size(exefs_context* ctx, u32 size) 27 | { 28 | ctx->size = size; 29 | } 30 | 31 | void exefs_set_usersettings(exefs_context* ctx, settings* usersettings) 32 | { 33 | ctx->usersettings = usersettings; 34 | } 35 | 36 | void exefs_set_partitionid(exefs_context* ctx, u8 partitionid[8]) 37 | { 38 | memcpy(ctx->partitionid, partitionid, 8); 39 | } 40 | 41 | void exefs_set_compressedflag(exefs_context* ctx, int compressedflag) 42 | { 43 | ctx->compressedflag = compressedflag; 44 | } 45 | 46 | void exefs_set_encrypted(exefs_context* ctx, u32 encrypted) 47 | { 48 | ctx->encrypted = encrypted; 49 | } 50 | 51 | void exefs_set_key(exefs_context* ctx, u8 key[16]) 52 | { 53 | memcpy(ctx->key, key, 16); 54 | } 55 | 56 | void exefs_set_counter(exefs_context* ctx, u8 counter[16]) 57 | { 58 | memcpy(ctx->counter, counter, 16); 59 | } 60 | 61 | void exefs_determine_key(exefs_context* ctx, u32 actions) 62 | { 63 | u8* key = settings_get_ncch_key(ctx->usersettings); 64 | 65 | if (actions & PlainFlag) 66 | ctx->encrypted = 0; 67 | else 68 | { 69 | if (key) 70 | { 71 | ctx->encrypted = 1; 72 | memcpy(ctx->key, key, 0x10); 73 | } 74 | } 75 | } 76 | 77 | void exefs_save(exefs_context* ctx, u32 index, u32 flags) 78 | { 79 | exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index); 80 | char outfname[MAX_PATH]; 81 | char name[64]; 82 | u32 offset; 83 | u32 size; 84 | FILE* fout; 85 | u32 compressedsize = 0; 86 | u32 decompressedsize = 0; 87 | u8* compressedbuffer = 0; 88 | u8* decompressedbuffer = 0; 89 | filepath* dirpath = 0; 90 | 91 | 92 | offset = getle32(section->offset) + sizeof(exefs_header); 93 | size = getle32(section->size); 94 | dirpath = settings_get_exefs_dir_path(ctx->usersettings); 95 | 96 | if (size == 0 || dirpath == 0 || dirpath->valid == 0) 97 | return; 98 | 99 | if (size >= ctx->size) 100 | { 101 | fprintf(stderr, "Error, ExeFS section %d size invalid\n", index); 102 | return; 103 | } 104 | 105 | memset(name, 0, sizeof(name)); 106 | memcpy(name, section->name, 8); 107 | 108 | 109 | memcpy(outfname, dirpath->pathname, MAX_PATH); 110 | strcat(outfname, "/"); 111 | 112 | if (name[0] == '.') 113 | strcat(outfname, name+1); 114 | else 115 | strcat(outfname, name); 116 | strcat(outfname, ".bin"); 117 | 118 | fout = fopen(outfname, "wb"); 119 | 120 | if (fout == 0) 121 | { 122 | fprintf(stderr, "Error, failed to create file %s\n", outfname); 123 | goto clean; 124 | } 125 | 126 | 127 | 128 | fseek(ctx->file, ctx->offset + offset, SEEK_SET); 129 | ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); 130 | ctr_add_counter(&ctx->aes, offset / 0x10); 131 | 132 | if (index == 0 && ctx->compressedflag && ((flags & RawFlag) == 0)) 133 | { 134 | fprintf(stdout, "Decompressing section %s to %s...\n", name, outfname); 135 | 136 | compressedsize = size; 137 | compressedbuffer = malloc(compressedsize); 138 | 139 | if (compressedbuffer == 0) 140 | { 141 | fprintf(stdout, "Error allocating memory\n"); 142 | goto clean; 143 | } 144 | if (compressedsize != fread(compressedbuffer, 1, compressedsize, ctx->file)) 145 | { 146 | fprintf(stdout, "Error reading input file\n"); 147 | goto clean; 148 | } 149 | 150 | if (ctx->encrypted) 151 | ctr_crypt_counter(&ctx->aes, compressedbuffer, compressedbuffer, compressedsize); 152 | 153 | 154 | decompressedsize = lzss_get_decompressed_size(compressedbuffer, compressedsize); 155 | decompressedbuffer = malloc(decompressedsize); 156 | if (decompressedbuffer == 0) 157 | { 158 | fprintf(stdout, "Error allocating memory\n"); 159 | goto clean; 160 | } 161 | 162 | if (0 == lzss_decompress(compressedbuffer, compressedsize, decompressedbuffer, decompressedsize)) 163 | goto clean; 164 | 165 | if (decompressedsize != fwrite(decompressedbuffer, 1, decompressedsize, fout)) 166 | { 167 | fprintf(stdout, "Error writing output file\n"); 168 | goto clean; 169 | } 170 | } 171 | else 172 | { 173 | u8 buffer[16 * 1024]; 174 | 175 | fprintf(stdout, "Saving section %s to %s...\n", name, outfname); 176 | 177 | while(size) 178 | { 179 | u32 max = sizeof(buffer); 180 | if (max > size) 181 | max = size; 182 | 183 | if (max != fread(buffer, 1, max, ctx->file)) 184 | { 185 | fprintf(stdout, "Error reading input file\n"); 186 | goto clean; 187 | } 188 | 189 | if (ctx->encrypted) 190 | ctr_crypt_counter(&ctx->aes, buffer, buffer, max); 191 | 192 | if (max != fwrite(buffer, 1, max, fout)) 193 | { 194 | fprintf(stdout, "Error writing output file\n"); 195 | goto clean; 196 | } 197 | 198 | size -= max; 199 | } 200 | } 201 | 202 | clean: 203 | free(compressedbuffer); 204 | free(decompressedbuffer); 205 | return; 206 | } 207 | 208 | void exefs_read_header(exefs_context* ctx, u32 flags) 209 | { 210 | fseek(ctx->file, ctx->offset, SEEK_SET); 211 | fread(&ctx->header, 1, sizeof(exefs_header), ctx->file); 212 | 213 | ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); 214 | 215 | if (ctx->encrypted) 216 | ctr_crypt_counter(&ctx->aes, (u8*)&ctx->header, (u8*)&ctx->header, sizeof(exefs_header)); 217 | } 218 | 219 | void exefs_calculate_hash(exefs_context* ctx, u8 hash[32]) 220 | { 221 | ctr_sha_256((const u8*)&ctx->header, sizeof(exefs_header), hash); 222 | } 223 | 224 | void exefs_process(exefs_context* ctx, u32 actions) 225 | { 226 | u32 i; 227 | 228 | exefs_determine_key(ctx, actions); 229 | 230 | exefs_read_header(ctx, actions); 231 | 232 | if (actions & VerifyFlag) 233 | { 234 | for(i=0; i<8; i++) 235 | ctx->hashcheck[i] = exefs_verify(ctx, i, actions)? Good : Fail; 236 | } 237 | 238 | if (actions & InfoFlag) 239 | { 240 | exefs_print(ctx); 241 | } 242 | 243 | if (actions & ExtractFlag) 244 | { 245 | filepath* dirpath = settings_get_exefs_dir_path(ctx->usersettings); 246 | 247 | if (dirpath && dirpath->valid) 248 | { 249 | makedir(dirpath->pathname); 250 | for(i=0; i<8; i++) 251 | exefs_save(ctx, i, actions); 252 | } 253 | } 254 | } 255 | 256 | int exefs_verify(exefs_context* ctx, u32 index, u32 flags) 257 | { 258 | exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index); 259 | u32 offset; 260 | u32 size; 261 | u8 buffer[16 * 1024]; 262 | u8 hash[0x20]; 263 | 264 | 265 | offset = getle32(section->offset) + sizeof(exefs_header); 266 | size = getle32(section->size); 267 | 268 | if (size == 0) 269 | return 0; 270 | 271 | fseek(ctx->file, ctx->offset + offset, SEEK_SET); 272 | ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); 273 | ctr_add_counter(&ctx->aes, offset / 0x10); 274 | 275 | ctr_sha_256_init(&ctx->sha); 276 | 277 | while(size) 278 | { 279 | u32 max = sizeof(buffer); 280 | if (max > size) 281 | max = size; 282 | 283 | if (max != fread(buffer, 1, max, ctx->file)) 284 | { 285 | fprintf(stdout, "Error reading input file\n"); 286 | goto clean; 287 | } 288 | 289 | if (ctx->encrypted) 290 | ctr_crypt_counter(&ctx->aes, buffer, buffer, max); 291 | 292 | ctr_sha_256_update(&ctx->sha, buffer, max); 293 | 294 | size -= max; 295 | } 296 | 297 | ctr_sha_256_finish(&ctx->sha, hash); 298 | 299 | if (memcmp(hash, ctx->header.hashes[7-index], 0x20) == 0) 300 | return 1; 301 | clean: 302 | return 0; 303 | } 304 | 305 | void exefs_print(exefs_context* ctx) 306 | { 307 | u32 i; 308 | char sectname[9]; 309 | u32 sectoffset; 310 | u32 sectsize; 311 | 312 | fprintf(stdout, "\nExeFS:\n"); 313 | for(i=0; i<8; i++) 314 | { 315 | exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + i); 316 | 317 | 318 | memset(sectname, 0, sizeof(sectname)); 319 | memcpy(sectname, section->name, 8); 320 | 321 | sectoffset = getle32(section->offset); 322 | sectsize = getle32(section->size); 323 | 324 | if (sectsize) 325 | { 326 | fprintf(stdout, "Section name: %s\n", sectname); 327 | fprintf(stdout, "Section offset: 0x%08x\n", sectoffset + 0x200); 328 | fprintf(stdout, "Section size: 0x%08x\n", sectsize); 329 | if (ctx->hashcheck[i] == Good) 330 | memdump(stdout, "Section hash (GOOD): ", ctx->header.hashes[7-i], 0x20); 331 | else if (ctx->hashcheck[i] == Fail) 332 | memdump(stdout, "Section hash (FAIL): ", ctx->header.hashes[7-i], 0x20); 333 | else 334 | memdump(stdout, "Section hash: ", ctx->header.hashes[7-i], 0x20); 335 | } 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /ctrtool/tinyxml/tinystr.h: -------------------------------------------------------------------------------- 1 | /* 2 | www.sourceforge.net/projects/tinyxml 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any 6 | damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it and 10 | redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must 13 | not claim that you wrote the original software. If you use this 14 | software in a product, an acknowledgment in the product documentation 15 | would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and 18 | must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | */ 23 | 24 | 25 | #ifndef TIXML_USE_STL 26 | 27 | #ifndef TIXML_STRING_INCLUDED 28 | #define TIXML_STRING_INCLUDED 29 | 30 | #include 31 | #include 32 | 33 | /* The support for explicit isn't that universal, and it isn't really 34 | required - it is used to check that the TiXmlString class isn't incorrectly 35 | used. Be nice to old compilers and macro it here: 36 | */ 37 | #if defined(_MSC_VER) && (_MSC_VER >= 1200 ) 38 | // Microsoft visual studio, version 6 and higher. 39 | #define TIXML_EXPLICIT explicit 40 | #elif defined(__GNUC__) && (__GNUC__ >= 3 ) 41 | // GCC version 3 and higher.s 42 | #define TIXML_EXPLICIT explicit 43 | #else 44 | #define TIXML_EXPLICIT 45 | #endif 46 | 47 | 48 | /* 49 | TiXmlString is an emulation of a subset of the std::string template. 50 | Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. 51 | Only the member functions relevant to the TinyXML project have been implemented. 52 | The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase 53 | a string and there's no more room, we allocate a buffer twice as big as we need. 54 | */ 55 | class TiXmlString 56 | { 57 | public : 58 | // The size type used 59 | typedef size_t size_type; 60 | 61 | // Error value for find primitive 62 | static const size_type npos; // = -1; 63 | 64 | 65 | // TiXmlString empty constructor 66 | TiXmlString () : rep_(&nullrep_) 67 | { 68 | } 69 | 70 | // TiXmlString copy constructor 71 | TiXmlString ( const TiXmlString & copy) : rep_(0) 72 | { 73 | init(copy.length()); 74 | memcpy(start(), copy.data(), length()); 75 | } 76 | 77 | // TiXmlString constructor, based on a string 78 | TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) 79 | { 80 | init( static_cast( strlen(copy) )); 81 | memcpy(start(), copy, length()); 82 | } 83 | 84 | // TiXmlString constructor, based on a string 85 | TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) 86 | { 87 | init(len); 88 | memcpy(start(), str, len); 89 | } 90 | 91 | // TiXmlString destructor 92 | ~TiXmlString () 93 | { 94 | quit(); 95 | } 96 | 97 | TiXmlString& operator = (const char * copy) 98 | { 99 | return assign( copy, (size_type)strlen(copy)); 100 | } 101 | 102 | TiXmlString& operator = (const TiXmlString & copy) 103 | { 104 | return assign(copy.start(), copy.length()); 105 | } 106 | 107 | 108 | // += operator. Maps to append 109 | TiXmlString& operator += (const char * suffix) 110 | { 111 | return append(suffix, static_cast( strlen(suffix) )); 112 | } 113 | 114 | // += operator. Maps to append 115 | TiXmlString& operator += (char single) 116 | { 117 | return append(&single, 1); 118 | } 119 | 120 | // += operator. Maps to append 121 | TiXmlString& operator += (const TiXmlString & suffix) 122 | { 123 | return append(suffix.data(), suffix.length()); 124 | } 125 | 126 | 127 | // Convert a TiXmlString into a null-terminated char * 128 | const char * c_str () const { return rep_->str; } 129 | 130 | // Convert a TiXmlString into a char * (need not be null terminated). 131 | const char * data () const { return rep_->str; } 132 | 133 | // Return the length of a TiXmlString 134 | size_type length () const { return rep_->size; } 135 | 136 | // Alias for length() 137 | size_type size () const { return rep_->size; } 138 | 139 | // Checks if a TiXmlString is empty 140 | bool empty () const { return rep_->size == 0; } 141 | 142 | // Return capacity of string 143 | size_type capacity () const { return rep_->capacity; } 144 | 145 | 146 | // single char extraction 147 | const char& at (size_type index) const 148 | { 149 | assert( index < length() ); 150 | return rep_->str[ index ]; 151 | } 152 | 153 | // [] operator 154 | char& operator [] (size_type index) const 155 | { 156 | assert( index < length() ); 157 | return rep_->str[ index ]; 158 | } 159 | 160 | // find a char in a string. Return TiXmlString::npos if not found 161 | size_type find (char lookup) const 162 | { 163 | return find(lookup, 0); 164 | } 165 | 166 | // find a char in a string from an offset. Return TiXmlString::npos if not found 167 | size_type find (char tofind, size_type offset) const 168 | { 169 | if (offset >= length()) return npos; 170 | 171 | for (const char* p = c_str() + offset; *p != '\0'; ++p) 172 | { 173 | if (*p == tofind) return static_cast< size_type >( p - c_str() ); 174 | } 175 | return npos; 176 | } 177 | 178 | void clear () 179 | { 180 | //Lee: 181 | //The original was just too strange, though correct: 182 | // TiXmlString().swap(*this); 183 | //Instead use the quit & re-init: 184 | quit(); 185 | init(0,0); 186 | } 187 | 188 | /* Function to reserve a big amount of data when we know we'll need it. Be aware that this 189 | function DOES NOT clear the content of the TiXmlString if any exists. 190 | */ 191 | void reserve (size_type cap); 192 | 193 | TiXmlString& assign (const char* str, size_type len); 194 | 195 | TiXmlString& append (const char* str, size_type len); 196 | 197 | void swap (TiXmlString& other) 198 | { 199 | Rep* r = rep_; 200 | rep_ = other.rep_; 201 | other.rep_ = r; 202 | } 203 | 204 | private: 205 | 206 | void init(size_type sz) { init(sz, sz); } 207 | void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } 208 | char* start() const { return rep_->str; } 209 | char* finish() const { return rep_->str + rep_->size; } 210 | 211 | struct Rep 212 | { 213 | size_type size, capacity; 214 | char str[1]; 215 | }; 216 | 217 | void init(size_type sz, size_type cap) 218 | { 219 | if (cap) 220 | { 221 | // Lee: the original form: 222 | // rep_ = static_cast(operator new(sizeof(Rep) + cap)); 223 | // doesn't work in some cases of new being overloaded. Switching 224 | // to the normal allocation, although use an 'int' for systems 225 | // that are overly picky about structure alignment. 226 | const size_type bytesNeeded = sizeof(Rep) + cap; 227 | const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); 228 | rep_ = reinterpret_cast( new int[ intsNeeded ] ); 229 | 230 | rep_->str[ rep_->size = sz ] = '\0'; 231 | rep_->capacity = cap; 232 | } 233 | else 234 | { 235 | rep_ = &nullrep_; 236 | } 237 | } 238 | 239 | void quit() 240 | { 241 | if (rep_ != &nullrep_) 242 | { 243 | // The rep_ is really an array of ints. (see the allocator, above). 244 | // Cast it back before delete, so the compiler won't incorrectly call destructors. 245 | delete [] ( reinterpret_cast( rep_ ) ); 246 | } 247 | } 248 | 249 | Rep * rep_; 250 | static Rep nullrep_; 251 | 252 | } ; 253 | 254 | 255 | inline bool operator == (const TiXmlString & a, const TiXmlString & b) 256 | { 257 | return ( a.length() == b.length() ) // optimization on some platforms 258 | && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare 259 | } 260 | inline bool operator < (const TiXmlString & a, const TiXmlString & b) 261 | { 262 | return strcmp(a.c_str(), b.c_str()) < 0; 263 | } 264 | 265 | inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } 266 | inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } 267 | inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } 268 | inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } 269 | 270 | inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } 271 | inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } 272 | inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } 273 | inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } 274 | 275 | TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); 276 | TiXmlString operator + (const TiXmlString & a, const char* b); 277 | TiXmlString operator + (const char* a, const TiXmlString & b); 278 | 279 | 280 | /* 281 | TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. 282 | Only the operators that we need for TinyXML have been developped. 283 | */ 284 | class TiXmlOutStream : public TiXmlString 285 | { 286 | public : 287 | 288 | // TiXmlOutStream << operator. 289 | TiXmlOutStream & operator << (const TiXmlString & in) 290 | { 291 | *this += in; 292 | return *this; 293 | } 294 | 295 | // TiXmlOutStream << operator. 296 | TiXmlOutStream & operator << (const char * in) 297 | { 298 | *this += in; 299 | return *this; 300 | } 301 | 302 | } ; 303 | 304 | #endif // TIXML_STRING_INCLUDED 305 | #endif // TIXML_USE_STL 306 | -------------------------------------------------------------------------------- /ctrtool/ctrtool.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 55 | 58 | 61 | 64 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 93 | 101 | 104 | 107 | 110 | 113 | 116 | 128 | 131 | 134 | 137 | 147 | 150 | 153 | 156 | 159 | 162 | 165 | 168 | 169 | 170 | 171 | 172 | 173 | 178 | 181 | 182 | 185 | 186 | 189 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 205 | 206 | 209 | 210 | 213 | 214 | 217 | 218 | 221 | 222 | 225 | 226 | 229 | 230 | 233 | 234 | 237 | 238 | 241 | 242 | 245 | 246 | 249 | 250 | 253 | 254 | 257 | 258 | 261 | 262 | 265 | 268 | 269 | 272 | 273 | 276 | 277 | 280 | 281 | 282 | 285 | 288 | 289 | 292 | 293 | 296 | 297 | 300 | 301 | 302 | 303 | 308 | 311 | 312 | 315 | 316 | 319 | 320 | 323 | 324 | 327 | 328 | 331 | 332 | 335 | 336 | 339 | 340 | 343 | 344 | 347 | 348 | 351 | 352 | 355 | 356 | 359 | 360 | 363 | 364 | 367 | 368 | 371 | 372 | 375 | 376 | 379 | 380 | 383 | 384 | 387 | 388 | 391 | 392 | 395 | 398 | 399 | 402 | 403 | 406 | 407 | 410 | 411 | 414 | 415 | 418 | 419 | 420 | 423 | 426 | 427 | 430 | 431 | 432 | 433 | 438 | 439 | 440 | 441 | 442 | 443 | -------------------------------------------------------------------------------- /ctrtool/romfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "types.h" 7 | #include "romfs.h" 8 | #include "utils.h" 9 | 10 | void romfs_init(romfs_context* ctx) 11 | { 12 | memset(ctx, 0, sizeof(romfs_context)); 13 | ivfc_init(&ctx->ivfc); 14 | } 15 | 16 | void romfs_set_file(romfs_context* ctx, FILE* file) 17 | { 18 | ctx->file = file; 19 | } 20 | 21 | void romfs_set_offset(romfs_context* ctx, u32 offset) 22 | { 23 | ctx->offset = offset; 24 | } 25 | 26 | void romfs_set_size(romfs_context* ctx, u32 size) 27 | { 28 | ctx->size = size; 29 | } 30 | 31 | void romfs_set_usersettings(romfs_context* ctx, settings* usersettings) 32 | { 33 | ctx->usersettings = usersettings; 34 | } 35 | 36 | 37 | 38 | void romfs_process(romfs_context* ctx, u32 actions) 39 | { 40 | u32 dirblockoffset = 0; 41 | u32 dirblocksize = 0; 42 | u32 fileblockoffset = 0; 43 | u32 fileblocksize = 0; 44 | 45 | 46 | ivfc_set_offset(&ctx->ivfc, ctx->offset); 47 | ivfc_set_size(&ctx->ivfc, ctx->size); 48 | ivfc_set_file(&ctx->ivfc, ctx->file); 49 | ivfc_set_usersettings(&ctx->ivfc, ctx->usersettings); 50 | ivfc_process(&ctx->ivfc, actions); 51 | 52 | fseek(ctx->file, ctx->offset, SEEK_SET); 53 | fread(&ctx->header, 1, sizeof(romfs_header), ctx->file); 54 | 55 | if (getle32(ctx->header.magic) != MAGIC_IVFC) 56 | { 57 | fprintf(stdout, "Error, RomFS corrupted\n"); 58 | return; 59 | } 60 | 61 | ctx->infoblockoffset = ctx->offset + 0x1000; 62 | 63 | fseek(ctx->file, ctx->infoblockoffset, SEEK_SET); 64 | fread(&ctx->infoheader, 1, sizeof(romfs_infoheader), ctx->file); 65 | 66 | if (getle32(ctx->infoheader.headersize) != sizeof(romfs_infoheader)) 67 | { 68 | fprintf(stderr, "Error, info header mismatch\n"); 69 | return; 70 | } 71 | 72 | dirblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[1].offset); 73 | dirblocksize = getle32(ctx->infoheader.section[1].size); 74 | fileblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[3].offset); 75 | fileblocksize = getle32(ctx->infoheader.section[3].size); 76 | 77 | ctx->dirblock = malloc(dirblocksize); 78 | ctx->dirblocksize = dirblocksize; 79 | ctx->fileblock = malloc(fileblocksize); 80 | ctx->fileblocksize = fileblocksize; 81 | 82 | ctx->datablockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.dataoffset); 83 | 84 | if (ctx->dirblock) 85 | { 86 | fseek(ctx->file, dirblockoffset, SEEK_SET); 87 | fread(ctx->dirblock, 1, dirblocksize, ctx->file); 88 | } 89 | 90 | if (ctx->fileblock) 91 | { 92 | fseek(ctx->file, fileblockoffset, SEEK_SET); 93 | fread(ctx->fileblock, 1, fileblocksize, ctx->file); 94 | } 95 | 96 | if (actions & InfoFlag) 97 | romfs_print(ctx); 98 | 99 | romfs_visit_dir(ctx, 0, 0, actions, settings_get_romfs_dir_path(ctx->usersettings)); 100 | 101 | } 102 | 103 | int romfs_dirblock_read(romfs_context* ctx, u32 diroffset, u32 dirsize, void* buffer) 104 | { 105 | if (!ctx->dirblock) 106 | return 0; 107 | 108 | if (diroffset+dirsize > ctx->dirblocksize) 109 | return 0; 110 | 111 | memcpy(buffer, ctx->dirblock + diroffset, dirsize); 112 | return 1; 113 | } 114 | 115 | int romfs_dirblock_readentry(romfs_context* ctx, u32 diroffset, romfs_direntry* entry) 116 | { 117 | u32 size_without_name = sizeof(romfs_direntry) - ROMFS_MAXNAMESIZE; 118 | u32 namesize; 119 | 120 | 121 | if (!ctx->dirblock) 122 | return 0; 123 | 124 | if (!romfs_dirblock_read(ctx, diroffset, size_without_name, entry)) 125 | return 0; 126 | 127 | namesize = getle32(entry->namesize); 128 | if (namesize > (ROMFS_MAXNAMESIZE-2)) 129 | namesize = (ROMFS_MAXNAMESIZE-2); 130 | memset(entry->name + namesize, 0, 2); 131 | if (!romfs_dirblock_read(ctx, diroffset + size_without_name, namesize, entry->name)) 132 | return 0; 133 | 134 | return 1; 135 | } 136 | 137 | 138 | int romfs_fileblock_read(romfs_context* ctx, u32 fileoffset, u32 filesize, void* buffer) 139 | { 140 | if (!ctx->fileblock) 141 | return 0; 142 | 143 | if (fileoffset+filesize > ctx->fileblocksize) 144 | return 0; 145 | 146 | memcpy(buffer, ctx->fileblock + fileoffset, filesize); 147 | return 1; 148 | } 149 | 150 | int romfs_fileblock_readentry(romfs_context* ctx, u32 fileoffset, romfs_fileentry* entry) 151 | { 152 | u32 size_without_name = sizeof(romfs_fileentry) - ROMFS_MAXNAMESIZE; 153 | u32 namesize; 154 | 155 | 156 | if (!ctx->fileblock) 157 | return 0; 158 | 159 | if (!romfs_fileblock_read(ctx, fileoffset, size_without_name, entry)) 160 | return 0; 161 | 162 | namesize = getle32(entry->namesize); 163 | if (namesize > (ROMFS_MAXNAMESIZE-2)) 164 | namesize = (ROMFS_MAXNAMESIZE-2); 165 | memset(entry->name + namesize, 0, 2); 166 | if (!romfs_fileblock_read(ctx, fileoffset + size_without_name, namesize, entry->name)) 167 | return 0; 168 | 169 | return 1; 170 | } 171 | 172 | 173 | 174 | void romfs_visit_dir(romfs_context* ctx, u32 diroffset, u32 depth, u32 actions, filepath* rootpath) 175 | { 176 | u32 siblingoffset; 177 | u32 childoffset; 178 | u32 fileoffset; 179 | filepath currentpath; 180 | romfs_direntry* entry = &ctx->direntry; 181 | 182 | 183 | if (!romfs_dirblock_readentry(ctx, diroffset, entry)) 184 | return; 185 | 186 | 187 | // fprintf(stdout, "%08X %08X %08X %08X %08X ", 188 | // getle32(entry->parentoffset), getle32(entry->siblingoffset), getle32(entry->childoffset), 189 | // getle32(entry->fileoffset), getle32(entry->weirdoffset)); 190 | // fwprintf(stdout, L"%ls\n", entry->name); 191 | 192 | 193 | if (rootpath && rootpath->valid) 194 | { 195 | filepath_copy(¤tpath, rootpath); 196 | filepath_append_utf16(¤tpath, entry->name); 197 | if (currentpath.valid) 198 | { 199 | makedir(currentpath.pathname); 200 | } 201 | else 202 | { 203 | fprintf(stderr, "Error creating directory in root %s\n", rootpath->pathname); 204 | return; 205 | } 206 | } 207 | else 208 | { 209 | filepath_init(¤tpath); 210 | 211 | if (settings_get_list_romfs_files(ctx->usersettings)) 212 | { 213 | u32 i; 214 | 215 | for(i=0; iname); 218 | } 219 | } 220 | 221 | 222 | siblingoffset = getle32(entry->siblingoffset); 223 | childoffset = getle32(entry->childoffset); 224 | fileoffset = getle32(entry->fileoffset); 225 | 226 | if (fileoffset != (~0)) 227 | romfs_visit_file(ctx, fileoffset, depth+1, actions, ¤tpath); 228 | 229 | if (childoffset != (~0)) 230 | romfs_visit_dir(ctx, childoffset, depth+1, actions, ¤tpath); 231 | 232 | if (siblingoffset != (~0)) 233 | romfs_visit_dir(ctx, siblingoffset, depth, actions, rootpath); 234 | } 235 | 236 | 237 | void romfs_visit_file(romfs_context* ctx, u32 fileoffset, u32 depth, u32 actions, filepath* rootpath) 238 | { 239 | u32 siblingoffset = 0; 240 | filepath currentpath; 241 | romfs_fileentry* entry = &ctx->fileentry; 242 | 243 | 244 | if (!romfs_fileblock_readentry(ctx, fileoffset, entry)) 245 | return; 246 | 247 | 248 | // fprintf(stdout, "%08X %08X %016llX %016llX %08X ", 249 | // getle32(entry->parentdiroffset), getle32(entry->siblingoffset), ctx->datablockoffset+getle64(entry->dataoffset), 250 | // getle64(entry->datasize), getle32(entry->unknown)); 251 | // fwprintf(stdout, L"%ls\n", entry->name); 252 | 253 | if (rootpath && rootpath->valid) 254 | { 255 | filepath_copy(¤tpath, rootpath); 256 | filepath_append_utf16(¤tpath, entry->name); 257 | if (currentpath.valid) 258 | { 259 | fprintf(stdout, "Saving %s...\n", currentpath.pathname); 260 | romfs_extract_datafile(ctx, getle64(entry->dataoffset), getle64(entry->datasize), ¤tpath); 261 | } 262 | else 263 | { 264 | fprintf(stderr, "Error creating directory in root %s\n", rootpath->pathname); 265 | return; 266 | } 267 | } 268 | else 269 | { 270 | filepath_init(¤tpath); 271 | if (settings_get_list_romfs_files(ctx->usersettings)) 272 | { 273 | u32 i; 274 | 275 | for(i=0; iname); 278 | } 279 | } 280 | 281 | siblingoffset = getle32(entry->siblingoffset); 282 | 283 | if (siblingoffset != (~0)) 284 | romfs_visit_file(ctx, siblingoffset, depth, actions, rootpath); 285 | } 286 | 287 | void romfs_extract_datafile(romfs_context* ctx, u64 offset, u64 size, filepath* path) 288 | { 289 | FILE* outfile = 0; 290 | u32 max; 291 | u8 buffer[4096]; 292 | 293 | 294 | if (path == 0 || path->valid == 0) 295 | goto clean; 296 | 297 | offset += ctx->datablockoffset; 298 | if ( (offset >> 32) ) 299 | { 300 | fprintf(stderr, "Error, support for 64-bit offset not yet implemented.\n"); 301 | goto clean; 302 | } 303 | 304 | fseek(ctx->file, offset, SEEK_SET); 305 | outfile = fopen(path->pathname, "wb"); 306 | if (outfile == 0) 307 | { 308 | fprintf(stderr, "Error opening file for writing\n"); 309 | goto clean; 310 | } 311 | 312 | while(size) 313 | { 314 | max = sizeof(buffer); 315 | if (max > size) 316 | max = size; 317 | 318 | if (max != fread(buffer, 1, max, ctx->file)) 319 | { 320 | fprintf(stderr, "Error reading file\n"); 321 | goto clean; 322 | } 323 | 324 | if (max != fwrite(buffer, 1, max, outfile)) 325 | { 326 | fprintf(stderr, "Error writing file\n"); 327 | goto clean; 328 | } 329 | 330 | size -= max; 331 | } 332 | clean: 333 | if (outfile) 334 | fclose(outfile); 335 | } 336 | 337 | 338 | void romfs_print(romfs_context* ctx) 339 | { 340 | u32 i; 341 | 342 | fprintf(stdout, "\nRomFS:\n"); 343 | 344 | fprintf(stdout, "Header size: 0x%08X\n", getle32(ctx->infoheader.headersize)); 345 | for(i=0; i<4; i++) 346 | { 347 | fprintf(stdout, "Section %d offset: 0x%08X\n", i, ctx->offset + 0x1000 + getle32(ctx->infoheader.section[i].offset)); 348 | fprintf(stdout, "Section %d size: 0x%08X\n", i, getle32(ctx->infoheader.section[i].size)); 349 | } 350 | 351 | fprintf(stdout, "Data offset: 0x%08X\n", ctx->offset + 0x1000 + getle32(ctx->infoheader.dataoffset)); 352 | } 353 | -------------------------------------------------------------------------------- /ctrtool/polarssl/rsa.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file rsa.h 3 | * 4 | * Copyright (C) 2006-2010, Brainspark B.V. 5 | * 6 | * This file is part of PolarSSL (http://www.polarssl.org) 7 | * Lead Maintainer: Paul Bakker 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | #ifndef POLARSSL_RSA_H 26 | #define POLARSSL_RSA_H 27 | 28 | #include "polarssl/bignum.h" 29 | 30 | /* 31 | * RSA Error codes 32 | */ 33 | #define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x0400 34 | #define POLARSSL_ERR_RSA_INVALID_PADDING -0x0410 35 | #define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x0420 36 | #define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x0430 37 | #define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x0440 38 | #define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x0450 39 | #define POLARSSL_ERR_RSA_VERIFY_FAILED -0x0460 40 | #define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x0470 41 | #define POLARSSL_ERR_RSA_RNG_FAILED -0x0480 42 | 43 | /* 44 | * PKCS#1 constants 45 | */ 46 | #define SIG_RSA_RAW 0 47 | #define SIG_RSA_MD2 2 48 | #define SIG_RSA_MD4 3 49 | #define SIG_RSA_MD5 4 50 | #define SIG_RSA_SHA1 5 51 | #define SIG_RSA_SHA224 14 52 | #define SIG_RSA_SHA256 11 53 | #define SIG_RSA_SHA384 12 54 | #define SIG_RSA_SHA512 13 55 | 56 | #define RSA_PUBLIC 0 57 | #define RSA_PRIVATE 1 58 | 59 | #define RSA_PKCS_V15 0 60 | #define RSA_PKCS_V21 1 61 | 62 | #define RSA_SIGN 1 63 | #define RSA_CRYPT 2 64 | 65 | #define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30" 66 | #define ASN1_STR_NULL "\x05" 67 | #define ASN1_STR_OID "\x06" 68 | #define ASN1_STR_OCTET_STRING "\x04" 69 | 70 | #define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00" 71 | #define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a" 72 | #define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00" 73 | 74 | #define OID_ISO_MEMBER_BODIES "\x2a" 75 | #define OID_ISO_IDENTIFIED_ORG "\x2b" 76 | 77 | /* 78 | * ISO Member bodies OID parts 79 | */ 80 | #define OID_COUNTRY_US "\x86\x48" 81 | #define OID_RSA_DATA_SECURITY "\x86\xf7\x0d" 82 | 83 | /* 84 | * ISO Identified organization OID parts 85 | */ 86 | #define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a" 87 | 88 | /* 89 | * DigestInfo ::= SEQUENCE { 90 | * digestAlgorithm DigestAlgorithmIdentifier, 91 | * digest Digest } 92 | * 93 | * DigestAlgorithmIdentifier ::= AlgorithmIdentifier 94 | * 95 | * Digest ::= OCTET STRING 96 | */ 97 | #define ASN1_HASH_MDX \ 98 | ( \ 99 | ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \ 100 | ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \ 101 | ASN1_STR_OID "\x08" \ 102 | OID_DIGEST_ALG_MDX \ 103 | ASN1_STR_NULL "\x00" \ 104 | ASN1_STR_OCTET_STRING "\x10" \ 105 | ) 106 | 107 | #define ASN1_HASH_SHA1 \ 108 | ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \ 109 | ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \ 110 | ASN1_STR_OID "\x05" \ 111 | OID_HASH_ALG_SHA1 \ 112 | ASN1_STR_NULL "\x00" \ 113 | ASN1_STR_OCTET_STRING "\x14" 114 | 115 | #define ASN1_HASH_SHA2X \ 116 | ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \ 117 | ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \ 118 | ASN1_STR_OID "\x09" \ 119 | OID_HASH_ALG_SHA2X \ 120 | ASN1_STR_NULL "\x00" \ 121 | ASN1_STR_OCTET_STRING "\x00" 122 | 123 | /** 124 | * \brief RSA context structure 125 | */ 126 | typedef struct 127 | { 128 | int ver; /*!< always 0 */ 129 | int len; /*!< size(N) in chars */ 130 | 131 | mpi N; /*!< public modulus */ 132 | mpi E; /*!< public exponent */ 133 | 134 | mpi D; /*!< private exponent */ 135 | mpi P; /*!< 1st prime factor */ 136 | mpi Q; /*!< 2nd prime factor */ 137 | mpi DP; /*!< D % (P - 1) */ 138 | mpi DQ; /*!< D % (Q - 1) */ 139 | mpi QP; /*!< 1 / (Q % P) */ 140 | 141 | mpi RN; /*!< cached R^2 mod N */ 142 | mpi RP; /*!< cached R^2 mod P */ 143 | mpi RQ; /*!< cached R^2 mod Q */ 144 | 145 | int padding; /*!< 1.5 or OAEP/PSS */ 146 | int hash_id; /*!< hash identifier */ 147 | } 148 | rsa_context; 149 | 150 | #ifdef __cplusplus 151 | extern "C" { 152 | #endif 153 | 154 | /** 155 | * \brief Initialize an RSA context 156 | * 157 | * \param ctx RSA context to be initialized 158 | * \param padding RSA_PKCS_V15 or RSA_PKCS_V21 159 | * \param hash_id RSA_PKCS_V21 hash identifier 160 | * 161 | * \note The hash_id parameter is actually ignored 162 | * when using RSA_PKCS_V15 padding. 163 | * 164 | * \note Currently, RSA_PKCS_V21 padding 165 | * is not supported. 166 | */ 167 | void rsa_init( rsa_context *ctx, 168 | int padding, 169 | int hash_id); 170 | 171 | /** 172 | * \brief Generate an RSA keypair 173 | * 174 | * \param ctx RSA context that will hold the key 175 | * \param f_rng RNG function 176 | * \param p_rng RNG parameter 177 | * \param nbits size of the public key in bits 178 | * \param exponent public exponent (e.g., 65537) 179 | * 180 | * \note rsa_init() must be called beforehand to setup 181 | * the RSA context. 182 | * 183 | * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code 184 | */ 185 | int rsa_gen_key( rsa_context *ctx, 186 | int (*f_rng)(void *), 187 | void *p_rng, 188 | int nbits, int exponent ); 189 | 190 | /** 191 | * \brief Check a public RSA key 192 | * 193 | * \param ctx RSA context to be checked 194 | * 195 | * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code 196 | */ 197 | int rsa_check_pubkey( const rsa_context *ctx ); 198 | 199 | /** 200 | * \brief Check a private RSA key 201 | * 202 | * \param ctx RSA context to be checked 203 | * 204 | * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code 205 | */ 206 | int rsa_check_privkey( const rsa_context *ctx ); 207 | 208 | /** 209 | * \brief Do an RSA public key operation 210 | * 211 | * \param ctx RSA context 212 | * \param input input buffer 213 | * \param output output buffer 214 | * 215 | * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code 216 | * 217 | * \note This function does NOT take care of message 218 | * padding. Also, be sure to set input[0] = 0 or assure that 219 | * input is smaller than N. 220 | * 221 | * \note The input and output buffers must be large 222 | * enough (eg. 128 bytes if RSA-1024 is used). 223 | */ 224 | int rsa_public( rsa_context *ctx, 225 | const unsigned char *input, 226 | unsigned char *output ); 227 | 228 | /** 229 | * \brief Do an RSA private key operation 230 | * 231 | * \param ctx RSA context 232 | * \param input input buffer 233 | * \param output output buffer 234 | * 235 | * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code 236 | * 237 | * \note The input and output buffers must be large 238 | * enough (eg. 128 bytes if RSA-1024 is used). 239 | */ 240 | int rsa_private( rsa_context *ctx, 241 | const unsigned char *input, 242 | unsigned char *output ); 243 | 244 | /** 245 | * \brief Add the message padding, then do an RSA operation 246 | * 247 | * \param ctx RSA context 248 | * \param f_rng RNG function 249 | * \param p_rng RNG parameter 250 | * \param mode RSA_PUBLIC or RSA_PRIVATE 251 | * \param ilen contains the plaintext length 252 | * \param input buffer holding the data to be encrypted 253 | * \param output buffer that will hold the ciphertext 254 | * 255 | * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code 256 | * 257 | * \note The output buffer must be as large as the size 258 | * of ctx->N (eg. 128 bytes if RSA-1024 is used). 259 | */ 260 | int rsa_pkcs1_encrypt( rsa_context *ctx, 261 | int (*f_rng)(void *), 262 | void *p_rng, 263 | int mode, int ilen, 264 | const unsigned char *input, 265 | unsigned char *output ); 266 | 267 | /** 268 | * \brief Do an RSA operation, then remove the message padding 269 | * 270 | * \param ctx RSA context 271 | * \param mode RSA_PUBLIC or RSA_PRIVATE 272 | * \param input buffer holding the encrypted data 273 | * \param output buffer that will hold the plaintext 274 | * \param olen will contain the plaintext length 275 | * \param output_max_len maximum length of the output buffer 276 | * 277 | * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code 278 | * 279 | * \note The output buffer must be as large as the size 280 | * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise 281 | * an error is thrown. 282 | */ 283 | int rsa_pkcs1_decrypt( rsa_context *ctx, 284 | int mode, int *olen, 285 | const unsigned char *input, 286 | unsigned char *output, 287 | int output_max_len ); 288 | 289 | /** 290 | * \brief Do a private RSA to sign a message digest 291 | * 292 | * \param ctx RSA context 293 | * \param mode RSA_PUBLIC or RSA_PRIVATE 294 | * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} 295 | * \param hashlen message digest length (for SIG_RSA_RAW only) 296 | * \param hash buffer holding the message digest 297 | * \param sig buffer that will hold the ciphertext 298 | * 299 | * \return 0 if the signing operation was successful, 300 | * or an POLARSSL_ERR_RSA_XXX error code 301 | * 302 | * \note The "sig" buffer must be as large as the size 303 | * of ctx->N (eg. 128 bytes if RSA-1024 is used). 304 | */ 305 | int rsa_pkcs1_sign( rsa_context *ctx, 306 | int mode, 307 | int hash_id, 308 | int hashlen, 309 | const unsigned char *hash, 310 | unsigned char *sig ); 311 | 312 | /** 313 | * \brief Do a public RSA and check the message digest 314 | * 315 | * \param ctx points to an RSA public key 316 | * \param mode RSA_PUBLIC or RSA_PRIVATE 317 | * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} 318 | * \param hashlen message digest length (for SIG_RSA_RAW only) 319 | * \param hash buffer holding the message digest 320 | * \param sig buffer holding the ciphertext 321 | * 322 | * \return 0 if the verify operation was successful, 323 | * or an POLARSSL_ERR_RSA_XXX error code 324 | * 325 | * \note The "sig" buffer must be as large as the size 326 | * of ctx->N (eg. 128 bytes if RSA-1024 is used). 327 | */ 328 | int rsa_pkcs1_verify( rsa_context *ctx, 329 | int mode, 330 | int hash_id, 331 | int hashlen, 332 | const unsigned char *hash, 333 | unsigned char *sig ); 334 | 335 | /** 336 | * \brief Free the components of an RSA key 337 | * 338 | * \param ctx RSA Context to free 339 | */ 340 | void rsa_free( rsa_context *ctx ); 341 | 342 | /** 343 | * \brief Checkup routine 344 | * 345 | * \return 0 if successful, or 1 if the test failed 346 | */ 347 | int rsa_self_test( int verbose ); 348 | 349 | #ifdef __cplusplus 350 | } 351 | #endif 352 | 353 | #endif /* rsa.h */ 354 | -------------------------------------------------------------------------------- /ctrtool/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "utils.h" 6 | #include "ctr.h" 7 | #include "ncch.h" 8 | #include "ncsd.h" 9 | #include "cia.h" 10 | #include "tmd.h" 11 | #include "tik.h" 12 | #include "lzss.h" 13 | #include "keyset.h" 14 | #include "exefs.h" 15 | #include "info.h" 16 | #include "settings.h" 17 | #include "firm.h" 18 | #include "cwav.h" 19 | #include "romfs.h" 20 | 21 | enum cryptotype 22 | { 23 | Plain, 24 | CTR, 25 | CBC 26 | }; 27 | 28 | 29 | typedef struct 30 | { 31 | int actions; 32 | u32 filetype; 33 | FILE* infile; 34 | u32 infilesize; 35 | settings usersettings; 36 | } toolcontext; 37 | 38 | static void usage(const char *argv0) 39 | { 40 | fprintf(stderr, 41 | "Usage: %s [options...] \n" 42 | "CTRTOOL (c) neimod.\n" 43 | "\n" 44 | "Options:\n" 45 | " -i, --info Show file info.\n" 46 | " This is the default action.\n" 47 | " -x, --extract Extract data from file.\n" 48 | " This is also the default action.\n" 49 | " -p, --plain Extract data without decrypting.\n" 50 | " -r, --raw Keep raw data, don't unpack.\n" 51 | " -k, --keyset=file Specify keyset file.\n" 52 | " -v, --verbose Give verbose output.\n" 53 | " -y, --verify Verify hashes and signatures.\n" 54 | " --unitsize=size Set media unit size (default 0x200).\n" 55 | " --commonkey=key Set common key.\n" 56 | " --ncchkey=key Set ncch key.\n" 57 | " --ncchsyskey=key Set ncch fixed system key.\n" 58 | " --showkeys Show the keys being used.\n" 59 | " -t, --intype=type Specify input file type [ncsd, ncch, exheader, cia, tmd, lzss,\n" 60 | " firm, cwav, romfs]\n" 61 | "LZSS options:\n" 62 | " --lzssout=file Specify lzss output file\n" 63 | "CXI/CCI options:\n" 64 | " -n, --ncch=offs Specify offset for NCCH header.\n" 65 | " --exefs=file Specify ExeFS file path.\n" 66 | " --exefsdir=dir Specify ExeFS directory path.\n" 67 | " --romfs=file Specify RomFS file path.\n" 68 | " --exheader=file Specify Extended Header file path.\n" 69 | "CIA options:\n" 70 | " --certs=file Specify Certificate chain file path.\n" 71 | " --tik=file Specify Ticket file path.\n" 72 | " --tmd=file Specify TMD file path.\n" 73 | " --contents=file Specify Contents file path.\n" 74 | " --meta=file Specify Meta file path.\n" 75 | "FIRM options:\n" 76 | " --firmdir=dir Specify Firm directory path.\n" 77 | "CWAV options:\n" 78 | " --wav=file Specify wav output file.\n" 79 | " --wavloops=count Specify wav loop count, default 0.\n" 80 | "ROMFS options:\n" 81 | " --romfsdir=dir Specify RomFS directory path.\n" 82 | " --listromfs List files in RomFS.\n" 83 | "\n", 84 | argv0); 85 | exit(1); 86 | } 87 | 88 | 89 | int main(int argc, char* argv[]) 90 | { 91 | toolcontext ctx; 92 | u8 magic[4]; 93 | char infname[512]; 94 | int c; 95 | u32 ncchoffset = ~0; 96 | char keysetfname[512] = "keys.xml"; 97 | keyset tmpkeys; 98 | unsigned int checkkeysetfile = 0; 99 | 100 | memset(&ctx, 0, sizeof(toolcontext)); 101 | ctx.actions = InfoFlag | ExtractFlag; 102 | ctx.filetype = FILETYPE_UNKNOWN; 103 | 104 | settings_init(&ctx.usersettings); 105 | keyset_init(&ctx.usersettings.keys); 106 | keyset_init(&tmpkeys); 107 | 108 | 109 | while (1) 110 | { 111 | int option_index; 112 | static struct option long_options[] = 113 | { 114 | {"extract", 0, NULL, 'x'}, 115 | {"plain", 0, NULL, 'p'}, 116 | {"info", 0, NULL, 'i'}, 117 | {"exefs", 1, NULL, 0}, 118 | {"romfs", 1, NULL, 1}, 119 | {"exheader", 1, NULL, 2}, 120 | {"certs", 1, NULL, 3}, 121 | {"tik", 1, NULL, 4}, 122 | {"tmd", 1, NULL, 5}, 123 | {"contents", 1, NULL, 6}, 124 | {"meta", 1, NULL, 7}, 125 | {"exefsdir", 1, NULL, 8}, 126 | {"keyset", 1, NULL, 'k'}, 127 | {"ncch", 1, NULL, 'n'}, 128 | {"verbose", 0, NULL, 'v'}, 129 | {"verify", 0, NULL, 'y'}, 130 | {"raw", 0, NULL, 'r'}, 131 | {"unitsize", 1, NULL, 9}, 132 | {"showkeys", 0, NULL, 10}, 133 | {"commonkey", 1, NULL, 11}, 134 | {"ncchkey", 1, NULL, 12}, 135 | {"intype", 1, NULL, 't'}, 136 | {"lzssout", 1, NULL, 13}, 137 | {"firmdir", 1, NULL, 14}, 138 | {"ncchsyskey", 1, NULL, 15}, 139 | {"wav", 1, NULL, 16}, 140 | {"romfsdir", 1, NULL, 17}, 141 | {"listromfs", 0, NULL, 18}, 142 | {"wavloops", 1, NULL, 19}, 143 | {NULL}, 144 | }; 145 | 146 | c = getopt_long(argc, argv, "ryxivpk:n:t:", long_options, &option_index); 147 | if (c == -1) 148 | break; 149 | 150 | switch (c) 151 | { 152 | case 'x': 153 | ctx.actions |= ExtractFlag; 154 | break; 155 | 156 | case 'v': 157 | ctx.actions |= VerboseFlag; 158 | break; 159 | 160 | case 'y': 161 | ctx.actions |= VerifyFlag; 162 | break; 163 | 164 | case 'p': 165 | ctx.actions |= PlainFlag; 166 | break; 167 | 168 | case 'r': 169 | ctx.actions |= RawFlag; 170 | break; 171 | 172 | case 'i': 173 | ctx.actions |= InfoFlag; 174 | break; 175 | 176 | case 'n': 177 | ncchoffset = strtoul(optarg, 0, 0); 178 | break; 179 | 180 | case 'k': 181 | strncpy(keysetfname, optarg, sizeof(keysetfname)); 182 | checkkeysetfile = 1; 183 | break; 184 | 185 | case 't': 186 | if (!strcmp(optarg, "exheader")) 187 | ctx.filetype = FILETYPE_EXHEADER; 188 | else if (!strcmp(optarg, "ncch")) 189 | ctx.filetype = FILETYPE_CXI; 190 | else if (!strcmp(optarg, "ncsd")) 191 | ctx.filetype = FILETYPE_CCI; 192 | else if (!strcmp(optarg, "cia")) 193 | ctx.filetype = FILETYPE_CIA; 194 | else if (!strcmp(optarg, "tmd")) 195 | ctx.filetype = FILETYPE_TMD; 196 | else if (!strcmp(optarg, "lzss")) 197 | ctx.filetype = FILETYPE_LZSS; 198 | else if (!strcmp(optarg, "firm")) 199 | ctx.filetype = FILETYPE_FIRM; 200 | else if (!strcmp(optarg, "cwav")) 201 | ctx.filetype = FILETYPE_CWAV; 202 | else if (!strcmp(optarg, "romfs")) 203 | ctx.filetype = FILETYPE_ROMFS; 204 | break; 205 | 206 | case 0: settings_set_exefs_path(&ctx.usersettings, optarg); break; 207 | case 1: settings_set_romfs_path(&ctx.usersettings, optarg); break; 208 | case 2: settings_set_exheader_path(&ctx.usersettings, optarg); break; 209 | case 3: settings_set_certs_path(&ctx.usersettings, optarg); break; 210 | case 4: settings_set_tik_path(&ctx.usersettings, optarg); break; 211 | case 5: settings_set_tmd_path(&ctx.usersettings, optarg); break; 212 | case 6: settings_set_content_path(&ctx.usersettings, optarg); break; 213 | case 7: settings_set_content_path(&ctx.usersettings, optarg); break; 214 | case 8: settings_set_exefs_dir_path(&ctx.usersettings, optarg); break; 215 | case 9: settings_set_mediaunit_size(&ctx.usersettings, strtoul(optarg, 0, 0)); break; 216 | case 10: ctx.actions |= ShowKeysFlag; break; 217 | case 11: keyset_parse_commonkey(&tmpkeys, optarg, strlen(optarg)); break; 218 | case 12: keyset_parse_ncchkey(&tmpkeys, optarg, strlen(optarg)); break; 219 | case 13: settings_set_lzss_path(&ctx.usersettings, optarg); break; 220 | case 14: settings_set_firm_dir_path(&ctx.usersettings, optarg); break; 221 | case 15: keyset_parse_ncchfixedsystemkey(&tmpkeys, optarg, strlen(optarg)); break; 222 | case 16: settings_set_wav_path(&ctx.usersettings, optarg); break; 223 | case 17: settings_set_romfs_dir_path(&ctx.usersettings, optarg); break; 224 | case 18: settings_set_list_romfs_files(&ctx.usersettings, 1); break; 225 | case 19: settings_set_cwav_loopcount(&ctx.usersettings, strtoul(optarg, 0, 0)); break; 226 | 227 | 228 | default: 229 | usage(argv[0]); 230 | } 231 | } 232 | 233 | if (optind == argc - 1) 234 | { 235 | // Exactly one extra argument - an input file 236 | strncpy(infname, argv[optind], sizeof(infname)); 237 | } 238 | else if ( (optind < argc) || (argc == 1) ) 239 | { 240 | // Too many extra args 241 | usage(argv[0]); 242 | } 243 | 244 | keyset_load(&ctx.usersettings.keys, keysetfname, (ctx.actions & VerboseFlag) | checkkeysetfile); 245 | keyset_merge(&ctx.usersettings.keys, &tmpkeys); 246 | if (ctx.actions & ShowKeysFlag) 247 | keyset_dump(&ctx.usersettings.keys); 248 | 249 | ctx.infile = fopen(infname, "rb"); 250 | 251 | if (ctx.infile == 0) 252 | { 253 | fprintf(stderr, "error: could not open input file!\n"); 254 | return -1; 255 | } 256 | 257 | fseek(ctx.infile, 0, SEEK_END); 258 | ctx.infilesize = ftell(ctx.infile); 259 | fseek(ctx.infile, 0, SEEK_SET); 260 | 261 | 262 | 263 | 264 | if (ctx.filetype == FILETYPE_UNKNOWN) 265 | { 266 | fseek(ctx.infile, 0x100, SEEK_SET); 267 | fread(&magic, 1, 4, ctx.infile); 268 | 269 | switch(getle32(magic)) 270 | { 271 | case MAGIC_NCCH: 272 | ctx.filetype = FILETYPE_CXI; 273 | break; 274 | 275 | case MAGIC_NCSD: 276 | ctx.filetype = FILETYPE_CCI; 277 | break; 278 | 279 | default: 280 | break; 281 | } 282 | } 283 | 284 | if (ctx.filetype == FILETYPE_UNKNOWN) 285 | { 286 | fseek(ctx.infile, 0, SEEK_SET); 287 | fread(magic, 1, 4, ctx.infile); 288 | 289 | switch(getle32(magic)) 290 | { 291 | case 0x2020: 292 | ctx.filetype = FILETYPE_CIA; 293 | break; 294 | 295 | case MAGIC_FIRM: 296 | ctx.filetype = FILETYPE_FIRM; 297 | break; 298 | 299 | case MAGIC_CWAV: 300 | ctx.filetype = FILETYPE_CWAV; 301 | break; 302 | 303 | case MAGIC_IVFC: 304 | ctx.filetype = FILETYPE_ROMFS; // TODO: need to determine more here.. savegames use IVFC too, but is not ROMFS. 305 | break; 306 | } 307 | } 308 | 309 | if (ctx.filetype == FILETYPE_UNKNOWN) 310 | { 311 | fprintf(stdout, "Unknown file\n"); 312 | exit(1); 313 | } 314 | 315 | 316 | switch(ctx.filetype) 317 | { 318 | case FILETYPE_CCI: 319 | { 320 | ncsd_context ncsdctx; 321 | 322 | ncsd_init(&ncsdctx); 323 | ncsd_set_file(&ncsdctx, ctx.infile); 324 | ncsd_set_size(&ncsdctx, ctx.infilesize); 325 | ncsd_set_usersettings(&ncsdctx, &ctx.usersettings); 326 | ncsd_process(&ncsdctx, ctx.actions); 327 | 328 | break; 329 | } 330 | 331 | case FILETYPE_FIRM: 332 | { 333 | firm_context firmctx; 334 | 335 | firm_init(&firmctx); 336 | firm_set_file(&firmctx, ctx.infile); 337 | firm_set_size(&firmctx, ctx.infilesize); 338 | firm_set_usersettings(&firmctx, &ctx.usersettings); 339 | firm_process(&firmctx, ctx.actions); 340 | 341 | break; 342 | } 343 | 344 | case FILETYPE_CXI: 345 | { 346 | ncch_context ncchctx; 347 | 348 | ncch_init(&ncchctx); 349 | ncch_set_file(&ncchctx, ctx.infile); 350 | ncch_set_size(&ncchctx, ctx.infilesize); 351 | ncch_set_usersettings(&ncchctx, &ctx.usersettings); 352 | ncch_process(&ncchctx, ctx.actions); 353 | 354 | break; 355 | } 356 | 357 | 358 | case FILETYPE_CIA: 359 | { 360 | cia_context ciactx; 361 | 362 | cia_init(&ciactx); 363 | cia_set_file(&ciactx, ctx.infile); 364 | cia_set_size(&ciactx, ctx.infilesize); 365 | cia_set_usersettings(&ciactx, &ctx.usersettings); 366 | cia_process(&ciactx, ctx.actions); 367 | 368 | break; 369 | } 370 | 371 | case FILETYPE_EXHEADER: 372 | { 373 | exheader_context exheaderctx; 374 | 375 | exheader_init(&exheaderctx); 376 | exheader_set_file(&exheaderctx, ctx.infile); 377 | exheader_set_size(&exheaderctx, ctx.infilesize); 378 | settings_set_ignore_programid(&ctx.usersettings, 1); 379 | 380 | exheader_set_usersettings(&exheaderctx, &ctx.usersettings); 381 | exheader_process(&exheaderctx, ctx.actions); 382 | 383 | break; 384 | } 385 | 386 | case FILETYPE_TMD: 387 | { 388 | tmd_context tmdctx; 389 | 390 | tmd_init(&tmdctx); 391 | tmd_set_file(&tmdctx, ctx.infile); 392 | tmd_set_size(&tmdctx, ctx.infilesize); 393 | tmd_set_usersettings(&tmdctx, &ctx.usersettings); 394 | tmd_process(&tmdctx, ctx.actions); 395 | 396 | break; 397 | } 398 | 399 | case FILETYPE_LZSS: 400 | { 401 | lzss_context lzssctx; 402 | 403 | lzss_init(&lzssctx); 404 | lzss_set_file(&lzssctx, ctx.infile); 405 | lzss_set_size(&lzssctx, ctx.infilesize); 406 | lzss_set_usersettings(&lzssctx, &ctx.usersettings); 407 | lzss_process(&lzssctx, ctx.actions); 408 | 409 | break; 410 | } 411 | 412 | 413 | case FILETYPE_CWAV: 414 | { 415 | cwav_context cwavctx; 416 | 417 | cwav_init(&cwavctx); 418 | cwav_set_file(&cwavctx, ctx.infile); 419 | cwav_set_size(&cwavctx, ctx.infilesize); 420 | cwav_set_usersettings(&cwavctx, &ctx.usersettings); 421 | cwav_process(&cwavctx, ctx.actions); 422 | 423 | break; 424 | } 425 | 426 | case FILETYPE_ROMFS: 427 | { 428 | romfs_context romfsctx; 429 | 430 | romfs_init(&romfsctx); 431 | romfs_set_file(&romfsctx, ctx.infile); 432 | romfs_set_size(&romfsctx, ctx.infilesize); 433 | romfs_set_usersettings(&romfsctx, &ctx.usersettings); 434 | romfs_process(&romfsctx, ctx.actions); 435 | 436 | break; 437 | } 438 | } 439 | 440 | if (ctx.infile) 441 | fclose(ctx.infile); 442 | 443 | return 0; 444 | } 445 | --------------------------------------------------------------------------------