CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/HLE/sceChnnlsv.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "Core/MemMapHelpers.h"18#include "Core/HLE/HLE.h"19#include "Core/HLE/FunctionWrappers.h"2021#include "Core/HLE/sceChnnlsv.h"22#include "Core/HLE/sceKernel.h"23extern "C"24{25#include "ext/libkirk/kirk_engine.h"26}2728u8 dataBuf[2048+20];29u8* dataBuf2 = dataBuf + 20;3031static const u8 hash198C[16] = {0xFA, 0xAA, 0x50, 0xEC, 0x2F, 0xDE, 0x54, 0x93, 0xAD, 0x14, 0xB2, 0xCE, 0xA5, 0x30, 0x05, 0xDF};32static const u8 hash19BC[16] = {0xCB, 0x15, 0xF4, 0x07, 0xF9, 0x6A, 0x52, 0x3C, 0x04, 0xB9, 0xB2, 0xEE, 0x5C, 0x53, 0xFA, 0x86};3334static const u8 key19CC[16] = {0x70, 0x44, 0xA3, 0xAE, 0xEF, 0x5D, 0xA5, 0xF2, 0x85, 0x7F, 0xF2, 0xD6, 0x94, 0xF5, 0x36, 0x3B};35static const u8 key19DC[16] = {0xEC, 0x6D, 0x29, 0x59, 0x26, 0x35, 0xA5, 0x7F, 0x97, 0x2A, 0x0D, 0xBC, 0xA3, 0x26, 0x33, 0x00};36static const u8 key199C[16] = {0x36, 0xA5, 0x3E, 0xAC, 0xC5, 0x26, 0x9E, 0xA3, 0x83, 0xD9, 0xEC, 0x25, 0x6C, 0x48, 0x48, 0x72};37static const u8 key19AC[16] = {0xD8, 0xC0, 0xB0, 0xF3, 0x3E, 0x6B, 0x76, 0x85, 0xFD, 0xFB, 0x4D, 0x7D, 0x45, 0x1E, 0x92, 0x03};3839static void *memxor(void * dest, const void * src, size_t n)40{41char const *s = (char const*)src;42char *d = (char*)dest;4344for (; n > 0; n--)45*d++ ^= *s++;4647return dest;48}4950// The reason for the values from *FromMode calculations are not known.51static int numFromMode(int mode)52{53int num = 0;54switch(mode)55{56case 1:57num = 3;58break;59case 2:60num = 5;61break;62case 3:63num = 12;64break;65case 4:66num = 13;67break;68case 6:69num = 17;70break;71default:72num = 16;73break;74}75return num;76}77static int numFromMode2(int mode)78{79int num = 18;80if (mode == 1)81num = 4;82else if (mode == 3)83num = 14;84return num;85}8687static int typeFromMode(int mode)88{89return (mode == 1 || mode == 2) ? 83 :90((mode == 3 || mode == 4) ? 87 : 100);91}9293static int kirkSendCmd(u8* data, int length, int num, bool encrypt)94{95*(int*)(data+0) = encrypt ? KIRK_MODE_ENCRYPT_CBC : KIRK_MODE_DECRYPT_CBC;96*(int*)(data+4) = 0;97*(int*)(data+8) = 0;98*(int*)(data+12) = num;99*(int*)(data+16) = length;100101if (kirk_sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_0 : KIRK_CMD_DECRYPT_IV_0))102return -257;103104return 0;105}106107static int kirkSendFuseCmd(u8* data, int length, bool encrypt)108{109*(int*)(data+0) = encrypt ? KIRK_MODE_ENCRYPT_CBC : KIRK_MODE_DECRYPT_CBC;110*(int*)(data+4) = 0;111*(int*)(data+8) = 0;112*(int*)(data+12) = 256;113*(int*)(data+16) = length;114115// Note: CMD 5 and 8 are not available, will always return -1116if (kirk_sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_FUSE : KIRK_CMD_DECRYPT_IV_FUSE))117return -258;118119return 0;120}121122static int sub_15B0(u8* data, int alignedLen, u8* buf, int val)123{124u8 sp0[16];125memcpy(sp0, data+alignedLen+4, 16);126127int res = kirkSendCmd(data, alignedLen, val, false);128if (res)129return res;130131memxor(data, buf, 16);132memcpy(buf, sp0, 16);133return 0;134}135136static int sub_0000(u8* data_out, u8* data, int alignedLen, const u8* data2, int& data3, int mode)137{138memcpy(data_out+20, data2, 16);139// Mode 1:2 is 83, 3:4 is 87, 5:6 is 100140int type = typeFromMode(mode);141int res;142143if (type == 87)144memxor(data_out+20, key19AC, 16);145else if (type == 100)146memxor(data_out+20, key19DC, 16);147148// Odd is Cmd, Even is FuseCmd149switch(mode)150{151case 2: case 4: case 6: res = kirkSendFuseCmd(data_out, 16, false);152break;153case 1: case 3: default:res = kirkSendCmd(data_out, 16, numFromMode2(mode), false);154break;155}156157if (type == 87)158memxor(data_out, key199C, 16);159else if (type == 100)160memxor(data_out, key19CC, 16);161162if (res)163return res;164165u8 sp0[16], sp16[16];166memcpy(sp16, data_out, 16);167if (data3 == 1)168{169memset(sp0, 0, 16);170}171else172{173memcpy(sp0, sp16, 12);174*(u32*)(sp0+12) = data3-1;175}176177if (alignedLen > 0)178{179for(int i = 20; i < alignedLen + 20; i += 16)180{181memcpy(data_out+i, sp16, 12);182*(u32*)(data_out+12+i) = data3;183data3++;184}185}186187res = sub_15B0(data_out, alignedLen, sp0, type);188if (res)189return res;190191if (alignedLen > 0)192memxor(data, data_out, alignedLen);193194return 0;195}196197static int sub_1510(u8* data, int size, u8* result , int num)198{199memxor(data+20, result, 16);200201int res = kirkSendCmd(data, size, num, true);202if(res)203return res;204205memcpy(result, data+size+4, 16);206return 0;207}208209static int sub_17A8(u8* data)210{211if (kirk_sceUtilsBufferCopyWithRange(data, 20, 0, 0, 14) == 0)212return 0;213return -261;214}215216static int sceSdGetLastIndex(u32 addressCtx, u32 addressHash, u32 addressKey) {217auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);218u8 *hash = Memory::GetPointerWrite(addressHash);219if (!ctx.IsValid() || !hash)220return hleLogError(Log::sceMisc, 0, "Invalid pointer");221return hleLogSuccessI(Log::sceMisc, sceSdGetLastIndex_(*ctx, hash, Memory::GetPointerWrite(addressKey)));222}223224int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, const u8* in_key)225{226if(ctx.keyLength >= 17)227return -1026;228229int num = numFromMode(ctx.mode);230231memset(dataBuf2, 0, 16);232233int res = kirkSendCmd(dataBuf, 16, num, true);234if(res)235return res;236237u8 data1[16], data2[16];238239memcpy(data1, dataBuf2, 16);240int tmp1 = (data1[0] & 0x80) ? 135 : 0;241242for(int i = 0; i < 15; i++)243{244u8 val1 = data1[i] << 1;245u8 val2 = data1[i+1] >> 7;246data1[i] = val1 | val2;247}248249u8 tmp2 = data1[15] << 1;250tmp2 = tmp1 ^ tmp2;251data1[15] = tmp2;252253if(ctx.keyLength < 16)254{255tmp1 = 0;256if((s8)data1[0] < 0)257{258tmp1 = 135;259}260for(int i = 0; i < 15; i++)261{262u8 val1 = data1[i] << 1;263u8 val2 = data1[i+1] >> 7;264data1[i] = val1 | val2;265}266u8 tmp2 = data1[15] << 1;267tmp2 = tmp1 ^ tmp2;268data1[15] = tmp2;269270int oldKeyLength = ctx.keyLength;271*(s8*)(ctx.key + ctx.keyLength) = -128;272int i = oldKeyLength + 1;273if(i < 16)274memset(ctx.key + i, 0, 16 - i);275}276277memxor(ctx.key, data1, 16);278memcpy(dataBuf2, ctx.key, 16);279memcpy(data2, ctx.result, 16);280281int ret = sub_1510(dataBuf, 16, data2, num);282if(ret)283return ret;284285if(ctx.mode == 3 || ctx.mode == 4)286memxor(data2, hash198C, 16);287else if(ctx.mode == 5 || ctx.mode == 6)288memxor(data2, hash19BC, 16);289290int cond = ((ctx.mode ^ 0x2) < 1 || (ctx.mode ^ 0x4) < 1 || ctx.mode == 6);291if(cond != 0)292{293memcpy(dataBuf2, data2, 16);294int ret = kirkSendFuseCmd(dataBuf, 16, true);295if(ret)296return ret;297298int res = kirkSendCmd(dataBuf, 16, num, true);299if(res)300return res;301302memcpy(data2, dataBuf2, 16);303}304305if(in_key != 0)306{307for(int i = 0; i < 16; i++)308{309data2[i] = in_key[i] ^ data2[i];310}311312memcpy(dataBuf2, data2, 16);313314int res = kirkSendCmd(dataBuf, 16, num, true);315if(res)316return res;317318memcpy(data2, dataBuf2, 16);319}320memcpy(in_hash, data2, 16);321sceSdSetIndex_(ctx, 0);322323return 0;324}325326static int sceSdSetIndex(u32 addressCtx, int value) {327auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);328if (!ctx.IsValid())329return hleLogError(Log::sceMisc, 0, "Invalid pointer");330return hleLogSuccessI(Log::sceMisc, sceSdSetIndex_(*ctx, value));331}332333int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value)334{335ctx.mode = value;336memset(ctx.result, 0, 16);337memset(ctx.key, 0, 16);338ctx.keyLength = 0;339return 0;340}341342343static int sceSdRemoveValue(u32 addressCtx, u32 addressData, int length) {344auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);345if (!ctx.IsValid() || !Memory::IsValidAddress(addressData))346return hleLogError(Log::sceMisc, 0, "Invalid pointer");347return hleLogSuccessI(Log::sceMisc, sceSdRemoveValue_(*ctx, Memory::GetPointerWrite(addressData), length));348}349350int sceSdRemoveValue_(pspChnnlsvContext1& ctx, const u8* data, int length)351{352if(ctx.keyLength >= 17)353return -1026;354355if(ctx.keyLength + length < 17)356{357memcpy(ctx.key+ctx.keyLength, data, length);358ctx.keyLength = ctx.keyLength + length;359return 0;360}361int num = numFromMode(ctx.mode);362363memset(dataBuf2, 0, 2048);364memcpy(dataBuf2, ctx.key, ctx.keyLength);365366int len = (ctx.keyLength + length) & 0xF;367if(len == 0) len = 16;368369int newSize = ctx.keyLength;370ctx.keyLength = len;371372int diff = length - len;373memcpy(ctx.key, data+diff, len);374for(int i = 0; i < diff; i++)375{376if(newSize == 2048)377{378int res = sub_1510(dataBuf, 2048, ctx.result, num);379if(res)380return res;381newSize = 0;382}383dataBuf2[newSize] = data[i];384newSize++;385}386if(newSize)387sub_1510(dataBuf, newSize, ctx.result, num);388// The RE code showed this always returning 0. I suspect it would want to return res instead.389return 0;390}391392static int sceSdCreateList(u32 ctx2Addr, int mode, int unkwn, u32 dataAddr, u32 cryptkeyAddr) {393auto ctx2 = PSPPointer<pspChnnlsvContext2>::Create(ctx2Addr);394u8* data = Memory::GetPointerWrite(dataAddr);395u8* cryptkey = Memory::GetPointerWrite(cryptkeyAddr);396if (!ctx2.IsValid() || !data)397return hleLogError(Log::sceMisc, 0, "Invalid pointer");398399return hleLogSuccessI(Log::sceMisc, sceSdCreateList_(*ctx2, mode, unkwn, data, cryptkey));400}401402int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, const u8* cryptkey)403{404ctx2.mode = mode;405ctx2.unkn = 1;406if (uknw == 2)407{408memcpy(ctx2.cryptedData, data, 16);409if (cryptkey)410memxor(ctx2.cryptedData, cryptkey, 16);411412return 0;413}414else if (uknw == 1)415{416u8 kirkHeader[37];417u8* kirkData = kirkHeader+20;418int res = sub_17A8(kirkHeader);419if (res)420return res;421422memcpy(kirkHeader+20, kirkHeader, 16);423memset(kirkHeader+32, 0, 4);424425int type = typeFromMode(mode);426if (type == 87)427memxor(kirkData, key199C, 16);428else if (type == 100)429memxor(kirkData, key19CC, 16);430431switch (mode)432{433case 2: case 4: case 6: res = kirkSendFuseCmd(kirkHeader, 16, true);434break;435case 1: case 3: default:res = kirkSendCmd(kirkHeader, 16, numFromMode2(mode), true);436break;437}438439if (type == 87)440memxor(kirkData, key19AC, 16);441else if (type == 100)442memxor(kirkData, key19DC, 16);443444if (res)445return res;446447memcpy(ctx2.cryptedData, kirkData, 16);448memcpy(data, kirkData, 16);449if (cryptkey)450memxor(ctx2.cryptedData, cryptkey, 16);451}452453return 0;454}455456static int sceSdSetMember(u32 ctxAddr, u32 dataAddr, int alignedLen) {457auto ctx = PSPPointer<pspChnnlsvContext2>::Create(ctxAddr);458u8 *data = Memory::GetPointerWrite(dataAddr);459if (!ctx.IsValid() || !data)460return hleLogError(Log::sceMisc, 0, "Invalid pointer");461462return hleLogSuccessI(Log::sceMisc, sceSdSetMember_(*ctx, data, alignedLen));463}464465int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen)466{467if (alignedLen == 0)468{469return 0;470}471if ((alignedLen & 0xF) != 0)472{473return -1025;474}475int i = 0;476u8 kirkData[20+2048];477if ((u32)alignedLen >= (u32)2048)478{479for(i = 0; alignedLen >= 2048; i += 2048)480{481int ctx_unkn = ctx.unkn;482int res = sub_0000(kirkData, data + i, 2048, ctx.cryptedData, ctx_unkn, ctx.mode);483ctx.unkn = ctx_unkn;484alignedLen -= 2048;485if (res)486return res;487}488}489if (alignedLen == 0)490{491return 0;492}493int ctx_unkn = ctx.unkn;494int res = sub_0000(kirkData, data + i, alignedLen, ctx.cryptedData, ctx_unkn, ctx.mode);495ctx.unkn = ctx_unkn;496return res;497}498499static int sceSdCleanList(u32 ctxAddr) {500auto ctx = PSPPointer<pspChnnlsvContext2>::Create(ctxAddr);501if (!ctx.IsValid())502return hleLogError(Log::sceMisc, 0, "Invalid pointer");503return hleLogSuccessI(Log::sceMisc, sceSdCleanList_(*ctx));504}505506int sceSdCleanList_(pspChnnlsvContext2& ctx)507{508memset(ctx.cryptedData, 0, 16);509ctx.unkn = 0;510ctx.mode = 0;511512return 0;513}514515const HLEFunction sceChnnlsv[] =516{517{0XE7833020, &WrapI_UI<sceSdSetIndex>, "sceSdSetIndex", 'i', "xi" },518{0XF21A1FCA, &WrapI_UUI<sceSdRemoveValue>, "sceSdRemoveValue", 'i', "xxi" },519{0XC4C494F8, &WrapI_UUU<sceSdGetLastIndex>, "sceSdGetLastIndex", 'i', "xxx" },520{0XABFDFC8B, &WrapI_UIIUU<sceSdCreateList>, "sceSdCreateList", 'i', "xiixx"},521{0X850A7FA1, &WrapI_UUI<sceSdSetMember>, "sceSdSetMember", 'i', "xxi" },522{0X21BE78B4, &WrapI_U<sceSdCleanList>, "sceSdCleanList", 'i', "x" },523};524525void Register_sceChnnlsv()526{527RegisterModule("sceChnnlsv", ARRAY_SIZE(sceChnnlsv), sceChnnlsv);528kirk_init();529}530531532