mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
add PGD file support.
This commit is contained in:
parent
50def41ffa
commit
a4f65624c3
6 changed files with 846 additions and 6 deletions
|
@ -31,6 +31,10 @@
|
|||
#include "../FileSystems/ISOFileSystem.h"
|
||||
#include "../FileSystems/DirectoryFileSystem.h"
|
||||
|
||||
extern "C" {
|
||||
#include "ext/libkirk/amctrl.h"
|
||||
};
|
||||
|
||||
#include "sceIo.h"
|
||||
#include "sceRtc.h"
|
||||
#include "sceKernel.h"
|
||||
|
@ -76,6 +80,7 @@ umd01: block access - umd
|
|||
#define O_CREAT 0x0200
|
||||
#define O_TRUNC 0x0400
|
||||
#define O_NOWAIT 0x8000
|
||||
#define O_NPDRM 0x40000000
|
||||
|
||||
|
||||
typedef s32 SceMode;
|
||||
|
@ -168,8 +173,17 @@ public:
|
|||
|
||||
PSPFileInfo info;
|
||||
u32 openMode;
|
||||
|
||||
u32 npdrm;
|
||||
PGD_DESC *pgdInfo;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void TellFsThreadEnded (SceUID threadID) {
|
||||
pspFileSystem.ThreadEnded(threadID);
|
||||
}
|
||||
|
@ -342,6 +356,42 @@ u32 sceIoGetstat(const char *filename, u32 addr) {
|
|||
}
|
||||
}
|
||||
|
||||
u32 npdrmRead(FileNode *f, u8 *data, int size) {
|
||||
PGD_DESC *pgd = f->pgdInfo;
|
||||
u32 block, offset;
|
||||
u32 remain_size, copy_size;
|
||||
|
||||
block = pgd->file_offset/pgd->block_size;
|
||||
offset = pgd->file_offset%pgd->block_size;
|
||||
|
||||
remain_size = size;
|
||||
|
||||
while(remain_size){
|
||||
|
||||
if(pgd->current_block!=block){
|
||||
pspFileSystem.ReadFile(f->handle, pgd->block_buf, pgd->block_size);
|
||||
pgd_decrypt_block(pgd, block);
|
||||
pgd->current_block = block;
|
||||
}
|
||||
|
||||
if(offset+remain_size>pgd->block_size){
|
||||
copy_size = pgd->block_size-offset;
|
||||
block += 1;
|
||||
offset = 0;
|
||||
}else{
|
||||
copy_size = remain_size;
|
||||
}
|
||||
|
||||
memcpy(data, pgd->block_buf+offset, copy_size);
|
||||
|
||||
data += copy_size;
|
||||
remain_size -= copy_size;
|
||||
pgd->file_offset += copy_size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
//Not sure about wrapping it or not, since the log seems to take the address of the data var
|
||||
u32 sceIoRead(int id, u32 data_addr, int size) {
|
||||
if (id == 3) {
|
||||
|
@ -358,7 +408,11 @@ u32 sceIoRead(int id, u32 data_addr, int size) {
|
|||
}
|
||||
else if (Memory::IsValidAddress(data_addr)) {
|
||||
u8 *data = (u8*) Memory::GetPointer(data_addr);
|
||||
f->asyncResult = (u32) pspFileSystem.ReadFile(f->handle, data, size);
|
||||
if(f->npdrm){
|
||||
f->asyncResult = (u32) npdrmRead(f, data, size);
|
||||
}else{
|
||||
f->asyncResult = (u32) pspFileSystem.ReadFile(f->handle, data, size);
|
||||
}
|
||||
DEBUG_LOG(HLE, "%i=sceIoRead(%d, %08x , %i)", f->asyncResult, id, data_addr, size);
|
||||
return f->asyncResult;
|
||||
} else {
|
||||
|
@ -445,6 +499,26 @@ u32 sceIoCancel(int id)
|
|||
return error;
|
||||
}
|
||||
|
||||
u32 npdrmLseek(FileNode *f, s32 where, FileMove whence)
|
||||
{
|
||||
u32 newPos;
|
||||
|
||||
if(whence==FILEMOVE_BEGIN){
|
||||
newPos = where;
|
||||
}else if(whence==FILEMOVE_CURRENT){
|
||||
newPos = f->pgdInfo->file_offset+where;
|
||||
}else{
|
||||
newPos = f->pgdInfo->data_size+where;
|
||||
}
|
||||
|
||||
if(newPos<0 || newPos>f->pgdInfo->data_size){
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f->pgdInfo->file_offset = newPos;
|
||||
return newPos;
|
||||
}
|
||||
|
||||
s64 sceIoLseek(int id, s64 offset, int whence) {
|
||||
u32 error;
|
||||
FileNode *f = kernelObjects.Get < FileNode > (id, error);
|
||||
|
@ -468,7 +542,11 @@ s64 sceIoLseek(int id, s64 offset, int whence) {
|
|||
if(newPos < 0)
|
||||
return -1;
|
||||
|
||||
f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek);
|
||||
if(f->npdrm){
|
||||
f->asyncResult = npdrmLseek(f, (s32)offset, seek);
|
||||
}else{
|
||||
f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek);
|
||||
}
|
||||
DEBUG_LOG(HLE, "%i = sceIoLseek(%d,%i,%i)", f->asyncResult, id, (int) offset, whence);
|
||||
return f->asyncResult;
|
||||
} else {
|
||||
|
@ -500,7 +578,11 @@ u32 sceIoLseek32(int id, int offset, int whence) {
|
|||
if(newPos < 0)
|
||||
return -1;
|
||||
|
||||
f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek);
|
||||
if(f->npdrm){
|
||||
f->asyncResult = npdrmLseek(f, (s32)offset, seek);
|
||||
}else{
|
||||
f->asyncResult = (u32) pspFileSystem.SeekFile(f->handle, (s32) offset, seek);
|
||||
}
|
||||
DEBUG_LOG(HLE, "%i = sceIoLseek32(%d,%i,%i)", f->asyncResult, id, (int) offset, whence);
|
||||
return f->asyncResult;
|
||||
} else {
|
||||
|
@ -520,6 +602,8 @@ u32 sceIoOpen(const char* filename, int flags, int mode) {
|
|||
access |= FILEACCESS_APPEND;
|
||||
if (flags & O_CREAT)
|
||||
access |= FILEACCESS_CREATE;
|
||||
if (flags & O_NPDRM)
|
||||
|
||||
|
||||
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
|
||||
u32 h = pspFileSystem.OpenFile(filename, (FileAccess) access);
|
||||
|
@ -535,14 +619,23 @@ u32 sceIoOpen(const char* filename, int flags, int mode) {
|
|||
f->handle = h;
|
||||
f->fullpath = filename;
|
||||
f->asyncResult = id;
|
||||
f->info = info;
|
||||
f->info = pspFileSystem.GetFileInfo(filename);
|
||||
f->openMode = access;
|
||||
|
||||
f->npdrm = (flags & O_NPDRM)? true: false;
|
||||
|
||||
DEBUG_LOG(HLE, "%i=sceIoOpen(%s, %08x, %08x)", id, filename, flags, mode);
|
||||
return id;
|
||||
}
|
||||
|
||||
u32 sceIoClose(int id) {
|
||||
u32 error;
|
||||
DEBUG_LOG(HLE, "sceIoClose(%d)", id);
|
||||
FileNode *f = kernelObjects.Get < FileNode > (id, error);
|
||||
if(f && f->npdrm){
|
||||
free(f->pgdInfo->block_buf);
|
||||
free(f->pgdInfo);
|
||||
}
|
||||
return kernelObjects.Destroy < FileNode > (id);
|
||||
}
|
||||
|
||||
|
@ -1091,8 +1184,16 @@ u32 sceIoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 ou
|
|||
case 0x04100001:
|
||||
if (Memory::IsValidAddress(indataPtr) && inlen == 16) {
|
||||
u8 keybuf[16];
|
||||
u8 pgd_header[0x90];
|
||||
memcpy(keybuf, Memory::GetPointer(indataPtr), 16);
|
||||
ERROR_LOG(HLE, "PGD DRM not yet supported, sorry.");
|
||||
pspFileSystem.ReadFile(f->handle, pgd_header, 0x90);
|
||||
f->pgdInfo = pgd_open(pgd_header, 2, keybuf);
|
||||
if(f->pgdInfo==NULL){
|
||||
DEBUG_LOG(HLE, "Not a valid PGD file. Open as normal file.");
|
||||
f->npdrm = false;
|
||||
pspFileSystem.SeekFile(f->handle, (s32)0, FILEMOVE_BEGIN);
|
||||
}
|
||||
f->asyncResult = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
671
ext/libkirk/amctrl.c
Normal file
671
ext/libkirk/amctrl.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* amctrl.c -- Reverse engineering of amctrl.prx
|
||||
* written by tpu.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kirk_engine.h"
|
||||
#include "AES.h"
|
||||
#include "SHA1.h"
|
||||
#include "amctrl.h"
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static u8 loc_1CD4[16] = {0xE3, 0x50, 0xED, 0x1D, 0x91, 0x0A, 0x1F, 0xD0, 0x29, 0xBB, 0x1C, 0x3E, 0xF3, 0x40, 0x77, 0xFB};
|
||||
static u8 loc_1CE4[16] = {0x13, 0x5F, 0xA4, 0x7C, 0xAB, 0x39, 0x5B, 0xA4, 0x76, 0xB8, 0xCC, 0xA9, 0x8F, 0x3A, 0x04, 0x45};
|
||||
static u8 loc_1CF4[16] = {0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E};
|
||||
|
||||
static u8 kirk_buf[0x0814]; // 1DC0 1DD4
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static int kirk4(u8 *buf, int size, int type)
|
||||
{
|
||||
int retv;
|
||||
u32 *header = (u32*)buf;
|
||||
|
||||
header[0] = 4;
|
||||
header[1] = 0;
|
||||
header[2] = 0;
|
||||
header[3] = type;
|
||||
header[4] = size;
|
||||
|
||||
retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 4);
|
||||
|
||||
if(retv)
|
||||
return 0x80510311;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirk7(u8 *buf, int size, int type)
|
||||
{
|
||||
int retv;
|
||||
u32 *header = (u32*)buf;
|
||||
|
||||
header[0] = 5;
|
||||
header[1] = 0;
|
||||
header[2] = 0;
|
||||
header[3] = type;
|
||||
header[4] = size;
|
||||
|
||||
retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 7);
|
||||
if(retv)
|
||||
return 0x80510311;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirk5(u8 *buf, int size)
|
||||
{
|
||||
int retv;
|
||||
u32 *header = (u32*)buf;
|
||||
|
||||
header[0] = 4;
|
||||
header[1] = 0;
|
||||
header[2] = 0;
|
||||
header[3] = 0x0100;
|
||||
header[4] = size;
|
||||
|
||||
retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 5);
|
||||
if(retv)
|
||||
return 0x80510312;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirk8(u8 *buf, int size)
|
||||
{
|
||||
int retv;
|
||||
u32 *header = (u32*)buf;
|
||||
|
||||
header[0] = 5;
|
||||
header[1] = 0;
|
||||
header[2] = 0;
|
||||
header[3] = 0x0100;
|
||||
header[4] = size;
|
||||
|
||||
retv = sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size, 8);
|
||||
if(retv)
|
||||
return 0x80510312;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirk14(u8 *buf)
|
||||
{
|
||||
int retv;
|
||||
|
||||
retv = sceUtilsBufferCopyWithRange(buf, 0x14, 0, 0, 14);
|
||||
if(retv)
|
||||
return 0x80510315;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
// Called by sceDrmBBMacUpdate
|
||||
// encrypt_buf
|
||||
static int sub_158(u8 *buf, int size, u8 *key, int key_type)
|
||||
{
|
||||
int i, retv;
|
||||
|
||||
for(i=0; i<16; i++){
|
||||
buf[0x14+i] ^= key[i];
|
||||
}
|
||||
|
||||
retv = kirk4(buf, size, key_type);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
// copy last 16 bytes to keys
|
||||
memcpy(key, buf+size+4, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// type:
|
||||
// 2: use fuse id
|
||||
// 3: use fixed id
|
||||
int sceDrmBBMacInit(MAC_KEY *mkey, int type)
|
||||
{
|
||||
mkey->type = type;
|
||||
mkey->pad_size = 0;
|
||||
|
||||
memset(mkey->key, 0, 16);
|
||||
memset(mkey->pad, 0, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceDrmBBMacUpdate(MAC_KEY *mkey, u8 *buf, int size)
|
||||
{
|
||||
int retv = 0, ksize, p, type;
|
||||
u8 *kbuf;
|
||||
|
||||
if(mkey->pad_size>16){
|
||||
retv = 0x80510302;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if(mkey->pad_size+size<=16){
|
||||
memcpy(mkey->pad+mkey->pad_size, buf, size);
|
||||
mkey->pad_size += size;
|
||||
retv = 0;
|
||||
}else{
|
||||
kbuf = kirk_buf+0x14;
|
||||
// copy pad data first
|
||||
memcpy(kbuf, mkey->pad, mkey->pad_size);
|
||||
|
||||
p = mkey->pad_size;
|
||||
|
||||
mkey->pad_size += size;
|
||||
mkey->pad_size &= 0x0f;
|
||||
if(mkey->pad_size==0)
|
||||
mkey->pad_size = 16;
|
||||
|
||||
size -= mkey->pad_size;
|
||||
// save last data to pad buf
|
||||
memcpy(mkey->pad, buf+size, mkey->pad_size);
|
||||
|
||||
type = (mkey->type==2)? 0x3A : 0x38;
|
||||
|
||||
while(size){
|
||||
ksize = (size+p>=0x0800)? 0x0800 : size+p;
|
||||
memcpy(kbuf+p, buf, ksize-p);
|
||||
retv = sub_158(kirk_buf, ksize, mkey->key, type);
|
||||
if(retv)
|
||||
goto _exit;
|
||||
size -= (ksize-p);
|
||||
buf += ksize-p;
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_exit:
|
||||
return retv;
|
||||
|
||||
}
|
||||
|
||||
int sceDrmBBMacFinal(MAC_KEY *mkey, u8 *buf, u8 *vkey)
|
||||
{
|
||||
int i, retv, code;
|
||||
u8 *kbuf, tmp[16], tmp1[16];
|
||||
u32 t0, v0, v1;
|
||||
|
||||
if(mkey->pad_size>16)
|
||||
return 0x80510302;
|
||||
|
||||
code = (mkey->type==2)? 0x3A : 0x38;
|
||||
kbuf = kirk_buf+0x14;
|
||||
|
||||
memset(kbuf, 0, 16);
|
||||
retv = kirk4(kirk_buf, 16, code);
|
||||
if(retv)
|
||||
goto _exit;
|
||||
memcpy(tmp, kbuf, 16);
|
||||
|
||||
// left shift tmp 1 bit
|
||||
t0 = (tmp[0]&0x80)? 0x87 : 0;
|
||||
for(i=0; i<15; i++){
|
||||
v1 = tmp[i+0];
|
||||
v0 = tmp[i+1];
|
||||
v1 <<= 1;
|
||||
v0 >>= 7;
|
||||
v0 |= v1;
|
||||
tmp[i+0] = v0;
|
||||
}
|
||||
v0 = tmp[15];
|
||||
v0 <<= 1;
|
||||
v0 ^= t0;
|
||||
tmp[15] = v0;
|
||||
|
||||
// padding remain data
|
||||
if(mkey->pad_size<16){
|
||||
// left shift tmp 1 bit
|
||||
t0 = (tmp[0]&0x80)? 0x87 : 0;
|
||||
for(i=0; i<15; i++){
|
||||
v1 = tmp[i+0];
|
||||
v0 = tmp[i+1];
|
||||
v1 <<= 1;
|
||||
v0 >>= 7;
|
||||
v0 |= v1;
|
||||
tmp[i+0] = v0;
|
||||
}
|
||||
v0 = tmp[15];
|
||||
v0 <<= 1;
|
||||
v0 ^= t0;
|
||||
tmp[15] = v0;
|
||||
|
||||
mkey->pad[mkey->pad_size] = 0x80;
|
||||
if(mkey->pad_size+1<16)
|
||||
memset(mkey->pad+mkey->pad_size+1, 0, 16-mkey->pad_size-1);
|
||||
}
|
||||
|
||||
for(i=0; i<16; i++){
|
||||
mkey->pad[i] ^= tmp[i];
|
||||
}
|
||||
|
||||
memcpy(kbuf, mkey->pad, 16);
|
||||
memcpy(tmp1, mkey->key, 16);
|
||||
|
||||
retv = sub_158(kirk_buf, 0x10, tmp1, code);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
for(i=0; i<0x10; i++){
|
||||
tmp1[i] ^= loc_1CD4[i];
|
||||
}
|
||||
|
||||
if(mkey->type==2){
|
||||
memcpy(kbuf, tmp1, 16);
|
||||
|
||||
retv = kirk5(kirk_buf, 0x10);
|
||||
if(retv)
|
||||
goto _exit;
|
||||
|
||||
retv = kirk4(kirk_buf, 0x10, code);
|
||||
if(retv)
|
||||
goto _exit;
|
||||
|
||||
memcpy(tmp1, kbuf, 16);
|
||||
}
|
||||
|
||||
if(vkey){
|
||||
for(i=0; i<0x10; i++){
|
||||
tmp1[i] ^= vkey[i];
|
||||
}
|
||||
memcpy(kbuf, tmp1, 16);
|
||||
|
||||
retv = kirk4(kirk_buf, 0x10, code);
|
||||
if(retv)
|
||||
goto _exit;
|
||||
|
||||
memcpy(tmp1, kbuf, 16);
|
||||
}
|
||||
|
||||
memcpy(buf, tmp1, 16);
|
||||
|
||||
memset(mkey->key, 0, 16);
|
||||
memset(mkey->pad, 0, 16);
|
||||
|
||||
mkey->pad_size = 0;
|
||||
mkey->type = 0;
|
||||
retv = 0;
|
||||
|
||||
_exit:
|
||||
return retv;
|
||||
}
|
||||
|
||||
int sceDrmBBMacFinal2(MAC_KEY *mkey, u8 *out, u8 *vkey)
|
||||
{
|
||||
int i, retv, type;
|
||||
u8 *kbuf, tmp[16];
|
||||
|
||||
type = mkey->type;
|
||||
retv = sceDrmBBMacFinal(mkey, tmp, vkey);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
kbuf = kirk_buf+0x14;
|
||||
|
||||
// decrypt bbmac
|
||||
if(type==3){
|
||||
memcpy(kbuf, out, 0x10);
|
||||
kirk7(kirk_buf, 0x10, 0x63);
|
||||
}else{
|
||||
memcpy(kirk_buf, out, 0x10);
|
||||
}
|
||||
|
||||
retv = 0;
|
||||
for(i=0; i<0x10; i++){
|
||||
if(kirk_buf[i]!=tmp[i]){
|
||||
retv = 0x80510300;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static int sub_1F8(u8 *buf, int size, u8 *key, int key_type)
|
||||
{
|
||||
int i, retv;
|
||||
u8 tmp[16];
|
||||
|
||||
// copy last 16 bytes to tmp
|
||||
memcpy(tmp, buf+size+0x14-16, 16);
|
||||
|
||||
retv = kirk7(buf, size, key_type);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
for(i=0; i<16; i++){
|
||||
buf[i] ^= key[i];
|
||||
}
|
||||
|
||||
// copy last 16 bytes to keys
|
||||
memcpy(key, tmp, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int sub_428(u8 *kbuf, u8 *dbuf, int size, CIPHER_KEY *ckey)
|
||||
{
|
||||
int i, retv;
|
||||
u8 tmp1[16], tmp2[16];
|
||||
|
||||
memcpy(kbuf+0x14, ckey->key, 16);
|
||||
|
||||
for(i=0; i<16; i++){
|
||||
kbuf[0x14+i] ^= loc_1CF4[i];
|
||||
}
|
||||
|
||||
if(ckey->type==2)
|
||||
retv = kirk8(kbuf, 16);
|
||||
else
|
||||
retv = kirk7(kbuf, 16, 0x39);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
for(i=0; i<16; i++){
|
||||
kbuf[i] ^= loc_1CE4[i];
|
||||
}
|
||||
|
||||
memcpy(tmp2, kbuf, 0x10);
|
||||
|
||||
if(ckey->seed==1){
|
||||
memset(tmp1, 0, 0x10);
|
||||
}else{
|
||||
memcpy(tmp1, tmp2, 0x10);
|
||||
*(u32*)(tmp1+0x0c) = ckey->seed-1;
|
||||
}
|
||||
|
||||
for(i=0; i<size; i+=16){
|
||||
memcpy(kbuf+0x14+i, tmp2, 12);
|
||||
*(u32*)(kbuf+0x14+i+12) = ckey->seed;
|
||||
ckey->seed += 1;
|
||||
}
|
||||
|
||||
retv = sub_1F8(kbuf, size, tmp1, 0x63);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
for(i=0; i<size; i++){
|
||||
dbuf[i] ^= kbuf[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// type: 1 use fixed key
|
||||
// 2 use fuse id
|
||||
// mode: 1 for encrypt
|
||||
// 2 for decrypt
|
||||
int sceDrmBBCipherInit(CIPHER_KEY *ckey, int type, int mode, u8 *header_key, u8 *version_key, u32 seed)
|
||||
{
|
||||
int i, retv;
|
||||
u8 *kbuf;
|
||||
|
||||
kbuf = kirk_buf+0x14;
|
||||
ckey->type = type;
|
||||
if(mode==2){
|
||||
ckey->seed = seed+1;
|
||||
for(i=0; i<16; i++){
|
||||
ckey->key[i] = header_key[i];
|
||||
}
|
||||
if(version_key){
|
||||
for(i=0; i<16; i++){
|
||||
ckey->key[i] ^= version_key[i];
|
||||
}
|
||||
}
|
||||
retv = 0;
|
||||
}else if(mode==1){
|
||||
ckey->seed = 1;
|
||||
retv = kirk14(kirk_buf);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
memcpy(kbuf, kirk_buf, 0x10);
|
||||
memset(kbuf+0x0c, 0, 4);
|
||||
|
||||
if(ckey->type==2){
|
||||
for(i=0; i<16; i++){
|
||||
kbuf[i] ^= loc_1CE4[i];
|
||||
}
|
||||
retv = kirk5(kirk_buf, 0x10);
|
||||
for(i=0; i<16; i++){
|
||||
kbuf[i] ^= loc_1CF4[i];
|
||||
}
|
||||
}else{
|
||||
for(i=0; i<16; i++){
|
||||
kbuf[i] ^= loc_1CE4[i];
|
||||
}
|
||||
retv = kirk4(kirk_buf, 0x10, 0x39);
|
||||
for(i=0; i<16; i++){
|
||||
kbuf[i] ^= loc_1CF4[i];
|
||||
}
|
||||
}
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
memcpy(ckey->key, kbuf, 0x10);
|
||||
memcpy(header_key, kbuf, 0x10);
|
||||
|
||||
if(version_key){
|
||||
for(i=0; i<16; i++){
|
||||
ckey->key[i] ^= version_key[i];
|
||||
}
|
||||
}
|
||||
}else{
|
||||
retv = 0;
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
int sceDrmBBCipherUpdate(CIPHER_KEY *ckey, u8 *data, int size)
|
||||
{
|
||||
int p, retv, dsize;
|
||||
|
||||
retv = 0;
|
||||
p = 0;
|
||||
|
||||
while(size>0){
|
||||
dsize = (size>=0x0800)? 0x0800 : size;
|
||||
retv = sub_428(kirk_buf, data+p, dsize, ckey);
|
||||
if(retv)
|
||||
break;
|
||||
size -= dsize;
|
||||
p += dsize;
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
int sceDrmBBCipherFinal(CIPHER_KEY *ckey)
|
||||
{
|
||||
memset(ckey->key, 0, 16);
|
||||
ckey->type = 0;
|
||||
ckey->seed = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
// AES128 encrypt key
|
||||
static u8 key_357C[0x30] = {
|
||||
0x07,0x3D,0x9E,0x9D,0xA8,0xFD,0x3B,0x2F,0x63,0x18,0x93,0x2E,0xF8,0x57,0xA6,0x64,
|
||||
0x37,0x49,0xB7,0x01,0xCA,0xE2,0xE0,0xC5,0x44,0x2E,0x06,0xB6,0x1E,0xFF,0x84,0xF2,
|
||||
0x9D,0x31,0xB8,0x5A,0xC8,0xFA,0x16,0x80,0x73,0x60,0x18,0x82,0x18,0x77,0x91,0x9D,
|
||||
};
|
||||
|
||||
static u8 key_363C[16] = {
|
||||
0x38,0x20,0xD0,0x11,0x07,0xA3,0xFF,0x3E,0x0A,0x4C,0x20,0x85,0x39,0x10,0xB5,0x54,
|
||||
};
|
||||
|
||||
int sceNpDrmGetFixedKey(u8 *key, char *npstr, int type)
|
||||
{
|
||||
AES_ctx akey;
|
||||
MAC_KEY mkey;
|
||||
char strbuf[0x30];
|
||||
int retv;
|
||||
|
||||
if((type&0x01000000)==0)
|
||||
return 0x80550901;
|
||||
type &= 0x000000ff;
|
||||
|
||||
memset(strbuf, 0, 0x30);
|
||||
strncpy(strbuf, npstr, 0x30);
|
||||
|
||||
retv = sceDrmBBMacInit(&mkey, 1);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
retv = sceDrmBBMacUpdate(&mkey, (u8*)strbuf, 0x30);
|
||||
if(retv)
|
||||
return retv;
|
||||
|
||||
retv = sceDrmBBMacFinal(&mkey, key, key_363C);
|
||||
if(retv)
|
||||
return 0x80550902;
|
||||
|
||||
if(type==0)
|
||||
return 0;
|
||||
if(type>3)
|
||||
return 0x80550901;
|
||||
type = (type-1)*16;
|
||||
|
||||
AES_set_key(&akey, &key_357C[type], 128);
|
||||
AES_encrypt(&akey, key, key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
|
||||
static u8 dnas_key1A90[] = {0xED,0xE2,0x5D,0x2D,0xBB,0xF8,0x12,0xE5,0x3C,0x5C,0x59,0x32,0xFA,0xE3,0xE2,0x43};
|
||||
static u8 dnas_key1AA0[] = {0x27,0x74,0xFB,0xEB,0xA4,0xA0, 1,0xD7, 2,0x56,0x9E,0x33,0x8C,0x19,0x57,0x83};
|
||||
|
||||
PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey)
|
||||
{
|
||||
PGD_DESC *pgd;
|
||||
MAC_KEY mkey;
|
||||
CIPHER_KEY ckey;
|
||||
u8 *fkey;
|
||||
int retv;
|
||||
|
||||
//DEBUG_LOG(HLE, "Open PGD ...");
|
||||
|
||||
pgd = (PGD_DESC*)malloc(sizeof(PGD_DESC));
|
||||
memset(pgd, 0, sizeof(PGD_DESC));
|
||||
|
||||
pgd->key_index = *(u32*)(pgd_buf+4);
|
||||
pgd->drm_type = *(u32*)(pgd_buf+8);
|
||||
|
||||
if(pgd->drm_type==1){
|
||||
pgd->mac_type = 1;
|
||||
pgd_flag |= 4;
|
||||
if(pgd->key_index>1){
|
||||
pgd->mac_type = 3;
|
||||
pgd_flag |= 8;
|
||||
}
|
||||
pgd->cipher_type = 1;
|
||||
}else{
|
||||
pgd->mac_type = 2;
|
||||
pgd->cipher_type = 2;
|
||||
}
|
||||
pgd->open_flag = pgd_flag;
|
||||
|
||||
// select fixed key
|
||||
fkey = NULL;
|
||||
if(pgd_flag&2)
|
||||
fkey = dnas_key1A90;
|
||||
if(pgd_flag&1)
|
||||
fkey = dnas_key1AA0;
|
||||
if(fkey==NULL){
|
||||
//ERROR_LOG(HLE, "pgd_open: invalid pgd_flag! %08x\n", pgd_flag);
|
||||
free(pgd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// MAC_0x80 check
|
||||
sceDrmBBMacInit(&mkey, pgd->mac_type);
|
||||
sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x80);
|
||||
retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x80, fkey);
|
||||
if(retv){
|
||||
//ERROR_LOG(HLE, "pgd_open: MAC_80 check failed!: %08x(%d)\n", retv, retv);
|
||||
free(pgd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// MAC_0x70
|
||||
sceDrmBBMacInit(&mkey, pgd->mac_type);
|
||||
sceDrmBBMacUpdate(&mkey, pgd_buf+0x00, 0x70);
|
||||
if(pgd_vkey){
|
||||
// use given vkey
|
||||
retv = sceDrmBBMacFinal2(&mkey, pgd_buf+0x70, pgd_vkey);
|
||||
if(retv){
|
||||
//ERROR_LOG(HLE, "pgd_open: MAC_70 check failed!: %08x(%d)\n", retv, retv);
|
||||
free(pgd);
|
||||
return NULL;
|
||||
}else{
|
||||
memcpy(pgd->vkey, pgd_vkey, 16);
|
||||
}
|
||||
}else{
|
||||
//ERROR_LOG(HLE, "pgd_open: need key!\n");
|
||||
free(pgd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// decrypt PGD_DESC
|
||||
sceDrmBBCipherInit(&ckey, pgd->cipher_type, 2, pgd_buf+0x10, pgd->vkey, 0);
|
||||
sceDrmBBCipherUpdate(&ckey, pgd_buf+0x30, 0x30);
|
||||
sceDrmBBCipherFinal(&ckey);
|
||||
|
||||
pgd->data_size = *(u32*)(pgd_buf+0x44);
|
||||
pgd->block_size = *(u32*)(pgd_buf+0x48);
|
||||
pgd->data_offset = *(u32*)(pgd_buf+0x4c);
|
||||
memcpy(pgd->dkey, pgd_buf+0x30, 16);
|
||||
|
||||
pgd->align_size = (pgd->data_size+15)&~15;
|
||||
pgd->table_offset = pgd->data_offset+pgd->align_size;
|
||||
pgd->block_nr = (pgd->align_size+pgd->block_size-1)&~(pgd->block_size-1);
|
||||
pgd->block_nr = pgd->block_nr/pgd->block_size;
|
||||
|
||||
pgd->file_offset = 0;
|
||||
pgd->current_block = -1;
|
||||
pgd->block_buf = (u8*)malloc(pgd->block_size*2);
|
||||
|
||||
return pgd;
|
||||
}
|
||||
|
||||
int pgd_decrypt_block(PGD_DESC *pgd, int block)
|
||||
{
|
||||
CIPHER_KEY ckey;
|
||||
u32 block_offset;
|
||||
|
||||
block_offset = block*pgd->block_size;
|
||||
|
||||
// decrypt block data
|
||||
sceDrmBBCipherInit(&ckey, pgd->cipher_type, 2, pgd->dkey, pgd->vkey, block_offset>>4);
|
||||
sceDrmBBCipherUpdate(&ckey, pgd->block_buf, pgd->block_size);
|
||||
sceDrmBBCipherFinal(&ckey);
|
||||
|
||||
return pgd->block_size;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
64
ext/libkirk/amctrl.h
Normal file
64
ext/libkirk/amctrl.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef AMCTRL_H
|
||||
#define AMCTRL_H
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
u8 key[16];
|
||||
u8 pad[16];
|
||||
int pad_size;
|
||||
} MAC_KEY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 type;
|
||||
u32 seed;
|
||||
u8 key[16];
|
||||
} CIPHER_KEY;
|
||||
|
||||
typedef struct {
|
||||
u8 vkey[16]; // key to decrypt PGD header
|
||||
u8 dkey[16]; // key to decrypt PGD data
|
||||
|
||||
u32 open_flag;
|
||||
u32 key_index;
|
||||
u32 drm_type;
|
||||
u32 mac_type;
|
||||
u32 cipher_type;
|
||||
|
||||
u32 data_size;
|
||||
u32 align_size;
|
||||
u32 block_size;
|
||||
u32 block_nr;
|
||||
u32 data_offset;
|
||||
u32 table_offset;
|
||||
|
||||
u8 *block_buf;
|
||||
u32 current_block;
|
||||
u32 file_offset;
|
||||
}PGD_DESC;
|
||||
|
||||
|
||||
// type:
|
||||
// 2: use fuse id
|
||||
// 3: use fixed key. MAC need encrypt again
|
||||
int sceDrmBBMacInit(MAC_KEY *mkey, int type);
|
||||
int sceDrmBBMacUpdate(MAC_KEY *mkey, u8 *buf, int size);
|
||||
int sceDrmBBMacFinal(MAC_KEY *mkey, u8 *buf, u8 *vkey);
|
||||
int sceDrmBBMacFinal2(MAC_KEY *mkey, u8 *out, u8 *vkey);
|
||||
|
||||
// type: 1 use fixed key
|
||||
// 2 use fuse id
|
||||
// mode: 1 for encrypt
|
||||
// 2 for decrypt
|
||||
int sceDrmBBCipherInit(CIPHER_KEY *ckey, int type, int mode, u8 *header_key, u8 *version_key, u32 seed);
|
||||
int sceDrmBBCipherUpdate(CIPHER_KEY *ckey, u8 *data, int size);
|
||||
int sceDrmBBCipherFinal(CIPHER_KEY *ckey);
|
||||
|
||||
// npdrm.prx
|
||||
int sceNpDrmGetFixedKey(u8 *key, char *npstr, int type);
|
||||
|
||||
PGD_DESC *pgd_open(u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey);
|
||||
int pgd_decrypt_block(PGD_DESC *pgd, int block);
|
||||
|
||||
#endif
|
||||
|
|
@ -184,7 +184,7 @@ typedef struct
|
|||
0x0C: Mul1
|
||||
0x0D: Mul2
|
||||
0x0E: Random Number Gen
|
||||
0x0F: (absolutely no idea – could be KIRK initialization)
|
||||
0x0F: (absolutely no idea ?could be KIRK initialization)
|
||||
0x10: Signature Gen
|
||||
// Sig Checks
|
||||
0x11: Signature Check (checks for generated sigs)
|
||||
|
|
|
@ -116,6 +116,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AES.c" />
|
||||
<ClCompile Include="amctrl.c" />
|
||||
<ClCompile Include="bn.c" />
|
||||
<ClCompile Include="ec.c" />
|
||||
<ClCompile Include="kirk_engine.c" />
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
<ClCompile Include="SHA1.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="amctrl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AES.h">
|
||||
|
|
Loading…
Add table
Reference in a new issue