static int ctr_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) { struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); int err, first, rounds = 6 + ctx->key_length / 4; struct blkcipher_walk walk; int blocks; desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); first = 1; kernel_neon_begin(); while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { aes_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr, (u8 *)ctx->key_enc, rounds, blocks, walk.iv, first); first = 0; nbytes -= blocks * AES_BLOCK_SIZE; if (nbytes && nbytes == walk.nbytes % AES_BLOCK_SIZE) break; err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE); } if (nbytes) { u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE; u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE; u8 __aligned(8) tail[AES_BLOCK_SIZE]; /* * Minimum alignment is 8 bytes, so if nbytes is <= 8, we need * to tell aes_ctr_encrypt() to only read half a block. */ blocks = (nbytes <= 8) ? -1 : 1; aes_ctr_encrypt(tail, tsrc, (u8 *)ctx->key_enc, rounds, blocks, walk.iv, first); memcpy(tdst, tail, nbytes); err = blkcipher_walk_done(desc, &walk, 0); } kernel_neon_end(); return err; }
int fixup_pkg(char *pkg_name, char *new_name) { FILE *fp; u8 header[256], file_key[16], sha1_key[0x40]; u8 *pkg_buf, *pkg_aeskey, *file_table; int i, base, data_size, pkg_size, total_file; fp = fopen(pkg_name, "rb"); /* header check */ fread(header, 256, 1, fp); if(*(u32*)(header)!=0x474b507f){ printf("Selected file isn't a PKG file!\n"); return -1; } if(header[4]==0x80){ printf("Selected file isn't a debug PKG.\n"); return -1; } pkg_aeskey = psp_pkg_key; /* read all file */ fseek(fp, 0, SEEK_END); pkg_size = ftell(fp); fseek(fp, 0, SEEK_SET); pkg_buf = malloc(pkg_size); fread(pkg_buf, pkg_size, 1, fp); fclose(fp); /* make sha1 key */ memset(sha1_key, 0, 0x40); memcpy(sha1_key+0x00, pkg_buf+0x60, 8); memcpy(sha1_key+0x08, pkg_buf+0x60, 8); memcpy(sha1_key+0x10, pkg_buf+0x68, 8); memcpy(sha1_key+0x18, pkg_buf+0x68, 8); base = get_be32(pkg_buf+0x24); data_size = get_be32(pkg_buf+0x2c); total_file = get_be32(pkg_buf+0x14); // decrypt debug pkg sha1_ctr_encrypt(pkg_buf+base, data_size, 0, sha1_key); memcpy(file_key, header+0x70, 0x10); // read file table file_table = malloc(total_file*0x20); memcpy(file_table, pkg_buf+base, total_file*0x20); // encrypt file table aes_ctr_encrypt(pkg_buf+base, total_file*0x20, 0, file_key, pkg_aeskey); // process all file for(i=0; i<total_file; i++){ u8 *desc = file_table+i*0x20; int name_offset = get_be32(desc+0x00); int name_length = get_be32(desc+0x04); int file_offset = get_be32(desc+0x0c); int file_length = get_be32(desc+0x14); int content_type= desc[0x18]; int file_type = desc[0x1b]; u8 content_name[64]; // read name memcpy(content_name, pkg_buf+base+name_offset, name_length); content_name[name_length] = 0; // encrypt name if(content_type==0x90){ pkg_aeskey = psp_pkg_key; }else{ pkg_aeskey = ps3_pkg_key; } aes_ctr_encrypt(pkg_buf+base+name_offset, name_length, name_offset, file_key, pkg_aeskey); printf("file %2d: offset=%08x length=%08x type=(%2x %2x) %s\n", i, file_offset, file_length, content_type, file_type, content_name); if(file_type==0x04 || file_length==0){ // is DIR continue; } // encrypt data aes_ctr_encrypt(pkg_buf+base+file_offset, file_length, file_offset, file_key, pkg_aeskey); } // make sha1 hash pkg_buf[4] = 0x80; pkg_buf[7] = 0x02; memset(pkg_buf+base+data_size, 0, 0x60); SHA1(pkg_buf, pkg_size-0x20, pkg_buf+pkg_size-0x20); // write back fp = fopen(new_name, "wb"); fwrite(pkg_buf, pkg_size, 1, fp); fclose(fp); free(file_table); free(pkg_buf); return 0; }