CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/sceChnnlsv.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "Core/MemMapHelpers.h"
19
#include "Core/HLE/HLE.h"
20
#include "Core/HLE/FunctionWrappers.h"
21
22
#include "Core/HLE/sceChnnlsv.h"
23
#include "Core/HLE/sceKernel.h"
24
extern "C"
25
{
26
#include "ext/libkirk/kirk_engine.h"
27
}
28
29
u8 dataBuf[2048+20];
30
u8* dataBuf2 = dataBuf + 20;
31
32
static const u8 hash198C[16] = {0xFA, 0xAA, 0x50, 0xEC, 0x2F, 0xDE, 0x54, 0x93, 0xAD, 0x14, 0xB2, 0xCE, 0xA5, 0x30, 0x05, 0xDF};
33
static const u8 hash19BC[16] = {0xCB, 0x15, 0xF4, 0x07, 0xF9, 0x6A, 0x52, 0x3C, 0x04, 0xB9, 0xB2, 0xEE, 0x5C, 0x53, 0xFA, 0x86};
34
35
static const u8 key19CC[16] = {0x70, 0x44, 0xA3, 0xAE, 0xEF, 0x5D, 0xA5, 0xF2, 0x85, 0x7F, 0xF2, 0xD6, 0x94, 0xF5, 0x36, 0x3B};
36
static const u8 key19DC[16] = {0xEC, 0x6D, 0x29, 0x59, 0x26, 0x35, 0xA5, 0x7F, 0x97, 0x2A, 0x0D, 0xBC, 0xA3, 0x26, 0x33, 0x00};
37
static const u8 key199C[16] = {0x36, 0xA5, 0x3E, 0xAC, 0xC5, 0x26, 0x9E, 0xA3, 0x83, 0xD9, 0xEC, 0x25, 0x6C, 0x48, 0x48, 0x72};
38
static const u8 key19AC[16] = {0xD8, 0xC0, 0xB0, 0xF3, 0x3E, 0x6B, 0x76, 0x85, 0xFD, 0xFB, 0x4D, 0x7D, 0x45, 0x1E, 0x92, 0x03};
39
40
static void *memxor(void * dest, const void * src, size_t n)
41
{
42
char const *s = (char const*)src;
43
char *d = (char*)dest;
44
45
for (; n > 0; n--)
46
*d++ ^= *s++;
47
48
return dest;
49
}
50
51
// The reason for the values from *FromMode calculations are not known.
52
static int numFromMode(int mode)
53
{
54
int num = 0;
55
switch(mode)
56
{
57
case 1:
58
num = 3;
59
break;
60
case 2:
61
num = 5;
62
break;
63
case 3:
64
num = 12;
65
break;
66
case 4:
67
num = 13;
68
break;
69
case 6:
70
num = 17;
71
break;
72
default:
73
num = 16;
74
break;
75
}
76
return num;
77
}
78
static int numFromMode2(int mode)
79
{
80
int num = 18;
81
if (mode == 1)
82
num = 4;
83
else if (mode == 3)
84
num = 14;
85
return num;
86
}
87
88
static int typeFromMode(int mode)
89
{
90
return (mode == 1 || mode == 2) ? 83 :
91
((mode == 3 || mode == 4) ? 87 : 100);
92
}
93
94
static int kirkSendCmd(u8* data, int length, int num, bool encrypt)
95
{
96
*(int*)(data+0) = encrypt ? KIRK_MODE_ENCRYPT_CBC : KIRK_MODE_DECRYPT_CBC;
97
*(int*)(data+4) = 0;
98
*(int*)(data+8) = 0;
99
*(int*)(data+12) = num;
100
*(int*)(data+16) = length;
101
102
if (kirk_sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_0 : KIRK_CMD_DECRYPT_IV_0))
103
return -257;
104
105
return 0;
106
}
107
108
static int kirkSendFuseCmd(u8* data, int length, bool encrypt)
109
{
110
*(int*)(data+0) = encrypt ? KIRK_MODE_ENCRYPT_CBC : KIRK_MODE_DECRYPT_CBC;
111
*(int*)(data+4) = 0;
112
*(int*)(data+8) = 0;
113
*(int*)(data+12) = 256;
114
*(int*)(data+16) = length;
115
116
// Note: CMD 5 and 8 are not available, will always return -1
117
if (kirk_sceUtilsBufferCopyWithRange(data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_FUSE : KIRK_CMD_DECRYPT_IV_FUSE))
118
return -258;
119
120
return 0;
121
}
122
123
static int sub_15B0(u8* data, int alignedLen, u8* buf, int val)
124
{
125
u8 sp0[16];
126
memcpy(sp0, data+alignedLen+4, 16);
127
128
int res = kirkSendCmd(data, alignedLen, val, false);
129
if (res)
130
return res;
131
132
memxor(data, buf, 16);
133
memcpy(buf, sp0, 16);
134
return 0;
135
}
136
137
static int sub_0000(u8* data_out, u8* data, int alignedLen, const u8* data2, int& data3, int mode)
138
{
139
memcpy(data_out+20, data2, 16);
140
// Mode 1:2 is 83, 3:4 is 87, 5:6 is 100
141
int type = typeFromMode(mode);
142
int res;
143
144
if (type == 87)
145
memxor(data_out+20, key19AC, 16);
146
else if (type == 100)
147
memxor(data_out+20, key19DC, 16);
148
149
// Odd is Cmd, Even is FuseCmd
150
switch(mode)
151
{
152
case 2: case 4: case 6: res = kirkSendFuseCmd(data_out, 16, false);
153
break;
154
case 1: case 3: default:res = kirkSendCmd(data_out, 16, numFromMode2(mode), false);
155
break;
156
}
157
158
if (type == 87)
159
memxor(data_out, key199C, 16);
160
else if (type == 100)
161
memxor(data_out, key19CC, 16);
162
163
if (res)
164
return res;
165
166
u8 sp0[16], sp16[16];
167
memcpy(sp16, data_out, 16);
168
if (data3 == 1)
169
{
170
memset(sp0, 0, 16);
171
}
172
else
173
{
174
memcpy(sp0, sp16, 12);
175
*(u32*)(sp0+12) = data3-1;
176
}
177
178
if (alignedLen > 0)
179
{
180
for(int i = 20; i < alignedLen + 20; i += 16)
181
{
182
memcpy(data_out+i, sp16, 12);
183
*(u32*)(data_out+12+i) = data3;
184
data3++;
185
}
186
}
187
188
res = sub_15B0(data_out, alignedLen, sp0, type);
189
if (res)
190
return res;
191
192
if (alignedLen > 0)
193
memxor(data, data_out, alignedLen);
194
195
return 0;
196
}
197
198
static int sub_1510(u8* data, int size, u8* result , int num)
199
{
200
memxor(data+20, result, 16);
201
202
int res = kirkSendCmd(data, size, num, true);
203
if(res)
204
return res;
205
206
memcpy(result, data+size+4, 16);
207
return 0;
208
}
209
210
static int sub_17A8(u8* data)
211
{
212
if (kirk_sceUtilsBufferCopyWithRange(data, 20, 0, 0, 14) == 0)
213
return 0;
214
return -261;
215
}
216
217
static int sceSdGetLastIndex(u32 addressCtx, u32 addressHash, u32 addressKey) {
218
auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);
219
u8 *hash = Memory::GetPointerWrite(addressHash);
220
if (!ctx.IsValid() || !hash)
221
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
222
return hleLogSuccessI(Log::sceMisc, sceSdGetLastIndex_(*ctx, hash, Memory::GetPointerWrite(addressKey)));
223
}
224
225
int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, const u8* in_key)
226
{
227
if(ctx.keyLength >= 17)
228
return -1026;
229
230
int num = numFromMode(ctx.mode);
231
232
memset(dataBuf2, 0, 16);
233
234
int res = kirkSendCmd(dataBuf, 16, num, true);
235
if(res)
236
return res;
237
238
u8 data1[16], data2[16];
239
240
memcpy(data1, dataBuf2, 16);
241
int tmp1 = (data1[0] & 0x80) ? 135 : 0;
242
243
for(int i = 0; i < 15; i++)
244
{
245
u8 val1 = data1[i] << 1;
246
u8 val2 = data1[i+1] >> 7;
247
data1[i] = val1 | val2;
248
}
249
250
u8 tmp2 = data1[15] << 1;
251
tmp2 = tmp1 ^ tmp2;
252
data1[15] = tmp2;
253
254
if(ctx.keyLength < 16)
255
{
256
tmp1 = 0;
257
if((s8)data1[0] < 0)
258
{
259
tmp1 = 135;
260
}
261
for(int i = 0; i < 15; i++)
262
{
263
u8 val1 = data1[i] << 1;
264
u8 val2 = data1[i+1] >> 7;
265
data1[i] = val1 | val2;
266
}
267
u8 tmp2 = data1[15] << 1;
268
tmp2 = tmp1 ^ tmp2;
269
data1[15] = tmp2;
270
271
int oldKeyLength = ctx.keyLength;
272
*(s8*)(ctx.key + ctx.keyLength) = -128;
273
int i = oldKeyLength + 1;
274
if(i < 16)
275
memset(ctx.key + i, 0, 16 - i);
276
}
277
278
memxor(ctx.key, data1, 16);
279
memcpy(dataBuf2, ctx.key, 16);
280
memcpy(data2, ctx.result, 16);
281
282
int ret = sub_1510(dataBuf, 16, data2, num);
283
if(ret)
284
return ret;
285
286
if(ctx.mode == 3 || ctx.mode == 4)
287
memxor(data2, hash198C, 16);
288
else if(ctx.mode == 5 || ctx.mode == 6)
289
memxor(data2, hash19BC, 16);
290
291
int cond = ((ctx.mode ^ 0x2) < 1 || (ctx.mode ^ 0x4) < 1 || ctx.mode == 6);
292
if(cond != 0)
293
{
294
memcpy(dataBuf2, data2, 16);
295
int ret = kirkSendFuseCmd(dataBuf, 16, true);
296
if(ret)
297
return ret;
298
299
int res = kirkSendCmd(dataBuf, 16, num, true);
300
if(res)
301
return res;
302
303
memcpy(data2, dataBuf2, 16);
304
}
305
306
if(in_key != 0)
307
{
308
for(int i = 0; i < 16; i++)
309
{
310
data2[i] = in_key[i] ^ data2[i];
311
}
312
313
memcpy(dataBuf2, data2, 16);
314
315
int res = kirkSendCmd(dataBuf, 16, num, true);
316
if(res)
317
return res;
318
319
memcpy(data2, dataBuf2, 16);
320
}
321
memcpy(in_hash, data2, 16);
322
sceSdSetIndex_(ctx, 0);
323
324
return 0;
325
}
326
327
static int sceSdSetIndex(u32 addressCtx, int value) {
328
auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);
329
if (!ctx.IsValid())
330
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
331
return hleLogSuccessI(Log::sceMisc, sceSdSetIndex_(*ctx, value));
332
}
333
334
int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value)
335
{
336
ctx.mode = value;
337
memset(ctx.result, 0, 16);
338
memset(ctx.key, 0, 16);
339
ctx.keyLength = 0;
340
return 0;
341
}
342
343
344
static int sceSdRemoveValue(u32 addressCtx, u32 addressData, int length) {
345
auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);
346
if (!ctx.IsValid() || !Memory::IsValidAddress(addressData))
347
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
348
return hleLogSuccessI(Log::sceMisc, sceSdRemoveValue_(*ctx, Memory::GetPointerWrite(addressData), length));
349
}
350
351
int sceSdRemoveValue_(pspChnnlsvContext1& ctx, const u8* data, int length)
352
{
353
if(ctx.keyLength >= 17)
354
return -1026;
355
356
if(ctx.keyLength + length < 17)
357
{
358
memcpy(ctx.key+ctx.keyLength, data, length);
359
ctx.keyLength = ctx.keyLength + length;
360
return 0;
361
}
362
int num = numFromMode(ctx.mode);
363
364
memset(dataBuf2, 0, 2048);
365
memcpy(dataBuf2, ctx.key, ctx.keyLength);
366
367
int len = (ctx.keyLength + length) & 0xF;
368
if(len == 0) len = 16;
369
370
int newSize = ctx.keyLength;
371
ctx.keyLength = len;
372
373
int diff = length - len;
374
memcpy(ctx.key, data+diff, len);
375
for(int i = 0; i < diff; i++)
376
{
377
if(newSize == 2048)
378
{
379
int res = sub_1510(dataBuf, 2048, ctx.result, num);
380
if(res)
381
return res;
382
newSize = 0;
383
}
384
dataBuf2[newSize] = data[i];
385
newSize++;
386
}
387
if(newSize)
388
sub_1510(dataBuf, newSize, ctx.result, num);
389
// The RE code showed this always returning 0. I suspect it would want to return res instead.
390
return 0;
391
}
392
393
static int sceSdCreateList(u32 ctx2Addr, int mode, int unkwn, u32 dataAddr, u32 cryptkeyAddr) {
394
auto ctx2 = PSPPointer<pspChnnlsvContext2>::Create(ctx2Addr);
395
u8* data = Memory::GetPointerWrite(dataAddr);
396
u8* cryptkey = Memory::GetPointerWrite(cryptkeyAddr);
397
if (!ctx2.IsValid() || !data)
398
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
399
400
return hleLogSuccessI(Log::sceMisc, sceSdCreateList_(*ctx2, mode, unkwn, data, cryptkey));
401
}
402
403
int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, const u8* cryptkey)
404
{
405
ctx2.mode = mode;
406
ctx2.unkn = 1;
407
if (uknw == 2)
408
{
409
memcpy(ctx2.cryptedData, data, 16);
410
if (cryptkey)
411
memxor(ctx2.cryptedData, cryptkey, 16);
412
413
return 0;
414
}
415
else if (uknw == 1)
416
{
417
u8 kirkHeader[37];
418
u8* kirkData = kirkHeader+20;
419
int res = sub_17A8(kirkHeader);
420
if (res)
421
return res;
422
423
memcpy(kirkHeader+20, kirkHeader, 16);
424
memset(kirkHeader+32, 0, 4);
425
426
int type = typeFromMode(mode);
427
if (type == 87)
428
memxor(kirkData, key199C, 16);
429
else if (type == 100)
430
memxor(kirkData, key19CC, 16);
431
432
switch (mode)
433
{
434
case 2: case 4: case 6: res = kirkSendFuseCmd(kirkHeader, 16, true);
435
break;
436
case 1: case 3: default:res = kirkSendCmd(kirkHeader, 16, numFromMode2(mode), true);
437
break;
438
}
439
440
if (type == 87)
441
memxor(kirkData, key19AC, 16);
442
else if (type == 100)
443
memxor(kirkData, key19DC, 16);
444
445
if (res)
446
return res;
447
448
memcpy(ctx2.cryptedData, kirkData, 16);
449
memcpy(data, kirkData, 16);
450
if (cryptkey)
451
memxor(ctx2.cryptedData, cryptkey, 16);
452
}
453
454
return 0;
455
}
456
457
static int sceSdSetMember(u32 ctxAddr, u32 dataAddr, int alignedLen) {
458
auto ctx = PSPPointer<pspChnnlsvContext2>::Create(ctxAddr);
459
u8 *data = Memory::GetPointerWrite(dataAddr);
460
if (!ctx.IsValid() || !data)
461
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
462
463
return hleLogSuccessI(Log::sceMisc, sceSdSetMember_(*ctx, data, alignedLen));
464
}
465
466
int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen)
467
{
468
if (alignedLen == 0)
469
{
470
return 0;
471
}
472
if ((alignedLen & 0xF) != 0)
473
{
474
return -1025;
475
}
476
int i = 0;
477
u8 kirkData[20+2048];
478
if ((u32)alignedLen >= (u32)2048)
479
{
480
for(i = 0; alignedLen >= 2048; i += 2048)
481
{
482
int ctx_unkn = ctx.unkn;
483
int res = sub_0000(kirkData, data + i, 2048, ctx.cryptedData, ctx_unkn, ctx.mode);
484
ctx.unkn = ctx_unkn;
485
alignedLen -= 2048;
486
if (res)
487
return res;
488
}
489
}
490
if (alignedLen == 0)
491
{
492
return 0;
493
}
494
int ctx_unkn = ctx.unkn;
495
int res = sub_0000(kirkData, data + i, alignedLen, ctx.cryptedData, ctx_unkn, ctx.mode);
496
ctx.unkn = ctx_unkn;
497
return res;
498
}
499
500
static int sceSdCleanList(u32 ctxAddr) {
501
auto ctx = PSPPointer<pspChnnlsvContext2>::Create(ctxAddr);
502
if (!ctx.IsValid())
503
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
504
return hleLogSuccessI(Log::sceMisc, sceSdCleanList_(*ctx));
505
}
506
507
int sceSdCleanList_(pspChnnlsvContext2& ctx)
508
{
509
memset(ctx.cryptedData, 0, 16);
510
ctx.unkn = 0;
511
ctx.mode = 0;
512
513
return 0;
514
}
515
516
const HLEFunction sceChnnlsv[] =
517
{
518
{0XE7833020, &WrapI_UI<sceSdSetIndex>, "sceSdSetIndex", 'i', "xi" },
519
{0XF21A1FCA, &WrapI_UUI<sceSdRemoveValue>, "sceSdRemoveValue", 'i', "xxi" },
520
{0XC4C494F8, &WrapI_UUU<sceSdGetLastIndex>, "sceSdGetLastIndex", 'i', "xxx" },
521
{0XABFDFC8B, &WrapI_UIIUU<sceSdCreateList>, "sceSdCreateList", 'i', "xiixx"},
522
{0X850A7FA1, &WrapI_UUI<sceSdSetMember>, "sceSdSetMember", 'i', "xxi" },
523
{0X21BE78B4, &WrapI_U<sceSdCleanList>, "sceSdCleanList", 'i', "x" },
524
};
525
526
void Register_sceChnnlsv()
527
{
528
RegisterModule("sceChnnlsv", ARRAY_SIZE(sceChnnlsv), sceChnnlsv);
529
kirk_init();
530
}
531
532