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
memxor(void * dest,const void * src,size_t n)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.
numFromMode(int mode)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 }
numFromMode2(int mode)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
typeFromMode(int mode)88 static int typeFromMode(int mode)
89 {
90 return (mode == 1 || mode == 2) ? 83 :
91 ((mode == 3 || mode == 4) ? 87 : 100);
92 }
93
kirkSendCmd(u8 * data,int length,int num,bool encrypt)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
kirkSendFuseCmd(u8 * data,int length,bool encrypt)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
sub_15B0(u8 * data,int alignedLen,u8 * buf,int val)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
sub_0000(u8 * data_out,u8 * data,int alignedLen,u8 * data2,int & data3,int mode)137 static int sub_0000(u8* data_out, u8* data, int alignedLen, 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
sub_1510(u8 * data,int size,u8 * result,int num)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
sub_17A8(u8 * data)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
sceSdGetLastIndex(u32 addressCtx,u32 addressHash,u32 addressKey)217 static int sceSdGetLastIndex(u32 addressCtx, u32 addressHash, u32 addressKey)
218 {
219 pspChnnlsvContext1 ctx;
220 Memory::ReadStruct(addressCtx, &ctx);
221 int res = sceSdGetLastIndex_(ctx, Memory::GetPointer(addressHash), Memory::GetPointer(addressKey));
222 Memory::WriteStruct(addressCtx, &ctx);
223 return res;
224 }
225
sceSdGetLastIndex_(pspChnnlsvContext1 & ctx,u8 * in_hash,u8 * in_key)226 int sceSdGetLastIndex_(pspChnnlsvContext1& ctx, u8* in_hash, u8* in_key)
227 {
228 if(ctx.keyLength >= 17)
229 return -1026;
230
231 int num = numFromMode(ctx.mode);
232
233 memset(dataBuf2, 0, 16);
234
235 int res = kirkSendCmd(dataBuf, 16, num, true);
236 if(res)
237 return res;
238
239 u8 data1[16], data2[16];
240
241 memcpy(data1, dataBuf2, 16);
242 int tmp1 = (data1[0] & 0x80) ? 135 : 0;
243
244 for(int i = 0; i < 15; i++)
245 {
246 u8 val1 = data1[i] << 1;
247 u8 val2 = data1[i+1] >> 7;
248 data1[i] = val1 | val2;
249 }
250
251 u8 tmp2 = data1[15] << 1;
252 tmp2 = tmp1 ^ tmp2;
253 data1[15] = tmp2;
254
255 if(ctx.keyLength < 16)
256 {
257 tmp1 = 0;
258 if((s8)data1[0] < 0)
259 {
260 tmp1 = 135;
261 }
262 for(int i = 0; i < 15; i++)
263 {
264 u8 val1 = data1[i] << 1;
265 u8 val2 = data1[i+1] >> 7;
266 data1[i] = val1 | val2;
267 }
268 u8 tmp2 = data1[15] << 1;
269 tmp2 = tmp1 ^ tmp2;
270 data1[15] = tmp2;
271
272 int oldKeyLength = ctx.keyLength;
273 *(s8*)(ctx.key + ctx.keyLength) = -128;
274 int i = oldKeyLength + 1;
275 if(i < 16)
276 memset(ctx.key + i, 0, 16 - i);
277 }
278
279 memxor(ctx.key, data1, 16);
280 memcpy(dataBuf2, ctx.key, 16);
281 memcpy(data2, ctx.result, 16);
282
283 int ret = sub_1510(dataBuf, 16, data2, num);
284 if(ret)
285 return ret;
286
287 if(ctx.mode == 3 || ctx.mode == 4)
288 memxor(data2, hash198C, 16);
289 else if(ctx.mode == 5 || ctx.mode == 6)
290 memxor(data2, hash19BC, 16);
291
292 int cond = ((ctx.mode ^ 0x2) < 1 || (ctx.mode ^ 0x4) < 1 || ctx.mode == 6);
293 if(cond != 0)
294 {
295 memcpy(dataBuf2, data2, 16);
296 int ret = kirkSendFuseCmd(dataBuf, 16, true);
297 if(ret)
298 return ret;
299
300 int res = kirkSendCmd(dataBuf, 16, num, true);
301 if(res)
302 return res;
303
304 memcpy(data2, dataBuf2, 16);
305 }
306
307 if(in_key != 0)
308 {
309 for(int i = 0; i < 16; i++)
310 {
311 data2[i] = in_key[i] ^ data2[i];
312 }
313
314 memcpy(dataBuf2, data2, 16);
315
316 int res = kirkSendCmd(dataBuf, 16, num, true);
317 if(res)
318 return res;
319
320 memcpy(data2, dataBuf2, 16);
321 }
322 memcpy(in_hash, data2, 16);
323 sceSdSetIndex_(ctx, 0);
324
325 return 0;
326 }
327
sceSdSetIndex(u32 addressCtx,int value)328 static int sceSdSetIndex(u32 addressCtx, int value)
329 {
330 pspChnnlsvContext1 ctx;
331 Memory::ReadStruct(addressCtx,&ctx);
332 int res = sceSdSetIndex_(ctx, value);
333 Memory::WriteStruct(addressCtx,&ctx);
334 return res;
335 }
336
sceSdSetIndex_(pspChnnlsvContext1 & ctx,int value)337 int sceSdSetIndex_(pspChnnlsvContext1& ctx, int value)
338 {
339 ctx.mode = value;
340 memset(ctx.result, 0, 16);
341 memset(ctx.key, 0, 16);
342 ctx.keyLength = 0;
343 return 0;
344 }
345
346
sceSdRemoveValue(u32 addressCtx,u32 addressData,int length)347 static int sceSdRemoveValue(u32 addressCtx, u32 addressData, int length)
348 {
349 pspChnnlsvContext1 ctx;
350 Memory::ReadStruct(addressCtx, &ctx);
351 int res = sceSdRemoveValue_(ctx, Memory::GetPointer(addressData), length);
352 Memory::WriteStruct(addressCtx, &ctx);
353
354 return res;
355 }
356
sceSdRemoveValue_(pspChnnlsvContext1 & ctx,u8 * data,int length)357 int sceSdRemoveValue_(pspChnnlsvContext1& ctx, u8* data, int length)
358 {
359 if(ctx.keyLength >= 17)
360 return -1026;
361
362 if(ctx.keyLength + length < 17)
363 {
364 memcpy(ctx.key+ctx.keyLength, data, length);
365 ctx.keyLength = ctx.keyLength + length;
366 return 0;
367 }
368 int num = numFromMode(ctx.mode);
369
370 memset(dataBuf2, 0, 2048);
371 memcpy(dataBuf2, ctx.key, ctx.keyLength);
372
373 int len = (ctx.keyLength + length) & 0xF;
374 if(len == 0) len = 16;
375
376 int newSize = ctx.keyLength;
377 ctx.keyLength = len;
378
379 int diff = length - len;
380 memcpy(ctx.key, data+diff, len);
381 for(int i = 0; i < diff; i++)
382 {
383 if(newSize == 2048)
384 {
385 int res = sub_1510(dataBuf, 2048, ctx.result, num);
386 if(res)
387 return res;
388 newSize = 0;
389 }
390 dataBuf2[newSize] = data[i];
391 newSize++;
392 }
393 if(newSize)
394 sub_1510(dataBuf, newSize, ctx.result, num);
395 // The RE code showed this always returning 0. I suspect it would want to return res instead.
396 return 0;
397 }
398
sceSdCreateList(u32 ctx2Addr,int mode,int unkwn,u32 dataAddr,u32 cryptkeyAddr)399 static int sceSdCreateList(u32 ctx2Addr, int mode, int unkwn, u32 dataAddr, u32 cryptkeyAddr)
400 {
401 pspChnnlsvContext2 ctx2;
402 Memory::ReadStruct(ctx2Addr, &ctx2);
403 u8* data = Memory::GetPointer(dataAddr);
404 u8* cryptkey = Memory::GetPointer(cryptkeyAddr);
405
406 int res = sceSdCreateList_(ctx2, mode, unkwn, data, cryptkey);
407
408 Memory::WriteStruct(ctx2Addr, &ctx2);
409
410 return res;
411 }
412
sceSdCreateList_(pspChnnlsvContext2 & ctx2,int mode,int uknw,u8 * data,u8 * cryptkey)413 int sceSdCreateList_(pspChnnlsvContext2& ctx2, int mode, int uknw, u8* data, u8* cryptkey)
414 {
415 ctx2.mode = mode;
416 ctx2.unkn = 1;
417 if (uknw == 2)
418 {
419 memcpy(ctx2.cryptedData, data, 16);
420 if (cryptkey)
421 memxor(ctx2.cryptedData, cryptkey, 16);
422
423 return 0;
424 }
425 else if (uknw == 1)
426 {
427 u8 kirkHeader[37];
428 u8* kirkData = kirkHeader+20;
429 int res = sub_17A8(kirkHeader);
430 if (res)
431 return res;
432
433 memcpy(kirkHeader+20, kirkHeader, 16);
434 memset(kirkHeader+32, 0, 4);
435
436 int type = typeFromMode(mode);
437 if (type == 87)
438 memxor(kirkData, key199C, 16);
439 else if (type == 100)
440 memxor(kirkData, key19CC, 16);
441
442 switch (mode)
443 {
444 case 2: case 4: case 6: res = kirkSendFuseCmd(kirkHeader, 16, true);
445 break;
446 case 1: case 3: default:res = kirkSendCmd(kirkHeader, 16, numFromMode2(mode), true);
447 break;
448 }
449
450 if (type == 87)
451 memxor(kirkData, key19AC, 16);
452 else if (type == 100)
453 memxor(kirkData, key19DC, 16);
454
455 if (res)
456 return res;
457
458 memcpy(ctx2.cryptedData, kirkData, 16);
459 memcpy(data, kirkData, 16);
460 if (cryptkey)
461 memxor(ctx2.cryptedData, cryptkey, 16);
462 }
463
464 return 0;
465 }
466
sceSdSetMember(u32 ctxAddr,u32 dataAddr,int alignedLen)467 static int sceSdSetMember(u32 ctxAddr, u32 dataAddr, int alignedLen)
468 {
469 pspChnnlsvContext2 ctx;
470 Memory::ReadStruct(ctxAddr, &ctx);
471 u8* data = Memory::GetPointer(dataAddr);
472
473 int res = sceSdSetMember_(ctx, data, alignedLen);
474
475 Memory::WriteStruct(ctxAddr, &ctx);
476
477 return res;
478 }
479
sceSdSetMember_(pspChnnlsvContext2 & ctx,u8 * data,int alignedLen)480 int sceSdSetMember_(pspChnnlsvContext2& ctx, u8* data, int alignedLen)
481 {
482 if (alignedLen == 0)
483 {
484 return 0;
485 }
486 if ((alignedLen & 0xF) != 0)
487 {
488 return -1025;
489 }
490 int i = 0;
491 u8 kirkData[20+2048];
492 if ((u32)alignedLen >= (u32)2048)
493 {
494 for(i = 0; alignedLen >= 2048; i += 2048)
495 {
496 int ctx_unkn = ctx.unkn;
497 int res = sub_0000(kirkData, data + i, 2048, ctx.cryptedData, ctx_unkn, ctx.mode);
498 ctx.unkn = ctx_unkn;
499 alignedLen -= 2048;
500 if (res)
501 return res;
502 }
503 }
504 if (alignedLen == 0)
505 {
506 return 0;
507 }
508 int ctx_unkn = ctx.unkn;
509 int res = sub_0000(kirkData, data + i, alignedLen, ctx.cryptedData, ctx_unkn, ctx.mode);
510 ctx.unkn = ctx_unkn;
511 return res;
512 }
513
sceChnnlsv_21BE78B4(u32 ctxAddr)514 static int sceChnnlsv_21BE78B4(u32 ctxAddr)
515 {
516 pspChnnlsvContext2 ctx;
517 Memory::ReadStruct(ctxAddr, &ctx);
518
519 int res = sceChnnlsv_21BE78B4_(ctx);
520
521 Memory::WriteStruct(ctxAddr, &ctx);
522 return res;
523 }
524
sceChnnlsv_21BE78B4_(pspChnnlsvContext2 & ctx)525 int sceChnnlsv_21BE78B4_(pspChnnlsvContext2& ctx)
526 {
527 memset(ctx.cryptedData, 0, 16);
528 ctx.unkn = 0;
529 ctx.mode = 0;
530
531 return 0;
532 }
533
534 const HLEFunction sceChnnlsv[] =
535 {
536 {0XE7833020, &WrapI_UI<sceSdSetIndex>, "sceSdSetIndex", 'i', "xi" },
537 {0XF21A1FCA, &WrapI_UUI<sceSdRemoveValue>, "sceSdRemoveValue", 'i', "xxi" },
538 {0XC4C494F8, &WrapI_UUU<sceSdGetLastIndex>, "sceSdGetLastIndex", 'i', "xxx" },
539 {0XABFDFC8B, &WrapI_UIIUU<sceSdCreateList>, "sceSdCreateList", 'i', "xiixx"},
540 {0X850A7FA1, &WrapI_UUI<sceSdSetMember>, "sceSdSetMember", 'i', "xxi" },
541 {0X21BE78B4, &WrapI_U<sceChnnlsv_21BE78B4>, "sceChnnlsv_21BE78B4", 'i', "x" },
542 };
543
Register_sceChnnlsv()544 void Register_sceChnnlsv()
545 {
546 RegisterModule("sceChnnlsv", ARRAY_SIZE(sceChnnlsv), sceChnnlsv);
547 kirk_init();
548 }
549