Save encryption. Load/Save encrypted/decrypted save

RE of Chnnlsv lib
Correct size bug in kirk
This commit is contained in:
Xele02 2013-01-29 00:11:02 +01:00
parent 630c025fd5
commit aa01751589
15 changed files with 1294 additions and 30 deletions

View File

@ -680,6 +680,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceAtrac.h Core/HLE/sceAtrac.h
Core/HLE/sceAudio.cpp Core/HLE/sceAudio.cpp
Core/HLE/sceAudio.h Core/HLE/sceAudio.h
Core/HLE/sceChnnlsv.cpp
Core/HLE/sceChnnlsv.h
Core/HLE/sceCtrl.cpp Core/HLE/sceCtrl.cpp
Core/HLE/sceCtrl.h Core/HLE/sceCtrl.h
Core/HLE/sceDisplay.cpp Core/HLE/sceDisplay.cpp

View File

@ -87,6 +87,7 @@ void CConfig::Load(const char *iniFileName)
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam"); IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
pspConfig->Get("Language", &ilanguage, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH); pspConfig->Get("Language", &ilanguage, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH);
pspConfig->Get("TimeFormat", &itimeformat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR); pspConfig->Get("TimeFormat", &itimeformat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR);
pspConfig->Get("EncryptSave", &bEncryptSave, true);
// Ephemeral settings // Ephemeral settings
bDrawWireframe = false; bDrawWireframe = false;
@ -136,6 +137,7 @@ void CConfig::Save()
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam"); IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
pspConfig->Set("Language", ilanguage); pspConfig->Set("Language", ilanguage);
pspConfig->Set("TimeFormat", itimeformat); pspConfig->Set("TimeFormat", itimeformat);
pspConfig->Set("EncryptSave", bEncryptSave);
if (!iniFile.Save(iniFilename_.c_str())) { if (!iniFile.Save(iniFilename_.c_str())) {
ERROR_LOG(LOADER, "Error saving config - can't write ini %s", iniFilename_.c_str()); ERROR_LOG(LOADER, "Error saving config - can't write ini %s", iniFilename_.c_str());

View File

@ -74,6 +74,7 @@ public:
// SystemParam // SystemParam
int ilanguage; int ilanguage;
int itimeformat; int itimeformat;
bool bEncryptSave;
std::string currentDirectory; std::string currentDirectory;
std::string memCardDirectory; std::string memCardDirectory;

View File

@ -142,6 +142,7 @@
<ClCompile Include="HLE\HLETables.cpp" /> <ClCompile Include="HLE\HLETables.cpp" />
<ClCompile Include="HLE\sceAtrac.cpp" /> <ClCompile Include="HLE\sceAtrac.cpp" />
<ClCompile Include="HLE\sceAudio.cpp" /> <ClCompile Include="HLE\sceAudio.cpp" />
<ClCompile Include="HLE\sceChnnlsv.cpp" />
<ClCompile Include="HLE\sceCtrl.cpp" /> <ClCompile Include="HLE\sceCtrl.cpp" />
<ClCompile Include="HLE\sceDisplay.cpp" /> <ClCompile Include="HLE\sceDisplay.cpp" />
<ClCompile Include="HLE\sceDmac.cpp" /> <ClCompile Include="HLE\sceDmac.cpp" />
@ -311,6 +312,7 @@
<ClInclude Include="HLE\sceAtrac.h" /> <ClInclude Include="HLE\sceAtrac.h" />
<ClInclude Include="HLE\sceAudio.h" /> <ClInclude Include="HLE\sceAudio.h" />
<ClInclude Include="HLE\sceCtrl.h" /> <ClInclude Include="HLE\sceCtrl.h" />
<ClInclude Include="HLE\sceChnnlsv.h" />
<ClInclude Include="HLE\sceDisplay.h" /> <ClInclude Include="HLE\sceDisplay.h" />
<ClInclude Include="HLE\sceDmac.h" /> <ClInclude Include="HLE\sceDmac.h" />
<ClInclude Include="HLE\sceFont.h" /> <ClInclude Include="HLE\sceFont.h" />

View File

@ -89,6 +89,7 @@ int PSPSaveDialog::Init(int paramAddr)
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
case SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE:
display = DS_NONE; display = DS_NONE;
break; break;
case SCE_UTILITY_SAVEDATA_TYPE_DELETE: // This run on PSP display a list of all save on the PSP. Weird. (Not really, it's to let you free up space) case SCE_UTILITY_SAVEDATA_TYPE_DELETE: // This run on PSP display a list of all save on the PSP. Weird. (Not really, it's to let you free up space)
@ -736,6 +737,17 @@ int PSPSaveDialog::Update()
} }
status = SCE_UTILITY_STATUS_FINISHED; status = SCE_UTILITY_STATUS_FINISHED;
break; break;
case SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE:
if(param.Delete(param.GetPspParam()), param.GetSelectedSave())
{
param.GetPspParam()->result = 0;
}
else
{
param.GetPspParam()->result = SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA;
}
status = SCE_UTILITY_STATUS_FINISHED;
break;
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE: case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
if(param.Save(param.GetPspParam(),param.GetSelectedSave())) if(param.Save(param.GetPspParam(),param.GetSelectedSave()))

View File

@ -19,6 +19,7 @@
#include "image/png_load.h" #include "image/png_load.h"
#include "../HLE/sceKernelMemory.h" #include "../HLE/sceKernelMemory.h"
#include "../ELF/ParamSFO.h" #include "../ELF/ParamSFO.h"
#include "../HLE/sceChnnlsv.h"
#include "Core/HW/MemoryStick.h" #include "Core/HW/MemoryStick.h"
#include "PSPSaveDialog.h" #include "PSPSaveDialog.h"
@ -45,13 +46,19 @@ namespace
str[strLength - 1] = 0; str[strLength - 1] = 0;
} }
bool ReadPSPFile(std::string filename, u8 *data, s64 dataSize, s64 *readSize) bool ReadPSPFile(std::string filename, u8 **data, s64 dataSize, s64 *readSize)
{ {
u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ);
if (handle == 0) if (handle == 0)
return false; return false;
size_t result = pspFileSystem.ReadFile(handle, data, dataSize); if(dataSize == -1)
{
dataSize = pspFileSystem.GetFileInfo(filename).size;
*data = new u8[dataSize];
}
size_t result = pspFileSystem.ReadFile(handle, *data, dataSize);
pspFileSystem.CloseFile(handle); pspFileSystem.CloseFile(handle);
if(readSize) if(readSize)
*readSize = result; *readSize = result;
@ -110,6 +117,28 @@ namespace
return false; return false;
} }
int align16(int address)
{
return ((address + 0xF) >> 4) << 4;
}
int GetSDKMainVersion(int sdkVersion)
{
if(sdkVersion > 0x307FFFF)
return 6;
if(sdkVersion > 0x300FFFF)
return 5;
if(sdkVersion > 0x206FFFF)
return 4;
if(sdkVersion > 0x205FFFF)
return 3;
if(sdkVersion >= 0x2000000)
return 2;
if(sdkVersion >= 0x1000000)
return 1;
return 0;
};
} }
SavedataParam::SavedataParam() SavedataParam::SavedataParam()
@ -222,22 +251,36 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
if (!pspFileSystem.GetFileInfo(dirPath).exists) if (!pspFileSystem.GetFileInfo(dirPath).exists)
pspFileSystem.MkDir(dirPath); pspFileSystem.MkDir(dirPath);
if(param->dataBuf != 0) // Can launch save without save data in mode 13 u8* cryptedData = 0;
int cryptedSize = 0;
u8 cryptedHash[16];
memset(cryptedHash,0,0x16);
// Encrypt save.
if(param->dataBuf != 0 && g_Config.bEncryptSave)
{ {
std::string filePath = dirPath+"/"+GetFileName(param); cryptedSize = param->dataSize;
SceSize saveSize = param->dataSize; if(cryptedSize == 0 || cryptedSize > param->dataBufSize)
if(saveSize == 0 || saveSize > param->dataBufSize) cryptedSize = param->dataBufSize; // fallback, should never use this
saveSize = param->dataBufSize; // fallback, should never use this u8* data_ = (u8*)Memory::GetPointer(param->dataBuf);
INFO_LOG(HLE,"Saving file with size %u in %s",saveSize,filePath.c_str());
u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf);
// copy back save name in request int aligned_len = align16(cryptedSize);
strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20); cryptedData = new u8[aligned_len + 0x10];
memcpy(cryptedData, data_, cryptedSize);
if (!WritePSPFile(filePath, data_, saveSize)) int decryptMode = 1;
if(param->key[0] != 0)
{ {
ERROR_LOG(HLE,"Error writing file %s",filePath.c_str()); decryptMode = (GetSDKMainVersion(sceKernelGetCompiledSdkVersion()) >= 4 ? 5 : 3);
return false; }
if(EncryptData(decryptMode, cryptedData, &cryptedSize, &aligned_len, cryptedHash, ((param->key[0] != 0)?param->key:0)) == 0)
{
}
else
{
ERROR_LOG(HLE,"Save encryption failed. This save won't work on real PSP");
delete[] cryptedData;
cryptedData = 0;
} }
} }
@ -249,7 +292,7 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
{ {
u8 *sfoData = new u8[(size_t)sfoInfo.size]; u8 *sfoData = new u8[(size_t)sfoInfo.size];
size_t sfoSize = (size_t)sfoInfo.size; size_t sfoSize = (size_t)sfoInfo.size;
if(ReadPSPFile(sfopath,sfoData,sfoSize, NULL)) if(ReadPSPFile(sfopath,&sfoData,sfoSize, NULL))
{ {
sfoFile.ReadSFO(sfoData,sfoSize); sfoFile.ReadSFO(sfoData,sfoSize);
delete[] sfoData; delete[] sfoData;
@ -285,18 +328,19 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
if(fName[0] == 0) if(fName[0] == 0)
break; // End of list break; // End of list
if(strncmp(fName,GetFileName(param).c_str(),20) == 0) if(strncmp(fName,GetFileName(param).c_str(),20) == 0)
break; // File already in SFO break;
fName += FILE_LIST_ITEM_SIZE; fName += FILE_LIST_ITEM_SIZE;
} }
if (fName + 20 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE) if (fName + 13 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE)
snprintf(fName, 20, "%s",GetFileName(param).c_str()); snprintf(fName, 13, "%s",GetFileName(param).c_str());
if (fName + 13 + 16 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE)
memcpy(fName+13, cryptedHash, 16);
} }
sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, FILE_LIST_TOTAL_SIZE, FILE_LIST_TOTAL_SIZE); sfoFile.SetValue("SAVEDATA_FILE_LIST", tmpData, FILE_LIST_TOTAL_SIZE, FILE_LIST_TOTAL_SIZE);
delete[] tmpData; delete[] tmpData;
// No crypted save, so fill with 0 // Init param with 0. This will be used to detect crypted save or not on loading
tmpData = new u8[128]; tmpData = new u8[128];
memset(tmpData, 0, 128); memset(tmpData, 0, 128);
sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128); sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128);
@ -305,9 +349,54 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
u8 *sfoData; u8 *sfoData;
size_t sfoSize; size_t sfoSize;
sfoFile.WriteSFO(&sfoData,&sfoSize); sfoFile.WriteSFO(&sfoData,&sfoSize);
// Calc SFO hash for PSP.
if(cryptedData != 0)
{
int offset = sfoFile.GetDataOffset(sfoData,"SAVEDATA_PARAMS");
if(offset >= 0)
UpdateHash(sfoData, sfoSize, offset, (param->key[0]?3:1));
}
WritePSPFile(sfopath, sfoData, (SceSize)sfoSize); WritePSPFile(sfopath, sfoData, (SceSize)sfoSize);
delete[] sfoData; delete[] sfoData;
if(param->dataBuf != 0) // Can launch save without save data in mode 13
{
std::string filePath = dirPath+"/"+GetFileName(param);
u8* data_ = 0;
SceSize saveSize = 0;
if(cryptedData == 0) // Save decrypted data
{
saveSize = param->dataSize;
if(saveSize == 0 || saveSize > param->dataBufSize)
saveSize = param->dataBufSize; // fallback, should never use this
data_ = (u8*)Memory::GetPointer(param->dataBuf);
}
else
{
data_ = cryptedData;
saveSize = cryptedSize;
}
INFO_LOG(HLE,"Saving file with size %u in %s",saveSize,filePath.c_str());
// copy back save name in request
strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20);
if (!WritePSPFile(filePath, data_, saveSize))
{
ERROR_LOG(HLE,"Error writing file %s",filePath.c_str());
if(cryptedData != 0)
{
delete[] cryptedData;
}
return false;
}
delete[] cryptedData;
}
// SAVE ICON0 // SAVE ICON0
if (param->icon0FileData.buf) if (param->icon0FileData.buf)
{ {
@ -375,12 +464,14 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId)
std::string filePath = dirPath+"/"+GetFileName(param); std::string filePath = dirPath+"/"+GetFileName(param);
s64 readSize; s64 readSize;
INFO_LOG(HLE,"Loading file with size %u in %s",param->dataBufSize,filePath.c_str()); INFO_LOG(HLE,"Loading file with size %u in %s",param->dataBufSize,filePath.c_str());
if (!ReadPSPFile(filePath, data_, param->dataBufSize, &readSize)) u8* saveData = 0;
int saveSize = -1;
if (!ReadPSPFile(filePath, &saveData, saveSize, &readSize))
{ {
ERROR_LOG(HLE,"Error reading file %s",filePath.c_str()); ERROR_LOG(HLE,"Error reading file %s",filePath.c_str());
return false; return false;
} }
param->dataSize = (SceSize)readSize; saveSize = readSize;
// copy back save name in request // copy back save name in request
strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20); strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20);
@ -392,7 +483,7 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId)
{ {
u8 *sfoData = new u8[(size_t)sfoInfo.size]; u8 *sfoData = new u8[(size_t)sfoInfo.size];
size_t sfoSize = (size_t)sfoInfo.size; size_t sfoSize = (size_t)sfoInfo.size;
if(ReadPSPFile(sfopath,sfoData,sfoSize, NULL)) if(ReadPSPFile(sfopath,&sfoData,sfoSize, NULL))
{ {
sfoFile.ReadSFO(sfoData,sfoSize); sfoFile.ReadSFO(sfoData,sfoSize);
@ -407,9 +498,210 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId)
// Don't know what it is, but PSP always respond this and this unlock some game // Don't know what it is, but PSP always respond this and this unlock some game
param->bind = 1021; param->bind = 1021;
bool isCrypted = IsSaveEncrypted(param,saveId);
bool saveDone = false;
if(isCrypted)// Try to decrypt
{
int align_len = align16(saveSize);
u8* data_base = new u8[align_len];
u8* cryptKey = new u8[0x10];
memset(cryptKey,0,0x10);
if(param->key[0] != 0)
{
memcpy(cryptKey, param->key, 0x10);
}
memset(data_base + saveSize, 0, align_len - saveSize);
memcpy(data_base, saveData, saveSize);
int decryptMode = 1;
if(param->key[0] != 0)
{
decryptMode = (GetSDKMainVersion(sceKernelGetCompiledSdkVersion()) >= 4 ? 5 : 3);
}
if(DecryptSave(decryptMode, data_base, &saveSize, &align_len, ((param->key[0] != 0)?cryptKey:0)) == 0)
{
memcpy(data_, data_base, saveSize);
saveDone = true;
}
delete[] data_base;
delete[] cryptKey;
}
if(!saveDone) // not crypted or decrypt fail
{
memcpy(data_, saveData, saveSize);
}
param->dataSize = (SceSize)saveSize;
delete[] saveData;
return true; return true;
} }
int SavedataParam::EncryptData(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *hash,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
pspChnnlsvContext2 ctx2;
/* Make room for the IV in front of the data. */
memmove(data + 0x10, data, *alignedLen);
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(&ctx2, 0, sizeof(pspChnnlsvContext2));
memset(hash, 0, 0x10);
memset(data, 0, 0x10);
/* Build the 0x10-byte IV and setup encryption */
if (sceSdCreateList_(ctx2, mode, 1, data, cryptkey) < 0)
return -1;
if (sceSdSetIndex_(ctx1, mode) < 0)
return -2;
if (sceSdRemoveValue_(ctx1, data, 0x10) < 0)
return -3;
if (sceSdSetMember_(ctx2, data + 0x10, *alignedLen) < 0)
return -4;
/* Clear any extra bytes left from the previous steps */
memset(data + 0x10 + *dataLen, 0, *alignedLen - *dataLen);
/* Encrypt the data */
if (sceSdRemoveValue_(ctx1, data + 0x10, *alignedLen) < 0)
return -5;
/* Verify encryption */
if (sceChnnlsv_21BE78B4_(ctx2) < 0)
return -6;
/* Build the file hash from this PSP */
if (sceSdGetLastIndex_(ctx1, hash, cryptkey) < 0)
return -7;
/* Adjust sizes to account for IV */
*alignedLen += 0x10;
*dataLen += 0x10;
/* All done */
return 0;
}
int SavedataParam::DecryptSave(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
pspChnnlsvContext2 ctx2;
/* Need a 16-byte IV plus some data */
if (*alignedLen <= 0x10)
return -1;
*dataLen -= 0x10;
*alignedLen -= 0x10;
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(&ctx2, 0, sizeof(pspChnnlsvContext2));
/* Perform the magic */
if (sceSdSetIndex_(ctx1, mode) < 0)
return -2;
if (sceSdCreateList_(ctx2, mode, 2, data, cryptkey) < 0)
return -3;
if (sceSdRemoveValue_(ctx1, data, 0x10) < 0)
return -4;
if (sceSdRemoveValue_(ctx1, data + 0x10, *alignedLen) < 0)
return -5;
if (sceSdSetMember_(ctx2, data + 0x10, *alignedLen) < 0)
return -6;
/* Verify that it decrypted correctly */
if (sceChnnlsv_21BE78B4_(ctx2) < 0)
return -7;
/* The decrypted data starts at data + 0x10, so shift it back. */
memmove(data, data + 0x10, *dataLen);
return 0;
}
int SavedataParam::UpdateHash(u8* sfoData, int sfoSize, int sfoDataParamsOffset, int encryptmode)
{
int alignedLen = align16(sfoSize);
memset(sfoData+sfoDataParamsOffset, 0, 128);
u8 filehash[16];
int ret = 0;
/* Compute 11D0 hash over entire file */
if ((ret = BuildHash(filehash, sfoData, sfoSize, alignedLen, (encryptmode & 2) ? 4 : 2, NULL)) < 0)
{ // Not sure about "2"
return ret - 400;
}
/* Copy 11D0 hash to param.sfo and set flag indicating it's there */
memcpy(sfoData+sfoDataParamsOffset + 0x20, filehash, 0x10);
*(sfoData+sfoDataParamsOffset) |= 0x01;
/* If new encryption mode, compute and insert the 1220 hash. */
if (encryptmode & 2)
{
/* Enable the hash bit first */
*(sfoData+sfoDataParamsOffset) |= 0x20;
if ((ret = BuildHash(filehash, sfoData, sfoSize, alignedLen, 3, 0)) < 0)
{
return ret - 500;
}
memcpy(sfoData+sfoDataParamsOffset + 0x70, filehash, 0x10);
}
/* Compute and insert the 11C0 hash. */
if ((ret = BuildHash(filehash, sfoData, sfoSize, alignedLen, 1, 0)) < 0)
{
return ret - 600;
}
memcpy(sfoData+sfoDataParamsOffset + 0x10, filehash, 0x10);
/* All done. */
return 0;
}
int SavedataParam::BuildHash(unsigned char *output,
unsigned char *data,
unsigned int len,
unsigned int alignedLen,
int mode,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(output, 0, 0x10);
memset(data + len, 0, alignedLen - len);
/* Perform the magic */
if (sceSdSetIndex_(ctx1, mode & 0xFF) < 0)
return -1;
if (sceSdRemoveValue_(ctx1, data, alignedLen) < 0)
return -2;
if (sceSdGetLastIndex_(ctx1, output, cryptkey) < 0)
{
// Got here since Kirk CMD5 missing, return random value;
memset(output,0x1,0x10);
return 0;
}
/* All done. */
return 0;
}
std::string SavedataParam::GetSpaceText(int size) std::string SavedataParam::GetSpaceText(int size)
{ {
char text[50]; char text[50];
@ -464,7 +756,7 @@ bool SavedataParam::GetSizes(SceUtilitySavedataParam *param)
PSPFileInfo finfo = pspFileSystem.GetFileInfo(path); PSPFileInfo finfo = pspFileSystem.GetFileInfo(path);
if(finfo.exists) if(finfo.exists)
{ {
// TODO : fill correctly with the total save size // TODO : fill correctly with the total save size, be aware of crypted file size
Memory::Write_U32(1,param->msData+36); //1 Memory::Write_U32(1,param->msData+36); //1
Memory::Write_U32(0x20,param->msData+40); // 0x20 Memory::Write_U32(0x20,param->msData+40); // 0x20
Memory::Write_U8(0,param->msData+44); // "32 KB" // 8 u8 Memory::Write_U8(0,param->msData+44); // "32 KB" // 8 u8
@ -585,8 +877,12 @@ bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param)
PSPFileInfo info = pspFileSystem.GetFileInfo(filePath); PSPFileInfo info = pspFileSystem.GetFileInfo(filePath);
if (info.exists) if (info.exists)
{ {
bool isCrypted = IsSaveEncrypted(param,0);
Memory::Write_U32(0x21FF, curFileInfoAddr+0); Memory::Write_U32(0x21FF, curFileInfoAddr+0);
Memory::Write_U64(info.size, curFileInfoAddr+8); if(isCrypted) // Crypted save are 16 bytes bigger
Memory::Write_U64(info.size - 0x10, curFileInfoAddr+8);
else
Memory::Write_U64(info.size, curFileInfoAddr+8);
Memory::Write_U64(0,curFileInfoAddr + 16); // TODO ctime Memory::Write_U64(0,curFileInfoAddr + 16); // TODO ctime
Memory::Write_U64(0,curFileInfoAddr + 24); // TODO unknow Memory::Write_U64(0,curFileInfoAddr + 24); // TODO unknow
Memory::Write_U64(0,curFileInfoAddr + 32); // TODO atime Memory::Write_U64(0,curFileInfoAddr + 32); // TODO atime
@ -797,7 +1093,7 @@ void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName
if (info2.exists) if (info2.exists)
{ {
u8 *textureDataPNG = new u8[(size_t)info2.size]; u8 *textureDataPNG = new u8[(size_t)info2.size];
ReadPSPFile(fileDataPath2, textureDataPNG, info2.size, NULL); ReadPSPFile(fileDataPath2, &textureDataPNG, info2.size, NULL);
CreatePNGIcon(textureDataPNG, (int)info2.size, saveDataList[idx]); CreatePNGIcon(textureDataPNG, (int)info2.size, saveDataList[idx]);
delete[] textureDataPNG; delete[] textureDataPNG;
} }
@ -808,7 +1104,7 @@ void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName
if (info2.exists) if (info2.exists)
{ {
u8 *sfoParam = new u8[(size_t)info2.size]; u8 *sfoParam = new u8[(size_t)info2.size];
ReadPSPFile(fileDataPath2, sfoParam, info2.size, NULL); ReadPSPFile(fileDataPath2, &sfoParam, info2.size, NULL);
ParamSFOData sfoFile; ParamSFOData sfoFile;
if (sfoFile.ReadSFO(sfoParam,(size_t)info2.size)) if (sfoFile.ReadSFO(sfoParam,(size_t)info2.size))
{ {
@ -864,3 +1160,38 @@ void SavedataParam::DoState(PointerWrap &p)
p.DoArray(saveDataList, saveDataListCount); p.DoArray(saveDataList, saveDataListCount);
p.DoMarker("SavedataParam"); p.DoMarker("SavedataParam");
} }
bool SavedataParam::IsSaveEncrypted(SceUtilitySavedataParam* param, int saveId)
{
bool isCrypted = false;
ParamSFOData sfoFile;
std::string dirPath = GetSaveFilePath(param, saveId);
std::string sfopath = dirPath+"/"+sfoName;
PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath);
if(sfoInfo.exists) // Read sfo
{
u8 *sfoData = new u8[(size_t)sfoInfo.size];
size_t sfoSize = (size_t)sfoInfo.size;
if(ReadPSPFile(sfopath,&sfoData,sfoSize, NULL))
{
sfoFile.ReadSFO(sfoData,sfoSize);
// save created in PPSSPP and not encrypted has '0' in SAVEDATA_PARAMS
u32 tmpDataSize = 0;
u8* tmpDataOrig = sfoFile.GetValueData("SAVEDATA_PARAMS", &tmpDataSize);
for(int i = 0; i < tmpDataSize; i++)
{
if(tmpDataOrig[i] != 0)
{
isCrypted = true;
break;
}
}
}
delete[] sfoData;
}
return isCrypted;
}

View File

@ -31,6 +31,7 @@ enum SceUtilitySavedataType
SCE_UTILITY_SAVEDATA_TYPE_DELETE = 6, SCE_UTILITY_SAVEDATA_TYPE_DELETE = 6,
SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 7, SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 7,
SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8, SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8,
SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE = 10,
SCE_UTILITY_SAVEDATA_TYPE_LIST = 11, SCE_UTILITY_SAVEDATA_TYPE_LIST = 11,
SCE_UTILITY_SAVEDATA_TYPE_FILES = 12, SCE_UTILITY_SAVEDATA_TYPE_FILES = 12,
SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE = 13, SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE = 13,
@ -107,7 +108,7 @@ struct SceUtilitySavedataParam
u32 msData; u32 msData;
u32 utilityData; u32 utilityData;
char key[16]; u8 key[16];
int secureVersion; int secureVersion;
int multiStatus; int multiStatus;
@ -157,6 +158,7 @@ public:
bool GetList(SceUtilitySavedataParam* param); bool GetList(SceUtilitySavedataParam* param);
bool GetFilesList(SceUtilitySavedataParam* param); bool GetFilesList(SceUtilitySavedataParam* param);
bool GetSize(SceUtilitySavedataParam* param); bool GetSize(SceUtilitySavedataParam* param);
bool IsSaveEncrypted(SceUtilitySavedataParam* param, int saveId);
std::string GetGameName(SceUtilitySavedataParam* param); std::string GetGameName(SceUtilitySavedataParam* param);
std::string GetSaveName(SceUtilitySavedataParam* param); std::string GetSaveName(SceUtilitySavedataParam* param);
@ -181,6 +183,11 @@ private:
bool CreatePNGIcon(u8* pngData, int pngSize, SaveFileInfo& info); bool CreatePNGIcon(u8* pngData, int pngSize, SaveFileInfo& info);
void SetFileInfo(int idx, PSPFileInfo &info, std::string saveName); void SetFileInfo(int idx, PSPFileInfo &info, std::string saveName);
int DecryptSave(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, unsigned char *cryptkey);
int EncryptData(unsigned int mode, unsigned char *data, int *dataLen, int *alignedLen, unsigned char *hash, unsigned char *cryptkey);
int UpdateHash(u8* sfoData, int sfoSize, int sfoDataParamsOffset, int encryptmode);
int BuildHash(unsigned char *output, unsigned char *data, unsigned int len, unsigned int alignedLen, int mode, unsigned char *cryptkey);
SceUtilitySavedataParam* pspParam; SceUtilitySavedataParam* pspParam;
int selectedSave; int selectedSave;
SaveFileInfo* saveDataList; SaveFileInfo* saveDataList;

View File

@ -133,6 +133,31 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size)
return true; return true;
} }
int ParamSFOData::GetDataOffset(const u8 *paramsfo, std::string dataName)
{
const Header *header = (const Header *)paramsfo;
if (header->magic != 0x46535000)
return -1;
if (header->version != 0x00000101)
WARN_LOG(LOADER, "Unexpected SFO header version: %08x", header->version);
const IndexTable *indexTables = (const IndexTable *)(paramsfo + sizeof(Header));
const u8 *key_start = paramsfo + header->key_table_start;
int data_start = header->data_table_start;
for (u32 i = 0; i < header->index_table_entries; i++)
{
const char *key = (const char *)(key_start + indexTables[i].key_table_offset);
if(std::string(key) == dataName)
{
return data_start + indexTables[i].data_table_offset;
}
}
return -1;
}
bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size) bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
{ {
size_t total_size = 0; size_t total_size = 0;

View File

@ -34,6 +34,8 @@ public:
bool ReadSFO(const u8 *paramsfo, size_t size); bool ReadSFO(const u8 *paramsfo, size_t size);
bool WriteSFO(u8 **paramsfo, size_t *size); bool WriteSFO(u8 **paramsfo, size_t *size);
int GetDataOffset(const u8 *paramsfo, std::string dataName);
private: private:
enum ValueType enum ValueType
{ {

View File

@ -255,6 +255,11 @@ template<u32 func(u32, int, int)> void WrapU_UII() {
RETURN(retval); RETURN(retval);
} }
template<int func(u32, int, int, u32, u32)> void WrapI_UIIUU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
template<void func(u32, int, int, int)> void WrapV_UIII() { template<void func(u32, int, int, int)> void WrapV_UIII() {
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
} }

View File

@ -53,6 +53,7 @@
#include "sceParseHttp.h" #include "sceParseHttp.h"
#include "sceVaudio.h" #include "sceVaudio.h"
#include "sceUsb.h" #include "sceUsb.h"
#include "sceChnnlsv.h"
#define N(s) s #define N(s) s
@ -244,6 +245,7 @@ void RegisterAllModules() {
Register_sceParseHttp(); Register_sceParseHttp();
Register_sceVaudio(); Register_sceVaudio();
Register_sceUsb(); Register_sceUsb();
Register_sceChnnlsv();
for (int i = 0; i < numModules; i++) for (int i = 0; i < numModules; i++)
{ {

827
Core/HLE/sceChnnlsv.cpp Normal file
View File

@ -0,0 +1,827 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "HLE.h"
#include "sceChnnlsv.h"
#include "sceKernel.h"
extern "C"
{
#include "ext/libkirk/kirk_engine.h"
}
u8 dataBuf[2048+20];
u8* dataBuf2 = dataBuf + 20;
u8 hash198C[16] = {0xFA, 0xAA, 0x50, 0xEC, 0x2F, 0xDE, 0x54, 0x93, 0xAD, 0x14, 0xB2, 0xCE, 0xA5, 0x30, 0x05, 0xDF };
u8 hash19BC[16] = {0xCB, 0x15, 0xF4, 0x07, 0xF9, 0x6A, 0x52, 0x3C, 0x04, 0xB9, 0xB2, 0xEE, 0x5C, 0x53, 0xFA, 0x86 };
u8 key000019CC[16] = {0x70, 0x44, 0xA3, 0xAE, 0xEF, 0x5D, 0xA5, 0xF2, 0x85, 0x7F, 0xF2, 0xD6, 0x94, 0xF5, 0x36, 0x3B};
u8 key000019DC[16] = {0xEC, 0x6D, 0x29, 0x59, 0x26, 0x35, 0xA5, 0x7F, 0x97, 0x2A, 0x0D, 0xBC, 0xA3, 0x26, 0x33, 0x00};
u8 key0000199C[16] = {0x36, 0xA5, 0x3E, 0xAC, 0xC5, 0x26, 0x9E, 0xA3, 0x83, 0xD9, 0xEC, 0x25, 0x6C, 0x48, 0x48, 0x72};
u8 key000019AC[16] = {0xD8, 0xC0, 0xB0, 0xF3, 0x3E, 0x6B, 0x76, 0x85, 0xFD, 0xFB, 0x4D, 0x7D, 0x45, 0x1E, 0x92, 0x03};
int sub_000014BC(u8* data, int length)
{
*(s32*)(data + 0) = 5;
*(s32*)(data + 12) = 256;
*(s32*)(data + 4) = 0;
*(s32*)(data + 8) = 0;
*(s32*)(data + 16) = length;
int res = sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, 8);
if (res == 0)
return 0;
return -258;
}
int sub_00001418(u8* data, int length, int val2)
{
*(s32*)(data + 12) = val2;
*(s32*)(data + 0) = 5;
*(s32*)(data + 4) = 0;
*(s32*)(data + 8) = 0;
*(s32*)(data + 16) = length;
int res = sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, 7);
if (res == 0)
return 0;
return -257;
}
int sub_000015B0(u8* data, int alignedLen, u8* buf, int val)
{
u8 sp0[16];
for(int i = 0; i < 16; i++)
{
sp0[i] = data[alignedLen+i+4];
}
int res = sub_00001418(data, alignedLen, val);
if (res != 0)
{
return res;
}
for(int i = 0; i < 16; i++)
{
data[i] = data[i] ^ buf[i];
}
for(int i = 0; i < 16; i++)
{
buf[i] = sp0[i];
}
return 0;
}
int sub_00000000(u8* data_out, u8* data, int alignedLen, u8* data2, int& data3, int mode)
{
for(int i = 0; i < 16; i++)
{
data_out[20+i] = data2[i];
}
int valS4 = 100;
int res;
if (mode == 6)
{
valS4 = 100;
for(int i = 0; i < 16; i++)
{
data_out[20+i] = data_out[20+i] ^ key000019DC[i];
}
res = sub_000014BC(data_out, 16);
for(int i = 0; i < 16; i++)
{
data_out[i] = data_out[i] ^ key000019CC[i];
}
}
else if (mode == 4)
{
valS4 = 87;
for(int i = 0; i < 16; i++)
{
data_out[20+i] = data_out[20+i] ^ key000019AC[i];
}
res = sub_000014BC(data_out, 16);
for(int i = 0; i < 16; i++)
{
data_out[i] = data_out[i] ^ key0000199C[i];
}
}
else if (mode == 2)
{
res = sub_000014BC(data_out, 16);
valS4 = 83;
}
else if (mode == 1)
{
res = sub_00001418(data_out, 16, 4);
valS4 = 83;
}
else if (mode == 3)
{
valS4 = 87;
for(int i = 0; i < 16; i++)
{
data_out[i+20] = data_out[i+20] ^ key000019AC[i];
}
res = sub_00001418(data_out, 16, 14);
for(int i = 0; i < 16; i++)
{
data_out[i] = data_out[i] ^ key0000199C[i];
}
}
else
{
valS4 = 100;
for(int i = 0; i < 16; i++)
{
data_out[i + 20] = data_out[i + 20] ^ key000019DC[i];
}
res = sub_00001418(data_out, 16, 18);
for(int i = 0; i < 16; i++)
{
data_out[i] = data_out[i] ^ key000019CC[i];
}
}
u8 sp16[16];
if (res != 0)
{
return res;
}
for(int i = 0; i < 16; i++)
{
sp16[i] = data_out[i];
}
u8 sp0[16];
if (data3 == 1)
{
for(int i = 0; i < 16; i++)
{
sp0[i] = 0;
}
}
else
{
for(int i = 0; i < 12; i++)
{
sp0[i] = sp16[i];
}
sp0[12] = (data3-1) & 0xFF ;
sp0[13] = ((data3-1) >> 8) & 0xFF;
sp0[14] = ((data3-1) >> 16) & 0xFF;
sp0[15] = ((data3-1) >> 24) & 0xFF;
}
if ((u32)20 < (u32)alignedLen + 20)
{
for(int i = 20; i < alignedLen + 20; i += 16)
{
for(int j = 0; j < 12; j++)
{
data_out[i+j] = sp16[j];
}
data_out[12+i] = data3;
data_out[13+i] = (data3 >> 8) & 0xFF;
data_out[14+i] = (data3 >> 16) & 0xFF;
data_out[15+i] = (data3 >> 24) & 0xFF;
data3++;
}
}
res = sub_000015B0(data_out, alignedLen, sp0, valS4);
if (res != 0)
{
return res;
}
if (res >= alignedLen)
{
return 0;
}
for(int i = 0; i < alignedLen; i++)
{
data[i] = data[i] ^ data_out[i];
}
return 0;
}
int sub_000013C8(u8* data, int size, int num)
{
*(int*)(data+0) = 4;
*(int*)(data+4) = 0;
*(int*)(data+8) = 0;
*(int*)(data+12) = num;
*(int*)(data+16) = size;
size = size + 20;
int res = sceUtilsBufferCopyWithRange(data,size,data,size,4);
if(res != 0)
{
return -257;
}
return 0;
}
int sub_00001468(u8* data, int size)
{
*(int*)(data+0) = 4;
*(int*)(data+12) = 256;
*(int*)(data+4) = 0;
*(int*)(data+8) = 0;
*(int*)(data+16) = size;
size = size + 20;
int res = sceUtilsBufferCopyWithRange(data,size,data,size,5);
if(res != 0)
{
return -258;
}
return 0;
}
int sub_00001510(u8* data, int size, u8* result , int num)
{
for(int i = 0; i < 16; i++)
{
int v1 = data[i+20];
v1 = v1 ^ result[i];
data[i+20] = v1;
}
int res = sub_000013C8(data, size, num);
if(res != 0)
{
return res;
}
for(int i = 0; i < 16; i++)
{
result[i] = data[size + i + 4];
}
return 0;
}
int sub_000017A8(u8* data)
{
int res = sceUtilsBufferCopyWithRange(data, 20, 0, 0, 14);
if (res == 0)
return 0;
return -261;
}
int sceSdGetLastIndex(u32 addressCtx,u32 addressHash, u32 addressKey)
{
pspChnnlsvContext1 ctx;
Memory::ReadStruct(addressCtx,&ctx);
u8* in_hash;
u8* in_key;
in_hash = Memory::GetPointer(addressHash);
in_key = Memory::GetPointer(addressKey);
int res = sceSdGetLastIndex_(ctx, in_hash, in_key);
Memory::WriteStruct(addressCtx,&ctx);
return res;
}
int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, u8* in_key)
{
if(ctx.keyLength >= 17)
{
return -1026;
}
int num = 0;
switch(ctx.mode)
{
case 6:
num = 17;
break;
case 4:
num = 13;
break;
case 2:
num = 5;
break;
case 1:
num = 3;
break;
case 3:
num = 12;
break;
default:
num = 16;
break;
}
memset(dataBuf2,0,16);
int res = sub_000013C8(dataBuf,16,num);
if(res != 0)
{
return res;
}
u8 data1[16];
u8 data2[16];
memcpy(data1,dataBuf2,16);
int tmp1 = 0;
if((s8)data1[0] < 0)
tmp1 = 135;
for(int i = 0; i < 15; i++)
{
u8 val1 = data1[i] << 1;
u8 val2 = data1[i+1] >> 7;
data1[i] = val1 | val2;
}
u8 tmp2 = data1[15] << 1;
tmp2 = tmp1 ^ tmp2;
data1[15] = tmp2;
if(ctx.keyLength < 16)
{
tmp1 = 0;
if((s8)data1[0] < 0)
{
tmp1 = 135;
}
for(int i = 0; i < 15; i++)
{
u8 val1 = data1[i] << 1;
u8 val2 = data1[i+1] >> 7;
data1[i] = val1 | val2;
}
u8 tmp2 = data1[15] << 1;
tmp2 = tmp1 ^ tmp2;
data1[15] = tmp2;
int oldKeyLength = ctx.keyLength;
*(s8*)(ctx.key + ctx.keyLength) = -128;
if(oldKeyLength + 1 < 16)
{
for(int i = oldKeyLength + 1; i < 16; i++)
{
*(s8*)(ctx.key + i) = 0;
}
}
}
for(int i = 0; i < 16; i++)
{
ctx.key[i] = ctx.key[i] ^ data1[i];
}
for(int i = 0; i < 16; i++)
{
dataBuf2[i] = ctx.key[i];
}
for(int i = 0; i < 16; i++)
{
data2[i] = ctx.result[i];
}
int ret = sub_00001510(dataBuf,16,data2,num);
if(ret != 0)
{
return ret;
}
if((u32)(ctx.mode-3) < 2)
{
for(int i = 0; i < 16; i++)
{
data2[i] = data2[i] ^ hash198C[i];
}
}
else if((u32)(ctx.mode-5) < 2)
{
for(int i = 0; i < 16; i++)
{
data2[i] = data2[i] ^ hash19BC[i];
}
}
int cond = ((ctx.mode ^ 0x2) < 1 || (ctx.mode ^ 0x4) < 1 || ctx.mode == 6);
if(cond != 0)
{
for(int i = 0; i < 16; i++)
{
dataBuf2[i] = data2[i];
}
int ret = sub_00001468(dataBuf,16);
if(ret != 0)
{
return ret;
}
int res = sub_000013C8(dataBuf,16,num);
if(res != 0)
{
return res;
}
for(int i = 0; i < 16; i++)
{
data2[i] = dataBuf2[i];
}
}
if(in_key != 0)
{
for(int i = 0; i < 16; i++)
{
data2[i] = in_key[i] ^ data2[i];
}
for(int i = 0; i < 16; i++)
{
dataBuf2[i] = data2[i];
}
int res = sub_000013C8(dataBuf,16,num);
if(res != 0)
{
return res;
}
for(int i = 0; i < 16; i++)
{
data2[i] = dataBuf2[i];
}
}
for(int i = 0; i < 16; i++)
{
in_hash[i] = data2[i];
}
for(int i = 0; i < 16; i++)
{
ctx.result[i] = 0;
}
for(int i = 0; i < 16; i++)
{
ctx.key[i] = 0;
}
ctx.keyLength = 0;
ctx.mode = 0;
return 0;
}
int sceSdSetIndex(u32 addressCtx, int value)
{
pspChnnlsvContext1 ctx;
Memory::ReadStruct(addressCtx,&ctx);
int res = sceSdSetIndex_(ctx, value);
Memory::WriteStruct(addressCtx,&ctx);
return res;
}
int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value)
{
ctx.mode = value;
memset(ctx.result,0,16);
memset(ctx.key,0,16);
ctx.keyLength = 0;
return 0;
}
int sceSdRemoveValue(u32 addressCtx, u32 addressData, int length)
{
pspChnnlsvContext1 ctx;
Memory::ReadStruct(addressCtx,&ctx);
u8* data;
data = Memory::GetPointer(addressData);
int res = sceSdRemoveValue_(ctx, data, length);
Memory::WriteStruct(addressCtx,&ctx);
return res;
}
int sceSdRemoveValue_(pspChnnlsvContext1& ctx, u8* data, int length)
{
if(ctx.keyLength >= 17)
{
return -1026;
}
if(ctx.keyLength + length < 17)
{
if(length == 0)
{
return 0;
}
for(int i = 0; i < length; i++)
{
ctx.key[ctx.keyLength+i] = data[i];
}
ctx.keyLength = ctx.keyLength + length;
return 0;
}
int mode = ctx.mode;
int num = 0;
switch(mode)
{
case 6:
num = 17;
break;
case 4:
num = 13;
break;
case 2:
num = 5;
break;
case 1:
num = 3;
break;
case 3:
num = 12;
break;
default:
num = 16;
break;
}
memset(dataBuf2,0,2048);
if(ctx.keyLength > 0)
{
memcpy(dataBuf2,ctx.key,ctx.keyLength);
}
int len = (ctx.keyLength + length) & 0xF;
if(len == 0) len = 16;
int oldLength = ctx.keyLength;
ctx.keyLength = len;
int diff = length - len;
if(len != 0)
{
memcpy(ctx.key,data+diff,len);
}
int newSize = oldLength;
if(diff != 0)
{
for(int i = 0; i < diff; i++)
{
if(newSize == 2048)
{
int res = sub_00001510(dataBuf,2048,ctx.result,num);
if(res != 0)
{
return res;
}
newSize = 0;
}
dataBuf2[newSize] = data[i];
newSize++;
}
}
if(newSize == 0)
{
return 0;
}
int res = sub_00001510(dataBuf,newSize,ctx.result, num);
if(res == 0)
{
return res;
}
return 0;
}
int sceSdCreateList(u32 ctx2Addr, int mode, int unkwn, u32 dataAddr, u32 cryptkeyAddr)
{
pspChnnlsvContext2 ctx2;
Memory::ReadStruct(ctx2Addr, &ctx2);
u8* data = Memory::GetPointer(dataAddr);
u8* cryptkey = Memory::GetPointer(cryptkeyAddr);
int res = sceSdCreateList_(ctx2, mode, unkwn, data, cryptkey);
Memory::WriteStruct(ctx2Addr, &ctx2);
return res;
}
int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, u8* cryptkey)
{
ctx2.mode = mode;
ctx2.unkn = 1;
if (uknw == 2)
{
for(int i = 0; i < 16; i++)
{
ctx2.unknown[i] = data[i];
}
if (cryptkey == 0)
{
return 0;
}
for(int i = 0; i < 16; i++)
{
ctx2.unknown[i] = ctx2.unknown[i] ^ cryptkey[i];
}
return 0;
}
else if (uknw == 1)
{
u8 kirkHeader[37];
u8* kirkData = kirkHeader+20;
int res = sub_000017A8(kirkHeader);
if (res != 0)
{
return res;
}
for(int i = 15; i >= 0 ; i--)
{
kirkHeader[i+20] = kirkHeader[i];
}
for(int i = 0; i < 4; i++)
{
kirkHeader[i+32] = 0;
}
if (mode == 6)
{
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key000019CC[i];
}
res = sub_00001468(kirkHeader, 16);
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key000019DC[i];
}
}
else if (mode == 4)
{
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key0000199C[i];
}
res = sub_00001468(kirkHeader, 16);
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key000019AC[i];
}
}
else if (mode == 2)
{
res = sub_00001468(kirkHeader, 16);
}
else if (mode == 1)
{
res = sub_000013C8(kirkHeader, 16, 4);
}
else if (mode == 3)
{
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key0000199C[i];
}
res = sub_000013C8(kirkHeader, 16, 14);
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key000019AC[i];
}
}
else
{
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key000019CC[i];
}
res = sub_000013C8(kirkHeader, 16, 18);
for(int i = 0; i < 16; i++)
{
kirkData[i] = kirkData[i] ^ key000019DC[i];
}
}
if (res != 0)
{
return res;
}
for(int i = 0; i < 16; i++)
{
ctx2.unknown[i] = kirkData[i];
}
for(int i = 0; i < 16; i++)
{
data[i] = kirkData[i];
}
if (cryptkey != 0)
{
for(int i = 0; i < 16; i++)
{
ctx2.unknown[i] = ctx2.unknown[i] ^ cryptkey[i];
}
}
}
return 0;
}
int sceSdSetMember(u32 ctxAddr, u32 dataAddr, int alignedLen)
{
pspChnnlsvContext2 ctx;
Memory::ReadStruct(ctxAddr, &ctx);
u8* data = Memory::GetPointer(dataAddr);
int res = sceSdSetMember_(ctx, data, alignedLen);
Memory::WriteStruct(ctxAddr, &ctx);
return res;
}
int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen)
{
if (alignedLen == 0)
{
return 0;
}
if (alignedLen & 0xF != 0)
{
return -1025;
}
int i = 0;
u8 kirkData[20+2048];
if ((u32)alignedLen >= (u32)2048)
{
for(i = 0; alignedLen >= 2048; i += 2048)
{
int res = sub_00000000(kirkData, data + i, 2048, ctx.unknown, ctx.unkn, ctx.mode);
alignedLen = alignedLen - 2048;
if (res != 0)
{
return res;
}
}
}
if (alignedLen == 0)
{
return 0;
}
int res = sub_00000000(kirkData, data + i, alignedLen, ctx.unknown, ctx.unkn, ctx.mode);
return res;
}
int sceChnnlsv_21BE78B4(u32 ctxAddr)
{
pspChnnlsvContext2 ctx;
Memory::ReadStruct(ctxAddr, &ctx);
int res = sceChnnlsv_21BE78B4_(ctx);
Memory::WriteStruct(ctxAddr, &ctx);
return res;
}
int sceChnnlsv_21BE78B4_(pspChnnlsvContext2& ctx)
{
for(int i = 0; i < 16; i++)
{
ctx.unknown[i] = 0;
}
ctx.unkn = 0;
ctx.mode = 0;
return 0;
}
const HLEFunction sceChnnlsv[] =
{
{0xE7833020,WrapI_UI<sceSdSetIndex>,"sceSdSetIndex"},
{0xF21A1FCA,WrapI_UUI<sceSdRemoveValue>,"sceSdRemoveValue"},
{0xC4C494F8,WrapI_UUU<sceSdGetLastIndex>,"sceSdGetLastIndex"},
{0xABFDFC8B,WrapI_UIIUU<sceSdCreateList>,"sceSdCreateList"},
{0x850A7FA1,WrapI_UUI<sceSdSetMember>,"sceSdSetMember"},
{0x21BE78B4,WrapI_U<sceChnnlsv_21BE78B4>,"sceChnnlsv_21BE78B4"},
};
void Register_sceChnnlsv()
{
RegisterModule("sceChnnlsv",ARRAY_SIZE(sceChnnlsv),sceChnnlsv);
kirk_init();
}

44
Core/HLE/sceChnnlsv.h Normal file
View File

@ -0,0 +1,44 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
typedef struct _pspChnnlsvContext1 {
/** Cipher mode */
int mode;
/** Context data */
u8 result[0x10];
u8 key[0x10];
int keyLength;
} pspChnnlsvContext1;
typedef struct _pspChnnlsvContext2 {
/** Context data */
int mode;
int unkn;
u8 unknown[0x92];
} pspChnnlsvContext2;
int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value);
int sceSdRemoveValue_(pspChnnlsvContext1& ctx, u8* data, int length);
int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, u8* cryptkey);
int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen);
int sceChnnlsv_21BE78B4_(pspChnnlsvContext2& ctx);
int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, u8* in_key);
void Register_sceChnnlsv();

View File

@ -69,6 +69,7 @@ SOURCES += ../Core/CPU.cpp \ # Core
../Core/HLE/sceAtrac.cpp \ ../Core/HLE/sceAtrac.cpp \
../Core/HLE/sceAudio.cpp \ ../Core/HLE/sceAudio.cpp \
../Core/HLE/sceCtrl.cpp \ ../Core/HLE/sceCtrl.cpp \
../Core/HLE/sceChnnlsv.cpp \
../Core/HLE/sceDisplay.cpp \ ../Core/HLE/sceDisplay.cpp \
../Core/HLE/sceDmac.cpp \ ../Core/HLE/sceDmac.cpp \
../Core/HLE/sceGe.cpp \ ../Core/HLE/sceGe.cpp \
@ -181,6 +182,7 @@ HEADERS += ../Core/CPU.h \
../Core/HLE/sceAtrac.h \ ../Core/HLE/sceAtrac.h \
../Core/HLE/sceAudio.h \ ../Core/HLE/sceAudio.h \
../Core/HLE/sceCtrl.h \ ../Core/HLE/sceCtrl.h \
../Core/HLE/sceChnnlsv.h \
../Core/HLE/sceDisplay.h \ ../Core/HLE/sceDisplay.h \
../Core/HLE/sceDmac.h \ ../Core/HLE/sceDmac.h \
../Core/HLE/sceGe.h \ ../Core/HLE/sceGe.h \

View File

@ -216,7 +216,7 @@ int kirk_CMD4(u8* outbuff, u8* inbuff, int size)
//Set the key //Set the key
AES_set_key(&aesKey, key, 128); AES_set_key(&aesKey, key, 128);
AES_cbc_encrypt(&aesKey, inbuff+sizeof(KIRK_AES128CBC_HEADER), outbuff+sizeof(KIRK_AES128CBC_HEADER), size); AES_cbc_encrypt(&aesKey, inbuff+sizeof(KIRK_AES128CBC_HEADER), outbuff+sizeof(KIRK_AES128CBC_HEADER), header->data_size);
return KIRK_OPERATION_SUCCESS; return KIRK_OPERATION_SUCCESS;
} }
@ -236,7 +236,7 @@ int kirk_CMD7(u8* outbuff, u8* inbuff, int size)
//Set the key //Set the key
AES_set_key(&aesKey, key, 128); AES_set_key(&aesKey, key, 128);
AES_cbc_decrypt(&aesKey, inbuff+sizeof(KIRK_AES128CBC_HEADER), outbuff, size); AES_cbc_decrypt(&aesKey, inbuff+sizeof(KIRK_AES128CBC_HEADER), outbuff, header->data_size);
return KIRK_OPERATION_SUCCESS; return KIRK_OPERATION_SUCCESS;
} }