chovy-trans/CHOVY-TRANSFER/PSVMDBuilder.cs

209 lines
7.5 KiB
C#

using Ionic.Zlib;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace PSVIMGTOOLS
{
class PSVMDBuilder
{
private static void memset(byte[] buf, byte content, long length)
{
for (int i = 0; i < length; i++)
{
buf[i] = content;
}
}
private static void writeUInt64(Stream dst, UInt64 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x8);
}
private static void writeInt64(Stream dst, Int64 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x8);
}
private static void writeUInt16(Stream dst, UInt16 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x2);
}
private static void writeInt16(Stream dst, Int16 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x2);
}
private static void writeInt32(Stream dst, Int32 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x4);
}
private static void writeUInt32(Stream dst, UInt32 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x4);
}
private static void writeString(Stream dst, string str, int len = -1)
{
if (len < 0)
{
len = str.Length;
}
byte[] StrBytes = Encoding.UTF8.GetBytes(str);
dst.Write(StrBytes, 0x00, len);
}
private static void writePadding(Stream dst, byte paddingByte, long paddingLen)
{
byte[] paddingData = new byte[paddingLen];
memset(paddingData, paddingByte, paddingLen);
dst.Write(paddingData, 0x00, paddingData.Length);
}
private static void writeStringWithPadding(Stream dst, string str, int padSize, byte padByte = 0x78)
{
int StrLen = str.Length;
if (StrLen > padSize)
{
StrLen = padSize;
}
int PaddingLen = (padSize - StrLen) - 1;
writeString(dst, str, StrLen);
dst.WriteByte(0x00);
writePadding(dst, padByte, PaddingLen);
}
private static byte[] aes_ecb_decrypt(byte[] cipherText, byte[] KEY, int size = -1)
{
if (size < 0)
{
size = cipherText.Length;
}
MemoryStream ms = new MemoryStream();
Aes alg = Aes.Create();
alg.Mode = CipherMode.ECB;
alg.Padding = PaddingMode.None;
alg.KeySize = 256;
alg.BlockSize = 128;
alg.Key = KEY;
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(cipherText, 0, size);
cs.Close();
byte[] plainText = ms.ToArray();
return plainText;
}
private static byte[] aes_cbc_decrypt(byte[] cipherData, byte[] IV, byte[] Key)
{
MemoryStream ms = new MemoryStream();
Aes alg = Aes.Create();
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.None;
alg.KeySize = 256;
alg.BlockSize = 128;
alg.Key = Key;
alg.IV = IV;
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(cipherData, 0, cipherData.Length);
cs.Close();
byte[] decryptedData = ms.ToArray();
return decryptedData;
}
private static byte[] aes_cbc_encrypt(byte[] plainText, byte[] IV, byte[] KEY, int size = -1)
{
if (size < 0)
{
size = plainText.Length;
}
MemoryStream ms = new MemoryStream();
Aes alg = Aes.Create();
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.None;
alg.KeySize = 256;
alg.BlockSize = 128;
alg.Key = KEY;
alg.IV = IV;
CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plainText, 0, size);
cs.Close();
byte[] cipherText = ms.ToArray();
return cipherText;
}
public static void CreatePsvmd(Stream OutputStream, Stream EncryptedPsvimg, long ContentSize, string BackupType,byte[] Key)
{
byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE];
EncryptedPsvimg.Seek(0x00, SeekOrigin.Begin);
EncryptedPsvimg.Read(IV, 0x00, IV.Length);
IV = aes_ecb_decrypt(IV, Key);
MemoryStream ms = new MemoryStream();
writeUInt32(ms, 0xFEE1900D); // magic
writeUInt32(ms, 0x2); // type
writeUInt64(ms, 0x03000000); // fw ver
ms.Write(new byte[0x10], 0x00, 0x10); // PSID
writeStringWithPadding(ms, BackupType, 0x40, 0x00); //backup type
writeInt64(ms, EncryptedPsvimg.Length); // total size
writeUInt64(ms, 0x2); //version
writeInt64(ms, ContentSize); // content size
ms.Write(IV, 0x00, 0x10); // IV
writeUInt64(ms, 0x00); //ux0 info
writeUInt64(ms, 0x00); //ur0 info
writeUInt64(ms, 0x00); //unused 98
writeUInt64(ms, 0x00); //unused A0
writeUInt32(ms, 0x1); //add data
ms.Seek(0x00, SeekOrigin.Begin);
byte[] psvMd = ms.ToArray();
ms.Close();
ms = new MemoryStream();
byte[] psvMdCompressed = ZlibStream.CompressBuffer(psvMd);
psvMdCompressed[0x1] = 0x9C;
ms.Write(psvMdCompressed, 0x00, psvMdCompressed.Length);
SHA256 sha = SHA256.Create();
byte[] shadata = sha.ComputeHash(psvMdCompressed);
ms.Write(shadata, 0x00, shadata.Length);
int PaddingLen = Convert.ToInt32(PSVIMGConstants.AES_BLOCK_SIZE - (ms.Length & (PSVIMGConstants.AES_BLOCK_SIZE - 1)));
writePadding(ms, 0x00, PaddingLen);
writeInt32(ms, PaddingLen); //Padding Length
writeUInt32(ms, 0x00);
writeInt64(ms, (ms.Length+0x8)+IV.Length);
ms.Seek(0x00, SeekOrigin.Begin);
byte[] toEncrypt = ms.ToArray();
ms.Close();
byte[] EncryptedData = aes_cbc_encrypt(toEncrypt, IV, Key);
OutputStream.Write(IV, 0x00, IV.Length);
OutputStream.Write(EncryptedData, 0x00, EncryptedData.Length);
return;
}
public static byte[] DecryptPsvmd(Stream PsvMdFile, byte[] Key)
{
byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE];
PsvMdFile.Read(IV, 0x00, IV.Length);
byte[] remaining = new byte[PsvMdFile.Length - IV.Length];
PsvMdFile.Read(remaining, 0x00, remaining.Length);
byte[] zlibCompressed = aes_cbc_decrypt(remaining, IV, Key);
return zlibCompressed;
// return ZlibStream.UncompressBuffer(zlibCompressed);
}
}
}