Skip to content

Commit dc9f81d

Browse files
authored
decrypt response table
1 parent 9fb4f20 commit dc9f81d

File tree

1 file changed

+100
-53
lines changed

1 file changed

+100
-53
lines changed

MPF.Processors/ProcessingTool.cs

Lines changed: 100 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#if NET35_OR_GREATER || NETCOREAPP
44
using System.Linq;
55
#endif
6+
using System.Security.Cryptography;
67
using System.Text;
78
using System.Text.RegularExpressions;
89
using System.Xml;
@@ -1168,7 +1169,7 @@ public static bool IsFixedSS(byte[] ss)
11681169
if (!GetXGDType(ss, out int xgdType))
11691170
return false;
11701171

1171-
// Valid XGD1 is always fixed
1172+
// XGD1 can't be fixed
11721173
if (xgdType == 1)
11731174
return true;
11741175

@@ -1209,7 +1210,7 @@ public static bool IsFixedSS(byte[] ss)
12091210
if (ss[rtOffset + 67] != 0x01)
12101211
return false;
12111212
}
1212-
else
1213+
else if (xgdType == 2)
12131214
{
12141215
// Check for a cleaned XGD2
12151216
int rtOffset = 0x204;
@@ -1247,33 +1248,8 @@ public static bool IsFixedSS(byte[] ss)
12471248
return false;
12481249
}
12491250

1250-
// Determine challenge table offset
1251-
int ccrt_offset = 0;
1252-
if (xgdType == 2)
1253-
ccrt_offset = 0x200;
1254-
else if (xgdType == 3)
1255-
ccrt_offset = 0x20;
1256-
1257-
// Check for empty challenge responses
1258-
int[] entry_offsets = [0, 9, 18, 27, 36, 45, 54, 63];
1259-
int[] entry_lengths = [8, 8, 8, 8, 4, 4, 4, 4];
1260-
for (int i = 0; i < entry_offsets.Length; i++)
1261-
{
1262-
bool emptyResponse = true;
1263-
for (int b = 0; b < entry_lengths[i]; b++)
1264-
{
1265-
if (ss[ccrt_offset + entry_offsets[i] + b] != 0x00)
1266-
{
1267-
emptyResponse = false;
1268-
break;
1269-
}
1270-
}
1271-
1272-
if (emptyResponse)
1273-
return false;
1274-
}
1275-
1276-
// TODO: Check for correct challenge responses
1251+
// Check challenge responses
1252+
FixSS(ss, false);
12771253

12781254
return true;
12791255
}
@@ -1306,7 +1282,7 @@ public static bool FixSS(string rawSS, string fixedSS)
13061282
/// </summary>
13071283
/// <param name="ss">Byte array of raw SS sector</param>
13081284
/// <returns>True if successful, false otherwise</returns>
1309-
public static bool FixSS(byte[] ss)
1285+
public static bool FixSS(byte[] ss, bool write = true)
13101286
{
13111287
// Must be entire sector
13121288
if (ss.Length != 2048)
@@ -1337,34 +1313,37 @@ public static bool FixSS(byte[] ss)
13371313
switch (xgdType)
13381314
{
13391315
case 1:
1340-
// Cannot clean XGD1 SS.bin
1341-
break;
1316+
// Cannot clean or fix XGD1 SS
1317+
return true;
13421318

13431319
case 2:
13441320
// Fix standard SSv1 ss.bin
1345-
ss[552] = 1; // 0x01
1346-
ss[553] = 0; // 0x00
1347-
ss[555] = 0; // 0x00
1348-
ss[556] = 0; // 0x00
1349-
1350-
ss[561] = 91; // 0x5B
1351-
ss[562] = 0; // 0x00
1352-
ss[564] = 0; // 0x00
1353-
ss[565] = 0; // 0x00
1354-
1355-
ss[570] = 181; // 0xB5
1356-
ss[571] = 0; // 0x00
1357-
ss[573] = 0; // 0x00
1358-
ss[574] = 0; // 0x00
1359-
1360-
ss[579] = 15; // 0x0F
1361-
ss[580] = 1; // 0x01
1362-
ss[582] = 0; // 0x00
1363-
ss[583] = 0; // 0x00
1321+
if (write)
1322+
{
1323+
ss[552] = 1; // 0x01
1324+
ss[553] = 0; // 0x00
1325+
ss[555] = 0; // 0x00
1326+
ss[556] = 0; // 0x00
1327+
1328+
ss[561] = 91; // 0x5B
1329+
ss[562] = 0; // 0x00
1330+
ss[564] = 0; // 0x00
1331+
ss[565] = 0; // 0x00
1332+
1333+
ss[570] = 181; // 0xB5
1334+
ss[571] = 0; // 0x00
1335+
ss[573] = 0; // 0x00
1336+
ss[574] = 0; // 0x00
1337+
1338+
ss[579] = 15; // 0x0F
1339+
ss[580] = 1; // 0x01
1340+
ss[582] = 0; // 0x00
1341+
ss[583] = 0; // 0x00
1342+
}
13641343
break;
13651344

13661345
case 3:
1367-
if (ssv2)
1346+
if (write && ssv2)
13681347
{
13691348
ss[72] = 1; // 0x01
13701349
ss[73] = 0; // 0x00
@@ -1386,7 +1365,7 @@ public static bool FixSS(byte[] ss)
13861365
ss[102] = 15; // 0x0F
13871366
ss[103] = 1; // 0x01
13881367
}
1389-
else
1368+
else if (write)
13901369
{
13911370
ss[552] = 1; // 0x01
13921371
ss[553] = 0; // 0x00
@@ -1407,6 +1386,74 @@ public static bool FixSS(byte[] ss)
14071386
return false;
14081387
}
14091388

1389+
// Determine challenge table offset
1390+
int ccrt_offset = 0;
1391+
if (xgdType == 2)
1392+
ccrt_offset = 0x200;
1393+
else if (xgdType == 3)
1394+
ccrt_offset = 0x20;
1395+
1396+
// Setup decryptor
1397+
#if NET20
1398+
using RijndaelManaged aes = new RijndaelManaged();
1399+
aes.BlockSize = 128;
1400+
#else
1401+
using Aes aes = Aes.Create();
1402+
#endif
1403+
aes.Key = new byte[] { 0xD1, 0xE3, 0xB3, 0x3A, 0x6C, 0x1E, 0xF7, 0x70, 0x5F, 0x6D, 0xE9, 0x3B, 0xB6, 0xC0, 0xDC, 0x71 };
1404+
aes.Mode = CipherMode.ECB;
1405+
aes.Padding = PaddingMode.None;
1406+
using ICryptoTransform decryptor = aes.CreateDecryptor();
1407+
1408+
// Perform decryption
1409+
byte[] iv = new byte[16];
1410+
byte[] dcrt = new byte[252];
1411+
bool ct01_found = false;
1412+
for (int i = 0; i < 240; i+=16)
1413+
{
1414+
decryptor.TransformBlock(ss, 0x304 + i, 16, dcrt, i);
1415+
for (int j = 0; j < 16; j++)
1416+
{
1417+
dcrt[i + j] ^= iv[j];
1418+
iv[j] = ss[0x304 + i + j];
1419+
}
1420+
// Validate challenge type 1
1421+
if (dcrt[i] == 1)
1422+
{
1423+
// Cannot fix SS with two type 1 challenges
1424+
if (ct01_found)
1425+
return false;
1426+
ct01_found = true;
1427+
// Challenge type 1 must match CPR_MAI
1428+
int cpr_mai_offset = (xgdType == 3) ? 0xF0 : 0x2D0;
1429+
if (dcrt[i + 4] != ss[cpr_mai_offset] || dcrt[i + 5] != ss[cpr_mai_offset + 1] || dcrt[i + 6] != ss[cpr_mai_offset + 2] || dcrt[i + 7] != ss[cpr_mai_offset + 3])
1430+
return false;
1431+
}
1432+
// Cannot fix unknown challenge types
1433+
else if (dcrt[i] != 0xE0 && dcrt[i] != 0x14 && dcrt[i] != 0x15 && dcrt[i] != 0x24 && dcrt[i] != 0x25 && (dcrt[i] & 0xF) != 0xF0)
1434+
return false;
1435+
}
1436+
Array.Copy(ss, 0x304 + 240, dcrt, 240, 12);
1437+
1438+
// Check for empty challenge responses
1439+
int[] entryOffsets = [0, 9, 18, 27, 36, 45, 54, 63];
1440+
int[] entryLengths = [8, 8, 8, 8, 4, 4, 4, 4];
1441+
for (int i = 0; i < entryOffsets.Length; i++)
1442+
{
1443+
bool emptyResponse = true;
1444+
for (int b = 0; b < entryLengths[i]; b++)
1445+
{
1446+
if (ss[ccrt_offset + entryOffsets[i] + b] != 0x00)
1447+
{
1448+
emptyResponse = false;
1449+
break;
1450+
}
1451+
}
1452+
1453+
if (emptyResponse)
1454+
return false;
1455+
}
1456+
14101457
// TODO: Repair challenge responses
14111458

14121459
return true;

0 commit comments

Comments
 (0)