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