1
// Copyright 2013 Dolphin Emulator Project
2
// Licensed under GPLv2
3
// Refer to the license.txt file included.
5
// Most of the code in this file is from:
6
// GCNcrypt - Gamecube AR Crypto Program
7
// Copyright (C) 2003-2004 Parasyte
10
#include "ARDecrypt.h"
17
namespace ActionReplay
20
// Alphanumeric filter for text<->bin conversion
21
const char *filter = "0123456789ABCDEFGHJKMNPQRTUVWXYZILOS";
26
const u8 bitstringlen[0x08] = {
27
0x06, 0x0A, 0x0C, 0x11, 0x11, 0x08, 0x07, 0x20,
30
const u8 gentable0[0x38] = {
31
0x39, 0x31, 0x29, 0x21, 0x19, 0x11, 0x09, 0x01,
32
0x3A, 0x32, 0x2A, 0x22, 0x1A, 0x12, 0x0A, 0x02,
33
0x3B, 0x33, 0x2B, 0x23, 0x1B, 0x13, 0x0B, 0x03,
34
0x3C, 0x34, 0x2C, 0x24, 0x3F, 0x37, 0x2F, 0x27,
35
0x1F, 0x17, 0x0F, 0x07, 0x3E, 0x36, 0x2E, 0x26,
36
0x1E, 0x16, 0x0E, 0x06, 0x3D, 0x35, 0x2D, 0x25,
37
0x1D, 0x15, 0x0D, 0x05, 0x1C, 0x14, 0x0C, 0x04,
39
const u8 gentable1[0x08] = {
40
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
42
const u8 gentable2[0x10] = {
43
0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
44
0x0F, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1C,
46
const u8 gentable3[0x30] = {
47
0x0E, 0x11, 0x0B, 0x18, 0x01, 0x05, 0x03, 0x1C,
48
0x0F, 0x06, 0x15, 0x0A, 0x17, 0x13, 0x0C, 0x04,
49
0x1A, 0x08, 0x10, 0x07, 0x1B, 0x14, 0x0D, 0x02,
50
0x29, 0x34, 0x1F, 0x25, 0x2F, 0x37, 0x1E, 0x28,
51
0x33, 0x2D, 0x21, 0x30, 0x2C, 0x31, 0x27, 0x38,
52
0x22, 0x35, 0x2E, 0x2A, 0x32, 0x24, 0x1D, 0x20,
55
const u16 crctable0[0x10] = {
56
0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387,
57
0x8408, 0x9489, 0xA50A, 0xB58B, 0xC60C, 0xD68D, 0xE70E, 0xF78F,
59
const u16 crctable1[0x10] = {
60
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
61
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
64
const u8 gensubtable[0x08] = {
65
0x34, 0x1C, 0x84, 0x9E, 0xFD, 0xA4, 0xB6, 0x7B,
69
const u32 table0[0x40] = {
70
0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000,
71
0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,
72
0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404,
73
0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000,
74
0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400,
75
0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404,
76
0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400,
77
0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004,
79
const u32 table1[0x40] = {
80
0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020,
81
0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,
82
0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000,
83
0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020,
84
0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000,
85
0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000,
86
0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020,
87
0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000,
89
const u32 table2[0x40] = {
90
0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200,
91
0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,
92
0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208,
93
0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000,
94
0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000,
95
0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008,
96
0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008,
97
0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200,
99
const u32 table3[0x40] = {
100
0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001,
101
0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,
102
0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080,
103
0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081,
104
0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000,
105
0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
106
0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081,
107
0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080,
109
const u32 table4[0x40] = {
110
0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000,
111
0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,
112
0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100,
113
0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100,
114
0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100,
115
0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000,
116
0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000,
117
0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100,
119
const u32 table5[0x40] = {
120
0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000,
121
0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,
122
0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010,
123
0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000,
124
0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010,
125
0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000,
126
0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010,
127
0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010,
129
const u32 table6[0x40] = {
130
0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800,
131
0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,
132
0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002,
133
0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800,
134
0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002,
135
0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800,
136
0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802,
137
0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002,
139
const u32 table7[0x40] = {
140
0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000,
141
0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,
142
0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000,
143
0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000,
144
0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040,
145
0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040,
146
0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000,
147
0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000,
151
void generateseeds(u32 *seeds, const u8 *seedtable, u8 doreverse)
155
u8 array0[0x38],array1[0x38],array2[0x08];
161
tmp = (gentable0[i] - 1);
162
array0[i++] = ((u32)(0-(seedtable[tmp>>3] & gentable1[tmp&7])) >> 31);
171
for (j = 0; j < 0x38; j++)
177
if (tmp > 0x37) tmp-=0x1C;
179
else if (tmp > 0x1B) tmp-=0x1C;
181
array1[j] = array0[tmp];
183
for (j = 0; j < 0x30; j++)
185
if (!array1[gentable3[j]-1]) continue;
186
tmp = (((j*0x2AAB)>>16) - (j>>0x1F));
187
array2[tmp] |= (gentable1[j-(tmp*6)]>>2);
189
seeds[i<<1] = ((array2[0]<<24)|(array2[2]<<16)|(array2[4]<<8)|array2[6]);
190
seeds[(i<<1)+1] = ((array2[1]<<24)|(array2[3]<<16)|(array2[5]<<8)|array2[7]);
197
for (i = 0; i < 16; i+=2)
200
seeds[i] = seeds[j-1];
204
seeds[i+1] = seeds[j];
213
generateseeds(genseeds,gensubtable,0);
216
void getcode(u32 *src, u32 *addr, u32 *val)
218
*addr = Common::swap32(src[0]);
219
*val = Common::swap32(src[1]);
222
void setcode(u32 *dst, u32 addr, u32 val)
224
dst[0] = Common::swap32(addr);
225
dst[1] = Common::swap32(val);
228
u16 gencrc16(u32 *codes, u16 size)
238
for (i = 0; i < 4; i++)
240
tmp2 = ((codes[tmp] >> (i<<3))^ret);
241
ret = ((crctable0[(tmp2>>4)&0x0F]^crctable1[tmp2&0x0F])^(ret>>8));
249
u8 verifycode(u32 *codes, u16 size)
253
tmp = gencrc16(codes,size);
254
return (((tmp>>12)^(tmp>>8)^(tmp>>4)^tmp)&0x0F);
257
void unscramble1(u32 *addr, u32 *val)
261
*val = _rotl(*val,4);
263
tmp = ((*addr^*val)&0xF0F0F0F0);
265
*val = _rotr((*val^tmp),0x14);
267
tmp = ((*addr^*val)&0xFFFF0000);
269
*val = _rotr((*val^tmp),0x12);
271
tmp = ((*addr^*val)&0x33333333);
273
*val = _rotr((*val^tmp),6);
275
tmp = ((*addr^*val)&0x00FF00FF);
277
*val = _rotl((*val^tmp),9);
279
tmp = ((*addr^*val)&0xAAAAAAAA);
280
*addr = _rotl((*addr^tmp),1);
284
void unscramble2(u32 *addr, u32 *val)
288
*val = _rotr(*val,1);
290
tmp = ((*addr^*val)&0xAAAAAAAA);
292
*addr = _rotr((*addr^tmp),9);
294
tmp = ((*addr^*val)&0x00FF00FF);
296
*addr = _rotl((*addr^tmp),6);
298
tmp = ((*addr^*val)&0x33333333);
300
*addr = _rotl((*addr^tmp),0x12);
302
tmp = ((*addr^*val)&0xFFFF0000);
304
*addr = _rotl((*addr^tmp),0x14);
306
tmp = ((*addr^*val)&0xF0F0F0F0);
308
*addr = _rotr((*addr^tmp),4);
311
void decryptcode(u32 *seeds, u32 *code)
317
getcode(code,&addr,&val);
318
unscramble1(&addr,&val);
321
tmp = (_rotr(val,4)^seeds[i++]);
322
tmp2 = (val^seeds[i++]);
323
addr ^= (table6[tmp&0x3F]^table4[(tmp>>8)&0x3F]^table2[(tmp>>16)&0x3F]^table0[(tmp>>24)&0x3F]^table7[tmp2&0x3F]^table5[(tmp2>>8)&0x3F]^table3[(tmp2>>16)&0x3F]^table1[(tmp2>>24)&0x3F]);
325
tmp = (_rotr(addr,4)^seeds[i++]);
326
tmp2 = (addr^seeds[i++]);
327
val ^= (table6[tmp&0x3F]^table4[(tmp>>8)&0x3F]^table2[(tmp>>16)&0x3F]^table0[(tmp>>24)&0x3F]^table7[tmp2&0x3F]^table5[(tmp2>>8)&0x3F]^table3[(tmp2>>16)&0x3F]^table1[(tmp2>>24)&0x3F]);
329
unscramble2(&addr,&val);
330
setcode(code,val,addr);
333
bool getbitstring(u32 *ctrl, u32 *out, u8 len)
335
u32 tmp=(ctrl[0]+(ctrl[1]<<2));
344
tmp = (ctrl[0]+(ctrl[1]<<2));
346
if (ctrl[1] >= ctrl[3]) return false;
347
*out = ((*out<<1) | ((tmp >> (0x1F-ctrl[2])) & 1));
353
bool batchdecrypt(u32 *codes, u16 size)
356
u32 tmparray[4] = { 0 },tmparray2[8] = { 0 };
359
//if (size & 1) return 0;
360
//if (!size) return 0;
365
decryptcode(genseeds,ptr);
369
tmparray[0] = *codes;
371
tmparray[2] = 4; // Skip crc
373
getbitstring(tmparray,tmparray2+1,11); // Game id
374
getbitstring(tmparray,tmparray2+2,17); // Code id
375
getbitstring(tmparray,tmparray2+3,1); // Master code
376
getbitstring(tmparray,tmparray2+4,1); // Unknown
377
getbitstring(tmparray,tmparray2+5,2); // Region
379
// Grab gameid and region from the last decrypted code
380
// Maybe check this against dolphin's GameID? - "code is for wrong game" type msg
381
//gameid = tmparray2[1];
382
//region = tmparray2[5];
385
codes[0] &= 0x0FFFFFFF;
386
if ((tmp>>28) != verifycode(codes,size)) return false;
390
// Unfinished (so says Parasyte :p )
393
int GetVal(const char *flt, char chr)
395
int ret = (int)(strchr(flt,chr) - flt);
412
int alphatobin(u32 *dst, std::vector<std::string> alpha, int size)
415
int ret=0,org=(size+1);
422
for (i = 0; i < 6; i++)
424
bin[0] |= (GetVal(filter,alpha[j>>1][i]) << (((5-i)*5)+2));
426
bin[0] |= (GetVal(filter,alpha[j>>1][6]) >> 3);
430
for (i = 0; i < 6; i++)
432
bin[1] |= (GetVal(filter,alpha[j>>1][i+6]) << (((5-i)*5)+4));
434
bin[1] |= (GetVal(filter,alpha[j>>1][12]) >> 1);
440
for (i = 0; i < 64; i++)
443
parity ^= (bin[k] >> (i-(k<<5)));
445
if ((parity&1) != (GetVal(filter,alpha[(j-2)>>1][12])&1)) ret=(org-size);
453
void DecryptARCode(std::vector<std::string> vCodes, std::vector<AREntry> &ops)
455
// The almighty buildseeds() function!! without this, the crypto routines are useless
461
for(i = 0; i < vCodes.size(); ++i)
463
transform(vCodes[i].begin(), vCodes[i].end(), vCodes[i].begin(), toupper);
464
//PanicAlert("Encrypted AR Code\n%s", vCodes[i].c_str());
467
if ((ret=alphatobin(uCodes, vCodes, (int)vCodes.size())))
469
PanicAlertT("Action Replay Code Decryption Error:\nParity Check Failed\n\nCulprit Code:\n%s", vCodes[ret].c_str());
470
batchdecrypt(uCodes, (u16)vCodes.size()<<1);
472
else if (!batchdecrypt(uCodes, (u16)vCodes.size()<<1))
474
// Commented out since we just send the code anyways and hope for the best XD
475
//PanicAlert("Action Replay Code Decryption Error:\nCRC Check Failed\n\n"
476
// "First Code in Block(should be verification code):\n%s", vCodes[0].c_str());
478
for (i = 0; i < (vCodes.size()<<1); i+=2)
481
op.cmd_addr = uCodes[i];
482
op.value = uCodes[i+1];
484
//PanicAlert("Decrypted AR Code without verification code:\n%08X %08X", uCodes[i], uCodes[i+1]);
489
// Skip passing the verification code back
490
for (i = 2; i < (vCodes.size()<<1); i+=2)
493
op.cmd_addr = uCodes[i];
494
op.value = uCodes[i+1];
496
//PanicAlert("Decrypted AR Code:\n%08X %08X", uCodes[i], uCodes[i+1]);
501
} //namespace ActionReplay