From aa017515897faa21948975611c07a653005f6236 Mon Sep 17 00:00:00 2001 From: Xele02 Date: Tue, 29 Jan 2013 00:11:02 +0100 Subject: [PATCH] Save encryption. Load/Save encrypted/decrypted save RE of Chnnlsv lib Correct size bug in kirk --- CMakeLists.txt | 2 + Core/Config.cpp | 2 + Core/Config.h | 1 + Core/Core.vcxproj | 2 + Core/Dialog/PSPSaveDialog.cpp | 12 + Core/Dialog/SavedataParam.cpp | 385 ++++++++++++++-- Core/Dialog/SavedataParam.h | 9 +- Core/ELF/ParamSFO.cpp | 25 + Core/ELF/ParamSFO.h | 2 + Core/HLE/FunctionWrappers.h | 5 + Core/HLE/HLETables.cpp | 2 + Core/HLE/sceChnnlsv.cpp | 827 ++++++++++++++++++++++++++++++++++ Core/HLE/sceChnnlsv.h | 44 ++ Qt/Core.pro | 2 + ext/libkirk/kirk_engine.c | 4 +- 15 files changed, 1294 insertions(+), 30 deletions(-) create mode 100644 Core/HLE/sceChnnlsv.cpp create mode 100644 Core/HLE/sceChnnlsv.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b28f37763..94dbe764ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Core/Config.cpp b/Core/Config.cpp index 6d79df1bad..270cdbb4a2 100644 --- a/Core/Config.cpp +++ b/Core/Config.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()); diff --git a/Core/Config.h b/Core/Config.h index 669331404d..e03a5dea76 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -74,6 +74,7 @@ public: // SystemParam int ilanguage; int itimeformat; + bool bEncryptSave; std::string currentDirectory; std::string memCardDirectory; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 40ec87f5e0..265a9fd0f4 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -142,6 +142,7 @@ + @@ -311,6 +312,7 @@ + diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index a5d22b9511..2732991d5e 100644 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -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())) diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 0984a32052..d660e999af 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -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; +} + diff --git a/Core/Dialog/SavedataParam.h b/Core/Dialog/SavedataParam.h index dc9384e46e..e8ce083985 100644 --- a/Core/Dialog/SavedataParam.h +++ b/Core/Dialog/SavedataParam.h @@ -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; diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index ec8fdfcda3..cfbe1ecc21 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -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; diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index 1620563dd0..119ec72b3b 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -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 { diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 4e55b661af..f07f3b9b3f 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -255,6 +255,11 @@ template void WrapU_UII() { RETURN(retval); } +template void WrapI_UIIUU() { + u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); + RETURN(retval); +} + template void WrapV_UIII() { func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); } diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 9676a49bc2..3f9597b443 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -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++) { diff --git a/Core/HLE/sceChnnlsv.cpp b/Core/HLE/sceChnnlsv.cpp new file mode 100644 index 0000000000..45fa317833 --- /dev/null +++ b/Core/HLE/sceChnnlsv.cpp @@ -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"}, + {0xF21A1FCA,WrapI_UUI,"sceSdRemoveValue"}, + {0xC4C494F8,WrapI_UUU,"sceSdGetLastIndex"}, + {0xABFDFC8B,WrapI_UIIUU,"sceSdCreateList"}, + {0x850A7FA1,WrapI_UUI,"sceSdSetMember"}, + {0x21BE78B4,WrapI_U,"sceChnnlsv_21BE78B4"}, +}; + +void Register_sceChnnlsv() +{ + RegisterModule("sceChnnlsv",ARRAY_SIZE(sceChnnlsv),sceChnnlsv); + kirk_init(); +} diff --git a/Core/HLE/sceChnnlsv.h b/Core/HLE/sceChnnlsv.h new file mode 100644 index 0000000000..d6ec1480f3 --- /dev/null +++ b/Core/HLE/sceChnnlsv.h @@ -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(); diff --git a/Qt/Core.pro b/Qt/Core.pro index 614698b3c5..6880adc580 100755 --- a/Qt/Core.pro +++ b/Qt/Core.pro @@ -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 \ diff --git a/ext/libkirk/kirk_engine.c b/ext/libkirk/kirk_engine.c index bf07dfcf9d..eea283e1a8 100644 --- a/ext/libkirk/kirk_engine.c +++ b/ext/libkirk/kirk_engine.c @@ -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; }