Skip to content

Commit

Permalink
Merge pull request #33 from KuromeSan/master
Browse files Browse the repository at this point in the history
Add support for "MCX.BIN" used by Vita's PocketStation Emulator
  • Loading branch information
ShendoXT authored Dec 16, 2022
2 parents 3fa5c37 + ea321b7 commit d52fa96
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 10 deletions.
13 changes: 9 additions & 4 deletions MemcardRex/GUI/mainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ private void openCardDialog()
OpenFileDialog openFileDlg = new OpenFileDialog
{
Title = "Open Memory Card",
Filter = "All supported|*.bin;*.ddf;*.gme;*.mc;*.mcd;*.mci;*.mcr;*.mem;*.ps;*.psm;*.srm;*.vgs;*.vm1;*.vmp|Standard Memory Card|*.mcr;*.bin;*.ddf;*.mc;*.mcd;*.mci;*.ps;*.psm;*.srm;*.VM1|PSP/Vita Memory Card|*.VMP|DexDrive Memory Card|*.gme|VGS Memory Card|*.mem;*.vgs|All files|*.*",
Filter = "All supported|*.bin;*.ddf;*.gme;*.mc;*.mcd;*.mci;*.mcr;*.mem;*.ps;*.psm;*.srm;*.vgs;*.vm1;*.vmp|Standard Memory Card|*.mcr;*.bin;*.ddf;*.mc;*.mcd;*.mci;*.ps;*.psm;*.srm;*.VM1|PSP/Vita Memory Card|*.VMP|Vita \"MCX\" PocketStation Memory Card|*.BIN|DexDrive Memory Card|*.gme|VGS Memory Card|*.mem;*.vgs|All files|*.*",
Multiselect = true
};

Expand Down Expand Up @@ -459,7 +459,7 @@ private void saveCardDialog(int listIndex)
SaveFileDialog saveFileDlg = new SaveFileDialog
{
Title = "Save Memory Card",
Filter = "Standard Memory Card|*.mcr;*.bin;*.ddf;*.mc;*.mcd;*.mci;*.ps;*.psm;*.srm;*.vm1|PSP/Vita Memory Card|*.VMP|DexDrive Memory Card|*.gme|VGS Memory Card|*.mem;*.vgs",
Filter = "Standard Memory Card|*.mcr;*.bin;*.ddf;*.mc;*.mcd;*.mci;*.ps;*.psm;*.srm;*.vm1|PSP/Vita Memory Card|*.VMP|Vita \"MCX\" PocketStation Memory Card|*.BIN|DexDrive Memory Card|*.gme|VGS Memory Card|*.mem;*.vgs",
FilterIndex = mainSettings.lastSaveFormat
};

Expand All @@ -482,13 +482,18 @@ private void saveCardDialog(int listIndex)
memoryCardType = 4;
break;

case 3: //GME Memory Card
case 3: //MCX Memory Card
memoryCardType = 5;
break;

case 4: //GME Memory Card
memoryCardType = 2;
break;

case 4: //VGS Memory Card
case 5: //VGS Memory Card
memoryCardType = 3;
break;

}
saveMemoryCard(listIndex, saveFileDlg.FileName, memoryCardType);
}
Expand Down
104 changes: 98 additions & 6 deletions MemcardRex/ps1card.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class ps1card
readonly byte[] saveKey = { 0xAB, 0x5A, 0xBC, 0x9F, 0xC1, 0xF4, 0x9D, 0xE6, 0xA0, 0x51, 0xDB, 0xAE, 0xFA, 0x51, 0x88, 0x59 };
readonly byte[] saveIv = { 0xB3, 0x0F, 0xFE, 0xED, 0xB7, 0xDC, 0x5E, 0xB7, 0x13, 0x3D, 0xA6, 0x0D, 0x1B, 0x6B, 0x2C, 0xDC };

readonly byte[] mcxKey = { 0x81, 0xD9, 0xCC, 0xE9, 0x71, 0xA9, 0x49, 0x9B, 0x04, 0xAD, 0xDC, 0x48, 0x30, 0x7F, 0x07, 0x92 };
readonly byte[] mcxIv = { 0x13, 0xC2, 0xE7, 0x69, 0x4B, 0xEC, 0x69, 0x6D, 0x52, 0xCF, 0x00, 0x09, 0x2A, 0xC1, 0xF2, 0x72 };

//Overwrite the contents of one byte array
private void FillByteArray(byte[] destination, int start, int fill)
{
Expand Down Expand Up @@ -96,6 +99,55 @@ private void XorWithIv(byte[] destBuffer, byte[] iv)
}
}

//Encrypts a buffer using AES CBC 128
private byte[] AesCbcEncrypt(byte[] toEncrypt, byte[] key, byte[] iv)
{
Aes aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;

using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
{
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter bnEncrypt = new BinaryWriter(csEncrypt))
{
bnEncrypt.Write(toEncrypt);
}
return msEncrypt.ToArray();
}
}
}
}

//Decrypts a buffer using AES CBC 128
private byte[] AesCbcDecrypt(byte[] toDecrypt, byte[] key, byte[] iv)
{
Aes aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;

using (ICryptoTransform decryptor = aes.CreateDecryptor(key, iv))
{
using (MemoryStream msDecrypt = new MemoryStream(toDecrypt))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (BinaryReader bnDecrypt = new BinaryReader(csDecrypt))
{
return bnDecrypt.ReadBytes(toDecrypt.Length - (toDecrypt.Length % 16));
}
}
}
}
}

//Encrypts a buffer using AES ECB 128
private byte[] AesEcbEncrypt(byte[] toEncrypt, byte[] key, byte[] iv)
{
Expand All @@ -105,7 +157,7 @@ private byte[] AesEcbEncrypt(byte[] toEncrypt, byte[] key, byte[] iv)
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.ECB;

using (ICryptoTransform encryptor = aes.CreateEncryptor(saveKey, saveIv))
using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
{
using (MemoryStream msEncrypt = new MemoryStream())
{
Expand All @@ -130,7 +182,7 @@ private byte[] AesEcbDecrypt(byte[] toDecrypt, byte[] key, byte[] iv)
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.ECB;

using (ICryptoTransform decryptor = aes.CreateDecryptor(saveKey, saveIv))
using (ICryptoTransform decryptor = aes.CreateDecryptor(key, iv))
{
using (MemoryStream msDecrypt = new MemoryStream(toDecrypt))
{
Expand Down Expand Up @@ -296,6 +348,39 @@ private byte[] GetHmac(byte[] data, byte[] saltSeed)

}

private byte[] DecryptMcxCard(byte[] rawCard)
{
byte[] mcxCard = new byte[0x200A0];
Array.Copy(rawCard, mcxCard, mcxCard.Length);
return AesCbcDecrypt(mcxCard, mcxKey, mcxIv);
}
// Check if a given card is a MCX image
private bool IsMcxCard(byte[] rawCard)
{
byte[] mcxCard = DecryptMcxCard(rawCard);
// Check for "MC" header 0x80 bytes in
if (mcxCard[0x80] == 'M' && mcxCard[0x81] == 'C')
return true;
else
return false;
}

//Generate encrypted MCX Memory Card
private byte[] MakeMcxCard(byte[] rawCard)
{
byte[] mcxCard = new byte[0x200A0];
byte[] hash;

Array.Copy(rawCard, 0, mcxCard, 0x80, 0x20000);

using (SHA256 sha = SHA256.Create())
hash = sha.ComputeHash(mcxCard, 0, 0x20080);

Array.Copy(hash, 0, mcxCard, 0x20080, 0x20);
Array.Copy(AesCbcEncrypt(mcxCard, mcxKey, mcxIv), 0, mcxCard, 0x0, 0x200A0);
return mcxCard;
}

//Generate signed VMP Memory Card
private byte[] MakeVmpCard(byte[] rawCard)
{
Expand Down Expand Up @@ -1119,6 +1204,9 @@ public bool saveMemoryCard(string fileName, int memoryCardType, bool fixData)
case 4: //VMP Memory Card
binWriter.Write(MakeVmpCard(rawMemoryCard));
break;
case 5: //MCX Memory Card
binWriter.Write(MakeMcxCard(rawMemoryCard));
break;
}

//Store the location of the Memory Card
Expand Down Expand Up @@ -1196,7 +1284,7 @@ public string openMemoryCard(string fileName, bool fixData)

//Put data into temp array
binReader.BaseStream.Read(tempData, 0, 134976);

//File is sucesfully read, close the stream
binReader.Close();

Expand All @@ -1210,9 +1298,14 @@ public string openMemoryCard(string fileName, bool fixData)
tempString = Encoding.ASCII.GetString(tempData, 0, 11).Trim((char)0x0, (char)0x1, (char)0x3F);
switch (tempString)
{
default: //File type is not supported
default: //File type is not supported or is MCX
if (IsMcxCard(tempData)) {
tempData = DecryptMcxCard(tempData);
startOffset = 128;
cardType = 5;
break;
}
return "'" + cardName + "' is not a supported Memory Card format.";

case "MC": //Standard raw Memory Card
startOffset = 0;
cardType = 1;
Expand All @@ -1239,7 +1332,6 @@ public string openMemoryCard(string fileName, bool fixData)

//Copy data to rawMemoryCard array with offset from input data
Array.Copy(tempData, startOffset, rawMemoryCard, 0, 131072);

//Load Memory Card data from raw card
loadDataFromRawCard();
}
Expand Down

0 comments on commit d52fa96

Please sign in to comment.