This commit is contained in:
SilicaAndPina 2019-10-08 19:10:57 +13:00
parent 9d698dc492
commit ead7745626
13 changed files with 877 additions and 282 deletions

View File

@ -5,7 +5,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D46AA2C2-2BDC-45C7-ACA5-D7A2295564E8}</ProjectGuid>
<OutputType>WinExe</OutputType>
<OutputType>Exe</OutputType>
<RootNamespace>CHOVY</RootNamespace>
<AssemblyName>CHOVY-SIGN</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
@ -34,13 +34,13 @@
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'CHOVY|AnyCPU'">
<OutputPath>bin\CHOVY\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.8.5.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
<HintPath>..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath>
</Reference>
<Reference Include="DiscUtils, Version=0.11.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Discutils.0.11.0.2\lib\net40\DiscUtils.dll</HintPath>
</Reference>
@ -77,8 +77,10 @@
<Compile Include="pbp.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PSVIMGReader.cs" />
<Compile Include="PSVIMGBuilder.cs" />
<Compile Include="PSVIMGFileStream.cs" />
<Compile Include="PSVIMGStream.cs" />
<Compile Include="PSVIMGStructs.cs" />
<Compile Include="psvimgtools.cs" />
<EmbeddedResource Include="CHOVY.resx">
<DependentUpon>CHOVY.cs</DependentUpon>

View File

@ -13,8 +13,6 @@ using System.Windows.Forms;
namespace CHOVY
{
public partial class CHOVY : Form
{
bool MutedAudio = false;
@ -78,7 +76,7 @@ namespace CHOVY
{
RegistryKey key;
key = Registry.CurrentUser.CreateSubKey(@"Software\CHOVY");
key = Registry.CurrentUser.CreateSubKey(@"Software\CHOVYProject\Chovy-Sign");
Value = key.GetValue(Setting).ToString();
key.Close();
}
@ -90,9 +88,8 @@ namespace CHOVY
{
try
{
RegistryKey key;
key = Registry.CurrentUser.CreateSubKey(@"Software\CHOVY");
key = Registry.CurrentUser.CreateSubKey(@"Software\CHOVYProject\Chovy-Sign");
key.SetValue(Setting, Value);
key.Close();
}
@ -317,49 +314,44 @@ namespace CHOVY
this.Hide();
string cmaDir = "";
string accountId = "0000000000000000";
try
{
cmaDir = ReadSetting("CmaDir");
//try qcma
cmaDir = Registry.CurrentUser.OpenSubKey(@"Software\codestation\qcma").GetValue("appsPath").ToString();
accountId = Registry.CurrentUser.OpenSubKey(@"Software\codestation\qcma").GetValue("lastAccountId").ToString();
}
catch(Exception)
catch (Exception)
{
try
{
//try qcma
cmaDir = Registry.CurrentUser.OpenSubKey(@"Software\codestation\qcma").GetValue("appsPath").ToString();
accountId = Registry.CurrentUser.OpenSubKey(@"Software\codestation\qcma").GetValue("lastAccountId").ToString();
//try sony cma
cmaDir = Registry.CurrentUser.OpenSubKey(@"Software\Sony Corporation\Content Manager Assistant\Settings").GetValue("ApplicationHomePath").ToString();
}
catch (Exception)
{
try
{
//try sony cma
cmaDir = Registry.CurrentUser.OpenSubKey(@"Software\Sony Corporation\Content Manager Assistant\Settings").GetValue("ApplicationHomePath").ToString();
//try devkit cma
cmaDir = Registry.CurrentUser.OpenSubKey(@"Software\SCE\PSP2\Services\Content Manager Assistant for PlayStation(R)Vita DevKit\Settings").GetValue("ApplicationHomePath").ToString();
}
catch (Exception)
{
try
{
//try devkit cma
cmaDir = Registry.CurrentUser.OpenSubKey(@"Software\SCE\PSP2\Services\Content Manager Assistant for PlayStation(R)Vita DevKit\Settings").GetValue("ApplicationHomePath").ToString();
string DefaultDir = Path.Combine(Environment.GetEnvironmentVariable("HOMEDRIVE"), Environment.GetEnvironmentVariable("HOMEPATH"), "Documents", "PS Vita");
if (Directory.Exists(DefaultDir))
{
cmaDir = DefaultDir;
}
}
catch (Exception)
{
try
{
string DefaultDir = Path.Combine(Environment.GetEnvironmentVariable("HOMEDRIVE"), Environment.GetEnvironmentVariable("HOMEPATH"), "Documents", "PS Vita");
if (Directory.Exists(DefaultDir))
{
cmaDir = DefaultDir;
}
}
catch (Exception)
{
//Do nothing
}
//Do nothing
}
}
}
}
@ -379,6 +371,7 @@ namespace CHOVY
ccs.Hide();
this.Show();
this.Focus();
WriteSetting("CmaDir", CmaDir);
if (Backup == "")
{
@ -414,9 +407,7 @@ namespace CHOVY
string ContentID = pbp.GetContentId(EbootPbp);
PSVIMGFileStream LicenseRif = new PSVIMGFileStream(LicensePsvimg, "/"+ ContentID+ ".rif");
byte[] LicenseFile = new byte[LicenseRif.Length];
LicenseRif.Read(LicenseFile, 0x00, Convert.ToInt32(LicenseRif.Length));
File.WriteAllBytes(Rif, LicenseFile);
LicenseRif.WriteToFile(Rif);
LicenseRif.Close();
LicensePsvimg.Close();
@ -424,7 +415,6 @@ namespace CHOVY
GamePsvimg.Close();
WriteSetting("RifPath", Rif);
WriteSetting("CmaDir", CmaDir);
Versionkey.Text = VerKey;
RifPath.Text = Rif;

View File

@ -7,7 +7,7 @@ namespace CHOVY
{
public partial class CHOVYCmaSelector : Form
{
public CHOVYCmaSelector(string CMA="",string AID="")
public CHOVYCmaSelector(string CMA = "", string AID = "")
{
InitializeComponent();
CMADir.Text = CMA;
@ -20,7 +20,7 @@ namespace CHOVY
{
return BackupList.Text.Substring(0, 9);
}
catch(Exception)
catch (Exception)
{
return "";
}
@ -33,7 +33,7 @@ namespace CHOVY
{
return AIDSelector.Text;
}
private void UpdateAidList()
{
AIDSelector.Items.Clear();
@ -71,7 +71,7 @@ namespace CHOVY
string BackupName = (Path.GetFileName(Dir) + " - " + Title);
BackupList.Items.Add(BackupName);
}
catch(Exception)
catch (Exception)
{
BackupList.Items.Add(Path.GetFileName(Dir));
}
@ -107,4 +107,4 @@ namespace CHOVY
this.Close();
}
}
}
}

402
CHOVY/PSVIMGBuilder.cs Normal file
View File

@ -0,0 +1,402 @@
using Org.BouncyCastle.Crypto.Digests;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using static PSVIMGTOOLS.SceIoStat;
namespace PSVIMGTOOLS
{
class PSVIMGBuilder
{
private byte[] IV = new byte[0x10];
private byte[] KEY;
private Random rnd = new Random();
private Stream mainStream;
private Sha256Digest shaCtx;
byte[] blockData;
MemoryStream blockStream;
//Footer
private long totalBytes = 0;
private byte[] aes_ecb_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;
}
private void writeUInt64(Stream dst,UInt64 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x8);
}
private void writeInt64(Stream dst,Int64 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x8);
}
private void writeUInt16(Stream dst, UInt16 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x2);
}
private void writeInt16(Stream dst, Int16 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x2);
}
private void writeInt32(Stream dst, Int32 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x4);
}
private void writeUInt32(Stream dst, UInt32 value)
{
byte[] ValueBytes = BitConverter.GetBytes(value);
dst.Write(ValueBytes, 0x00, 0x4);
}
private SceDateTime dateTimeToSceDateTime(DateTime dt)
{
SceDateTime sdt = new SceDateTime();
sdt.Day = Convert.ToUInt16(dt.Day);
sdt.Month = Convert.ToUInt16(dt.Month);
sdt.Year = Convert.ToUInt16(dt.Year);
sdt.Hour = Convert.ToUInt16(dt.Hour);
sdt.Minute = Convert.ToUInt16(dt.Minute);
sdt.Second = Convert.ToUInt16(dt.Second);
sdt.Microsecond = Convert.ToUInt32(dt.Millisecond * 1000);
return sdt;
}
private SceIoStat sceIoStat(string path)
{
SceIoStat stats = new SceIoStat();
FileAttributes attrbutes = File.GetAttributes(path);
if (attrbutes.HasFlag(FileAttributes.Directory))
{
stats.Mode |= Modes.Directory;
stats.Attributes |= AttributesEnum.Directory;
stats.Size = 0;
}
else
{
stats.Mode |= Modes.File;
stats.Attributes |= AttributesEnum.File;
stats.Size = Convert.ToUInt64(new FileInfo(path).Length);
}
if(attrbutes.HasFlag(FileAttributes.ReadOnly))
{
stats.Mode |= Modes.GroupRead;
stats.Mode |= Modes.GroupExecute;
stats.Mode |= Modes.OthersExecute;
stats.Mode |= Modes.OthersRead;
stats.Mode |= Modes.UserRead;
stats.Mode |= Modes.UserExecute;
stats.Attributes |= AttributesEnum.Read;
stats.Attributes |= AttributesEnum.Execute;
}
else
{
stats.Mode |= Modes.GroupRead;
stats.Mode |= Modes.GroupExecute;
stats.Mode |= Modes.GroupWrite;
stats.Mode |= Modes.OthersExecute;
stats.Mode |= Modes.OthersRead;
stats.Mode |= Modes.OthersWrite;
stats.Mode |= Modes.UserRead;
stats.Mode |= Modes.UserExecute;
stats.Mode |= Modes.UserWrite;
stats.Attributes |= AttributesEnum.Read;
stats.Attributes |= AttributesEnum.Write;
stats.Attributes |= AttributesEnum.Execute;
}
stats.CreationTime = dateTimeToSceDateTime(File.GetCreationTimeUtc(path));
stats.AccessTime = dateTimeToSceDateTime(File.GetLastAccessTimeUtc(path));
stats.ModificaionTime = dateTimeToSceDateTime(File.GetLastWriteTimeUtc(path));
return stats;
}
private void writeSceDateTime(Stream dst,SceDateTime time)
{
writeUInt16(dst, time.Year);
writeUInt16(dst, time.Month);
writeUInt16(dst, time.Day);
writeUInt16(dst, time.Hour);
writeUInt16(dst, time.Minute);
writeUInt16(dst, time.Second);
writeUInt32(dst, time.Microsecond);
}
private void writeSceIoStat(Stream dst, SceIoStat stats)
{
writeUInt32(dst, Convert.ToUInt32(stats.Mode));
writeUInt32(dst, Convert.ToUInt32(stats.Attributes));
writeUInt64(dst, stats.Size);
writeSceDateTime(dst, stats.CreationTime);
writeSceDateTime(dst, stats.AccessTime);
writeSceDateTime(dst, stats.ModificaionTime);
foreach(UInt32 i in stats.Private)
{
writeUInt32(dst,i);
}
}
private void memset(byte[] buf, byte content, long length)
{
for(int i = 0; i < length; i++)
{
buf[i] = content;
}
}
private 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 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 void writePadding(Stream dst, byte paddingByte, long paddingLen)
{
byte[] paddingData = new byte[paddingLen];
memset(paddingData, paddingByte, paddingLen);
dst.Write(paddingData, 0x00, paddingData.Length);
}
private byte[] getHeader(string FilePath, string ParentPath, string PathRel)
{
using (MemoryStream Header = new MemoryStream())
{
writeInt64(Header, DateTime.UtcNow.Ticks); // SysTime
writeInt64(Header, 0); // Flags
writeSceIoStat(Header, sceIoStat(FilePath));
writeStringWithPadding(Header, ParentPath, 256); // Parent Path
writeUInt32(Header, 1); //unk_16C
writeStringWithPadding(Header, PathRel, 256); //Relative Path
writePadding(Header, 0x78, 904); //'x'
writeString(Header, PSVIMGConstants.PSVIMG_HEADER_END); //EndOfHeader
Header.Seek(0x00, SeekOrigin.Begin);
return Header.ToArray();
}
}
private void startNewBlock()
{
blockData = new byte[PSVIMGConstants.FULL_PSVIMG_SIZE];
blockStream = new MemoryStream(blockData, 0x00, PSVIMGConstants.FULL_PSVIMG_SIZE);
}
private byte[] shaBlock(int length = PSVIMGConstants.PSVIMG_BLOCK_SIZE,bool final=false)
{
byte[] outbytes = new byte[PSVIMGConstants.SHA256_BLOCK_SIZE];
shaCtx.BlockUpdate(blockData, 0x00, length);
Sha256Digest shaTmp = (Sha256Digest)shaCtx.Copy();
shaTmp.DoFinal(outbytes,0x00);
return outbytes;
}
private void finishBlock(bool final = false)
{
int len = Convert.ToInt32(blockStream.Position);
byte[] shaBytes = shaBlock(len, final);
blockStream.Write(shaBytes, 0x00, PSVIMGConstants.SHA256_BLOCK_SIZE);
blockStream.Close();
len += PSVIMGConstants.SHA256_BLOCK_SIZE;
//Get next IV
byte[] encryptedBlock = aes_ecb_encrypt(blockData, IV, KEY, len);
for (int i = 0; i < IV.Length; i++)
{
int encBlockOffset = (encryptedBlock.Length - IV.Length)+i;
IV[i] = encryptedBlock[encBlockOffset];
}
mainStream.Write(encryptedBlock, 0x00, encryptedBlock.Length);
totalBytes += encryptedBlock.Length;
}
private int remainingBlockSize()
{
return Convert.ToInt32((PSVIMGConstants.PSVIMG_BLOCK_SIZE - blockStream.Position));
}
private void writeBlock(byte[] data)
{
long dLen = data.Length;
while (dLen > 0)
{
int remaining = remainingBlockSize();
if (dLen > remaining)
{
blockStream.Write(data, 0x00, remaining);
dLen -= remaining;
finishBlock();
startNewBlock();
}
else
{
blockStream.Write(data, 0x00, Convert.ToInt32(dLen));
dLen = 0;
}
}
}
private byte[] getPadding(long size)
{
using (MemoryStream ms = new MemoryStream())
{
long paddingSize = PSVIMGPadding.GetPadding(size);
if(paddingSize != 0)
{
writePadding(ms, 0x2B, paddingSize-PSVIMGConstants.PSVIMG_PADDING_END.Length);
writeString(ms, PSVIMGConstants.PSVIMG_PADDING_END);
}
ms.Seek(0x00, SeekOrigin.Begin);
return ms.ToArray();
}
}
private byte[] getTailer()
{
using (MemoryStream ms = new MemoryStream())
{
writeUInt64(ms, 0x00);
writePadding(ms, 0x7a, 1004);
writeString(ms, PSVIMGConstants.PSVIMG_TAILOR_END);
ms.Seek(0x00, SeekOrigin.Begin);
return ms.ToArray();
}
}
private void writeStream(Stream dst)
{
while(dst.Position < dst.Length)
{
byte[] work_buf;
Int64 bytes_remain = (dst.Length - dst.Position);
if (bytes_remain > 0x8388608)
{
work_buf = new byte[0x8388608];
}
else
{
work_buf = new byte[bytes_remain];
}
dst.Read(work_buf, 0x00, work_buf.Length);
writeBlock(work_buf);
}
}
private byte[] getFooter()
{
using (MemoryStream ms = new MemoryStream())
{
// uint sz = Convert.ToUInt32(totalBytes & (PSVIMGConstants.AES_BLOCK_SIZE - 1));
// int paddingInt = Convert.ToInt32(PSVIMGConstants.AES_BLOCK_SIZE - (sz & (PSVIMGConstants.AES_BLOCK_SIZE - 1)));
totalBytes += 0x10; //number of bytes used by this footer.
writeInt32(ms, 0x00); // int padding (idk wht this is)
writeUInt32(ms, 0x00);
writeInt64(ms, totalBytes);
ms.Seek(0x00, SeekOrigin.Begin);
return aes_ecb_encrypt(ms.ToArray(), IV, KEY);
}
}
public void AddFile(string FilePath, string ParentPath, string PathRel)
{
long sz = Convert.ToInt64(sceIoStat(FilePath).Size);
writeBlock(getHeader(FilePath, ParentPath, PathRel));
writeStream(File.OpenRead(FilePath));
writeBlock(getPadding(sz));
writeBlock(getTailer());
}
public void AddDir(string DirPath, string ParentPath, string PathRel)
{
writeBlock(getHeader(DirPath, ParentPath, PathRel));
writeBlock(getPadding(0));
writeBlock(getTailer());
}
public void Finish()
{
finishBlock(true);
byte[] footer = getFooter();
mainStream.Write(footer, 0x00, footer.Length);
blockStream.Close();
mainStream.Close();
}
public PSVIMGBuilder(Stream dst, byte[] Key)
{
totalBytes = 0;
shaCtx = new Sha256Digest();
mainStream = dst;
KEY = Key;
rnd.NextBytes(IV);
mainStream.Write(IV, 0x00, IV.Length);
totalBytes += IV.Length;
startNewBlock();
}
}
}

View File

@ -1,122 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static PSVIMGTOOLS.SceIoStat;
namespace PSVIMGTOOLS
{
internal class strings
{
internal static string readTerminator(byte[] StringBytes)
{
string str = "";
foreach (byte sByte in StringBytes)
{
if (sByte != 0x00)
{
str += (char)sByte;
}
else
{
return str;
}
}
return str;
}
}
class SceDateTime
{
public UInt16 Year;
public UInt16 Month;
public UInt16 Day;
public UInt16 Hour;
public UInt16 Minute;
public UInt16 Second;
public UInt32 Microsecond;
public SceDateTime()
{
}
}
class SceIoStat
{
public UInt32 Mode;
public uint Attributes;
/** Size of the file in bytes. */
public UInt64 Size;
/** Creation time. */
public SceDateTime CreationTime;
/** Access time. */
public SceDateTime AccessTime;
/** Modification time. */
public SceDateTime ModificaionTime;
/** Device-specific data. */
public UInt32[] Private = new UInt32[6];
public SceIoStat()
{
}
};
class PsvImgTailer
{
public UInt64 Flags;
public Byte[] Padding = new Byte[1004];
public Byte[] bEnd = new Byte[12];
public String End
{
get
{
return strings.readTerminator(bEnd);
}
}
}
class PsvImgHeader
{
public UInt64 SysTime;
public UInt64 Flags;
public SceIoStat Statistics;
public Byte[] bParentPath = new Byte[256];
public UInt32 unk_16C; // set to 1
public Byte[] bPath = new Byte[256];
public Byte[] Padding = new Byte[904];
public Byte[] bEnd = new Byte[12];
public String Path
{
get
{
return strings.readTerminator(bPath);
}
}
public String End
{
get
{
return strings.readTerminator(bEnd);
}
}
public String ParentPath
{
get
{
return strings.readTerminator(bParentPath);
}
}
public PsvImgHeader()
{
}
}
class PSVIMGFileStream : Stream
{
@ -131,6 +18,36 @@ namespace PSVIMGTOOLS
psvStream = psv;
findFile(Path);
}
public void WriteToFile(string FilePath)
{
using (FileStream fs = File.OpenWrite(FilePath))
{
fs.SetLength(0);
int written = 0;
long left = (length - written);
byte[] work_buf;
this.Seek(0x00, SeekOrigin.Begin);
while (left > 0)
{
left = (length - written);
if (left < 0x10000)
{
work_buf = new byte[left];
}
else
{
work_buf = new byte[0x10000];
}
this.Read(work_buf, 0x00, work_buf.Length);
fs.Write(work_buf, 0x00, work_buf.Length);
written += work_buf.Length;
}
}
}
public override bool CanRead
{
get
@ -185,7 +102,7 @@ namespace PSVIMGTOOLS
int read = 0;
while(true)
{
int remainBlock = Convert.ToInt32(psvStream.BlockRemaining - psvStream.SHA256_BLOCK_SIZE);
int remainBlock = Convert.ToInt32(psvStream.BlockRemaining - PSVIMGConstants.SHA256_BLOCK_SIZE);
int remainRead = count - read;
if (remainRead < remainBlock)
@ -201,7 +118,7 @@ namespace PSVIMGTOOLS
byte[] tmp = new byte[remainBlock];
psvStream.Read(tmp, 0x00, remainBlock);
ms.Write(tmp, 0x00, tmp.Length);
psvStream.Seek(psvStream.SHA256_BLOCK_SIZE, SeekOrigin.Current);
psvStream.Seek(PSVIMGConstants.SHA256_BLOCK_SIZE, SeekOrigin.Current);
read += Convert.ToInt32(remainBlock);
}
}
@ -215,7 +132,7 @@ namespace PSVIMGTOOLS
{
long ToSeek = 0;
long SeekAdd = 0;
long remainBlock = psvStream.BlockRemaining - psvStream.SHA256_BLOCK_SIZE;
long remainBlock = psvStream.BlockRemaining - PSVIMGConstants.SHA256_BLOCK_SIZE;
while (true)
{
long remainSeek = amount - ToSeek;
@ -228,9 +145,9 @@ namespace PSVIMGTOOLS
else
{
ToSeek += remainBlock;
SeekAdd += psvStream.SHA256_BLOCK_SIZE;
SeekAdd += PSVIMGConstants.SHA256_BLOCK_SIZE;
}
remainBlock = psvStream.PSVIMG_BLOCK_SIZE;
remainBlock = PSVIMGConstants.PSVIMG_BLOCK_SIZE;
}
ToSeek += SeekAdd;
return psvStream.Seek(ToSeek,orig);
@ -333,8 +250,8 @@ namespace PSVIMGTOOLS
private SceIoStat readStats()
{
SceIoStat stat = new SceIoStat();
stat.Mode = readUInt32();
stat.Attributes = readUInt32();
stat.Mode = (Modes)readUInt32();
stat.Attributes = (AttributesEnum)readUInt32();
stat.Size = readUInt64();
stat.CreationTime = readDatetime();
stat.AccessTime = readDatetime();
@ -374,17 +291,7 @@ namespace PSVIMGTOOLS
{
PsvImgHeader header = readHeader();
long size = (long)header.Statistics.Size;
//Read Padding (if any)
int padding;
if ((size & (psvStream.PSVIMG_ENTRY_ALIGN - 1))>=1)
{
padding = Convert.ToInt32(psvStream.PSVIMG_ENTRY_ALIGN - (size & (psvStream.PSVIMG_ENTRY_ALIGN - 1)));
}
else
{
padding = 0;
}
long padding = PSVIMGPadding.GetPadding(size);
if (header.Path == path)
{

View File

@ -8,13 +8,9 @@ namespace PSVIMGTOOLS
class PSVIMGStream : Stream
{
public int AES_BLOCK_SIZE = 0x10;
public int SHA256_BLOCK_SIZE = 0x20;
public int PSVIMG_BLOCK_SIZE = 0x8000;
public int FULL_PSVIMG_SIZE = 0x8020;
public int PSVIMG_ENTRY_ALIGN = 0x400;
private Stream baseStream;
private MemoryStream blockStream;
private long _position = 0;
private byte[] key;
public Stream BaseStream
{
@ -24,6 +20,29 @@ namespace PSVIMGTOOLS
}
}
private long position
{
get
{
return _position;
}
set
{
if (value > this.Length)
{
_position = this.Length;
}
else if(value < 0)
{
_position = 0;
}
else
{
_position = value;
}
}
}
public Byte[] Key
{
get
@ -87,7 +106,7 @@ namespace PSVIMGTOOLS
{
get
{
return baseStream.Length - AES_BLOCK_SIZE;
return baseStream.Length - PSVIMGConstants.AES_BLOCK_SIZE;
}
}
@ -103,7 +122,7 @@ namespace PSVIMGTOOLS
{
get
{
return baseStream.Position - AES_BLOCK_SIZE;
return position;
}
set
{
@ -112,61 +131,94 @@ namespace PSVIMGTOOLS
}
private bool verifyFooter()
{
byte[] Footer = new byte[0x10];
byte[] IV = new byte[PSVIMGConstants.AES_BLOCK_SIZE];
baseStream.Seek(baseStream.Length - (Footer.Length + IV.Length), SeekOrigin.Begin);
baseStream.Read(IV, 0x00, PSVIMGConstants.AES_BLOCK_SIZE);
baseStream.Read(Footer, 0x00, 0x10);
byte[] FooterDec = aes_ecb_decrypt(Footer, IV);
UInt64 FooterLen;
using (MemoryStream ms = new MemoryStream(FooterDec))
{
ms.Seek(0x4, SeekOrigin.Current);
ms.Seek(0x4, SeekOrigin.Current);
byte[] LenInt = new byte[0x8];
ms.Read(LenInt, 0x00, 0x8);
FooterLen = BitConverter.ToUInt64(LenInt, 0x00);
}
if(Convert.ToUInt64(baseStream.Length) == FooterLen)
{
return true;
}
else
{
return false;
}
}
public PSVIMGStream(Stream file, byte[] KEY)
{
baseStream = file;
key = KEY;
if(!verifyFooter())
{
throw new Exception("Invalid KEY!");
}
blockStream = new MemoryStream();
baseStream.Seek(AES_BLOCK_SIZE, SeekOrigin.Begin);
this.Seek(0x00, SeekOrigin.Begin);
update();
}
public override int Read(byte[] buffer, int offset, int count)
{
int remaining = (int)getRemainingBlock();
int read = 0;
if (count < remaining)
long totalRead = 0;
using (MemoryStream ms = new MemoryStream())
{
read += blockStream.Read(buffer, offset, count);
baseStream.Seek(count, SeekOrigin.Current);
}
else
{
using (MemoryStream ms = new MemoryStream())
while (true)
{
while (true)
if (this.Position >= this.Length)
{
update();
remaining = (int)getRemainingBlock();
int curPos = count - read;
if (curPos > remaining)
{
read += remaining;
blockStream.CopyTo(ms, remaining);
baseStream.Seek(remaining, SeekOrigin.Current);
}
else
{
read += curPos;
blockStream.CopyTo(ms, curPos);
baseStream.Seek(curPos, SeekOrigin.Current);
break;
}
break;
}
ms.Seek(0x00, SeekOrigin.Begin);
ms.Read(buffer, offset, count);
}
}
return read;
long rem = getRemainingBlock();
long totalLeft = (count - totalRead);
if (rem < totalLeft)
{
byte[] remB = new byte[rem];
long read = blockStream.Read(remB, 0x00, remB.Length);
totalRead += read;
ms.Write(remB, 0x00, remB.Length);
long indx = getBlockIndex() + 1;
seekToBlock(indx);
update();
}
else
{
byte[] remB = new byte[totalLeft];
long read = blockStream.Read(remB, 0x00, remB.Length);
totalRead += read;
ms.Write(remB, 0x00, remB.Length);
break;
}
}
ms.Seek(0x00, SeekOrigin.Begin);
totalRead = ms.Read(buffer, offset, count);
position += totalRead;
}
return Convert.ToInt32(totalRead);
}
public override void Flush()
{
update();
baseStream.Flush();
blockStream.Flush();
}
@ -174,35 +226,26 @@ namespace PSVIMGTOOLS
public override long Seek(long offset, SeekOrigin origin)
{
long ret = 0;
if(origin == SeekOrigin.Begin)
if (origin == SeekOrigin.Begin)
{
ret = baseStream.Seek(offset + AES_BLOCK_SIZE, SeekOrigin.Begin);
long blockNo = getBlockIndex(offset);
seekToBlock(blockNo);
update();
long onwards = offset % blockStream.Length;
ret = blockStream.Seek(onwards, SeekOrigin.Begin);
position = (baseStream.Position - PSVIMGConstants.AES_BLOCK_SIZE) + BlockPosition;
}
else if (origin == SeekOrigin.Current)
{
long pos = baseStream.Position;
if ((pos + offset) >= AES_BLOCK_SIZE)
{
ret = baseStream.Seek(offset, SeekOrigin.Current);
}
else
{
ret = baseStream.Seek(offset+ AES_BLOCK_SIZE, SeekOrigin.Current);
}
long currentPos = this.Position;
this.Seek(currentPos + offset, SeekOrigin.Begin);
}
else if (origin == SeekOrigin.End)
{
long pos = baseStream.Length;
if ((pos + offset) >= AES_BLOCK_SIZE)
{
ret = baseStream.Seek(offset, SeekOrigin.End);
}
else
{
ret = baseStream.Seek(offset + AES_BLOCK_SIZE, SeekOrigin.End);
}
long len = this.Length;
this.Seek(Length + offset, SeekOrigin.Begin);
}
update();
return ret;
}
@ -225,52 +268,44 @@ namespace PSVIMGTOOLS
baseStream.Dispose();
this.Dispose();
}
private void update()
{
long offset = (this.Position % FULL_PSVIMG_SIZE);
long blockIndex = getBlockIndex();
byte[] decryptedBlock = getBlock(blockIndex);
blockStream.Seek(0x00, SeekOrigin.Begin);
blockStream.SetLength(decryptedBlock.Length);
blockStream.Dispose();
blockStream = new MemoryStream(decryptedBlock, 0x00, decryptedBlock.Length);
blockStream.Write(decryptedBlock, 0x00, decryptedBlock.Length);
blockStream.Seek(0x00, SeekOrigin.Begin);
seekToBlock(blockIndex);
baseStream.Seek(offset, SeekOrigin.Current);
blockStream.Seek(offset, SeekOrigin.Begin);
}
private long getBlockIndex()
private long getBlockIndex(long pos = -1)
{
long i = 0;
long curPos = baseStream.Position;
long fullBlock;
long blockOffset;
while (true)
long blockOffset = 0;
long blockEnd = blockOffset + PSVIMGConstants.FULL_PSVIMG_SIZE;
long blockIndex = 0;
if (pos < 0)
{
blockOffset = (i * FULL_PSVIMG_SIZE) + AES_BLOCK_SIZE;
long remaining = getRemainingBase();
if (remaining < FULL_PSVIMG_SIZE)
{
fullBlock = blockOffset + remaining;
}
else
{
fullBlock = blockOffset + FULL_PSVIMG_SIZE;
}
if ((curPos >= blockOffset) && (curPos < fullBlock))
{
break;
}
if (blockOffset > baseStream.Length)
{
break;
}
i++;
pos = this.Position;
}
return i;
while (blockOffset < this.Length)
{
blockOffset = (blockIndex * PSVIMGConstants.FULL_PSVIMG_SIZE);
blockEnd = blockOffset + PSVIMGConstants.FULL_PSVIMG_SIZE;
if (pos >= blockOffset && pos < blockEnd)
{
return blockIndex;
}
blockIndex++;
}
throw new Exception("Not found somehow..");
}
private long getRemainingBase()
{
return baseStream.Length - baseStream.Position;
@ -283,7 +318,7 @@ namespace PSVIMGTOOLS
{
byte[] iv = new byte[0x10];
seekToBlock(blockindex);
baseStream.Seek(baseStream.Position - AES_BLOCK_SIZE, SeekOrigin.Begin);
baseStream.Seek(baseStream.Position - PSVIMGConstants.AES_BLOCK_SIZE, SeekOrigin.Begin);
baseStream.Read(iv, 0x00, iv.Length);
return iv;
}
@ -306,15 +341,12 @@ namespace PSVIMGTOOLS
private void seekToBlock(long blockIndex)
{
long blockOffset;
blockOffset = (blockIndex * FULL_PSVIMG_SIZE) + AES_BLOCK_SIZE;
long blockOffset = (blockIndex * PSVIMGConstants.FULL_PSVIMG_SIZE) + PSVIMGConstants.AES_BLOCK_SIZE;
if (blockOffset > baseStream.Length)
{
blockOffset = baseStream.Length;
}
baseStream.Seek(blockOffset, SeekOrigin.Begin);
}
private byte[] getBlock(long blockIndex)
@ -322,17 +354,15 @@ namespace PSVIMGTOOLS
byte[] iv = getIV(blockIndex);
long remaining = getRemainingBase();
byte[] encryptedBlock;
if (FULL_PSVIMG_SIZE < remaining)
if (PSVIMGConstants.FULL_PSVIMG_SIZE < remaining)
{
encryptedBlock = new byte[FULL_PSVIMG_SIZE];
encryptedBlock = new byte[PSVIMGConstants.FULL_PSVIMG_SIZE];
}
else
{
encryptedBlock = new byte[remaining];
}
baseStream.Read(encryptedBlock, 0x00, encryptedBlock.Length);
baseStream.Read(encryptedBlock, 0x00, encryptedBlock.Length);
byte[] decryptedBlock = aes_ecb_decrypt(encryptedBlock, iv);
return decryptedBlock;
}

212
CHOVY/PSVIMGStructs.cs Normal file
View File

@ -0,0 +1,212 @@
using System;
namespace PSVIMGTOOLS
{
internal class PSVIMGConstants
{
public const int AES_BLOCK_SIZE = 0x10;
public const int SHA256_BLOCK_SIZE = 0x20;
public const int PSVIMG_BLOCK_SIZE = 0x8000;
public const int PSVIMG_ENTRY_ALIGN = 0x400;
public const string PSVIMG_HEADER_END = "EndOfHeader\n";
public const string PSVIMG_TAILOR_END = "EndOfTailer\n";
public const string PSVIMG_PADDING_END = "\n";
public const int FULL_PSVIMG_SIZE = PSVIMG_BLOCK_SIZE + SHA256_BLOCK_SIZE;
}
internal class StringReader
{
internal static string ReadUntilTerminator(byte[] StringBytes)
{
string str = "";
foreach (byte sByte in StringBytes)
{
if (sByte != 0x00)
{
str += (char)sByte;
}
else
{
return str;
}
}
return str;
}
}
internal class SceDateTime
{
public UInt16 Year;
public UInt16 Month;
public UInt16 Day;
public UInt16 Hour;
public UInt16 Minute;
public UInt16 Second;
public UInt32 Microsecond;
public SceDateTime()
{
}
}
internal class SceIoStat
{
public enum Modes{
/** Format bits mask */
FormatBits = 0xF000,
/** Symbolic link */
SymbLink = 0x4000,
/** Directory */
Directory = 0x1000,
/** Regular file */
File = 0x2000,
/** Set UID */
SetUid = 0x0800,
/** Set GID */
SetGid = 0x0400,
/** Sticky */
Sticky = 0x0200,
/** Others access rights mask */
OthersAcesssMask = 0x01C0,
/** Others read permission */
OthersRead = 0x0100,
/** Others write permission */
OthersWrite = 0x0080,
/** Others execute permission */
OthersExecute = 0x0040,
/** Group access rights mask */
GroupAcessMask = 0x0038,
/** Group read permission */
GroupRead = 0x0020,
/** Group write permission */
GroupWrite = 0x0010,
/** Group execute permission */
GroupExecute = 0x0008,
/** User access rights mask */
UserAcessMask = 0x0007,
/** User read permission */
UserRead = 0x0004,
/** User write permission */
UserWrite = 0x0002,
/** User execute permission */
UserExecute = 0x0001,
};
public enum AttributesEnum
{
/** Format mask */
FormatMask = 0x0038, // Format mask
/** Symlink */
SymbLink = 0x0008, // Symbolic link
/** Directory */
Directory = 0x0010, // Directory
/** Regular file */
File = 0x0020, // Regular file
/** Hidden read permission */
Read = 0x0004, // read
/** Hidden write permission */
Write = 0x0002, // write
/** Hidden execute permission */
Execute = 0x0001, // execute
};
public Modes Mode;
public AttributesEnum Attributes;
/** Size of the file in bytes. */
public UInt64 Size;
/** Creation time. */
public SceDateTime CreationTime;
/** Access time. */
public SceDateTime AccessTime;
/** Modification time. */
public SceDateTime ModificaionTime;
/** Device-specific data. */
public UInt32[] Private = new UInt32[6];
public SceIoStat()
{
for(int i = 0; i < Private.Length; i++)
{
Private[i] = 0;
}
}
};
internal class PsvImgTailer
{
public UInt64 Flags;
public Byte[] Padding = new Byte[1004];
public Byte[] bEnd = new Byte[12];
public String End
{
get
{
return StringReader.ReadUntilTerminator(bEnd);
}
}
}
internal class PSVIMGPadding
{
public static long GetPadding(long size)
{
long padding;
if ((size & (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1)) >= 1)
{
padding = (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - (size & (PSVIMGConstants.PSVIMG_ENTRY_ALIGN - 1)));
}
else
{
padding = 0;
}
return padding;
}
}
internal class PsvImgHeader
{
public UInt64 SysTime;
public UInt64 Flags;
public SceIoStat Statistics;
public Byte[] bParentPath = new Byte[256];
public UInt32 unk_16C; // set to 1
public Byte[] bPath = new Byte[256];
public Byte[] Padding = new Byte[904];
public Byte[] bEnd = new Byte[12];
public String Path
{
get
{
return StringReader.ReadUntilTerminator(bPath);
}
}
public String End
{
get
{
return StringReader.ReadUntilTerminator(bEnd);
}
}
public String ParentPath
{
get
{
return StringReader.ReadUntilTerminator(bParentPath);
}
}
public PsvImgHeader()
{
}
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PSVIMGTOOLS;
using System;
using System.IO;
using System.Windows.Forms;
namespace CHOVY
@ -14,6 +13,28 @@ namespace CHOVY
[STAThread]
static void Main()
{
/*
FileStream fs = File.OpenWrite(@"C:\Users\earsy\Documents\Visual Studio 2017\Projects\CSharpImgTools\CSharpImgTools\bin\Debug\test.psvimg");
PSVIMGBuilder psvBuild = new PSVIMGBuilder(fs, CmaKeys.GenerateKey(new byte[] { 0xcf, 0x61, 0x85, 0xd5, 0xa7, 0x87, 0x0c, 0x4a }));
psvBuild.AddFile(@"C:\Users\earsy\Documents\Visual Studio 2017\Projects\CSharpImgTools\CSharpImgTools\bin\Debug\EBOOT.PBP", @"ux0:temp/game/PCSG90096/app/PCSG90096", @"/EBOOT.PBP");
psvBuild.AddDir(@"C:\Users\earsy\Documents\Visual Studio 2017\Projects\CSharpImgTools\CSharpImgTools\bin\Debug", @"ux0:temp/game/PCSG90096/app/PCSG90096", @"/sce_sys");
psvBuild.AddFile(@"C:\Users\earsy\Documents\Visual Studio 2017\Projects\CSharpImgTools\CSharpImgTools\bin\Debug\param.sfo", @"ux0:temp/game/PCSG90096/app/PCSG90096", @"/sce_sys/param.sfo");
psvBuild.Finish();
MemoryStream ms = new MemoryStream();
FileStream fs2 = File.OpenRead(@"C:\Users\earsy\Documents\Visual Studio 2017\Projects\CSharpImgTools\CSharpImgTools\bin\Debug\test.psvimg");
fs2.CopyTo(ms);
fs2.Close();
ms.Seek(0x00, SeekOrigin.Begin);
FileStream fs3 = File.OpenWrite(@"C:\Users\earsy\Documents\Visual Studio 2017\Projects\CSharpImgTools\CSharpImgTools\bin\Debug\test.psvimgd");
PSVIMGStream psv = new PSVIMGStream(ms, CmaKeys.GenerateKey(new byte[] { 0xcf, 0x61, 0x85, 0xd5, 0xa7, 0x87, 0x0c, 0x4a }));
psv.CopyTo(fs3);
fs3.Close();
psv.Close();
*/
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new CHOVY());

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.8.5" targetFramework="net45" />
<package id="Discutils" version="0.11.0.2" targetFramework="net452" />
</packages>

Binary file not shown.

Binary file not shown.

30
packages/BouncyCastle.1.8.5/README.md vendored Normal file
View File

@ -0,0 +1,30 @@
# The Bouncy Castle Crypto Package For C Sharp
The Bouncy Castle Crypto package is a C\# implementation of cryptographic algorithms and protocols, it was developed by the Legion of the Bouncy Castle, a registered Australian Charity, with a little help! The Legion, and the latest goings on with this package, can be found at [http://www.bouncycastle.org](http://www.bouncycastle.org). In addition to providing basic cryptography algorithms, the package also provides support for CMS, TSP, X.509 certificate generation and a variety of other standards such as OpenPGP.
The Legion also gratefully acknowledges the contributions made to this package by others (see [here](http://www.bouncycastle.org/csharp/contributors.html) for the current list). If you would like to contribute to our efforts please feel free to get in touch with us or visit our [donations page](https://www.bouncycastle.org/donate), sponsor some specific work, or purchase a support contract through [Crypto Workshop](http://www.cryptoworkshop.com).
Except where otherwise stated, this software is distributed under a license based on the MIT X Consortium license. To view the license, [see here](http://www.bouncycastle.org/licence.html). The OpenPGP library also includes a modified BZIP2 library which is licensed under the [Apache Software License, Version 2.0](http://www.apache.org/licenses/).
**Note**: this source tree is not the FIPS version of the APIs - if you are interested in our FIPS version please contact us directly at [office@bouncycastle.org](mailto:office@bouncycastle.org).
## Mailing Lists
For those who are interested, there are 2 mailing lists for participation in this project. To subscribe use the links below and include the word subscribe in the message body. (To unsubscribe, replace **subscribe** with **unsubscribe** in the message body)
* [announce-crypto-csharp-request@bouncycastle.org](mailto:announce-crypto-csharp-request@bouncycastle.org)
This mailing list is for new release announcements only, general subscribers cannot post to it.
* [dev-crypto-csharp-request@bouncycastle.org](mailto:dev-crypto-csharp-request@bouncycastle.org)
This mailing list is for discussion of development of the package. This includes bugs, comments, requests for enhancements, questions about use or operation.
**NOTE:**You need to be subscribed to send mail to the above mailing list.
## Feedback
If you want to provide feedback directly to the members of **The Legion** then please use [feedback-crypto@bouncycastle.org](mailto:feedback-crypto@bouncycastle.org), if you want to help this project survive please consider [donating](https://www.bouncycastle.org/donate).
For bug reporting/requests you can report issues here on github, via feedback-crypto if required, and we also have a [Jira issue tracker](http://www.bouncycastle.org/jira). We will accept pull requests based on this repository as well.
## Finally
Enjoy!

Binary file not shown.