| | 1 | /*+-----------------------------+*/ |
| | 2 | /*|2013 USER |*/ |
| | 3 | /*|decrypt algos by flatz |*/ |
| | 4 | /*| |*/ |
| | 5 | /*|GPL v3, DO NOT USE IF YOU |*/ |
| | 6 | /*|DISAGREE TO RELEASE SRC :P |*/ |
| | 7 | /*+-----------------------------+*/ |
| | 8 | |
| | 9 | #include "tools.h" |
| | 10 | #include "types.h" |
| | 11 | #include "iso.h" |
| | 12 | |
| | 13 | #include <stdio.h> |
| | 14 | #include <string.h> |
| | 15 | #include <assert.h> |
| | 16 | #include <stdlib.h> |
| | 17 | |
| | 18 | |
| | 19 | // !!!---- IMPORTANT FOR FWRITE FILES > 2GB ON 32BIT SYSTEMS ----!!! |
| | 20 | // add -D"_LARGEFILE64_SOURCE" |
| | 21 | // and -D"_FILE_OFFSET_BITS=64" |
| | 22 | // to CFLAGS |
| | 23 | // !!!-----------------------------------------------------------!!! |
| | 24 | |
| | 25 | #define PS2_META_SEGMENT_START 1 |
| | 26 | #define PS2_DATA_SEGMENT_START 2 |
| | 27 | #define PS2_DEFAULT_SEGMENT_SIZE 0x4000 |
| | 28 | #define PS2_META_ENTRY_SIZE 0x20 |
| | 29 | |
| | 30 | #define PS2_VMC_ENCRYPT 1 |
| | 31 | #define PS2_VMC_DECRYPT 0 |
| | 32 | |
| | 33 | //prototypes |
| | 34 | void ps2_encrypt_image(char mode[], char image_name[], char data_file[], char real_out_name[], char CID[]); |
| | 35 | void ps2_decrypt_image(char mode[], char image_name[], char meta_file[], char data_file[]); |
| | 36 | void ps2_crypt_vmc(char mode[], char vmc_path[], char vmc_out[], u8 root_key[], int crypt_mode); |
| | 37 | static void build_ps2_header(u8 * buffer, int npd_type, char content_id[], char filename[], s64 iso_size); |
| | 38 | |
| | 39 | |
| | 40 | //keys |
| | 41 | u8 ps2_per_console_seed[] = { 0xD9, 0x2D, 0x65, 0xDB, 0x05, 0x7D, 0x49, 0xE1, 0xA6, 0x6F, 0x22, 0x74, 0xB8, 0xBA, 0xC5, 0x08 }; |
| | 42 | |
| | 43 | u8 ps2_key_cex_meta[] = { 0x38, 0x9D, 0xCB, 0xA5, 0x20, 0x3C, 0x81, 0x59, 0xEC, 0xF9, 0x4C, 0x93, 0x93, 0x16, 0x4C, 0xC9 }; |
| | 44 | u8 ps2_key_cex_data[] = { 0x10, 0x17, 0x82, 0x34, 0x63, 0xF4, 0x68, 0xC1, 0xAA, 0x41, 0xD7, 0x00, 0xB1, 0x40, 0xF2, 0x57 }; |
| | 45 | u8 ps2_key_cex_vmc[] = { 0x64, 0xE3, 0x0D, 0x19, 0xA1, 0x69, 0x41, 0xD6, 0x77, 0xE3, 0x2E, 0xEB, 0xE0, 0x7F, 0x45, 0xD2 }; |
| | 46 | |
| | 47 | u8 ps2_key_dex_meta[] = { 0x2B, 0x05, 0xF7, 0xC7, 0xAF, 0xD1, 0xB1, 0x69, 0xD6, 0x25, 0x86, 0x50, 0x3A, 0xEA, 0x97, 0x98 }; |
| | 48 | u8 ps2_key_dex_data[] = { 0x74, 0xFF, 0x7E, 0x5D, 0x1D, 0x7B, 0x96, 0x94, 0x3B, 0xEF, 0xDC, 0xFA, 0x81, 0xFC, 0x20, 0x07 }; |
| | 49 | u8 ps2_key_dex_vmc[] = { 0x30, 0x47, 0x9D, 0x4B, 0x80, 0xE8, 0x9E, 0x2B, 0x59, 0xE5, 0xC9, 0x14, 0x5E, 0x10, 0x64, 0xA9 }; |
| | 50 | |
| | 51 | u8 ps2_iv[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
| | 52 | |
| | 53 | u8 fallback_header_hash[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; |
| | 54 | |
| | 55 | u8 npd_omac_key2[] = {0x6B,0xA5,0x29,0x76,0xEF,0xDA,0x16,0xEF,0x3C,0x33,0x9F,0xB2,0x97,0x1E,0x25,0x6B}; |
| | 56 | u8 npd_omac_key3[] = {0x9B,0x51,0x5F,0xEA,0xCF,0x75,0x06,0x49,0x81,0xAA,0x60,0x4D,0x91,0xA5,0x4E,0x97}; |
| | 57 | u8 npd_kek[] = {0x72,0xF9,0x90,0x78,0x8F,0x9C,0xFF,0x74,0x57,0x25,0xF0,0x8E,0x4C,0x12,0x83,0x87}; |
| | 58 | |
| | 59 | |
| | 60 | u8 eid_root_key[0x30]; |
| | 61 | u8 * klicensee; |
| | 62 | |
| | 63 | |
| | 64 | static void set_ps2_iv(u8 iv[]) |
| | 65 | { |
| | 66 | memcpy(iv, ps2_iv, 0x10); |
| | 67 | } |
| | 68 | |
| | 69 | |
| | 70 | static void build_ps2_header(u8 * buffer, int npd_type, char content_id[], char filename[], s64 iso_size) |
| | 71 | { |
| | 72 | |
| | 73 | int i; |
| | 74 | u32 type = 1; |
| | 75 | u8 test_hash[] = { 0xBF, 0x2E, 0x44, 0x15, 0x52, 0x8F, 0xD7, 0xDD, 0xDB, 0x0A, 0xC2, 0xBF, 0x8C, 0x15, 0x87, 0x51 }; |
| | 76 | |
| | 77 | wbe32(buffer, 0x50533200); // PS2\0 |
| | 78 | wbe16(buffer + 0x4, 0x1); // ver major |
| | 79 | wbe16(buffer + 0x6, 0x1); // ver minor |
| | 80 | wbe32(buffer + 0x8, npd_type); // NPD type XX |
| | 81 | wbe32(buffer + 0xc, type); // type |
| | 82 | |
| | 83 | wbe64(buffer + 0x88, iso_size); //iso size |
| | 84 | wbe32(buffer + 0x84, PS2_DEFAULT_SEGMENT_SIZE); //segment size |
| | 85 | |
| | 86 | strncpy(buffer + 0x10, content_id, 0x30); |
| | 87 | |
| | 88 | u8 npd_omac_key[0x10]; |
| | 89 | |
| | 90 | for(i=0;i<0x10;i++) npd_omac_key[i] = npd_kek[i] ^ npd_omac_key2[i]; |
| | 91 | |
| | 92 | get_rand(buffer + 0x40, 0x10); //npdhash1 |
| | 93 | //memcpy(buffer + 0x40, test_hash, 0x10); |
| | 94 | |
| | 95 | int buf_len = 0x30+strlen(filename); |
| | 96 | char *buf = (char*)malloc(buf_len+1); |
| | 97 | memcpy(buf, buffer + 0x10, 0x30); |
| | 98 | strcpy(buf+0x30, filename); |
| | 99 | aesOmacMode1(buffer + 0x50, buf, buf_len, npd_omac_key3, sizeof(npd_omac_key3)*8); //npdhash2 |
| | 100 | free(buf); |
| | 101 | aesOmacMode1(buffer + 0x60, (u8*)(buffer), 0x60, npd_omac_key, sizeof(npd_omac_key)*8); //npdhash3 |
| | 102 | |
| | 103 | } |
| | 104 | |
| | 105 | |
| | 106 | void ps2_decrypt_image(char mode[], char image_name[], char meta_file[], char data_file[]) |
| | 107 | { |
| | 108 | FILE * in; |
| | 109 | FILE * data_out; |
| | 110 | FILE * meta_out; |
| | 111 | |
| | 112 | u8 ps2_data_key[0x10]; |
| | 113 | u8 ps2_meta_key[0x10]; |
| | 114 | u8 iv[0x10]; |
| | 115 | |
| | 116 | int segment_size; |
| | 117 | s64 data_size; |
| | 118 | int i; |
| | 119 | u8 header[256]; |
| | 120 | u8 * data_buffer; |
| | 121 | u8 * meta_buffer; |
| | 122 | u32 read = 0; |
| | 123 | int num_child_segments; |
| | 124 | |
| | 125 | //open files |
| | 126 | in = fopen(image_name, "rb"); |
| | 127 | meta_out = fopen(meta_file, "wb"); |
| | 128 | data_out = fopen(data_file, "wb"); |
| | 129 | |
| | 130 | //get file info |
| | 131 | read = fread(header, 256, 1, in); |
| | 132 | segment_size = be32(header + 0x84); |
| | 133 | data_size = be64(header + 0x88); |
| | 134 | num_child_segments = segment_size / PS2_META_ENTRY_SIZE; |
| | 135 | |
| | 136 | printf("segment size: %x\ndata_size: %lx\n\n", segment_size, data_size); |
| | 137 | |
| | 138 | //alloc buffers |
| | 139 | data_buffer = malloc(segment_size*num_child_segments); |
| | 140 | meta_buffer = malloc(segment_size); |
| | 141 | |
| | 142 | //generate keys |
| | 143 | if(strcmp(mode, "cex") == 0) |
| | 144 | { |
| | 145 | printf("cex\n"); |
| | 146 | set_ps2_iv(iv); |
| | 147 | aes128cbc_enc(ps2_key_cex_data, iv, klicensee, 0x10, ps2_data_key); |
| | 148 | aes128cbc_enc(ps2_key_cex_meta, iv, klicensee, 0x10, ps2_meta_key); |
| | 149 | }else{ |
| | 150 | printf("dex\n"); |
| | 151 | set_ps2_iv(iv); |
| | 152 | aes128cbc_enc(ps2_key_dex_data, iv, klicensee, 0x10, ps2_data_key); |
| | 153 | aes128cbc_enc(ps2_key_dex_meta, iv, klicensee, 0x10, ps2_meta_key); |
| | 154 | } |
| | 155 | |
| | 156 | |
| | 157 | //decrypt iso |
| | 158 | fseek(in, segment_size, SEEK_SET); |
| | 159 | |
| | 160 | while(read = fread(meta_buffer, 1, segment_size, in)) |
| | 161 | { |
| | 162 | //decrypt meta |
| | 163 | aes128cbc(ps2_meta_key, iv, meta_buffer, read, meta_buffer); |
| | 164 | fwrite(meta_buffer, read, 1, meta_out); |
| | 165 | |
| | 166 | |
| | 167 | read = fread(data_buffer, 1, segment_size*num_child_segments, in); |
| | 168 | for(i=0;i<num_child_segments;i++) |
| | 169 | aes128cbc(ps2_data_key, iv, data_buffer+(i*segment_size), segment_size, data_buffer+(i*segment_size)); |
| | 170 | if(data_size >= read) |
| | 171 | fwrite(data_buffer, read, 1, data_out); |
| | 172 | else |
| | 173 | fwrite(data_buffer, data_size, 1, data_out); |
| | 174 | |
| | 175 | data_size -= read; |
| | 176 | } |
| | 177 | |
| | 178 | //cleanup |
| | 179 | free(data_buffer); |
| | 180 | free(meta_buffer); |
| | 181 | |
| | 182 | fclose(in); |
| | 183 | fclose(data_out); |
| | 184 | fclose(meta_out); |
| | 185 | } |
| | 186 | |
| | 187 | |
| | 188 | void ps2_encrypt_image(char mode[], char image_name[], char data_file[], char real_out_name[], char CID[]) |
| | 189 | { |
| | 190 | FILE * in; |
| | 191 | FILE * data_out; |
| | 192 | |
| | 193 | u8 ps2_data_key[0x10]; |
| | 194 | u8 ps2_meta_key[0x10]; |
| | 195 | u8 iv[0x10]; |
| | 196 | |
| | 197 | u32 segment_size; |
| | 198 | s64 data_size; |
| | 199 | u32 i; |
| | 200 | u8 header[256]; |
| | 201 | u8 * data_buffer; |
| | 202 | u8 * meta_buffer; |
| | 203 | u8 * ps2_header; |
| | 204 | |
| | 205 | |
| | 206 | u32 read = 0; |
| | 207 | u32 num_child_segments = 0x200; |
| | 208 | u32 segment_number = 0; |
| | 209 | |
| | 210 | //open files |
| | 211 | in = fopen(image_name, "rb"); |
| | 212 | data_out = fopen(data_file, "wb"); |
| | 213 | |
| | 214 | //get file info |
| | 215 | segment_size = PS2_DEFAULT_SEGMENT_SIZE; |
| | 216 | fseeko(in, 0, SEEK_END); |
| | 217 | data_size = ftello(in); |
| | 218 | fseeko(in, 0, SEEK_SET); |
| | 219 | |
| | 220 | printf("segment size: %x\ndata_size: %lx\nCID: %s\niso %s\nout file: %s\n", segment_size, data_size, CID, image_name, data_file); |
| | 221 | |
| | 222 | //prepare buffers |
| | 223 | data_buffer = malloc(segment_size * 0x200); |
| | 224 | meta_buffer = malloc(segment_size); |
| | 225 | ps2_header = malloc(segment_size); |
| | 226 | memset(ps2_header, 0, segment_size); |
| | 227 | |
| | 228 | //generate keys |
| | 229 | if(strcmp(mode, "cex") == 0) |
| | 230 | { |
| | 231 | printf("cex\n"); |
| | 232 | set_ps2_iv(iv); |
| | 233 | aes128cbc_enc(ps2_key_cex_data, iv, klicensee, 0x10, ps2_data_key); |
| | 234 | aes128cbc_enc(ps2_key_cex_meta, iv, klicensee, 0x10, ps2_meta_key); |
| | 235 | }else{ |
| | 236 | printf("dex\n"); |
| | 237 | set_ps2_iv(iv); |
| | 238 | aes128cbc_enc(ps2_key_dex_data, iv, klicensee, 0x10, ps2_data_key); |
| | 239 | aes128cbc_enc(ps2_key_dex_meta, iv, klicensee, 0x10, ps2_meta_key); |
| | 240 | } |
| | 241 | |
| | 242 | |
| | 243 | //write incomplete ps2 header |
| | 244 | build_ps2_header(ps2_header, 2, CID, real_out_name, data_size); |
| | 245 | fwrite(ps2_header, segment_size, 1, data_out); |
| | 246 | |
| | 247 | |
| | 248 | //write encrypted image |
| | 249 | while(read = fread(data_buffer, 1, segment_size*num_child_segments, in)) |
| | 250 | { |
| | 251 | //last segments? |
| | 252 | if(read != (segment_size*num_child_segments)) |
| | 253 | { |
| | 254 | num_child_segments = (read / segment_size); |
| | 255 | if((read % segment_size) > 0) |
| | 256 | num_child_segments += 1; |
| | 257 | } |
| | 258 | |
| | 259 | memset(meta_buffer, 0, segment_size); |
| | 260 | |
| | 261 | //encrypt data and create meta |
| | 262 | for(i=0;i<num_child_segments;i++) |
| | 263 | { |
| | 264 | aes128cbc_enc(ps2_data_key, iv, data_buffer+(i*segment_size), segment_size, data_buffer+(i*segment_size)); |
| | 265 | sha1(data_buffer+(i*segment_size), segment_size, meta_buffer+(i*PS2_META_ENTRY_SIZE)); |
| | 266 | wbe32(meta_buffer+(i*PS2_META_ENTRY_SIZE)+0x14, segment_number); |
| | 267 | segment_number++; |
| | 268 | } |
| | 269 | |
| | 270 | //encrypt meta |
| | 271 | aes128cbc_enc(ps2_meta_key, iv, meta_buffer, segment_size, meta_buffer); |
| | 272 | |
| | 273 | //write meta and data |
| | 274 | fwrite(meta_buffer, segment_size, 1, data_out); |
| | 275 | fwrite(data_buffer, segment_size*num_child_segments, 1, data_out); |
| | 276 | |
| | 277 | memset(data_buffer, 0, segment_size*num_child_segments); |
| | 278 | } |
| | 279 | |
| | 280 | //finalize ps2_header |
| | 281 | // - wtf is between signature and first segment? |
| | 282 | |
| | 283 | //cleanup |
| | 284 | free(data_buffer); |
| | 285 | free(meta_buffer); |
| | 286 | free(ps2_header); |
| | 287 | |
| | 288 | fclose(in); |
| | 289 | fclose(data_out); |
| | 290 | } |
| | 291 | |
| | 292 | void ps2_crypt_vmc(char mode[], char vmc_path[], char vmc_out[], u8 root_key[], int crypt_mode) |
| | 293 | { |
| | 294 | FILE * in; |
| | 295 | FILE * data_out; |
| | 296 | FILE * meta_out; |
| | 297 | |
| | 298 | u8 ps2_vmc_key[0x10]; |
| | 299 | u8 iv[0x10]; |
| | 300 | |
| | 301 | int segment_size, data_size; |
| | 302 | int i; |
| | 303 | u8 header[256]; |
| | 304 | u8 * data_buffer; |
| | 305 | u8 * meta_buffer; |
| | 306 | u32 read = 0; |
| | 307 | |
| | 308 | segment_size = PS2_DEFAULT_SEGMENT_SIZE; |
| | 309 | |
| | 310 | //open files |
| | 311 | in = fopen(vmc_path, "rb"); |
| | 312 | data_out = fopen(vmc_out, "wb"); |
| | 313 | |
| | 314 | //alloc buffers |
| | 315 | data_buffer = malloc(segment_size); |
| | 316 | |
| | 317 | //generate keys |
| | 318 | if(strcmp(mode, "cex") == 0) |
| | 319 | { |
| | 320 | aes256cbc_enc(root_key, root_key+0x20, ps2_per_console_seed, 0x10, iv); |
| | 321 | memcpy(ps2_vmc_key, ps2_key_cex_vmc, 0x10); |
| | 322 | }else{ |
| | 323 | aes256cbc_enc(root_key, root_key+0x20, ps2_per_console_seed, 0x10, iv); |
| | 324 | memcpy(ps2_vmc_key, ps2_key_dex_vmc, 0x10); |
| | 325 | } |
| | 326 | |
| | 327 | memset(iv+8, 0, 8); |
| | 328 | |
| | 329 | while(read = fread(data_buffer, 1, segment_size, in)) |
| | 330 | { |
| | 331 | //decrypt or encrypt vmc |
| | 332 | if(crypt_mode == PS2_VMC_DECRYPT) |
| | 333 | aes128cbc(ps2_vmc_key, ps2_iv, data_buffer, read, data_buffer); |
| | 334 | else |
| | 335 | aes128cbc_enc(ps2_vmc_key, ps2_iv, data_buffer, read, data_buffer); |
| | 336 | fwrite(data_buffer, read, 1, data_out); |
| | 337 | |
| | 338 | } |
| | 339 | |
| | 340 | //cleanup |
| | 341 | free(data_buffer); |
| | 342 | |
| | 343 | fclose(in); |
| | 344 | fclose(data_out); |
| | 345 | |
| | 346 | } |
| | 347 | |
| | 348 | |
| | 349 | |
| | 350 | |
| | 351 | int main(int argc, char *argv[]) |
| | 352 | { |
| | 353 | |
| | 354 | u8 * root_key = NULL; |
| | 355 | |
| | 356 | printf("\nps2classic\nhttp://gitorious.ps3dev.net/ps2classic\nLicense: GPLv3\n\n"); |
| | 357 | |
| | 358 | |
| | 359 | if(argc == 1) |
| | 360 | { |
| | 361 | printf("usage:\n\tiso:\n\t\t%s d [cex/dex] [klicensee] [encrypted image] [out data] [out meta]\n", argv[0]); |
| | 362 | printf("\t\t%s e [cex/dex] [klicensee] [iso] [out data] [real out name] [CID]\n", argv[0]); |
| | 363 | printf("\t\nvmc:\n\t\t%s vd [cex/dex] [vme file] [out vmc] [(eid root key)]\n", argv[0]); |
| | 364 | printf("\t\t%s ve [cex/dex] [vmc file] [out vme] [(eid root key)]\n", argv[0]); |
| | 365 | printf("\t\nimage tools:\n\t\t%s prepare [image file]\n", argv[0]); |
| | 366 | printf("\t\t%s info [image file]\n", argv[0]); |
| | 367 | exit(0); |
| | 368 | } |
| | 369 | |
| | 370 | if(argc > 6) |
| | 371 | klicensee = mmap_file(argv[3]); |
| | 372 | |
| | 373 | if(strcmp(argv[1], "d") == 0) |
| | 374 | if(argc == 7) |
| | 375 | ps2_decrypt_image(argv[2], argv[4], argv[6], argv[5]); |
| | 376 | else |
| | 377 | printf("Error: invalid number of arguments for decryption\n"); |
| | 378 | else if(strcmp(argv[1], "e") == 0) |
| | 379 | if(argc == 8) |
| | 380 | ps2_encrypt_image(argv[2], argv[4], argv[5], argv[6], argv[7]); |
| | 381 | else |
| | 382 | printf("Error: invalid number of arguments for encryption\n"); |
| | 383 | else if(strcmp(argv[1], "vd") == 0 || strcmp(argv[1], "ve") == 0) |
| | 384 | { |
| | 385 | if(argc == 6) |
| | 386 | root_key = mmap_file(argv[3]); |
| | 387 | else if(argc == 5){ |
| | 388 | root_key = malloc(0x30); |
| | 389 | memset(root_key, 0, 0x30); |
| | 390 | }else{ |
| | 391 | printf("Error: invalid number of arguments for vme processing\n"); |
| | 392 | exit(0); |
| | 393 | } |
| | 394 | |
| | 395 | if(strcmp(argv[1], "vd") == 0) |
| | 396 | ps2_crypt_vmc(argv[2], argv[3], argv[4], root_key, PS2_VMC_DECRYPT); |
| | 397 | else |
| | 398 | ps2_crypt_vmc(argv[2], argv[3], argv[4], root_key, PS2_VMC_ENCRYPT); |
| | 399 | |
| | 400 | free(root_key); |
| | 401 | } |
| | 402 | else if(strcmp(argv[1], "prepare") == 0 && argc == 3) |
| | 403 | { |
| | 404 | prepare_iso(argv[2]); |
| | 405 | } |
| | 406 | else if(strcmp(argv[1], "info") == 0 && argc == 3) |
| | 407 | { |
| | 408 | print_ps2image_info(argv[2]); |
| | 409 | } |
| | 410 | else |
| | 411 | printf("FAIL: unknown option or wrong number of arguments\n"); |
| | 412 | |
| | 413 | } |