├── common ├── utils.c └── utils.h ├── fake_np ├── Makefile ├── NPJH90126.h ├── NPJH90126 │ └── fixed.h ├── NPJH90157.h ├── NPJH90157 │ └── fixed.h ├── NPJH90252.PBP ├── NPJH90252.h ├── NPJH90252 │ ├── NPJH90252.h │ └── dpsar.h ├── fake_np.c ├── fake_np_v05.c ├── fixed.h ├── isoreader.c └── isoreader.h ├── ipl ├── Makefile └── ipl_decrypt.c ├── kirk ├── Makefile ├── amctrl.c ├── amctrl.h ├── bn.c ├── crypto.c ├── crypto.h ├── ec.c ├── ecdsa.h ├── kirk_engine.c ├── kirk_engine.h └── psp_headers.h ├── npdpc ├── Makefile ├── libccc.c ├── my_npd.c ├── npeg.c └── tlzrc.c ├── npdrm ├── Makefile ├── dnas.c ├── dnas_ida.c ├── edata.c ├── npdk_test │ ├── Makefile │ ├── lzdecode.h │ ├── my_npd.c │ ├── npeg.c │ ├── printk.c │ ├── sceAmctrl_driver.S │ └── scePspNpDrm_driver.S └── pgd.c ├── pspcipher ├── Makefile ├── keys_data.h ├── kirk.xlsx ├── prx_decrypt.c ├── pspcipher.c ├── pspcipher.h └── test_prx_decrypt.c ├── pspkg ├── Makefile ├── pspkg.c └── pspkg_fixup.c ├── sign_eboot ├── Makefile ├── readme.txt └── sign_eboot.c └── test ├── Makefile ├── edata.h └── edata_ec.c /common/utils.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | 13 | typedef unsigned char u8; 14 | 15 | /**************************************************************/ 16 | 17 | char ownisgraph (u8 c) 18 | { 19 | if ( c >= 0x21 && c <= 0x7e ) 20 | return 1; 21 | 22 | return 0; 23 | } 24 | 25 | void hex_dump(const char *str, void *addr, int size) 26 | { 27 | int i; 28 | u8 *p = (u8*)addr; 29 | 30 | if (addr == NULL) { 31 | printf("hexdump: \n"); 32 | return; 33 | } 34 | 35 | if (size == 0) { 36 | printf("hexdump: size 0\n"); 37 | return; 38 | } 39 | 40 | if(str) 41 | printf("%s:\n", str); 42 | 43 | #if 0 44 | printf("Address: "); 45 | i=0; for(;i<16; ++i) { 46 | if (i == 8) 47 | printf("- "); 48 | 49 | printf("%02X ", i); 50 | } 51 | 52 | i=0; for(;i<16; ++i) { 53 | printf("%1X", i); 54 | } 55 | 56 | printf("\n-----------------------------------------------------------------------------\n"); 57 | #endif 58 | 59 | i=0; 60 | printf("0x%08X ", i); 61 | 62 | for(; i0; --j) { 67 | if(ownisgraph(p[i-j])) { 68 | printf("%c", p[i-j]); 69 | } else { 70 | printf("."); 71 | } 72 | } 73 | printf("\n0x%08X ", i); 74 | } 75 | 76 | if (i != 0 && i % 8 == 0 && i % 16 != 0) { 77 | printf("- "); 78 | } 79 | 80 | printf("%02X ", p[i]); 81 | } 82 | 83 | int rest = (16-(i%16)); 84 | 85 | rest = rest == 16 ? 0 : rest; 86 | int j; for(j=0; j0; --j) { 96 | if(ownisgraph(p[i-j])) { 97 | printf("%c", p[i-j]); 98 | } else { 99 | printf("."); 100 | } 101 | } 102 | 103 | printf("\n\n"); 104 | } 105 | 106 | 107 | /**************************************************************/ 108 | 109 | FILE *open_file(char *name, int *size) 110 | { 111 | FILE *fp; 112 | 113 | fp = fopen(name, "rb"); 114 | if(fp==NULL){ 115 | //printf("Open file %s failed!\n", name); 116 | return NULL; 117 | } 118 | 119 | fseek(fp, 0, SEEK_END); 120 | *size = ftell(fp); 121 | fseek(fp, 0, SEEK_SET); 122 | 123 | return fp; 124 | } 125 | 126 | u8 *load_file(char *name, int *size) 127 | { 128 | FILE *fp; 129 | u8 *buf; 130 | 131 | fp = open_file(name, size); 132 | if(fp==NULL) 133 | return NULL; 134 | buf = malloc(*size); 135 | fread(buf, *size, 1, fp); 136 | fclose(fp); 137 | 138 | return buf; 139 | } 140 | 141 | int write_file(char *file, void *buf, int size) 142 | { 143 | FILE *fp; 144 | int written; 145 | 146 | fp = fopen(file, "wb"); 147 | if(fp==NULL) 148 | return -1; 149 | written = fwrite(buf, 1, size, fp); 150 | fclose(fp); 151 | 152 | return written; 153 | } 154 | 155 | /**************************************************************/ 156 | 157 | int walk_dir(char *dname, void *func_ptr, int verbose) 158 | { 159 | DIR *pdir; 160 | struct dirent *d; 161 | struct stat statbuf; 162 | char fname[256]; 163 | int i, ndir; 164 | int (*f_process_file)(char *) = func_ptr; 165 | 166 | /* process file */ 167 | memset(&statbuf, 0, sizeof(statbuf)); 168 | stat(dname, &statbuf); 169 | if((statbuf.st_mode&S_IFMT) != S_IFDIR){ 170 | if(func_ptr!=NULL) 171 | return f_process_file(dname); 172 | else 173 | return 0; 174 | } 175 | 176 | /* open directory */ 177 | pdir = opendir(dname); 178 | if(pdir==NULL){ 179 | printf("Can't open directory <%s>\n", dname); 180 | return -1; 181 | } 182 | 183 | /* get number of files in dircetory */ 184 | ndir = 0; 185 | while((d=readdir(pdir))){ 186 | ndir++; 187 | } 188 | d = malloc(sizeof(struct dirent)*ndir); 189 | 190 | /* read dirent first */ 191 | rewinddir(pdir); 192 | for(i=0; i ...\n", dname); 199 | for(i=0; i ...\n", dname); 212 | 213 | free(d); 214 | closedir(pdir); 215 | return 0; 216 | } 217 | 218 | /**************************************************************/ 219 | 220 | void mkdir_p(char *dname) 221 | { 222 | char name[256]; 223 | char *p, *cp; 224 | 225 | strcpy(name, dname); 226 | 227 | cp = name; 228 | while(1){ 229 | p = strchr(cp, '/'); 230 | if(p==NULL) 231 | p = strchr(cp, '\\'); 232 | if(p==NULL) 233 | break; 234 | 235 | *p = 0; 236 | //mkdir(name, 0777); 237 | mkdir(name); 238 | *p = '/'; 239 | cp = p+1; 240 | }; 241 | } 242 | 243 | 244 | /**************************************************************/ 245 | 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /common/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 5 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 6 | #define NELEMS(a) (sizeof(a) / sizeof(a[0])) 7 | 8 | void hex_dump(const char *str, void *addr, int size); 9 | 10 | 11 | FILE *open_file(char *name, int *size); 12 | u8 *load_file(char *name, int *size); 13 | int write_file(char *file, void *buf, int size); 14 | 15 | int walk_dir(char *dname, void *func_ptr, int verbose); 16 | void mkdir_p(char *dname); 17 | 18 | #endif 19 | 20 | -------------------------------------------------------------------------------- /fake_np/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -I../kirk -I../common 3 | TARGET = fake_np 4 | OBJS = fake_np.o isoreader.o ../common/utils.o ../npdpc/tlzrc.o 5 | 6 | ifeq ($(DEBUG), 1) 7 | CFLAGS+=-g -O0 8 | else 9 | CFLAGS+=-O2 10 | endif 11 | 12 | all: $(TARGET) 13 | 14 | $(TARGET): $(OBJS) 15 | $(CC) $(CFLAGS) -o $@ $(OBJS) -L ../kirk -lkirk -lz 16 | 17 | clean: 18 | $(RM) *.o $(TARGET) *.exe *.exe.stackdump 19 | -------------------------------------------------------------------------------- /fake_np/NPJH90252.PBP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpunix/kirk_engine/ee09e86b743d1c147579ff21f46dd0874303daf3/fake_np/NPJH90252.PBP -------------------------------------------------------------------------------- /fake_np/NPJH90252/dpsar.h: -------------------------------------------------------------------------------- 1 | #ifndef __data_psar__ 2 | #define __data_psar__ 3 | 4 | static unsigned char data_psar[] __attribute__((aligned(16))) = { 5 | 0x4e, 0x50, 0x55, 0x4d, 0x44, 0x49, 0x4d, 0x47, 0x03, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 6 | 0x4a, 0x50, 0x30, 0x30, 0x38, 0x32, 0x2d, 0x4e, 0x50, 0x4a, 0x48, 0x39, 0x30, 0x32, 0x35, 0x32, 7 | 0x5f, 0x30, 0x30, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 8 | 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 9 | 0x50, 0xd5, 0x94, 0xa7, 0x0b, 0xf5, 0x35, 0x2e, 0xea, 0x5f, 0x85, 0xfc, 0xd1, 0x06, 0xec, 0x94, 10 | 0x19, 0x67, 0x79, 0x1a, 0x2d, 0x65, 0x84, 0x82, 0x76, 0x4e, 0x50, 0xc0, 0x27, 0xbf, 0x4b, 0xde, 11 | 0x66, 0xd5, 0x5c, 0xb2, 0xdc, 0xd2, 0x39, 0x49, 0x2b, 0xab, 0x99, 0x34, 0x47, 0x8b, 0x07, 0xda, 12 | 0x14, 0x99, 0x6b, 0xff, 0x5d, 0xd1, 0x44, 0x37, 0x61, 0xab, 0x6f, 0x86, 0xff, 0x18, 0x8e, 0x28, 13 | 0xe0, 0x50, 0x1f, 0x48, 0x59, 0xfa, 0xf9, 0xf3, 0x10, 0x9b, 0xa1, 0x88, 0x27, 0x52, 0x42, 0x69, 14 | 0x94, 0x9d, 0x69, 0x72, 0x94, 0x02, 0x7a, 0x31, 0xeb, 0xce, 0x02, 0x2e, 0xe5, 0x7f, 0x14, 0x99, 15 | 0x5d, 0x4b, 0xeb, 0x01, 0x03, 0x94, 0xe7, 0xb1, 0xf8, 0x42, 0x3f, 0xd0, 0x10, 0x24, 0xa0, 0xef, 16 | 0xe1, 0x83, 0x49, 0x7f, 0x1f, 0x15, 0x4d, 0x2e, 0x20, 0x7c, 0x0e, 0x83, 0x5f, 0x1a, 0x03, 0xce, 17 | 0x7a, 0xfb, 0xd6, 0x5c, 0x84, 0x03, 0xae, 0xe1, 0xc7, 0xef, 0xce, 0x2a, 0x77, 0x82, 0xff, 0x4c, 18 | 0x9e, 0x23, 0x2a, 0xd5, 0xd9, 0xdd, 0xac, 0xac, 0x01, 0x3d, 0xb0, 0x5b, 0xc9, 0x31, 0x9e, 0x74, 19 | 0x59, 0x52, 0xf5, 0xc7, 0x28, 0x7d, 0x40, 0xf1, 0x54, 0x97, 0xf2, 0xf0, 0x7a, 0x89, 0x63, 0xfa, 20 | 0x70, 0xe6, 0xe9, 0xdf, 0x61, 0xfc, 0xe3, 0x33, 0xa0, 0x30, 0xc5, 0xf5, 0x53, 0xc0, 0x86, 0x8a, 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /fake_np/fake_np_v05.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fake_np.c -- make a fake NPdemo package 3 | * written by tpu. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include "utils.h" 10 | 11 | #include "kirk_engine.h" 12 | #include "amctrl.h" 13 | #include "fixed.h" 14 | 15 | #include "isoreader.h" 16 | 17 | /*************************************************************/ 18 | 19 | static u8 zero_lz[0x50] = { 20 | 0x05, 0xff, 0x80, 0x01, 0x0e, 0xd6, 0xe7, 0x37, 0x04, 0x3f, 0x53, 0x0b, 0xbc, 0xe7, 0xa3, 0x72, 21 | 0x14, 0xdc, 0x38, 0x8e, 0x0c, 0xaa, 0x94, 0x93, 0x46, 0xbf, 0xf8, 0x72, 0x15, 0x04, 0x7e, 0x9c, 22 | 0xe0, 0xec, 0x8b, 0x6c, 0x7d, 0xee, 0xf0, 0x7a, 0x90, 0x91, 0x0e, 0xb3, 0xc7, 0x8b, 0xd8, 0x08, 23 | 0x9d, 0x68, 0x09, 0xe5, 0x9e, 0xfe, 0x43, 0x03, 0x5b, 0x0b, 0x7c, 0x52, 0xe4, 0xfe, 0xfe, 0x66, 24 | 0x26, 0xe5, 0xcc, 0x83, 0xfc, 0x55, 0x16, 0xd2, 0x5e, 0x92, 0x00, 0x00, 0x8a, 0xed, 0x5e, 0x1a, 25 | }; 26 | 27 | /*************************************************************/ 28 | 29 | FILE *open_file(char *name, int *size) 30 | { 31 | FILE *fp; 32 | 33 | fp = fopen(name, "rb"); 34 | if(fp==NULL){ 35 | //printf("Open file %s failed!\n", name); 36 | return NULL; 37 | } 38 | 39 | fseek(fp, 0, SEEK_END); 40 | *size = ftell(fp); 41 | fseek(fp, 0, SEEK_SET); 42 | 43 | return fp; 44 | } 45 | 46 | u8 *load_file_from_ISO(const char *iso, char *name, int *size) 47 | { 48 | int ret; 49 | u32 lba; 50 | u8 *buf; 51 | 52 | ret = isoOpen(iso); 53 | if (ret < 0) { 54 | return NULL; 55 | } 56 | 57 | ret = isoGetFileInfo(name, (u32*)size, &lba); 58 | if (ret < 0) { 59 | isoClose(); 60 | return NULL; 61 | } 62 | 63 | buf = malloc(*size); 64 | if (buf == NULL) { 65 | isoClose(); 66 | return NULL; 67 | } 68 | 69 | ret = isoRead(buf, lba, 0, *size); 70 | if (ret < 0) { 71 | isoClose(); 72 | return NULL; 73 | } 74 | 75 | isoClose(); 76 | return buf; 77 | } 78 | 79 | int write_file(char *file, void *buf, int size) 80 | { 81 | FILE *fp; 82 | int written; 83 | 84 | fp = fopen(file, "wb"); 85 | if(fp==NULL) 86 | return -1; 87 | written = fwrite(buf, 1, size, fp); 88 | fclose(fp); 89 | 90 | return written; 91 | } 92 | 93 | int main(int argc, char *argv[]) 94 | { 95 | MAC_KEY mkey; 96 | CIPHER_KEY ckey; 97 | FILE *fp; 98 | u8 fixed_key[16], tmp_header[256]; 99 | u8 *np_buf, *pbp_header, *tb; 100 | u8 *ico0_buf, *ico1_buf, *pic0_buf, *pic1_buf, *snd0_buf; 101 | int i, block_size, iso_block, offset, header_size; 102 | int ico0_size, ico1_size, pic0_size, pic1_size, snd0_size, iso_size, np_size; 103 | int start, end, lba_size, total_block; 104 | 105 | ico0_size = 0; 106 | ico1_size = 0; 107 | pic0_size = 0; 108 | pic1_size = 0; 109 | snd0_size = 0; 110 | iso_size = 0; 111 | 112 | printf("fake_np v0.5 by tpu\n\n"); 113 | 114 | kirk_init(); 115 | // test Cipher 116 | memcpy(tmp_header, np_header, sizeof(tmp_header)); 117 | 118 | sceNpDrmGetFixedKey(fixed_key, (char*)np_header+0x10, *(int*)(np_header+0x08)); 119 | sceDrmBBCipherInit(&ckey, 1, 2, np_header+0xa0, fixed_key, 0); 120 | sceDrmBBCipherUpdate(&ckey, tmp_header+0x40, 0x60); 121 | sceDrmBBCipherFinal(&ckey); 122 | 123 | block_size = *(u32*)(np_header+0x0c); 124 | start = *(u32*)(tmp_header+0x54); 125 | end = *(u32*)(tmp_header+0x64); 126 | lba_size = end-start+1; 127 | total_block = (lba_size+block_size-1)/block_size; 128 | 129 | // build NPUMDIMG 130 | fp = open_file("np.iso", &iso_size); 131 | 132 | if(fp==NULL){ 133 | printf("Open np.iso faield!\n"); 134 | return -1; 135 | } 136 | 137 | block_size *= 2048; 138 | 139 | if(iso_size>(total_block-1)*block_size){ 140 | printf("ISO file too big! %d>%d\n", iso_size, (total_block-1)*block_size); 141 | fclose(fp); 142 | return -1; 143 | } 144 | 145 | printf("Load np.iso ...\n"); 146 | 147 | np_size = 0x0100+total_block*(block_size+0x20); 148 | np_buf = malloc(np_size); 149 | 150 | if (np_buf == NULL) { 151 | printf("np_buf: cannot allocate %d bytes\n", np_size); 152 | fclose(fp); 153 | return -2; 154 | } 155 | 156 | memset(np_buf, 0, np_size); 157 | 158 | iso_block = iso_size/block_size; 159 | offset = 0x0100+total_block*0x20; 160 | 161 | fread(np_buf+offset, iso_size, 1, fp); 162 | fclose(fp); 163 | 164 | memcpy(np_buf, np_header, 0x0100); 165 | 166 | // build lookup table 167 | for(i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "utils.h" 9 | 10 | typedef unsigned char u8; 11 | typedef unsigned short u16; 12 | typedef unsigned int u32; 13 | typedef unsigned long long u64; 14 | 15 | #include "isoreader.h" 16 | 17 | #define MAX_RETRIES 1 18 | #define MAX_DIR_LEVEL 8 19 | #define CISO_IDX_BUFFER_SIZE 0x200 20 | #define CISO_DEC_BUFFER_SIZE 0x2000 21 | #define ISO_STANDARD_ID "CD001" 22 | 23 | typedef struct _CISOHeader { 24 | u8 magic[4]; /* +00 : 'C','I','S','O' */ 25 | u32 header_size; 26 | u64 total_bytes; /* +08 : number of original data size */ 27 | u32 block_size; /* +10 : number of compressed block size */ 28 | u8 ver; /* +14 : version 01 */ 29 | u8 align; /* +15 : align of index (offset = index[n]< 0) { 78 | fp = fopen(g_filename, "rb"); 79 | if(fp){ 80 | break; 81 | } 82 | } 83 | 84 | if (fp >= 0) { 85 | g_isofp = fp; 86 | } 87 | 88 | return fp; 89 | } 90 | 91 | static int readRawData(void* addr, u32 size, int offset) 92 | { 93 | int ret, i; 94 | 95 | for(i=0; i= 0) { 98 | break; 99 | } else { 100 | printf("%s: got error 0x%08X, reOpening ISO: %s\n", __func__, ret, g_filename); 101 | } 102 | } 103 | 104 | for(i=0; i= 0) { 107 | break; 108 | } else { 109 | printf("%s: got error 0x%08X, reOpening ISO: %s\n", __func__, ret, g_filename); 110 | } 111 | } 112 | 113 | return ret; 114 | } 115 | 116 | static int gzip_decompress(void *dst, int dst_size, void *src, int src_size) 117 | { 118 | z_stream strm; 119 | int ret; 120 | 121 | memset(&strm, 0, sizeof(strm)); 122 | 123 | strm.next_in = src; 124 | strm.avail_in = src_size; 125 | strm.next_out = dst; 126 | strm.avail_out = dst_size; 127 | 128 | ret = inflateInit2(&strm, -15); 129 | 130 | if (ret != Z_OK) { 131 | return -1; 132 | } 133 | 134 | ret = inflate(&strm, Z_FINISH); 135 | 136 | if (ret != Z_STREAM_END) { 137 | return -2; 138 | } 139 | 140 | inflateEnd(&strm); 141 | 142 | return strm.total_out; 143 | } 144 | 145 | static int readSectorCompressed(int sector, void *addr) 146 | { 147 | int ret; 148 | int n_sector; 149 | int offset, next_offset; 150 | int size; 151 | 152 | n_sector = sector - g_CISO_cur_idx; 153 | 154 | // not within sector idx cache? 155 | if (g_CISO_cur_idx == -1 || n_sector < 0 || n_sector >= NELEMS(g_CISO_idx_cache)) { 156 | ret = readRawData(g_CISO_idx_cache, sizeof(g_CISO_idx_cache), 157 | (sector << 2) + sizeof(CISOHeader)); 158 | 159 | if (ret < 0) { 160 | return ret; 161 | } 162 | 163 | g_CISO_cur_idx = sector; 164 | n_sector = 0; 165 | } 166 | 167 | offset = (g_CISO_idx_cache[n_sector] & 0x7FFFFFFF) << g_ciso_h.align; 168 | 169 | // is uncompressed data? 170 | if (g_CISO_idx_cache[n_sector] & 0x80000000) { 171 | return readRawData(addr, SECTOR_SIZE, offset); 172 | } 173 | 174 | sector++; 175 | n_sector = sector - g_CISO_cur_idx; 176 | 177 | if (g_CISO_cur_idx == -1 || n_sector < 0 || n_sector >= NELEMS(g_CISO_idx_cache)) { 178 | ret = readRawData(g_CISO_idx_cache, sizeof(g_CISO_idx_cache), (sector << 2) + sizeof(CISOHeader)); 179 | 180 | if (ret < 0) { 181 | return ret; 182 | } 183 | 184 | g_CISO_cur_idx = sector; 185 | n_sector = 0; 186 | } 187 | 188 | next_offset = (g_CISO_idx_cache[n_sector] & 0x7FFFFFFF) << g_ciso_h.align; 189 | size = next_offset - offset; 190 | 191 | if (size <= SECTOR_SIZE) 192 | size = SECTOR_SIZE; 193 | 194 | if (offset < g_ciso_dec_buf_offset || size + offset >= g_ciso_dec_buf_offset + CISO_DEC_BUFFER_SIZE) { 195 | ret = readRawData(g_ciso_dec_buf, CISO_DEC_BUFFER_SIZE, offset); 196 | 197 | if (ret < 0) { 198 | g_ciso_dec_buf_offset = 0xFFF00000; 199 | 200 | return ret; 201 | } 202 | 203 | g_ciso_dec_buf_offset = offset; 204 | } 205 | 206 | ret = gzip_decompress(addr, SECTOR_SIZE, 207 | g_ciso_dec_buf + offset - g_ciso_dec_buf_offset, size 208 | ); 209 | 210 | return ret; 211 | } 212 | 213 | static int readSector(u32 sector, void *buf) 214 | { 215 | int ret; 216 | u32 pos; 217 | 218 | if (g_is_compressed) { 219 | ret = readSectorCompressed(sector, buf); 220 | } else { 221 | pos = isoLBA2Pos(sector, 0); 222 | ret = readRawData(buf, SECTOR_SIZE, pos); 223 | } 224 | 225 | return ret; 226 | } 227 | 228 | static void normalizeName(char *filename) 229 | { 230 | char *p; 231 | 232 | p = strstr(filename, ";1"); 233 | 234 | if (p) { 235 | *p = '\0'; 236 | } 237 | } 238 | 239 | static int findFile(const char * file, u32 lba, u32 dir_size, u32 is_dir, Iso9660DirectoryRecord *result_record) 240 | { 241 | u32 pos; 242 | int ret; 243 | Iso9660DirectoryRecord *rec; 244 | char name[32]; 245 | int re; 246 | 247 | pos = isoLBA2Pos(lba, 0); 248 | re = lba = 0; 249 | 250 | while ( re < dir_size ) { 251 | if (isoPos2LBA(pos) != lba) { 252 | lba = isoPos2LBA(pos); 253 | ret = readSector(lba, g_sector_buffer); 254 | 255 | if (ret < 0) { 256 | return ret; 257 | } 258 | } 259 | 260 | rec = (Iso9660DirectoryRecord*)&g_sector_buffer[isoPos2OffsetInSector(pos)]; 261 | 262 | if(rec->len_dr == 0) { 263 | u32 remaining; 264 | 265 | remaining = isoPos2RestSize(pos); 266 | pos += remaining; 267 | re += remaining; 268 | continue; 269 | } 270 | 271 | if(rec->len_dr < rec->len_fi + sizeof(*rec)) { 272 | printf("%s: Corrupt directory record found in %s, LBA %d\n", __func__, g_filename, lba); 273 | 274 | return -12; 275 | } 276 | 277 | if(rec->len_fi > 32) { 278 | return -11; 279 | } 280 | 281 | if(rec->len_fi == 1 && rec->fi == 0) { 282 | if (0 == strcmp(file, ".")) { 283 | memcpy(result_record, rec, sizeof(*result_record)); 284 | 285 | return 0; 286 | } 287 | } else if(rec->len_fi == 1 && rec->fi == 1) { 288 | if (0 == strcmp(file, "..")) { 289 | // didn't support .. 290 | return -19; 291 | } 292 | } else { 293 | memset(name, 0, sizeof(name)); 294 | memcpy(name, &rec->fi, rec->len_fi); 295 | normalizeName(name); 296 | 297 | if (0 == strcmp(name, file)) { 298 | if (is_dir) { 299 | if(!rec->fileFlags & ISO9660_FILEFLAGS_DIR) { 300 | return -14; 301 | } 302 | } 303 | 304 | memcpy(result_record, rec, sizeof(*result_record)); 305 | 306 | return 0; 307 | } 308 | } 309 | 310 | pos += rec->len_dr; 311 | re += rec->len_dr; 312 | } 313 | 314 | return -18; 315 | } 316 | 317 | static int findPath(const char *path, Iso9660DirectoryRecord *result_record) 318 | { 319 | int level = 0, ret; 320 | const char *cur_path, *next; 321 | u32 lba, dir_size; 322 | char cur_dir[32]; 323 | 324 | if (result_record == NULL) { 325 | return -17; 326 | } 327 | 328 | memset(result_record, 0, sizeof(*result_record)); 329 | lba = g_root_record.lsbStart; 330 | dir_size = g_root_record.lsbDataLength; 331 | 332 | cur_path = path; 333 | 334 | while(*cur_path == '/') { 335 | cur_path++; 336 | } 337 | 338 | next = strchr(cur_path, '/'); 339 | 340 | while (next != NULL) { 341 | if (next-cur_path >= sizeof(cur_dir)) { 342 | return -15; 343 | } 344 | 345 | memset(cur_dir, 0, sizeof(cur_dir)); 346 | strncpy(cur_dir, cur_path, next-cur_path); 347 | cur_dir[next-cur_path] = '\0'; 348 | 349 | if (0 == strcmp(cur_dir, ".")) { 350 | } else if (0 == strcmp(cur_dir, "..")) { 351 | level--; 352 | } else { 353 | level++; 354 | } 355 | 356 | if(level > MAX_DIR_LEVEL) { 357 | return -16; 358 | } 359 | 360 | ret = findFile(cur_dir, lba, dir_size, 1, result_record); 361 | 362 | if (ret < 0) { 363 | return ret; 364 | } 365 | 366 | lba = result_record->lsbStart; 367 | dir_size = result_record->lsbDataLength; 368 | 369 | cur_path=next+1; 370 | 371 | // skip unwant path separator 372 | while(*cur_path == '/') { 373 | cur_path++; 374 | } 375 | 376 | next = strchr(cur_path, '/'); 377 | } 378 | 379 | ret = findFile(cur_path, lba, dir_size, 0, result_record); 380 | 381 | return ret; 382 | } 383 | 384 | int isoOpen(const char *path) 385 | { 386 | int ret; 387 | 388 | if (g_isofp != NULL) { 389 | isoClose(); 390 | } 391 | 392 | g_filename = path; 393 | 394 | if (reOpen() == NULL) { 395 | printf("%s: open failed %s\n", __func__, g_filename); 396 | ret = -2; 397 | goto error; 398 | } 399 | 400 | fseek(g_isofp, 0, SEEK_SET); 401 | memset(&g_ciso_h, 0, sizeof(g_ciso_h)); 402 | ret = fread(&g_ciso_h, sizeof(g_ciso_h), 1, g_isofp); 403 | if (ret != 1) { 404 | ret = -9; 405 | goto error; 406 | } 407 | 408 | if (*(u32*)g_ciso_h.magic == 0x4F534943 && g_ciso_h.block_size == SECTOR_SIZE) { 409 | g_is_compressed = 1; 410 | } else { 411 | g_is_compressed = 0; 412 | } 413 | 414 | if (g_is_compressed) { 415 | g_total_sectors = g_ciso_h.total_bytes / g_ciso_h.block_size; 416 | g_CISO_cur_idx = -1; 417 | 418 | if (g_ciso_dec_buf == NULL) { 419 | g_ciso_dec_buf = malloc(CISO_DEC_BUFFER_SIZE); 420 | 421 | if (g_ciso_dec_buf == NULL) { 422 | printf("malloc -> 0x%08x\n", (u32)g_ciso_dec_buf); 423 | ret = -6; 424 | goto error; 425 | } 426 | } 427 | 428 | memset(g_CISO_idx_cache, 0, sizeof(g_CISO_idx_cache)); 429 | g_ciso_dec_buf_offset = -1; 430 | g_CISO_cur_idx = -1; 431 | } else { 432 | g_total_sectors = isoGetSize(); 433 | } 434 | 435 | ret = readSector(16, g_sector_buffer); 436 | 437 | if (ret < 0) { 438 | ret = -7; 439 | goto error; 440 | } 441 | 442 | if (memcmp(&g_sector_buffer[1], ISO_STANDARD_ID, sizeof(ISO_STANDARD_ID)-1)) { 443 | printf("%s: vol descriptor not found\n", __func__); 444 | ret = -10; 445 | 446 | goto error; 447 | } 448 | 449 | memcpy(&g_root_record, &g_sector_buffer[0x9C], sizeof(g_root_record)); 450 | 451 | return 0; 452 | 453 | error: 454 | if (g_isofp >= 0) { 455 | isoClose(); 456 | } 457 | 458 | return ret; 459 | } 460 | 461 | int isoGetSize(void) 462 | { 463 | int ret, size; 464 | 465 | ret = ftell(g_isofp); 466 | 467 | fseek(g_isofp, 0, SEEK_END); 468 | size = ftell(g_isofp); 469 | 470 | fseek(g_isofp, ret, SEEK_SET); 471 | 472 | return isoPos2LBA(size); 473 | } 474 | 475 | void isoClose(void) 476 | { 477 | fclose(g_isofp); 478 | g_isofp = NULL; 479 | g_filename = NULL; 480 | 481 | if (g_ciso_dec_buf != NULL) { 482 | free(g_ciso_dec_buf); 483 | g_ciso_dec_buf = NULL; 484 | } 485 | } 486 | 487 | int isoGetFileInfo(char * path, u32 *filesize, u32 *lba) 488 | { 489 | int ret; 490 | Iso9660DirectoryRecord rec; 491 | 492 | ret = findPath(path, &rec); 493 | 494 | if (ret < 0) { 495 | return ret; 496 | } 497 | 498 | *lba = rec.lsbStart; 499 | 500 | if (filesize != NULL) { 501 | *filesize = rec.lsbDataLength; 502 | } 503 | 504 | return 0; 505 | } 506 | 507 | int isoRead(void *buffer, u32 lba, int offset, u32 size) 508 | { 509 | u32 remaining; 510 | u32 pos, copied; 511 | u32 re; 512 | int ret; 513 | 514 | remaining = size; 515 | pos = isoLBA2Pos(lba, offset); 516 | copied = 0; 517 | 518 | while(remaining > 0) { 519 | ret = readSector(isoPos2LBA(pos), g_sector_buffer); 520 | 521 | if (ret < 0) { 522 | break; 523 | } 524 | 525 | re = MIN(isoPos2RestSize(pos), remaining); 526 | memcpy(buffer+copied, g_sector_buffer+isoPos2OffsetInSector(pos), re); 527 | remaining -= re; 528 | pos += re; 529 | copied += re; 530 | } 531 | 532 | return copied; 533 | } 534 | 535 | -------------------------------------------------------------------------------- /fake_np/isoreader.h: -------------------------------------------------------------------------------- 1 | #ifndef _ISOREADER_H_ 2 | #define _ISOREADER_H_ 3 | 4 | #define SECTOR_SIZE 0x800 5 | 6 | #define ISO9660_FILEFLAGS_FILE 1 7 | #define ISO9660_FILEFLAGS_DIR 2 8 | 9 | typedef struct __attribute__((packed)) 10 | { 11 | /* Directory record length. */ 12 | u8 len_dr; 13 | /* Extended attribute record length. */ 14 | u8 XARlength; 15 | /* First logical block where file starts. */ 16 | u32 lsbStart; 17 | u32 msbStart; 18 | /* Number of bytes in file. */ 19 | u32 lsbDataLength; 20 | u32 msbDataLength; 21 | /* Since 1900. */ 22 | u8 year; 23 | u8 month; 24 | u8 day; 25 | u8 hour; 26 | u8 minute; 27 | u8 second; 28 | /* 15-minute offset from Universal Time. */ 29 | u8 gmtOffse; 30 | /* Attributes of a file or directory. */ 31 | u8 fileFlags; 32 | /* Used for interleaved files. */ 33 | u8 interleaveSize; 34 | /* Used for interleaved files. */ 35 | u8 interleaveSkip; 36 | /* Which volume in volume set contains this file. */ 37 | u16 lsbVolSetSeqNum; 38 | u16 msbVolSetSeqNum; 39 | /* Length of file identifier that follows. */ 40 | u8 len_fi; 41 | /* File identifier: actual is len_fi. */ 42 | /* Contains extra blank byte if len_fi odd. */ 43 | char fi; 44 | } Iso9660DirectoryRecord; 45 | 46 | int isoOpen(const char *path); 47 | 48 | void isoClose(void); 49 | 50 | int isoGetSize(void); 51 | 52 | //get file information 53 | int isoGetFileInfo(char * str, u32 * filesize, u32 *lba); 54 | 55 | //read raw data from iso 56 | int isoRead(void *buffer, u32 lba, int offset, u32 size); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /ipl/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -g -O0 -I../kirk 3 | TARGET = ipld 4 | OBJS = ipl_decrypt.o 5 | 6 | all: $(TARGET) 7 | 8 | $(TARGET): $(OBJS) 9 | $(CC) $(CFLAGS) -o $@ $(OBJS) -L ../kirk -lkirk 10 | 11 | clean: 12 | $(RM) *.o $(TARGET) *.exe *.exe.stackdump 13 | -------------------------------------------------------------------------------- /ipl/ipl_decrypt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "kirk_engine.h" 5 | 6 | //IPL-DECRYPTER SAMPLE 7 | 8 | typedef struct 9 | { 10 | void *loadaddr; 11 | u32 blocksize; 12 | void (* entry)(void); 13 | u32 checksum; 14 | u8 data[0xF50]; 15 | } IplBlock; 16 | 17 | void printHEX(int hex) 18 | { 19 | if(hex < 0x10) printf("0%X", hex); 20 | else printf("%X", hex); 21 | } 22 | 23 | void PrintKIRK1Header(u8* buf) 24 | { 25 | KIRK_CMD1_HEADER* header = (KIRK_CMD1_HEADER*)buf; 26 | printf("AES encrypted key:\n"); 27 | int i; 28 | for(i = 0; i < 16; i++) 29 | { 30 | printHEX(header->AES_key[i]); 31 | } 32 | printf("\nCMAC encrypted key:\n"); 33 | for(i = 0; i < 16; i++) 34 | { 35 | printHEX(header->CMAC_key[i]); 36 | } 37 | printf("\nCMAC header hash:\n"); 38 | for(i = 0; i < 16; i++) 39 | { 40 | printHEX(header->CMAC_header_hash[i]); 41 | } 42 | printf("\nCMAC data hash:\n"); 43 | for(i = 0; i < 16; i++) 44 | { 45 | printHEX(header->CMAC_data_hash[i]); 46 | } 47 | printf("\nmode: %d, data_size 0x%X, data_offset 0x%X\n", header->mode, header->data_size, header->data_offset); 48 | } 49 | 50 | int DecryptIplBlock(void *dst, const void *src) 51 | { 52 | //PrintKIRK1Header((void*)src); 53 | int ret = kirk_CMD1(dst, (void*)src, 0x1000); 54 | if(ret == KIRK_NOT_ENABLED){ printf("KIRK not enabled!\n"); return -1;} 55 | else if(ret == KIRK_INVALID_MODE){ printf("Mode in header not CMD1\n"); return -1;} 56 | else if(ret == KIRK_HEADER_HASH_INVALID){ printf("header hash check failed\n"); return -1;} 57 | else if(ret == KIRK_DATA_HASH_INVALID){ printf("data hash check failed\n"); return -1;} 58 | else if(ret == KIRK_DATA_SIZE_ZERO){ printf("data size = 0\n"); return -1;} 59 | return 0; 60 | } 61 | 62 | u32 _memcpy(void *dst, const void *src, int size) 63 | { 64 | int i; 65 | u32 checksum = 0; 66 | 67 | for (i=0; i 7 | #include 8 | #include 9 | 10 | #include "crypto.h" 11 | #include "kirk_engine.h" 12 | #include "psp_headers.h" 13 | #include "amctrl.h" 14 | 15 | /*************************************************************/ 16 | 17 | static u8 loc_1CD4[16] = {0xE3, 0x50, 0xED, 0x1D, 0x91, 0x0A, 0x1F, 0xD0, 0x29, 0xBB, 0x1C, 0x3E, 0xF3, 0x40, 0x77, 0xFB}; 18 | static u8 loc_1CE4[16] = {0x13, 0x5F, 0xA4, 0x7C, 0xAB, 0x39, 0x5B, 0xA4, 0x76, 0xB8, 0xCC, 0xA9, 0x8F, 0x3A, 0x04, 0x45}; 19 | static u8 loc_1CF4[16] = {0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E}; 20 | 21 | static u8 kirk_buf[0x0814]; // 1DC0 1DD4 22 | 23 | /*************************************************************/ 24 | 25 | static int kirk4(u8 *buf, int size, int type) 26 | { 27 | int retv; 28 | u32 *header = (u32*)buf; 29 | 30 | header[0] = 4; 31 | header[1] = 0; 32 | header[2] = 0; 33 | header[3] = type; 34 | header[4] = size; 35 | 36 | retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 4); 37 | 38 | if(retv) 39 | return 0x80510311; 40 | 41 | return 0; 42 | } 43 | 44 | static int kirk7(u8 *buf, int size, int type) 45 | { 46 | int retv; 47 | u32 *header = (u32*)buf; 48 | 49 | header[0] = 5; 50 | header[1] = 0; 51 | header[2] = 0; 52 | header[3] = type; 53 | header[4] = size; 54 | 55 | retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 7); 56 | if(retv) 57 | return 0x80510311; 58 | 59 | return 0; 60 | } 61 | 62 | static int kirk5(u8 *buf, int size) 63 | { 64 | int retv; 65 | u32 *header = (u32*)buf; 66 | 67 | header[0] = 4; 68 | header[1] = 0; 69 | header[2] = 0; 70 | header[3] = 0x0100; 71 | header[4] = size; 72 | 73 | retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 5); 74 | if(retv) 75 | return 0x80510312; 76 | 77 | return 0; 78 | } 79 | 80 | static int kirk8(u8 *buf, int size) 81 | { 82 | int retv; 83 | u32 *header = (u32*)buf; 84 | 85 | header[0] = 5; 86 | header[1] = 0; 87 | header[2] = 0; 88 | header[3] = 0x0100; 89 | header[4] = size; 90 | 91 | retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 8); 92 | if(retv) 93 | return 0x80510312; 94 | 95 | return 0; 96 | } 97 | 98 | static int kirk14(u8 *buf) 99 | { 100 | int retv; 101 | 102 | retv = sceUtilsBufferCopyWithRange(buf, 0x14, 0, 0, 14); 103 | if(retv) 104 | return 0x80510315; 105 | 106 | return 0; 107 | } 108 | 109 | /*************************************************************/ 110 | 111 | // Called by sceDrmBBMacUpdate 112 | // encrypt_buf 113 | static int sub_158(u8 *buf, int size, u8 *key, int key_type) 114 | { 115 | int i, retv; 116 | 117 | for(i=0; i<16; i++){ 118 | buf[0x14+i] ^= key[i]; 119 | } 120 | 121 | retv = kirk4(buf, size, key_type); 122 | if(retv) 123 | return retv; 124 | 125 | // copy last 16 bytes to keys 126 | memcpy(key, buf+size+4, 16); 127 | 128 | return 0; 129 | } 130 | 131 | 132 | // type: 133 | // 2: use fuse id 134 | // 3: use fixed id 135 | int sceDrmBBMacInit(MAC_KEY *mkey, int type) 136 | { 137 | mkey->type = type; 138 | mkey->pad_size = 0; 139 | 140 | memset(mkey->key, 0, 16); 141 | memset(mkey->pad, 0, 16); 142 | 143 | return 0; 144 | } 145 | 146 | int sceDrmBBMacUpdate(MAC_KEY *mkey, u8 *buf, int size) 147 | { 148 | int retv = 0, ksize, p, type; 149 | u8 *kbuf; 150 | 151 | if(mkey->pad_size>16){ 152 | retv = 0x80510302; 153 | goto _exit; 154 | } 155 | 156 | if(mkey->pad_size+size<=16){ 157 | memcpy(mkey->pad+mkey->pad_size, buf, size); 158 | mkey->pad_size += size; 159 | retv = 0; 160 | }else{ 161 | kbuf = kirk_buf+0x14; 162 | // copy pad data first 163 | memcpy(kbuf, mkey->pad, mkey->pad_size); 164 | 165 | p = mkey->pad_size; 166 | 167 | mkey->pad_size += size; 168 | mkey->pad_size &= 0x0f; 169 | if(mkey->pad_size==0) 170 | mkey->pad_size = 16; 171 | 172 | size -= mkey->pad_size; 173 | // save last data to pad buf 174 | memcpy(mkey->pad, buf+size, mkey->pad_size); 175 | 176 | type = (mkey->type==2)? 0x3A : 0x38; 177 | 178 | while(size){ 179 | ksize = (size+p>=0x0800)? 0x0800 : size+p; 180 | memcpy(kbuf+p, buf, ksize-p); 181 | retv = sub_158(kirk_buf, ksize, mkey->key, type); 182 | if(retv) 183 | goto _exit; 184 | size -= (ksize-p); 185 | buf += ksize-p; 186 | p = 0; 187 | } 188 | } 189 | 190 | _exit: 191 | return retv; 192 | 193 | } 194 | 195 | int sceDrmBBMacFinal(MAC_KEY *mkey, u8 *buf, u8 *vkey) 196 | { 197 | int i, retv, code; 198 | u8 *kbuf, tmp[16], tmp1[16]; 199 | u32 t0, v0, v1; 200 | 201 | if(mkey->pad_size>16) 202 | return 0x80510302; 203 | 204 | code = (mkey->type==2)? 0x3A : 0x38; 205 | kbuf = kirk_buf+0x14; 206 | 207 | memset(kbuf, 0, 16); 208 | retv = kirk4(kirk_buf, 16, code); 209 | if(retv) 210 | goto _exit; 211 | memcpy(tmp, kbuf, 16); 212 | 213 | // left shift tmp 1 bit 214 | t0 = (tmp[0]&0x80)? 0x87 : 0; 215 | for(i=0; i<15; i++){ 216 | v1 = tmp[i+0]; 217 | v0 = tmp[i+1]; 218 | v1 <<= 1; 219 | v0 >>= 7; 220 | v0 |= v1; 221 | tmp[i+0] = v0; 222 | } 223 | v0 = tmp[15]; 224 | v0 <<= 1; 225 | v0 ^= t0; 226 | tmp[15] = v0; 227 | 228 | // padding remain data 229 | if(mkey->pad_size<16){ 230 | // left shift tmp 1 bit 231 | t0 = (tmp[0]&0x80)? 0x87 : 0; 232 | for(i=0; i<15; i++){ 233 | v1 = tmp[i+0]; 234 | v0 = tmp[i+1]; 235 | v1 <<= 1; 236 | v0 >>= 7; 237 | v0 |= v1; 238 | tmp[i+0] = v0; 239 | } 240 | v0 = tmp[15]; 241 | v0 <<= 1; 242 | v0 ^= t0; 243 | tmp[15] = v0; 244 | 245 | mkey->pad[mkey->pad_size] = 0x80; 246 | if(mkey->pad_size+1<16) 247 | memset(mkey->pad+mkey->pad_size+1, 0, 16-mkey->pad_size-1); 248 | } 249 | 250 | for(i=0; i<16; i++){ 251 | mkey->pad[i] ^= tmp[i]; 252 | } 253 | 254 | memcpy(kbuf, mkey->pad, 16); 255 | memcpy(tmp1, mkey->key, 16); 256 | 257 | retv = sub_158(kirk_buf, 0x10, tmp1, code); 258 | if(retv) 259 | return retv; 260 | 261 | for(i=0; i<0x10; i++){ 262 | tmp1[i] ^= loc_1CD4[i]; 263 | } 264 | 265 | if(mkey->type==2){ 266 | memcpy(kbuf, tmp1, 16); 267 | 268 | retv = kirk5(kirk_buf, 0x10); 269 | if(retv) 270 | goto _exit; 271 | 272 | retv = kirk4(kirk_buf, 0x10, code); 273 | if(retv) 274 | goto _exit; 275 | 276 | memcpy(tmp1, kbuf, 16); 277 | } 278 | 279 | if(vkey){ 280 | for(i=0; i<0x10; i++){ 281 | tmp1[i] ^= vkey[i]; 282 | } 283 | memcpy(kbuf, tmp1, 16); 284 | 285 | retv = kirk4(kirk_buf, 0x10, code); 286 | if(retv) 287 | goto _exit; 288 | 289 | memcpy(tmp1, kbuf, 16); 290 | } 291 | 292 | memcpy(buf, tmp1, 16); 293 | 294 | memset(mkey->key, 0, 16); 295 | memset(mkey->pad, 0, 16); 296 | 297 | mkey->pad_size = 0; 298 | mkey->type = 0; 299 | retv = 0; 300 | 301 | _exit: 302 | return retv; 303 | } 304 | 305 | int sceDrmBBMacFinal2(MAC_KEY *mkey, u8 *out, u8 *vkey) 306 | { 307 | int i, retv, type; 308 | u8 *kbuf, tmp[16]; 309 | 310 | type = mkey->type; 311 | retv = sceDrmBBMacFinal(mkey, tmp, vkey); 312 | if(retv) 313 | return retv; 314 | 315 | kbuf = kirk_buf+0x14; 316 | 317 | // decrypt bbmac 318 | if(type==3){ 319 | memcpy(kbuf, out, 0x10); 320 | kirk7(kirk_buf, 0x10, 0x63); 321 | }else{ 322 | memcpy(kirk_buf, out, 0x10); 323 | } 324 | 325 | retv = 0; 326 | for(i=0; i<0x10; i++){ 327 | if(kirk_buf[i]!=tmp[i]){ 328 | retv = 0x80510300; 329 | break; 330 | } 331 | } 332 | 333 | return retv; 334 | } 335 | 336 | int bbmac_build_final2(int type, u8 *mac) 337 | { 338 | u8 *kbuf = kirk_buf+0x14; 339 | 340 | if(type==3){ 341 | memcpy(kbuf, mac, 16); 342 | kirk4(kirk_buf, 0x10, 0x63); 343 | memcpy(mac, kbuf, 16); 344 | } 345 | 346 | return 0; 347 | } 348 | 349 | // get key from bbmac 350 | int bbmac_getkey(MAC_KEY *mkey, u8 *bbmac, u8 *vkey) 351 | { 352 | int i, retv, type, code; 353 | u8 *kbuf, tmp[16], tmp1[16]; 354 | 355 | type = mkey->type; 356 | retv = sceDrmBBMacFinal(mkey, tmp, NULL); 357 | if(retv) 358 | return retv; 359 | 360 | kbuf = kirk_buf+0x14; 361 | 362 | // decrypt bbmac 363 | if(type==3){ 364 | memcpy(kbuf, bbmac, 0x10); 365 | kirk7(kirk_buf, 0x10, 0x63); 366 | }else{ 367 | memcpy(kirk_buf, bbmac, 0x10); 368 | } 369 | 370 | memcpy(tmp1, kirk_buf, 16); 371 | memcpy(kbuf, tmp1, 16); 372 | 373 | code = (type==2)? 0x3A : 0x38; 374 | kirk7(kirk_buf, 0x10, code); 375 | 376 | for(i=0; i<0x10; i++){ 377 | vkey[i] = tmp[i] ^ kirk_buf[i]; 378 | } 379 | 380 | return 0; 381 | } 382 | 383 | int bbmac_forge(MAC_KEY *mkey, u8 *bbmac, u8 *vkey, u8 *buf) 384 | { 385 | int i, retv, type; 386 | u8 *kbuf, tmp[16], tmp1[16]; 387 | u32 t0, v0, v1; 388 | 389 | if(mkey->pad_size>16) 390 | return 0x80510302; 391 | 392 | type = (mkey->type==2)? 0x3A : 0x38; 393 | kbuf = kirk_buf+0x14; 394 | 395 | memset(kbuf, 0, 16); 396 | retv = kirk4(kirk_buf, 16, type); 397 | if(retv) 398 | return retv; 399 | memcpy(tmp, kbuf, 16); 400 | 401 | // left shift tmp 1 bit 402 | t0 = (tmp[0]&0x80)? 0x87 : 0; 403 | for(i=0; i<15; i++){ 404 | v1 = tmp[i+0]; 405 | v0 = tmp[i+1]; 406 | v1 <<= 1; 407 | v0 >>= 7; 408 | v0 |= v1; 409 | tmp[i+0] = v0; 410 | } 411 | v0 = tmp[15]; 412 | v0 <<= 1; 413 | v0 ^= t0; 414 | tmp[15] = v0; 415 | 416 | // padding remain data 417 | if(mkey->pad_size<16){ 418 | // left shift tmp 1 bit 419 | t0 = (tmp[0]&0x80)? 0x87 : 0; 420 | for(i=0; i<15; i++){ 421 | v1 = tmp[i+0]; 422 | v0 = tmp[i+1]; 423 | v1 <<= 1; 424 | v0 >>= 7; 425 | v0 |= v1; 426 | tmp[i+0] = v0; 427 | } 428 | v0 = tmp[15]; 429 | v0 <<= 1; 430 | v0 ^= t0; 431 | tmp[15] = t0; 432 | 433 | mkey->pad[mkey->pad_size] = 0x80; 434 | if(mkey->pad_size+1<16) 435 | memset(mkey->pad+mkey->pad_size+1, 0, 16-mkey->pad_size-1); 436 | } 437 | 438 | for(i=0; i<16; i++){ 439 | mkey->pad[i] ^= tmp[i]; 440 | } 441 | for(i=0; i<0x10; i++){ 442 | mkey->pad[i] ^= mkey->key[i]; 443 | } 444 | 445 | // reverse order 446 | memcpy(kbuf, bbmac, 0x10); 447 | kirk7(kirk_buf, 0x10, 0x63); 448 | 449 | memcpy(kbuf, kirk_buf, 0x10); 450 | kirk7(kirk_buf, 0x10, type); 451 | 452 | memcpy(tmp1, kirk_buf, 0x10); 453 | for(i=0; i<0x10; i++){ 454 | tmp1[i] ^= vkey[i]; 455 | } 456 | for(i=0; i<0x10; i++){ 457 | tmp1[i] ^= loc_1CD4[i]; 458 | } 459 | 460 | memcpy(kbuf, tmp1, 0x10); 461 | kirk7(kirk_buf, 0x10, type); 462 | 463 | memcpy(tmp1, kirk_buf, 0x10); 464 | for(i=0; i<16; i++){ 465 | mkey->pad[i] ^= tmp1[i]; 466 | } 467 | 468 | // modify the last 16 bytes 469 | for(i=0; i<16; i++){ 470 | buf[i] ^= mkey->pad[i]; 471 | } 472 | 473 | return 0; 474 | } 475 | 476 | 477 | 478 | /*************************************************************/ 479 | 480 | static int sub_1F8(u8 *buf, int size, u8 *key, int key_type) 481 | { 482 | int i, retv; 483 | u8 tmp[16]; 484 | 485 | // copy last 16 bytes to tmp 486 | memcpy(tmp, buf+size+0x14-16, 16); 487 | 488 | retv = kirk7(buf, size, key_type); 489 | if(retv) 490 | return retv; 491 | 492 | for(i=0; i<16; i++){ 493 | buf[i] ^= key[i]; 494 | } 495 | 496 | // copy last 16 bytes to keys 497 | memcpy(key, tmp, 16); 498 | 499 | return 0; 500 | } 501 | 502 | 503 | static int sub_428(u8 *kbuf, u8 *dbuf, int size, CIPHER_KEY *ckey) 504 | { 505 | int i, retv; 506 | u8 tmp1[16], tmp2[16]; 507 | 508 | memcpy(kbuf+0x14, ckey->key, 16); 509 | 510 | for(i=0; i<16; i++){ 511 | kbuf[0x14+i] ^= loc_1CF4[i]; 512 | } 513 | 514 | if(ckey->type==2) 515 | retv = kirk8(kbuf, 16); 516 | else 517 | retv = kirk7(kbuf, 16, 0x39); 518 | if(retv) 519 | return retv; 520 | 521 | for(i=0; i<16; i++){ 522 | kbuf[i] ^= loc_1CE4[i]; 523 | } 524 | 525 | memcpy(tmp2, kbuf, 0x10); 526 | 527 | if(ckey->seed==1){ 528 | memset(tmp1, 0, 0x10); 529 | }else{ 530 | memcpy(tmp1, tmp2, 0x10); 531 | *(u32*)(tmp1+0x0c) = ckey->seed-1; 532 | } 533 | 534 | for(i=0; iseed; 537 | ckey->seed += 1; 538 | } 539 | 540 | retv = sub_1F8(kbuf, size, tmp1, 0x63); 541 | if(retv) 542 | return retv; 543 | 544 | for(i=0; itype = type; 562 | if(mode==2){ 563 | ckey->seed = seed+1; 564 | for(i=0; i<16; i++){ 565 | ckey->key[i] = header_key[i]; 566 | } 567 | if(version_key){ 568 | for(i=0; i<16; i++){ 569 | ckey->key[i] ^= version_key[i]; 570 | } 571 | } 572 | retv = 0; 573 | }else if(mode==1){ 574 | ckey->seed = 1; 575 | retv = kirk14(kirk_buf); 576 | if(retv) 577 | return retv; 578 | 579 | memcpy(kbuf, kirk_buf, 0x10); 580 | memset(kbuf+0x0c, 0, 4); 581 | 582 | if(ckey->type==2){ 583 | for(i=0; i<16; i++){ 584 | kbuf[i] ^= loc_1CE4[i]; 585 | } 586 | retv = kirk5(kirk_buf, 0x10); 587 | for(i=0; i<16; i++){ 588 | kbuf[i] ^= loc_1CF4[i]; 589 | } 590 | }else{ 591 | for(i=0; i<16; i++){ 592 | kbuf[i] ^= loc_1CE4[i]; 593 | } 594 | retv = kirk4(kirk_buf, 0x10, 0x39); 595 | for(i=0; i<16; i++){ 596 | kbuf[i] ^= loc_1CF4[i]; 597 | } 598 | } 599 | if(retv) 600 | return retv; 601 | 602 | memcpy(ckey->key, kbuf, 0x10); 603 | memcpy(header_key, kbuf, 0x10); 604 | 605 | if(version_key){ 606 | for(i=0; i<16; i++){ 607 | ckey->key[i] ^= version_key[i]; 608 | } 609 | } 610 | }else{ 611 | retv = 0; 612 | } 613 | 614 | return retv; 615 | } 616 | 617 | int sceDrmBBCipherUpdate(CIPHER_KEY *ckey, u8 *data, int size) 618 | { 619 | int p, retv, dsize; 620 | 621 | retv = 0; 622 | p = 0; 623 | 624 | while(size>0){ 625 | dsize = (size>=0x0800)? 0x0800 : size; 626 | retv = sub_428(kirk_buf, data+p, dsize, ckey); 627 | if(retv) 628 | break; 629 | size -= dsize; 630 | p += dsize; 631 | } 632 | 633 | return retv; 634 | } 635 | 636 | int sceDrmBBCipherFinal(CIPHER_KEY *ckey) 637 | { 638 | memset(ckey->key, 0, 16); 639 | ckey->type = 0; 640 | ckey->seed = 0; 641 | 642 | return 0; 643 | } 644 | 645 | /*************************************************************/ 646 | 647 | // AES128 encrypt key 648 | static u8 key_357C[0x30] = { 649 | 0x07,0x3D,0x9E,0x9D,0xA8,0xFD,0x3B,0x2F,0x63,0x18,0x93,0x2E,0xF8,0x57,0xA6,0x64, 650 | 0x37,0x49,0xB7,0x01,0xCA,0xE2,0xE0,0xC5,0x44,0x2E,0x06,0xB6,0x1E,0xFF,0x84,0xF2, 651 | 0x9D,0x31,0xB8,0x5A,0xC8,0xFA,0x16,0x80,0x73,0x60,0x18,0x82,0x18,0x77,0x91,0x9D, 652 | }; 653 | 654 | static u8 key_363C[16] = { 655 | 0x38,0x20,0xD0,0x11,0x07,0xA3,0xFF,0x3E,0x0A,0x4C,0x20,0x85,0x39,0x10,0xB5,0x54, 656 | }; 657 | 658 | int sceNpDrmGetFixedKey(u8 *key, char *npstr, int type) 659 | { 660 | AES_ctx akey; 661 | MAC_KEY mkey; 662 | char strbuf[0x30]; 663 | int retv; 664 | 665 | if((type&0x01000000)==0) 666 | return 0x80550901; 667 | type &= 0x000000ff; 668 | 669 | memset(strbuf, 0, 0x30); 670 | strncpy(strbuf, npstr, 0x30); 671 | 672 | retv = sceDrmBBMacInit(&mkey, 1); 673 | if(retv) 674 | return retv; 675 | 676 | retv = sceDrmBBMacUpdate(&mkey, (u8*)strbuf, 0x30); 677 | if(retv) 678 | return retv; 679 | 680 | retv = sceDrmBBMacFinal(&mkey, key, key_363C); 681 | if(retv) 682 | return 0x80550902; 683 | 684 | if(type==0) 685 | return 0; 686 | if(type>3) 687 | return 0x80550901; 688 | type = (type-1)*16; 689 | 690 | AES_set_key(&akey, &key_357C[type], 128); 691 | AES_encrypt(&akey, key, key); 692 | 693 | return 0; 694 | } 695 | -------------------------------------------------------------------------------- /kirk/amctrl.h: -------------------------------------------------------------------------------- 1 | #ifndef AMCTRL_H 2 | #define AMCTRL_H 3 | 4 | typedef struct { 5 | int type; 6 | u8 key[16]; 7 | u8 pad[16]; 8 | int pad_size; 9 | } MAC_KEY; 10 | 11 | typedef struct 12 | { 13 | u32 type; 14 | u32 seed; 15 | u8 key[16]; 16 | } CIPHER_KEY; 17 | 18 | // type: 19 | // 2: use fuse id 20 | // 3: use fixed key. MAC need encrypt again 21 | int sceDrmBBMacInit(MAC_KEY *mkey, int type); 22 | int sceDrmBBMacUpdate(MAC_KEY *mkey, u8 *buf, int size); 23 | int sceDrmBBMacFinal(MAC_KEY *mkey, u8 *buf, u8 *vkey); 24 | int sceDrmBBMacFinal2(MAC_KEY *mkey, u8 *out, u8 *vkey); 25 | 26 | int bbmac_build_final2(int type, u8 *mac); 27 | int bbmac_getkey(MAC_KEY *mkey, u8 *bbmac, u8 *vkey); 28 | int bbmac_forge(MAC_KEY *mkey, u8 *bbmac, u8 *vkey, u8 *buf); 29 | 30 | // type: 1 use fixed key 31 | // 2 use fuse id 32 | // mode: 1 for encrypt 33 | // 2 for decrypt 34 | int sceDrmBBCipherInit(CIPHER_KEY *ckey, int type, int mode, u8 *header_key, u8 *version_key, u32 seed); 35 | int sceDrmBBCipherUpdate(CIPHER_KEY *ckey, u8 *data, int size); 36 | int sceDrmBBCipherFinal(CIPHER_KEY *ckey); 37 | 38 | // npdrm.prx 39 | int sceNpDrmGetFixedKey(u8 *key, char *npstr, int type); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /kirk/bn.c: -------------------------------------------------------------------------------- 1 | // Copyright 2007,2008,2010 Segher Boessenkool 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include 6 | #include 7 | 8 | #include "kirk_engine.h" 9 | #include "ecdsa.h" 10 | 11 | 12 | void bn_dump(char *str, u8 *buf, u32 size) 13 | { 14 | u32 i; 15 | 16 | printf("%16s: ", str); 17 | for(i=0; i b[i]) 53 | return 1; 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | static u8 bn_add_1(u8 *d, u8 *a, u8 *b, u32 n) 60 | { 61 | u32 i; 62 | u32 dig; 63 | u8 c; 64 | 65 | c = 0; 66 | for (i = n - 1; i < n; i--) { 67 | dig = a[i] + b[i] + c; 68 | c = dig >> 8; 69 | d[i] = dig; 70 | } 71 | 72 | return c; 73 | } 74 | 75 | static u8 bn_sub_1(u8 *d, u8 *a, u8 *b, u32 n) 76 | { 77 | u32 i; 78 | u32 dig; 79 | u8 c; 80 | 81 | c = 1; 82 | for (i = n - 1; i < n; i--) { 83 | dig = a[i] + 255 - b[i] + c; 84 | c = dig >> 8; 85 | d[i] = dig; 86 | } 87 | 88 | return 1 - c; 89 | } 90 | 91 | void bn_reduce(u8 *d, u8 *N, u32 n) 92 | { 93 | if (bn_compare(d, N, n) >= 0) 94 | bn_sub_1(d, d, N, n); 95 | } 96 | 97 | void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) 98 | { 99 | if (bn_add_1(d, a, b, n)) 100 | bn_sub_1(d, d, N, n); 101 | 102 | bn_reduce(d, N, n); 103 | } 104 | 105 | void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) 106 | { 107 | if (bn_sub_1(d, a, b, n)) 108 | bn_add_1(d, d, N, n); 109 | } 110 | 111 | static const u8 inv256[0x80] = { 112 | 0x01, 0xab, 0xcd, 0xb7, 0x39, 0xa3, 0xc5, 0xef, 113 | 0xf1, 0x1b, 0x3d, 0xa7, 0x29, 0x13, 0x35, 0xdf, 114 | 0xe1, 0x8b, 0xad, 0x97, 0x19, 0x83, 0xa5, 0xcf, 115 | 0xd1, 0xfb, 0x1d, 0x87, 0x09, 0xf3, 0x15, 0xbf, 116 | 0xc1, 0x6b, 0x8d, 0x77, 0xf9, 0x63, 0x85, 0xaf, 117 | 0xb1, 0xdb, 0xfd, 0x67, 0xe9, 0xd3, 0xf5, 0x9f, 118 | 0xa1, 0x4b, 0x6d, 0x57, 0xd9, 0x43, 0x65, 0x8f, 119 | 0x91, 0xbb, 0xdd, 0x47, 0xc9, 0xb3, 0xd5, 0x7f, 120 | 0x81, 0x2b, 0x4d, 0x37, 0xb9, 0x23, 0x45, 0x6f, 121 | 0x71, 0x9b, 0xbd, 0x27, 0xa9, 0x93, 0xb5, 0x5f, 122 | 0x61, 0x0b, 0x2d, 0x17, 0x99, 0x03, 0x25, 0x4f, 123 | 0x51, 0x7b, 0x9d, 0x07, 0x89, 0x73, 0x95, 0x3f, 124 | 0x41, 0xeb, 0x0d, 0xf7, 0x79, 0xe3, 0x05, 0x2f, 125 | 0x31, 0x5b, 0x7d, 0xe7, 0x69, 0x53, 0x75, 0x1f, 126 | 0x21, 0xcb, 0xed, 0xd7, 0x59, 0xc3, 0xe5, 0x0f, 127 | 0x11, 0x3b, 0x5d, 0xc7, 0x49, 0x33, 0x55, 0xff, 128 | }; 129 | 130 | static void bn_mon_muladd_dig(u8 *d, u8 *a, u8 b, u8 *N, u32 n) 131 | { 132 | u32 dig; 133 | u32 i; 134 | 135 | u8 z = -(d[n-1] + a[n-1]*b) * inv256[N[n-1]/2]; 136 | 137 | dig = d[n-1] + a[n-1]*b + N[n-1]*z; 138 | dig >>= 8; 139 | 140 | for (i = n - 2; i < n; i--) { 141 | dig += d[i] + a[i]*b + N[i]*z; 142 | d[i+1] = dig; 143 | dig >>= 8; 144 | } 145 | 146 | d[0] = dig; 147 | dig >>= 8; 148 | 149 | if (dig) 150 | bn_sub_1(d, d, N, n); 151 | 152 | bn_reduce(d, N, n); 153 | } 154 | 155 | void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) 156 | { 157 | u8 t[512]; 158 | u32 i; 159 | 160 | bn_zero(t, n); 161 | 162 | for (i = n - 1; i < n; i--) 163 | bn_mon_muladd_dig(t, a, b[i], N, n); 164 | 165 | bn_copy(d, t, n); 166 | } 167 | 168 | void bn_to_mon(u8 *d, u8 *N, u32 n) 169 | { 170 | u32 i; 171 | 172 | for (i = 0; i < 8*n; i++) 173 | bn_add(d, d, d, N, n); 174 | } 175 | 176 | void bn_from_mon(u8 *d, u8 *N, u32 n) 177 | { 178 | u8 t[512]; 179 | 180 | bn_zero(t, n); 181 | t[n-1] = 1; 182 | bn_mon_mul(d, d, t, N, n); 183 | } 184 | 185 | static void bn_mon_exp(u8 *d, u8 *a, u8 *N, u32 n, u8 *e, u32 en) 186 | { 187 | u8 t[512]; 188 | u32 i; 189 | u8 mask; 190 | 191 | bn_zero(d, n); 192 | d[n-1] = 1; 193 | bn_to_mon(d, N, n); 194 | 195 | for (i = 0; i < en; i++) 196 | for (mask = 0x80; mask != 0; mask >>= 1) { 197 | bn_mon_mul(t, d, d, N, n); 198 | if ((e[i] & mask) != 0) 199 | bn_mon_mul(d, t, a, N, n); 200 | else 201 | bn_copy(d, t, n); 202 | } 203 | } 204 | 205 | void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n) 206 | { 207 | u8 t[512], s[512]; 208 | 209 | bn_zero(s, n); 210 | s[n-1] = 2; 211 | bn_sub_1(t, N, s, n); 212 | bn_mon_exp(d, a, N, n, t, n); 213 | } 214 | 215 | /*************************************************************/ 216 | 217 | void bn_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) 218 | { 219 | u32 i; 220 | u8 mask; 221 | u8 td[512]; 222 | 223 | bn_zero(td, 512); 224 | 225 | for (i = 0; i < n; i++){ 226 | for (mask = 0x80; mask != 0; mask >>= 1) { 227 | bn_add(td, td, td, N, n); 228 | if ((a[i] & mask) != 0) 229 | bn_add(td, td, b, N, n); 230 | } 231 | } 232 | 233 | bn_copy(d, td, n); 234 | } 235 | 236 | /*************************************************************/ 237 | 238 | static int bn_is_odd(u8 *d, u32 n) 239 | { 240 | return (d[n-1])&1; 241 | } 242 | 243 | static void bn_rshift1(u8 *d, u8 *a, u32 n) 244 | { 245 | u8 b, c; 246 | int i; 247 | 248 | c = 0; 249 | for(i=0; i>1)|c; 252 | c = (b<<7)&0x80; 253 | } 254 | } 255 | 256 | void bn_gcd(u8 *out_d, u8 *in_a, u8 *in_b, u32 n) 257 | { 258 | u8 a[512], b[512], t[512], mn[512]; 259 | int shift; 260 | 261 | shift = 0; 262 | memset(mn, 0, 512); 263 | mn[0] = 0x80; 264 | 265 | memcpy(a, in_a, n); 266 | memcpy(b, in_b, n); 267 | 268 | if(bn_compare(a, b, n)<0){ 269 | memcpy(t, a, n); 270 | memcpy(a, b, n); 271 | memcpy(b, t, n); 272 | } 273 | 274 | while(!bn_is_zero(b, n)){ 275 | if(bn_is_odd(a, n)){ 276 | if(bn_is_odd(b, n)){ 277 | bn_sub(a, a, b, mn, n); 278 | bn_rshift1(a, a, n); 279 | if(bn_compare(a, b, n)<0){ 280 | memcpy(t, a, n); 281 | memcpy(a, b, n); 282 | memcpy(b, t, n); 283 | } 284 | }else{ 285 | bn_rshift1(b, b, n); 286 | } 287 | }else{ 288 | if(bn_is_odd(b, n)){ 289 | bn_rshift1(a, a, n); 290 | if(bn_compare(a, b, n)<0){ 291 | memcpy(t, a, n); 292 | memcpy(a, b, n); 293 | memcpy(b, t, n); 294 | } 295 | }else{ 296 | bn_rshift1(a, a, n); 297 | bn_rshift1(b, b, n); 298 | shift += 1; 299 | } 300 | } 301 | } 302 | 303 | // skip this step 304 | //bn_lshift(a, a, shift, n); 305 | 306 | memcpy(out_d, a, n); 307 | } 308 | 309 | -------------------------------------------------------------------------------- /kirk/crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef __RIJNDAEL_H 2 | #define __RIJNDAEL_H 3 | 4 | #include "kirk_engine.h" 5 | 6 | #define AES_KEY_LEN_128 (128) 7 | #define AES_KEY_LEN_192 (192) 8 | #define AES_KEY_LEN_256 (256) 9 | 10 | #define AES_BUFFER_SIZE (16) 11 | 12 | #define AES_MAXKEYBITS (256) 13 | #define AES_MAXKEYBYTES (AES_MAXKEYBITS/8) 14 | /* for 256-bit keys, fewer for less */ 15 | #define AES_MAXROUNDS 14 16 | 17 | /* The structure for key information */ 18 | typedef struct 19 | { 20 | int enc_only; /* context contains only encrypt schedule */ 21 | int Nr; /* key-length-dependent number of rounds */ 22 | u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */ 23 | u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */ 24 | } AES_ctx; 25 | 26 | int AES_set_key(AES_ctx *ctx, const u8 *key, int bits); 27 | void AES_encrypt(AES_ctx *ctx, const u8 *src, u8 *dst); 28 | void AES_decrypt(AES_ctx *ctx, const u8 *src, u8 *dst); 29 | void AES_cbc_encrypt(AES_ctx *ctx, u8 *src, u8 *dst, int size); 30 | void AES_cbc_decrypt(AES_ctx *ctx, u8 *src, u8 *dst, int size); 31 | void AES_CMAC(AES_ctx *ctx, unsigned char *input, int length, unsigned char *mac); 32 | 33 | typedef struct SHA1Context 34 | { 35 | unsigned Message_Digest[5]; /* Message Digest (output) */ 36 | unsigned Length_Low; /* Message length in bits */ 37 | unsigned Length_High; /* Message length in bits */ 38 | unsigned char Message_Block[64]; /* 512-bit message blocks */ 39 | int Message_Block_Index; /* Index into message block array */ 40 | int Computed; /* Is the digest computed? */ 41 | int Corrupted; /* Is the message digest corruped? */ 42 | } SHA1Context; 43 | 44 | /* 45 | * Function Prototypes 46 | */ 47 | void SHA1Reset(SHA1Context *); 48 | void SHA1Input(SHA1Context *, const unsigned char *, unsigned); 49 | int SHA1Result(SHA1Context *); 50 | void SHA1(unsigned char *d, size_t n, unsigned char *md); 51 | 52 | #endif /* __RIJNDAEL_H */ 53 | -------------------------------------------------------------------------------- /kirk/ec.c: -------------------------------------------------------------------------------- 1 | // Copyright 2007,2008,2010 Segher Boessenkool 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "kirk_engine.h" 10 | #include "ecdsa.h" 11 | 12 | struct point { 13 | u8 x[20]; 14 | u8 y[20]; 15 | }; 16 | 17 | static u8 ec_p[20]; 18 | static u8 ec_a[20]; // mon 19 | static u8 ec_b[20]; // mon 20 | static u8 ec_N[20]; 21 | static struct point ec_G; // mon 22 | static struct point ec_Q; // mon 23 | static u8 ec_k[20]; // private key 24 | 25 | static void elt_copy(u8 *d, u8 *a) 26 | { 27 | memcpy(d, a, 20); 28 | } 29 | 30 | static void elt_zero(u8 *d) 31 | { 32 | memset(d, 0, 20); 33 | } 34 | 35 | static int elt_is_zero(u8 *d) 36 | { 37 | u32 i; 38 | 39 | for (i = 0; i < 20; i++) 40 | if (d[i] != 0) 41 | return 0; 42 | 43 | return 1; 44 | } 45 | 46 | static void elt_add(u8 *d, u8 *a, u8 *b) 47 | { 48 | bn_add(d, a, b, ec_p, 20); 49 | } 50 | 51 | static void elt_sub(u8 *d, u8 *a, u8 *b) 52 | { 53 | bn_sub(d, a, b, ec_p, 20); 54 | } 55 | 56 | static void elt_mul(u8 *d, u8 *a, u8 *b) 57 | { 58 | bn_mon_mul(d, a, b, ec_p, 20); 59 | } 60 | 61 | static void elt_square(u8 *d, u8 *a) 62 | { 63 | elt_mul(d, a, a); 64 | } 65 | 66 | static void elt_inv(u8 *d, u8 *a) 67 | { 68 | u8 s[20]; 69 | elt_copy(s, a); 70 | bn_mon_inv(d, s, ec_p, 20); 71 | } 72 | 73 | static void point_to_mon(struct point *p) 74 | { 75 | bn_to_mon(p->x, ec_p, 20); 76 | bn_to_mon(p->y, ec_p, 20); 77 | } 78 | 79 | static void point_from_mon(struct point *p) 80 | { 81 | bn_from_mon(p->x, ec_p, 20); 82 | bn_from_mon(p->y, ec_p, 20); 83 | } 84 | 85 | static void point_zero(struct point *p) 86 | { 87 | elt_zero(p->x); 88 | elt_zero(p->y); 89 | } 90 | 91 | static int point_is_zero(struct point *p) 92 | { 93 | return elt_is_zero(p->x) && elt_is_zero(p->y); 94 | } 95 | 96 | static void point_double(struct point *r, struct point *p) 97 | { 98 | u8 s[20], t[20]; 99 | struct point pp; 100 | u8 *px, *py, *rx, *ry; 101 | 102 | pp = *p; 103 | 104 | px = pp.x; 105 | py = pp.y; 106 | rx = r->x; 107 | ry = r->y; 108 | 109 | if (elt_is_zero(py)) { 110 | point_zero(r); 111 | return; 112 | } 113 | 114 | elt_square(t, px); // t = px*px 115 | elt_add(s, t, t); // s = 2*px*px 116 | elt_add(s, s, t); // s = 3*px*px 117 | elt_add(s, s, ec_a);// s = 3*px*px + a 118 | elt_add(t, py, py); // t = 2*py 119 | elt_inv(t, t); // t = 1/(2*py) 120 | elt_mul(s, s, t); // s = (3*px*px+a)/(2*py) 121 | 122 | elt_square(rx, s); // rx = s*s 123 | elt_add(t, px, px); // t = 2*px 124 | elt_sub(rx, rx, t); // rx = s*s - 2*px 125 | 126 | elt_sub(t, px, rx); // t = -(rx-px) 127 | elt_mul(ry, s, t); // ry = -s*(rx-px) 128 | elt_sub(ry, ry, py);// ry = -s*(rx-px) - py 129 | } 130 | 131 | static void point_add(struct point *r, struct point *p, struct point *q) 132 | { 133 | u8 s[20], t[20], u[20]; 134 | u8 *px, *py, *qx, *qy, *rx, *ry; 135 | struct point pp, qq; 136 | 137 | pp = *p; 138 | qq = *q; 139 | 140 | px = pp.x; 141 | py = pp.y; 142 | qx = qq.x; 143 | qy = qq.y; 144 | rx = r->x; 145 | ry = r->y; 146 | 147 | if (point_is_zero(&pp)) { 148 | elt_copy(rx, qx); 149 | elt_copy(ry, qy); 150 | return; 151 | } 152 | 153 | if (point_is_zero(&qq)) { 154 | elt_copy(rx, px); 155 | elt_copy(ry, py); 156 | return; 157 | } 158 | 159 | elt_sub(u, qx, px); 160 | 161 | if (elt_is_zero(u)) { 162 | elt_sub(u, qy, py); 163 | if (elt_is_zero(u)) 164 | point_double(r, &pp); 165 | else 166 | point_zero(r); 167 | 168 | return; 169 | } 170 | 171 | elt_inv(t, u); // t = 1/(qx-px) 172 | elt_sub(u, qy, py); // u = qy-py 173 | elt_mul(s, t, u); // s = (qy-py)/(qx-px) 174 | 175 | elt_square(rx, s); // rx = s*s 176 | elt_add(t, px, qx); // t = px+qx 177 | elt_sub(rx, rx, t); // rx = s*s - (px+qx) 178 | 179 | elt_sub(t, px, rx); // t = -(rx-px) 180 | elt_mul(ry, s, t); // ry = -s*(rx-px) 181 | elt_sub(ry, ry, py);// ry = -s*(rx-px) - py 182 | } 183 | 184 | static void point_mul(struct point *d, u8 *a, struct point *b) 185 | { 186 | u32 i; 187 | u8 mask; 188 | 189 | point_zero(d); 190 | 191 | for (i = 0; i < 20; i++) 192 | for (mask = 0x80; mask != 0; mask >>= 1) { 193 | point_double(d, d); 194 | if ((a[i] & mask) != 0) 195 | point_add(d, d, b); 196 | } 197 | } 198 | 199 | static void generate_ecdsa(u8 *R, u8 *S, u8 *k, u8 *hash, u8 *random) 200 | { 201 | u8 e[20]; 202 | u8 kk[20]; 203 | u8 m[20]; 204 | u8 minv[20]; 205 | struct point mG; 206 | 207 | memcpy(e, hash, 20); 208 | bn_reduce(e, ec_N, 20); 209 | 210 | if(random==NULL){ 211 | do{ 212 | kirk_CMD14(m, 20); 213 | }while(bn_compare(m, ec_N, 20) >= 0); 214 | }else{ 215 | memcpy(m, random, 20); 216 | } 217 | 218 | point_mul(&mG, m, &ec_G); 219 | point_from_mon(&mG); 220 | elt_copy(R, mG.x); 221 | 222 | bn_copy(kk, k, 20); 223 | bn_reduce(kk, ec_N, 20); 224 | bn_to_mon(m, ec_N, 20); 225 | bn_to_mon(e, ec_N, 20); 226 | bn_to_mon(R, ec_N, 20); 227 | bn_to_mon(kk, ec_N, 20); 228 | 229 | bn_mon_mul(S, R, kk, ec_N, 20); 230 | bn_add(kk, S, e, ec_N, 20); 231 | bn_mon_inv(minv, m, ec_N, 20); 232 | bn_mon_mul(S, minv, kk, ec_N, 20); 233 | 234 | bn_from_mon(R, ec_N, 20); 235 | bn_from_mon(S, ec_N, 20); 236 | } 237 | 238 | static int check_ecdsa(struct point *Q, u8 *R, u8 *S, u8 *hash) 239 | { 240 | u8 Sinv[20]; 241 | u8 e[20]; 242 | u8 w1[20], w2[20]; 243 | struct point r1, r2, r3; 244 | u8 rr[20]; 245 | 246 | memcpy(e, hash, 20); 247 | bn_reduce(e, ec_N, 20); 248 | 249 | // Sinv = INV(s) 250 | bn_to_mon(S, ec_N, 20); 251 | bn_mon_inv(Sinv, S, ec_N, 20); 252 | 253 | // w1 = e*Sinv 254 | bn_to_mon(e, ec_N, 20); 255 | bn_mon_mul(w1, e, Sinv, ec_N, 20); 256 | bn_from_mon(w1, ec_N, 20); 257 | 258 | // w2 = R*Sinv 259 | bn_to_mon(R, ec_N, 20); 260 | bn_mon_mul(w2, R, Sinv, ec_N, 20); 261 | bn_from_mon(w2, ec_N, 20); 262 | 263 | // r1 = w1*G 264 | point_mul(&r1, w1, &ec_G); 265 | // r2 = w2*Q 266 | point_mul(&r2, w2, Q); 267 | // r3 = r1+r2 268 | point_add(&r3, &r1, &r2); 269 | 270 | point_from_mon(&r3); 271 | memcpy(rr, r3.x, 20); 272 | bn_reduce(rr, ec_N, 20); 273 | 274 | bn_from_mon(R, ec_N, 20); 275 | bn_from_mon(S, ec_N, 20); 276 | 277 | return bn_compare(rr, R, 20); 278 | } 279 | 280 | void ecdsa_sign_fixed(u8 *hash, u8 *fixed_m, u8 *fixed_r, u8 *S) 281 | { 282 | u8 minv[20], m[20], k[20], r[20], z[20]; 283 | 284 | memcpy(z, hash, 20); 285 | memcpy(k, ec_k, 20); 286 | memcpy(m, fixed_m, 20); 287 | memcpy(r, fixed_r, 20); 288 | 289 | bn_to_mon(m, ec_N, 20); 290 | bn_mon_inv(minv, m, ec_N, 20); 291 | 292 | bn_to_mon(k, ec_N, 20); 293 | bn_to_mon(r, ec_N, 20); 294 | bn_mon_mul(z, k, r, ec_N, 20); 295 | bn_from_mon(z, ec_N, 20); 296 | 297 | bn_add(z, z, hash, ec_N, 20); 298 | 299 | bn_to_mon(z, ec_N, 20); 300 | bn_mon_mul(S, minv, z, ec_N, 20); 301 | bn_from_mon(S, ec_N, 20); 302 | } 303 | 304 | void ecdsa_set_curve(ECDSA_PARAM *param) 305 | { 306 | memcpy(ec_p, param->p, 20); 307 | memcpy(ec_a, param->a, 20); 308 | memcpy(ec_b, param->b, 20); 309 | memcpy(ec_N, param->N, 20); 310 | memcpy(ec_G.x, param->Gx, 20); 311 | memcpy(ec_G.y, param->Gy, 20); 312 | 313 | bn_to_mon(ec_a, ec_p, 20); 314 | bn_to_mon(ec_b, ec_p, 20); 315 | 316 | point_to_mon(&ec_G); 317 | } 318 | 319 | void ecdsa_set_N(u8 *N) 320 | { 321 | memcpy(ec_N, N, 20); 322 | } 323 | 324 | void ecdsa_set_pub(u8 *Qx, u8 *Qy) 325 | { 326 | memcpy(ec_Q.x, Qx, 20); 327 | memcpy(ec_Q.y, Qy, 20); 328 | point_to_mon(&ec_Q); 329 | } 330 | 331 | void ecdsa_set_priv(u8 *k) 332 | { 333 | memcpy(ec_k, k, sizeof ec_k); 334 | } 335 | 336 | int ecdsa_verify(u8 *hash, u8 *R, u8 *S) 337 | { 338 | return check_ecdsa(&ec_Q, R, S, hash); 339 | } 340 | 341 | void ecdsa_sign(u8 *hash, u8 *R, u8 *S, u8 *random) 342 | { 343 | generate_ecdsa(R, S, ec_k, hash, random); 344 | } 345 | 346 | /*************************************************************/ 347 | 348 | // calculate the random and private key from signs with same r value 349 | void ecdsa_find_m_k(u8 *sig_r, u8 *sig_s1, u8 *hash1, u8 *sig_s2, u8 *hash2, u8 *N, u8 *ret_m, u8 *ret_k) 350 | { 351 | u8 e1[20], e2[20]; 352 | u8 s1[20], s2[20]; 353 | u8 sinv[20], m[20]; 354 | u8 r[20], rinv[20], kk[20]; 355 | 356 | // e1 357 | memcpy(e1, hash1, 20); 358 | // e2 359 | memcpy(e2, hash2, 20); 360 | // s1, s2 361 | memcpy(s1, sig_s1, 20); 362 | memcpy(s2, sig_s2, 20); 363 | 364 | // restore random m 365 | // s1 = s1-s2 366 | bn_sub(s1, s1, s2, N, 20); 367 | // e1 = e1-e2 368 | bn_sub(e1, e1, e2, N, 20); 369 | 370 | bn_to_mon(s1, N, 20); 371 | bn_to_mon(e1, N, 20); 372 | 373 | // m = (e1-e2)/(s1-s2) 374 | bn_mon_inv(sinv, s1, N, 20); 375 | bn_mon_mul(m, sinv, e1, N, 20); 376 | bn_from_mon(m, N, 20); 377 | 378 | bn_dump("random m", m, 20); 379 | memcpy(ret_m, m, 20); 380 | 381 | // restore private key 382 | memcpy(e1, hash1, 20); 383 | memcpy(s1, sig_s1, 20); 384 | memcpy(r, sig_r, 20); 385 | 386 | // kk = m*s 387 | bn_to_mon(s1, N, 20); 388 | bn_to_mon(m, N, 20); 389 | bn_mon_mul(kk, m, s1, N, 20); 390 | 391 | // kk = m*s-e 392 | bn_from_mon(kk, N, 20); 393 | bn_sub(kk, kk, e1, N, 20); 394 | bn_to_mon(kk, N, 20); 395 | 396 | // kk = (m*s-e)/r 397 | bn_to_mon(r, N, 20); 398 | bn_mon_inv(rinv, r, N, 20); 399 | bn_mon_mul(kk, rinv, kk, N, 20); 400 | bn_from_mon(kk, N, 20); 401 | 402 | bn_dump("private key", kk, 20); 403 | memcpy(ret_k, kk, 20); 404 | 405 | } 406 | 407 | -------------------------------------------------------------------------------- /kirk/ecdsa.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Copyright 2007,2008,2010 Segher Boessenkool 3 | // Licensed under the terms of the GNU GPL, version 2 4 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 5 | 6 | #ifndef ECDSA_H__ 7 | #define ECDSA_H__ 1 8 | 9 | typedef struct { 10 | u8 p[20]; 11 | u8 a[20]; 12 | u8 b[20]; 13 | u8 N[20]; 14 | u8 Gx[20]; 15 | u8 Gy[20]; 16 | }ECDSA_PARAM; 17 | 18 | void ecdsa_set_curve(ECDSA_PARAM *param); 19 | void ecdsa_set_N(u8 *N); 20 | void ecdsa_set_pub(u8 *Qx, u8 *Qy); 21 | void ecdsa_set_priv(u8 *k); 22 | int ecdsa_verify(u8 *hash, u8 *R, u8 *S); 23 | void ecdsa_sign(u8 *hash, u8 *R, u8 *S, u8 *random); 24 | void ecdsa_sign_fixed(u8 *hash, u8 *fixed_m, u8 *fixed_r, u8 *S); 25 | void ecdsa_find_m_k(u8 *sig_r, u8 *sig_s1, u8 *hash1, u8 *sig_s2, u8 *hash2, u8 *N, u8 *ret_m, u8 *ret_k); 26 | 27 | void bn_dump(char *msg, u8 *d, u32 n); 28 | int bn_is_zero(u8 *d, u32 n); 29 | void bn_copy(u8 *d, u8 *a, u32 n); 30 | int bn_compare(u8 *a, u8 *b, u32 n); 31 | void bn_reduce(u8 *d, u8 *N, u32 n); 32 | void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); 33 | void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); 34 | void bn_to_mon(u8 *d, u8 *N, u32 n); 35 | void bn_from_mon(u8 *d, u8 *N, u32 n); 36 | void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); 37 | void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n); 38 | 39 | void bn_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); 40 | void bn_gcd(u8 *out_d, u8 *in_a, u8 *in_b, u32 n); 41 | 42 | #endif 43 | 44 | -------------------------------------------------------------------------------- /kirk/kirk_engine.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpunix/kirk_engine/ee09e86b743d1c147579ff21f46dd0874303daf3/kirk/kirk_engine.h -------------------------------------------------------------------------------- /kirk/psp_headers.h: -------------------------------------------------------------------------------- 1 | 2 | /*************************************************************/ 3 | 4 | typedef struct 5 | { 6 | u32 e_magic; 7 | u8 e_class; 8 | u8 e_data; 9 | u8 e_idver; 10 | u8 e_pad[9]; 11 | u16 e_type; 12 | u16 e_machine; 13 | u32 e_version; 14 | u32 e_entry; 15 | u32 e_phoff; 16 | u32 e_shoff; 17 | u32 e_flags; 18 | u16 e_ehsize; 19 | u16 e_phentsize; 20 | u16 e_phnum; 21 | u16 e_shentsize; 22 | u16 e_shnum; 23 | u16 e_shstrndx; 24 | } __attribute__((packed)) Elf32_Ehdr; 25 | 26 | typedef struct 27 | { 28 | u32 p_type; 29 | u32 p_offset; 30 | u32 p_vaddr; 31 | u32 p_paddr; 32 | u32 p_filesz; 33 | u32 p_memsz; 34 | u32 p_flags; 35 | u32 p_align; 36 | } __attribute__((packed)) Elf32_Phdr; 37 | 38 | typedef struct 39 | { 40 | u32 sh_name; 41 | u32 sh_type; 42 | u32 sh_flags; 43 | u32 sh_addr; 44 | u32 sh_offset; 45 | u32 sh_size; 46 | u32 sh_link; 47 | u32 sh_info; 48 | u32 sh_addralign; 49 | u32 sh_entsize; 50 | } __attribute__((packed)) Elf32_Shdr; 51 | 52 | typedef struct { 53 | u32 r_offset; 54 | u32 r_info; /* sym, type: ELF32_R_... */ 55 | } Elf32_Rel; 56 | 57 | /* Values for p_type. */ 58 | #define PT_LOAD 1 /* Loadable segment. */ 59 | 60 | /* Values for p_flags. */ 61 | #define PF_X 0x1 /* Executable. */ 62 | #define PF_W 0x2 /* Writable. */ 63 | #define PF_R 0x4 /* Readable. */ 64 | #define PF_RW (PF_R|PF_W) 65 | 66 | /*************************************************************/ 67 | 68 | typedef struct { 69 | u16 modattribute; 70 | u8 modversion[2]; /* minor, major, etc... */ 71 | char modname[28]; 72 | void *gp_value; 73 | void *ent_top; 74 | void *ent_end; 75 | void *stub_top; 76 | void *stub_end; 77 | } SceModuleInfo; 78 | 79 | 80 | typedef struct 81 | { 82 | u32 signature; //0 83 | u16 mod_attribute; //4 84 | u16 comp_attribute; //6 compress method: 85 | // 0x0001=PRX Compress 86 | // 0x0002=ELF Packed 87 | // 0x0008=GZIP overlap 88 | // 0x0200=KL4E(if not set, GZIP) 89 | u8 module_ver_lo; //8 90 | u8 module_ver_hi; //9 91 | char modname[28]; //0xA 92 | u8 mod_version; //0x26 93 | u8 nsegments; //0x27 94 | u32 elf_size; //0x28 95 | u32 psp_size; //0x2C 96 | u32 boot_entry; //0x30 97 | u32 modinfo_offset; //0x34 98 | int bss_size; //0x38 99 | u16 seg_align[4]; //0x3C 100 | u32 seg_address[4]; //0x44 101 | int seg_size[4]; //0x54 102 | u32 reserved[5]; //0x64 103 | u32 devkit_version; //0x78 104 | u8 decrypt_mode; //0x7C 105 | u8 padding; //0x7D 106 | u16 overlap_size; //0x7E 107 | u8 key_data[0x30]; //0x80 108 | u32 comp_size; //0xB0 kirk data_size 109 | int _80; //0xB4 kirk data_offset 110 | u32 unk_B8; //0xB8 111 | u32 unk_BC; //0xBC 112 | u8 key_data2[0x10]; //0xC0 113 | u32 tag; //0xD0 114 | u8 scheck[0x58]; //0xD4 115 | u8 sha1_hash[0x14]; //0x12C 116 | u8 key_data4[0x10]; //0x140 117 | } __attribute__((packed)) PSP_Header2; //0x150 118 | 119 | typedef struct 120 | { 121 | u32 signature; // 0 122 | u16 attribute; 123 | u8 module_ver_lo; 124 | u8 module_ver_hi; 125 | char modname[28]; 126 | u8 version; // 26 127 | u8 nsegments; // 27 128 | int elf_size; // 28 129 | int psp_size; // 2C 130 | u32 entry; // 30 131 | u32 modinfo_offset; // 34 132 | int bss_size; // 38 133 | u16 seg_align[4]; // 3C 134 | u32 seg_address[4]; // 44 135 | int seg_size[4]; // 54 136 | u32 reserved[5]; // 64 137 | u32 devkitversion; // 78 138 | u32 decrypt_mode; // 7C 139 | u8 key_data0[0x30]; // 80 140 | int comp_size; // B0 141 | int _80; // B4 142 | int reserved2[2]; // B8 143 | u8 key_data1[0x10]; // C0 144 | u32 tag; // D0 145 | u8 scheck[0x58]; // D4 146 | u32 key_data2; // 12C 147 | u32 oe_tag; // 130 148 | u8 key_data3[0x1C]; // 134 149 | } __attribute__((packed)) PSP_Header; 150 | 151 | /*************************************************************/ 152 | 153 | -------------------------------------------------------------------------------- /npdpc/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -I../kirk -I../common 3 | TARGET = npdpc 4 | OBJS = my_npd.o npeg.o libccc.o tlzrc.o ../common/utils.o 5 | 6 | ifeq ($(DEBUG), 1) 7 | CFLAGS+=-g -O0 8 | else 9 | CFLAGS+=-O2 10 | endif 11 | 12 | all: $(TARGET) 13 | 14 | $(TARGET): $(OBJS) 15 | $(CC) $(CFLAGS) -o $@ $(OBJS) -L ../kirk -lkirk -lz 16 | 17 | clean: 18 | $(RM) *.o $(TARGET) *.exe *.exe.stackdump 19 | 20 | -------------------------------------------------------------------------------- /npdpc/libccc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libccc.c 3 | * Character Code Conversion Library 4 | * Version 0.31 by BenHur - http://www.psp-programming.com/benhur 5 | * 6 | * This work is licensed under the Creative Commons Attribution-Share Alike 3.0 License. 7 | * See LICENSE for more details. 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | /* the following code is adapted from libLZR 0.11 (see http://www.psp-programming.com/benhur) */ 16 | 17 | static void cccLZRFillBuffer(unsigned int *test_mask, unsigned int *mask, unsigned int *buffer, unsigned char **next_in) { 18 | /* if necessary: fill up in buffer and shift mask */ 19 | if (*test_mask <= 0x00FFFFFFu) { 20 | (*buffer) = ((*buffer) << 8) + *(*next_in)++; 21 | *mask = *test_mask << 8; 22 | } 23 | } 24 | 25 | static char cccLZRNextBit(unsigned char *buf_ptr1, int *number, unsigned int *test_mask, unsigned int *mask, unsigned int *buffer, unsigned char **next_in) { 26 | /* extract and return next bit of information from in stream, update buffer and mask */ 27 | cccLZRFillBuffer(test_mask, mask, buffer, next_in); 28 | unsigned int value = (*mask >> 8) * (*buf_ptr1); 29 | if (test_mask != mask) *test_mask = value; 30 | *buf_ptr1 -= *buf_ptr1 >> 3; 31 | if (number) (*number) <<= 1; 32 | if (*buffer < value) { 33 | *mask = value; 34 | *buf_ptr1 += 31; 35 | if (number) (*number)++; 36 | return 1; 37 | } else { 38 | *buffer -= value; 39 | *mask -= value; 40 | return 0; 41 | } 42 | } 43 | 44 | static int cccLZRGetNumber(signed char n_bits, unsigned char *buf_ptr, char inc, char *flag, unsigned int *mask, unsigned int *buffer, unsigned char **next_in) { 45 | /* extract and return a number (consisting of n_bits bits) from in stream */ 46 | int number = 1; 47 | if (n_bits >= 3) { 48 | cccLZRNextBit(buf_ptr+3*inc, &number, mask, mask, buffer, next_in); 49 | if (n_bits >= 4) { 50 | cccLZRNextBit(buf_ptr+3*inc, &number, mask, mask, buffer, next_in); 51 | if (n_bits >= 5) { 52 | cccLZRFillBuffer(mask, mask, buffer, next_in); 53 | for (; n_bits >= 5; n_bits--) { 54 | number <<= 1; 55 | (*mask) >>= 1; 56 | if (*buffer < *mask) number++; else (*buffer) -= *mask; 57 | } 58 | } 59 | } 60 | } 61 | *flag = cccLZRNextBit(buf_ptr, &number, mask, mask, buffer, next_in); 62 | if (n_bits >= 1) { 63 | cccLZRNextBit(buf_ptr+inc, &number, mask, mask, buffer, next_in); 64 | if (n_bits >= 2) { 65 | cccLZRNextBit(buf_ptr+2*inc, &number, mask, mask, buffer, next_in); 66 | } 67 | } 68 | return number; 69 | } 70 | 71 | int cccLZRDecompress(void *out, unsigned int out_capacity, void *in, void *in_end) { 72 | unsigned char **next_in, *tmp, *next_out, *out_end, *next_seq, *seq_end, *buf_ptr1, *buf_ptr2; 73 | unsigned char last_char = 0; 74 | int seq_len, seq_off, n_bits, buf_off = 0, i, j; 75 | unsigned int mask = 0xFFFFFFFF, test_mask; 76 | char flag; 77 | 78 | signed char type = *(signed char*)in; 79 | unsigned int buffer = ((unsigned int)*(unsigned char*)(in+1) << 24) + 80 | ((unsigned int)*(unsigned char*)(in+2) << 16) + 81 | ((unsigned int)*(unsigned char*)(in+3) << 8) + 82 | ((unsigned int)*(unsigned char*)(in+4) ); 83 | next_in = (in_end) ? in_end : &tmp; //use user provided counter if available 84 | *next_in = in + 5; 85 | next_out = out; 86 | out_end = out + out_capacity; 87 | 88 | if (type < 0) { 89 | 90 | /* copy from stream without decompression */ 91 | 92 | seq_end = next_out + buffer; 93 | if (seq_end > out_end) return -1; 94 | while (next_out < seq_end) { 95 | *next_out++ = *(*next_in)++; 96 | } 97 | (*next_in)++; //skip 1 byte padding 98 | return next_out - (unsigned char*)out; 99 | 100 | } 101 | 102 | /* create and init buffer */ 103 | unsigned char *buf = (unsigned char*)malloc(2800); 104 | if (!buf) return -3; 105 | for (i = 0; i < 2800; i++) buf[i] = 0x80; 106 | 107 | while (1) { 108 | 109 | buf_ptr1 = buf + buf_off + 2488; 110 | if (!cccLZRNextBit(buf_ptr1, 0, &mask, &mask, &buffer, next_in)) { 111 | 112 | /* single new char */ 113 | 114 | if (buf_off > 0) buf_off--; 115 | if (next_out == out_end) return -1; 116 | buf_ptr1 = buf + (((((((int)(next_out - (unsigned char*)out)) & 0x07) << 8) + last_char) >> type) & 0x07) * 0xFF - 0x01; 117 | for (j = 1; j <= 0xFF; ) { 118 | cccLZRNextBit(buf_ptr1+j, &j, &mask, &mask, &buffer, next_in); 119 | } 120 | *next_out++ = j; 121 | 122 | } else { 123 | 124 | /* sequence of chars that exists in out stream */ 125 | 126 | /* find number of bits of sequence length */ 127 | test_mask = mask; 128 | n_bits = -1; 129 | do { 130 | buf_ptr1 += 8; 131 | flag = cccLZRNextBit(buf_ptr1, 0, &test_mask, &mask, &buffer, next_in); 132 | n_bits += flag; 133 | } while ((flag != 0) && (n_bits < 6)); 134 | 135 | /* find sequence length */ 136 | buf_ptr2 = buf + n_bits + 2033; 137 | j = 64; 138 | if ((flag != 0) || (n_bits >= 0)) { 139 | buf_ptr1 = buf + (n_bits << 5) + (((((int)(next_out - (unsigned char*)out)) << n_bits) & 0x03) << 3) + buf_off + 2552; 140 | seq_len = cccLZRGetNumber(n_bits, buf_ptr1, 8, &flag, &mask, &buffer, next_in); 141 | if (seq_len == 0xFF) return next_out - (unsigned char*)out; //end of data stream 142 | if ((flag != 0) || (n_bits > 0)) { 143 | buf_ptr2 += 56; 144 | j = 352; 145 | } 146 | } else { 147 | seq_len = 1; 148 | } 149 | 150 | /* find number of bits of sequence offset */ 151 | i = 1; 152 | do { 153 | n_bits = (i << 4) - j; 154 | flag = cccLZRNextBit(buf_ptr2 + (i << 3), &i, &mask, &mask, &buffer, next_in); 155 | } while (n_bits < 0); 156 | 157 | /* find sequence offset */ 158 | if (flag || (n_bits > 0)) { 159 | if (!flag) n_bits -= 8; 160 | seq_off = cccLZRGetNumber(n_bits/8, buf+n_bits+2344, 1, &flag, &mask, &buffer, next_in); 161 | } else { 162 | seq_off = 1; 163 | } 164 | 165 | /* copy sequence */ 166 | next_seq = next_out - seq_off; 167 | if (next_seq < (unsigned char*)out) return -2; 168 | seq_end = next_out + seq_len + 1; 169 | if (seq_end > out_end) return -1; 170 | buf_off = ((((int)(seq_end - (unsigned char*)out))+1) & 0x01) + 0x06; 171 | do { 172 | *next_out++ = *next_seq++; 173 | } while (next_out < seq_end); 174 | 175 | } 176 | last_char = *(next_out-1); 177 | } 178 | } 179 | 180 | /* end of code adapted from libLZR 0.11 (see http://www.psp-programming.com/benhur) */ 181 | 182 | -------------------------------------------------------------------------------- /npdpc/my_npd.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utils.h" 6 | 7 | #include "kirk_engine.h" 8 | #include "amctrl.h" 9 | 10 | /*****************************************************************************/ 11 | 12 | int NpegOpen(char *name, u8 *header, u8 *table, int *table_size); 13 | int NpegReadBlock(u8 *data_buf, u8 *out_buf, int block); 14 | int NpegClose(void); 15 | 16 | /*****************************************************************************/ 17 | 18 | u8 table[0x400000]; 19 | u8 data_buf[0x100000]; 20 | u8 decrypt_buf[0x200000]; 21 | u8 header[0x100]; 22 | 23 | /*****************************************************************************/ 24 | 25 | int write_file(char *file, void *buf, int size) 26 | { 27 | FILE *fp; 28 | int written; 29 | 30 | fp = fopen(file, "wb"); 31 | if(fp==NULL) 32 | return -1; 33 | written = fwrite(buf, 1, size, fp); 34 | fclose(fp); 35 | 36 | return written; 37 | } 38 | 39 | /*****************************************************************************/ 40 | 41 | int main(int argc, char *argv[]) 42 | { 43 | int table_size, retv; 44 | int blocks, block_size; 45 | int start, end, iso_size; 46 | int i; 47 | char iso_name[64]; 48 | FILE *iso_fd; 49 | 50 | printf("NP Decryptor for PC. Writen by tpu.\n"); 51 | kirk_init(); 52 | 53 | retv = NpegOpen("NP.PBP", header, table, &table_size); 54 | if(retv<0){ 55 | retv = NpegOpen("EBOOT.PBP", header, table, &table_size); 56 | if(retv<0){ 57 | printf("NpegOpen Error! %08x\n", retv); 58 | return -1; 59 | } 60 | } 61 | 62 | write_file("header.bin", header, 0x100); 63 | printf("table_size=%d\n", table_size); 64 | printf("Dumped header.\n\n"); 65 | 66 | start = *(u32*)(header+0x54); // 0x54 LBA start 67 | end = *(u32*)(header+0x64); // 0x64 LBA end 68 | iso_size = (end-start+1)*2048; 69 | 70 | block_size = *(u32*)(header+0x0c); // 0x0C block size? 71 | block_size *= 2048; 72 | 73 | printf("ISO name: %s.iso\n", header+0x70); 74 | printf("ISO size: %d MB\n", iso_size/0x100000); 75 | 76 | sprintf(iso_name, "%s.iso", header+0x70); 77 | iso_fd = fopen(iso_name, "wb"); 78 | if(iso_fd==NULL){ 79 | printf("Error creating %s\n", iso_name); 80 | } 81 | 82 | blocks = table_size/32; 83 | 84 | for(i=0; i 4 | #include 5 | #include 6 | #include "utils.h" 7 | 8 | #include "kirk_engine.h" 9 | #include "amctrl.h" 10 | 11 | /*****************************************************************************/ 12 | 13 | int write_file(char *file, void *buf, int size); 14 | int cccLZRDecompress(void *out, unsigned int out_capacity, void *in, void *in_end); 15 | int lzrc_decompress(void *out, int out_len, void *in, int in_len); 16 | int lzrc_compress(void *out, int out_len, void *in, int in_len); 17 | 18 | /*****************************************************************************/ 19 | 20 | u8 header_key[16]; 21 | FILE *iso_fd; 22 | int offset_psar; 23 | u8 *np_table; 24 | int total_blocks; 25 | int block_size; 26 | u8 version_key[16]; 27 | 28 | /*****************************************************************************/ 29 | 30 | int NpegOpen(char *name, u8 *header, u8 *table, int *table_size) 31 | { 32 | MAC_KEY mkey; 33 | CIPHER_KEY ckey; 34 | u8 pbp_buf[0x28]; 35 | u8 *np_header; 36 | int start, end, lba_size, offset_table; 37 | u32 *tp; 38 | int retv, i; 39 | 40 | np_header = header; 41 | np_table = table; 42 | 43 | iso_fd = fopen(name, "rb"); 44 | if(iso_fd==NULL) 45 | return -2; 46 | 47 | // read PBP header 48 | retv = fread(pbp_buf, 0x28, 1, iso_fd); 49 | if(retv!=1) 50 | return -3; 51 | 52 | // check "PBP" 53 | if(*(u32*)pbp_buf!=0x50425000) 54 | return -4; 55 | 56 | offset_psar = *(u32*)(pbp_buf+0x24); 57 | fseek(iso_fd, offset_psar, SEEK_SET); 58 | 59 | retv = fread(np_header, 0x0100, 1, iso_fd); 60 | if(retv!=1) 61 | return -6; 62 | 63 | // check "NPUMDIMG" 64 | if(strncmp((char*)np_header, "NPUMDIMG", 8)){ 65 | printf("DATA.PSAR isn't a NPUMDIMG!\n"); 66 | return -7; 67 | } 68 | 69 | // bbmac_getkey 70 | sceDrmBBMacInit(&mkey, 3); 71 | sceDrmBBMacUpdate(&mkey, np_header, 0xc0); 72 | bbmac_getkey(&mkey, np_header+0xc0, version_key); 73 | 74 | // header MAC check 75 | sceDrmBBMacInit(&mkey, 3); 76 | sceDrmBBMacUpdate(&mkey, np_header, 0xc0); 77 | retv = sceDrmBBMacFinal2(&mkey, np_header+0xc0, version_key); 78 | if(retv){ 79 | printf("NP header MAC check failed!\n"); 80 | return -13; 81 | } 82 | 83 | write_file("version_key.bin", version_key, 16); 84 | 85 | // decrypt NP header 86 | memcpy(header_key, np_header+0xa0, 0x10); 87 | sceDrmBBCipherInit(&ckey, 1, 2, header_key, version_key, 0); 88 | sceDrmBBCipherUpdate(&ckey, np_header+0x40, 0x60); 89 | sceDrmBBCipherFinal(&ckey); 90 | 91 | start = *(u32*)(np_header+0x54); // LBA start 92 | end = *(u32*)(np_header+0x64); // LBA end 93 | block_size = *(u32*)(np_header+0x0c); // block_size 94 | lba_size = (end-start+1); // LBA size of ISO 95 | total_blocks = (lba_size+block_size-1)/block_size; // total blocks; 96 | 97 | offset_table = *(u32*)(np_header+0x6c); // table offset 98 | fseek(iso_fd, offset_psar+offset_table, SEEK_SET); 99 | 100 | *table_size = total_blocks*32; 101 | retv = fread(np_table, *table_size, 1, iso_fd); 102 | if(retv!=1) 103 | return -18; 104 | 105 | // table mac test 106 | int msize; 107 | u8 bbmac[16]; 108 | 109 | sceDrmBBMacInit(&mkey, 3); 110 | for(i=0; i<*table_size; i+=0x8000){ 111 | if(i+0x8000>*table_size) 112 | msize = *table_size-i; 113 | else 114 | msize = 0x8000; 115 | sceDrmBBMacUpdate(&mkey, np_table+i, msize); 116 | } 117 | sceDrmBBMacFinal(&mkey, bbmac, version_key); 118 | bbmac_build_final2(3, bbmac); 119 | 120 | tp = (u32*)np_table; 121 | for(i=0; i>4); 202 | sceDrmBBCipherUpdate(&ckey, data_buf, tp[5]); 203 | sceDrmBBCipherFinal(&ckey); 204 | } 205 | 206 | if(tp[5] 7 | #include 8 | #include 9 | 10 | #include "kirk_engine.h" 11 | #include "crypto.h" 12 | #include "psp_headers.h" 13 | #include "amctrl.h" 14 | #include "utils.h" 15 | 16 | /*************************************************************/ 17 | #if 0 18 | typedef struct { 19 | u8 key[16]; // 00: used to decrypt data content. 20 | u32 version; // 10: always 00 21 | u32 data_size; // 14 22 | u32 block_size; // 18 23 | u32 data_offset; // 1C 24 | u8 unk_20[16]; 25 | }PGD_DESC; 26 | 27 | 28 | typedef struct { 29 | PGD_DESC pgdesc; 30 | u32 key_index; // 0x30 31 | u8 pgd_key[16]; // 0x34 32 | u32 flag; // 0x44 33 | u32 flag_open; // 0x48 34 | u32 pgd_offset; // 0x4C 35 | int seek_offset; // 0x50 36 | u32 data_offset; // 0x54 37 | u32 table_offset;// 0x58 38 | u32 unk_5c; 39 | u32 unk_60; 40 | }PspIoHookParam; 41 | 42 | 43 | u8 dnas_key1A90[] = {0xED,0xE2,0x5D,0x2D,0xBB,0xF8,0x12,0xE5,0x3C,0x5C,0x59,0x32,0xFA,0xE3,0xE2,0x43}; 44 | u8 dnas_key1AA0[] = {0x27,0x74,0xFB,0xEB,0xA4,0xA0, 1,0xD7, 2,0x56,0x9E,0x33,0x8C,0x19,0x57,0x83}; 45 | 46 | 47 | 48 | int process_pgd(u8 *pgd_buf, int pgd_size, int pgd_flag) 49 | { 50 | MAC_KEY mkey; 51 | CIPHER_KEY ckey; 52 | u8 *fkey, vkey[16]; 53 | int key_index, mac_type, cipher_type, drm_type; 54 | int retv, file_size, block_size, data_offset, table_size, align_size; 55 | 56 | 57 | key_index = *(u32*)(pgd_buf+4); 58 | drm_type = *(u32*)(pgd_buf+8); 59 | 60 | if(drm_type==1){ 61 | mac_type = 1; 62 | pgd_flag |= 4; 63 | if(key_index>1){ 64 | mac_type = 3; 65 | pgd_flag |= 8; 66 | } 67 | cipher_type = 1; 68 | }else{ 69 | mac_type = 2; 70 | cipher_type = 2; 71 | } 72 | 73 | // select fixed key 74 | fkey = NULL; 75 | if(pgd_flag&2) 76 | fkey = dnas_key1A90; 77 | if(pgd_flag&1) 78 | fkey = dnas_key1AA0; 79 | if(fkey==NULL){ 80 | printf("invalid pgd_flag! %08x\n", pgd_flag); 81 | return -1; 82 | } 83 | 84 | // MAC_0x80 check 85 | sceDrmBBMacInit(&mkey, mac_type); 86 | sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x80); 87 | retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x80, fkey); 88 | if(retv){ 89 | printf("MAC_80 check failed!: %08x(%d)\n", retv, retv); 90 | return -2; 91 | }else{ 92 | printf("MAC_80 check pass.\n\n"); 93 | } 94 | 95 | // MAC_0x70 96 | sceDrmBBMacInit(&mkey, mac_type); 97 | sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x70); 98 | bbmac_getkey(&mkey, pgd_buf+0x70, vkey); 99 | hex_dump("Get version_key from MAC_70:", vkey, 16); 100 | 101 | // decrypt PGD_DESC 102 | sceDrmBBCipherInit(&ckey, cipher_type, 2, pgd_buf+0x10, vkey, 0); 103 | sceDrmBBCipherUpdate(&ckey, pgd_buf+0x30, 0x30); 104 | sceDrmBBCipherFinal(&ckey); 105 | hex_dump("PGD header", pgd_buf, 0x90); 106 | 107 | file_size = *(u32*)(pgd_buf+0x44); 108 | block_size = *(u32*)(pgd_buf+0x48); 109 | data_offset = *(u32*)(pgd_buf+0x4c); 110 | 111 | file_size = (file_size+15)&~15; 112 | align_size = (file_size+block_size-1)&~(block_size-1); 113 | table_size = align_size/block_size; 114 | table_size *= 16; 115 | 116 | printf("file_size=%08x block_size=%08x table_size=%08x data_offset=%08x\n\n", 117 | file_size, block_size, table_size, data_offset); 118 | 119 | if(file_size+table_size>pgd_size){ 120 | printf("invalid pgd data!\n"); 121 | return -3; 122 | } 123 | 124 | // table MAC check 125 | sceDrmBBMacInit(&mkey, mac_type); 126 | sceDrmBBMacUpdate(&mkey, pgd_buf+data_offset+file_size, table_size); 127 | retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x60, vkey); 128 | if(retv){ 129 | printf("MAC_table check failed!: %08x(%d)\n", retv, retv); 130 | return -4; 131 | }else{ 132 | printf("MAC_table check pass.\n\n"); 133 | } 134 | 135 | // decrypt data 136 | sceDrmBBCipherInit(&ckey, cipher_type, 2, pgd_buf+0x30, vkey, 0); 137 | sceDrmBBCipherUpdate(&ckey, pgd_buf+0x90, file_size); 138 | sceDrmBBCipherFinal(&ckey); 139 | hex_dump("PGD data", pgd_buf+0x90, (file_size>0x100)? 0x100 : file_size); 140 | 141 | file_size = *(u32*)(pgd_buf+0x44); 142 | return file_size; 143 | } 144 | #endif 145 | 146 | int verbose = 0; 147 | 148 | int pgd_decrypt(u8 *pgd_buf, int pgd_size, int pgd_flag, u8 *pgd_vkey); 149 | 150 | int process_pgd(char *pgd_file) 151 | { 152 | u8 *data_buf, *pgd_buf; 153 | char fname[256]; 154 | int retv, data_size, pgd_size, pgd_flag; 155 | 156 | data_buf = load_file(pgd_file, &data_size); 157 | if(data_buf==NULL){ 158 | printf("Open input file <%s> error!\n", pgd_file); 159 | return -1; 160 | } 161 | if(data_size<0x90){ 162 | free(data_buf); 163 | return -1; 164 | } 165 | 166 | if(*(u32*)(data_buf+0)==0x44475000){ 167 | pgd_buf = data_buf; 168 | pgd_size = data_size; 169 | }else if(*(u32*)(data_buf+0x90)==0x44475000){ 170 | pgd_buf = data_buf+0x90; 171 | pgd_size = data_size-0x90; 172 | }else{ 173 | free(data_buf); 174 | return -1; 175 | } 176 | printf("\nProcess %s ...\n", pgd_file); 177 | 178 | // 0x40xxxxxx : 2 179 | // 0x44xxxxxx : 1 180 | // default as 2 181 | pgd_flag = 2; 182 | 183 | retv = pgd_decrypt(pgd_buf, pgd_size, pgd_flag, NULL); 184 | if(retv>0){ 185 | sprintf(fname, "%s.decrypt", pgd_file); 186 | write_file(fname, pgd_buf+0x90, retv); 187 | printf("Save %s ...\n", fname); 188 | } 189 | 190 | free(data_buf); 191 | return 0; 192 | } 193 | 194 | 195 | int main(int argc, char *argv[]) 196 | { 197 | printf("\n"); 198 | printf("pgdecrypt: decrypt EDAT/PGD file. writen by tpu.\n"); 199 | printf("-------------------------------------------------------------\n"); 200 | printf("\n"); 201 | 202 | if(argc==2 && (strcmp(argv[1], "-v")==0)) 203 | verbose = 1; 204 | 205 | return walk_dir(".", process_pgd, 0); 206 | 207 | } 208 | 209 | -------------------------------------------------------------------------------- /npdrm/dnas_ida.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /**************************************************/ 4 | /* error codes */ 5 | /**************************************************/ 6 | #define SCE_GAMEDATA_ERROR_INVALID_ARG 0x80510201 7 | #define SCE_GAMEDATA_ERROR_MFILE 0x80510202 8 | #define SCE_GAMEDATA_ERROR_BADF 0x80510203 9 | #define SCE_GAMEDATA_ERROR_INVALID_FORMAT 0x80510204 10 | #define SCE_GAMEDATA_ERROR_UNKNOWN_VERSION 0x80510205 11 | #define SCE_GAMEDATA_ERROR_SECURE_INSTALL_ID 0x80510206 12 | #define SCE_GAMEDATA_ERROR_BROKEN_DATA 0x80510207 13 | 14 | /**************************************************/ 15 | /* ioctl commands */ 16 | /**************************************************/ 17 | #define SCE_GAMEDATA_IOCTL_BASE (0x41 << 20) 18 | #define SCE_GAMEDATA_SET_SECURE_INSTALL_ID (SCE_GAMEDATA_IOCTL_BASE|0x01) 19 | 20 | 21 | typedef struct { 22 | u8 key[16]; // 00 23 | u32 version; // 10: always 00 24 | u32 file_size; // 14 25 | u32 block_size; // 18 26 | u32 data_offset; // 1C 27 | u8 unk_20[16]; 28 | }PGD_DESC; 29 | 30 | 31 | typedef struct { 32 | PGD_DESC pgdesc; 33 | u8 pgd_key[0x10]; 34 | u32 flag; // 0x40 35 | u32 flag_open; // 0x44 36 | u32 pgd_offset; // 0x48 37 | int seek_offset; // 0x4C 38 | u32 data_offset; // 0x50 39 | u32 table_offset;// 0x54 40 | u32 unk_58; 41 | u32 unk_5c; 42 | }PspIoHookParam; 43 | 44 | 45 | typedef struct 46 | { 47 | u32 unk_00; 48 | u32 fs_num; 49 | PSpIoDrvFuncs *funcs; 50 | PspIoHookParam *hp; 51 | }PspIoHookFileArg; 52 | 53 | 54 | 55 | 56 | 57 | int dnas_sema; 58 | 59 | 60 | 61 | u8 loc_1A90[] = {0xED,0xE2,0x5D,0x2D,0xBB,0xF8,0x12,0xE5,0x3C,0x5C,0x59,0x32,0xFA,0xE3,0xE2,0x43}; 62 | u8 loc_1AA0[] = {0x27,0x74,0xFB,0xEB,0xA4,0xA0, 1,0xD7, 2,0x56,0x9E,0x33,0x8C,0x19,0x57,0x83}; 63 | 64 | u8 loc_1AC0[0x640]; 65 | 66 | // dnas_init 67 | int hook_func0_E8() 68 | { 69 | return 0; 70 | } 71 | 72 | // dnas_exit 73 | int hook_func1_F0() 74 | { 75 | return 0; 76 | } 77 | 78 | // dnas_match 79 | int hook_func2_F8(PspIoHookFileArg *file, int a1, int a2) 80 | { 81 | return (a2>>30)&1; 82 | } 83 | 84 | // dnas_open 85 | int hook_func3_100(PspIoHookFileArg *file, char *name, int flag, int mode) 86 | { 87 | s1 = a2; 88 | s5 = a3; 89 | s4 = a1; 90 | s3 = a0; 91 | s7 = 0xffffffff; 92 | 93 | if(flag&2) 94 | return 0x80510201; 95 | 96 | s2 = loc_1780; 97 | s6 = (flag&0x04000000)? 1 : 2; 98 | 99 | // max open files: 8 100 | a1 = *(u32*)(s2+0x304); 101 | if(a1>7) 102 | return 0x80510202; 103 | 104 | retv = file->funcs->IoOpen(file->fs_num, name, flag, mode); 105 | if(retv<0) 106 | return retv; 107 | 108 | *(u32*)(s2+0x304) += 1; 109 | s2 = retv; 110 | 111 | retv = file->funcs->IoIoctl(file->fs_num, 0x00208002, 0, 0, 0, 0); 112 | if(retv<0){ 113 | retv = file->funcs->IoIoctl(file->fs_num, 0x00208011, 0, 0, 0, 0); 114 | if(retv<0){ 115 | retv = 0x80020146; 116 | goto _error; 117 | } 118 | } 119 | 120 | t9 = loc_1780; 121 | s1 = t9; 122 | s0 = 0; 123 | v1 = t9+0x40; 124 | 125 | s7 = -1; 126 | while(s0<8){ 127 | a3 = *(u32*)(v1); 128 | v1 += 0x60; 129 | if(a3==0){ 130 | memset(s1, 0, 0x60); 131 | s7 = s0; 132 | *(u32*)(s1+0x40) = s6; 133 | break; 134 | } 135 | s0 += 1; 136 | s1 += 0x60; 137 | } 138 | if(s7<0){ 139 | // xxxx 140 | retv = 0x80510202; 141 | goto _error: 142 | } 143 | 144 | s0 = s7*2; 145 | a1 = s0+s7; // s7*3 146 | v1 = a1<<5; // s7*3*32 147 | fp = v1+a2; // a2+s7*0x60 148 | 149 | *(u32*)(fp+0x44) = 0; 150 | file->unk_0c = fp; 151 | return s2; 152 | 153 | _error: 154 | if(s2>=0){ 155 | file->funcs->IoClose(file->fs_num); 156 | *(u32*)(s2+0x304) -= 1; 157 | if(s7){ 158 | t5 = s7*2; 159 | t4 = t5+s7; // s7*3 160 | t3 = t4<<5; // s7*3*32 161 | a0 = t3+v1; // t3+s7*0x60 162 | memset(a0, 0, 0x60); 163 | } 164 | } 165 | 166 | return retv; 167 | } 168 | 169 | // dnas_close 170 | int hook_func4_35C(PspIoHookFileArg *file) 171 | { 172 | v1 = a0; 173 | 174 | file->funcs->IoClose(file->fs_num); 175 | 176 | s0 = file->unk_0c; 177 | 178 | memset(s0, 0, 0x60); 179 | *(u32*)(s2+0x304) -= 1; 180 | 181 | return 0; 182 | } 183 | 184 | // dnas_lseek 185 | int hook_func7_3F4(PspIoHookFileArg *file, int offset, int mode) 186 | { 187 | s3 = file->unk_0c; 188 | 189 | a2 = *(u32*)(s3+0x44); 190 | if((a2&8)==0) 191 | return 0x80510206; 192 | 193 | if(mode<0 || mode>2) 194 | return 0x80510201; 195 | 196 | if(mode==SEEK_CUR){ 197 | v0 = *(u32*)(s3+0x4c); 198 | offset += v0; 199 | }else if(s2==SEEK_END){ 200 | v0 = *(u32*)(s3+0x14); 201 | offset += v0; 202 | } 203 | 204 | file_size = *(u32*)(s3+0x14); 205 | if(offset>file_size){ 206 | offset = file_size; 207 | } 208 | *(u32*)(s3+0x4c) = offset; 209 | 210 | return offset; 211 | } 212 | 213 | 214 | 215 | int sub_12B4(u8 *buf, int size, u32 seed, u8 *vkey, u8 *hkey, int type) 216 | { 217 | CIPHER_KEY ckey; 218 | 219 | v1 = a3; // vkey 220 | t2 = t1; // type 221 | s0 = a0; // buf 222 | s1 = a1; // size 223 | 224 | retv = sceDrmBBCipherInit(&ckey, type, 2, hkey, vkey, seed); 225 | if(retv<0) 226 | return retv; 227 | 228 | retv = sceDrmBBCipherUpdate(&ckey, buf, size); 229 | if(retv<0) 230 | return retv; 231 | 232 | retv = sceDrmBBCipherFinal(&ckey); 233 | if(retv<0) 234 | return retv; 235 | 236 | return 0; 237 | } 238 | 239 | 240 | 241 | int sub_1368(u8 *buf, int size, u8 *key, u8 *bbmac, int type) 242 | { 243 | u8 tmp[0x10]; 244 | MAC_KEY mkey; 245 | int retv; 246 | 247 | if(bbmac==0) 248 | return SCE_GAMEDATA_ERROR_INVALID_ARG; 249 | 250 | retv = sceDrmBBMacInit(&mkey, type); 251 | if(retv<0) 252 | return SCE_GAMEDATA_ERROR_BROKEN_DATA; 253 | 254 | retv = sceDrmBBMacUpdate(&mkey, buf, size); 255 | if(retv<0) 256 | return SCE_GAMEDATA_ERROR_BROKEN_DATA; 257 | 258 | retv = sceDrmBBMacFinal(&mkey, tmp, key); 259 | if(retv<0) 260 | return SCE_GAMEDATA_ERROR_BROKEN_DATA; 261 | 262 | if(memcmp(bbmac, tmp, 0x10)) 263 | return SCE_GAMEDATA_ERROR_BROKEN_DATA; 264 | 265 | memset(tmp, 0, 0x10); 266 | 267 | return 0; 268 | } 269 | 270 | 271 | 272 | 273 | int _pgd_open_1124(u8 *buf, u8 *vkey, int flag) 274 | { 275 | v1 = 0x80510201; 276 | type = 2; 277 | s3 = a2; 278 | s2 = 0; 279 | s1 = a1; 280 | s0 = a0; 281 | 282 | if(key==NULL) 283 | return SCE_GAMEDATA_ERROR_INVALID_ARG; 284 | 285 | // check "\0PGD" 286 | if(*(u32*)(buf+0)!=0x44475000) 287 | return SCE_GAMEDATA_ERROR_INVALID_FORMAT; 288 | if(*(u32*)(buf+4)!=0x00000001) 289 | return SCE_GAMEDATA_ERROR_UNKNOWN_VERSION; 290 | 291 | if(*(u32*)(buf+8)==0x00000000){ 292 | if(flag&4) 293 | return SCE_GAMEDATA_ERROR_INVALID_FORMAT; 294 | }else if(*(u32*)(buf+8)==0x00000001){ 295 | flag |= 4; 296 | type = 1; 297 | }else 298 | return SCE_GAMEDATA_ERROR_INVALID_FORMAT; 299 | 300 | if(flag&2) 301 | fkey = 0x1A90; 302 | if(flag&1) 303 | fkey = 0x1AA0; 304 | if(fkey==0) 305 | return SCE_GAMEDATA_ERROR_INVALID_ARG; 306 | 307 | // sub_1368(u8 *buf, int size, u8 *key, u8 *bbmac, int type) 308 | retv = sub_1368(buf, 0x80, fkey, buf+0x80, type); 309 | if(retv<0) 310 | return SCE_GAMEDATA_ERROR_INVALID_FORMAT; 311 | 312 | retv = sub_1368(buf, 0x70, vkey, buf+0x70, type); 313 | if(retv<0) 314 | return SCE_GAMEDATA_ERROR_SECURE_INSTALL_ID; 315 | 316 | // sub_12B4(u8 *buf, int size, u32 seed, u8 *vkey, u8 *hkey, int type) 317 | retv = sub_12B4(buf+0x30, 0x30, 0, vkey, buf+0x10, type); 318 | if(retv<0) 319 | return SCE_GAMEDATA_ERROR_UNKNOWN_VERSION; 320 | 321 | if(*(u32*)(buf+0x40)) 322 | return SCE_GAMEDATA_ERROR_UNKNOWN_VERSION; 323 | 324 | if(*(u32*)(buf+0x48)!=0x0400) 325 | return SCE_GAMEDATA_ERROR_INVALID_FORMAT; 326 | 327 | flag |= 8; 328 | 329 | return flag; 330 | } 331 | 332 | /* 333 | * PGD header: 334 | * 00: PGD 335 | * 10: header_key 336 | * 20: unk 337 | * 30: encrypted data 338 | * 40: 339 | * 50: 340 | * 60: MAC of table 341 | * 70: MAC of 00-60 342 | * 80: MAC of 00-70 343 | * 344 | */ 345 | 346 | int sub_B60(PspIoHookFileArg *file, u8 *key) 347 | { 348 | u8 tmp[16]; 349 | 350 | s1 = file->unk_0c; 351 | s5 = loc_1AC0; 352 | 353 | memcpy(s1+0x30, key, 0x10); 354 | 355 | offset = *(u32*)(s1+0x48); 356 | retv = file->funcs->IoLseek(file->fs_num, offset, SEEK_SET); 357 | if(retv!=offset) 358 | goto _exit; 359 | 360 | retv = file->funcs->IoRead(file->fs_num, s5, 0x90); 361 | if(retv<0x90) 362 | goto _exit; 363 | 364 | flag = *(u32*)(s1+0x40); 365 | retv = _pgd_open_1124(s5, key, flag); 366 | if(retv<0 || retv&8==0){ 367 | *(u32*)(s1+0x44) = 0; 368 | goto _exit; 369 | } 370 | *(u32*)(s1+0x44) = retv; 371 | 372 | memcpy(s1, s5+0x30, 0x30); 373 | memcpy(tmp, s5+0x60, 0x10); 374 | 375 | fp = (retv&4)? 1 : 2 ; 376 | 377 | t0 = *(u32*)(s1+0x14); // file_size 378 | t9 = *(u32*)(s1+0x18); // block_size 0x00000400 379 | 380 | s2 = t0+0x0f; 381 | s2 &= 0xfffffff0; // file_size 382 | 383 | a1 = s2+t9; 384 | v1 = a1-1; // file_size+block_size-1; 385 | a2 = -t9; // 0xfffffc00; 386 | s7 = v1&a2; // s7 = file_size_block 387 | t8 = t9>>4; 388 | s7 = s7/t8; // s7 = table_size; 389 | 390 | t5 = *(u32*)(s1+0x48); // PGD offset 391 | t6 = *(u32*)(s1+0x1C); // data offset in PGD 392 | t4 = s2+0x90; 393 | t3 = t6+t5; 394 | s0 = t4+t5; // PGD_offset+0x90+file_size 395 | *(u32*)(s1+0x50) = t3; // data offset in EDATA 396 | *(u32*)(s1+0x54) = s0; // table offset in EDATA 397 | t2 = 0x0007ffff; 398 | if(t2funcs->IoLseek(file->fs_num, s0, SEEK_SET); 406 | if(retv<0) 407 | goto _exit; 408 | 409 | for(i=0; i0x400) 412 | s0 = 0x400; 413 | retv = file->funcs->IoRead(file->fs_num, s5, s0); 414 | if(retvunk_0c; 446 | v0 = *(u32*)(s0+0x48); 447 | if(v0==a1) 448 | return 0; 449 | 450 | *(u32*)(s0+0x44) = 0; 451 | *(u32*)(s0+0x48) = a1; 452 | 453 | return 0; 454 | } 455 | 456 | // set 0x58 457 | int sub_EB8(PspIoHookFileArg *file, u32 a1) 458 | { 459 | s0 = file->unk_0c; 460 | *(u32*)(s0+0x58) = a1; 461 | 462 | return 0; 463 | } 464 | 465 | // seek and read 466 | int sub_F28(PspIoHookFileArg *file, u8 *buf, int offset, int size) 467 | { 468 | 469 | retv = file->funcs->IoLseek(file->fs_num, offset, SEEK_SET); 470 | if(retv==offset){ 471 | retv = file->funcs->IoRead(file->fs_num, buf, size); 472 | if(retvunk_0c; 485 | a2 = *(u32*)(s0+0x44); 486 | if(a2&8==0) 487 | return = SCE_GAMEDATA_ERROR_SECURE_INSTALL_ID; 488 | 489 | return 0; 490 | } 491 | 492 | int sub_1094(PspIoHookFileArg *file) 493 | { 494 | s0 = file->unk_0c; 495 | a2 = *(u32*)(s0+0x44); 496 | if(a2&8==0) 497 | return = SCE_GAMEDATA_ERROR_SECURE_INSTALL_ID; 498 | 499 | s1 = *(u32*)(s0+0x14); 500 | return s1; 501 | } 502 | 503 | 504 | int _dnas_ioctl_9F0(PspIoHookFileArg *file, int cmd, int a2, int a3, int t0) 505 | { 506 | s0 = a0; 507 | v0 = cmd-0x04100001; 508 | 509 | retv = SCE_GAMEDATA_ERROR_INVALID_ARG; 510 | switch(v0){ 511 | case 0: 512 | // pgd open 513 | if(a2<1 || a3>15) 514 | break; 515 | retv = sub_B60(a0, a2); 516 | break; 517 | case 1: 518 | // set pgd offset 519 | if(a2<1 || a3>4) 520 | break; 521 | retv = sub_E3C(a0, a2); 522 | break; 523 | case 2: 524 | retv = sceKernelApplicationType(); 525 | if(retv!=a2){ 526 | retv = SCE_GAMEDATA_ERROR_INVALID_ARG; 527 | break; 528 | } 529 | retv = sub_EB8(a0, 1); 530 | break; 531 | case 3: 532 | retv = sub_EB8(a0, 0); 533 | break; 534 | case 4: 535 | // seek and read 536 | if(a2<1 || a3>8 || t0==0) 537 | break; 538 | a3 = *(u32*)(a2+4); 539 | if(t1 4 | #include 5 | #include 6 | #include "kirk_engine.h" 7 | #include "amctrl.h" 8 | #include "crypto.h" 9 | #include "ecdsa.h" 10 | #include "utils.h" 11 | 12 | 13 | 14 | u8 pubkey_edat_x[20] = {0x1F,0x07,0x2B,0xCC,0xC1,0x62,0xF2,0xCF,0xAE,0xA0,0xE7,0xF4,0xCD,0xFD,0x9C,0xAE,0xC6,0xC4,0x55,0x21}; 15 | u8 pubkey_edat_y[20] = {0x53,0x01,0xF4,0xE3,0x70,0xC3,0xED,0xE2,0xD4,0xF5,0xDB,0xC3,0xA7,0xDE,0x8C,0xAA,0xE8,0xAD,0x5B,0x7D}; 16 | 17 | 18 | u8 edat_aeskey[16] = {0xBA,0x87,0xE4,0xAB,0x2C,0x60,0x5F,0x59,0xB8,0x3B,0xDB,0xA6,0x82,0xFD,0xAE,0x14}; 19 | 20 | extern ECDSA_PARAM ecdsa_app; 21 | extern u8 priv_key_edata[]; 22 | 23 | int verbose = 0; 24 | 25 | /*************************************************************/ 26 | 27 | int edata_check_ecdsa(u8 *edata_buf) 28 | { 29 | u8 sha1_hash[20]; 30 | int retv; 31 | 32 | printf("EDATA ID: %s\n", (char*)(edata_buf+0x10)); 33 | 34 | ecdsa_set_curve(&ecdsa_app); 35 | ecdsa_set_pub(pubkey_edat_x, pubkey_edat_y); 36 | 37 | SHA1(edata_buf, 0x58, sha1_hash); 38 | retv = ecdsa_verify(sha1_hash, edata_buf+0x58, edata_buf+0x6c); 39 | if(retv==0){ 40 | //printf("ECDSA verify passed!\n"); 41 | }else{ 42 | printf("edata_check_ecdsa: ECDSA verify failed!\n"); 43 | } 44 | 45 | return retv; 46 | } 47 | 48 | 49 | int edata_sign_free(u8 *edata_buf, u8 *pgd_key) 50 | { 51 | MAC_KEY mkey; 52 | AES_ctx aes; 53 | u8 sha1_hash[20], license_key[16]; 54 | int flag, i; 55 | 56 | printf("re-sign EDATA ...\n"); 57 | 58 | flag = *(u8*)(edata_buf+15); 59 | 60 | // get license_key 61 | if(flag&1){ 62 | sceDrmBBMacInit(&mkey, 3); 63 | sceDrmBBMacUpdate(&mkey, edata_buf, 0x80); 64 | bbmac_getkey(&mkey, edata_buf+0x80, license_key); 65 | if(verbose) hex_dump("license key", license_key, 16); 66 | } 67 | 68 | // change to use free license 69 | *(u32*)(edata_buf+8) = 0x01000000; 70 | 71 | // build ecdsa 72 | ecdsa_set_curve(&ecdsa_app); 73 | ecdsa_set_priv(priv_key_edata); 74 | SHA1(edata_buf, 0x58, sha1_hash); 75 | ecdsa_sign(sha1_hash, edata_buf+0x58, edata_buf+0x6c, NULL); 76 | 77 | // build BBMAC 78 | if(flag&1){ 79 | sceDrmBBMacInit(&mkey, 3); 80 | sceDrmBBMacUpdate(&mkey, edata_buf, 0x80); 81 | sceDrmBBMacFinal(&mkey, edata_buf+0x80, license_key); 82 | bbmac_build_final2(3, edata_buf+0x80); 83 | } 84 | 85 | // build PGD key 86 | sceNpDrmGetFixedKey(pgd_key, (char*)(edata_buf+16), 0x01000000); 87 | if(verbose) hex_dump("get_fixed_key", pgd_key, 16); 88 | 89 | if(flag&1){ 90 | for(i=0; i<16; i++){ 91 | pgd_key[i] ^= license_key[i]; 92 | } 93 | } 94 | 95 | AES_set_key(&aes, edat_aeskey, 128); 96 | AES_decrypt(&aes, pgd_key, pgd_key); 97 | if(verbose) hex_dump("new PGD key", pgd_key, 16); 98 | 99 | return 0; 100 | } 101 | 102 | /*************************************************************/ 103 | 104 | 105 | int pgd_decrypt(u8 *pgd_buf, int pgd_size, int pgd_flag, u8 *pgd_vkey); 106 | int pgd_encrypt(u8 *pgd_buf, int pgd_flag, u8 *vkey); 107 | 108 | int free_edata(char *edata_name) 109 | { 110 | u8 *edata_buf; 111 | u32 *hd; 112 | u8 pgd_key[16]; 113 | int retv, edata_size, pgd_offset; 114 | 115 | edata_buf = load_file(edata_name, &edata_size); 116 | if(edata_buf==NULL){ 117 | printf("Open input file <%s> error!\n", edata_name); 118 | return -1; 119 | } 120 | 121 | hd = (u32*)edata_buf; 122 | if(hd[0]!=0x50535000 || hd[1]!=0x54414445){ 123 | free(edata_buf); 124 | return -1; 125 | } 126 | printf("\nProcess %s ...\n", edata_name); 127 | 128 | 129 | retv = edata_check_ecdsa(edata_buf); 130 | if(retv) 131 | return retv; 132 | 133 | edata_sign_free(edata_buf, pgd_key); 134 | 135 | 136 | // PGD 137 | pgd_offset = *(u32*)(edata_buf+0x0c); 138 | pgd_offset &= 0x00ffffff; 139 | 140 | retv = pgd_decrypt(edata_buf+pgd_offset, edata_size-pgd_offset, 2, NULL); 141 | if(retv<0){ 142 | printf("pgd_decrypt failed! %08x(%d)\n", retv, retv); 143 | return -1; 144 | } 145 | 146 | retv = pgd_encrypt(edata_buf+pgd_offset, 2, pgd_key); 147 | if(retv<0){ 148 | printf("pgd_encrypt failed! %08x(%d)\n", retv, retv); 149 | return -1; 150 | } 151 | 152 | write_file(edata_name, edata_buf, edata_size); 153 | printf("write %s\n\n", edata_name); 154 | 155 | return 0; 156 | } 157 | 158 | int main(int argc, char *argv[]) 159 | { 160 | printf("\n"); 161 | printf("freedata: convert EDAT file to use fixed license. writen by tpu.\n"); 162 | printf("-------------------------------------------------------------\n"); 163 | printf("\n"); 164 | 165 | if(argc==2 && (strcmp(argv[1], "-v")==0)) 166 | verbose = 1; 167 | 168 | return walk_dir(".", free_edata, 0); 169 | } 170 | 171 | -------------------------------------------------------------------------------- /npdrm/npdk_test/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = my_npd 2 | OBJS = my_npd.o npeg.o printk.o sceAmctrl_driver.o scePspNpDrm_driver.o 3 | 4 | CFLAGS = -O2 -G0 -Wall -I. 5 | LDFLAGS = -mno-crt0 -nostartfiles -L. 6 | LIBS += -lpsppower_driver 7 | 8 | BUILD_PRX=1 9 | USE_KERNEL_LIBS=1 10 | USE_KERNEL_LIBC=1 11 | 12 | EXTRA_TARGETS = EBOOT.PBP 13 | PSP_EBOOT_TITLE = New Npdecrypt 14 | 15 | PSPSDK = $(shell psp-config --pspsdk-path) 16 | include $(PSPSDK)/lib/build.mak 17 | 18 | -------------------------------------------------------------------------------- /npdrm/npdk_test/lzdecode.h: -------------------------------------------------------------------------------- 1 | #ifndef __lzdecode__ 2 | #define __lzdecode__ 3 | 4 | static unsigned char lzdecode[] __attribute__((aligned(16))) = { 5 | 0xf0, 0xf4, 0xbd, 0x27, 0x00, 0x0b, 0xb2, 0xaf, 0x21, 0x60, 0x85, 0x00, 0xff, 0xff, 0x8b, 0x24, 6 | 0xfc, 0x0a, 0xb1, 0xaf, 0x06, 0x00, 0x0a, 0x24, 0x08, 0xf5, 0xa5, 0x27, 0xf8, 0x0a, 0xb0, 0xaf, 7 | 0x21, 0xc8, 0x00, 0x00, 0x01, 0x00, 0x08, 0x24, 0x04, 0x0b, 0xb3, 0xaf, 0xff, 0xff, 0x13, 0x24, 8 | 0x08, 0x0b, 0xb4, 0xaf, 0xc0, 0xff, 0x94, 0x25, 0x04, 0x28, 0x14, 0x7c, 0x00, 0x00, 0xd0, 0x80, 9 | 0x04, 0x00, 0xc9, 0x88, 0x01, 0x00, 0xc9, 0x98, 0x20, 0x02, 0x00, 0x06, 0xe0, 0x48, 0x09, 0x7c, 10 | 0x80, 0x80, 0x01, 0x34, 0x04, 0xfc, 0x21, 0x7c, 0xf8, 0x0a, 0xa1, 0xac, 0x08, 0x00, 0xa5, 0x24, 11 | 0xfd, 0xff, 0xbd, 0x14, 0xf4, 0x0a, 0xa1, 0xac, 0xff, 0x00, 0x01, 0x24, 0x02, 0x8e, 0x13, 0x00, 12 | 0xb8, 0x09, 0xad, 0x90, 0x3c, 0x00, 0x20, 0x12, 0x02, 0x1a, 0x13, 0x00, 0x18, 0x00, 0x6d, 0x00, 13 | 0x01, 0x00, 0x6b, 0x25, 0xc2, 0x18, 0x0d, 0x00, 0x12, 0x88, 0x00, 0x00, 0x2b, 0x70, 0x31, 0x01, 14 | 0x41, 0x00, 0xc0, 0x15, 0x23, 0x68, 0xa3, 0x01, 0xb8, 0x09, 0xad, 0xa0, 0xff, 0xff, 0xa5, 0x24, 15 | 0x2c, 0x28, 0xbd, 0x00, 0x23, 0x48, 0x31, 0x01, 0x13, 0x02, 0x6c, 0x11, 0x23, 0x98, 0x71, 0x02, 16 | 0x04, 0x52, 0x79, 0x7d, 0x07, 0x18, 0x19, 0x02, 0x07, 0x00, 0x63, 0x30, 0x00, 0xca, 0x03, 0x00, 17 | 0x23, 0xc0, 0x23, 0x03, 0x21, 0x18, 0xb8, 0x03, 0x01, 0x00, 0x19, 0x24, 0x21, 0x78, 0x79, 0x00, 18 | 0x02, 0x6e, 0x13, 0x00, 0x11, 0x00, 0xa0, 0x11, 0xff, 0xff, 0xee, 0x91, 0x40, 0xc8, 0x19, 0x00, 19 | 0x02, 0x92, 0x13, 0x00, 0x18, 0x00, 0x4e, 0x02, 0xc2, 0x90, 0x0e, 0x00, 0x23, 0x70, 0xd2, 0x01, 20 | 0x12, 0x68, 0x00, 0x00, 0x2b, 0xc0, 0x2d, 0x01, 0x15, 0x00, 0x00, 0x13, 0x02, 0x92, 0x19, 0x00, 21 | 0x12, 0x98, 0x00, 0x00, 0x1f, 0x00, 0xce, 0x25, 0xff, 0xff, 0xee, 0xa1, 0xef, 0xff, 0x40, 0x12, 22 | 0x01, 0x00, 0x39, 0x27, 0xd5, 0xff, 0x00, 0x10, 0x00, 0x00, 0x79, 0xa1, 0x05, 0x00, 0xd2, 0x90, 23 | 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x32, 0x01, 0x40, 0xc8, 0x19, 0x00, 24 | 0x18, 0x00, 0x6e, 0x02, 0x00, 0x9a, 0x13, 0x00, 0xc2, 0x90, 0x0e, 0x00, 0x23, 0x70, 0xd2, 0x01, 25 | 0x12, 0x68, 0x00, 0x00, 0x2b, 0xc0, 0x2d, 0x01, 0xed, 0xff, 0x00, 0x17, 0x02, 0x92, 0x19, 0x00, 26 | 0xff, 0xff, 0xee, 0xa1, 0x23, 0x48, 0x2d, 0x01, 0xdc, 0xff, 0x40, 0x12, 0x23, 0x98, 0x6d, 0x02, 27 | 0xc2, 0xff, 0x00, 0x10, 0x00, 0x00, 0x79, 0xa1, 0x05, 0x00, 0xd8, 0x90, 0x01, 0x00, 0x6b, 0x25, 28 | 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x38, 0x01, 0x18, 0x00, 0x6d, 0x02, 29 | 0x00, 0x9a, 0x13, 0x00, 0xc2, 0x18, 0x0d, 0x00, 0x12, 0x88, 0x00, 0x00, 0x2b, 0x70, 0x31, 0x01, 30 | 0xc1, 0xff, 0xc0, 0x11, 0x23, 0x68, 0xa3, 0x01, 0x1f, 0x00, 0xb3, 0x25, 0xb8, 0x09, 0xb3, 0xa0, 31 | 0xff, 0xff, 0x18, 0x24, 0x12, 0x98, 0x00, 0x00, 0x02, 0xce, 0x11, 0x00, 0x63, 0x01, 0x20, 0x13, 32 | 0xc0, 0x09, 0xad, 0x90, 0x08, 0x00, 0xa5, 0x24, 0x02, 0x92, 0x13, 0x00, 0x18, 0x00, 0x4d, 0x02, 33 | 0xc2, 0x90, 0x0d, 0x00, 0x23, 0x68, 0xb2, 0x01, 0x12, 0x88, 0x00, 0x00, 0x2b, 0xc8, 0x31, 0x01, 34 | 0x67, 0x01, 0x20, 0x17, 0x1f, 0x00, 0xa3, 0x25, 0x23, 0x98, 0x71, 0x02, 0x23, 0x48, 0x31, 0x01, 35 | 0xb8, 0x09, 0xad, 0xa0, 0x69, 0x00, 0x00, 0x07, 0x21, 0x68, 0xb8, 0x03, 0xfd, 0xff, 0x19, 0x27, 36 | 0x04, 0x70, 0x0b, 0x03, 0x40, 0x89, 0x18, 0x00, 0xc4, 0x20, 0xd1, 0x7d, 0x04, 0x10, 0xb1, 0x7c, 37 | 0x21, 0x88, 0xb1, 0x03, 0x28, 0x00, 0x20, 0x07, 0x01, 0x00, 0x0e, 0x24, 0x10, 0x0a, 0x32, 0x92, 38 | 0x02, 0x1e, 0x13, 0x00, 0x8b, 0x01, 0x60, 0x10, 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 39 | 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 40 | 0x98, 0x01, 0x40, 0x14, 0x02, 0x00, 0x0e, 0x24, 0x23, 0x48, 0x23, 0x01, 0x19, 0x00, 0x20, 0x1b, 41 | 0x23, 0x98, 0x63, 0x02, 0x02, 0x1e, 0x13, 0x00, 0x99, 0x01, 0x60, 0x10, 0x02, 0x12, 0x13, 0x00, 42 | 0x18, 0x00, 0x52, 0x00, 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 43 | 0x2b, 0x10, 0x23, 0x01, 0x7e, 0x01, 0x40, 0x14, 0x40, 0x70, 0x0e, 0x00, 0x23, 0x48, 0x23, 0x01, 44 | 0x0c, 0x00, 0x28, 0x13, 0x23, 0x98, 0x63, 0x02, 0x02, 0x1e, 0x13, 0x00, 0x7f, 0x01, 0x60, 0x10, 45 | 0x40, 0x70, 0x0e, 0x00, 0x42, 0x98, 0x13, 0x00, 0x2b, 0x10, 0x33, 0x01, 0x23, 0x18, 0x33, 0x01, 46 | 0xff, 0xff, 0x39, 0x27, 0x0a, 0x48, 0x62, 0x00, 0x21, 0x70, 0xc2, 0x01, 0xf9, 0xff, 0x28, 0x57, 47 | 0x40, 0x70, 0x0e, 0x00, 0x10, 0x0a, 0x32, 0xa2, 0x02, 0x1e, 0x13, 0x00, 0x07, 0x00, 0xa5, 0x27, 48 | 0xf8, 0x09, 0x32, 0x92, 0x50, 0x01, 0x60, 0x10, 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 49 | 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 50 | 0x55, 0x01, 0x40, 0x14, 0x40, 0x70, 0x0e, 0x00, 0xf8, 0x09, 0x32, 0xa2, 0x23, 0x48, 0x23, 0x01, 51 | 0x2b, 0x00, 0x00, 0x1b, 0x23, 0x98, 0x63, 0x02, 0x00, 0x0a, 0x32, 0x92, 0x02, 0x1e, 0x13, 0x00, 52 | 0x3a, 0x01, 0x60, 0x10, 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 0xc2, 0x10, 0x12, 0x00, 53 | 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 0x2c, 0x01, 0x40, 0x14, 54 | 0x40, 0x70, 0x0e, 0x00, 0x00, 0x0a, 0x32, 0xa2, 0x23, 0x48, 0x23, 0x01, 0x0f, 0x00, 0x08, 0x13, 55 | 0x23, 0x98, 0x63, 0x02, 0x08, 0x0a, 0x32, 0x92, 0x02, 0x1e, 0x13, 0x00, 0x16, 0x01, 0x60, 0x10, 56 | 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 57 | 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 0x16, 0x01, 0x40, 0x14, 0x40, 0x70, 0x0e, 0x00, 58 | 0x08, 0x0a, 0x32, 0xa2, 0x23, 0x48, 0x23, 0x01, 0x23, 0x98, 0x63, 0x02, 0x38, 0x00, 0xad, 0x25, 59 | 0x60, 0x01, 0x12, 0x24, 0x08, 0x00, 0x11, 0x24, 0x02, 0x1e, 0x13, 0x00, 0x0d, 0x00, 0x60, 0x14, 60 | 0x21, 0xc8, 0xb1, 0x01, 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 61 | 0x21, 0x48, 0x23, 0x01, 0x07, 0x00, 0x00, 0x10, 0x00, 0x9a, 0x13, 0x00, 0x07, 0x00, 0xa5, 0x27, 62 | 0x40, 0x00, 0x12, 0x24, 0x08, 0x00, 0x11, 0x24, 0x02, 0x1e, 0x13, 0x00, 0xf5, 0xff, 0x60, 0x10, 63 | 0x21, 0xc8, 0xb1, 0x01, 0xf1, 0x07, 0x38, 0x93, 0x02, 0x12, 0x13, 0x00, 0x40, 0x88, 0x11, 0x00, 64 | 0x18, 0x00, 0x58, 0x00, 0xc2, 0x10, 0x18, 0x00, 0x23, 0x78, 0x02, 0x03, 0x12, 0x18, 0x00, 0x00, 65 | 0x2b, 0xc0, 0x23, 0x01, 0xd0, 0x00, 0x00, 0x13, 0x23, 0xc0, 0x32, 0x02, 0x12, 0x98, 0x00, 0x00, 66 | 0x1f, 0x00, 0xef, 0x25, 0xf1, 0x07, 0x2f, 0xa3, 0xef, 0xff, 0x00, 0x07, 0x08, 0x00, 0x31, 0x26, 67 | 0x21, 0x88, 0xb8, 0x03, 0xc3, 0xc0, 0x18, 0x00, 0xfd, 0xff, 0x19, 0x27, 0x28, 0x09, 0x2d, 0x8e, 68 | 0x28, 0x00, 0x20, 0x07, 0x01, 0x00, 0x0f, 0x24, 0x02, 0x16, 0x13, 0x00, 0xa0, 0x00, 0x40, 0x10, 69 | 0x00, 0x3e, 0xb2, 0x7d, 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 0xc2, 0x10, 0x12, 0x00, 70 | 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 0xac, 0x00, 0x40, 0x14, 71 | 0x02, 0x00, 0x0f, 0x24, 0x23, 0x48, 0x23, 0x01, 0x19, 0x00, 0x20, 0x1b, 0x23, 0x98, 0x63, 0x02, 72 | 0x02, 0x16, 0x13, 0x00, 0xad, 0x00, 0x40, 0x10, 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 73 | 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 74 | 0x92, 0x00, 0x40, 0x14, 0x40, 0x78, 0x0f, 0x00, 0x23, 0x48, 0x23, 0x01, 0x0c, 0x00, 0x28, 0x13, 75 | 0x23, 0x98, 0x63, 0x02, 0x02, 0x16, 0x13, 0x00, 0x93, 0x00, 0x40, 0x10, 0x40, 0x78, 0x0f, 0x00, 76 | 0x42, 0x98, 0x13, 0x00, 0x2b, 0x10, 0x33, 0x01, 0x23, 0x18, 0x33, 0x01, 0xff, 0xff, 0x39, 0x27, 77 | 0x0a, 0x48, 0x62, 0x00, 0x21, 0x78, 0xe2, 0x01, 0xf9, 0xff, 0x28, 0x57, 0x40, 0x78, 0x0f, 0x00, 78 | 0x04, 0xfe, 0x4d, 0x7e, 0x02, 0x16, 0x13, 0x00, 0x72, 0x00, 0x40, 0x10, 0x00, 0x38, 0xb2, 0x7d, 79 | 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 80 | 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 0x5d, 0x00, 0x40, 0x14, 0x40, 0x78, 0x0f, 0x00, 81 | 0x04, 0x38, 0x4d, 0x7e, 0x23, 0x48, 0x23, 0x01, 0x1e, 0x00, 0x00, 0x1b, 0x23, 0x98, 0x63, 0x02, 82 | 0x02, 0x16, 0x13, 0x00, 0x5c, 0x00, 0x40, 0x10, 0x00, 0x3a, 0xb2, 0x7d, 0x02, 0x12, 0x13, 0x00, 83 | 0x18, 0x00, 0x52, 0x00, 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 84 | 0x2b, 0x10, 0x23, 0x01, 0x48, 0x00, 0x40, 0x14, 0x40, 0x78, 0x0f, 0x00, 0x04, 0x7a, 0x4d, 0x7e, 85 | 0x23, 0x48, 0x23, 0x01, 0x0f, 0x00, 0x08, 0x13, 0x23, 0x98, 0x63, 0x02, 0x02, 0x16, 0x13, 0x00, 86 | 0x36, 0x00, 0x40, 0x10, 0x00, 0x3c, 0xb2, 0x7d, 0x02, 0x12, 0x13, 0x00, 0x18, 0x00, 0x52, 0x00, 87 | 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 88 | 0x35, 0x00, 0x40, 0x14, 0x40, 0x78, 0x0f, 0x00, 0x04, 0xbc, 0x4d, 0x7e, 0x23, 0x48, 0x23, 0x01, 89 | 0x23, 0x98, 0x63, 0x02, 0xff, 0xff, 0xef, 0x25, 0x28, 0x09, 0x2d, 0xae, 0x23, 0x68, 0x64, 0x01, 90 | 0x2b, 0xc8, 0xed, 0x01, 0x76, 0x00, 0x20, 0x13, 0x21, 0x70, 0x6e, 0x01, 0x23, 0x18, 0x6f, 0x01, 91 | 0x2b, 0xc8, 0xcc, 0x01, 0xe4, 0x00, 0x20, 0x13, 0xff, 0xff, 0x79, 0x90, 0x04, 0x00, 0xc5, 0x7d, 92 | 0x2b, 0x88, 0x94, 0x01, 0x08, 0x00, 0x20, 0x56, 0x40, 0x00, 0x78, 0xbd, 0x01, 0x00, 0x6b, 0x25, 93 | 0xff, 0xff, 0x79, 0xa1, 0x01, 0x00, 0x63, 0x24, 0xfc, 0xff, 0x6e, 0x15, 0xff, 0xff, 0x79, 0x90, 94 | 0xb6, 0xfe, 0x00, 0x10, 0x00, 0x00, 0x79, 0xa1, 0x23, 0x88, 0xcb, 0x01, 0x04, 0x00, 0x31, 0x2a, 95 | 0xf6, 0xff, 0x20, 0x16, 0x23, 0x88, 0x63, 0x01, 0x03, 0x00, 0x31, 0x2a, 0xf3, 0xff, 0x20, 0x16, 96 | 0x00, 0x00, 0x62, 0x25, 0x21, 0x58, 0xc0, 0x01, 0x04, 0x08, 0x4e, 0x7c, 0x02, 0x00, 0x79, 0x88, 97 | 0xff, 0xff, 0x79, 0x98, 0x03, 0x00, 0x59, 0xa8, 0x00, 0x00, 0x59, 0xb8, 0x03, 0x00, 0xc2, 0x11, 98 | 0x04, 0x00, 0x63, 0x24, 0xf9, 0xff, 0x00, 0x10, 0x04, 0x00, 0x42, 0x24, 0xa3, 0xfe, 0x6c, 0x15, 99 | 0x00, 0x00, 0x79, 0x91, 0xc6, 0x00, 0x00, 0x10, 0x23, 0x10, 0x64, 0x01, 0x05, 0x00, 0xc3, 0x90, 100 | 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x18, 0x00, 0x72, 0x02, 101 | 0xc7, 0xff, 0x00, 0x10, 0x00, 0x9a, 0x13, 0x00, 0x1f, 0x00, 0x52, 0x26, 0x04, 0xbc, 0x4d, 0x7e, 102 | 0xcd, 0xff, 0x00, 0x10, 0x12, 0x98, 0x00, 0x00, 0x1f, 0x00, 0x52, 0x26, 0x04, 0x7a, 0x4d, 0x7e, 103 | 0xc9, 0xff, 0x08, 0x13, 0x12, 0x98, 0x00, 0x00, 0xb8, 0xff, 0x00, 0x10, 0x01, 0x00, 0xef, 0x25, 104 | 0x1f, 0x00, 0x52, 0x26, 0x04, 0x38, 0x4d, 0x7e, 0xc3, 0xff, 0x00, 0x1b, 0x12, 0x98, 0x00, 0x00, 105 | 0xa3, 0xff, 0x00, 0x10, 0x01, 0x00, 0xef, 0x25, 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 106 | 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x18, 0x00, 0x72, 0x02, 0xa1, 0xff, 0x00, 0x10, 107 | 0x00, 0x9a, 0x13, 0x00, 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 108 | 0x21, 0x48, 0x23, 0x01, 0x18, 0x00, 0x72, 0x02, 0x8b, 0xff, 0x00, 0x10, 0x00, 0x9a, 0x13, 0x00, 109 | 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 110 | 0x18, 0x00, 0x72, 0x02, 0x5d, 0xff, 0x00, 0x10, 0x00, 0x9a, 0x13, 0x00, 0x12, 0x98, 0x00, 0x00, 111 | 0x01, 0x00, 0xef, 0x25, 0x7a, 0xff, 0x28, 0x13, 0x1f, 0x00, 0x52, 0x26, 0x02, 0x16, 0x13, 0x00, 112 | 0x6f, 0xff, 0x40, 0x14, 0x40, 0x78, 0x0f, 0x00, 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 113 | 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x6a, 0xff, 0x00, 0x10, 0xc0, 0x99, 0x13, 0x00, 114 | 0x12, 0x98, 0x00, 0x00, 0x03, 0x00, 0x0f, 0x24, 0x6d, 0xff, 0x20, 0x1b, 0x1f, 0x00, 0x52, 0x26, 115 | 0x02, 0x16, 0x13, 0x00, 0x55, 0xff, 0x40, 0x14, 0x02, 0x12, 0x13, 0x00, 0x05, 0x00, 0xc3, 0x90, 116 | 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x00, 0x9a, 0x13, 0x00, 117 | 0x4e, 0xff, 0x00, 0x10, 0x02, 0x12, 0x13, 0x00, 0x23, 0x98, 0x63, 0x02, 0x23, 0x48, 0x23, 0x01, 118 | 0x21, 0xff, 0x00, 0x07, 0xf1, 0x07, 0x2f, 0xa3, 0x31, 0xff, 0x00, 0x17, 0xf8, 0xff, 0x18, 0x27, 119 | 0x21, 0x18, 0x60, 0x01, 0x23, 0x68, 0x64, 0x01, 0x8d, 0xff, 0xa0, 0x15, 0x21, 0x70, 0x6e, 0x01, 120 | 0x00, 0x80, 0x02, 0x3c, 0x72, 0x00, 0x00, 0x10, 0x08, 0x01, 0x42, 0x34, 0x05, 0x00, 0xc3, 0x90, 121 | 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x08, 0x00, 0xa5, 0x24, 122 | 0x18, 0x00, 0x6d, 0x02, 0x00, 0x9a, 0x11, 0x00, 0xc2, 0x90, 0x0d, 0x00, 0x12, 0x88, 0x00, 0x00, 123 | 0x2b, 0xc8, 0x31, 0x01, 0x9c, 0xfe, 0x20, 0x13, 0x23, 0x68, 0xb2, 0x01, 0x1f, 0x00, 0xa3, 0x25, 124 | 0x01, 0x00, 0x18, 0x27, 0x12, 0x98, 0x00, 0x00, 0x8b, 0xfe, 0x0a, 0x17, 0xb8, 0x09, 0xa3, 0xa0, 125 | 0x9a, 0xfe, 0x00, 0x10, 0x21, 0x68, 0xb8, 0x03, 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 126 | 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x18, 0x00, 0x72, 0x02, 0xe6, 0xfe, 0x00, 0x10, 127 | 0x00, 0x9a, 0x13, 0x00, 0x1f, 0x00, 0x52, 0x26, 0x08, 0x0a, 0x32, 0xa2, 0x01, 0x00, 0xce, 0x25, 128 | 0xea, 0xfe, 0xc1, 0x15, 0x12, 0x98, 0x00, 0x00, 0x51, 0x00, 0x00, 0x10, 0x23, 0x10, 0x64, 0x01, 129 | 0x1f, 0x00, 0x52, 0x26, 0x00, 0x0a, 0x32, 0xa2, 0x01, 0x00, 0xce, 0x25, 0xe3, 0xfe, 0x08, 0x13, 130 | 0x12, 0x98, 0x00, 0x00, 0xd4, 0xfe, 0x00, 0x10, 0x08, 0x0a, 0x32, 0x92, 0x05, 0x00, 0xc3, 0x90, 131 | 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x18, 0x00, 0x72, 0x02, 132 | 0xc2, 0xfe, 0x00, 0x10, 0x00, 0x9a, 0x13, 0x00, 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 133 | 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x18, 0x00, 0x72, 0x02, 0x00, 0x9a, 0x13, 0x00, 134 | 0xc2, 0x10, 0x12, 0x00, 0x23, 0x90, 0x42, 0x02, 0x12, 0x18, 0x00, 0x00, 0x2b, 0x10, 0x23, 0x01, 135 | 0xad, 0xfe, 0x40, 0x10, 0x40, 0x70, 0x0e, 0x00, 0x1f, 0x00, 0x52, 0x26, 0xf8, 0x09, 0x32, 0xa2, 136 | 0x12, 0x98, 0x00, 0x00, 0xc9, 0xfe, 0x00, 0x1b, 0x01, 0x00, 0xce, 0x25, 0xab, 0xfe, 0x00, 0x10, 137 | 0x00, 0x0a, 0x32, 0x92, 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 138 | 0x21, 0x48, 0x23, 0x01, 0x18, 0x00, 0x72, 0x02, 0x71, 0xfe, 0x00, 0x10, 0x00, 0x9a, 0x13, 0x00, 139 | 0x12, 0x98, 0x00, 0x00, 0x01, 0x00, 0xce, 0x25, 0x8e, 0xfe, 0x28, 0x13, 0x1f, 0x00, 0x52, 0x26, 140 | 0x02, 0x1e, 0x13, 0x00, 0x83, 0xfe, 0x60, 0x14, 0x40, 0x70, 0x0e, 0x00, 0x05, 0x00, 0xc3, 0x90, 141 | 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 0x7e, 0xfe, 0x00, 0x10, 142 | 0xc0, 0x99, 0x13, 0x00, 0x12, 0x98, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x24, 0x81, 0xfe, 0x20, 0x1b, 143 | 0x1f, 0x00, 0x52, 0x26, 0x02, 0x1e, 0x13, 0x00, 0x69, 0xfe, 0x60, 0x14, 0x02, 0x12, 0x13, 0x00, 144 | 0x05, 0x00, 0xc3, 0x90, 0x00, 0x4a, 0x09, 0x00, 0x01, 0x00, 0xc6, 0x24, 0x21, 0x48, 0x23, 0x01, 145 | 0x00, 0x9a, 0x13, 0x00, 0x62, 0xfe, 0x00, 0x10, 0x02, 0x12, 0x13, 0x00, 0x21, 0x48, 0x24, 0x01, 146 | 0x2b, 0x18, 0x2c, 0x01, 0x08, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xc3, 0x90, 147 | 0x01, 0x00, 0xc6, 0x24, 0x01, 0x00, 0x6b, 0x25, 0xfc, 0xff, 0x69, 0x15, 0x00, 0x00, 0x63, 0xa1, 148 | 0x03, 0x00, 0x00, 0x10, 0x23, 0x10, 0x64, 0x01, 0x00, 0x80, 0x02, 0x3c, 0x04, 0x01, 0x42, 0x34, 149 | 0x02, 0x00, 0xe0, 0x10, 0x05, 0x00, 0xc6, 0x24, 0x00, 0x00, 0xe6, 0xac, 0x08, 0x0b, 0xb4, 0x8f, 150 | 0x04, 0x0b, 0xb3, 0x8f, 0x00, 0x0b, 0xb2, 0x8f, 0xfc, 0x0a, 0xb1, 0x8f, 0xf8, 0x0a, 0xb0, 0x8f, 151 | 0x08, 0x00, 0xe0, 0x03, 0x10, 0x0b, 0xbd, 0x27, 152 | }; 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /npdrm/npdk_test/my_npd.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | PSP_MODULE_INFO("New_NpDecrypt", 0x1000, 1, 1); 14 | 15 | /*****************************************************************************/ 16 | 17 | int NpegOpen(char *name, u8 *header, u8 *unk, u8 *table, int *table_size); 18 | int NpegReadBlock(u8 *data_buf, u8 *out_buf, int block); 19 | int NpegClose(void); 20 | 21 | /*****************************************************************************/ 22 | 23 | u8 *table = (u8*)0x09000000; 24 | u8 *data_buf = (u8*)0x09400000; 25 | u8 *decrypt_buf = (u8*)0x09500000; 26 | u8 *header = (u8*)0x09700000; 27 | u8 *actdat = (u8*)0x09700100; 28 | 29 | /*****************************************************************************/ 30 | 31 | #define printf pspDebugScreenPrintf 32 | 33 | int sceGeEdramGetAddr(void) 34 | { 35 | return 0x04000000; 36 | } 37 | 38 | /*****************************************************************************/ 39 | 40 | int load_start_module(char *name, int args, void *argv) 41 | { 42 | int mid; 43 | 44 | mid = sceKernelLoadModule(name, 0, NULL); 45 | if(mid>0) 46 | mid = sceKernelStartModule(mid, args, argv, NULL, NULL); 47 | 48 | return mid; 49 | } 50 | 51 | int write_file(char *name, u8 *buf, int size) 52 | { 53 | int fd; 54 | 55 | fd = sceIoOpen(name, PSP_O_WRONLY|PSP_O_CREAT|PSP_O_TRUNC, 0777); 56 | if(fd<0) 57 | return fd; 58 | 59 | sceIoWrite(fd, buf, size); 60 | sceIoClose(fd); 61 | 62 | return 0; 63 | } 64 | 65 | void hex_dump(char *str, u8 *buf, int size) 66 | { 67 | int i; 68 | 69 | if(str) 70 | printk("%s:", str); 71 | 72 | for(i=0; i=0) { 195 | sceKernelStartThread(thid, args, argp); 196 | } 197 | 198 | return 0; 199 | } 200 | 201 | int module_stop(SceSize args, void *argp) 202 | { 203 | return 0; 204 | } 205 | 206 | -------------------------------------------------------------------------------- /npdrm/npdk_test/npeg.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "lzdecode.h" 13 | 14 | #define byte_swap(x) ( ((x&0xff)<<24) | ((x&0xff00)<<8) | ((x&0xff0000)>>8) | ((x&0xff000000)>>24) ) 15 | 16 | 17 | /*****************************************************************************/ 18 | 19 | int sceNpDrmGetIDps(u8 *psid); 20 | 21 | int sceNpDrmGetFixedKey(u8 *version_key, u8 *name, u32 type); 22 | int sceNpDrmGetVersionKey(u8 *version_key, u8 *act_buf, u8 *rif_buf, u32 type); 23 | 24 | int sceDrmBBMacInit(u8 *mac_key, int type); 25 | int sceDrmBBMacUpdate(u8 *mac_key, u8 *buf, int size); 26 | int sceDrmBBMacFinal2(u8 *mac_key, u8 *buf, u8 *version_key); 27 | 28 | int sceDrmBBCipherInit(u8 *cipher_key, int unk1, int unk2, u8 *header_key, u8 *version_key, int unk3); 29 | int sceDrmBBCipherUpdate(u8 *cipher_key, u8 *buf, int size); 30 | int sceDrmBBCipherFinal(u8 *cipher_key); 31 | 32 | int (*lz_decomp)(u8 *out_buf, int out_size, u8 *src_buf, int src_size) = (void*)lzdecode; 33 | 34 | void hex_dump(char *str, u8 *buf, int size); 35 | 36 | /*****************************************************************************/ 37 | 38 | u8 header_key[16]; 39 | int iso_fd; 40 | int offset_psar; 41 | u8 *np_actdat; 42 | u8 *np_table; 43 | int block_size; 44 | u8 version_key[16]; 45 | 46 | /*****************************************************************************/ 47 | 48 | int NpegOpen(char *name, u8 *header, u8 *act_dat, u8 *table, int *table_size) 49 | { 50 | u8 psid[0x10]; 51 | u8 pbp_buf[0x28]; 52 | u8 rif_buf[0x98]; 53 | u8 mac_key[0x30]; 54 | u8 cipher_key[0x20]; 55 | char rif_name[0x40]; 56 | u8 *np_header, *act_buf; 57 | int start, end, lba_size, total_blocks, offset_table; 58 | u32 *tp; 59 | int retv, i, fd, type; 60 | 61 | np_header = header; 62 | np_actdat = act_dat; 63 | np_table = table; 64 | 65 | retv = sceNpDrmGetIDps(psid); 66 | if(retv<0) 67 | return -1; 68 | 69 | iso_fd = sceIoOpen(name, 0x04000000|PSP_O_RDONLY, 0); 70 | if(iso_fd<0) 71 | return -2; 72 | 73 | // read PBP header 74 | retv = sceIoRead(iso_fd, pbp_buf, 0x28); 75 | if(retv<0x28) 76 | return -3; 77 | // check "PBP" 78 | if(*(u32*)pbp_buf!=0x50425000) 79 | return -4; 80 | 81 | offset_psar = *(u32*)(pbp_buf+0x24); 82 | retv = sceIoLseek(iso_fd, offset_psar, SEEK_SET); 83 | if(retv<0) 84 | return -5; 85 | 86 | retv = sceIoRead(iso_fd, np_header, 0x0100); 87 | if(retv<0x0100) 88 | return -6; 89 | 90 | // check "NPUMDIMG" 91 | if(*(u32*)(np_header+0)!=0x4d55504e) 92 | return -7; 93 | if(*(u32*)(np_header+4)!=0x474d4944) 94 | return -7; 95 | 96 | type = *(u32*)(np_header+8); 97 | if(type&0x01000000){ 98 | retv = sceNpDrmGetFixedKey(version_key, np_header+0x10, type); 99 | hex_dump("fixed key:", version_key, 16); 100 | }else{ 101 | memset(rif_name, 0, 0x40); 102 | sprintf(rif_name, "ms0:/PSP/LICENSE/%s.rif", np_header+0x10); 103 | 104 | fd = sceIoOpen(rif_name, 0x04000000|PSP_O_RDONLY, 0); 105 | retv = sceIoRead(fd, rif_buf, 0x98); 106 | sceIoClose(fd); 107 | 108 | if(retv!=0x98) 109 | return -8; 110 | 111 | type = *(u32*)(rif_buf+4); 112 | type = byte_swap(type); 113 | if(type!=3){ 114 | fd = sceIoOpen("flash2:/act.dat", 0x04000000|PSP_O_RDONLY, 0); 115 | if(fd<0) 116 | return -9; 117 | retv = sceIoRead(fd, np_actdat, 0x1038); 118 | sceIoClose(fd); 119 | 120 | if(retv!=0x1038) 121 | return -10; 122 | act_buf = np_actdat; 123 | }else{ 124 | act_buf = NULL; 125 | } 126 | 127 | type = *(u32*)(np_header+8); 128 | retv = sceNpDrmGetVersionKey(version_key, act_buf, rif_buf, type); 129 | } 130 | if(retv<0) 131 | return retv; 132 | 133 | write_file("version_key.bin", version_key, 16); 134 | 135 | memcpy(header_key, np_header+0xa0, 0x10); 136 | retv = sceDrmBBMacInit(mac_key, 3); 137 | if(retv<0) 138 | return -11; 139 | 140 | retv = sceDrmBBMacUpdate(mac_key, np_header, 0xc0); 141 | if(retv<0) 142 | return -12; 143 | 144 | retv = sceDrmBBMacFinal2(mac_key, np_header+0xc0, version_key); 145 | if(retv<0) 146 | return -13; 147 | 148 | retv = sceDrmBBCipherInit(cipher_key, 1, 2, header_key, version_key, 0); 149 | if(retv<0) 150 | return -14; 151 | 152 | retv = sceDrmBBCipherUpdate(cipher_key, np_header+0x40, 0x60); 153 | if(retv<0) 154 | return -15; 155 | 156 | retv = sceDrmBBCipherFinal(cipher_key); 157 | if(retv<0) 158 | return -16; 159 | 160 | 161 | start = *(u32*)(np_header+0x54); // LBA start 162 | end = *(u32*)(np_header+0x64); // LBA end 163 | block_size = *(u32*)(np_header+0x0c); // block_size 164 | lba_size = (end-start+1); // LBA size of ISO 165 | total_blocks = (lba_size+block_size-1)/block_size; // total blocks; 166 | 167 | offset_table = *(u32*)(np_header+0x6c); // table offset 168 | sceIoLseek(iso_fd, offset_psar+offset_table, SEEK_SET); 169 | 170 | *table_size = total_blocks*32; 171 | retv = sceIoRead(iso_fd, np_table, *table_size); 172 | if(retv<*table_size) 173 | return -18; 174 | 175 | // table mac test 176 | int msize; 177 | u8 bbmac[16]; 178 | 179 | sceDrmBBMacInit(mac_key, 3); 180 | for(i=0; i<*table_size; i+=0x8000){ 181 | if(i+0x8000>*table_size) 182 | msize = *table_size-i; 183 | else 184 | msize = 0x8000; 185 | sceDrmBBMacUpdate(mac_key, np_table+i, msize); 186 | hex_dump("MacUpdate:", mac_key+4, 32+4); 187 | } 188 | sceDrmBBMacFinal(mac_key, bbmac, version_key); 189 | hex_dump("MacFinal:", bbmac, 16); 190 | 191 | tp = (u32*)np_table; 192 | for(i=0; i>4); 259 | if(retv<0) 260 | return -6; 261 | retv = sceDrmBBCipherUpdate(cipher_key, data_buf, tp[5]); 262 | if(retv<0) 263 | return -7; 264 | retv = sceDrmBBCipherFinal(cipher_key); 265 | if(retv<0) 266 | return -8; 267 | } 268 | 269 | if(tp[5] 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | 25 | static int itostr(char *buf, int in_data, int base, int upper, int sign) 26 | { 27 | int res, len, i; 28 | unsigned int data; 29 | char *str; 30 | 31 | if(base==10 && sign && in_data<0){ 32 | data = -in_data; 33 | }else{ 34 | data = in_data; 35 | } 36 | 37 | str = buf; 38 | do{ 39 | res = data%base; 40 | data = data/base; 41 | if(res<10){ 42 | res += '0'; 43 | }else{ 44 | if(upper){ 45 | res += 'A'-10; 46 | }else{ 47 | res += 'a'-10; 48 | } 49 | } 50 | *str++ = res; 51 | }while(data); 52 | len = str-buf; 53 | 54 | /* reverse digital order */ 55 | for(i=0; i'0' && *fmt<='9'){ 134 | field_width = field_width*10+(*fmt-'0'); 135 | fmt++; 136 | } 137 | if(*fmt && *fmt=='.'){ 138 | fmt++; 139 | /* skip n */ 140 | while(*fmt && *fmt>'0' && *fmt<='9'){ 141 | fmt++; 142 | } 143 | } 144 | 145 | /* get format char */ 146 | upper = 0; 147 | base = 0; 148 | sign = 0; 149 | len = 0; 150 | s = digital_buf; 151 | while((ch=*fmt)){ 152 | fmt++; 153 | switch(ch){ 154 | /* hexadecimal */ 155 | case 'p': 156 | case 'X': 157 | upper = 1; 158 | case 'x': 159 | base = 16; 160 | break; 161 | 162 | /* decimal */ 163 | case 'd': 164 | case 'i': 165 | sign = 1; 166 | case 'u': 167 | base = 10; 168 | break; 169 | 170 | /* octal */ 171 | case 'o': 172 | base = 8; 173 | break; 174 | 175 | /* character */ 176 | case 'c': 177 | digital_buf[0] = (unsigned char) va_arg(args, int); 178 | len = 1; 179 | break; 180 | 181 | /* string */ 182 | case 's': 183 | s = va_arg(args, char *); 184 | if(!s) s = ""; 185 | len = strlen(s); 186 | break; 187 | 188 | /* float format, skip it */ 189 | case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': 190 | va_arg(args, double); 191 | s = NULL; 192 | break; 193 | 194 | /* length modifier */ 195 | case 'l': case 'L': case 'h': case 'j': case 'z': case 't': 196 | /* skip it */ 197 | continue; 198 | 199 | /* bad format */ 200 | default: 201 | s = sstr; 202 | len = fmt-sstr; 203 | break; 204 | } 205 | break; 206 | } 207 | 208 | if(base){ 209 | i = va_arg(args, int); 210 | if(base==10 && sign){ 211 | if(i<0){ 212 | add_sign = '-'; 213 | } 214 | }else{ 215 | add_sign = 0; 216 | } 217 | 218 | len = itostr(digital_buf, i, base, upper, sign); 219 | }else{ 220 | zero_pad = ' '; 221 | add_sign = 0; 222 | } 223 | 224 | if(s){ 225 | if(len>=field_width){ 226 | field_width = len; 227 | if(add_sign) 228 | field_width++; 229 | } 230 | for(i=0; i 7 | #include 8 | #include 9 | 10 | #include "kirk_engine.h" 11 | #include "crypto.h" 12 | #include "amctrl.h" 13 | #include "utils.h" 14 | 15 | /*************************************************************/ 16 | 17 | typedef struct { 18 | u8 vkey[16]; 19 | 20 | int open_flag; 21 | int key_index; 22 | int drm_type; 23 | int mac_type; 24 | int cipher_type; 25 | 26 | int data_size; 27 | int align_size; 28 | int block_size; 29 | int block_nr; 30 | int data_offset; 31 | int table_offset; 32 | 33 | u8 *buf; 34 | }PGD_DESC; 35 | 36 | /* 37 | typedef struct { 38 | PGD_DESC pgdesc; 39 | u32 key_index; // 0x30 40 | u8 pgd_key[16]; // 0x34 41 | u32 flag; // 0x44 42 | u32 flag_open; // 0x48 43 | u32 pgd_offset; // 0x4C 44 | int seek_offset; // 0x50 45 | u32 data_offset; // 0x54 46 | u32 table_offset;// 0x58 47 | u32 unk_5c; 48 | u32 unk_60; 49 | }PspIoHookParam; 50 | */ 51 | 52 | u8 dnas_key1A90[] = {0xED,0xE2,0x5D,0x2D,0xBB,0xF8,0x12,0xE5,0x3C,0x5C,0x59,0x32,0xFA,0xE3,0xE2,0x43}; 53 | u8 dnas_key1AA0[] = {0x27,0x74,0xFB,0xEB,0xA4,0xA0, 1,0xD7, 2,0x56,0x9E,0x33,0x8C,0x19,0x57,0x83}; 54 | 55 | extern int verbose; 56 | 57 | PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey) 58 | { 59 | PGD_DESC *pgd; 60 | MAC_KEY mkey; 61 | CIPHER_KEY ckey; 62 | u8 *fkey; 63 | int retv; 64 | 65 | printf("open PGD ...\n"); 66 | 67 | pgd = (PGD_DESC*)malloc(sizeof(PGD_DESC)); 68 | memset(pgd, 0, sizeof(PGD_DESC)); 69 | 70 | pgd->buf = pgd_buf; 71 | pgd->key_index = *(u32*)(pgd_buf+4); 72 | pgd->drm_type = *(u32*)(pgd_buf+8); 73 | 74 | if(pgd->drm_type==1){ 75 | pgd->mac_type = 1; 76 | pgd_flag |= 4; 77 | if(pgd->key_index>1){ 78 | pgd->mac_type = 3; 79 | pgd_flag |= 8; 80 | } 81 | pgd->cipher_type = 1; 82 | }else{ 83 | pgd->mac_type = 2; 84 | pgd->cipher_type = 2; 85 | } 86 | pgd->open_flag = pgd_flag; 87 | 88 | // select fixed key 89 | fkey = NULL; 90 | if(pgd_flag&2) 91 | fkey = dnas_key1A90; 92 | if(pgd_flag&1) 93 | fkey = dnas_key1AA0; 94 | if(fkey==NULL){ 95 | printf("pgd_open: invalid pgd_flag! %08x\n", pgd_flag); 96 | free(pgd); 97 | return NULL; 98 | } 99 | 100 | // MAC_0x80 check 101 | sceDrmBBMacInit(&mkey, pgd->mac_type); 102 | sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x80); 103 | retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x80, fkey); 104 | if(retv){ 105 | printf("pgd_open: MAC_80 check failed!: %08x(%d)\n", retv, retv); 106 | free(pgd); 107 | return NULL; 108 | }else{ 109 | if(verbose) printf("pgd_open: MAC_80 check pass.\n"); 110 | } 111 | 112 | // MAC_0x70 113 | sceDrmBBMacInit(&mkey, pgd->mac_type); 114 | sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x70); 115 | if(pgd_vkey){ 116 | // use given vkey 117 | retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x70, pgd_vkey); 118 | if(retv){ 119 | printf("pgd_open: MAC_70 check failed!: %08x(%d)\n", retv, retv); 120 | free(pgd); 121 | return NULL; 122 | }else{ 123 | if(verbose) printf("pgd_open: MAC_70 check pass.\n"); 124 | memcpy(pgd->vkey, pgd_vkey, 16); 125 | } 126 | }else{ 127 | // get vkey from MAC_70 128 | bbmac_getkey(&mkey, pgd_buf+0x70, pgd->vkey); 129 | if(verbose) hex_dump("pgd_open: get version_key from MAC_70", pgd->vkey, 16); 130 | } 131 | 132 | // decrypt PGD_DESC 133 | sceDrmBBCipherInit(&ckey, pgd->cipher_type, 2, pgd_buf+0x10, pgd->vkey, 0); 134 | sceDrmBBCipherUpdate(&ckey, pgd_buf+0x30, 0x30); 135 | sceDrmBBCipherFinal(&ckey); 136 | //hex_dump("PGD header", pgd_buf, 0x90); 137 | 138 | pgd->data_size = *(u32*)(pgd_buf+0x44); 139 | pgd->block_size = *(u32*)(pgd_buf+0x48); 140 | pgd->data_offset = *(u32*)(pgd_buf+0x4c); 141 | 142 | pgd->align_size = (pgd->data_size+15)&~15; 143 | pgd->table_offset = pgd->data_offset+pgd->align_size; 144 | pgd->block_nr = (pgd->align_size+pgd->block_size-1)&~(pgd->block_size-1); 145 | pgd->block_nr = pgd->block_nr/pgd->block_size; 146 | 147 | return pgd; 148 | } 149 | 150 | int pgd_decrypt(u8 *pgd_buf, int pgd_size, int pgd_flag, u8 *pgd_vkey) 151 | { 152 | PGD_DESC *pgd; 153 | MAC_KEY mkey; 154 | CIPHER_KEY ckey; 155 | int retv; 156 | 157 | 158 | pgd = pgd_open(pgd_buf, pgd_flag, pgd_vkey); 159 | if(pgd==NULL){ 160 | printf("open PGD header failed!\n"); 161 | return -1; 162 | } 163 | 164 | 165 | printf("decrypt PGD ...\n"); 166 | if(verbose) printf("pgd_decrypt: data_size=%08x block_size=%08x table_size=%08x data_offset=%08x\n", 167 | pgd->data_size, pgd->block_size, pgd->block_nr*16, pgd->data_offset); 168 | 169 | if(pgd->align_size+pgd->block_nr*16>pgd_size){ 170 | printf("pgd_decrypt: invalid pgd data!\n"); 171 | return -3; 172 | } 173 | 174 | 175 | // table MAC check 176 | sceDrmBBMacInit(&mkey, pgd->mac_type); 177 | sceDrmBBMacUpdate(&mkey, pgd_buf+pgd->table_offset, pgd->block_nr*16); 178 | retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x60, pgd->vkey); 179 | if(retv){ 180 | printf("pgd_decrypt: MAC_table check failed!: %08x(%d)\n", retv, retv); 181 | return -4; 182 | }else{ 183 | if(verbose) printf("pgd_decrypt: MAC_table check pass.\n"); 184 | } 185 | 186 | // decrypt data 187 | sceDrmBBCipherInit(&ckey, pgd->cipher_type, 2, pgd_buf+0x30, pgd->vkey, 0); 188 | sceDrmBBCipherUpdate(&ckey, pgd_buf+0x90, pgd->align_size); 189 | sceDrmBBCipherFinal(&ckey); 190 | //hex_dump("PGD data", pgd_buf+0x90, (pgd->data_size>0x100)? 0x100 : pgd->data_size); 191 | 192 | return pgd->data_size; 193 | } 194 | 195 | int pgd_encrypt(u8 *pgd_buf, int pgd_flag, u8 *vkey) 196 | { 197 | MAC_KEY mkey; 198 | CIPHER_KEY ckey; 199 | u8 *fkey; 200 | int i, key_index, mac_type, cipher_type, drm_type; 201 | int data_size, block_size, data_offset, table_offset, block_nr; 202 | 203 | printf("encrypt PGD ...\n"); 204 | 205 | key_index = 1; 206 | drm_type = 1; 207 | mac_type = 1; 208 | cipher_type = 1; 209 | 210 | *(u32*)(pgd_buf+4) = key_index; 211 | *(u32*)(pgd_buf+8) = drm_type; 212 | 213 | // select fixed key 214 | fkey = NULL; 215 | if(pgd_flag&2) 216 | fkey = dnas_key1A90; 217 | if(pgd_flag&1) 218 | fkey = dnas_key1AA0; 219 | if(fkey==NULL){ 220 | printf("pgd_encrypt: invalid pgd_flag! %08x\n", pgd_flag); 221 | return -1; 222 | } 223 | 224 | data_size = *(u32*)(pgd_buf+0x44); 225 | block_size = *(u32*)(pgd_buf+0x48); 226 | data_offset = *(u32*)(pgd_buf+0x4c); 227 | 228 | data_size = (data_size+15)&~15; 229 | table_offset = data_offset+data_size; 230 | block_nr = (data_size+block_size-1)&~(block_size-1); 231 | block_nr = block_nr/block_size; 232 | 233 | // 1. encrypt data 234 | // use orig header_key 235 | sceDrmBBCipherInit(&ckey, cipher_type, 2, pgd_buf+0x30, vkey, 0); 236 | sceDrmBBCipherUpdate(&ckey, pgd_buf+data_offset, data_size); 237 | sceDrmBBCipherFinal(&ckey); 238 | 239 | // 2. build data MAC 240 | for(i=0; iblock_size) 243 | rsize = block_size; 244 | 245 | sceDrmBBMacInit(&mkey, mac_type); 246 | sceDrmBBMacUpdate(&mkey, pgd_buf+data_offset+i*block_size, rsize); 247 | sceDrmBBMacFinal(&mkey, pgd_buf+table_offset+i*16, vkey); 248 | } 249 | 250 | // 3. build table MAC 251 | sceDrmBBMacInit(&mkey, mac_type); 252 | sceDrmBBMacUpdate(&mkey, pgd_buf+table_offset, block_nr*16); 253 | sceDrmBBMacFinal(&mkey, pgd_buf+0x60, vkey); 254 | 255 | 256 | // 4. encrypt PGD_DESC 257 | sceDrmBBCipherInit(&ckey, cipher_type, 2, pgd_buf+0x10, vkey, 0); 258 | sceDrmBBCipherUpdate(&ckey, pgd_buf+0x30, 0x30); 259 | sceDrmBBCipherFinal(&ckey); 260 | 261 | // 5. build MAC_0x70 262 | sceDrmBBMacInit(&mkey, mac_type); 263 | sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x70); 264 | sceDrmBBMacFinal(&mkey, pgd_buf+0x70, vkey); 265 | 266 | 267 | // 6. build MAC_0x80 268 | sceDrmBBMacInit(&mkey, mac_type); 269 | sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x80); 270 | sceDrmBBMacFinal(&mkey, pgd_buf+0x80, fkey); 271 | 272 | return 0; 273 | } 274 | 275 | 276 | -------------------------------------------------------------------------------- /pspcipher/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -I../kirk -I../common 3 | TARGET = pspc 4 | OBJS = pspcipher.o prx_decrypt.o ../common/utils.o 5 | 6 | ifeq ($(DEBUG), 1) 7 | CFLAGS+=-g -O0 8 | else 9 | CFLAGS+=-O2 10 | endif 11 | 12 | all: $(TARGET) 13 | 14 | $(TARGET): $(OBJS) 15 | $(CC) $(CFLAGS) -o $@ $(OBJS) -L ../kirk -lkirk 16 | 17 | clean: 18 | $(RM) *.o $(TARGET) *.exe *.exe.stackdump 19 | -------------------------------------------------------------------------------- /pspcipher/keys_data.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYS_DATA 2 | #define KEYS_DATA 3 | 4 | /* 5 | * This file is part of pspcipher. 6 | * 7 | * Copyright (C) 2008 hrimfaxi (outmatch@gmail.com) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 | * for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License along 20 | * with this program; if not, write to the Free Software Foundation, Inc., 21 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 | */ 23 | 24 | // Begins our key here 25 | u8 key_d91609f0[16] = { 26 | 0xD0, 0x36, 0x12, 0x75, 0x80, 0x56, 0x20, 0x43, 27 | 0xC4, 0x30, 0x94, 0x3E, 0x1C, 0x75, 0xD1, 0xBF, 28 | }; 29 | 30 | u8 key_d9160af0[16] = { 31 | 0x10, 0xA9, 0xAC, 0x16, 0xAE, 0x19, 0xC0, 0x7E, 32 | 0x3B, 0x60, 0x77, 0x86, 0x01, 0x6F, 0xF2, 0x63, 33 | }; 34 | 35 | u8 key_d9160bf0[16] = { 36 | 0x83, 0x83, 0xF1, 0x37, 0x53, 0xD0, 0xBE, 0xFC, 37 | 0x8D, 0xA7, 0x32, 0x52, 0x46, 0x0A, 0xC2, 0xC2, 38 | }; 39 | 40 | u8 key_d91611f0[16] = { 41 | 0x61, 0xB0, 0xC0, 0x58, 0x71, 0x57, 0xD9, 0xFA, 42 | 0x74, 0x67, 0x0E, 0x5C, 0x7E, 0x6E, 0x95, 0xB9, 43 | }; 44 | 45 | u8 key_d91612f0[16] = { 46 | 0x9e, 0x20, 0xe1, 0xcd, 0xd7, 0x88, 0xde, 0xc0, 47 | 0x31, 0x9b, 0x10, 0xaf, 0xc5, 0xb8, 0x73, 0x23, 48 | }; 49 | 50 | u8 key_d91613f0[16] = { 51 | 0xEB, 0xFF, 0x40, 0xD8, 0xB4, 0x1A, 0xE1, 0x66, 52 | 0x91, 0x3B, 0x8F, 0x64, 0xB6, 0xFC, 0xB7, 0x12, 53 | }; 54 | 55 | u8 key_d91614f0[16] = { 56 | 0xFD, 0xF7, 0xB7, 0x3C, 0x9F, 0xD1, 0x33, 0x95, 57 | 0x11, 0xB8, 0xB5, 0xBB, 0x54, 0x23, 0x73, 0x85, 58 | }; 59 | 60 | u8 key_d91615f0[16] = { 61 | 0xC8, 0x03, 0xE3, 0x44, 0x50, 0xF1, 0xE7, 0x2A, 62 | 0x6A, 0x0D, 0xC3, 0x61, 0xB6, 0x8E, 0x5F, 0x51, 63 | }; 64 | 65 | u8 key_d91616f0[16] = { 66 | 0x53, 0x03, 0xB8, 0x6A, 0x10, 0x19, 0x98, 0x49, 67 | 0x1C, 0xAF, 0x30, 0xE4, 0x25, 0x1B, 0x6B, 0x28, 68 | }; 69 | 70 | u8 key_d91617f0[16] = { 71 | 0x02, 0xFA, 0x48, 0x73, 0x75, 0xAF, 0xAE, 0x0A, 72 | 0x67, 0x89, 0x2B, 0x95, 0x4B, 0x09, 0x87, 0xA3, 73 | }; 74 | 75 | u8 key_d91618f0[16] = { 76 | 0x96, 0x96, 0x7C, 0xC3, 0xF7, 0x12, 0xDA, 0x62, 77 | 0x1B, 0xF6, 0x9A, 0x9A, 0x44, 0x44, 0xBC, 0x48, 78 | }; 79 | 80 | u8 key_d91619f0[16] = { 81 | 0xE0, 0x32, 0xA7, 0x08, 0x6B, 0x2B, 0x29, 0x2C, 82 | 0xD1, 0x4D, 0x5B, 0xEE, 0xA8, 0xC8, 0xB4, 0xE9, 83 | }; 84 | 85 | u8 key_d91620f0[16] = { 86 | 0x52, 0x1C, 0xB4, 0x5F, 0x40, 0x3B, 0x9A, 0xDD, 87 | 0xAC, 0xFC, 0xEA, 0x92, 0xFD, 0xDD, 0xF5, 0x90, 88 | }; 89 | 90 | u8 key_d91621f0[16] = { 91 | 0xD1, 0x91, 0x2E, 0xA6, 0x21, 0x14, 0x29, 0x62, 92 | 0xF6, 0xED, 0xAE, 0xCB, 0xDD, 0xA3, 0xBA, 0xFE, 93 | }; 94 | 95 | u8 key_d91622f0[16] = { 96 | 0x59, 0x5D, 0x78, 0x4D, 0x21, 0xB2, 0x01, 0x17, 97 | 0x6C, 0x9A, 0xB5, 0x1B, 0xDA, 0xB7, 0xF9, 0xE6, 98 | }; 99 | 100 | u8 key_d91623f0[16] = { 101 | 0xAA, 0x45, 0xEB, 0x4F, 0x62, 0xFB, 0xD1, 0x0D, 102 | 0x71, 0xD5, 0x62, 0xD2, 0xF5, 0xBF, 0xA5, 0x2F, 103 | }; 104 | 105 | u8 key_d91624f0[16] = { 106 | 0x61, 0xB7, 0x26, 0xAF, 0x8B, 0xF1, 0x41, 0x58, 107 | 0x83, 0x6A, 0xC4, 0x92, 0x12, 0xCB, 0xB1, 0xE9, 108 | }; 109 | 110 | u8 key_d91628f0[16] = { 111 | 0x49, 0xA4, 0xFC, 0x66, 0xDC, 0xE7, 0x62, 0x21, 112 | 0xDB, 0x18, 0xA7, 0x50, 0xD6, 0xA8, 0xC1, 0xB6, 113 | }; 114 | 115 | u8 key_d91680f0[16] = { 116 | 0x2C, 0x22, 0x9B, 0x12, 0x36, 0x74, 0x11, 0x67, 117 | 0x49, 0xD1, 0xD1, 0x88, 0x92, 0xF6, 0xA1, 0xD8, 118 | }; 119 | 120 | u8 key_d91681f0[16] = { 121 | 0x52, 0xB6, 0x36, 0x6C, 0x8C, 0x46, 0x7F, 0x7A, 122 | 0xCC, 0x11, 0x62, 0x99, 0xC1, 0x99, 0xBE, 0x98, 123 | }; 124 | 125 | /* new 2.7X eboot.bin */ 126 | u8 ebootbin_271_new[0x10] = { 127 | 0xF4, 0xAE, 0xF4, 0xE1, 0x86, 0xDD, 0xD2, 0x9C, 128 | 0x7C, 0xC5, 0x42, 0xA6, 0x95, 0xA0, 0x83, 0x88, 129 | }; 130 | 131 | /* new 2.8X eboot.bin */ 132 | u8 ebootbin_280_new[0x10] = { 133 | 0xB8, 0x8C, 0x45, 0x8B, 0xB6, 0xE7, 0x6E, 0xB8, 134 | 0x51, 0x59, 0xA6, 0x53, 0x7C, 0x5E, 0x86, 0x31, 135 | }; 136 | 137 | /* new 3.XX eboot.bin */ 138 | u8 ebootbin_300_new[0x10] = { 139 | 0xED, 0x10, 0xE0, 0x36, 0xC4, 0xFE, 0x83, 0xF3, 140 | 0x75, 0x70, 0x5E, 0xF6, 0xA4, 0x40, 0x05, 0xF7, 141 | }; 142 | 143 | /* new 3.XX eboot.bin */ 144 | u8 ebootbin_310_new[0x10] = { 145 | 0x5C, 0x77, 0x0C, 0xBB, 0xB4, 0xC2, 0x4F, 0xA2, 146 | 0x7E, 0x3B, 0x4E, 0xB4, 0xB4, 0xC8, 0x70, 0xAF, 147 | }; 148 | 149 | CipherKey g_cipher[] = { 150 | // borrowed from PRXdecrypter 2.6b 151 | { 0x8004FD03, ebootbin_271_new, 0x5D, 2 }, // 2.71 eboot.bin 152 | { 0xD91605F0, ebootbin_280_new, 0x5D, 2 }, // 2.80 eboot.bin 153 | { 0xD91606F0, ebootbin_300_new, 0x5D, 2 }, // 3.00 eboot.bin 154 | { 0xD91608F0, ebootbin_310_new, 0x5D, 2 }, // 3.10 eboot.bin 155 | 156 | { 0xd91609f0, key_d91609f0, 0x5d, 2 }, 157 | { 0xd9160af0, key_d9160af0, 0x5d, 2 }, 158 | { 0xd9160bf0, key_d9160bf0, 0x5d, 2 }, 159 | { 0xd91611f0, key_d91611f0, 0x5d, 2 }, 160 | { 0xd91612f0, key_d91612f0, 0x5d, 2 }, 161 | { 0xd91613f0, key_d91613f0, 0x5d, 2 }, 162 | { 0xd91614f0, key_d91614f0, 0x5d, 2 }, 163 | { 0xd91615f0, key_d91615f0, 0x5d, 2 }, 164 | { 0xd91616f0, key_d91616f0, 0x5d, 2 }, 165 | { 0xd91617f0, key_d91617f0, 0x5d, 2 }, 166 | { 0xd91618f0, key_d91618f0, 0x5d, 2 }, 167 | { 0xd91619f0, key_d91619f0, 0x5d, 2 }, 168 | { 0xd91620f0, key_d91620f0, 0x5d, 2 }, 169 | { 0xd91621f0, key_d91621f0, 0x5d, 2 }, 170 | { 0xd91622f0, key_d91622f0, 0x5d, 2 }, 171 | { 0xd91623f0, key_d91623f0, 0x5d, 2 }, 172 | { 0xd91624f0, key_d91624f0, 0x5d, 2 }, 173 | { 0xd91628f0, key_d91628f0, 0x5d, 2 }, 174 | { 0xd91680f0, key_d91680f0, 0x5d, 6 }, 175 | { 0xd91681f0, key_d91681f0, 0x5d, 6 }, 176 | }; 177 | 178 | #endif 179 | -------------------------------------------------------------------------------- /pspcipher/kirk.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tpunix/kirk_engine/ee09e86b743d1c147579ff21f46dd0874303daf3/pspcipher/kirk.xlsx -------------------------------------------------------------------------------- /pspcipher/prx_decrypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of pspcipher. 3 | * 4 | * Copyright (C) 2008 hrimfaxi (outmatch@gmail.com) 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "utils.h" 28 | #include "kirk_engine.h" 29 | #include "pspcipher.h" 30 | #include "psp_headers.h" 31 | 32 | static int check_blacklist(u8 *prx, u8 *blacklist, u32 blacklistsize) 33 | { 34 | u32 i; 35 | 36 | if (blacklistsize / 16 == 0) { 37 | return 0; 38 | } 39 | 40 | i = 0; 41 | 42 | while (i < blacklistsize / 16) { 43 | if (!memcmp(blacklist + i * 16, (prx + 0x140), 0x10)) { 44 | return 1; 45 | } 46 | 47 | i++; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | static int kirk7(u8* prx, u32 size, u32 scramble_code, u32 use_polling) 54 | { 55 | int ret; 56 | 57 | ((u32 *) prx)[0] = 5; 58 | ((u32 *) prx)[1] = 0; 59 | ((u32 *) prx)[2] = 0; 60 | ((u32 *) prx)[3] = scramble_code; 61 | ((u32 *) prx)[4] = size; 62 | 63 | /* ignore use_polling */ 64 | ret = sceUtilsBufferCopyWithRange (prx, size + 20, prx, size + 20, 7); 65 | 66 | return ret; 67 | } 68 | 69 | static void prx_xor_key_into(u8 *dstbuf, u32 size, u8 *srcbuf, u8 *xor_key) 70 | { 71 | u32 i; 72 | 73 | i = 0; 74 | 75 | while (i < size) { 76 | dstbuf[i] = srcbuf[i] ^ xor_key[i]; 77 | ++i; 78 | } 79 | } 80 | 81 | static void prx_xor_key_large(u8 *buf, u32 size, u8 *xor_key) 82 | { 83 | u32 i; 84 | 85 | i = 0; 86 | 87 | while (i < size) { 88 | buf[i] = buf[i] ^ xor_key[i]; 89 | ++i; 90 | } 91 | } 92 | 93 | static void prx_xor_key(u8 *buf, u32 size, u8 *xor_key1, u8 *xor_key2) 94 | { 95 | u32 i; 96 | 97 | i =0; 98 | while (i < size) { 99 | if (xor_key2 != NULL) { 100 | buf[i] = buf[i] ^ xor_key2[i&0xf]; 101 | } 102 | 103 | buf[i] = buf[i] ^ xor_key1[i&0xf]; 104 | ++i; 105 | } 106 | } 107 | 108 | static void prx_xor_key_single(u8 *buf, u32 size, u8 *xor_key) 109 | { 110 | return prx_xor_key(buf, size, xor_key, NULL); 111 | } 112 | 113 | static u8 buf1[0x150]; 114 | static u8 buf2[0x150]; 115 | static u8 buf3[0x90]; 116 | static u8 buf4[0xb4]; 117 | static u8 buf5[0x20]; 118 | 119 | int uprx_decrypt(user_decryptor *pBlock) 120 | { 121 | if (pBlock == NULL) 122 | return -1; 123 | 124 | if (pBlock->prx == NULL || pBlock->newsize == NULL) 125 | return -2; 126 | 127 | if (pBlock->size < 0x160) 128 | return -202; 129 | 130 | u32 b_0xd4 = 0; 131 | 132 | memset(buf1, 0, sizeof(buf1)); 133 | memset(buf2, 0, sizeof(buf2)); 134 | memset(buf3, 0, sizeof(buf3)); 135 | memset(buf4, 0, sizeof(buf4)); 136 | memset(buf5, 0, sizeof(buf5)); 137 | 138 | memcpy(buf1, pBlock->prx, 0x150); 139 | 140 | /** tag mismatched */ 141 | if (memcmp(buf1 + 0xd0, pBlock->tag, 4)) 142 | return -45; 143 | 144 | int ret = -1; 145 | 146 | if (pBlock->type == 3) { 147 | u8 *p = buf1; 148 | u32 cnt = 0; 149 | 150 | while (p[0xd4] && cnt < 0x18 ) { 151 | cnt++; 152 | p = buf1 + cnt; 153 | } 154 | 155 | if (p[0xd4] != 0) 156 | return -17; 157 | } else if (pBlock->type == 2) { 158 | u8 *p = buf1; 159 | u32 cnt = 0; 160 | 161 | while (p[0xd4] && cnt < 0x58 ) { 162 | cnt++; 163 | p = buf1 + cnt; 164 | } 165 | 166 | if (p[0xd4] != 0) 167 | return -12; 168 | } else if (pBlock->type == 5) { 169 | u8 *p = buf1 + 1; 170 | u32 cnt = 1; 171 | 172 | while (p[0xd4] && cnt < 0x58 ) { 173 | cnt++; 174 | p = buf1 + cnt; 175 | } 176 | 177 | if (p[0xd4] != 0) 178 | return -13; 179 | 180 | b_0xd4 = buf1[0xd4]; 181 | } else if (pBlock->type == 6) { 182 | u8 *p = buf1; 183 | u32 cnt = 0; 184 | 185 | while (p[0xd4] && cnt < 0x38 ) { 186 | cnt++; 187 | p = buf1 + cnt; 188 | } 189 | 190 | if (p[0xd4] != 0) 191 | return -302; 192 | } else if (pBlock->type == 7) { 193 | u8 *p = buf1 + 1; 194 | u32 cnt = 1; 195 | 196 | while (p[0xd4] && cnt < 0x38 ) { 197 | cnt++; 198 | p = buf1 + cnt; 199 | } 200 | 201 | if (p[0xd4] != 0) 202 | return -302; 203 | } 204 | 205 | if (pBlock->blacklist != NULL && pBlock->blacklistsize != 0) { 206 | ret = check_blacklist(buf1, pBlock->blacklist, pBlock->blacklistsize); 207 | 208 | if (ret == 1) 209 | return -305; 210 | } 211 | 212 | u32 elf_size_comp = *(u32*)(buf1+0xb0); 213 | *pBlock->newsize = elf_size_comp; 214 | 215 | if (pBlock->size - 50 < elf_size_comp) 216 | return -206; 217 | 218 | if (pBlock->type >= 2 && pBlock->type <= 7) { 219 | int i; 220 | 221 | for (i=0; i<9; i++) { 222 | memcpy(buf2 + 0x14 + (i << 4), pBlock->key, 0x10); 223 | buf2[0x14+ (i<<4)] = i; 224 | } 225 | } else { 226 | memcpy(buf2 + 14, pBlock->key, 0x90); 227 | } 228 | 229 | if ((ret = kirk7(buf2, 0x90, pBlock->code, pBlock->use_polling)) < 0) { 230 | return ret; 231 | } 232 | 233 | if (pBlock->type == 3 || pBlock->type == 5 || pBlock->type == 7) { 234 | if (pBlock->xor_key2 != NULL) { 235 | prx_xor_key_single(buf2, 0x90, pBlock->xor_key2); 236 | } 237 | } 238 | 239 | memcpy(buf3, buf2, 0x90); 240 | 241 | if (pBlock->type == 3) { 242 | memcpy(buf2, buf1 + 0xec, 0x40); 243 | memset(buf2 + 0x40, 0, 0x50); 244 | buf2[0x60] = 0x03; 245 | buf2[0x70] = 0x50; 246 | 247 | memcpy(buf2 + 0x90, buf1 + 0x80, 0x30); 248 | memcpy(buf2 + 0xc0, buf1 + 0xc0, 0x10); 249 | memcpy(buf2 + 0xd0, buf1 + 0x12c, 0x10); 250 | 251 | prx_xor_key(buf2+144, 0x50, pBlock->xor_key1, pBlock->xor_key2); 252 | ret = sceUtilsBufferCopyWithRange(buf4, 0xb4, buf2, 0x150, 3); 253 | 254 | if (ret != 0) { 255 | return -14; 256 | } 257 | 258 | memcpy(buf2, buf1 + 0xd0, 0x04); 259 | memset(buf2 + 0x04, 0, 0x58); 260 | memcpy(buf2 + 0x5c, buf1 + 0x140, 0x10); 261 | memcpy(buf2 + 0x6c, buf1 + 0x12c, 0x14); 262 | memcpy(buf2 + 0x6c, buf4, 0x10); 263 | memcpy(buf2 + 0x80, buf4, 0x30); 264 | memcpy(buf2 + 0xb0, buf4 + 0x30, 0x10); 265 | memcpy(buf2 + 0xc0, buf1 + 0xb0, 0x10); 266 | memcpy(buf2 + 0xd0, buf1, 0x80); 267 | } else if (pBlock->type == 5 || pBlock->type == 7) { 268 | memcpy(buf2 + 0x14, buf1 + 0x80, 0x30); 269 | memcpy(buf2 + 0x44, buf1 + 0xc0, 0x10); 270 | memcpy(buf2 + 0x54, buf1 + 0x12c, 0x10); 271 | prx_xor_key(buf2+0x14, 0x50, pBlock->xor_key1, pBlock->xor_key2); 272 | ret = kirk7 (buf2, 0x50, pBlock->code, pBlock->use_polling); 273 | 274 | if (ret != 0) { 275 | return -11; 276 | } 277 | 278 | memcpy(buf4, buf2, 0x50); 279 | memcpy(buf2, buf1 + 0xd0, 0x4); 280 | memset(buf2 + 0x04, 0, 0x58); 281 | memcpy(buf2 + 0x5c, buf1 + 0x140, 0x10); 282 | memcpy(buf2 + 0x6c, buf1 + 0x12c, 0x14); 283 | memcpy(buf2 + 0x6c, buf4 + 0x40, 0x10); 284 | memcpy(buf2 + 0x80, buf4, 0x30); 285 | memcpy(buf2 + 0xb0, buf4 + 0x30, 0x10); 286 | memcpy(buf2 + 0xc0, buf1 + 0xb0, 0x10); 287 | memcpy(buf2 + 0xd0, buf1, 0x80); 288 | } else if (pBlock->type != 2 && pBlock->type != 4 && pBlock->type != 6) { 289 | memcpy(buf2, buf1 + 0xd0, 0x80); 290 | memcpy(buf2 + 0x80, buf1 + 0x80, 0x50); 291 | memcpy(buf2 + 0xd0, buf1, 0x80); 292 | } else { 293 | memcpy(buf2 , buf1 + 0xd0, 0x5C); 294 | memcpy(buf2 + 0x5c, buf1 + 0x140, 0x10); 295 | memcpy(buf2 + 0x6c, buf1 + 0x12c, 0x14); 296 | memcpy(buf2 + 0x80, buf1 + 0x80, 0x30); 297 | memcpy(buf2 + 0xb0, buf1 + 0xc0, 0x10); 298 | memcpy(buf2 + 0xc0, buf1 + 0xb0, 0x10); 299 | memcpy(buf2 + 0xd0, buf1 , 0x80); 300 | } 301 | 302 | if (pBlock->type == 1) { 303 | memcpy(buf4 + 0x14, buf2 + 0x10, 0xa0); 304 | ret = kirk7(buf4, 0xa0, pBlock->code, pBlock->use_polling); 305 | 306 | if (ret < 0) { 307 | return -15; 308 | } 309 | 310 | memcpy(buf2 + 0x10, buf4, 0xa0); 311 | } else { 312 | if (pBlock->type >= 2 && pBlock->type <= 7) { 313 | memcpy(buf4 + 0x14, buf2 + 0x5c, 0x60); 314 | } 315 | 316 | if (pBlock->type == 3 || pBlock->type == 5 || pBlock->type == 7) { 317 | prx_xor_key_single(buf4 + 20, 0x60, pBlock->xor_key1); 318 | } 319 | 320 | if (kirk7(buf4, 0x60, pBlock->code, pBlock->use_polling) < 0) { 321 | return -5; 322 | } 323 | 324 | memcpy(buf2 + 0x5c, buf4, 0x60); 325 | } 326 | 327 | if (pBlock->type < 2 || pBlock->type > 7) { 328 | memcpy(buf4, buf2 + 0x4, 0x14); 329 | *((u32*)buf2) = 0x14c; 330 | memcpy(buf2+0x4, buf3, 0x14); 331 | } else { 332 | memcpy(buf4, buf2+0x6c, 0x14); 333 | 334 | if (pBlock->type == 4) { 335 | memmove(buf2+0x18, buf2, 0x67); 336 | } else { 337 | memcpy(buf2+0x70, buf2+0x5C, 0x10); 338 | 339 | if (pBlock->type == 6 || pBlock->type == 7) { 340 | memcpy(buf5, buf2+0x3C, 0x20); 341 | memcpy(buf2+0x50, buf5, 0x20); 342 | memset(buf2+0x18, 0, 0x38); 343 | } else { 344 | memset(buf2+0x18, 0, 0x58); 345 | } 346 | 347 | if ( b_0xd4 == 0x80 ) { 348 | buf2[0x18] = 0x80; 349 | } 350 | } 351 | 352 | memcpy(buf2+0x04, buf2, 0x04); 353 | *((u32*)buf2) = 0x014C; 354 | memcpy(buf2+0x08, buf3, 0x10); 355 | } 356 | 357 | /* ignore use_polling */ 358 | ret = sceUtilsBufferCopyWithRange (buf2, 0x150, buf2, 0x150, 0xB); 359 | 360 | if (ret != 0) { 361 | return -6; 362 | } 363 | 364 | if (memcmp(buf2, buf4, 0x14)) { 365 | return -8; 366 | } 367 | 368 | if (pBlock->type < 2 || pBlock->type > 7) { 369 | prx_xor_key_large(buf2+0x40, 0x70, buf3+0x14); 370 | 371 | if (kirk7(buf2 + 0x2c, 0x70, pBlock->code, pBlock->use_polling) < 0) { 372 | return -16; 373 | } 374 | 375 | prx_xor_key_into(pBlock->prx+0x40, 0x70, buf2+0x2c, buf3+0x20); 376 | memcpy(pBlock->prx+0xb0, buf2 + 0xb0, 0xa0); 377 | } else { 378 | prx_xor_key_large(buf2 + 0x80, 0x40, buf3 + 16); 379 | 380 | if (kirk7(buf2 + 0x6c, 0x40, pBlock->code, pBlock->use_polling) < 0) { 381 | return -7; 382 | } 383 | 384 | prx_xor_key_into(pBlock->prx + 0x40, 0x40, buf2 + 108, buf3 + 80); 385 | 386 | if (pBlock->type == 6 || pBlock->type == 7) { 387 | memcpy(pBlock->prx+0x80, buf5, 0x20); 388 | memset(pBlock->prx+0xa0, 0, 0x10); 389 | ((u8*)pBlock->prx)[0xa4] = 1; 390 | ((u8*)pBlock->prx)[0xa0] = 1; 391 | } else { 392 | memset(pBlock->prx+0x80, 0, 0x30); 393 | ((u8*)pBlock->prx)[0xa0] = 1; 394 | } 395 | 396 | memcpy(pBlock->prx+0xb0, buf2+0xc0, 0x10); 397 | memset(pBlock->prx+0xc0, 0, 0x10); 398 | memcpy(pBlock->prx+0xd0, buf2+0xd0, 0x80); 399 | } 400 | 401 | if (b_0xd4 == 0x80) { 402 | if (((u8*)pBlock->prx)[0x590]) 403 | return -302; 404 | 405 | ((u8*)pBlock->prx)[0x590] |= 0x80; 406 | } 407 | 408 | // The real decryption 409 | ret = sceUtilsBufferCopyWithRange(pBlock->prx, pBlock->size, pBlock->prx+0x40, pBlock->size-0x40, 0x1); 410 | if (ret != 0) { 411 | return -9; 412 | } 413 | 414 | if (elf_size_comp < 0x150) { 415 | // Fill with 0 416 | memset(pBlock->prx+elf_size_comp, 0, 0x150-elf_size_comp); 417 | } 418 | 419 | return 0; 420 | } 421 | 422 | -------------------------------------------------------------------------------- /pspcipher/pspcipher.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of pspcipher. 3 | * 4 | * Copyright (C) 2008 hrimfaxi (outmatch@gmail.com) 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "utils.h" 31 | #include "kirk_engine.h" 32 | #include "pspcipher.h" 33 | #include "psp_headers.h" 34 | 35 | #define SAFE_FREE(p) do { \ 36 | if ((p) != NULL) { free(p); (p) = NULL; } \ 37 | } while ( 0 ); 38 | 39 | typedef struct { 40 | u32 tag; 41 | u8 *key; 42 | u32 code; 43 | u32 type; 44 | } CipherKey; 45 | 46 | #include "keys_data.h" 47 | 48 | CipherKey *GetCipherByTag(u32 tag) 49 | { 50 | int i; 51 | 52 | for(i=0; imodname); 106 | printf(", elf_size: %d", header->elf_size); 107 | printf(", decrypt_mode: 0x%X", header->decrypt_mode); 108 | printf(", tag: 0x%08X\n", header->tag); 109 | printf("\n"); 110 | } 111 | 112 | int IsPrxCompressed(u8 *prx) 113 | { 114 | if ((prx[0] == 0x1F && prx[1] == 0x8B) || 115 | memcmp(prx, "2RLZ", 4) == 0 || 116 | memcmp(prx, "KL4E", 4) == 0) { 117 | return 1; 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | int CipherDecrypt(u8 *prx, u32 size, const char *output_filename) 124 | { 125 | int ret; 126 | u32 cbDecrypted = 0; 127 | u32 tag; 128 | user_decryptor u_dec; 129 | 130 | tag = ((PSP_Header2*)prx)->tag; 131 | CipherKey *cipher = GetCipherByTag(tag); 132 | 133 | if (cipher == NULL) { 134 | printf("Unknown key tag: 0x%08x\n", tag); 135 | 136 | return -1; 137 | } 138 | 139 | u_dec.tag = &tag; 140 | u_dec.key = cipher->key; 141 | u_dec.code = cipher->code; 142 | u_dec.prx = prx; 143 | u_dec.size = size; 144 | u_dec.newsize = &cbDecrypted; 145 | u_dec.use_polling = 0; 146 | u_dec.blacklist = NULL; 147 | u_dec.blacklistsize = 0; 148 | u_dec.type = cipher->type; 149 | u_dec.xor_key1 = NULL; 150 | u_dec.xor_key2 = NULL; 151 | ret = uprx_decrypt(&u_dec); 152 | 153 | if (ret != 0) { 154 | printf("uprx_decrypt failed -> %d\n", ret); 155 | 156 | return ret; 157 | } else { 158 | printf("Decrypt OK, "); 159 | } 160 | 161 | if (IsPrxCompressed(prx)) { 162 | printf("Decompress not implenment yet\n"); 163 | } 164 | 165 | ret = WriteFile(output_filename, prx, cbDecrypted); 166 | 167 | if (ret != cbDecrypted) { 168 | ErrorExit("Error writing %s (%d)\n", output_filename, ret); 169 | } else { 170 | printf("%s saved\n", output_filename); 171 | } 172 | 173 | return 0; 174 | } 175 | 176 | void PrintUsage(int argc, char *argv[]) 177 | { 178 | printf("%s: \n", argv[0]); 179 | } 180 | 181 | int LoadFile(const char *src, u8 **output_buf, long *file_size) 182 | { 183 | FILE *fp; 184 | void *buf; 185 | 186 | fp = fopen(src, "rb"); 187 | 188 | if (fp == NULL) { 189 | return -1; 190 | } 191 | 192 | fseek(fp, 0, SEEK_END); 193 | *file_size = ftell(fp); 194 | buf = malloc(*file_size); 195 | 196 | if (buf == NULL) { 197 | fclose(fp); 198 | 199 | return -2; 200 | } 201 | 202 | fseek(fp, 0, SEEK_SET); 203 | 204 | if (1 != fread(buf, *file_size, 1, fp)) { 205 | fclose(fp); 206 | free(buf); 207 | 208 | return -3; 209 | } 210 | 211 | *output_buf = buf; 212 | fclose(fp); 213 | 214 | return 0; 215 | } 216 | 217 | u8 *CheckPrxHeader(u8 *file, int file_size) 218 | { 219 | u32 *header; 220 | 221 | if (file_size < 0x160) { 222 | return NULL; 223 | } 224 | 225 | for (header = (u32*)file; header < (u32*)(file+file_size); ++header) { 226 | if (*header == 0x5053507e /* ~PSP */ ) { 227 | break; 228 | } 229 | } 230 | 231 | if (header >= (u32*)(file+file_size)) { 232 | return NULL; 233 | } 234 | 235 | return (u8*)header; 236 | } 237 | 238 | int main(int argc, char *argv[]) 239 | { 240 | u8 *prx_file = NULL, *prx = NULL; 241 | const char *src, *dst; 242 | long file_size; 243 | int ret; 244 | 245 | kirk_init(); 246 | src = dst = NULL; 247 | 248 | if (argc < 3) { 249 | PrintUsage(argc, argv); 250 | 251 | return -1; 252 | } else { 253 | src = argv[1]; 254 | dst = argv[2]; 255 | } 256 | 257 | printf("PSPCipher by TPU & liquidzigong\n"); 258 | ret = LoadFile(src, &prx_file, &file_size); 259 | 260 | if (ret < 0) { 261 | ErrorExit("Load file failed (%d)\n", ret); 262 | } 263 | 264 | prx = CheckPrxHeader(prx_file, file_size); 265 | 266 | if (prx == NULL) { 267 | ErrorExit("Invalid PRX\n"); 268 | } 269 | 270 | DispPrxInfo(src, prx); 271 | CipherDecrypt(prx, file_size, dst); 272 | SAFE_FREE(prx_file); 273 | 274 | return 0; 275 | } 276 | -------------------------------------------------------------------------------- /pspcipher/pspcipher.h: -------------------------------------------------------------------------------- 1 | #ifndef DECRYPTBLOCK_H 2 | #define DECRYPTBLOCK_H 3 | 4 | /* 5 | * This file is part of pspcipher. 6 | * 7 | * Copyright (C) 2008 hrimfaxi (outmatch@gmail.com) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, but 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 | * for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License along 20 | * with this program; if not, write to the Free Software Foundation, Inc., 21 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 | */ 23 | 24 | typedef struct _user_decryptor { 25 | u32 *tag; // key tag addr 26 | u8 *key; // 16 bytes key 27 | u32 code; // scramble code 28 | u8 *prx; // prx addr 29 | u32 size; // prx size 30 | u32 *newsize; // pointer of prx new size after decryption 31 | u32 use_polling; // use sceUtilsBufferCopyByPollingWithRange when 1 is set, pass 0 32 | u8 *blacklist; // module blacklist, pass NULL 33 | u32 blacklistsize; // module blacklist size in byte, pass 0 34 | u32 type; // prx type 2 for game, 5 for game patch etc, look up loadcore.prx if you are unsure 35 | u8 *xor_key1; // optional xor key, when decrypting prx type 3/5 this key is essential, otherwise can be NULL 36 | u8 *xor_key2; // optional xor key, when decrypting DRMed module this key is essential, otherwise can be NULL 37 | } user_decryptor; 38 | 39 | typedef struct _kernel_decryptor { 40 | u8 *prx; // prx addr 41 | u32 size; // prx size 42 | u32 *newsize; // pointer of prx new size after decryption 43 | u32 use_polling; // use sceUtilsBufferCopyByPollingWithRange when 1 is set, pass 0 44 | } kernel_decryptor; 45 | 46 | /** 47 | * Decrypt user PRX module such as game, game-patch etc. 48 | * It has the same behavior with sub_000000e0 in mesg_led_02g.prx from FW 6.20 49 | */ 50 | extern int uprx_decrypt(user_decryptor *p); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /pspcipher/test_prx_decrypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of pspcipher. 3 | * 4 | * Copyright (C) 2008 hrimfaxi (outmatch@gmail.com) 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "utils.h" 28 | #include "kirk_engine.h" 29 | #include "pspcipher.h" 30 | #include "psp_headers.h" 31 | 32 | static int kirk7(u8* prx, u32 size, u32 scramble_code, u32 use_polling) 33 | { 34 | int ret; 35 | 36 | ((u32 *) prx)[0] = 5; 37 | ((u32 *) prx)[1] = 0; 38 | ((u32 *) prx)[2] = 0; 39 | ((u32 *) prx)[3] = scramble_code; 40 | ((u32 *) prx)[4] = size; 41 | 42 | /* ignore use_polling */ 43 | ret = sceUtilsBufferCopyWithRange (prx, size + 20, prx, size + 20, 7); 44 | 45 | return ret; 46 | } 47 | 48 | static void prx_xor_key_into(u8 *dstbuf, u32 size, u8 *srcbuf, u8 *xor_key) 49 | { 50 | u32 i; 51 | 52 | i = 0; 53 | 54 | while (i < size) { 55 | dstbuf[i] = srcbuf[i] ^ xor_key[i]; 56 | ++i; 57 | } 58 | } 59 | 60 | static void prx_xor_key_large(u8 *buf, u32 size, u8 *xor_key) 61 | { 62 | u32 i; 63 | 64 | i = 0; 65 | 66 | while (i < size) { 67 | buf[i] = buf[i] ^ xor_key[i]; 68 | ++i; 69 | } 70 | } 71 | 72 | static void prx_xor_key(u8 *buf, u32 size, u8 *xor_key1, u8 *xor_key2) 73 | { 74 | u32 i; 75 | 76 | i =0; 77 | while (i < size) { 78 | if (xor_key2 != NULL) { 79 | buf[i] = buf[i] ^ xor_key2[i&0xf]; 80 | } 81 | 82 | buf[i] = buf[i] ^ xor_key1[i&0xf]; 83 | ++i; 84 | } 85 | } 86 | 87 | static void prx_xor_key_single(u8 *buf, u32 size, u8 *xor_key) 88 | { 89 | return prx_xor_key(buf, size, xor_key, NULL); 90 | } 91 | 92 | static u8 buf1[0x150]; 93 | static u8 buf2[0x150]; 94 | static u8 buf3[0x90]; 95 | static u8 buf4[0xb4]; 96 | static u8 buf5[0x20]; 97 | 98 | int uprx_decrypt(user_decryptor *pBlock) 99 | { 100 | int i; 101 | if (pBlock == NULL) 102 | return -1; 103 | 104 | if (pBlock->prx == NULL || pBlock->newsize == NULL) 105 | return -2; 106 | 107 | if (pBlock->size < 0x160) 108 | return -202; 109 | 110 | u32 b_0xd4 = 0; 111 | 112 | memset(buf1, 0, sizeof(buf1)); 113 | memset(buf2, 0, sizeof(buf2)); 114 | memset(buf3, 0, sizeof(buf3)); 115 | memset(buf4, 0, sizeof(buf4)); 116 | memset(buf5, 0, sizeof(buf5)); 117 | 118 | memcpy(buf1, pBlock->prx, 0x150); 119 | 120 | /** tag mismatched */ 121 | if (memcmp(buf1 + 0xd0, pBlock->tag, 4)) 122 | return -45; 123 | 124 | int ret = -1; 125 | 126 | if (pBlock->type == 3) { 127 | // zero check: 0xd4 +0x18 128 | } else if (pBlock->type == 2) { 129 | // zero check: 0xd4 +0x58 130 | } else if (pBlock->type == 5) { 131 | // zero check: 0xd5 +0x57 132 | b_0xd4 = buf1[0xd4]; 133 | } else if (pBlock->type == 6) { 134 | // zero check: 0xd4 +0x38 135 | } else if (pBlock->type == 7) { 136 | // zero check: 0xd4 +0x38 137 | } 138 | 139 | u32 elf_size_comp = *(u32*)(buf1+0xb0); 140 | *pBlock->newsize = elf_size_comp; 141 | 142 | if (pBlock->size - 50 < elf_size_comp) 143 | return -206; 144 | 145 | // type 2,3,4,5,6,7 146 | for (i=0; i<9; i++) { 147 | memcpy(buf2 + 0x14 + (i << 4), pBlock->key, 0x10); 148 | buf2[0x14+ (i<<4)] = i; 149 | } 150 | if ((ret = kirk7(buf2, 0x90, pBlock->code, pBlock->use_polling)) < 0) { 151 | return ret; 152 | } 153 | 154 | memcpy(buf3, buf2, 0x90); 155 | 156 | memcpy(buf2 , buf1 + 0xd0, 0x5C); 157 | memcpy(buf2 + 0x5c, buf1 + 0x140, 0x10); 158 | memcpy(buf2 + 0x6c, buf1 + 0x12c, 0x14); 159 | memcpy(buf2 + 0x80, buf1 + 0x80, 0x30); 160 | memcpy(buf2 + 0xb0, buf1 + 0xc0, 0x10); 161 | memcpy(buf2 + 0xc0, buf1 + 0xb0, 0x10); 162 | memcpy(buf2 + 0xd0, buf1 , 0x80); 163 | 164 | memcpy(buf4 + 0x14, buf2 + 0x5c, 0x60); 165 | 166 | if (kirk7(buf4, 0x60, pBlock->code, pBlock->use_polling) < 0) { 167 | return -5; 168 | } 169 | memcpy(buf2 + 0x5c, buf4, 0x60); 170 | 171 | memcpy(buf4, buf2+0x6c, 0x14); 172 | memcpy(buf2+0x70, buf2+0x5C, 0x10); 173 | 174 | if (pBlock->type == 6) { 175 | memcpy(buf5, buf2+0x3C, 0x20); 176 | memcpy(buf2+0x50, buf5, 0x20); 177 | memset(buf2+0x18, 0, 0x38); 178 | } else { 179 | memset(buf2+0x18, 0, 0x58); 180 | } 181 | 182 | memcpy(buf2+0x04, buf2, 0x04); 183 | *((u32*)buf2) = 0x014C; 184 | memcpy(buf2+0x08, buf3, 0x10); 185 | 186 | /* SHA1 */ 187 | ret = sceUtilsBufferCopyWithRange (buf2, 0x150, buf2, 0x150, 0xB); 188 | if (ret != 0) { 189 | return -6; 190 | } 191 | if (memcmp(buf2, buf4, 0x14)) { 192 | return -8; 193 | } 194 | 195 | prx_xor_key_large(buf2+0x80, 0x40, buf3+0x10); 196 | 197 | if (kirk7(buf2+0x6c, 0x40, pBlock->code, pBlock->use_polling) < 0) { 198 | return -7; 199 | } 200 | 201 | prx_xor_key_into(pBlock->prx+0x40, 0x40, buf2+0x6c, buf3+0x50); 202 | 203 | if (pBlock->type == 6) { 204 | memcpy(pBlock->prx+0x80, buf5, 0x20); 205 | memset(pBlock->prx+0xa0, 0, 0x10); 206 | ((u8*)pBlock->prx)[0xa4] = 1; 207 | ((u8*)pBlock->prx)[0xa0] = 1; 208 | } else { 209 | memset(pBlock->prx+0x80, 0, 0x30); 210 | ((u8*)pBlock->prx)[0xa0] = 1; 211 | } 212 | 213 | memcpy(pBlock->prx+0xb0, buf2+0xc0, 0x10); 214 | memset(pBlock->prx+0xc0, 0, 0x10); 215 | memcpy(pBlock->prx+0xd0, buf2+0xd0, 0x80); 216 | 217 | // The real decryption 218 | ret = sceUtilsBufferCopyWithRange(pBlock->prx, pBlock->size, pBlock->prx+0x40, pBlock->size-0x40, 0x1); 219 | if (ret != 0) { 220 | return -9; 221 | } 222 | 223 | return 0; 224 | } 225 | 226 | -------------------------------------------------------------------------------- /pspkg/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -I../kirk -I../common 3 | TARGET = pspkg 4 | pspkg_OBJS = pspkg.o ../common/utils.o 5 | 6 | ifeq ($(DEBUG), 1) 7 | CFLAGS+=-g -O0 8 | else 9 | CFLAGS+=-O2 10 | endif 11 | 12 | all: $(TARGET) 13 | 14 | pspkg: $(pspkg_OBJS) 15 | $(CC) $(CFLAGS) -o $@ $(pspkg_OBJS) -L ../kirk -lkirk -lz 16 | 17 | clean: 18 | $(RM) *.o $(TARGET) *.exe *.exe.stackdump 19 | 20 | -------------------------------------------------------------------------------- /pspkg/pspkg_fixup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pspkg.c 3 | * psp/ps3 pkg extractor. 4 | * writen by tpu. 5 | * port from Mathieulh's C# source 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "kirk_engine.h" 16 | #include "crypto.h" 17 | 18 | /*************************************************************/ 19 | 20 | u8 psp_pkg_key[16] = {0x07,0xF2,0xC6,0x82,0x90,0xB5,0x0D,0x2C,0x33,0x81,0x8D,0x70,0x9B,0x60,0xE6,0x2B}; 21 | u8 ps3_pkg_key[16] = {0x2E,0x7B,0x71,0xD7,0xC9,0xC9,0xA1,0x4E,0xA3,0x22,0x1F,0x18,0x88,0x28,0xB8,0xF8}; 22 | 23 | 24 | u32 get_be64(u8 *buf) 25 | { 26 | return (u32)( (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]); 27 | } 28 | 29 | u32 get_be32(u8 *buf) 30 | { 31 | return (u32)( (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]); 32 | } 33 | 34 | /*************************************************************/ 35 | 36 | void xor_key(u8 *dst, u8 *src, int len) 37 | { 38 | int i; 39 | 40 | for(i=0; i 7 | #include 8 | #include 9 | 10 | #include "utils.h" 11 | #include "kirk_engine.h" 12 | #include "psp_headers.h" 13 | 14 | /*************************************************************/ 15 | 16 | typedef struct { 17 | u32 tag; 18 | u8 key[16]; 19 | u32 code; 20 | u32 type; 21 | } TAG_KEY; 22 | 23 | TAG_KEY key_list[] = { 24 | {0xd91609f0, {0xD0,0x36,0x12,0x75,0x80,0x56,0x20,0x43,0xC4,0x30,0x94,0x3E,0x1C,0x75,0xD1,0xBF}, 0x5d, 2}, 25 | {0xd9160af0, {0x10,0xA9,0xAC,0x16,0xAE,0x19,0xC0,0x7E,0x3B,0x60,0x77,0x86,0x01,0x6F,0xF2,0x63}, 0x5d, 2}, 26 | {0xd9160bf0, {0x83,0x83,0xF1,0x37,0x53,0xD0,0xBE,0xFC,0x8D,0xA7,0x32,0x52,0x46,0x0A,0xC2,0xC2}, 0x5d, 2}, 27 | {0xd91611f0, {0x61,0xB0,0xC0,0x58,0x71,0x57,0xD9,0xFA,0x74,0x67,0x0E,0x5C,0x7E,0x6E,0x95,0xB9}, 0x5d, 2}, 28 | {0xd91612f0, {0x9e,0x20,0xe1,0xcd,0xd7,0x88,0xde,0xc0,0x31,0x9b,0x10,0xaf,0xc5,0xb8,0x73,0x23}, 0x5d, 2}, 29 | {0xd91613f0, {0xEB,0xFF,0x40,0xD8,0xB4,0x1A,0xE1,0x66,0x91,0x3B,0x8F,0x64,0xB6,0xFC,0xB7,0x12}, 0x5d, 2}, 30 | {0xd91614f0, {0xFD,0xF7,0xB7,0x3C,0x9F,0xD1,0x33,0x95,0x11,0xB8,0xB5,0xBB,0x54,0x23,0x73,0x85}, 0x5d, 2}, 31 | {0xd91615f0, {0xC8,0x03,0xE3,0x44,0x50,0xF1,0xE7,0x2A,0x6A,0x0D,0xC3,0x61,0xB6,0x8E,0x5F,0x51}, 0x5d, 2}, 32 | {0xd91624f0, {0x61,0xB7,0x26,0xAF,0x8B,0xF1,0x41,0x58,0x83,0x6A,0xC4,0x92,0x12,0xCB,0xB1,0xE9}, 0x5d, 2}, 33 | {0xd91628f0, {0x49,0xA4,0xFC,0x66,0xDC,0xE7,0x62,0x21,0xDB,0x18,0xA7,0x50,0xD6,0xA8,0xC1,0xB6}, 0x5d, 2}, 34 | {0xd91680f0, {0x2C,0x22,0x9B,0x12,0x36,0x74,0x11,0x67,0x49,0xD1,0xD1,0x88,0x92,0xF6,0xA1,0xD8}, 0x5d, 6}, 35 | {0xd91681f0, {0x52,0xB6,0x36,0x6C,0x8C,0x46,0x7F,0x7A,0xCC,0x11,0x62,0x99,0xC1,0x99,0xBE,0x98}, 0x5d, 6}, 36 | }; 37 | 38 | int total_tags = sizeof(key_list)/sizeof(TAG_KEY); 39 | 40 | /*************************************************************/ 41 | 42 | int WriteFile(const char *file, void *buf, int size) 43 | { 44 | FILE *fp; 45 | int written; 46 | 47 | fp = fopen(file, "wb"); 48 | if(fp==NULL) 49 | return -1; 50 | written = fwrite(buf, 1, size, fp); 51 | fclose(fp); 52 | 53 | return written; 54 | } 55 | 56 | void dump_psp_header(PSP_Header2 *h) 57 | { 58 | int i; 59 | 60 | printf(" sig: %08x\n", h->signature); 61 | printf(" mod_attr: %04x\n", h->mod_attribute); 62 | printf(" comp_attr: %04x\n", h->comp_attribute); 63 | printf(" modver_lo: %02x\n", h->module_ver_lo); 64 | printf(" modver_hi: %02x\n", h->module_ver_hi); 65 | printf(" modname: %s\n" , h->modname); 66 | printf("modversion: %02x\n", h->mod_version); 67 | printf(" segments: %02x\n", h->nsegments); 68 | printf(" elf_size: %08x\n", h->elf_size); 69 | printf(" file_size: %08x\n", h->psp_size); 70 | printf("boot_entry: %08x\n", h->boot_entry); 71 | printf("modinfo_pt: %08x\n", h->modinfo_offset); 72 | printf(" bss_size: %08x\n", h->bss_size); 73 | for(i=0; i<4; i++){ 74 | printf(" seg[%d]: align %04x addr %08x size %08x\n", i, h->seg_align[i], h->seg_address[i], h->seg_size[i]); 75 | } 76 | 77 | printf(" devkit_ver: %08x\n", h->devkit_version); 78 | printf("decrypt_mode: %02x\n", h->decrypt_mode); 79 | printf(" padding: %02x\n", h->padding); 80 | printf("overlap_size: %04x\n", h->overlap_size); 81 | 82 | } 83 | 84 | /*************************************************************/ 85 | 86 | char *strtable; 87 | int e_shnum; 88 | Elf32_Shdr *section; 89 | 90 | Elf32_Shdr *find_section(char *name) 91 | { 92 | int i; 93 | 94 | for(i=0; ie_shoff); 133 | e_shnum = elf->e_shnum; 134 | 135 | shtab_size = e_shnum*elf->e_shentsize; 136 | if(elf->e_shoff+shtab_size>esize){ 137 | printf("Invalid section table! ignore it.\n"); 138 | e_shnum = 0; 139 | }else{ 140 | strtable = (char*)(ebuf+section[elf->e_shstrndx].sh_offset); 141 | fix_reloc7(ebuf); 142 | } 143 | 144 | 145 | memset(psph, 0, sizeof(PSP_Header2)); 146 | 147 | psph->signature = 0x5053507E; 148 | psph->mod_attribute = 0; 149 | psph->comp_attribute = 0; 150 | psph->module_ver_lo = 1; 151 | psph->module_ver_hi = 1; 152 | psph->mod_version = 1; 153 | psph->devkit_version = 0x06020010; 154 | psph->decrypt_mode = 9; 155 | psph->overlap_size = 0; 156 | 157 | psph->comp_size = esize; 158 | psph->_80 = 0x80; 159 | 160 | psph->boot_entry = elf->e_entry; 161 | psph->elf_size = esize; 162 | psph->psp_size = ((esize+15)&0xfffffff0)+0x150; 163 | 164 | // find sceModuleInfo struct 165 | ph = (Elf32_Phdr*)(ebuf+elf->e_phoff); 166 | sh = find_section(".rodata.sceModuleInfo"); 167 | if(sh){ 168 | psph->modinfo_offset = sh->sh_offset; 169 | modinfo = (SceModuleInfo*)(ebuf+sh->sh_offset); 170 | }else{ 171 | // if no section table found, 172 | // ph[0].p_paddr is the offset of .rodata.sceModuleInfo 173 | psph->modinfo_offset = ph[0].p_paddr; 174 | modinfo = (SceModuleInfo*)(ebuf+ph[0].p_paddr); 175 | } 176 | 177 | strcpy(psph->modname, modinfo->modname); 178 | 179 | j = 0; 180 | for(i=0; ie_phnum; i++){ 181 | if(ph[i].p_type==PT_LOAD){ 182 | if(j>3){ 183 | printf("too many segments!\n"); 184 | continue; 185 | } 186 | psph->seg_align[j] = ph[i].p_align; 187 | psph->seg_address[j] = ph[i].p_vaddr; 188 | psph->seg_size[j] = ph[i].p_memsz; 189 | // bss_size are caculated use last ph. 190 | psph->bss_size = ph[i].p_memsz-ph[i].p_filesz; 191 | j++; 192 | } 193 | } 194 | 195 | psph->nsegments = j; 196 | 197 | } 198 | 199 | /*************************************************************/ 200 | 201 | 202 | TAG_KEY *tkey; 203 | 204 | u8 tag_key[0x100]; 205 | 206 | void build_tag_key(TAG_KEY *tk) 207 | { 208 | int i; 209 | u32 *k7 = (u32*)tag_key; 210 | 211 | for(i=0; i<9; i++){ 212 | memcpy(tag_key+0x14+(i*16), tk->key, 0x10); 213 | tag_key[0x14+(i*16)] = i; 214 | } 215 | 216 | k7[0] = KIRK_MODE_DECRYPT_CBC; 217 | k7[1] = 0; 218 | k7[2] = 0; 219 | k7[3] = tk->code; 220 | k7[4] = 0x90; 221 | 222 | kirk_CMD7(tag_key, tag_key, 0x90+0x14); 223 | //hex_dump("tag_keys", tag_key, 0x100); 224 | } 225 | 226 | void show_taglist(void) 227 | { 228 | int i; 229 | 230 | for(i=0; imode = KIRK_MODE_CMD1; 250 | k1->data_size = esize; 251 | k1->data_offset = 0x80; 252 | if(tkey->type==6) 253 | k1->ecdsa = 1; 254 | 255 | memcpy(kbuf+0x90, pbuf, 0x80); 256 | 257 | if(esize%16){ 258 | for(i=0; i<(16-(esize%16)); i++){ 259 | kbuf[0x110+esize+i] = 0xFF-i*0x11; 260 | } 261 | } 262 | 263 | //hex_dump("before kirk0", kbuf, 0x200); 264 | kirk_CMD0(kbuf, kbuf, esize); 265 | //hex_dump("after kirk0", kbuf, 0x200); 266 | 267 | } 268 | 269 | u8 test_k140[16] = { 270 | 0x35, 0xfe, 0x4c, 0x96, 0x00, 0xb2, 0xf6, 0x7e, 0xf5, 0x83, 0xa6, 0x79, 0x1f, 0xa0, 0xe8, 0x86, 271 | }; 272 | 273 | void build_psp_SHA1(u8 *ebuf, u8 *pbuf) 274 | { 275 | u8 tmp[0x150]; 276 | u32 *k4 = (u32*)tmp; 277 | int i; 278 | 279 | memset(tmp, 0, 0x150); 280 | 281 | for(i=0; i<0x40; i++){ 282 | tmp[0x14+i] = ebuf[0x40+i]^tag_key[0x50+i]; 283 | } 284 | memcpy(tmp+0xd0, pbuf, 0x80); 285 | //hex_dump("xor from:", tmp+0x14, 0x40); 286 | 287 | k4[0] = KIRK_MODE_ENCRYPT_CBC; 288 | k4[1] = 0; 289 | k4[2] = 0; 290 | k4[3] = tkey->code; 291 | k4[4] = 0x40; 292 | kirk_CMD4(tmp+0x80-0x14, tmp, 0x40+0x14); 293 | //hex_dump("kirk4:", tmp, 0x100); 294 | 295 | for(i=0; i<0x40; i++){ 296 | tmp[0x80+i] ^= tag_key[0x10+i]; 297 | } 298 | 299 | memcpy(tmp+0xd0, pbuf, 0x80); 300 | memcpy(tmp+0xc0, pbuf+0xb0, 0x10); 301 | memcpy(tmp+0x70, test_k140, 0x10); 302 | memset(tmp, 0, 0x70); 303 | if(tkey->type==6) 304 | memcpy(tmp+0x50, ebuf+0x40+0x40, 0x20); 305 | memcpy(tmp+0x08, tag_key, 0x10); 306 | k4[0] = 0x014c; 307 | k4[1] = tkey->tag; 308 | 309 | //hex_dump("before SHA1:", tmp, 0x150); 310 | kirk_CMD11(tmp, tmp, 0x150); 311 | //hex_dump("after SHA1:", tmp, 0x150); 312 | 313 | 314 | memcpy(tmp+0x5c, test_k140, 0x10); 315 | memcpy(tmp+0x6c, tmp, 0x14); 316 | 317 | 318 | k4 = (u32*)(tmp+0x48); 319 | k4[0] = KIRK_MODE_ENCRYPT_CBC; 320 | k4[1] = 0; 321 | k4[2] = 0; 322 | k4[3] = tkey->code; 323 | k4[4] = 0x60; 324 | kirk_CMD4(tmp+0x48, tmp+0x48, 0x60+0x14); 325 | 326 | memset(tmp, 0, 0x5c); 327 | if(tkey->type==6) 328 | memcpy(tmp+0x3c, ebuf+0x40+0x40, 0x20); 329 | k4 = (u32*)tmp; 330 | k4[0] = tkey->tag; 331 | 332 | //hex_dump("reorder:", tmp, 0x150); 333 | 334 | memcpy(ebuf+0x000, tmp+0xd0, 0x80); 335 | memcpy(ebuf+0x080, tmp+0x80, 0x30); 336 | memcpy(ebuf+0x0b0, tmp+0xc0, 0x10); 337 | memcpy(ebuf+0x0c0, tmp+0xb0, 0x10); 338 | memcpy(ebuf+0x0d0, tmp+0x00, 0x5c); 339 | memcpy(ebuf+0x12c, tmp+0x6c, 0x14); 340 | memcpy(ebuf+0x140, tmp+0x5c, 0x10); 341 | 342 | //hex_dump("PSP header:", ebuf, 0x150); 343 | } 344 | 345 | /*************************************************************/ 346 | 347 | PSP_Header2 psp_header; 348 | 349 | int main(int argc, char *argv[]) 350 | { 351 | FILE *fp; 352 | u8 *ebuf; 353 | int esize; 354 | 355 | int ap, do_list_tag, do_fake_sign, select_tag; 356 | char *input_name, *output_name; 357 | 358 | input_name = NULL; 359 | output_name = NULL; 360 | do_list_tag = 0; 361 | select_tag = -1; 362 | do_fake_sign = 0; 363 | ap = 1; 364 | 365 | if (argc<2) { 366 | printf("Usage: sign_eboot -l\n"); 367 | printf(" list all tags\n"); 368 | printf("Usage: sign_eboot -tn elf_file signed_file\n"); 369 | printf(" sign your elf file. -tn select a tag to use.\n"); 370 | return -1; 371 | } 372 | 373 | while(ap=total_tags){ 402 | printf("invalid tag index!\n"); 403 | show_taglist(); 404 | return -1; 405 | } 406 | 407 | tkey = &key_list[select_tag]; 408 | 409 | fp = fopen(input_name, "rb"); 410 | if(fp==NULL){ 411 | printf("Open file %s failed!\n", input_name); 412 | exit(-1); 413 | } 414 | 415 | fseek(fp, 0, SEEK_END); 416 | esize = ftell(fp); 417 | fseek(fp, 0, SEEK_SET); 418 | 419 | ebuf = malloc(esize+4096); 420 | memset(ebuf, 0, esize+4096); 421 | 422 | fread(ebuf+0x150, esize, 1, fp); 423 | fclose(fp); 424 | 425 | if(*(u32*)(ebuf+0x150)!=0x464c457f) { 426 | printf("%s: not a ELF file.\n", argv[1]); 427 | return -1; 428 | } 429 | printf("Load %s ...\n", input_name); 430 | printf("Use tag %08x\n", tkey->tag); 431 | 432 | build_psp_header(&psp_header, ebuf+0x150, esize); 433 | 434 | build_psp_kirk1(ebuf+0x40, (u8*)&psp_header, esize); 435 | 436 | build_tag_key(tkey); 437 | 438 | build_psp_SHA1(ebuf, (u8*)&psp_header); 439 | 440 | esize = (esize+15)&~15; 441 | 442 | WriteFile(output_name, ebuf, esize+0x150); 443 | printf("Save %s .\n", output_name); 444 | 445 | return 0; 446 | } 447 | 448 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -g -I../kirk -I../common 3 | TARGET = p_edata 4 | PEDATA_OBJS = edata_ec.o ../common/utils.o 5 | 6 | 7 | all: $(TARGET) 8 | 9 | p_edata: $(PEDATA_OBJS) 10 | $(CC) $(CFLAGS) -o $@ $(PEDATA_OBJS) -L ../kirk -lkirk 11 | 12 | clean: 13 | $(RM) *.o $(TARGET) *.exe *.exe.stackdump 14 | 15 | -------------------------------------------------------------------------------- /test/edata.h: -------------------------------------------------------------------------------- 1 | 2 | static unsigned char ed0[] __attribute__((aligned(16))) = { 3 | 0x00, 0x50, 0x53, 0x50, 0x45, 0x44, 0x41, 0x54, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x01, 4 | 0x4a, 0x50, 0x30, 0x34, 0x30, 0x34, 0x2d, 0x55, 0x4c, 0x4a, 0x53, 0x30, 0x30, 0x31, 0x35, 0x30, 5 | 0x5f, 0x30, 0x30, 0x2d, 0x43, 0x30, 0x31, 0x41, 0x31, 0x41, 0x33, 0x46, 0x34, 0x46, 0x42, 0x41, 6 | 0x38, 0x35, 0x39, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7 | 0xa8, 0xdb, 0x0f, 0x19, 0x2d, 0x55, 0x89, 0xfb, 0xf2, 0x85, 0xef, 0x06, 0xf8, 0x20, 0x59, 0xfe, 8 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xcf, 0x2c, 0x96, 0x51, 0x5e, 0x39, 0x38, 9 | 0xce, 0xe9, 0x18, 0xb4, 0xd1, 0xb6, 0xda, 0xe8, 0x8f, 0xff, 0xf3, 0x9a, 0x73, 0x28, 0xfa, 0x22, 10 | 0x2f, 0x58, 0x5c, 0xcc, 0x8e, 0x4f, 0x8f, 0xf3, 0x52, 0x46, 0x7d, 0x3f, 0xb5, 0x43, 0xe3, 0x48, 11 | 0x4c, 0x05, 0x9a, 0x06, 0xad, 0x82, 0xec, 0x5e, 0xe2, 0x5e, 0x03, 0x44, 0x07, 0x93, 0x29, 0xca, 12 | }; 13 | 14 | 15 | static unsigned char ed1[] __attribute__((aligned(16))) = { 16 | 0x00, 0x50, 0x53, 0x50, 0x45, 0x44, 0x41, 0x54, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x01, 17 | 0x4a, 0x50, 0x30, 0x34, 0x30, 0x34, 0x2d, 0x55, 0x4c, 0x4a, 0x53, 0x30, 0x30, 0x31, 0x35, 0x30, 18 | 0x5f, 0x30, 0x30, 0x2d, 0x44, 0x30, 0x39, 0x37, 0x36, 0x44, 0x35, 0x33, 0x38, 0x45, 0x31, 0x41, 19 | 0x30, 0x34, 0x31, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 20 | 0xfa, 0xf4, 0xa2, 0x34, 0x04, 0x48, 0x2c, 0xcc, 0x58, 0xbb, 0xbd, 0x1a, 0x6c, 0x28, 0x0e, 0xa8, 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xcf, 0x2c, 0x96, 0x51, 0x5e, 0x39, 0x38, 22 | 0xce, 0xe9, 0x18, 0xb4, 0xd1, 0xb6, 0xda, 0xe8, 0x8f, 0xff, 0xf3, 0x9a, 0xb6, 0x2f, 0xac, 0x9b, 23 | 0xd4, 0x26, 0x46, 0x8e, 0x62, 0x0f, 0xda, 0x58, 0xa1, 0x06, 0x54, 0xbc, 0xd3, 0x59, 0xdd, 0x24, 24 | 0xc7, 0xf3, 0xeb, 0x1a, 0x20, 0x37, 0x7c, 0x10, 0x48, 0xe1, 0xa0, 0x38, 0x70, 0xf3, 0x1d, 0xec, 25 | }; 26 | 27 | 28 | static unsigned char ed2[] __attribute__((aligned(16))) = { 29 | 0x00, 0x50, 0x53, 0x50, 0x45, 0x44, 0x41, 0x54, 0x02, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x01, 30 | 0x4a, 0x50, 0x30, 0x34, 0x30, 0x34, 0x2d, 0x55, 0x4c, 0x4a, 0x53, 0x30, 0x30, 0x31, 0x35, 0x30, 31 | 0x5f, 0x30, 0x30, 0x2d, 0x35, 0x35, 0x45, 0x39, 0x38, 0x42, 0x38, 0x44, 0x31, 0x38, 0x37, 0x43, 32 | 0x44, 0x33, 0x36, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0xf7, 0xda, 0x23, 0x77, 0x31, 0xb6, 0xa8, 0x73, 0x6e, 0x47, 0xdf, 0x54, 0x10, 0x70, 0x33, 0x81, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xcf, 0x2c, 0x96, 0x51, 0x5e, 0x39, 0x38, 35 | 0xce, 0xe9, 0x18, 0xb4, 0xd1, 0xb6, 0xda, 0xe8, 0x8f, 0xff, 0xf3, 0x9a, 0x7e, 0x1c, 0x63, 0x2c, 36 | 0xd2, 0x52, 0x1c, 0x26, 0x65, 0x9d, 0x9d, 0xe9, 0x89, 0xcc, 0x7a, 0xce, 0x04, 0x84, 0x17, 0x55, 37 | 0xd7, 0x83, 0x81, 0x27, 0x5d, 0x73, 0x9e, 0xa3, 0x88, 0xc4, 0x64, 0x85, 0xb8, 0xf1, 0xdd, 0x6a, 38 | }; 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/edata_ec.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "kirk_engine.h" 6 | #include "ecdsa.h" 7 | 8 | /*************************************************************/ 9 | 10 | typedef struct { 11 | u8 r[20]; 12 | u8 s[20]; 13 | u8 e[20]; 14 | }SIGN_INFO; 15 | 16 | #include "edata.h" 17 | 18 | u8 pubkey_edat_x[20] = {0x1F,0x07,0x2B,0xCC,0xC1,0x62,0xF2,0xCF,0xAE,0xA0,0xE7,0xF4,0xCD,0xFD,0x9C,0xAE,0xC6,0xC4,0x55,0x21}; 19 | u8 pubkey_edat_y[20] = {0x53,0x01,0xF4,0xE3,0x70,0xC3,0xED,0xE2,0xD4,0xF5,0xDB,0xC3,0xA7,0xDE,0x8C,0xAA,0xE8,0xAD,0x5B,0x7D}; 20 | 21 | /*************************************************************/ 22 | 23 | u8 psp_N[20] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xB5,0xAE,0x3C,0x52,0x3E,0x63,0x94,0x4F,0x21,0x27}; 24 | u8 psp_m[20]; 25 | u8 psp_k[20]; 26 | u8 psp_r[20]; 27 | 28 | extern ECDSA_PARAM ecdsa_app; 29 | 30 | /*************************************************************/ 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | SIGN_INFO sig0, sig1, sig2; 35 | u8 nr[20], ns[20]; 36 | int retv; 37 | 38 | printf("EDATA ID: %s\n", ed0+0x10); 39 | 40 | SHA1(ed0, 0x58, sig0.e); 41 | memcpy(sig0.r, ed0+0x58, 20); 42 | memcpy(sig0.s, ed0+0x6c, 20); 43 | 44 | SHA1(ed1, 0x58, sig1.e); 45 | memcpy(sig1.r, ed1+0x58, 20); 46 | memcpy(sig1.s, ed1+0x6c, 20); 47 | 48 | SHA1(ed2, 0x58, sig2.e); 49 | memcpy(sig2.r, ed2+0x58, 20); 50 | memcpy(sig2.s, ed2+0x6c, 20); 51 | 52 | memcpy(psp_r, sig0.r, 20); 53 | 54 | 55 | ecdsa_find_m_k(sig0.r, sig0.s, sig0.e, sig1.s, sig1.e, psp_N, psp_m, psp_k); 56 | ecdsa_find_m_k(sig0.r, sig0.s, sig0.e, sig2.s, sig2.e, psp_N, psp_m, psp_k); 57 | ecdsa_find_m_k(sig0.r, sig1.s, sig1.e, sig2.s, sig2.e, psp_N, psp_m, psp_k); 58 | 59 | printf("====================================\n"); 60 | bn_dump("orig r", sig0.r, 20); 61 | bn_dump("orig s", sig0.s, 20); 62 | 63 | /* ECDSA sign use fixed param */ 64 | ecdsa_set_N(psp_N); 65 | ecdsa_set_priv(psp_k); 66 | ecdsa_sign_fixed(sig0.e, psp_m, psp_r, ns); 67 | printf("ECDSA sign use fixed param:\n"); 68 | bn_dump("sign s", ns, 20); 69 | 70 | 71 | /* ECDSA sign test */ 72 | ecdsa_set_curve(&ecdsa_app); 73 | ecdsa_set_priv(psp_k); 74 | ecdsa_sign(sig0.e, nr, ns, psp_m); 75 | printf("ECDSA sign use full param:\n"); 76 | bn_dump("new r", nr, 20); 77 | bn_dump("new s", ns, 20); 78 | 79 | /* ECDSA verify test */ 80 | ecdsa_set_pub(pubkey_edat_x, pubkey_edat_y); 81 | retv = ecdsa_verify(sig0.e, sig0.r, sig0.s); 82 | if(retv==0) 83 | printf("ECDSA verify passed!\n"); 84 | else 85 | printf("ECDSA verify failed!\n"); 86 | 87 | printf("\n"); 88 | return 0; 89 | } 90 | 91 | --------------------------------------------------------------------------------