mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Save encryption. Load/Save encrypted/decrypted save
RE of Chnnlsv lib Correct size bug in kirk
This commit is contained in:
parent
630c025fd5
commit
aa01751589
@ -680,6 +680,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/HLE/sceAtrac.h
|
||||
Core/HLE/sceAudio.cpp
|
||||
Core/HLE/sceAudio.h
|
||||
Core/HLE/sceChnnlsv.cpp
|
||||
Core/HLE/sceChnnlsv.h
|
||||
Core/HLE/sceCtrl.cpp
|
||||
Core/HLE/sceCtrl.h
|
||||
Core/HLE/sceDisplay.cpp
|
||||
|
@ -87,6 +87,7 @@ void CConfig::Load(const char *iniFileName)
|
||||
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
|
||||
pspConfig->Get("Language", &ilanguage, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH);
|
||||
pspConfig->Get("TimeFormat", &itimeformat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR);
|
||||
pspConfig->Get("EncryptSave", &bEncryptSave, true);
|
||||
|
||||
// Ephemeral settings
|
||||
bDrawWireframe = false;
|
||||
@ -136,6 +137,7 @@ void CConfig::Save()
|
||||
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
|
||||
pspConfig->Set("Language", ilanguage);
|
||||
pspConfig->Set("TimeFormat", itimeformat);
|
||||
pspConfig->Set("EncryptSave", bEncryptSave);
|
||||
|
||||
if (!iniFile.Save(iniFilename_.c_str())) {
|
||||
ERROR_LOG(LOADER, "Error saving config - can't write ini %s", iniFilename_.c_str());
|
||||
|
@ -74,6 +74,7 @@ public:
|
||||
// SystemParam
|
||||
int ilanguage;
|
||||
int itimeformat;
|
||||
bool bEncryptSave;
|
||||
|
||||
std::string currentDirectory;
|
||||
std::string memCardDirectory;
|
||||
|
@ -142,6 +142,7 @@
|
||||
<ClCompile Include="HLE\HLETables.cpp" />
|
||||
<ClCompile Include="HLE\sceAtrac.cpp" />
|
||||
<ClCompile Include="HLE\sceAudio.cpp" />
|
||||
<ClCompile Include="HLE\sceChnnlsv.cpp" />
|
||||
<ClCompile Include="HLE\sceCtrl.cpp" />
|
||||
<ClCompile Include="HLE\sceDisplay.cpp" />
|
||||
<ClCompile Include="HLE\sceDmac.cpp" />
|
||||
@ -311,6 +312,7 @@
|
||||
<ClInclude Include="HLE\sceAtrac.h" />
|
||||
<ClInclude Include="HLE\sceAudio.h" />
|
||||
<ClInclude Include="HLE\sceCtrl.h" />
|
||||
<ClInclude Include="HLE\sceChnnlsv.h" />
|
||||
<ClInclude Include="HLE\sceDisplay.h" />
|
||||
<ClInclude Include="HLE\sceDmac.h" />
|
||||
<ClInclude Include="HLE\sceFont.h" />
|
||||
|
@ -89,6 +89,7 @@ int PSPSaveDialog::Init(int paramAddr)
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
|
||||
case SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE:
|
||||
display = DS_NONE;
|
||||
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)
|
||||
@ -736,6 +737,17 @@ int PSPSaveDialog::Update()
|
||||
}
|
||||
status = SCE_UTILITY_STATUS_FINISHED;
|
||||
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_WRITEDATASECURE:
|
||||
if(param.Save(param.GetPspParam(),param.GetSelectedSave()))
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "image/png_load.h"
|
||||
#include "../HLE/sceKernelMemory.h"
|
||||
#include "../ELF/ParamSFO.h"
|
||||
#include "../HLE/sceChnnlsv.h"
|
||||
#include "Core/HW/MemoryStick.h"
|
||||
#include "PSPSaveDialog.h"
|
||||
|
||||
@ -45,13 +46,19 @@ namespace
|
||||
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);
|
||||
if (handle == 0)
|
||||
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);
|
||||
if(readSize)
|
||||
*readSize = result;
|
||||
@ -110,6 +117,28 @@ namespace
|
||||
|
||||
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()
|
||||
@ -222,22 +251,36 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
|
||||
if (!pspFileSystem.GetFileInfo(dirPath).exists)
|
||||
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);
|
||||
SceSize saveSize = param->dataSize;
|
||||
if(saveSize == 0 || saveSize > param->dataBufSize)
|
||||
saveSize = param->dataBufSize; // fallback, should never use this
|
||||
INFO_LOG(HLE,"Saving file with size %u in %s",saveSize,filePath.c_str());
|
||||
u8 *data_ = (u8*)Memory::GetPointer(param->dataBuf);
|
||||
cryptedSize = param->dataSize;
|
||||
if(cryptedSize == 0 || cryptedSize > param->dataBufSize)
|
||||
cryptedSize = param->dataBufSize; // fallback, should never use this
|
||||
u8* data_ = (u8*)Memory::GetPointer(param->dataBuf);
|
||||
|
||||
// copy back save name in request
|
||||
strncpy(param->saveName,GetSaveDirName(param, saveId).c_str(),20);
|
||||
int aligned_len = align16(cryptedSize);
|
||||
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());
|
||||
return false;
|
||||
decryptMode = (GetSDKMainVersion(sceKernelGetCompiledSdkVersion()) >= 4 ? 5 : 3);
|
||||
}
|
||||
|
||||
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];
|
||||
size_t sfoSize = (size_t)sfoInfo.size;
|
||||
if(ReadPSPFile(sfopath,sfoData,sfoSize, NULL))
|
||||
if(ReadPSPFile(sfopath,&sfoData,sfoSize, NULL))
|
||||
{
|
||||
sfoFile.ReadSFO(sfoData,sfoSize);
|
||||
delete[] sfoData;
|
||||
@ -285,18 +328,19 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
|
||||
if(fName[0] == 0)
|
||||
break; // End of list
|
||||
if(strncmp(fName,GetFileName(param).c_str(),20) == 0)
|
||||
break; // File already in SFO
|
||||
|
||||
break;
|
||||
fName += FILE_LIST_ITEM_SIZE;
|
||||
}
|
||||
|
||||
if (fName + 20 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE)
|
||||
snprintf(fName, 20, "%s",GetFileName(param).c_str());
|
||||
if (fName + 13 <= (char*)tmpData + FILE_LIST_TOTAL_SIZE)
|
||||
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);
|
||||
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];
|
||||
memset(tmpData, 0, 128);
|
||||
sfoFile.SetValue("SAVEDATA_PARAMS", tmpData, 128, 128);
|
||||
@ -305,9 +349,54 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
|
||||
u8 *sfoData;
|
||||
size_t 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);
|
||||
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
|
||||
if (param->icon0FileData.buf)
|
||||
{
|
||||
@ -375,12 +464,14 @@ bool SavedataParam::Load(SceUtilitySavedataParam *param, int saveId)
|
||||
std::string filePath = dirPath+"/"+GetFileName(param);
|
||||
s64 readSize;
|
||||
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());
|
||||
return false;
|
||||
}
|
||||
param->dataSize = (SceSize)readSize;
|
||||
saveSize = readSize;
|
||||
|
||||
// copy back save name in request
|
||||
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];
|
||||
size_t sfoSize = (size_t)sfoInfo.size;
|
||||
if(ReadPSPFile(sfopath,sfoData,sfoSize, NULL))
|
||||
if(ReadPSPFile(sfopath,&sfoData,sfoSize, NULL))
|
||||
{
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char text[50];
|
||||
@ -464,7 +756,7 @@ bool SavedataParam::GetSizes(SceUtilitySavedataParam *param)
|
||||
PSPFileInfo finfo = pspFileSystem.GetFileInfo(path);
|
||||
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(0x20,param->msData+40); // 0x20
|
||||
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);
|
||||
if (info.exists)
|
||||
{
|
||||
bool isCrypted = IsSaveEncrypted(param,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 + 24); // TODO unknow
|
||||
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)
|
||||
{
|
||||
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]);
|
||||
delete[] textureDataPNG;
|
||||
}
|
||||
@ -808,7 +1104,7 @@ void SavedataParam::SetFileInfo(int idx, PSPFileInfo &info, std::string saveName
|
||||
if (info2.exists)
|
||||
{
|
||||
u8 *sfoParam = new u8[(size_t)info2.size];
|
||||
ReadPSPFile(fileDataPath2, sfoParam, info2.size, NULL);
|
||||
ReadPSPFile(fileDataPath2, &sfoParam, info2.size, NULL);
|
||||
ParamSFOData sfoFile;
|
||||
if (sfoFile.ReadSFO(sfoParam,(size_t)info2.size))
|
||||
{
|
||||
@ -864,3 +1160,38 @@ void SavedataParam::DoState(PointerWrap &p)
|
||||
p.DoArray(saveDataList, saveDataListCount);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ enum SceUtilitySavedataType
|
||||
SCE_UTILITY_SAVEDATA_TYPE_DELETE = 6,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE = 7,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_SIZES = 8,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_SINGLEDELETE = 10,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_LIST = 11,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_FILES = 12,
|
||||
SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE = 13,
|
||||
@ -107,7 +108,7 @@ struct SceUtilitySavedataParam
|
||||
u32 msData;
|
||||
u32 utilityData;
|
||||
|
||||
char key[16];
|
||||
u8 key[16];
|
||||
|
||||
int secureVersion;
|
||||
int multiStatus;
|
||||
@ -157,6 +158,7 @@ public:
|
||||
bool GetList(SceUtilitySavedataParam* param);
|
||||
bool GetFilesList(SceUtilitySavedataParam* param);
|
||||
bool GetSize(SceUtilitySavedataParam* param);
|
||||
bool IsSaveEncrypted(SceUtilitySavedataParam* param, int saveId);
|
||||
|
||||
std::string GetGameName(SceUtilitySavedataParam* param);
|
||||
std::string GetSaveName(SceUtilitySavedataParam* param);
|
||||
@ -181,6 +183,11 @@ private:
|
||||
bool CreatePNGIcon(u8* pngData, int pngSize, SaveFileInfo& info);
|
||||
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;
|
||||
int selectedSave;
|
||||
SaveFileInfo* saveDataList;
|
||||
|
@ -133,6 +133,31 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size)
|
||||
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)
|
||||
{
|
||||
size_t total_size = 0;
|
||||
|
@ -34,6 +34,8 @@ public:
|
||||
bool ReadSFO(const u8 *paramsfo, size_t size);
|
||||
bool WriteSFO(u8 **paramsfo, size_t *size);
|
||||
|
||||
int GetDataOffset(const u8 *paramsfo, std::string dataName);
|
||||
|
||||
private:
|
||||
enum ValueType
|
||||
{
|
||||
|
@ -255,6 +255,11 @@ template<u32 func(u32, int, int)> void WrapU_UII() {
|
||||
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() {
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
}
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "sceParseHttp.h"
|
||||
#include "sceVaudio.h"
|
||||
#include "sceUsb.h"
|
||||
#include "sceChnnlsv.h"
|
||||
|
||||
#define N(s) s
|
||||
|
||||
@ -244,6 +245,7 @@ void RegisterAllModules() {
|
||||
Register_sceParseHttp();
|
||||
Register_sceVaudio();
|
||||
Register_sceUsb();
|
||||
Register_sceChnnlsv();
|
||||
|
||||
for (int i = 0; i < numModules; i++)
|
||||
{
|
||||
|
827
Core/HLE/sceChnnlsv.cpp
Normal file
827
Core/HLE/sceChnnlsv.cpp
Normal 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
44
Core/HLE/sceChnnlsv.h
Normal 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();
|
@ -69,6 +69,7 @@ SOURCES += ../Core/CPU.cpp \ # Core
|
||||
../Core/HLE/sceAtrac.cpp \
|
||||
../Core/HLE/sceAudio.cpp \
|
||||
../Core/HLE/sceCtrl.cpp \
|
||||
../Core/HLE/sceChnnlsv.cpp \
|
||||
../Core/HLE/sceDisplay.cpp \
|
||||
../Core/HLE/sceDmac.cpp \
|
||||
../Core/HLE/sceGe.cpp \
|
||||
@ -181,6 +182,7 @@ HEADERS += ../Core/CPU.h \
|
||||
../Core/HLE/sceAtrac.h \
|
||||
../Core/HLE/sceAudio.h \
|
||||
../Core/HLE/sceCtrl.h \
|
||||
../Core/HLE/sceChnnlsv.h \
|
||||
../Core/HLE/sceDisplay.h \
|
||||
../Core/HLE/sceDmac.h \
|
||||
../Core/HLE/sceGe.h \
|
||||
|
@ -216,7 +216,7 @@ int kirk_CMD4(u8* outbuff, u8* inbuff, int size)
|
||||
|
||||
//Set the key
|
||||
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;
|
||||
}
|
||||
@ -236,7 +236,7 @@ int kirk_CMD7(u8* outbuff, u8* inbuff, int size)
|
||||
|
||||
//Set the key
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user