Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/sceChnnlsv.cpp
3186 views
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
25
static KirkState g_kirk;
26
27
KirkState *__ChnnlsvKirkState() {
28
return &g_kirk;
29
}
30
31
static u8 dataBuf[2048+20];
32
static u8 *dataBuf2 = dataBuf + 20;
33
34
static const u8 hash198C[16] = {0xFA, 0xAA, 0x50, 0xEC, 0x2F, 0xDE, 0x54, 0x93, 0xAD, 0x14, 0xB2, 0xCE, 0xA5, 0x30, 0x05, 0xDF};
35
static const u8 hash19BC[16] = {0xCB, 0x15, 0xF4, 0x07, 0xF9, 0x6A, 0x52, 0x3C, 0x04, 0xB9, 0xB2, 0xEE, 0x5C, 0x53, 0xFA, 0x86};
36
37
static const u8 key19CC[16] = {0x70, 0x44, 0xA3, 0xAE, 0xEF, 0x5D, 0xA5, 0xF2, 0x85, 0x7F, 0xF2, 0xD6, 0x94, 0xF5, 0x36, 0x3B};
38
static const u8 key19DC[16] = {0xEC, 0x6D, 0x29, 0x59, 0x26, 0x35, 0xA5, 0x7F, 0x97, 0x2A, 0x0D, 0xBC, 0xA3, 0x26, 0x33, 0x00};
39
static const u8 key199C[16] = {0x36, 0xA5, 0x3E, 0xAC, 0xC5, 0x26, 0x9E, 0xA3, 0x83, 0xD9, 0xEC, 0x25, 0x6C, 0x48, 0x48, 0x72};
40
static const u8 key19AC[16] = {0xD8, 0xC0, 0xB0, 0xF3, 0x3E, 0x6B, 0x76, 0x85, 0xFD, 0xFB, 0x4D, 0x7D, 0x45, 0x1E, 0x92, 0x03};
41
42
static void *memxor(void * dest, const void * src, size_t n)
43
{
44
char const *s = (char const*)src;
45
char *d = (char*)dest;
46
47
for (; n > 0; n--)
48
*d++ ^= *s++;
49
50
return dest;
51
}
52
53
// The reason for the values from *FromMode calculations are not known.
54
static int numFromMode(int mode)
55
{
56
int num = 0;
57
switch(mode)
58
{
59
case 1:
60
num = 3;
61
break;
62
case 2:
63
num = 5;
64
break;
65
case 3:
66
num = 12;
67
break;
68
case 4:
69
num = 13;
70
break;
71
case 6:
72
num = 17;
73
break;
74
default:
75
num = 16;
76
break;
77
}
78
return num;
79
}
80
static int numFromMode2(int mode)
81
{
82
int num = 18;
83
if (mode == 1)
84
num = 4;
85
else if (mode == 3)
86
num = 14;
87
return num;
88
}
89
90
static int typeFromMode(int mode)
91
{
92
return (mode == 1 || mode == 2) ? 83 :
93
((mode == 3 || mode == 4) ? 87 : 100);
94
}
95
96
static int kirkSendCmd(KirkState *kirk, u8* data, int length, int num, bool encrypt)
97
{
98
*(int*)(data+0) = encrypt ? KIRK_MODE_ENCRYPT_CBC : KIRK_MODE_DECRYPT_CBC;
99
*(int*)(data+4) = 0;
100
*(int*)(data+8) = 0;
101
*(int*)(data+12) = num;
102
*(int*)(data+16) = length;
103
104
if (kirk_sceUtilsBufferCopyWithRange(kirk, data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_0 : KIRK_CMD_DECRYPT_IV_0))
105
return -257;
106
107
return 0;
108
}
109
110
static int kirkSendFuseCmd(KirkState *kirk, u8* data, int length, bool encrypt)
111
{
112
*(int*)(data+0) = encrypt ? KIRK_MODE_ENCRYPT_CBC : KIRK_MODE_DECRYPT_CBC;
113
*(int*)(data+4) = 0;
114
*(int*)(data+8) = 0;
115
*(int*)(data+12) = 256;
116
*(int*)(data+16) = length;
117
118
// Note: CMD 5 and 8 are not available, will always return -1
119
if (kirk_sceUtilsBufferCopyWithRange(kirk, data, length + 20, data, length + 20, encrypt ? KIRK_CMD_ENCRYPT_IV_FUSE : KIRK_CMD_DECRYPT_IV_FUSE))
120
return -258;
121
122
return 0;
123
}
124
125
static int sub_15B0(KirkState *kirk, u8* data, int alignedLen, u8* buf, int val)
126
{
127
u8 sp0[16];
128
memcpy(sp0, data+alignedLen+4, 16);
129
130
int res = kirkSendCmd(kirk, data, alignedLen, val, false);
131
if (res)
132
return res;
133
134
memxor(data, buf, 16);
135
memcpy(buf, sp0, 16);
136
return 0;
137
}
138
139
static int sub_0000(KirkState *kirk, u8* data_out, u8* data, int alignedLen, const u8* data2, int& data3, int mode)
140
{
141
memcpy(data_out+20, data2, 16);
142
// Mode 1:2 is 83, 3:4 is 87, 5:6 is 100
143
int type = typeFromMode(mode);
144
int res;
145
146
if (type == 87)
147
memxor(data_out+20, key19AC, 16);
148
else if (type == 100)
149
memxor(data_out+20, key19DC, 16);
150
151
// Odd is Cmd, Even is FuseCmd
152
switch(mode)
153
{
154
case 2: case 4: case 6: res = kirkSendFuseCmd(kirk, data_out, 16, false);
155
break;
156
case 1: case 3: default:res = kirkSendCmd(kirk, data_out, 16, numFromMode2(mode), false);
157
break;
158
}
159
160
if (type == 87)
161
memxor(data_out, key199C, 16);
162
else if (type == 100)
163
memxor(data_out, key19CC, 16);
164
165
if (res)
166
return res;
167
168
u8 sp0[16], sp16[16];
169
memcpy(sp16, data_out, 16);
170
if (data3 == 1)
171
{
172
memset(sp0, 0, 16);
173
}
174
else
175
{
176
memcpy(sp0, sp16, 12);
177
*(u32*)(sp0+12) = data3-1;
178
}
179
180
if (alignedLen > 0)
181
{
182
for(int i = 20; i < alignedLen + 20; i += 16)
183
{
184
memcpy(data_out+i, sp16, 12);
185
*(u32*)(data_out+12+i) = data3;
186
data3++;
187
}
188
}
189
190
res = sub_15B0(kirk, data_out, alignedLen, sp0, type);
191
if (res)
192
return res;
193
194
if (alignedLen > 0)
195
memxor(data, data_out, alignedLen);
196
197
return 0;
198
}
199
200
static int sub_1510(KirkState *kirk, u8* data, int size, u8* result , int num)
201
{
202
memxor(data+20, result, 16);
203
204
int res = kirkSendCmd(kirk, data, size, num, true);
205
if(res)
206
return res;
207
208
memcpy(result, data+size+4, 16);
209
return 0;
210
}
211
212
static int sub_17A8(KirkState *kirk, u8* data)
213
{
214
if (kirk_sceUtilsBufferCopyWithRange(kirk, data, 20, 0, 0, 14) == 0)
215
return 0;
216
return -261;
217
}
218
219
static int sceSdGetLastIndex(u32 addressCtx, u32 addressHash, u32 addressKey) {
220
auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);
221
u8 *hash = Memory::GetPointerWrite(addressHash);
222
if (!ctx.IsValid() || !hash)
223
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
224
return hleLogDebug(Log::sceMisc, sceSdMacFinal(*ctx, hash, Memory::GetPointerWrite(addressKey)));
225
}
226
227
int sceSdMacFinal(pspChnnlsvContext1& ctx, u8* in_hash, const u8* in_key)
228
{
229
if(ctx.keyLength >= 17)
230
return -1026;
231
232
int num = numFromMode(ctx.mode);
233
234
memset(dataBuf2, 0, 16);
235
236
int res = kirkSendCmd(&g_kirk, dataBuf, 16, num, true);
237
if(res)
238
return res;
239
240
u8 data1[16], data2[16];
241
242
memcpy(data1, dataBuf2, 16);
243
int tmp1 = (data1[0] & 0x80) ? 135 : 0;
244
245
for(int i = 0; i < 15; i++)
246
{
247
u8 val1 = data1[i] << 1;
248
u8 val2 = data1[i+1] >> 7;
249
data1[i] = val1 | val2;
250
}
251
252
u8 tmp2 = data1[15] << 1;
253
tmp2 = tmp1 ^ tmp2;
254
data1[15] = tmp2;
255
256
if(ctx.keyLength < 16)
257
{
258
tmp1 = 0;
259
if((s8)data1[0] < 0)
260
{
261
tmp1 = 135;
262
}
263
for(int i = 0; i < 15; i++)
264
{
265
u8 val1 = data1[i] << 1;
266
u8 val2 = data1[i+1] >> 7;
267
data1[i] = val1 | val2;
268
}
269
u8 tmp2 = data1[15] << 1;
270
tmp2 = tmp1 ^ tmp2;
271
data1[15] = tmp2;
272
273
int oldKeyLength = ctx.keyLength;
274
*(s8*)(ctx.key + ctx.keyLength) = -128;
275
int i = oldKeyLength + 1;
276
if(i < 16)
277
memset(ctx.key + i, 0, 16 - i);
278
}
279
280
memxor(ctx.key, data1, 16);
281
memcpy(dataBuf2, ctx.key, 16);
282
memcpy(data2, ctx.result, 16);
283
284
int ret = sub_1510(&g_kirk, dataBuf, 16, data2, num);
285
if(ret)
286
return ret;
287
288
if(ctx.mode == 3 || ctx.mode == 4)
289
memxor(data2, hash198C, 16);
290
else if(ctx.mode == 5 || ctx.mode == 6)
291
memxor(data2, hash19BC, 16);
292
293
int cond = ((ctx.mode ^ 0x2) < 1 || (ctx.mode ^ 0x4) < 1 || ctx.mode == 6);
294
if(cond != 0)
295
{
296
memcpy(dataBuf2, data2, 16);
297
int ret = kirkSendFuseCmd(&g_kirk, dataBuf, 16, true);
298
if(ret)
299
return ret;
300
301
int res = kirkSendCmd(&g_kirk, dataBuf, 16, num, true);
302
if(res)
303
return res;
304
305
memcpy(data2, dataBuf2, 16);
306
}
307
308
if(in_key != 0)
309
{
310
for(int i = 0; i < 16; i++)
311
{
312
data2[i] = in_key[i] ^ data2[i];
313
}
314
315
memcpy(dataBuf2, data2, 16);
316
317
int res = kirkSendCmd(&g_kirk, dataBuf, 16, num, true);
318
if(res)
319
return res;
320
321
memcpy(data2, dataBuf2, 16);
322
}
323
memcpy(in_hash, data2, 16);
324
sceSdMacInit(ctx, 0);
325
326
return 0;
327
}
328
329
static int sceSdSetIndex(u32 addressCtx, int value) {
330
auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);
331
if (!ctx.IsValid())
332
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
333
return hleLogDebug(Log::sceMisc, sceSdMacInit(*ctx, value));
334
}
335
336
int sceSdMacInit(pspChnnlsvContext1& ctx, int value)
337
{
338
ctx.mode = value;
339
memset(ctx.result, 0, 16);
340
memset(ctx.key, 0, 16);
341
ctx.keyLength = 0;
342
return 0;
343
}
344
345
346
static int sceSdRemoveValue(u32 addressCtx, u32 addressData, int length) {
347
auto ctx = PSPPointer<pspChnnlsvContext1>::Create(addressCtx);
348
if (!ctx.IsValid() || !Memory::IsValidAddress(addressData))
349
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
350
return hleLogDebug(Log::sceMisc, sceSdMacUpdate(*ctx, Memory::GetPointerWrite(addressData), length));
351
}
352
353
int sceSdMacUpdate(pspChnnlsvContext1& ctx, const u8* data, int length)
354
{
355
if(ctx.keyLength >= 17)
356
return -1026;
357
358
if(ctx.keyLength + length < 17)
359
{
360
memcpy(ctx.key+ctx.keyLength, data, length);
361
ctx.keyLength = ctx.keyLength + length;
362
return 0;
363
}
364
int num = numFromMode(ctx.mode);
365
366
memset(dataBuf2, 0, 2048);
367
memcpy(dataBuf2, ctx.key, ctx.keyLength);
368
369
int len = (ctx.keyLength + length) & 0xF;
370
if(len == 0) len = 16;
371
372
int newSize = ctx.keyLength;
373
ctx.keyLength = len;
374
375
int diff = length - len;
376
memcpy(ctx.key, data+diff, len);
377
for(int i = 0; i < diff; i++)
378
{
379
if(newSize == 2048)
380
{
381
int res = sub_1510(&g_kirk, dataBuf, 2048, ctx.result, num);
382
if(res)
383
return res;
384
newSize = 0;
385
}
386
dataBuf2[newSize] = data[i];
387
newSize++;
388
}
389
if(newSize)
390
sub_1510(&g_kirk, dataBuf, newSize, ctx.result, num);
391
// The RE code showed this always returning 0. I suspect it would want to return res instead.
392
return 0;
393
}
394
395
static int sceSdCreateList(u32 ctx2Addr, int mode, int unkwn, u32 dataAddr, u32 cryptkeyAddr) {
396
auto ctx2 = PSPPointer<pspChnnlsvContext2>::Create(ctx2Addr);
397
u8* data = Memory::GetPointerWrite(dataAddr);
398
u8* cryptkey = Memory::GetPointerWrite(cryptkeyAddr);
399
if (!ctx2.IsValid() || !data)
400
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
401
402
return hleLogDebug(Log::sceMisc, sceSdCipherInit(*ctx2, mode, unkwn, data, cryptkey));
403
}
404
405
int sceSdCipherInit(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, const u8* cryptkey)
406
{
407
ctx2.mode = mode;
408
ctx2.unkn = 1;
409
if (uknw == 2)
410
{
411
memcpy(ctx2.cryptedData, data, 16);
412
if (cryptkey)
413
memxor(ctx2.cryptedData, cryptkey, 16);
414
415
return 0;
416
}
417
else if (uknw == 1)
418
{
419
u8 kirkHeader[37];
420
u8* kirkData = kirkHeader+20;
421
int res = sub_17A8(&g_kirk, kirkHeader);
422
if (res)
423
return res;
424
425
memcpy(kirkHeader+20, kirkHeader, 16);
426
memset(kirkHeader+32, 0, 4);
427
428
int type = typeFromMode(mode);
429
if (type == 87)
430
memxor(kirkData, key199C, 16);
431
else if (type == 100)
432
memxor(kirkData, key19CC, 16);
433
434
switch (mode)
435
{
436
case 2: case 4: case 6: res = kirkSendFuseCmd(&g_kirk, kirkHeader, 16, true);
437
break;
438
case 1: case 3: default:res = kirkSendCmd(&g_kirk, kirkHeader, 16, numFromMode2(mode), true);
439
break;
440
}
441
442
if (type == 87)
443
memxor(kirkData, key19AC, 16);
444
else if (type == 100)
445
memxor(kirkData, key19DC, 16);
446
447
if (res)
448
return res;
449
450
memcpy(ctx2.cryptedData, kirkData, 16);
451
memcpy(data, kirkData, 16);
452
if (cryptkey)
453
memxor(ctx2.cryptedData, cryptkey, 16);
454
}
455
456
return 0;
457
}
458
459
static int sceSdSetMember(u32 ctxAddr, u32 dataAddr, int alignedLen) {
460
auto ctx = PSPPointer<pspChnnlsvContext2>::Create(ctxAddr);
461
u8 *data = Memory::GetPointerWrite(dataAddr);
462
if (!ctx.IsValid() || !data)
463
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
464
465
return hleLogDebug(Log::sceMisc, sceSdCipherUpdate(*ctx, data, alignedLen));
466
}
467
468
int sceSdCipherUpdate(pspChnnlsvContext2& ctx, u8* data, int alignedLen)
469
{
470
if (alignedLen == 0)
471
{
472
return 0;
473
}
474
if ((alignedLen & 0xF) != 0)
475
{
476
return -1025;
477
}
478
int i = 0;
479
u8 kirkData[20+2048];
480
if ((u32)alignedLen >= (u32)2048)
481
{
482
for(i = 0; alignedLen >= 2048; i += 2048)
483
{
484
int ctx_unkn = ctx.unkn;
485
int res = sub_0000(&g_kirk, kirkData, data + i, 2048, ctx.cryptedData, ctx_unkn, ctx.mode);
486
ctx.unkn = ctx_unkn;
487
alignedLen -= 2048;
488
if (res)
489
return res;
490
}
491
}
492
if (alignedLen == 0)
493
{
494
return 0;
495
}
496
int ctx_unkn = ctx.unkn;
497
int res = sub_0000(&g_kirk, kirkData, data + i, alignedLen, ctx.cryptedData, ctx_unkn, ctx.mode);
498
ctx.unkn = ctx_unkn;
499
return res;
500
}
501
502
static int sceSdCleanList(u32 ctxAddr) {
503
auto ctx = PSPPointer<pspChnnlsvContext2>::Create(ctxAddr);
504
if (!ctx.IsValid())
505
return hleLogError(Log::sceMisc, 0, "Invalid pointer");
506
return hleLogDebug(Log::sceMisc, sceSdCipherFinal(*ctx));
507
}
508
509
int sceSdCipherFinal(pspChnnlsvContext2& ctx)
510
{
511
memset(ctx.cryptedData, 0, 16);
512
ctx.unkn = 0;
513
ctx.mode = 0;
514
515
return 0;
516
}
517
518
const HLEFunction sceChnnlsv[] =
519
{
520
{0XE7833020, &WrapI_UI<sceSdSetIndex>, "sceSdSetIndex", 'i', "xi" },
521
{0XF21A1FCA, &WrapI_UUI<sceSdRemoveValue>, "sceSdRemoveValue", 'i', "xxi" },
522
{0XC4C494F8, &WrapI_UUU<sceSdGetLastIndex>, "sceSdGetLastIndex", 'i', "xxx" },
523
{0XABFDFC8B, &WrapI_UIIUU<sceSdCreateList>, "sceSdCreateList", 'i', "xiixx"},
524
{0X850A7FA1, &WrapI_UUI<sceSdSetMember>, "sceSdSetMember", 'i', "xxi" },
525
{0X21BE78B4, &WrapI_U<sceSdCleanList>, "sceSdCleanList", 'i', "x" },
526
};
527
528
void Register_sceChnnlsv()
529
{
530
RegisterHLEModule("sceChnnlsv", ARRAY_SIZE(sceChnnlsv), sceChnnlsv);
531
kirk_init(&g_kirk);
532
}
533
534
// The below functions don't really belong to sceKernelSemaphore. They are the core crypto functionality,
535
// exposed through the confusingly named "sceUtilsBufferCopyWithRange" name, which Sony placed in the
536
// not-at-all-suspicious "semaphore" library, which has nothing to do with semaphores.
537
538
static u32 sceUtilsBufferCopyWithRange(u32 outAddr, int outSize, u32 inAddr, int inSize, int cmd) {
539
u8 *outAddress = Memory::IsValidRange(outAddr, outSize) ? Memory::GetPointerWriteUnchecked(outAddr) : nullptr;
540
u8 *inAddress = Memory::IsValidRange(inAddr, inSize) ? Memory::GetPointerWriteUnchecked(inAddr) : nullptr;
541
int temp = kirk_sceUtilsBufferCopyWithRange(&g_kirk, outAddress, outSize, inAddress, inSize, cmd);
542
if (temp != 0) {
543
ERROR_LOG(Log::sceKernel, "hleUtilsBufferCopyWithRange: Failed with %d", temp);
544
}
545
return hleNoLog(0);
546
}
547
548
// Note sure what difference there is between this and sceUtilsBufferCopyWithRange.
549
static int sceUtilsBufferCopyByPollingWithRange(u32 outAddr, int outSize, u32 inAddr, int inSize, int cmd) {
550
u8 *outAddress = Memory::IsValidRange(outAddr, outSize) ? Memory::GetPointerWriteUnchecked(outAddr) : nullptr;
551
u8 *inAddress = Memory::IsValidRange(inAddr, inSize) ? Memory::GetPointerWriteUnchecked(inAddr) : nullptr;
552
return hleNoLog(kirk_sceUtilsBufferCopyWithRange(&g_kirk, outAddress, outSize, inAddress, inSize, cmd));
553
}
554
555
const HLEFunction semaphore[] = {
556
{0x4C537C72, &WrapU_UIUII<sceUtilsBufferCopyWithRange>, "sceUtilsBufferCopyWithRange", 'x', "xixii" },
557
{0x77E97079, &WrapI_UIUII<sceUtilsBufferCopyByPollingWithRange>, "sceUtilsBufferCopyByPollingWithRange", 'i', "xixii" },
558
};
559
560
void Register_semaphore() {
561
RegisterHLEModule("semaphore", ARRAY_SIZE(semaphore), semaphore);
562
}
563
564