#include
#include
#include
#include
#include
#include "common.h"
#include "mappath.h"
#include "modulespatch.h"
#include "ps3mapi_core.h"
#include "make_rif.h"
#define ACCOUNTID 1
#define READ 0
#define XREGISTRY_FILE "/dev_flash2/etc/xRegistry.sys"
static uint8_t empty[0x10] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char RAP_KEY[] = { 0x86, 0x9F, 0x77, 0x45, 0xC1, 0x3F, 0xD8, 0x90, 0xCC, 0xF2, 0x91, 0x88, 0xE3, 0xCC, 0x3E, 0xDF };
unsigned char RAP_PBOX[] = { 0x0C, 0x03, 0x06, 0x04, 0x01, 0x0B, 0x0F, 0x08, 0x02, 0x07, 0x00, 0x05, 0x0A, 0x0E, 0x0D, 0x09 };
unsigned char RAP_E1[] = { 0xA9, 0x3E, 0x1F, 0xD6, 0x7C, 0x55, 0xA3, 0x29, 0xB7, 0x5F, 0xDD, 0xA6, 0x2A, 0x95, 0xC7, 0xA5 };
unsigned char RAP_E2[] = { 0x67, 0xD4, 0x5D, 0xA3, 0x29, 0x6D, 0x00, 0x6A, 0x4E, 0x7C, 0x53, 0x7B, 0xF5, 0x53, 0x8C, 0x74 };
uint32_t userID;
uint8_t skip_existing_rif = 0;
uint8_t account_id[0x10];
static int xreg_data(char *value)
{
int fd, result = -1;
uint16_t offset = 0;
uint64_t read, seek;
if(cellFsOpen(XREGISTRY_FILE, CELL_FS_O_RDWR, &fd, 0666, NULL, 0) != SUCCEEDED)
return result;
char *buffer = malloc(0x2A);
if(!buffer)
return result;
// Get offset
for(int i = 0; i < 0x10000; i++)
{
cellFsLseek(fd, i, SEEK_SET, &seek);
cellFsRead(fd, buffer, 0x31 + 1, &read);
// Found offset
if(strcmp(buffer, value) == 0)
{
offset = i - 0x15;
uint8_t *data = NULL;
// Search value from value table
for(int i = 0x10000; i < 0x15000; i++)
{
data = (uint8_t *) malloc(0x17);
if(!data)
{
free(buffer);
return result;
}
cellFsLseek(fd, i, SEEK_SET, &seek);
cellFsRead(fd, data, 0x17, &read);
// Found value
if (memcmp(data, &offset, 2) == 0 && data[4] == 0x00 && data[5] == 0x11 && data[6] == 0x02)
{
result = 0;
memcpy(&account_id, data + 7, 0x10);
if(memcmp(data + 7, empty, 0x10) != SUCCEEDED)
result = 1;
free(data);
free(buffer);
cellFsClose(fd);
return result;
}
free(data);
}
}
}
free(buffer);
cellFsClose(fd);
return result;
}
static void get_rif_key(unsigned char* rap, unsigned char* rif)
{
int i;
int round;
unsigned char key[0x10];
unsigned char iv[0x10];
memset(key, 0, 0x10);
memset(iv, 0, 0x10);
// Initial decrypt.
aescbccfb_dec(key, rap, 0x10, RAP_KEY, 0x80, iv);
memset(iv, 0, 0x10);
// rap2rifkey round.
for (round = 0; round < 5; ++round)
{
for (i = 0; i < 16; ++i)
{
int p = RAP_PBOX[i];
key[p] ^= RAP_E1[p];
}
for (i = 15; i >= 1; --i)
{
int p = RAP_PBOX[i];
int pp = RAP_PBOX[i - 1];
key[p] ^= key[pp];
}
int o = 0;
for (i = 0; i < 16; ++i)
{
int p = RAP_PBOX[i];
unsigned char kc = key[p] - o;
unsigned char ec2 = RAP_E2[p];
if (o != 1 || kc != 0xFF)
{
o = kc < ec2 ? 1 : 0;
key[p] = kc - ec2;
}
else if (kc == 0xFF)
key[p] = kc - ec2;
else
key[p] = kc;
}
}
memcpy(rif, key, 0x10);
}
static void read_act_dat_and_make_rif(uint8_t *rap, uint8_t *act_dat, const char *content_id, const char *rif_path)
{
int fd;
if(cellFsOpen(rif_path, CELL_FS_O_WRONLY | CELL_FS_O_CREAT | CELL_FS_O_TRUNC, &fd, 0666, NULL, 0) == SUCCEEDED)
{
uint8_t idps_const[0x10] = { 0x5E, 0x06, 0xE0, 0x4F, 0xD9, 0x4A, 0x71, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
uint8_t rif_key_const[0x10] = { 0xDA, 0x7D, 0x4B, 0x5E, 0x49, 0x9A, 0x4F, 0x53, 0xB1, 0xC1, 0xA1, 0x4A, 0x74, 0x84, 0x44, 0x3B };
uint8_t *rif = ALLOC_RIF_BUFFER;
uint8_t *key_index = rif + 0x40;
uint8_t *rif_key = rif + 0x50;
memset(rif, 0, 0x70);
get_rif_key(rap, rif_key); //convert rap to rifkey (klicensee)
uint8_t *iv = rif + 0x60;
aescbccfb_enc(idps_const, idps_const, 0x10, (void*)PS3MAPI_IDPS_2, IDPS_KEYBITS, iv);
uint8_t *act_dat_key = rap;
memcpy(act_dat_key, act_dat + 0x10, 0x10);
memset(iv, 0, 0x10);
aescbccfb_dec(act_dat_key, act_dat_key, 0x10, idps_const, IDPS_KEYBITS, iv);
memset(iv, 0, 0x10);
aescbccfb_enc(rif_key, rif_key, 0x10, act_dat_key, ACT_DAT_KEYBITS, iv);
memset(iv, 0, 0x10);
aescbccfb_enc(key_index, key_index, 0x10, rif_key_const, RIF_KEYBITS, iv);
const uint32_t version_number = 1;
const uint32_t license_type = 0x00010002;
const uint64_t timestamp = 0x000001619BF6DDCA;
const uint64_t expiration_time = 0;
memcpy(rif, &version_number, 4); // 0x00 version_number
memcpy(rif + 0x04, &license_type, 4); // 0x04 license_type
memcpy(rif + 0x08, act_dat + 0x8, 8); // 0x08 account_id
memcpy(rif + 0x10, content_id, 0x24); // 0x10 content_id
// 0x40 encrypted key index (Used for choosing act.dat key)
// 0x50 encrypted rif_key
memcpy(rif + 0x60, ×tamp, 8); // 0x60 timestamp
memcpy(rif + 0x68, &expiration_time, 8); // 0x68 expiration time
uint64_t size;
memset(rif + 0x70, 0x11, 0x28); // 0x70 ECDSA Signature
cellFsWrite(fd, rif, 0x98, &size);
cellFsClose(fd);
}
}
int create_act_dat(const char *userid)
{
int fd;
uint64_t size;
char full_path[120], exdata_dir[120];
CellFsStat stat;
//DPRINTF("Creating act.dat for userID %s...\n", userid);
uint8_t timedata[0x10] =
{
0x00, 0x00, 0x01, 0x2F, 0x3F, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const uint64_t header = 0x0000000100000002;
uint64_t accountID = (uint64_t)strtoull((const char*)account_id, NULL, 16);
accountID = SWAP64(accountID);
uint8_t *actdat = malloc(0x1038);
if(!actdat)
return 1;
memset(actdat, 0x11, 0x1038);
memcpy(actdat, &header, 8);
memcpy(actdat + 8, &accountID, 8);
memcpy(actdat + 0x870, timedata, 0x10);
sprintf(exdata_dir, "/dev_hdd0/home/%s/exdata", userid);
if(cellFsStat(exdata_dir, &stat) != SUCCEEDED)
cellFsMkdir(exdata_dir, 0777);
sprintf(full_path, "%s/act.dat", exdata_dir);
cellFsOpen(full_path, CELL_FS_O_WRONLY | CELL_FS_O_CREAT | CELL_FS_O_TRUNC, &fd, 0666, NULL, 0);
cellFsWrite(fd, actdat, 0x1038, &size);
cellFsClose(fd);
free(actdat);
return SUCCEEDED;
}
void make_rif(const char *path)
{
char buffer[120];
int path_len = strlen(path);
if(!strncmp(path, "/dev_hdd0/home/", 15) && !strcmp(path + path_len - 4, ".rif"))
{
int act_dat_found = 0;
int fd;
CellFsStat stat;
DPRINTF("open_path_hook: %s (looking for rap)\n", path);
char *content_id = ALLOC_CONTENT_ID;
memset(content_id, 0, 0x25);
strncpy(content_id, strrchr(path, '/') + 1, 0x24);
char *rap_path = ALLOC_PATH_BUFFER;
uint8_t is_ps2_classic = !strncmp(content_id, "2P0001-PS2U10000_00-0000111122223333", 0x24);
uint8_t is_psp_launcher = !strncmp(content_id, "UP0001-PSPC66820_00-0000111122223333", 0x24);
char userid[8];
strncpy(userid, path + 15, 8);
userid[8] = '\0';
if(!is_ps2_classic && !is_psp_launcher)
{
CellFsStat stat;
const char *ext = "rap";
// Support for rap and RAP extension (By aldostools)
for(uint8_t i = 0; i < 2; i++)
{
sprintf(rap_path, "/dev_usb000/exdata/%36s.%s", content_id, ext);
if(cellFsStat(rap_path, &stat) != SUCCEEDED)
rap_path[10] = '1'; //dev_usb001
if(cellFsStat(rap_path, &stat) != SUCCEEDED)
sprintf(rap_path, "/dev_hdd0/exdata/%36s.%s", content_id, ext);
if(cellFsStat(rap_path, &stat) != SUCCEEDED)
ext = "RAP";
else
break;
}
}
char rap_bin_dir[120];
sprintf(rap_bin_dir, "/dev_hdd0/home/%s/exdata/rap.bin", userid);
cellFsStat(rap_bin_dir, &stat);
if(is_ps2_classic || is_psp_launcher || cellFsOpen((!rap_mode) ? rap_path : rap_bin_dir, CELL_FS_O_RDONLY, &fd, 0666, NULL, 0) == SUCCEEDED)
{
uint64_t nread = 0;
uint8_t rap[0x10] = { 0xF5, 0xDE, 0xCA, 0xBB, 0x09, 0x88, 0x4F, 0xF4, 0x02, 0xD4, 0x12, 0x3C, 0x25, 0x01, 0x71, 0xD9 };
if(!is_ps2_classic && !is_psp_launcher)
{
if(!rap_mode)
{
DPRINTF("rap_path: %s output: %s\n", rap_path, path);
cellFsRead(fd, rap, 0x10, &nread);
}
else
{
// rap2bin-bin2rap by esc0rtd3w
// All credits goes to him
int MAGIC_NUMBER = 0xFAF0FAF0;
uint8_t buffer[0x50];
//DPRINTF("loading license from rap.bin...\n");
while(cellFsRead(fd, buffer, 0x50, &nread) == SUCCEEDED)
{
if((int)!nread)
break;
if(memcmp(buffer, &MAGIC_NUMBER, 4) == SUCCEEDED)
{
if(memcmp(buffer + 0x10, content_id, 0x24) == SUCCEEDED)
{
memcpy(rap, buffer + 0x40, 0x10);
DPRINTF("loaded license from rap.bin for %s\n", content_id);
break;
}
}
}
}
cellFsClose(fd);
}
// Search act.dat in home dirs
for(int i = 1; i < 100; i++)
{
sprintf(buffer, ACTDAT_PATH, i);
if(cellFsStat(buffer, &stat) == SUCCEEDED)
{
//DPRINTF("Found act.dat in %08d\n", i);
act_dat_found = 1;
break;
}
}
sprintf(buffer, ACCOUNTID_VALUE, userid);
if(!act_dat_found && xreg_data(buffer))
create_act_dat(userid);
act_dat_found = 0;
// Skip the creation of rif license if it already exists - By aldostool
if(skip_existing_rif && cellFsStat(path, &stat) == SUCCEEDED)
return;
char *act_path = ALLOC_PATH_BUFFER;
memset(act_path, 0, 0x50);
strncpy(act_path, path, strrchr(path, '/') - path);
strcpy(act_path + strlen(act_path), "/act.dat\0");
DPRINTF("act_path: %s content_id: %s\n", act_path, content_id);
if(cellFsOpen(act_path, CELL_FS_O_RDONLY, &fd, 0666, NULL, 0) == SUCCEEDED)
{
uint8_t *act_dat = ALLOC_ACT_DAT;
cellFsRead(fd, act_dat, 0x20, &nread); // size: 0x1038 but only first 0x20 are used to make rif
cellFsClose(fd);
if(nread == 0x20)
{
char *rif_path = ALLOC_PATH_BUFFER;
sprintf(rif_path, "/%s", path);
read_act_dat_and_make_rif(rap, act_dat, content_id, rif_path);
}
}
}
}
}