Compare commits

...

27 Commits
2.0 ... master

Author SHA1 Message Date
Li 2ef6e0c65d add new setting n stuff 2024-04-12 16:50:25 +12:00
Li 58b6de3d00 Get it working on .net 8.0 and latest avalonia! 2024-04-12 14:47:18 +12:00
Li dd3431c312 Fix bugs 2024-01-11 21:29:23 +13:00
Li 97c5959caf Fix an issue where yuo cant enable using content manager again 2024-01-11 19:52:35 +13:00
Li fb8c379751 Update 'README.md' 2023-06-10 09:03:03 +00:00
Li b433e30fcc Update 'README.md' 2023-06-10 09:02:24 +00:00
Li 1c1711d844 Update 'README.md' 2023-06-10 08:59:50 +00:00
Li 2b1154a140 Update 'README.md' 2023-06-10 08:58:53 +00:00
Li fec8c58ae5 Update 'README.md' 2023-06-10 08:53:35 +00:00
Li dad692f9dd Update 'README.md' 2023-06-10 08:48:52 +00:00
Li 434c3304b7 Update info2 2023-06-10 20:22:52 +12:00
Li 1779f2f7c2 Update readme again 2023-06-10 20:22:06 +12:00
Li c837fddb9f Update readme, fix some stuff 2023-06-10 20:20:11 +12:00
Li f087076653 Put new discoveries into practice 2023-06-10 19:20:27 +12:00
Li c15e345b30 make Chovy-Sign-CLI and GUI version run on linux 2023-06-09 21:06:44 +12:00
Li 5aa34528ea Update slight 2023-05-02 06:15:49 +12:00
Li 36a088e256 Add settings menu, libcrypt from database, etc 2023-05-02 05:52:34 +12:00
Li de65c71d2c Implement Sub Channel Generation. 2023-05-01 23:51:00 +12:00
Li dd6707d5ef Fix LC1 games! 2023-04-30 22:13:23 +12:00
Li 6647b319a2 Add code to read SBI File (Subchannel information, for libcrypt), and include magic word inside ISO HEADER 2023-04-30 21:08:57 +12:00
Li b13fa203a8 Merge pull request 'remove unused code, fix ps1 multi-disc gen `__sce_ebootpbp` failed.' (#18) from SquallATF/chovy-sign:master into master
Reviewed-on: SilicaAndPina/chovy-sign#18
2023-04-30 02:16:08 +00:00
SquallATF c96b43031a remove unused code, fix ps1 multi-disc gen `__sce_ebootpbp` failed. 2023-04-30 08:34:40 +08:00
Li 299b042dd9 Merge branch 'master' of https://silica.codes/SilicaAndPina/chovy-sign 2023-04-26 20:36:04 +12:00
Li 9001a461cc Remove test code from PbpResign 2023-04-26 20:35:47 +12:00
Li 73a6c3a0eb Update 'README.md' 2023-04-26 04:27:15 +00:00
Li 743a2cfc13 Update 'README.md' 2023-04-26 04:25:58 +00:00
Li 2d34072f91 Update 'README.md' 2023-04-26 03:30:10 +00:00
114 changed files with 4140 additions and 4542 deletions

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>ChovySign_CLI</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>C:\Users\Li\Documents\git\Chovy-Sign-v2\ChovySign-CLI\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
<_LastSelectedProfileId>C:\Users\Li\Desktop\git\chovy-sign\ChovySign-CLI\Properties\PublishProfiles\Linux64.pubxml</_LastSelectedProfileId>
</PropertyGroup>
</Project>

View File

@ -4,6 +4,9 @@ using GameBuilder.Psp;
using LibChovy;
using LibChovy.VersionKey;
using System.Text;
using Vita.ContentManager;
using PspCrypto;
using System.ComponentModel;
namespace ChovySign_CLI
{
@ -11,19 +14,29 @@ namespace ChovySign_CLI
{
private static ArgumentParsingMode mode = ArgumentParsingMode.ARG;
private static List<string> parameters = new List<string>();
private static string[] discs;
private static string[] discs = new string[] { };
private static bool pspCompress = false;
private static bool devKit = false;
private static string? popsDiscName;
private static string? popsIcon0File;
private static string? popsPic0File;
private static byte[]? popsIcon0File;
private static byte[]? popsPic0File;
private static PbpMode? pbpMode = null;
private static NpDrmRif? rifFile = null;
private static NpDrmInfo? drmInfo = null;
// cma
private static bool devKit = false;
private static bool packagePsvImg = true;
private static string? outputFolder = null;
// --vkey-gen
private static byte[]? actDat = null;
private static byte[]? idps = null;
private static string? rifFolder = null;
// --pops-eboot-sign
private static byte[]? ebootElf = null;
private static byte[]? configBin = null;
enum PbpMode
{
PSP = 0,
@ -33,15 +46,23 @@ namespace ChovySign_CLI
}
enum ArgumentParsingMode
{
ARG = 0,
POPS_DISC = 1,
PSP_UMD = 2,
VERSIONKEY = 3,
VERSIONKEY_EXTRACT = 4,
VERSIONKEY_GENERATOR = 5,
POPS_INFO = 6,
KEYS_TXT_GEN = 7,
RIF = 8
ARG,
POPS_DISC,
PSP_UMD,
VERSIONKEY,
VERSIONKEY_EXTRACT,
VERSIONKEY_GENERATOR,
CMA_DEVKIT,
CMA_OUTPUT_FOLDER,
CMA_PACKAGE_PSVIMG,
POPS_INFO,
POPS_EBOOT,
KEYS_TXT_GEN,
RIF
}
public static int Error(string errorMsg, int ret)
{
@ -85,6 +106,7 @@ namespace ChovySign_CLI
if(rif.AccountId != accountId) { Error(rif.ContentId + " account id does not match: " + accountId.ToString("X") + " (was " + rif.AccountId.ToString("X") + ")", 10); continue; }
string[] keys = new string[4];
for (int i = 0; i < keys.Length; i++)
keys[i] = BitConverter.ToString(ActRifMethod.GetVersionKey(actDat, rif.Rif, idps, i).VersionKey).Replace("-", "");
@ -92,7 +114,7 @@ namespace ChovySign_CLI
string keysTxt = String.Join(' ', keysTxtLine);
addKeys.AppendLine(keysTxt);
Console.WriteLine(keysTxt);
//Console.WriteLine(keysTxt);
}
File.AppendAllText("KEYS.TXT", addKeys.ToString());
}
@ -102,13 +124,13 @@ namespace ChovySign_CLI
switch (mode)
{
case ArgumentParsingMode.POPS_DISC:
if (parameters.Count > 5) return Error("--pops: no more than 5 disc images allowed in a single game (sony's rules, not mine)", 5);
if (parameters.Count < 1) return Error("--pops: at least 1 disc image file is required.", 5);
if (parameters.Count > 5) return Error("--pops: no more than 5 disc images allowed in a single game (sony's rules, not mine)", 4);
if (parameters.Count < 1) return Error("--pops: at least 1 disc image file is required.", 4);
discs = parameters.ToArray();
break;
case ArgumentParsingMode.PSP_UMD:
if (parameters.Count < 1) return Error("--psp: a path to a disc image is required", 5);
if (parameters.Count > 2) return Error("--psp: no more than 2 arguments. ("+parameters.Count+" given)", 5);
if (parameters.Count < 1) return Error("--psp: a path to a disc image is required", 4);
if (parameters.Count > 2) return Error("--psp: no more than 2 arguments. ("+parameters.Count+" given)", 4);
discs = new string[1];
discs[0] = parameters[0];
@ -123,8 +145,8 @@ namespace ChovySign_CLI
drmInfo = new NpDrmInfo(StringToByteArray(parameters[0]), parameters[1], int.Parse(parameters[2]));
break;
case ArgumentParsingMode.VERSIONKEY_EXTRACT:
if (parameters.Count != 1) return Error("--vkey-extract: expect 1 arguments. ("+parameters.Count+" given)", 4);
drmInfo = EbootPbpMethod.GetVersionKey(File.OpenRead(parameters[0]));
if (parameters.Count != 2) return Error("--vkey-extract: expect 2 arguments. ("+parameters.Count+" given)", 4);
drmInfo = EbootPbpMethod.GetVersionKey(File.OpenRead(parameters[0]), int.Parse(parameters[1]));
break;
case ArgumentParsingMode.VERSIONKEY_GENERATOR:
if(parameters.Count != 4) return Error("--vkey-gen: expect 4 arguments. ("+parameters.Count+" given)", 4);
@ -134,10 +156,10 @@ namespace ChovySign_CLI
if (parameters.Count < 2) return Error("--pops-info takes at least 1 arguments ("+parameters.Count+" given)", 4);
if (parameters.Count > 3) return Error("--pops-info takes no more than 3 arguments("+parameters.Count+" given)", 4);
popsDiscName = parameters[0];
if (parameters.Count > 1)
popsIcon0File = parameters[1];
if (parameters.Count > 2)
popsPic0File = parameters[2];
if (parameters.Count > 1 && File.Exists(parameters[1]))
popsIcon0File = File.ReadAllBytes(parameters[1]);
if (parameters.Count > 2 && File.Exists(parameters[2]))
popsPic0File = File.ReadAllBytes(parameters[2]);
break;
case ArgumentParsingMode.KEYS_TXT_GEN:
if (parameters.Count != 3) return Error("--keys-txt-gen takes 3 arguments, (" + parameters.Count + " given)", 4);
@ -145,6 +167,23 @@ namespace ChovySign_CLI
idps = StringToByteArray(parameters[1]);
rifFolder = parameters[2];
break;
case ArgumentParsingMode.POPS_EBOOT:
if (parameters.Count < 1) return Error("--pops-eboot-sign expects at most 1 arguments", 4);
if (!File.Exists(parameters[0])) return Error("--pops-eboot-sign: file not found", 4);
ebootElf = File.ReadAllBytes(parameters[0]);
if (parameters.Count >= 2 && File.Exists(parameters[1]))
configBin = File.ReadAllBytes(parameters[1]);
else
configBin = GameBuilder.Resources.DATAPSPSDCFG;
break;
case ArgumentParsingMode.CMA_OUTPUT_FOLDER:
if (parameters.Count < 1) return Error("--output-folder expects 1 output", 4);
if (!Directory.Exists(parameters[0])) return Error("--output-folder: directory not found", 4);
SettingsReader.BackupsFolder = parameters[0];
break;
case ArgumentParsingMode.RIF:
if (parameters.Count != 1) return Error("--rif expects only 1 argument,", 4);
rifFile = new NpDrmRif(File.ReadAllBytes(parameters[0]));
@ -155,20 +194,77 @@ namespace ChovySign_CLI
parameters.Clear();
return 0;
}
/*
public static void generateRif(byte[] idps, byte[] actBuf, byte[] versionKey, int versionKeyType, ulong accountId, string contentId)
{
byte[] vkey2 = new byte[versionKey.Length];
Array.Copy(versionKey, vkey2, versionKey.Length);
byte[] rkey = Rng.RandomBytes(0x10);
int keyId = 0x10; // (Int32)(Rng.RandomUInt() % 0x80);
Array.ConstrainedCopy(BitConverter.GetBytes(keyId).Reverse().ToArray(), 0, rkey, 0xC, 0x4);
byte[] encKey1 = new byte[0x10];
AesHelper.AesEncrypt(rkey, encKey1, KeyVault.drmRifKey);
// get the act key
byte[] actKey = new byte[0x10];
SceNpDrm.SetPSID(idps);
SceNpDrm.Aid = accountId;
Act act = MemoryMarshal.AsRef<Act>(actBuf);
GetActKey(actKey, act.PrimKeyTable[(keyId * 0x10)..], 1);
// reverse version key back to main version key
sceNpDrmTransformVersionKey(vkey2, versionKeyType, 0);
byte[] encKey2 = new byte[0x10];
AesHelper.AesEncrypt(vkey2, encKey2, actKey);
using (MemoryStream rifStream = new MemoryStream())
{
StreamUtil rifUtil = new StreamUtil(rifStream);
rifUtil.WriteInt16(0x0);
rifUtil.WriteInt16(0x1);
rifUtil.WriteInt32(0x2);
rifUtil.WriteUInt64(accountId);
rifUtil.WriteStrWithPadding(contentId, 0x00, 0x30);
rifUtil.WriteBytes(encKey1); // enckey1
rifUtil.WriteBytes(encKey2); // enckey2
rifUtil.WriteUInt64(SceRtc.ksceRtcGetCurrentSecureTick());
rifUtil.WriteUInt64(0x00); // expiry
rifUtil.WritePadding(0xFF, 0x28);
}
}
*/
public static int Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Chovy-Sign v2 (CLI)");
Console.WriteLine("--pops [disc1.cue] [disc2.cue] [disc3.cue] ... (up to 5)");
Console.WriteLine("--pops-info [game title] [icon0.png] (optional) [pic1.png] (optional)");
Console.WriteLine("--pops-eboot [eboot.elf] [config.bin] (optional)");
Console.WriteLine("--psp [umd.iso] [compress; true/false] (optional)");
Console.WriteLine("--rif [GAME.RIF]");
Console.WriteLine("--devkit (Use 000000000000 account id)");
Console.WriteLine("--no-psvimg (Disable creating a .psvimg file)");
Console.WriteLine("--output-folder [output_folder]");
Console.WriteLine("--vkey [versionkey] [contentid] [key_index]");
Console.WriteLine("--vkey-extract [eboot.pbp]");
Console.WriteLine("--vkey-extract [eboot.pbp] [key_index]");
Console.WriteLine("--vkey-gen [act.dat] [license.rif] [console_id] [key_index]");
Console.WriteLine("--keys-txt-gen [act.dat] [console_id] [psp_license_folder]");
}
@ -236,6 +332,17 @@ namespace ChovySign_CLI
return Error("rif is already set", 3);
break;
case "--pops-eboot":
mode = ArgumentParsingMode.POPS_EBOOT;
break;
case "--output-folder":
mode = ArgumentParsingMode.CMA_OUTPUT_FOLDER;
break;
case "--no-psvimg":
packagePsvImg = false;
break;
case "--devkit":
devKit = true;
break;
@ -248,6 +355,7 @@ namespace ChovySign_CLI
case ArgumentParsingMode.VERSIONKEY_EXTRACT:
case ArgumentParsingMode.PSP_UMD:
case ArgumentParsingMode.POPS_DISC:
case ArgumentParsingMode.POPS_EBOOT:
case ArgumentParsingMode.POPS_INFO:
case ArgumentParsingMode.RIF:
default:
@ -261,20 +369,17 @@ namespace ChovySign_CLI
generateKeysTxt();
if (drmInfo is null) return Error("no versionkey was found, exiting", 6);
//Console.WriteLine("Version Key: " + BitConverter.ToString(drmInfo.VersionKey).Replace("-", "") + ", " + drmInfo.KeyIndex);
if (pbpMode is null) return Error("no pbp mode was set, exiting", 7);
int targetKeyIndex = (pbpMode == PbpMode.PSP) ? 2 : 1;
if (drmInfo.KeyIndex != targetKeyIndex)
{
SceNpDrm.sceNpDrmTransformVersionKey(drmInfo.VersionKey, drmInfo.KeyIndex, 2);
drmInfo.KeyIndex = targetKeyIndex;
}
if (rifFile is null) return Error("Rif is not set, use --rif to specify base game RIF", 8);
if (pbpMode == PbpMode.PSP && drmInfo.KeyIndex != 2)
return Error("KeyType is "+drmInfo.KeyIndex+", but PBP mode is PSP, you cant do that .. please use a type 1 versionkey.", 8);
if (pbpMode == PbpMode.POPS && drmInfo.KeyIndex != 1)
return Error("KeyType is " + drmInfo.KeyIndex + ", but PBP mode is POPS, you cant do that .. please use a type 1 versionkey.", 8);
if (rifFile is null)
return Error("Rif is not set, use --rif to specify base game RIF", 8);
//if (pbpMode == PbpMode.POPS && (popsDiscName is null || popsIcon0File is null)) return Error("pbp mode is POPS, but you have not specified a disc title or icon file using --pops-info.", 9);
ChovySign csign = new ChovySign();
csign.RegisterCallback(onProgress);
if (pbpMode == PbpMode.POPS)
@ -287,11 +392,17 @@ namespace ChovySign_CLI
if(popsDiscName is not null)
popsParameters.Name = popsDiscName;
if(File.Exists(popsIcon0File))
popsParameters.Icon0 = File.ReadAllBytes(popsIcon0File);
if(popsIcon0File is not null)
popsParameters.Icon0 = popsIcon0File;
popsParameters.CreatePsvImg = packagePsvImg;
popsParameters.Account.Devkit = devKit;
// Allow for custom eboot.elf and configs
popsParameters.ConfigBinOverride = configBin;
popsParameters.EbootElfOverride = ebootElf;
csign.Go(popsParameters);
}
@ -299,6 +410,8 @@ namespace ChovySign_CLI
{
PspParameters pspParameters = new PspParameters(drmInfo, rifFile);
pspParameters.Account.Devkit = devKit;
pspParameters.CreatePsvImg = packagePsvImg;
pspParameters.Compress = pspCompress;
pspParameters.Umd = new UmdInfo(discs.First());

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<History>True|2023-04-23T20:18:55.4774877Z;True|2023-04-20T08:33:00.3404616+12:00;False|2023-04-20T08:29:02.1306599+12:00;True|2023-04-19T21:53:45.1116925+12:00;True|2023-04-19T20:46:20.2756012+12:00;True|2023-04-19T19:58:40.3825010+12:00;True|2023-04-18T00:00:51.4131559+12:00;True|2023-04-17T09:56:35.5065135+12:00;True|2023-04-17T09:22:54.8607008+12:00;True|2023-04-17T08:27:16.5281469+12:00;True|2023-04-17T08:22:02.0531219+12:00;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\Linux</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\Windows</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
</Project>

View File

@ -1,153 +1,123 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ChovySign_GUI.App">
x:Class="ChovySign_GUI.App"
RequestedThemeVariant="Dark">
<Application.Styles>
<FluentTheme Mode="Light"/>
<FluentTheme/>
<!-- Checkbox Styling -->
<Style Selector="CheckBox:checked /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<!-- checked -->
<Style Selector="CheckBox:checked">
<Setter Property="BorderBrush" Value="LightGreen" />
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="LightGreen" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="LightGreen" />
<Setter Property="Background" Value="#3f3f3f" />
</Style>
</Style>
<Style Selector="CheckBox:checked /template/ Border#NormalRectangle">
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
<!-- unchecked -->
<Style Selector="CheckBox:unchecked">
<Setter Property="BorderBrush" Value="LightGreen" />
<Setter Property="Foreground" Value="LightGreen" />
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="LightGreen" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="LightGreen" />
<Setter Property="Background" Value="#3f3f3f" />
</Style>
</Style>
<Style Selector="CheckBox:pointerover /template/ Border#NormalRectangle">
<Setter Property="BorderBrush">
<Setter.Value>Green</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#1f1f1f</Setter.Value>
</Setter>
</Style>
<!-- pointerover -->
<Style Selector="CheckBox /template/ Border#NormalRectangle">
<Setter Property="BorderBrush">
<Setter.Value>Green</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
</Style>
<Style Selector="CheckBox:pointerover">
<Setter Property="BorderBrush" Value="Green" />
<Style Selector="CheckBox:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground">
<Setter.Value>Green</Setter.Value>
</Setter>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Foreground" Value="Green" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="Green" />
<Setter Property="Background" Value="#1f1f1f" />
</Style>
</Style>
<Style Selector="CheckBox">
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
</Style>
<!-- Button styles -->
<Style Selector="Button:disabled /template/ ContentPresenter">
<Setter Property="Background">
<Setter.Value>Black</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>DarkRed</Setter.Value>
</Setter>
<Setter Property="TextBlock.Foreground">
<Setter.Value>DarkRed</Setter.Value>
</Setter>
<!-- disabled -->
<Style Selector="Button:disabled">
<Style Selector="^:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="Black" />
<Setter Property="BorderBrush" Value="DarkRed" />
<Setter Property="Foreground" Value="DarkRed" />
</Style>
</Style>
<Style Selector="Button:pointerover /template/ ContentPresenter">
<Setter Property="Background">
<Setter.Value>Red</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>DarkRed</Setter.Value>
</Setter>
<Setter Property="TextBlock.Foreground">
<Setter.Value>Black</Setter.Value>
</Setter>
<!-- pointerover -->
<Style Selector="Button:pointerover">
<Style Selector="^:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="Red" />
<Setter Property="BorderBrush" Value="DarkRed" />
<Setter Property="Foreground" Value="Black" />
</Style>
</Style>
<!-- regular -->
<Style Selector="Button">
<Setter Property="BorderThickness">
<Setter.Value>1</Setter.Value>
</Setter>
<Setter Property="Foreground">
<Setter.Value>Red</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>Red</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>Black</Setter.Value>
</Setter>
<Setter Property="Background" Value="Black" />
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="Foreground" Value="Red" />
<Setter Property="BorderThickness" Value="1" />
</Style>
<!-- Textbox Styling -->
<Style Selector="TextBox:focus">
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
</Style>
<Setter Property="Foreground" Value="LightGreen" />
<Style Selector="^ /template/ TextBlock">
<Setter Property="Foreground" Value="LightGreen" />
</Style>
<Style Selector="TextBox:focus /template/ TextBlock">
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
</Style>
<Style Selector="TextBox:focus /template/ Border">
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Style Selector="^ /template/ Border">
<Setter Property="Background" Value="#3f3f3f" />
<Setter Property="BorderBrush" Value="LightGreen" />
</Style>
</Style>
<Style Selector="TextBox:pointerover">
<Setter Property="Foreground">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
<Setter Property="Foreground" Value="Green" />
<Style Selector="TextBox:pointerover /template/ TextBlock">
<Setter Property="Foreground">
<Setter.Value>Green</Setter.Value>
</Setter>
<Style Selector="^ /template/ TextBlock">
<Setter Property="Foreground" Value="Green" />
</Style>
<Style Selector="^ /template/ Border">
<Setter Property="Background" Value="#1f1f1f" />
<Setter Property="BorderBrush" Value="Green" />
</Style>
</Style>
<Style Selector="TextBox:pointerover /template/ Border">
<Setter Property="Background">
<Setter.Value>#1f1f1f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
<Style Selector="TextBox">
<Setter Property="Foreground">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>#3f3f3f</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>LightGreen</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="LightGreen" />
<Setter Property="Background" Value="#3f3f3f" />
<Setter Property="BorderBrush" Value="LightGreen" />
</Style>
<!-- ComboBox -->

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
@ -16,8 +16,6 @@
<None Remove="Icon.png" />
<None Remove="Popup\Global\KeySelector\ACTRIFMETHOD.PNG" />
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD.PNG" />
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD1.png" />
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD2.png" />
<None Remove="Popup\Global\KeySelector\KEYSTXTMETHOD.PNG" />
<None Remove="PS1CD.PNG" />
<None Remove="UMD.png" />
@ -25,8 +23,7 @@
<ItemGroup>
<AvaloniaResource Include="ICON.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\ACTRIFMETHOD.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\EBOOTMETHOD1.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\EBOOTMETHOD2.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\EBOOTMETHOD.PNG" />
<AvaloniaResource Include="Popup\Global\KeySelector\KEYSTXTMETHOD.PNG" />
<AvaloniaResource Include="Ps1\PS1CD.PNG" />
<AvaloniaResource Include="Psp\UMD.PNG">
@ -42,11 +39,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.19" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.19" />
<PackageReference Include="Avalonia" Version="11.1.0-beta1" />
<PackageReference Include="Avalonia.Desktop" Version="11.1.0-beta1" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.19" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.6.1" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.0-beta1" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.0-beta1" />
</ItemGroup>
<ItemGroup>
@ -55,10 +52,12 @@
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Global\DevkitToggle.axaml" />
</ItemGroup>
<ItemGroup>
<Compile Update="Settings\ConfigPath.axaml.cs">
<DependentUpon>ConfigPath.axaml</DependentUpon>
</Compile>
<Compile Update="Settings\ConfigToggle.axaml.cs">
<DependentUpon>ConfigToggle.axaml</DependentUpon>
</Compile>
<Compile Update="Resource.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>

View File

@ -176,19 +176,28 @@ namespace ChovySign_GUI.Global
}
}
public BrowseButton()
{
InitializeComponent();
this.filePath.KeyUp += onKeyPress;
this.filePath.PropertyChanged += onPropertyChanged;
this.extension = "";
this.fileTypeName = "All Files";
}
private void onKeyPress(object? sender, KeyEventArgs e)
private void onPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
OnFileChanged(new EventArgs());
TextBox? txt = sender as TextBox;
if (txt is null) return;
if (e.Property.Name == "Text")
{
if (txt.Text is null) return;
if (!ContainsFile) return;
OnFileChanged(new EventArgs());
}
}
}
}

View File

@ -1,86 +0,0 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Popup.Global;
using LibChovy.Config;
using System;
using System.Collections.Generic;
using static ChovySign_GUI.Popup.Global.MessageBox;
namespace ChovySign_GUI.Global
{
public partial class DevkitToggle : UserControl
{
private static List<DevkitToggle> instances = new List<DevkitToggle>();
private const string useDevkitModeConfigKey = "USE_DEVKIT_ACCOUNT_ID";
internal bool disableEvents = false;
private async void onDevkitModeChecked(object? sender, RoutedEventArgs e)
{
if (disableEvents) return;
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? devMode = checkBox.IsChecked;
if (devMode is null) devMode = false;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
MessageBoxResult res = await MessageBox.Show(currentWindow, "This option will force the CMA Account ID to be all 0's\nWhich is how it is on Devkit, Testkit and IDU Firmware\nEnabling this if you have a retail firmware will result in the games just *not* showing up\n\nIf you DON'T know what this means, DON'T enable this.\ndo you want to continue?", "Are you sure?", MessageBoxButtons.YesNo);
if (res == MessageBoxResult.Yes)
{
IsDevkitMode = true;
}
else
{
IsDevkitMode = false;
}
}
private void onDevkitModeUnchecked(object? sender, RoutedEventArgs e)
{
if (disableEvents) return;
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? devMode = checkBox.IsChecked;
if (devMode is null) devMode = false;
IsDevkitMode = (bool)devMode;
}
public bool IsDevkitMode
{
get
{
if (this.devkitCheckbox.IsChecked is null) return false;
return (bool)this.devkitCheckbox.IsChecked;
}
set
{
foreach (DevkitToggle instance in instances)
{
instance.disableEvents = true;
instance.devkitCheckbox.IsChecked = value;
instance.disableEvents = false;
}
ChovyConfig.CurrentConfig.SetBool(useDevkitModeConfigKey, value);
}
}
public DevkitToggle()
{
InitializeComponent();
bool? isDevkitMode = ChovyConfig.CurrentConfig.GetBool(useDevkitModeConfigKey);
if (isDevkitMode is null) isDevkitMode = false;
devkitCheckbox.IsChecked = isDevkitMode;
devkitCheckbox.Unchecked += onDevkitModeUnchecked;
devkitCheckbox.Checked += onDevkitModeChecked;
instances.Add(this);
}
}
}

View File

@ -83,10 +83,24 @@ namespace ChovySign_GUI.Global
public FilteredTextBox()
{
InitializeComponent();
this.txtBox.PastingFromClipboard += onPaste;
this.txtBox.PropertyChanged += onPropertyChanged;
this.txtBox.AddHandler(TextInputEvent, onTxtInput, RoutingStrategies.Tunnel);
}
private void onPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
TextBox? txt = sender as TextBox;
if (txt is null) return;
if (e.Property.Name == "Text")
{
if (txt.Text is null) return;
txt.Text = filter(txt.Text);
OnTextChanged(new EventArgs());
}
}
private string filter(string original)
{
@ -104,36 +118,6 @@ namespace ChovySign_GUI.Global
}
return original;
}
private async Task<bool> setClipboardText(string text)
{
if (Application.Current is null) return false;
if (Application.Current.Clipboard is null) return false;
await Application.Current.Clipboard.SetTextAsync(text);
return true;
}
private async Task<string> getClipboardText()
{
if (Application.Current is null) return "";
if (Application.Current.Clipboard is null) return "";
string? clipboard = await Application.Current.Clipboard.GetTextAsync();
if (clipboard is null) return "";
return clipboard;
}
private async void onPaste(object? sender, RoutedEventArgs e)
{
TextBox? txt = sender as TextBox;
if (txt is null) return;
string clipboard = getClipboardText().Result;
clipboard = filter(clipboard);
_ = setClipboardText(clipboard).Result;
// annoyingly, the text being pasted isnt actually in the textbox yet
// and it wont trigger a textInput event when pasting; t-this really is the best can do
await Task.Delay(100);
OnTextChanged(new EventArgs());
}
private void onTxtInput(object? sender, TextInputEventArgs e)
{

View File

@ -153,19 +153,19 @@ namespace ChovySign_GUI.Global
break;
case VersionKeyMethod.EBOOT_PBP_METHOD:
CmaBackupPicker ebootBackupSelector = new CmaBackupPicker();
ebootBackupSelector.BackupType = ((keyIndex == 1) ? "PSGAME" : "PGAME");
ebootBackupSelector.BackupType = new string[] { "PGAME", "PSGAME" };
string? gameBackupFolder = await ebootBackupSelector.ShowDialog<string>(currentWindow);
string accountId = ebootBackupSelector.AccountId;
if (gameBackupFolder is null) break;
if (accountId == "") break;
key = CMAVersionKeyHelper.GetKeyFromGamePsvimg(gameBackupFolder, accountId);
key = CMAVersionKeyHelper.GetKeyFromGamePsvimg(gameBackupFolder, accountId, this.keyIndex);
rif = CMAVersionKeyHelper.GetRifFromLicensePsvimg(gameBackupFolder, accountId);
break;
case VersionKeyMethod.KEYS_TXT_METHOD:
CmaBackupPicker pspLicenseBackupSelector = new CmaBackupPicker();
pspLicenseBackupSelector.BackupType = "PGAME";
pspLicenseBackupSelector.BackupType = new string[] { "PGAME", "PSGAME" };
pspLicenseBackupSelector.Filter = KeysTxtMethod.TitleIds;
gameBackupFolder = await pspLicenseBackupSelector.ShowDialog<string>(currentWindow);
@ -186,10 +186,8 @@ namespace ChovySign_GUI.Global
if (key is not null)
{
if (key.KeyIndex != this.keyIndex)
{
await MessageBox.Show(currentWindow, "VersionKey obtained, but had keyindex: " + key.KeyIndex + " however keyindex " + this.keyIndex + " was required.", "KeyIndex mismatch!", MessageBoxButtons.Ok);
return;
}
sceNpDrmTransformVersionKey(key.VersionKey, key.KeyIndex, this.keyIndex);
// its a revoolution~
VersionKey = key.VersionKey;
}

View File

@ -52,9 +52,15 @@ namespace ChovySign_GUI.Global
public string[] Items
{
get
{
string[]? strings = this.comboBox.ItemsSource as string[];
if (strings is null) return new string[0];
return strings;
}
set
{
this.comboBox.Items = value;
this.comboBox.ItemsSource = value;
}
}

View File

@ -2,6 +2,7 @@ using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using ChovySign_GUI.Popup.Global;
using ChovySign_GUI.Settings;
using Li.Progress;
using LibChovy;
using System;
@ -13,6 +14,8 @@ namespace ChovySign_GUI.Global
public partial class ProgressStatus : UserControl
{
public ChovySignParameters? Parameters = null;
public event EventHandler<EventArgs>? Finished;
public event EventHandler<EventArgs>? BeforeStart;
private ChovySign chovySign;
public ProgressStatus()
{
@ -21,14 +24,13 @@ namespace ChovySign_GUI.Global
chovySign = new ChovySign();
chovySign.RegisterCallback(onProgress);
}
public event EventHandler<EventArgs>? BeforeStart;
protected virtual void OnBeforeStart(EventArgs e)
{
if (BeforeStart is not null)
BeforeStart(this, e);
}
public event EventHandler<EventArgs>? Finished;
protected virtual void OnFinished(EventArgs e)
{
if (Finished is not null)
@ -42,15 +44,25 @@ namespace ChovySign_GUI.Global
if (currentWindow is not Window) throw new Exception("could not find current window");
this.goButton.IsEnabled = false;
OnBeforeStart(new EventArgs());
// sanity check it
if(Parameters is null) { await MessageBox.Show(currentWindow, "ChovySignParameters was null, cannot start!", "Invalid Parameters", MessageBoxButtons.Ok); return; }
// apply settings that are global to all signs
if(SettingsTab.Settings is not null) Parameters.BuildStreamType = SettingsTab.Settings.BuildStreamType;
await Task.Run(() => { chovySign.Go(Parameters); });
try
{
await Task.Run(() => {
chovySign.Go(Parameters);
});
}
catch (Exception ex)
{
await MessageBox.Show(currentWindow, "Error building: " + ex.Message + "\n\nSTACKTRACE: " + ex.StackTrace, "ERROR", MessageBoxButtons.Ok);
return;
}
OnFinished(new EventArgs());
this.goButton.IsEnabled = true;
}

View File

@ -4,7 +4,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Ps1="clr-namespace:ChovySign_GUI.Ps1"
xmlns:Psp="clr-namespace:ChovySign_GUI.Psp"
mc:Ignorable="d" d:DesignWidth="850" d:DesignHeight="950"
xmlns:Settings="clr-namespace:ChovySign_GUI.Settings"
mc:Ignorable="d" d:DesignWidth="850" d:DesignHeight="760"
MinHeight="760"
x:Class="ChovySign_GUI.MainWindow"
Title="Chovy Sign V2" Icon="/ICON.PNG">
@ -13,9 +15,12 @@
<TabItem Header="PlayStation Portable">
<Psp:PspTab Name="pspTab"/>
</TabItem>
<TabItem Header="PlayStation 1">
<TabItem Header="PlayStation One">
<Ps1:Ps1Tab Name="ps1Tab"/>
</TabItem>
<TabItem Header="Settings">
<Settings:SettingsTab Name="settingsTab"/>
</TabItem>
</TabControl>
</Grid>

View File

@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Controls;
namespace ChovySign_GUI

View File

@ -3,7 +3,8 @@ using Avalonia.Interactivity;
using ChovySign_GUI.Global;
using GameBuilder.Psp;
using LibChovy.Config;
using Org.BouncyCastle.Utilities.Bzip2;
using Org.BouncyCastle.Asn1;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -16,7 +17,7 @@ namespace ChovySign_GUI.Popup.Global
private const string lookingInLabelText = "Looking in: ";
private string[]? gameDirectories;
private string backupSubFolder = "";
private string[] backupSubFolders;
private string[]? filter;
@ -69,50 +70,80 @@ namespace ChovySign_GUI.Popup.Global
}
}
private string accountIdSearchFolder
private string[] accountIdSearchFolders
{
get
{
string searchIn = Path.Combine(BackupDir, this.BackupType);
string[] searchIn = new string[this.BackupType.Length];
for (int i = 0; i < this.BackupType.Length; i++)
{
searchIn[i] = Path.Combine(BackupDir, this.BackupType[i]);
}
return searchIn;
}
}
private string backupSearchFolder
private string[] backupSearchFolders
{
get
{
if (AccountId == "") return accountIdSearchFolder;
return Path.Combine(accountIdSearchFolder, AccountId);
string[] backupFolders = new string[this.BackupType.Length];
string[] searchFolders = this.accountIdSearchFolders;
for (int i = 0; i < this.BackupType.Length; i++)
{
if (this.AccountId == "") backupFolders[i] = searchFolders[i];
backupFolders[i] = Path.Combine(searchFolders[i], this.AccountId);
}
return backupFolders;
}
}
public string BackupType
public string[] BackupType
{
get
{
return backupSubFolder;
return backupSubFolders;
}
set
{
backupSubFolder = value;
lookingInLbl.Content = lookingInLabelText + backupSubFolder;
backupSubFolders = value;
lookingInLbl.Content = lookingInLabelText + String.Join(", ", backupSubFolders);
reloadAccountIdsList();
reloadBackupsList();
}
}
private string[] GetAllDriectories(string[] dirList)
{
List<string> foundDir = new List<string>();
foreach(string dirSearch in dirList)
{
if (!Directory.Exists(dirSearch)) continue;
foreach(string dir in Directory.GetDirectories(dirSearch))
{
if (!foundDir.Contains(dir))
{
foundDir.Add(dir);
}
}
}
return foundDir.ToArray();
}
private void reloadAccountIdsList()
{
try
{
string[] usedAccountIds = Directory.GetDirectories(accountIdSearchFolder);
string[] usedAccountIds = GetAllDriectories(accountIdSearchFolders);
List<string> accountIdLst = new List<string>();
foreach (string accountId in usedAccountIds)
{
string aid = Path.GetFileName(accountId);
if (accountIdLst.Contains(aid)) continue;
if (aid.Length != 16) continue;
accountIdLst.Add(aid);
}
this.accId.Items = accountIdLst.ToArray();
@ -139,11 +170,11 @@ namespace ChovySign_GUI.Popup.Global
private void reloadBackupsList()
{
this.selectBtn.IsEnabled = false;
this.backupList.Items = new string[0];
this.backupList.ItemsSource = new string[0];
try
{
if(!Directory.Exists(backupSearchFolder)) { return; }
string[] gameBackupDirectories = Directory.GetDirectories(backupSearchFolder);
string[] gameBackupDirectories = GetAllDriectories(backupSearchFolders);
List<string> filteredGameDirectories = new List<string>();
List<string> gameList = new List<string>();
foreach (string gameDirectory in gameBackupDirectories)
@ -171,7 +202,7 @@ namespace ChovySign_GUI.Popup.Global
}
this.gameDirectories = filteredGameDirectories.ToArray();
this.backupList.Items = gameList;
this.backupList.ItemsSource = gameList;
}
catch { }
}
@ -180,7 +211,7 @@ namespace ChovySign_GUI.Popup.Global
{
InitializeComponent();
this.cmaDir.FilePath = BackupDir;
this.backupSubFolder = "APP";
this.backupSubFolders = new string[] { "APP" };
this.accId.SelectionChanged += onAccountSelectionChanged;
this.cmaDir.FileChanged += onCmaDirChanged;
this.backupList.SelectionChanged += onSelectedBackupChanged;
@ -191,6 +222,7 @@ namespace ChovySign_GUI.Popup.Global
private void onSelectedBackupChanged(object? sender, SelectionChangedEventArgs e)
{
ListBox? lstBox = sender as ListBox;
if (lstBox is null) return;
if (lstBox.SelectedIndex == -1) selectBtn.IsEnabled = false;
else selectBtn.IsEnabled = true;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -21,8 +21,7 @@
<Button Content="IDPS+RIF+ACT Method" Click="actRifMethodClick" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Button Content="KEYS.TXT Method" Click="keysTxtMethodClick" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Image Name="ebootMethodPs1Graphic" Source="/Popup/Global/KeySelector/EBOOTMETHOD1.PNG" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<Image Name="ebootMethodPspGraphic" Source="/Popup/Global/KeySelector/EBOOTMETHOD2.PNG" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<Image Name="ebootMethodGraphic" Source="/Popup/Global/KeySelector/EBOOTMETHOD.PNG" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<Image Name="actRifMethodGraphic" Source="/Popup/Global/KeySelector/ACTRIFMETHOD.PNG" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<Image Name="keysTxtMethodGraphic" Source="/Popup/Global/KeySelector/KEYSTXTMETHOD.PNG" Grid.Row="1" Grid.Column="2" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
</Grid>

View File

@ -20,8 +20,6 @@ namespace ChovySign_GUI.Popup.Global.KeySelector
set
{
keyIndex = value;
if (keyIndex == 1) { ebootMethodPspGraphic.IsVisible = false; ebootMethodPs1Graphic.IsVisible = true; }
else { ebootMethodPspGraphic.IsVisible = true; ebootMethodPs1Graphic.IsVisible = false; }
}
}

View File

@ -3,7 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="300"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="280"
x:Class="ChovySign_GUI.Ps1.CueSelector">
<!-- Bin/Cue Image selector -->
<Border Padding="5 5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

View File

@ -3,7 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="250"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="280"
x:Class="ChovySign_GUI.Ps1.GameInfoSelector">
<Border Padding="5 5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid>
@ -18,11 +18,13 @@
<RowDefinition Height="52"/>
<RowDefinition Height="52"/>
<RowDefinition Height="52"/>
<RowDefinition Height="52"/>
</Grid.RowDefinitions>
<Global:LabeledTextBox HorizontalAlignment="Stretch" Name="gameTitle" Label="Title:" Watermark="The BEST PlayStation 1 Game" MaxLength="128" Grid.Row="0"/>
<Global:BrowseButton HorizontalAlignment="Stretch" Name="iconFile" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="icon0.png:" Grid.Row="1"/>
<Global:BrowseButton HorizontalAlignment="Stretch" Name="pic0File" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="pic0.png:" Grid.Row="2"/>
<Global:BrowseButton HorizontalAlignment="Stretch" Name="pic1File" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="pic1.png:" Grid.Row="3"/>
<Global:LabeledTextBox HorizontalAlignment="Stretch" Name="discId" AllowedChars="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" Label="Disc ID:" Watermark="SLUS00001" MaxLength="9" Grid.Row="4"/>
</Grid>
</Grid>
</Border>

View File

@ -19,7 +19,18 @@ namespace ChovySign_GUI.Ps1
private byte[] iconCache;
private byte[] pic0Cache;
private byte[] pic1Cache;
public string DiscId
{
get
{
if (this.discId.Text is null) return "";
return this.discId.Text;
}
set
{
this.discId.Text = value;
}
}
public string Title
{
get
@ -84,14 +95,23 @@ namespace ChovySign_GUI.Ps1
{
try
{
DiscInfo disc = new DiscInfo(cueFile);
PSInfo disc = new PSInfo(cueFile);
Title = disc.DiscName;
DiscId = disc.DiscId;
byte[] newCover = await Downloader.DownloadCover(disc);
loadIcon(newCover);
iconCache = newCover;
if (!File.Exists(this.iconFile.FilePath))
{
byte[] newCover = await Downloader.DownloadCover(disc);
loadIcon(newCover);
iconCache = newCover;
}
}
catch (Exception e) {
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
await MessageBox.Show(currentWindow, "unable to read cue sheet: " + Path.GetFileName(cueFile) + "\n" + e.Message + "\n\nSTACKTRACE: " + e.StackTrace, "cannot load cue sheet", MessageBox.MessageBoxButtons.Ok);
}
catch (Exception) { }
}
private async Task<byte[]?> doLoad(BrowseButton imgFile, int width, int height)
@ -147,6 +167,13 @@ namespace ChovySign_GUI.Ps1
if (TitleChanged is not null)
TitleChanged(this, e);
}
public event EventHandler<EventArgs>? DiscIdChanged;
protected virtual void OnDiscIdChanged(EventArgs e)
{
if (DiscIdChanged is not null)
DiscIdChanged(this, e);
}
public GameInfoSelector()
{
InitializeComponent();
@ -161,6 +188,13 @@ namespace ChovySign_GUI.Ps1
this.pic1File.FileChanged += onPic1Change;
this.gameTitle.TextChanged += onTitleChange;
this.discId.TextChanged += onDiscIdChange;
}
private void onDiscIdChange(object? sender, EventArgs e)
{
OnDiscIdChanged(new EventArgs());
}
private void onTitleChange(object? sender, EventArgs e)

View File

@ -10,9 +10,9 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="1.5*" />
<RowDefinition Height="1.3*" />
<RowDefinition Height="0.6*" />
<RowDefinition Height="280" />
<RowDefinition Height="280" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
@ -22,14 +22,13 @@
<Global:KeySelector Name="keySelector" KeyIndex="1" Grid.Row="0" Grid.Column="1"/>
<Ps1:CueSelector Name="discSelector" Grid.Row="1" Grid.Column="1"/>
<Ps1:GameInfoSelector Name="gameInfo" Grid.Row="2" Grid.Column="1"/>
<Ps1:CueSelector Name="discSelector" Height="280" Grid.Row="1" Grid.Column="1"/>
<Ps1:GameInfoSelector Name="gameInfo" Height="280" Grid.Row="2" Grid.Column="1"/>
<Global:ProgressStatus VerticalAlignment="Center" Name="progressStatus" Grid.Row="3" Grid.Column="1"/>
</Grid>
<!-- Credits -->
<Global:DevkitToggle Name="devkitAccount" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<Label Content="Li, Dots TB, SquallATF, Motoharu, Davee" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</UserControl>

View File

@ -1,10 +1,9 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Global;
using ChovySign_GUI.Popup.Global;
using ChovySign_GUI.Settings;
using GameBuilder.Psp;
using LibChovy;
using LibChovy.Config;
using System;
using System.Linq;
using Vita.ContentManager;
@ -21,6 +20,7 @@ namespace ChovySign_GUI.Ps1
discSelector.DiscsSelected += onDiscSelected;
keySelector.ValidStateChanged += onKeyValidityChanged;
gameInfo.TitleChanged += onTitleChanged;
gameInfo.DiscIdChanged += onDiscIdChanged;
progressStatus.BeforeStart += onProcessStarting;
progressStatus.Finished += onProcessFinished;
@ -28,13 +28,12 @@ namespace ChovySign_GUI.Ps1
}
private async void onProcessFinished(object? sender, EventArgs e)
{
keySelector.IsEnabled = true;
discSelector.IsEnabled = true;
devkitAccount.IsEnabled = true;
gameInfo.IsEnabled = true;
SettingsTab.Settings.IsEnabled = true;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
@ -47,34 +46,43 @@ namespace ChovySign_GUI.Ps1
{
keySelector.IsEnabled = false;
discSelector.IsEnabled = false;
devkitAccount.IsEnabled = false;
gameInfo.IsEnabled = false;
SettingsTab.Settings.IsEnabled = false;
if (keySelector.Rif is null) return;
if (keySelector.VersionKey is null) return;
NpDrmRif rifInfo = new NpDrmRif(keySelector.Rif);
NpDrmInfo drmInfo = new NpDrmInfo(keySelector.VersionKey, rifInfo.ContentId, keySelector.KeyIndex);
PspParameters pspParameters = new PspParameters(drmInfo, rifInfo);
PopsParameters popsParameters = new PopsParameters(drmInfo, rifInfo);
foreach (string disc in discSelector.Discs)
popsParameters.AddCd(disc);
popsParameters.Name = gameInfo.Title;
popsParameters.Icon0 = gameInfo.Icon0;
popsParameters.Pic0 = gameInfo.Pic0;
popsParameters.Pic1 = gameInfo.Pic1;
popsParameters.Name = gameInfo.Title;
popsParameters.DiscId = gameInfo.DiscId;
popsParameters.Icon0 = gameInfo.Icon0;
popsParameters.Pic0 = gameInfo.Pic0;
popsParameters.Pic1 = gameInfo.Pic1;
if (devkitAccount.IsDevkitMode)
popsParameters.Account = new Account(0);
// read settings from settings tab.
if (SettingsTab.Settings.DevkitMode) popsParameters.Account = new Account(0);
popsParameters.CrackMethod = SettingsTab.Settings.LibcryptMode;
SettingsReader.BackupsFolder = SettingsTab.Settings.CmaDirectory;
popsParameters.CreatePsvImg = SettingsTab.Settings.PackagePsvimg;
progressStatus.Parameters = popsParameters;
}
private void onDiscIdChanged(object? sender, EventArgs e)
{
check();
}
private void onTitleChanged(object? sender, EventArgs e)
{
check();
@ -82,7 +90,7 @@ namespace ChovySign_GUI.Ps1
private void check()
{
this.progressStatus.IsEnabled = (discSelector.AnyDiscsSelected && keySelector.IsValid && gameInfo.Title != "");
this.progressStatus.IsEnabled = (discSelector.AnyDiscsSelected && keySelector.IsValid && gameInfo.Title != "" && gameInfo.DiscId.Length == 9);
}
private void onKeyValidityChanged(object? sender, EventArgs e)
{

View File

@ -26,7 +26,6 @@
</Grid>
<!-- Credits -->
<Global:DevkitToggle Name="devkitAccount" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<Label Content="Li, Dots TB, SquallATF, Motoharu, Davee" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</UserControl>

View File

@ -1,11 +1,13 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Popup.Global;
using ChovySign_GUI.Settings;
using GameBuilder.Psp;
using LibChovy;
using LibChovy.Config;
using System;
using System.Media;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Vita.ContentManager;
using static ChovySign_GUI.Popup.Global.MessageBox;
@ -36,7 +38,7 @@ namespace ChovySign_GUI.Psp
{
keySelector.IsEnabled = true;
isoSelector.IsEnabled = true;
devkitAccount.IsEnabled = true;
SettingsTab.Settings.IsEnabled = true;
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
@ -48,8 +50,9 @@ namespace ChovySign_GUI.Psp
private void onProcessStarting(object? sender, EventArgs e)
{
keySelector.IsEnabled = false;
devkitAccount.IsEnabled = false;
isoSelector.IsEnabled = false;
SettingsTab.Settings.IsEnabled = false;
if (keySelector.Rif is null) return;
if (keySelector.VersionKey is null) return;
@ -63,8 +66,10 @@ namespace ChovySign_GUI.Psp
pspParameters.Umd = umd;
pspParameters.Compress = isoSelector.Compress;
if (devkitAccount.IsDevkitMode)
pspParameters.Account = new Account(0);
// read settings from settings tab.
pspParameters.Account.Devkit = SettingsTab.Settings.DevkitMode;
SettingsReader.BackupsFolder = SettingsTab.Settings.CmaDirectory;
pspParameters.CreatePsvImg = SettingsTab.Settings.PackagePsvimg;
progressStatus.Parameters = pspParameters;
}

View File

@ -0,0 +1,30 @@
using Avalonia.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ChovySign_GUI.Settings
{
public abstract class ConfigControl : UserControl
{
private string? configKey = null;
public string ConfigKey
{
get
{
if (configKey is null) return "";
return configKey;
}
set
{
configKey = value;
init();
}
}
internal abstract void init();
}
}

View File

@ -0,0 +1,11 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="85"
x:Class="ChovySign_GUI.Settings.ConfigDropDown">
<Grid>
<Global:LabeledComboBox Name="configComboBox" Label="Label"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,71 @@
using Avalonia.Controls;
using ChovySign_GUI.Global;
using LibChovy.Config;
using System;
namespace ChovySign_GUI.Settings
{
public partial class ConfigDropDown : ConfigControl
{
internal override void init()
{
int? cfgInt = ChovyConfig.CurrentConfig.GetInt(ConfigKey);
if (cfgInt is null) cfgInt = 0;
this.configComboBox.SelectedIndex = (int)cfgInt;
}
public string Label
{
get
{
return this.configComboBox.Label;
}
set
{
this.configComboBox.Label = value;
}
}
public int SelectedIndex
{
get
{
return this.configComboBox.SelectedIndex;
}
set
{
this.configComboBox.SelectedIndex = value;
if (this.configComboBox.SelectedIndex < 0) return;
ChovyConfig.CurrentConfig.SetInt(ConfigKey, this.configComboBox.SelectedIndex);
}
}
public string[] Items
{
get
{
return this.configComboBox.Items;
}
set
{
this.configComboBox.Items = value;
init();
}
}
public ConfigDropDown()
{
InitializeComponent();
init();
this.configComboBox.SelectionChanged += onSelectionChange;
}
private void onSelectionChange(object? sender, EventArgs e)
{
LabeledComboBox? comboBox = sender as LabeledComboBox;
if (comboBox is null) return;
if (comboBox.SelectedIndex < 0) return;
ChovyConfig.CurrentConfig.SetInt(ConfigKey, comboBox.SelectedIndex);
}
}
}

View File

@ -0,0 +1,11 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
x:Class="ChovySign_GUI.Settings.ConfigPath">
<Grid>
<Global:BrowseButton Name="configPath" Label="Label"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,92 @@
using Avalonia.Controls;
using ChovySign_GUI.Global;
using LibChovy.Config;
using System;
namespace ChovySign_GUI.Settings
{
public partial class ConfigPath : ConfigControl
{
internal override void init()
{
string? cfgText = ChovyConfig.CurrentConfig.GetString(ConfigKey);
if (cfgText is null) cfgText = "";
configPath.FilePath = cfgText;
}
public string Label
{
get
{
return configPath.Label;
}
set
{
configPath.Label = value;
}
}
public string Value
{
get
{
return this.configPath.FilePath;
}
set
{
this.configPath.FilePath = value;
if(configPath.ContainsFile)
ChovyConfig.CurrentConfig.SetString(ConfigKey, this.configPath.FilePath);
}
}
public bool IsDirectory
{
get
{
return this.configPath.IsDirectory;
}
set
{
this.configPath.IsDirectory = value;
}
}
public string Extension
{
get
{
return this.configPath.Extension;
}
set
{
this.configPath.Extension = value;
}
}
public string FileTypeName
{
get
{
return this.configPath.FileTypeName;
}
set
{
this.configPath.FileTypeName = value;
}
}
public ConfigPath()
{
InitializeComponent();
init();
this.configPath.FileChanged += onFileChange;
}
private void onFileChange(object? sender, EventArgs e)
{
BrowseButton? browseBtn = sender as BrowseButton;
if (browseBtn is null) return;
if (!browseBtn.ContainsFile) return;
ChovyConfig.CurrentConfig.SetString(ConfigKey, browseBtn.FilePath);
}
}
}

View File

@ -0,0 +1,11 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
x:Class="ChovySign_GUI.Settings.ConfigText">
<Grid>
<Global:LabeledTextBox Name="configText" Label="Label"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,58 @@
using Avalonia.Controls;
using ChovySign_GUI.Global;
using LibChovy.Config;
using System;
namespace ChovySign_GUI.Settings
{
public partial class ConfigText : ConfigControl
{
internal override void init()
{
string? cfgText = ChovyConfig.CurrentConfig.GetString(ConfigKey);
if (cfgText is null) cfgText = "";
configText.Text = cfgText;
}
public string Label
{
get
{
return configText.Label;
}
set
{
configText.Label = value;
}
}
public string Value
{
get
{
if (this.configText.Text is null) return "";
return (string)this.configText.Text;
}
set
{
this.configText.Text = value;
ChovyConfig.CurrentConfig.SetString(ConfigKey, value);
}
}
public ConfigText()
{
InitializeComponent();
init();
this.configText.TextChanged += onTextChange;
}
private void onTextChange(object? sender, EventArgs e)
{
LabeledTextBox? txtBox = sender as LabeledTextBox;
if (txtBox is null) return;
if (txtBox.Text is null) return;
ChovyConfig.CurrentConfig.SetString(ConfigKey, txtBox.Text);
}
}
}

View File

@ -3,8 +3,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
x:Class="ChovySign_GUI.Global.DevkitToggle">
x:Class="ChovySign_GUI.Settings.ConfigToggle">
<Grid>
<CheckBox Name="devkitCheckbox" Content="I have a DevKit, TestKit or IDU Vita"/>
<CheckBox Name="configCheckbox" Content="Label"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,133 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using ChovySign_GUI.Popup.Global;
using LibChovy.Config;
using System;
using System.Collections.Generic;
using static ChovySign_GUI.Popup.Global.MessageBox;
namespace ChovySign_GUI.Settings
{
public partial class ConfigToggle : ConfigControl
{
internal bool disableEvents = false;
private string? promptMsg = null;
private bool defaultSetting = false;
internal override void init()
{
bool? isToggleChecked = ChovyConfig.CurrentConfig.GetBool(ConfigKey);
if(isToggleChecked is null) isToggleChecked = defaultSetting;
this.disableEvents = true;
configCheckbox.IsChecked = isToggleChecked;
this.disableEvents = false;
}
public bool Default
{
get
{
return defaultSetting;
}
set
{
defaultSetting = value;
if (ChovyConfig.CurrentConfig.GetBool(ConfigKey) is null)
this.IsToggled = defaultSetting;
}
}
public string Label
{
get
{
string? content = configCheckbox.Content as string;
if (content is null) return "";
return content;
}
set
{
configCheckbox.Content = value;
}
}
public string Prompt
{
get
{
if (promptMsg is null) return "";
return promptMsg;
}
set
{
promptMsg = value;
}
}
private async void onToggleChecked(object? sender, RoutedEventArgs e)
{
if (disableEvents) return;
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? toggled = checkBox.IsChecked;
if (toggled is null) toggled = false;
if (promptMsg is not null)
{
Window? currentWindow = this.VisualRoot as Window;
if (currentWindow is not Window) throw new Exception("could not find current window");
MessageBoxResult res = await MessageBox.Show(currentWindow, Prompt, "Are you sure?", MessageBoxButtons.YesNo);
if (res == MessageBoxResult.Yes)
IsToggled = true;
else
IsToggled = false;
}
else{
IsToggled = true;
}
}
private void onToggleUnchecked(object? sender, RoutedEventArgs e)
{
if (disableEvents) return;
CheckBox? checkBox = sender as CheckBox;
if (checkBox is null) return;
bool? toggle = checkBox.IsChecked;
if (toggle is null) toggle = false;
IsToggled = (bool)toggle;
}
public bool IsToggled
{
get
{
if (this.configCheckbox.IsChecked is null) return false;
return (bool)this.configCheckbox.IsChecked;
}
set
{
this.disableEvents = true;
this.configCheckbox.IsChecked = value;
this.disableEvents = false;
ChovyConfig.CurrentConfig.SetBool(ConfigKey, value);
}
}
public ConfigToggle()
{
InitializeComponent();
init();
configCheckbox.Unchecked += onToggleUnchecked;
configCheckbox.Checked += onToggleChecked;
}
}
}

View File

@ -0,0 +1,59 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Settings="clr-namespace:ChovySign_GUI.Settings"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ChovySign_GUI.Settings.SettingsTab">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="10*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Settings:ConfigToggle Name="devkitAccount"
ConfigKey="USE_DEVKIT_ACCOUNT_ID"
Label="Devkit Mode (Use 0x0000000000000000 Account ID)"
Prompt="This option will force the CMA Account ID to be all 0's&#x0a;Which is how it is on Devkit, Testkit and IDU Firmware&#x0a;Enabling this if you have a retail firmware will result in the games just *not* showing up&#x0a;&#x0a;If you DON'T know what this means, DON'T enable this.&#x0a;do you want to continue?"
HorizontalAlignment="Stretch"
Default="false"
Grid.Row="0"/>
<Settings:ConfigToggle Name="packagePsvimg"
ConfigKey="USE_CMA_PSVIMG"
Label="Use Content Manager (Package to PSVIMG)"
Default="true"
HorizontalAlignment="Stretch"
Grid.Row="1"/>
<Settings:ConfigPath Name="cmaDirectory"
ConfigKey="USE_CMA_DIRECTORY"
IsDirectory="true"
Label="Output Folder:"
HorizontalAlignment="Stretch"
Grid.Row="2"/>
<Settings:ConfigDropDown Name="libCryptMode"
ConfigKey="USE_LIBCRYPT_METHOD"
Label="LibCrypt Method:"
HorizontalAlignment="Stretch"
Grid.Row="3"/>
<Settings:ConfigDropDown Name="streamType"
ConfigKey="USE_STREAM_TYPE"
Label="Build Stream Type:"
HorizontalAlignment="Stretch"
Grid.Row="4"/>
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,72 @@
using Avalonia.Controls;
using GameBuilder.Pops.LibCrypt;
using GameBuilder;
using System.IO;
using Vita.ContentManager;
namespace ChovySign_GUI.Settings
{
public partial class SettingsTab : UserControl
{
public static SettingsTab? Settings;
public StreamType BuildStreamType
{
get
{
return (StreamType) this.streamType.SelectedIndex;
}
}
public LibCryptMethod LibcryptMode
{
get
{
if (this.libCryptMode.SelectedIndex == 0) return LibCryptMethod.METHOD_MAGIC_WORD;
else return LibCryptMethod.METHOD_SUB_CHANNEL;
}
}
public string CmaDirectory
{
get
{
return cmaDirectory.Value;
}
set
{
cmaDirectory.Value = value;
}
}
public bool DevkitMode
{
get
{
return devkitAccount.IsToggled;
}
}
public bool PackagePsvimg
{
get
{
return packagePsvimg.IsToggled;
}
}
public SettingsTab()
{
InitializeComponent();
libCryptMode.Items = new string[2] { "Magic Word in ISO Header", "Sub Channel PGD" };
streamType.Items = new string[2] { "MemoryStream - Create EBOOT in memory, faster, but high memory usage", "FileStream - Create EBOOT with temporary files, slower, but less memory usage" };
if (!Directory.Exists(this.CmaDirectory))
cmaDirectory.Value = SettingsReader.BackupsFolder;
Settings = this;
}
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
@ -12,6 +13,9 @@ namespace GameBuilder.Atrac3
{
public class Atrac3ToolEncoder : IAtracEncoderBase
{
[DllImport("libc")]
private static extern int setenv(string name, string value, bool overwrite);
private static Random rng = new Random();
private static string TOOLS_DIRECTORY = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tools");
@ -19,6 +23,7 @@ namespace GameBuilder.Atrac3
private static string AT3TOOL_LINUX = Path.Combine(TOOLS_DIRECTORY, "at3tool.elf");
private static string TEMP_DIRECTORY = Path.Combine(Path.GetTempPath(), "at3tool_tmp");
private static string LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
// random name so that can generate multiple at once if wanted ..
private string TEMP_WAV;
@ -45,10 +50,24 @@ namespace GameBuilder.Atrac3
}
}
private string setupLibaryPath()
{
string? libaryPath = Environment.GetEnvironmentVariable(LD_LIBRARY_PATH);
if (libaryPath is null) libaryPath = TOOLS_DIRECTORY;
else libaryPath += ";" + TOOLS_DIRECTORY;
Environment.SetEnvironmentVariable(libaryPath, libaryPath);
setenv(LD_LIBRARY_PATH, libaryPath, true);
return libaryPath;
}
private void runAtrac3Tool()
{
using(Process proc = new Process())
{
if (OperatingSystem.IsLinux())
proc.StartInfo.Environment.Add(LD_LIBRARY_PATH, setupLibaryPath());
proc.StartInfo.FileName = AT3TOOL_LOCATION;
proc.StartInfo.Arguments = "-br 132 -e \"" + TEMP_WAV + "\" \"" + TEMP_AT3 + "\"";

133
GameBuilder/BuildStream.cs Normal file
View File

@ -0,0 +1,133 @@
using DiscUtils.Streams;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder
{
public class BuildStream : Stream
{
public static StreamType BuildUsingStreamType = StreamType.TYPE_MEMORY_STREAM;
private Stream underylingStream;
private StreamType uStreamType;
private string? filename = null;
private void init()
{
this.uStreamType = BuildUsingStreamType;
if (this.uStreamType == StreamType.TYPE_MEMORY_STREAM)
{
this.underylingStream = new MemoryStream();
}
else if (this.uStreamType == StreamType.TYPE_FILE_STREAM)
{
string tmpFolder = Path.Combine(Path.GetTempPath(), "chovysign2");
Directory.CreateDirectory(tmpFolder);
this.filename = Path.Combine(tmpFolder, Guid.NewGuid().ToString());
this.underylingStream = File.Create(this.filename);
}
else
{
throw new Exception("unknown stream type");
}
}
public BuildStream(byte[] data)
{
init();
this.Write(data, 0, data.Length);
this.Seek(0x00, SeekOrigin.Begin);
}
public BuildStream()
{
init();
}
public override bool CanRead {
get {
return underylingStream.CanRead;
}
}
public override bool CanSeek {
get {
return underylingStream.CanSeek;
}
}
public override bool CanWrite {
get {
return underylingStream.CanWrite;
}
}
public override long Length {
get {
return underylingStream.Length;
}
}
public override long Position {
get {
return underylingStream.Position;
}
set {
underylingStream.Position = value;
}
}
public override void Close()
{
this.underylingStream.Close();
if(this.uStreamType == StreamType.TYPE_FILE_STREAM && this.filename is not null)
File.Delete(this.filename);
base.Close();
}
public override void Flush()
{
underylingStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return underylingStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return underylingStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
underylingStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
underylingStream.Write(buffer, offset, count);
}
public byte[] ToArray()
{
long oldLocation = this.Position;
this.Seek(0x00, SeekOrigin.Begin);
byte[] rdData = new byte[this.Length];
this.Read(rdData, 0x00, rdData.Length);
this.Seek(oldLocation, SeekOrigin.Begin);
return rdData;
}
}
}

View File

@ -30,24 +30,28 @@ namespace GameBuilder.Cue
return totalTracks;
}
public static byte BinaryDecimalConv(int i)
public static byte BinaryDecimalToDecimal(int i)
{
return Convert.ToByte(Convert.ToInt32(10 * (i - i % 16) / 16 + i % 16));
}
public static byte DecimalToBinaryDecimal(int i)
{
return Convert.ToByte(Convert.ToInt32((i % 10) + 16 * ((i / 10) % 10)));
}
public int IdxToSectorRel(CueIndex index)
public static int IdxToSectorRel(DiscIndex index)
{
int offset = (((index.Mrel * 60) + index.Srel) * 75 + index.Frel);
return offset;
}
public int IdxToSector(CueIndex index)
public static int IdxToSector(DiscIndex index)
{
int offset = (((index.m * 60) + index.s) * 75 + index.f);
return offset;
}
public CueIndex SectorToIdx(int sector)
public static DiscIndex SectorToIdx(int sector, byte index=1)
{
CueIndex idx = new CueIndex(1);
DiscIndex idx = new DiscIndex(index);
int x = sector;
int f = sector % 75;
@ -56,11 +60,6 @@ namespace GameBuilder.Cue
int s = x % 60;
int m = Convert.ToInt32(Math.Floor(Convert.ToDouble(x) / 60.0));
//idx.Mrel = Convert.ToByte(Convert.ToInt32(((sector / 75) / 60)));
//idx.Srel = Convert.ToByte(Convert.ToInt32(((sector / 75) % 60)));
//idx.Frel = Convert.ToByte(Convert.ToInt32(((sector % 75))));
//idx.Sdelta = 2; // why?
idx.Mrel = Convert.ToInt16(m);
idx.Srel = Convert.ToInt16(s);
idx.Frel = Convert.ToInt16(f);
@ -185,11 +184,11 @@ namespace GameBuilder.Cue
byte[] tocA0Entry = new byte[10] { 0x41, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00 };
// And an A1 track (determines how many tracks there are)
byte[] tocA1Entry = new byte[10] { 0x41, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, BinaryDecimalConv(GetTotalTracks()), 0x00, 0x00 };
byte[] tocA1Entry = new byte[10] { 0x41, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, DecimalToBinaryDecimal(GetTotalTracks()), 0x00, 0x00 };
// the A2 track is a bit more complicated ..
int totalSectors = getTotalSectorSz();
CueIndex idx = SectorToIdx(totalSectors);
DiscIndex idx = SectorToIdx(totalSectors);
idx.Sdelta = 2;
byte[] tocA2Entry = new byte[10] { 0x41, 0x00, 0xA2, 0x00, 0x00, 0x00, 0x00, idx.M, idx.S, idx.F };
@ -246,7 +245,7 @@ namespace GameBuilder.Cue
if (tracks[i] is null) continue;
int pos = positions[tracks[i].binFileName];
CueIndex idx = this.SectorToIdx(pos);
DiscIndex idx = SectorToIdx(pos);
// pregap not included on first track
if (tracks[i].TrackNo == 1) tracks[i].TrackIndex[0].Sdelta = 0;
@ -270,7 +269,7 @@ namespace GameBuilder.Cue
public byte[] CreateToc()
{
using (MemoryStream toc = new MemoryStream())
using (BuildStream toc = new BuildStream())
{
StreamUtil tocUtil = new StreamUtil(toc);
tocUtil.WriteBytes(createDummyTracks());
@ -301,6 +300,19 @@ namespace GameBuilder.Cue
openTracks.Clear();
}
private string getFilename(string str)
{
if (!str.Contains(' ')) throw new Exception("cue specifies no bin file.");
if (!str.Contains('"')) return str.Split(' ')[1];
int start = str.IndexOf('"');
str = str.Substring(start + 1);
int end = str.IndexOf('"');
str = str.Substring(0, end);
return str;
}
public CueReader(string cueFile)
{
openTracks = new Dictionary<int, CueStream>();
@ -311,10 +323,11 @@ namespace GameBuilder.Cue
CueTrack? curTrack = null;
for (string? cueData = cueReader.ReadLine();
cueData != null;
cueData is not null;
cueData = cueReader.ReadLine())
{
string[] cueLn = cueData.Trim().Replace("\r", "").Replace("\n", "").Split(' ');
cueData = cueData.Trim().Replace("\r", "").Replace("\n", "");
string[] cueLn = cueData.Split(' ');
if (cueLn[0] == "INDEX")
{
@ -351,17 +364,17 @@ namespace GameBuilder.Cue
if (curTrack != null) setTrackNumber(curTrack.TrackNo, ref curTrack);
// parse out filename..
string[] cueFnameParts = new string[cueLn.Length - 2];
Array.ConstrainedCopy(cueLn, 1, cueFnameParts, 0, cueFnameParts.Length);
string cueFname = String.Join(' ', cueFnameParts);
// open file ..
string binFileName = cueFname.Substring(1, cueFname.Length - 2);
string binFileName = getFilename(cueData);
string? folderContainingCue = Path.GetDirectoryName(cueFile);
if (folderContainingCue != null)
binFileName = Path.Combine(folderContainingCue, binFileName);
if(!File.Exists(binFileName))
binFileName = Path.ChangeExtension(cueFile, ".bin");
if (!File.Exists(binFileName)) throw new FileNotFoundException("unable to find bin file.");
curTrack = new CueTrack(binFileName);
}
}

View File

@ -6,16 +6,12 @@ using System.Threading.Tasks;
namespace GameBuilder.Cue
{
public class CueTrack
public class CueTrack : DiscTrack
{
public const int MODE2_SECTOR_SZ = 2352;
public const int CDDA_SECTOR_SZ = 2352;
public TrackType TrackType;
public byte TrackNo;
public CueIndex[] TrackIndex;
public int TrackLength;
public int SectorSz
{
@ -30,36 +26,14 @@ namespace GameBuilder.Cue
internal CueTrack(string binFile)
{
TrackIndex = new CueIndex[2];
for (int i = 0; i < TrackIndex.Length; i++)
TrackIndex[i] = new CueIndex(Convert.ToByte(i));
binFileName = binFile;
binFileSz = new FileInfo(binFileName).Length;
TrackType = TrackType.TRACK_MODE2_2352;
TrackNo = 0xFF;
this.TrackType = TrackType.TRACK_MODE2_2352;
this.TrackNo = 0xFF;
}
public byte[] ToTocEntry()
{
byte[] tocEntry = new byte[10];
tocEntry[0] = Convert.ToByte(this.TrackType);
tocEntry[1] = 0;
tocEntry[2] = CueReader.BinaryDecimalConv(this.TrackNo);
tocEntry[3] = this.TrackIndex[0].M;
tocEntry[4] = this.TrackIndex[0].S;
tocEntry[5] = this.TrackIndex[0].F;
tocEntry[6] = 0;
tocEntry[7] = this.TrackIndex[1].M;
tocEntry[8] = this.TrackIndex[1].S;
tocEntry[9] = this.TrackIndex[1].F;
return tocEntry;
}
}
}

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace GameBuilder.Cue
{
public class CueIndex
public class DiscIndex
{
public byte IndexNumber;
public short Mrel;
@ -73,7 +73,7 @@ namespace GameBuilder.Cue
{
get
{
return CueReader.BinaryDecimalConv(m);
return CueReader.DecimalToBinaryDecimal(m);
}
}
@ -81,7 +81,7 @@ namespace GameBuilder.Cue
{
get
{
return CueReader.BinaryDecimalConv(s);
return CueReader.DecimalToBinaryDecimal(s);
}
}
@ -89,11 +89,11 @@ namespace GameBuilder.Cue
{
get
{
return CueReader.BinaryDecimalConv(f);
return CueReader.DecimalToBinaryDecimal(f);
}
}
internal CueIndex(byte indexNumber)
internal DiscIndex(byte indexNumber)
{
IndexNumber = indexNumber;
Mrel = 0;

View File

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Cue
{
public class DiscTrack
{
private byte unk1;
private byte unk6;
public TrackType TrackType;
public byte TrackNo;
public DiscIndex[] TrackIndex;
public DiscTrack()
{
TrackIndex = new DiscIndex[2];
for (int i = 0; i < TrackIndex.Length; i++)
TrackIndex[i] = new DiscIndex(Convert.ToByte(i));
unk1 = 0;
unk6 = 0;
}
public static DiscTrack FromTocEntry(byte[] tocEntry)
{
if (tocEntry.Length != 0xA) throw new Exception("Invalid TOC Entry.");
DiscTrack track = new DiscTrack();
track.TrackType = (TrackType)tocEntry[0];
track.unk1 = tocEntry[1];
track.TrackNo = CueReader.BinaryDecimalToDecimal(tocEntry[2]);
track.TrackIndex[0].Mrel = Convert.ToInt16(CueReader.BinaryDecimalToDecimal(tocEntry[3]) - track.TrackIndex[0].Mdelta);
track.TrackIndex[0].Srel = Convert.ToInt16(CueReader.BinaryDecimalToDecimal(tocEntry[4]) - track.TrackIndex[0].Sdelta);
track.TrackIndex[0].Frel = Convert.ToInt16(CueReader.BinaryDecimalToDecimal(tocEntry[5]) - track.TrackIndex[0].Fdelta);
track.unk6 = tocEntry[6];
track.TrackIndex[1].Mrel = Convert.ToInt16(CueReader.BinaryDecimalToDecimal(tocEntry[7]) - track.TrackIndex[1].Mdelta);
track.TrackIndex[1].Srel = Convert.ToInt16(CueReader.BinaryDecimalToDecimal(tocEntry[8]) - track.TrackIndex[1].Sdelta);
track.TrackIndex[1].Frel = Convert.ToInt16(CueReader.BinaryDecimalToDecimal(tocEntry[9]) - track.TrackIndex[1].Fdelta);
return track;
}
public byte[] ToTocEntry()
{
byte[] tocEntry = new byte[0xA];
tocEntry[0] = Convert.ToByte(this.TrackType);
tocEntry[1] = unk1;
tocEntry[2] = CueReader.DecimalToBinaryDecimal(this.TrackNo);
tocEntry[3] = this.TrackIndex[0].M;
tocEntry[4] = this.TrackIndex[0].S;
tocEntry[5] = this.TrackIndex[0].F;
tocEntry[6] = unk6;
tocEntry[7] = this.TrackIndex[1].M;
tocEntry[8] = this.TrackIndex[1].S;
tocEntry[9] = this.TrackIndex[1].F;
return tocEntry;
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Cue
{
public class SbiEntry
{
public DiscIndex MSF;
public DiscTrack TOC;
public int Sector
{
get
{
return CueReader.IdxToSector(MSF);
}
}
public SbiEntry(DiscIndex Msf, DiscTrack Toc)
{
MSF = Msf;
TOC = Toc;
}
}
}

View File

@ -0,0 +1,65 @@
using Li.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Cue
{
public class SbiReader
{
private StreamUtil sbiUtil;
private List<SbiEntry> sbiEntries;
public SbiEntry[] Entries
{
get
{
return sbiEntries.ToArray();
}
}
private DiscIndex readMsfi()
{
byte m = CueReader.BinaryDecimalToDecimal(sbiUtil.ReadByte());
byte s = CueReader.BinaryDecimalToDecimal(sbiUtil.ReadByte());
byte f = CueReader.BinaryDecimalToDecimal(sbiUtil.ReadByte());
byte i = CueReader.BinaryDecimalToDecimal(sbiUtil.ReadByte());
DiscIndex idx = new DiscIndex(i);
idx.Mrel = m;
idx.Srel = s;
idx.Frel = f;
return idx;
}
private void init(Stream sbiFile)
{
sbiEntries = new List<SbiEntry>();
sbiUtil = new StreamUtil(sbiFile);
string magic = sbiUtil.ReadStrLen(3);
if (magic != "SBI")
throw new Exception("Invalid SBI Sub Channel file.");
sbiUtil.ReadByte();
do
{
DiscIndex idx = readMsfi();
DiscTrack toc = DiscTrack.FromTocEntry(sbiUtil.ReadBytes(0xA));
sbiEntries.Add(new SbiEntry(idx, toc));
} while (sbiFile.Position < sbiFile.Length);
}
public SbiReader(string sbiFileName)
{
using (FileStream fsbi = File.OpenRead(sbiFileName))
{
init(fsbi);
}
}
public SbiReader(Stream sbiFile)
{
init(sbiFile);
}
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

View File

@ -10,6 +10,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Li.Utilities;
using GameBuilder.Pops.LibCrypt;
namespace GameBuilder.Pops
{
@ -19,14 +20,14 @@ namespace GameBuilder.Pops
const int DEFAULT_ISO_OFFSET = 0x100000;
public int IsoOffset;
internal DiscCompressor(PopsImg srcImg, DiscInfo disc, IAtracEncoderBase encoder, int offset = DEFAULT_ISO_OFFSET)
internal DiscCompressor(PopsImg srcImg, PSInfo disc, IAtracEncoderBase encoder, int offset = DEFAULT_ISO_OFFSET)
{
this.srcImg = srcImg;
this.disc = disc;
this.cue = new CueReader(disc.CueFile);
this.IsoHeader = new MemoryStream();
this.CompressedIso = new MemoryStream();
this.IsoHeader = new BuildStream();
this.CompressedIso = new BuildStream();
this.isoHeaderUtil = new StreamUtil(IsoHeader);
this.atrac3Encoder = encoder;
@ -67,23 +68,6 @@ namespace GameBuilder.Pops
{
isoHeaderUtil.WriteStrWithPadding(disc.DiscIdHdr, 0x00, 0x400);
}
public byte[] GenerateIsoPgd()
{
IsoHeader.Seek(0x0, SeekOrigin.Begin);
byte[] isoHdr = IsoHeader.ToArray();
int headerSize = DNASHelper.CalculateSize(isoHdr.Length, 0x400);
byte[] headerEnc = new byte[headerSize];
int sz = DNASHelper.Encrypt(headerEnc, isoHdr, srcImg.DrmInfo.VersionKey, isoHdr.Length, srcImg.DrmInfo.KeyIndex, 1, blockSize: 0x400);
byte[] isoHdrPgd = headerEnc.ToArray();
Array.Resize(ref isoHdrPgd, sz);
return isoHdrPgd;
}
private void writeIsoLocation()
{
isoHeaderUtil.WriteInt32(0);
@ -92,7 +76,7 @@ namespace GameBuilder.Pops
isoHeaderUtil.WriteInt32(IsoOffset); // always 0x100000 on single disc game
isoHeaderUtil.WritePadding(0x00, 0x620);
isoHeaderUtil.WritePadding(0x00, 0x628);
}
private void writeCompressedIso()
@ -109,42 +93,68 @@ namespace GameBuilder.Pops
}
}
}
private void writeSubChannelPgd()
{
if(disc.LibCrypt.Method == LibCryptMethod.METHOD_SUB_CHANNEL)
{
byte[] subChannelsData = disc.LibCrypt.Subchannels;
int sz = subChannelsData.Length / 0xC;
uint location = Convert.ToUInt32(IsoOffset + CompressedIso.Position);
writeSubchannelDatLocation(location, sz);
byte[] pgdData = srcImg.CreatePgd(subChannelsData);
CompressedIso.Write(pgdData, 0, pgdData.Length);
}
}
public void GenerateIsoHeaderAndCompress()
{
writeHeader();
writeTOC();
writeIsoLocation();
writeName();
writeDiscInfo();
writeLibCryptData();
writeCompressedIso();
isoHeaderUtil.PadUntil(0x0, 0xb3880);
// now write CD-Audio data.
// write CD Audio data.
writeCompressedCDATracks();
// write subchannels
writeSubChannelPgd();
}
public void WriteSimpleDatLocation(Int64 location)
private void writeSubchannelDatLocation(uint location, int totalSubchannels)
{
IsoHeader.Seek(0xE20, SeekOrigin.Begin);
isoHeaderUtil.WriteInt64(location);
isoHeaderUtil.WriteUInt32At(location, 0xED4);
isoHeaderUtil.WriteInt32At(totalSubchannels, 0xED8);
}
private void writeName()
public void WriteSimpleDatLocation(uint location)
{
// copied from crash bandicoot warped
isoHeaderUtil.WriteUInt32At(location, 0xE20);
}
isoHeaderUtil.WriteInt64(0x00); // SIMPLE.DAT location
isoHeaderUtil.WriteInt32(2047); // unk
isoHeaderUtil.WriteStrWithPadding(disc.DiscName, 0x00, 0x80);
isoHeaderUtil.WriteInt32(3); // unk
isoHeaderUtil.WriteInt32(0x72d0ee59); // appears to be constant?
private void writeLibCryptData()
{
isoHeaderUtil.WriteInt32(disc.LibCrypt.ObfuscatedMagicWord);
isoHeaderUtil.WriteInt32(0);
isoHeaderUtil.WriteInt32(0);
isoHeaderUtil.WriteInt32(0);
isoHeaderUtil.WritePadding(0, 0x2D40);
}
private void writeDiscInfo()
{
isoHeaderUtil.WriteUInt32(Convert.ToUInt32(disc.LibCrypt.Method)); // libcrypt method
isoHeaderUtil.WriteStrWithPadding(disc.DiscName, 0x00, 0x80); // disc title
isoHeaderUtil.WriteInt32(3); // PARENTAL_LEVEL ?
}
private void writeCDAEntry(int position, int length, uint key)
@ -179,9 +189,9 @@ namespace GameBuilder.Pops
writeCDAEntry(Convert.ToInt32(CompressedIso.Position), atracData.Length, key);
using (MemoryStream atracStream = new MemoryStream(atracData))
using (BuildStream atracStream = new BuildStream(atracData))
{
using (MemoryStream encryptedAtracStream = new MemoryStream())
using (BuildStream encryptedAtracStream = new BuildStream())
{
AtracCrypto.ScrambleAtracData(atracStream, encryptedAtracStream, key);
encryptedAtracStream.Seek(0x00, SeekOrigin.Begin);
@ -227,12 +237,12 @@ namespace GameBuilder.Pops
cue.Dispose();
}
private DiscInfo disc;
private PSInfo disc;
private CueReader cue;
private PopsImg srcImg;
public MemoryStream IsoHeader;
public MemoryStream CompressedIso;
public BuildStream IsoHeader;
public BuildStream CompressedIso;
private StreamUtil isoHeaderUtil;
private IAtracEncoderBase atrac3Encoder;

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Pops.LibCrypt
{
public class Constants
{
public const int MAGIC_WORD_KEY = 0x72D0EE59;
public static int[][] LIBCRYPT_PAIRS = new int[16][] { new int[2] { 14105, 14110 },
new int[2] { 14231, 14236 },
new int[2] { 14485, 14490 },
new int[2] { 14579, 14584 },
new int[2] { 14649, 14654 },
new int[2] { 14899, 14904 },
new int[2] { 15056, 15061 },
new int[2] { 15130, 15135 },
new int[2] { 15242, 15247 },
new int[2] { 15312, 15317 },
new int[2] { 15378, 15383 },
new int[2] { 15628, 15633 },
new int[2] { 15919, 15924 },
new int[2] { 16031, 16036 },
new int[2] { 16101, 16106 },
new int[2] { 16167, 16172 }
};
}
}

View File

@ -0,0 +1,27 @@
using GameBuilder.Cue;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Pops.LibCrypt
{
public class DbLibCrypt : LibCryptInfo
{
private string discId;
public override int MagicWord
{
get
{
return LibCrypt.MagicWord.LookupMagicWord(discId);
}
}
public DbLibCrypt(string discId, LibCryptMethod method)
{
this.discId = discId;
this.Method = method;
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Pops.LibCrypt
{
public abstract class LibCryptInfo
{
private LibCryptMethod method;
public virtual LibCryptMethod Method
{
get
{
return method;
}
set
{
if (MagicWord == 0) return;
method = value;
}
}
public abstract int MagicWord { get; }
public virtual int ObfuscatedMagicWord
{
get
{
if (Method == LibCryptMethod.METHOD_SUB_CHANNEL) return 0;
return LibCrypt.MagicWord.ObfuscateMagicWord(this.MagicWord);
}
}
public virtual byte[] Subchannels
{
get
{
return LibCrypt.SubChannel.CreateSubchannelDat(this.MagicWord);
}
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Pops.LibCrypt
{
public enum LibCryptMethod : uint
{
METHOD_MAGIC_WORD = 0x7ff,
METHOD_SUB_CHANNEL = 0x8000,
}
}

View File

@ -0,0 +1,61 @@
using GameBuilder.Cue;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Pops.LibCrypt
{
public class MagicWord
{
public static int ObfuscateMagicWord(int magicWord)
{
return magicWord ^ Constants.MAGIC_WORD_KEY;
}
public static int LookupMagicWord(string discId)
{
using (TextReader magicWords = new StringReader(Resources.MAGICWORDS))
{
for(string? line = magicWords.ReadLine();
line is not null;
line = magicWords.ReadLine())
{
string[] split = line.Split(' ');
if (split[0].Equals(discId, StringComparison.InvariantCultureIgnoreCase))
{
return Int32.Parse(split[1], NumberStyles.HexNumber);
}
}
return 0;
}
}
public static int GenerateMagicWord(SbiEntry[] sbiEntries)
{
bool[] bits = new bool[16];
HashSet<int> sbiSectors = new HashSet<int>();
foreach(SbiEntry sbiEntry in sbiEntries)
sbiSectors.Add(sbiEntry.Sector);
for (int i = 0; i < bits.Length; i++)
bits[i] = (sbiSectors.Contains(Constants.LIBCRYPT_PAIRS[i][0]) && sbiSectors.Contains(Constants.LIBCRYPT_PAIRS[i][1]));
int magicWord = 0;
for (int i = 0; i < bits.Length; i++)
{
if (bits[i]) magicWord |= 1;
if(i+1 < bits.Length)
magicWord <<= 1;
}
return magicWord;
}
}
}

View File

@ -0,0 +1,27 @@
using GameBuilder.Cue;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Pops.LibCrypt
{
public class SbiLibCrypt : LibCryptInfo
{
private SbiReader sbiReader;
public override int MagicWord
{
get
{
return LibCrypt.MagicWord.GenerateMagicWord(sbiReader.Entries);
}
}
public SbiLibCrypt(SbiReader sbi, LibCryptMethod method)
{
this.sbiReader = sbi;
this.Method = method;
}
}
}

View File

@ -0,0 +1,69 @@
using GameBuilder.Cue;
using Li.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder.Pops.LibCrypt
{
public class SubChannel
{
public static byte[] CreateSubchannelDat(int magicWord)
{
using(BuildStream subChannels = new BuildStream())
{
StreamUtil subChannelsUtil = new StreamUtil(subChannels);
// this header seems to mark the start of the sub channel data.
subChannelsUtil.WriteUInt32(0xFFFFFFFF);
subChannelsUtil.WriteUInt32(0x00000000);
subChannelsUtil.WriteUInt32(0xFFFFFFFF);
for (int i = 0; i < Constants.LIBCRYPT_PAIRS.Length; i++)
{
if ((magicWord & (1 << ((Constants.LIBCRYPT_PAIRS.Length - 1) - i))) != 0)
{
int[] pair = Constants.LIBCRYPT_PAIRS[i];
foreach (int lcSector in pair)
{
DiscIndex sidx = CueReader.SectorToIdx(lcSector, 0);
sidx.Sdelta = -2;
int adjustedSector = CueReader.IdxToSector(sidx);
// write sector number offset by 2s
subChannelsUtil.WriteInt32(adjustedSector);
subChannelsUtil.WriteByte(0x01);
subChannelsUtil.WriteByte(0x01);
sidx.Fdelta = -1;
sidx.Sdelta = -2;
// write sector index 1 but corrupted
subChannelsUtil.WriteByte(sidx.M);
subChannelsUtil.WriteByte(sidx.S);
subChannelsUtil.WriteByte(sidx.F);
sidx.Sdelta = 0;
// write sector index 0 but corrupted
subChannelsUtil.WriteByte(sidx.M);
subChannelsUtil.WriteByte(sidx.S);
subChannelsUtil.WriteByte(sidx.F);
}
}
}
// this header seems to mark the end of the sub channel data.
subChannelsUtil.WriteUInt32(0xFFFFFFFF);
subChannelsUtil.WriteUInt32(0xFFFFFFFF);
subChannelsUtil.WriteUInt32(0xFFFFFFFF);
return subChannels.ToArray();
}
}
}
}

View File

@ -1,6 +1,8 @@
using DiscUtils.Iso9660Ps1;
using DiscUtils.Raw;
using DiscUtils.Streams;
using GameBuilder.Cue;
using GameBuilder.Pops.LibCrypt;
using Li.Utilities;
using System;
using System.Collections.Generic;
@ -10,12 +12,29 @@ using System.Threading.Tasks;
namespace GameBuilder.Pops
{
public class DiscInfo
public class PSInfo
{
private string cueFile;
private string discName;
private string discId;
private LibCryptInfo lc;
public LibCryptInfo LibCrypt
{
get
{
return lc;
}
}
public string? SbiFile
{
get
{
string sbiFileName = Path.ChangeExtension(CueFile, ".sbi");
if(File.Exists(sbiFileName)) return sbiFileName;
else return null;
}
}
public string CueFile
{
get
@ -50,9 +69,13 @@ namespace GameBuilder.Pops
{
return discId.Replace("-", "").Replace("_", "").ToUpperInvariant().PadRight(9, '0').Substring(0, 9).ToUpperInvariant();
}
set
{
this.discId = value.Replace("-", "").Replace("_", "").ToUpperInvariant().PadRight(9, '0').Substring(0, 9).ToUpperInvariant();
}
}
public DiscInfo(string cueFile)
public PSInfo(string cueFile)
{
this.cueFile = cueFile;
@ -92,6 +115,11 @@ namespace GameBuilder.Pops
if (discName == "") discName = Path.GetFileNameWithoutExtension(cueFile);
if (discId is null) discId = "SLUS00001";
if (this.SbiFile is not null)
this.lc = new SbiLibCrypt(new SbiReader(this.SbiFile), LibCryptMethod.METHOD_MAGIC_WORD);
else
this.lc = new DbLibCrypt(discId, LibCryptMethod.METHOD_MAGIC_WORD);
}
}
}

View File

@ -1,4 +1,5 @@
using GameBuilder;
using GameBuilder.Cue;
using GameBuilder.Psp;
using Li.Utilities;
using PspCrypto;
@ -16,21 +17,18 @@ namespace GameBuilder.Pops
public PopsImg(NpDrmInfo versionKey) : base(versionKey)
{
simple = new MemoryStream();
simple = new BuildStream();
simpleUtil = new StreamUtil(simple);
this.StartDat = NpDrmPsar.CreateStartDat(Resources.STARTDATPOPS);
this.createSimpleDat();
this.SimplePgd = generateSimplePgd();
this.SimplePgd = CreatePgd(simple.ToArray());
this.EbootElf = Resources.DATAPSPSD;
this.ConfigBin = Resources.DATAPSPSDCFG;
this.PatchEboot = true;
}
private MemoryStream simple;
private StreamUtil simpleUtil;
public byte[] StartDat;
public byte[] SimplePgd;
private void createSimpleDat()
internal void createSimpleDat()
{
simpleUtil.WriteStr("SIMPLE ");
simpleUtil.WriteInt32(100);
@ -41,17 +39,15 @@ namespace GameBuilder.Pops
simpleUtil.WriteBytes(Resources.SIMPLE);
}
private byte[] generateSimplePgd()
public byte[] CreatePgd(byte[] buffer)
{
simple.Seek(0x0, SeekOrigin.Begin);
byte[] simpleData = simple.ToArray();
int simpleSz = DNASHelper.CalculateSize(simpleData.Length, 0x400);
byte[] simpleEnc = new byte[simpleSz];
int bufferSz = DNASHelper.CalculateSize(buffer.Length, 0x400);
byte[] bufferEnc = new byte[bufferSz];
// get pgd
int sz = DNASHelper.Encrypt(simpleEnc, simpleData, DrmInfo.VersionKey, simpleData.Length, DrmInfo.KeyIndex, 1, blockSize: 0x400);
byte[] pgd = simpleEnc.ToArray();
int sz = DNASHelper.Encrypt(bufferEnc, buffer, DrmInfo.VersionKey, buffer.Length, DrmInfo.KeyIndex, 1, blockSize: 0x400);
byte[] pgd = bufferEnc.ToArray();
Array.Resize(ref pgd, sz);
return pgd;
@ -61,26 +57,44 @@ namespace GameBuilder.Pops
public override byte[] GenerateDataPsp()
{
Span<byte> loaderEnc = new byte[0x9B13];
//byte[] dataPspElf = Resources.DATAPSPSD;
byte[] dataPspElf = Resources.DATAPSPSD;
if (this.PatchEboot)
{
// calculate size low and high part ..
uint szLow = Convert.ToUInt32(Psar.Length) >> 16;
uint szHigh = Convert.ToUInt32(Psar.Length) & 0xFFFF;
// calculate size low and high part ..
uint szLow = Convert.ToUInt32(Psar.Length) >> 16;
uint szHigh = Convert.ToUInt32(Psar.Length) & 0xFFFF;
// convert to big endain bytes
byte[] lowBits = BitConverter.GetBytes(Convert.ToUInt16(szLow)).ToArray();
byte[] highBits = BitConverter.GetBytes(Convert.ToUInt16(szHigh)).ToArray();
// convert to big endain bytes
byte[] lowBits = BitConverter.GetBytes(Convert.ToUInt16(szLow)).ToArray();
byte[] highBits = BitConverter.GetBytes(Convert.ToUInt16(szHigh)).ToArray();
// overwrite data.psar size check ..
Array.ConstrainedCopy(lowBits, 0, this.EbootElf, 0x68C, 0x2);
Array.ConstrainedCopy(highBits, 0, this.EbootElf, 0x694, 0x2);
}
// overwrite data.psar size check ..
Array.ConstrainedCopy(lowBits, 0, dataPspElf, 0x68C, 0x2);
Array.ConstrainedCopy(highBits, 0, dataPspElf, 0x694, 0x2);
SceMesgLed.Encrypt(loaderEnc, dataPspElf, 0x0DAA06F0, SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC, DrmInfo.VersionKey, DrmInfo.ContentId, Resources.DATAPSPSDCFG);
SceMesgLed.Encrypt(
loaderEnc,
this.EbootElf,
0x0DAA06F0,
SceExecFileDecryptMode.DECRYPT_MODE_POPS_EXEC,
DrmInfo.VersionKey,
DrmInfo.ContentId,
this.ConfigBin);
return loaderEnc.ToArray();
}
private BuildStream simple;
private StreamUtil simpleUtil;
public byte[] EbootElf;
public byte[] ConfigBin;
public bool PatchEboot;
public byte[] StartDat;
public byte[] SimplePgd;
}
}

View File

@ -15,13 +15,13 @@ namespace GameBuilder.Pops
this.compressor = discCompressor;
}
public PsIsoImg(NpDrmInfo versionKey, DiscInfo disc, IAtracEncoderBase encoder) : base(versionKey)
public PsIsoImg(NpDrmInfo versionKey, PSInfo disc, IAtracEncoderBase encoder) : base(versionKey)
{
this.compressor = new DiscCompressor(this, disc, encoder);
this.compressor.RegisterCallback(onProgress);
}
public PsIsoImg(NpDrmInfo versionKey, DiscInfo disc) : base(versionKey)
public PsIsoImg(NpDrmInfo versionKey, PSInfo disc) : base(versionKey)
{
this.compressor = new DiscCompressor(this, disc, new Atrac3ToolEncoder());
this.compressor.RegisterCallback(onProgress);
@ -34,7 +34,7 @@ namespace GameBuilder.Pops
psarUtil.WritePadding(0x00, 0x3ec); // Skip forwards
byte[] isoHdrPgd = compressor.GenerateIsoPgd();
byte[] isoHdrPgd = this.CreatePgd(compressor.IsoHeader.ToArray());
psarUtil.WriteBytes(isoHdrPgd);
psarUtil.PadUntil(0x00, compressor.IsoOffset);
}
@ -45,7 +45,8 @@ namespace GameBuilder.Pops
compressor.GenerateIsoHeaderAndCompress();
// write STARTDAT location
compressor.WriteSimpleDatLocation((compressor.IsoOffset + compressor.CompressedIso.Length) + StartDat.Length);
UInt32 simpleDatLocation = Convert.ToUInt32((compressor.IsoOffset + compressor.CompressedIso.Length) + StartDat.Length);
compressor.WriteSimpleDatLocation(simpleDatLocation);
// write general PSISO header
generatePsIsoHeader();

View File

@ -24,7 +24,7 @@ namespace GameBuilder.Pops
this.updateProgress(inf.Done, inf.Remain, inf.CurrentProcess + " (disc " + discNumber + ")");
}
public PsTitleImg(NpDrmInfo drmInfo, DiscInfo[] discs) : base(drmInfo)
public PsTitleImg(NpDrmInfo drmInfo, PSInfo[] discs) : base(drmInfo)
{
if (discs.Length > MAX_DISCS) throw new Exception("Sorry, multi disc games only support up to 5 discs... (i dont make the rules)");
this.compressors = new DiscCompressor[MAX_DISCS];
@ -50,10 +50,10 @@ namespace GameBuilder.Pops
}
isoMap = new MemoryStream();
isoMap = new BuildStream();
isoMapUtil = new StreamUtil(isoMap);
isoPart = new MemoryStream();
isoPart = new BuildStream();
isoPartUtil = new StreamUtil(isoPart);
@ -171,13 +171,13 @@ namespace GameBuilder.Pops
base.Dispose();
}
private DiscInfo[] discs;
private PSInfo[] discs;
private DiscCompressor[] compressors;
private MemoryStream isoPart;
private BuildStream isoPart;
private StreamUtil isoPartUtil;
private MemoryStream isoMap;
private BuildStream isoMap;
private StreamUtil isoMapUtil;
}
}

View File

@ -17,19 +17,19 @@ namespace GameBuilder.Psp
{
DrmInfo = npDrmInfo;
Psar = new MemoryStream();
Psar = new BuildStream();
psarUtil = new StreamUtil(Psar);
}
public NpDrmInfo DrmInfo;
public MemoryStream Psar;
public BuildStream Psar;
internal StreamUtil psarUtil;
public abstract void CreatePsar();
public abstract byte[] GenerateDataPsp();
public static byte[] CreateStartDat(byte[] image)
{
using(MemoryStream startDatStream = new MemoryStream())
using(BuildStream startDatStream = new BuildStream())
{
StreamUtil startDatUtil = new StreamUtil(startDatStream);

View File

@ -21,16 +21,16 @@ namespace GameBuilder.Psp
{
this.compress = compress;
this.npHdr = new MemoryStream();
this.npHdr = new BuildStream();
this.npHdrUtil = new StreamUtil(npHdr);
this.npHdrBody = new MemoryStream();
this.npHdrBody = new BuildStream();
this.npHdrBodyUtil = new StreamUtil(npHdrBody);
this.npTbl = new MemoryStream();
this.npTbl = new BuildStream();
this.npTblUtil = new StreamUtil(npTbl);
this.isoData = new MemoryStream();
this.isoData = new BuildStream();
this.isoDataUtil = new StreamUtil(isoData);
this.headerKey = Rng.RandomBytes(0x10);
@ -43,8 +43,8 @@ namespace GameBuilder.Psp
public void PatchSfo()
{
Sfo sfoKeys = Sfo.ReadSfo(umdImage.DataFiles["PARAM.SFO"]);
if ((sfoKeys["CATEGORY"] as String) == "UG") // "UMD Game"
sfoKeys["CATEGORY"] = "EG"; // set it to "Eboot Game"
//if ((sfoKeys["CATEGORY"] as String) == "UG") // "UMD Game"
sfoKeys["CATEGORY"] = "EG"; // set it to "Eboot Game"
umdImage.DataFiles["PARAM.SFO"] = sfoKeys.WriteSfo();
}
private void createNpHdr()
@ -101,7 +101,7 @@ namespace GameBuilder.Psp
public override byte[] GenerateDataPsp()
{
byte[] startDat = CreateStartDat(umdImage.Minis ? Resources.STARTDATMINIS : Resources.STARTDATPSP);
using (MemoryStream dataPsp = new MemoryStream())
using (BuildStream dataPsp = new BuildStream())
{
StreamUtil dataPspUtil = new StreamUtil(dataPsp);
byte[] signature = signParamSfo(umdImage.DataFiles["PARAM.SFO"]);
@ -288,16 +288,16 @@ namespace GameBuilder.Psp
private byte[] dataKey;
private MemoryStream npHdr;
private BuildStream npHdr;
private StreamUtil npHdrUtil;
private MemoryStream npHdrBody;
private BuildStream npHdrBody;
private StreamUtil npHdrBodyUtil;
private MemoryStream isoData;
private BuildStream isoData;
private StreamUtil isoDataUtil;
private MemoryStream npTbl;
private BuildStream npTbl;
private StreamUtil npTblUtil;
}
}

View File

@ -18,7 +18,7 @@ namespace GameBuilder.Psp
private byte[]? snd0At3;
private NpDrmPsar psar;
private short pbpVersion;
private MemoryStream pbpStream;
private BuildStream pbpStream;
public PbpBuilder(byte[] paramSfo, byte[] icon0Png, byte[]? icon1Pmf,
byte[]? pic0Png, byte[]? pic1Png, byte[]? snd0At3,
@ -33,11 +33,11 @@ namespace GameBuilder.Psp
this.psar = dataPsar;
this.pbpVersion = version;
pbpStream = new MemoryStream();
pbpStream = new BuildStream();
psar.RegisterCallback(onProgress);
}
public MemoryStream PbpStream
public BuildStream PbpStream
{
get
{

View File

@ -12,12 +12,12 @@ namespace GameBuilder.Psp
{
private string[] filesList = new string[]
{
"PSP_GAME\\ICON0.PNG",
"PSP_GAME\\ICON1.PMF",
"PSP_GAME\\PARAM.SFO",
"PSP_GAME\\PIC0.PNG",
"PSP_GAME\\PIC1.PNG",
"PSP_GAME\\SND0.AT3"
Path.Combine("PSP_GAME","ICON0.PNG"),
Path.Combine("PSP_GAME","ICON1.PMF"),
Path.Combine("PSP_GAME","PARAM.SFO"),
Path.Combine("PSP_GAME","PIC0.PNG"),
Path.Combine("PSP_GAME","PIC1.PNG"),
Path.Combine("PSP_GAME","SND0.AT3")
};
public Dictionary<string, byte[]?> DataFiles = new Dictionary<string, byte[]?>();
@ -27,12 +27,12 @@ namespace GameBuilder.Psp
this.IsoStream = File.OpenRead(isoFile);
using (CDReader cdReader = new CDReader(this.IsoStream, true, true))
{
foreach (string file in filesList)
foreach (string file in this.filesList)
{
string fname = Path.GetFileName(file).ToUpperInvariant();
if (cdReader.FileExists(file))
if (cdReader.FileExists(file.Replace('/', '\\')))
{
using (SparseStream s = cdReader.OpenFile(file, FileMode.Open))
using (SparseStream s = cdReader.OpenFile(file.Replace('/', '\\'), FileMode.Open))
{
byte[] data = new byte[s.Length];
@ -48,11 +48,14 @@ namespace GameBuilder.Psp
}
}
if (DataFiles["PARAM.SFO"] is null) throw new Exception("ISO contains no PARAM.SFO file, so this is not a valid PSP game.");
byte[]? paramFile = DataFiles["PARAM.SFO"];
if (paramFile is null) throw new Exception("ISO contains no PARAM.SFO file, so this is not a valid PSP game.");
Sfo sfo = Sfo.ReadSfo(DataFiles["PARAM.SFO"]);
this.DiscId = sfo["DISC_ID"] as String;
Sfo sfo = Sfo.ReadSfo(paramFile);
string? discId = sfo["DISC_ID"] as String;
if (discId is null) throw new Exception("PARAM.SFO does not contain \"DISC_ID\"");
this.DiscId = discId;
// check minis
if (sfo["ATTRIBUTE"] is UInt32)

View File

@ -80,6 +80,47 @@ namespace GameBuilder {
}
}
/// <summary>
/// Looks up a localized string similar to SCES00311 87AA
///SCES01431 6547
///SCES01444 BD44
///SCES01492 D16A
///SCES01493 197A
///SCES01494 AAA6
///SCES01495 0E57
///SCES01516 44F6
///SCES01517 AE85
///SCES01518 9C27
///SCES01519 364B
///SCES01564 CEC1
///SCES01695 89EA
///SCES01700 4717
///SCES01701 C49E
///SCES01702 672A
///SCES01703 883F
///SCES01704 CE32
///SCES01763 096F
///SCES01882 B364
///SCES01909 E788
///SCES01979 0D9D
///SCES02004 C437
///SCES02005 9137
///SCES02006 7554
///SCES02007 E686
///SCES02028 9AD4
///SCES02029 26B6
///SCES02030 23D9
///SCES02031 D325
///SCES02080 9DE0
///SCES02104 744B
/// [rest of string was truncated]&quot;;.
/// </summary>
public static string MAGICWORDS {
get {
return ResourceManager.GetString("MAGICWORDS", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>

View File

@ -124,6 +124,9 @@
<data name="DATAPSPSDCFG" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\DATAPSPSDCFG.BIN;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="MAGICWORDS" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\MagicWords.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="SIMPLE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\SIMPLE.PNG;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>

View File

@ -0,0 +1,227 @@
SCES00311 87AA
SCES01431 6547
SCES01444 BD44
SCES01492 D16A
SCES01493 197A
SCES01494 AAA6
SCES01495 0E57
SCES01516 44F6
SCES01517 AE85
SCES01518 9C27
SCES01519 364B
SCES01564 CEC1
SCES01695 89EA
SCES01700 4717
SCES01701 C49E
SCES01702 672A
SCES01703 883F
SCES01704 CE32
SCES01763 096F
SCES01882 B364
SCES01909 E788
SCES01979 0D9D
SCES02004 C437
SCES02005 9137
SCES02006 7554
SCES02007 E686
SCES02028 9AD4
SCES02029 26B6
SCES02030 23D9
SCES02031 D325
SCES02080 9DE0
SCES02104 744B
SCES02105 A371
SCES02181 7D84
SCES02182 A8CD
SCES02184 1E5C
SCES02185 74E4
SCES02222 A4F8
SCES02264 0E3E
SCES02290 12D7
SCES02365 1CDC
SCES02366 D6C8
SCES02367 96A6
SCES02368 5C27
SCES02369 DC25
SCES02430 B159
SCES02431 7872
SCES02432 13AE
SCES02433 B50B
SCES02487 7AD0
SCES02488 898F
SCES02489 25EA
SCES02490 0F6C
SCES02491 F01B
SCES02544 3A17
SCES02545 A96C
SCES02546 378A
SCES02834 E728
SCES02835 369A
SCES02977 B88D
SCES03189 4BCC
SCES03190 710F
SCES03191 6A95
SCES12080 9DE0
SCES22080 9DE0
SCES32080 9DE0
SLES00017 E2B8
SLES00995 8BB1
SLES01041 6317
SLES01226 03E7
SLES01241 E313
SLES01301 B722
SLES01362 6CA6
SLES01545 A54E
SLES01715 A4F4
SLES01733 B06D
SLES01906 14ED
SLES01907 C0EE
SLES01943 7067
SLES02024 1B71
SLES02025 CA4E
SLES02026 116F
SLES02027 3A63
SLES02061 8AB5
SLES02071 2735
SLES02080 9DE0
SLES02081 6837
SLES02082 698B
SLES02083 94CD
SLES02084 44BD
SLES02086 16F4
SLES02112 AF44
SLES02113 5897
SLES02118 6DB0
SLES02207 3A6C
SLES02208 71A9
SLES02209 26D6
SLES02210 632D
SLES02211 1A57
SLES02292 86F2
SLES02293 BA85
SLES02328 3F22
SLES02329 9D38
SLES02330 E03D
SLES02354 64E9
SLES02355 4AE6
SLES02395 AAA9
SLES02396 A56A
SLES02402 AA3A
SLES02529 AD70
SLES02530 7C23
SLES02531 ACB8
SLES02532 1C3D
SLES02533 EA8A
SLES02538 6353
SLES02558 D5E0
SLES02559 5715
SLES02560 DB28
SLES02561 EA85
SLES02562 3D94
SLES02563 4B63
SLES02572 395C
SLES02573 5563
SLES02681 1CC7
SLES02688 7368
SLES02689 E1D2
SLES02698 1C9D
SLES02700 27D8
SLES02704 711E
SLES02705 4AAD
SLES02706 1EB1
SLES02707 AD31
SLES02708 5EC4
SLES02722 B68A
SLES02723 0FF0
SLES02724 CE94
SLES02733 B60D
SLES02754 1FC1
SLES02755 5917
SLES02756 E076
SLES02763 78A6
SLES02766 984F
SLES02767 AB45
SLES02768 9D68
SLES02769 30DE
SLES02824 B385
SLES02830 62BC
SLES02831 05DE
SLES02839 CB19
SLES02857 5F0A
SLES02858 3E1A
SLES02859 255E
SLES02860 A792
SLES02861 C8DC
SLES02862 C3D1
SLES02965 B6C8
SLES02966 CEA1
SLES02967 725A
SLES02968 E516
SLES02969 EC61
SLES02975 7A91
SLES02976 6547
SLES02978 5B13
SLES02979 2F4A
SLES03061 0C7E
SLES03062 B0CD
SLES03241 7B82
SLES03242 A768
SLES03243 2771
SLES03244 1597
SLES03245 05D7
SLES03324 CD31
SLES03489 90AF
SLES03519 BB14
SLES03520 9678
SLES03521 FB20
SLES03522 CB0E
SLES03523 30FC
SLES03530 93F0
SLES03603 5AC9
SLES03604 196E
SLES03605 F152
SLES03606 C5D4
SLES03607 8A3B
SLES03626 4F23
SLES03648 6939
SLES12080 9DE0
SLES12081 6837
SLES12082 698B
SLES12083 94CD
SLES12084 44BD
SLES12328 4AEC
SLES12329 9D38
SLES12330 DE03
SLES12558 D5E0
SLES12559 5715
SLES12560 DB28
SLES12561 EA85
SLES12562 3D94
SLES12965 A1D3
SLES12966 9731
SLES12967 D916
SLES12968 544F
SLES12969 645B
SLES22080 9DE0
SLES22081 6837
SLES22082 698B
SLES22083 94CD
SLES22084 44BD
SLES22328 70D3
SLES22329 9D38
SLES22330 236B
SLES22965 6DC2
SLES22966 C873
SLES22967 19B5
SLES22968 41CF
SLES22969 6636
SLES32080 9DE0
SLES32081 6837
SLES32082 698B
SLES32083 94CD
SLES32084 44BD
SLES32965 1EC5
SLES32966 35D1
SLES32967 54CD
SLES32968 C61D
SLES32969 E8C3

14
GameBuilder/StreamType.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameBuilder
{
public enum StreamType : uint
{
TYPE_MEMORY_STREAM,
TYPE_FILE_STREAM
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

View File

@ -117,6 +117,10 @@ namespace Li.Utilities
{
WriteBytesWithPadding(Encoding.UTF8.GetBytes(str), b, len);
}
public void WriteUInt64(UInt64 v)
{
WriteBytes(BitConverter.GetBytes(v));
}
public void WriteInt64(Int64 v)
{
WriteBytes(BitConverter.GetBytes(v));
@ -138,6 +142,21 @@ namespace Li.Utilities
{
WriteBytes(BitConverter.GetBytes(v).Reverse().ToArray());
}
public void WriteInt32At(Int32 v, long location)
{
long oldPos = s.Position;
s.Seek(location, SeekOrigin.Begin);
WriteInt32(v);
s.Seek(oldPos, SeekOrigin.Begin);
}
public void WriteUInt32At(UInt32 v, long location)
{
long oldPos = s.Position;
s.Seek(location, SeekOrigin.Begin);
WriteUInt32(v);
s.Seek(oldPos, SeekOrigin.Begin);
}
public void WriteInt32(Int32 v)
{
WriteBytes(BitConverter.GetBytes(v));

View File

@ -1,4 +1,5 @@
using GameBuilder.Pops;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System;
using System.Collections.Generic;
@ -13,7 +14,7 @@ namespace LibChovy.Art
private const string coverApi = "https://raw.githubusercontent.com/xlenore/psx-covers/main/covers/";
private static HttpClient httpClient = new HttpClient();
public static async Task<byte[]> DownloadCover(DiscInfo game)
public static async Task<byte[]> DownloadCover(PSInfo game)
{
string discIdDash = game.DiscId.Substring(0, 4) + "-" + game.DiscId.Substring(4, 5);
@ -30,7 +31,7 @@ namespace LibChovy.Art
using (Image psnBorder = Image.Load(Resources.ICON0))
{
coverImage.Mutate(x => x.Crop(new Rectangle(80, 0, coverImage.Width - 80, coverImage.Height)));
//coverImage.Mutate(x => x.Crop(new Rectangle(80, 0, coverImage.Width - 80, coverImage.Height)));
coverImage.Mutate(x => x.Resize(58, 58));
psnBorder.Mutate(x => x.DrawImage(coverImage, new Point(13, 11), 1.0f));

View File

@ -1,4 +1,6 @@
using System;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

View File

@ -1,4 +1,5 @@
using GameBuilder.Pops;
using GameBuilder;
using GameBuilder.Pops;
using GameBuilder.Psp;
using Li.Progress;
using PspCrypto;
@ -62,6 +63,17 @@ namespace LibChovy
else
img = new PsIsoImg(parameters.DrmInfo, parameters.FirstDisc);
// apply eboot elf overrides
if(parameters.EbootElfOverride is not null)
{
img.EbootElf = parameters.EbootElfOverride;
img.PatchEboot = false;
}
if (parameters.ConfigBinOverride is not null)
{
img.ConfigBin = parameters.ConfigBinOverride;
}
using (PbpBuilder pbpBuilder = new PbpBuilder(sfo, parameters.Icon0, null, parameters.Pic0, parameters.Pic1, null, img, 0))
{
pbpBuilder.RegisterCallback(onProgress);
@ -138,6 +150,8 @@ namespace LibChovy
SceNpDrm.Aid = parameters.DrmRif.AccountId;
BuildStream.BuildUsingStreamType = parameters.BuildStreamType;
if (!Directory.Exists(parameters.OutputFolder))
Directory.CreateDirectory(parameters.OutputFolder);

View File

@ -1,4 +1,5 @@
using GameBuilder.Psp;
using GameBuilder;
using GameBuilder.Psp;
using LibChovy.Config;
using System;
using System.Collections.Generic;
@ -19,6 +20,7 @@ namespace LibChovy
this.Account = new Account(DrmRif.AccountId);
this.CreatePsvImg = true;
this.FirmwareVersion = 0x3600000;
this.BuildStreamType = StreamType.TYPE_MEMORY_STREAM;
}
public int FirmwareVersion;
@ -27,7 +29,8 @@ namespace LibChovy
public NpDrmRif DrmRif;
public Account Account;
public ChovyTypes Type;
public StreamType BuildStreamType;
protected string? outputFolderOverride;

77
LibChovy/ChovyStream.cs Normal file
View File

@ -0,0 +1,77 @@
using DiscUtils.Streams;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LiLib
{
public class ChovyStream : Stream
{
private Stream underylingStream;
public ChovyStream()
{
underylingStream = new MemoryStream();
}
public override bool CanRead {
get {
return underylingStream.CanRead;
}
}
public override bool CanSeek {
get {
return underylingStream.CanSeek;
}
}
public override bool CanWrite {
get {
return underylingStream.CanWrite;
}
}
public override long Length {
get {
return underylingStream.Length;
}
}
public override long Position {
get {
return underylingStream.Position;
}
set {
underylingStream.Position = value;
}
}
public override void Flush()
{
underylingStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return underylingStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return underylingStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
underylingStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
underylingStream.Write(buffer, offset, count);
}
}
}

View File

@ -2,13 +2,13 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
</ItemGroup>
<ItemGroup>

View File

@ -1,4 +1,5 @@
using GameBuilder.Pops;
using GameBuilder.Pops.LibCrypt;
using GameBuilder.Psp;
using LibChovy.Art;
using System;
@ -16,16 +17,29 @@ namespace LibChovy
public PopsParameters(NpDrmInfo drmInfo, NpDrmRif rif) : base(drmInfo, rif)
{
Type = ChovyTypes.POPS;
discList = new List<DiscInfo>();
discList = new List<PSInfo>();
EbootElfOverride = null;
ConfigBinOverride = null;
discIdOverride = null;
nameOverride = null;
libCryptMethod = LibCryptMethod.METHOD_MAGIC_WORD;
}
private string? discIdOverride;
private string? nameOverride;
private List<DiscInfo> discList;
private List<PSInfo> discList;
private LibCryptMethod libCryptMethod;
private byte[]? pic0;
private byte[]? pic1;
private byte[]? icon0;
public DiscInfo FirstDisc
public byte[]? EbootElfOverride;
public byte[]? ConfigBinOverride;
public PSInfo FirstDisc
{
get
{
@ -101,9 +115,13 @@ namespace LibChovy
public void AddCd(string cd)
{
DiscInfo disc = new DiscInfo(cd);
if (nameOverride is not null) disc.DiscName = nameOverride;
else discList.Add(disc);
PSInfo disc = new PSInfo(cd);
if (nameOverride is not null) disc.DiscName = this.nameOverride;
if (discIdOverride is not null) disc.DiscId = this.discIdOverride;
if (disc.SbiFile is not null) disc.LibCrypt.Method = this.CrackMethod;
discList.Add(disc);
}
public void RemoveCd(string cd)
{
@ -116,13 +134,31 @@ namespace LibChovy
}
}
}
public DiscInfo[] Discs
public PSInfo[] Discs
{
get
{
return discList.ToArray();
}
}
public string DiscId
{
get
{
if (discIdOverride is not null && discIdOverride.Length == 9) return discIdOverride;
return FirstDisc.DiscId;
}
set
{
if (value.Equals(FirstDisc.DiscId, StringComparison.InvariantCultureIgnoreCase)) { discIdOverride = null; return; };
if (value.Length != 9) { discIdOverride = null; return; };
for (int i = 0; i < discList.Count; i++)
discList[i].DiscId = value;
discIdOverride = value;
}
}
public string Name
{
get
@ -143,6 +179,20 @@ namespace LibChovy
}
}
public LibCryptMethod CrackMethod
{
get
{
return libCryptMethod;
}
set
{
libCryptMethod = value;
for (int i = 0; i < discList.Count; i++)
discList[i].LibCrypt.Method = value;
}
}
public bool MultiDisc
{
get

View File

@ -137,3 +137,17 @@ EP9000-UCES01242_00-PRESELLADDONPCK0 FE1E0A3B419BB9376D084ABEC54A526B DBD40050D8
EP9000-UCES01242_00-PRESELLADDONPCK1 45331A2B5F214CD4E1297227126FAE95 FC1310D9604F5DC4FFF1015299A33524 A46821B0D75A1EA5932A9C6E6CC41E9B 70C67F9198F5105DFE70AA867679E0D3
EP9000-UCES01242_00-PRESELLADDONPCK3 3C67064205AF3B6F5516E1008F7E9578 3DA0A4525880F6E65D921B406291D0E0 FDB5E4B9E8FE2EBED8BE487F8B585ED9 C07F639AC4C4E5E3E3DED4054F600514
EP9000-UCES01242_00-PRESELLADDONPCK2 211625C7ACF3AD87FB80C088B5A816D0 731870DDA5D2B6A454FC32B196B39BB4 034B72CB73F41ECE183E17C5F1F5DB2F 01BDE1B45251E03597DE2D00F745E0E0
EP0001-NPEH00029_00-GPCASSASSINPGO02 3256531B6287569F75A12C24DB1D92F5 779E4C9FA20A2DC30DBBFDC05B6F8CE9 0E446F48989AF17569671B0BC24EE951 CBFD89B5ED02344EC13485B31E32DAB1
EP0006-NPEW00073_00-TPCFIFA11P000001 266993E225B9FE02F6784CF706624989 F19D7EDF0BDC5889A96DACB9B8D1AC68 C12E67459716BACCC208707B65793E1D 5C2104AB3DDB9974E444259EA0C75C2A
EP1004-ULES00502_00-GPCGRANDTH000001 0E39CF82632FFF40CB6431ED3D612C55 80C952D1EAE9B0486080B9A34E0F7C26 FD1233140909948C810391716D4730C9 9A1B891F7885430FBF0E2AD3B1AA15EE
EP1063-NPEH00101_00-PRAM001122334455 30CDDC33A4E18D8C9335278B7E05BB9B 4A1FBE67782A0324E4C7756F3854FE2B 60C5698A260CD64F8EF4ABFC936A354F D46F9CFBC83E2BCAE3C0AEB44D678756
EP1063-NPEH00101_00-TICKET0011223344 891C6358BCD5FA5822125170C9CFDC88 67128C1321601EB91F7FCF0D643A5A83 C0713C15C91ABF06278CC0A9437F1F27 53FAB2836B5DC5C89A2CC9D68CE5C23E
EP4293-ULES01515_00-GBPSPGAMERG00100 2CD73C4EFC809558543F1B3E3C272AB9 64794493FD2B4B960FB73AD6B1E140F7 766898B4E6BD91A138C242B4D56B1EE1 E849705F7C20FA3E4A963A01A632B8AA
EP9000-NPEG90013_00-DPCRESISTA000001 D9621D80C5BEF35B42DC2A18E8C1C1F2 D27AC3D28A9D564F8EE713B1C485C1B7 9BBB0AD3A6BDA78720ADBC73E30018BD 4EEE59B99F8DD06D97DFF7E196B317C0
EP9000-NPEG90019_00-LBPPSPEPSN000001 C0F7AD7D7012202CF27BBE670265BF05 1DCF8692689FB9CC0E010DE98EF77C23 8957E078A33C249D6CFEBF4A69CD21EE 6ADCB170B8A861E2035BAA20CB5BAA2C
EP9000-NPEW00068_00-TPCPSPGOPR000001 C3602E7EE9CA1B5D4600C5AA54BB1055 B53C53352F887C2DA84E5BDE29EB72AF 8CFA5E61BE013AFCFE418126CEF4D809 36644FDB1346637D6AF6C21426692FB8
EP9000-UCED90042_00-DPCSOCOMFTDEMO01 47D6208DF789C4ECD86692CF4D60A322 ECA7BAEC11B35B8F54280FE0D389B3B6 78DA407B23310875D52648802F7E4974 1878AC0652D24B8AEFB286358D2B5E60
EP9000-UCES00422_00-RIDGERACER2DEMO1 D5041BB4CBFBDFD6470F9F9EE6FE5A12 8A9833DB42B4848FEA6BF46E0CCCBB6D F09D093506D205CAE121D641C0AAB354 33B9BB2EE725BF8AD6AED826447C6BE9
EP9000-UCES00694_00-PFXTRMJUSTPSPGO2 0A4368759887952E157998EA5EA27396 71539E955A231AA6AB7044DA6E3D80AD FCCFB57EA5C15E1E5554811ECC7203E3 3041033FCD90D2ABA50545F6227410EB
EP9000-UCES01264_00-LBPPSPEFULL00001 297DBC7870E72EF195D85611A10B94E7 A9F0F0D181C264D15CB3AFC553EB63A7 0D905696883327C8F4CE4DC45B185FB8 900132071EB7175615C1CA822C804BA0
EP9001-NPEW00051_00-TPCGRANTUR000001 FEA1848910E05C9D45C9FBFA8863C1BE DE374F786E6CBF4E057B1C9EB64B3124 D50C141C8A7B0B840903F60A3796FB5B A346DCD09D173B36E524B29D776066C3

View File

@ -26,7 +26,7 @@ namespace LibChovy.VersionKey
catch { return null; }
}
public static NpDrmInfo? GetKeyFromGamePsvimg(string gameBackupFolder, string accountId)
public static NpDrmInfo? GetKeyFromGamePsvimg(string gameBackupFolder, string accountId, int keyIndex)
{
string gamePsvimgFile = Path.Combine(gameBackupFolder, "game", "game.psvimg");
if (!File.Exists(gamePsvimgFile)) return null;
@ -36,7 +36,7 @@ namespace LibChovy.VersionKey
using (PSVIMGFileStream? pbp = GetFileFromPsvImg(gamePsvimgFile, "/EBOOT.PBP", cmaKey))
{
if (pbp is null) return null;
return EbootPbpMethod.GetVersionKey(pbp);
return EbootPbpMethod.GetVersionKey(pbp, keyIndex);
}
}

View File

@ -21,7 +21,7 @@ namespace LibChovy.VersionKey
AMCTRL.bbmac_getkey(mkey, bbmac, versionKey);
return versionKey;
}
public static NpDrmInfo GetVersionKey(Stream ebootStream)
public static NpDrmInfo GetVersionKey(Stream ebootStream, int keyIndex)
{
using (ebootStream)
{
@ -39,32 +39,35 @@ namespace LibChovy.VersionKey
switch (psarMagic)
{
case "NPUMDIMG":
int keyType = ebootUtil.ReadInt32();
int orginalKeyIndex = ebootUtil.ReadInt32();
string contentId = ebootUtil.ReadStringAt(dataPsarLocation + 0x10);
byte[] npUmdHdr = ebootUtil.ReadBytesAt(dataPsarLocation, 0xC0);
byte[] npUmdHeaderHash = ebootUtil.ReadBytesAt(dataPsarLocation + 0xC0, 0x10);
byte[] versionkey = getKey(npUmdHeaderHash, npUmdHdr);
return new NpDrmInfo(versionkey, contentId, keyType);
SceNpDrm.sceNpDrmTransformVersionKey(versionkey, orginalKeyIndex, keyIndex);
return new NpDrmInfo(versionkey, contentId, keyIndex);
case "PSISOIMG":
using (DNASStream dnas = new DNASStream(ebootStream, dataPsarLocation + 0x400))
{
contentId = ebootUtil.ReadStringAt(dataPspLocation + 0x560);
keyType = dnas.KeyIndex;
orginalKeyIndex = dnas.KeyIndex;
versionkey = dnas.VersionKey;
return new NpDrmInfo(versionkey, contentId, keyType);
SceNpDrm.sceNpDrmTransformVersionKey(versionkey, orginalKeyIndex, keyIndex);
return new NpDrmInfo(versionkey, contentId, keyIndex);
}
case "PSTITLEI":
using (DNASStream dnas = new DNASStream(ebootStream, dataPsarLocation + 0x200))
{
contentId = ebootUtil.ReadStringAt(dataPspLocation + 0x560);
keyType = dnas.KeyIndex;
orginalKeyIndex = dnas.KeyIndex;
versionkey = dnas.VersionKey;
return new NpDrmInfo(versionkey, contentId, keyType);
SceNpDrm.sceNpDrmTransformVersionKey(versionkey, orginalKeyIndex, keyIndex);
return new NpDrmInfo(versionkey, contentId, keyIndex);
}
default:
throw new Exception("Cannot obtain versionkey from this EBOOT.PBP (magic:" + psarMagic + ")");

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

@ -2,12 +2,12 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.1.0" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.2.2" />
</ItemGroup>
<ItemGroup>

View File

@ -369,7 +369,7 @@ namespace PbpResign
AMCTRL.sceDrmBBCipherInit(out var ckey, 1, 2, npHdr.HeaderKey, vkey, 0);
AMCTRL.sceDrmBBCipherUpdate(ref ckey, psarBuff[0x40..], 0x60);
AMCTRL.sceDrmBBCipherFinal(ref ckey);
npHdr = Utils.AsRef<NpUmdImgHdr>(psarBuff);
npHdr = MemoryMarshal.AsRef<NpUmdImgHdr>(psarBuff);
var lbasize = npHdr.Body.LbaEnd - npHdr.Body.LbaStart + 1;
if (npHdr.BlockBasis == 0)
@ -1059,7 +1059,7 @@ namespace PbpResign
return false;
}
ref var npHdr = ref Utils.AsRef<NpUmdImgHdr>(psarBuff);
ref var npHdr = ref MemoryMarshal.AsRef<NpUmdImgHdr>(psarBuff);
if (npHdr.Magic0 == 0x4d55504e && npHdr.Magic1 == 0x474d4944)
{
@ -1070,22 +1070,6 @@ namespace PbpResign
return false;
}
type = 0;
/*
Console.WriteLine("VersionKey: " + BitConverter.ToString(NewVersionKey.ToArray()));
UmdInfo disc = new UmdInfo("fft.iso");
NpUmdImg npumd = new NpUmdImg(new NpDrmInfo(NewVersionKey.ToArray(), CId, npHdr.NpFlags), disc, false);
npumd.CreatePsar();
PbpBuilder.CreatePbp(disc.DataFiles["PARAM.SFO"],
disc.DataFiles["ICON0.PNG"],
disc.DataFiles["ICON1.PMF"],
disc.DataFiles["PIC0.PNG"],
disc.DataFiles["PIC1.PNG"],
disc.DataFiles["SND0.AT3"],
npumd,
"FFT.PBP"); */
return CopyNpUmdImg(input, output, pbpHdr, psarBuff, npHdr);
}
@ -1100,20 +1084,6 @@ namespace PbpResign
return false;
}
type = 1;
/*DiscInfo[] discs = new DiscInfo[2];
discs[0] = new DiscInfo("ABEE\\D1.CUE", "Oddworld: Abe's Exoddus", "SLES01480");
discs[1] = new DiscInfo("ABEE\\D2.CUE", "Oddworld: Abe's Exoddus", "SLES11480");
PsTitleImg title = new PsTitleImg(NewVersionKey.ToArray(), CId, discs);
title.CreatePsar();
PbpBuilder.CreatePbp(File.ReadAllBytes("TEST\\PARAM.SFO"), File.ReadAllBytes("TEST\\ICON0.PNG"), null,
File.ReadAllBytes("TEST\\PIC0.PNG"), File.ReadAllBytes("TEST\\PIC1.PNG"), null,
title.GenerateDataPsp(), title, "ABE-EBOOT.PBP");
//PsIsoImg i = new PsIsoImg("ROLLCAGE\\ROLLCAGE.CUE", "SLUS00800", "ROLLCAGE", CId, NewVersionKey.ToArray(),
// File.ReadAllBytes("TEST\\PARAM.SFO"), File.ReadAllBytes("TEST\\ICON0.PNG"), null,
// File.ReadAllBytes("TEST\\PIC0.PNG"), File.ReadAllBytes("TEST\\PIC1.PNG"), null);
//File.WriteAllBytes("TEST.BIN", i.GetIsoHeader());
//File.WriteAllBytes("TEST.ISOc", i.GetIso());*/
return CopyPsIsoImg(input, output, pbpHdr);
}
@ -1208,8 +1178,8 @@ namespace PbpResign
var srcPath = Path.GetDirectoryName(srcPbp);
// try
// {
try
{
using var input = File.OpenRead(srcPbp);
var hdr = new byte[Marshal.SizeOf<PbpHeader>()];
var len = input.Read(hdr);
@ -1219,7 +1189,7 @@ namespace PbpResign
return;
}
var pbpHdr = Utils.AsRef<PbpHeader>(hdr);
var pbpHdr = MemoryMarshal.AsRef<PbpHeader>(hdr);
if (pbpHdr.Sig != 0x50425000)
{
Console.WriteLine("Wrong pbp sig");
@ -1374,11 +1344,11 @@ namespace PbpResign
//}
}
//}
//catch (Exception e)
//{
// Console.WriteLine(e);
//}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}

View File

@ -6,10 +6,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\</PublishDir>
<PublishDir>bin\Release\net8.0\publish\win-x64\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>

View File

@ -67,7 +67,7 @@ namespace PspCrypto
static int Kirk4(Span<byte> buf, int size, int type)
{
int retv;
ref var hdr = ref Utils.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
hdr.keyseed = type;
hdr.data_size = size;
@ -83,7 +83,7 @@ namespace PspCrypto
static int Kirk5(Span<byte> buf, int size)
{
int retv;
ref var hdr = ref Utils.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_ENCRYPT_CBC;
hdr.keyseed = 0x0100;
hdr.data_size = size;
@ -99,7 +99,7 @@ namespace PspCrypto
static int Kirk7(Span<byte> buf, int size, int type)
{
int retv;
ref var hdr = ref Utils.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC;
hdr.keyseed = type;
hdr.data_size = size;
@ -115,7 +115,7 @@ namespace PspCrypto
static int Kirk8(Span<byte> buf, int size)
{
int retv;
ref var hdr = ref Utils.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
ref var hdr = ref MemoryMarshal.AsRef<KIRKEngine.KIRK_AES128CBC_HEADER>(buf);
hdr.mode = KIRKEngine.KIRK_MODE_DECRYPT_CBC;
hdr.keyseed = 0x0100;
hdr.data_size = size;
@ -553,7 +553,7 @@ namespace PspCrypto
public static int sceDrmBBMacFinal2(Span<byte> mkey, ReadOnlySpan<byte> hash, ReadOnlySpan<byte> vkey)
{
int i, retv, type;
int retv, type;
byte[] tmp = new byte[16];
int kbuf;
ref MAC_KEY macKey = ref MemoryMarshal.AsRef<MAC_KEY>(mkey);

View File

@ -197,6 +197,7 @@ namespace PspCrypto
var encData = encryptor.TransformFinalBlock(buffer, 0, buffer.Length);
encData.AsSpan().CopyTo(oubput);
}
#if false
public static byte[] AesDecrypt(Aes aes, byte[] data, int offset, int length)
{

View File

@ -35,7 +35,7 @@ namespace PspCrypto
data[..dataSize].CopyTo(pgdData[dataOffset..]);
ref var pgdHdr = ref Utils.AsRef<PgdHeader>(pgdData);
ref var pgdHdr = ref MemoryMarshal.AsRef<PgdHeader>(pgdData);
pgdHdr.Magic = 0x44475000;
pgdHdr.KeyIndex = keyIndex;
pgdHdr.DrmType = drmType;
@ -81,7 +81,7 @@ namespace PspCrypto
}
// Set the decryption parameters in the decrypted header.
ref var pgdDesc = ref Utils.AsRef<PgdDesc>(pgdHdr.PgdDesc);
ref var pgdDesc = ref MemoryMarshal.AsRef<PgdDesc>(pgdHdr.PgdDesc);
pgdDesc.DataSize = dataSize;
pgdDesc.BlockSize = blockSize;
pgdDesc.DataOffset = dataOffset;

View File

@ -169,7 +169,7 @@ namespace PspCrypto
{
throw new ArgumentException("stream too small", nameof(stream));
}
var header = Utils.AsRef<PgdHeader>(hdr);
var header = MemoryMarshal.AsRef<PgdHeader>(hdr);
_keyIndex = header.KeyIndex;
if (_keyIndex == 1)
{
@ -234,7 +234,7 @@ namespace PspCrypto
throw new IOException("Wrong MAC 0x80");
}
if (!Utils.isEmpty(_versionKey, 0x10))
if (!Utils.IsEmpty(_versionKey, 0x10))
{
ret = CheckBBMac(hdr, 0x70, _versionKey, header.Hash70, macType);
}
@ -253,7 +253,7 @@ namespace PspCrypto
{
throw new IOException($"Error 0x{ret:X8}");
}
var desc = Utils.AsRef<PgdDesc>(header.PgdDesc);
var desc = MemoryMarshal.AsRef<PgdDesc>(header.PgdDesc);
if (desc.Version != 0)
{
throw new IOException($"Error 0x{8051020:X8}");

View File

@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PspCrypto.Security.Cryptography;
using System;
using System.Security.Cryptography;
using System.Text;
using PspCrypto.Security.Cryptography;
namespace PspCrypto
{
@ -68,17 +65,6 @@ namespace PspCrypto
return new ECDsaManaged(par, ebootPbp, type);
}
public static ECDsa CreateNet(ECCurve curve, byte[] privateKey, byte[] pubx, byte[] puby)
{
var par = new ECParameters
{
Curve = curve,
D = privateKey,
Q = { X = pubx, Y = puby }
};
return ECDsa.Create(par);
}
public static void SignNpImageHeader(Span<byte> npHdr)
{
var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2,
@ -103,8 +89,8 @@ namespace PspCrypto
using var ecdsa = Create(curve, KeyVault.EdatPirv, KeyVault.EdatPx, KeyVault.EdatPy);
var sig = ecdsa.SignData(edat[..0x58].ToArray(), HashAlgorithmName.SHA1);
sig.CopyTo(edat[0x58..]);
}
}
public static void SignParamSfo(ReadOnlySpan<byte> param, Span<byte> sig)
{
var curve = SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b2, KeyVault.ec_N2, KeyVault.Gx2,

View File

@ -1,65 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using ECDsaTest.SafeHandles;
internal static partial class Interop
{
internal static partial class Crypto
{
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BigNumDestroy")]
internal static extern void BigNumDestroy(IntPtr a);
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BigNumToBinary")]
private static extern unsafe int BigNumToBinary(SafeBignumHandle a, byte* to);
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetBigNumBytes")]
private static extern int GetBigNumBytes(SafeBignumHandle a);
internal static byte[] ExtractBignum(IntPtr bignum, int targetSize)
{
// Given that the only reference held to bignum is an IntPtr, create an unowned SafeHandle
// to ensure that we don't destroy the key after extraction.
using (SafeBignumHandle handle = new SafeBignumHandle(bignum, ownsHandle: false))
{
return ExtractBignum(handle, targetSize);
}
}
private static unsafe byte[] ExtractBignum(SafeBignumHandle bignum, int targetSize)
{
if (bignum == null || bignum.IsInvalid)
{
return null;
}
int compactSize = GetBigNumBytes(bignum);
if (targetSize < compactSize)
{
targetSize = compactSize;
}
// OpenSSL BIGNUM values do not record leading zeroes.
// Windows Crypt32 does.
//
// Since RSACryptoServiceProvider already checks that RSAParameters.DP.Length is
// exactly half of RSAParameters.Modulus.Length, we need to left-pad (big-endian)
// the array with zeroes.
int offset = targetSize - compactSize;
byte[] buf = new byte[targetSize];
fixed (byte* to = buf)
{
byte* start = to + offset;
BigNumToBinary(bignum, start);
}
return buf;
}
}
}

View File

@ -1,93 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
internal static partial class Interop
{
internal static partial class Crypto
{
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ErrClearError")]
internal static extern ulong ErrClearError();
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ErrGetErrorAlloc")]
private static extern ulong ErrGetErrorAlloc([MarshalAs(UnmanagedType.Bool)] out bool isAllocFailure);
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ErrErrorStringN")]
private static extern unsafe void ErrErrorStringN(ulong e, byte* buf, int len);
private static unsafe string ErrErrorStringN(ulong error)
{
var buffer = new byte[1024];
fixed (byte* buf = &buffer[0])
{
ErrErrorStringN(error, buf, buffer.Length);
return Marshal.PtrToStringAnsi((IntPtr)buf);
}
}
internal static Exception CreateOpenSslCryptographicException()
{
// The Windows cryptography library reports error codes through
// Marshal.GetLastWin32Error, which has a single value when the
// function exits, last writer wins.
//
// OpenSSL maintains an error queue. Calls to ERR_get_error read
// values out of the queue in the order that ERR_set_error wrote
// them. Nothing enforces that a single call into an OpenSSL
// function will guarantee at-most one error being set.
//
// In order to maintain parity in how error flows look between the
// Windows code and the OpenSSL-calling code, drain the queue
// whenever an Exception is desired, and report the exception
// related to the last value in the queue.
bool isAllocFailure;
ulong error = ErrGetErrorAlloc(out isAllocFailure);
ulong lastRead = error;
bool lastIsAllocFailure = isAllocFailure;
// 0 (there's no named constant) is only returned when the calls
// to ERR_get_error exceed the calls to ERR_set_error.
while (lastRead != 0)
{
error = lastRead;
isAllocFailure = lastIsAllocFailure;
lastRead = ErrGetErrorAlloc(out lastIsAllocFailure);
}
// If we're in an error flow which results in an Exception, but
// no calls to ERR_set_error were made, throw the unadorned
// CryptographicException.
if (error == 0)
{
return new CryptographicException();
}
if (isAllocFailure)
{
return new OutOfMemoryException();
}
// Even though ErrGetError returns ulong (C++ unsigned long), we
// really only expect error codes in the UInt32 range
Debug.Assert(error <= uint.MaxValue, "ErrGetError should only return error codes in the UInt32 range.");
// If there was an error code, and it wasn't something handled specially,
// use the OpenSSL error string as the message to a CryptographicException.
return new OpenSslCryptographicException(unchecked((int)error), ErrErrorStringN(error));
}
private sealed class OpenSslCryptographicException : CryptographicException
{
internal OpenSslCryptographicException(int errorCode, string message)
: base(message)
{
HResult = errorCode;
}
}
}
}

View File

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using ECDsaTest.SafeHandles;
internal static partial class Interop
{
internal static partial class Crypto
{
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcKeyCreateByExplicitParameters")]
internal static extern SafeEcKeyHandle EcKeyCreateByExplicitParameters(
ECCurve.ECCurveType curveType,
byte[] qx, int qxLength,
byte[] qy, int qyLength,
byte[] d, int dLength,
byte[] p, int pLength,
byte[] a, int aLength,
byte[] b, int bLength,
byte[] gx, int gxLength,
byte[] gy, int gyLength,
byte[] order, int nLength,
byte[] cofactor, int cofactorLength,
byte[] seed, int seedLength);
internal static SafeEcKeyHandle EcKeyCreateByExplicitCurve(ECCurve curve)
{
byte[] p;
if (curve.IsPrime)
{
p = curve.Prime;
}
else if (curve.IsCharacteristic2)
{
p = curve.Polynomial;
}
else
{
throw new PlatformNotSupportedException(string.Format("The specified curve '{0}' or its parameters are not valid for this platform.", curve.CurveType.ToString()));
}
SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitParameters(
curve.CurveType,
null, 0,
null, 0,
null, 0,
p, p.Length,
curve.A, curve.A.Length,
curve.B, curve.B.Length,
curve.G.X, curve.G.X.Length,
curve.G.Y, curve.G.Y.Length,
curve.Order, curve.Order.Length,
curve.Cofactor, curve.Cofactor.Length,
curve.Seed, curve.Seed == null ? 0 : curve.Seed.Length);
if (key == null || key.IsInvalid)
{
if (key != null)
key.Dispose();
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
// EcKeyCreateByExplicitParameters may have polluted the error queue, but key was good in the end.
// Clean up the error queue.
Interop.Crypto.ErrClearError();
return key;
}
}
}

View File

@ -1,78 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using ECDsaTest;
using ECDsaTest.SafeHandles;
internal static partial class Interop
{
internal static partial class Crypto
{
internal static bool EcDsaSignEx(ReadOnlySpan<byte> dgst, Span<byte> sig, [In, Out] ref int siglen,
ReadOnlySpan<byte> kinv, ReadOnlySpan<byte> rp, SafeEcKeyHandle ecKey) => EcDsaSignEx(
ref MemoryMarshal.GetReference(dgst), dgst.Length, ref MemoryMarshal.GetReference(sig), ref siglen,
ref MemoryMarshal.GetReference(kinv), kinv.Length, ref MemoryMarshal.GetReference(rp), rp.Length, ecKey);
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcDsaSignEx")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EcDsaSignEx(ref byte dgst, int dlen, ref byte sig, [In, Out] ref int siglen,
ref byte kinv, int kinvlen, ref byte rp, int rplen, SafeEcKeyHandle ecKey);
// returns the maximum length of a DER encoded ECDSA signature created with this key.
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcDsaSize")]
private static extern int CryptoNative_EcDsaSize(SafeEcKeyHandle ecKey);
internal static int EcDsaSize(SafeEcKeyHandle ecKey)
{
int ret = CryptoNative_EcDsaSize(ecKey);
if (ret == 0)
{
throw CreateOpenSslCryptographicException();
}
return ret;
}
internal static PspParameter EcPspParameter(SafeEcKeyHandle key, ReadOnlySpan<byte> sha256, int len)
{
SafeBignumHandle kinv_bn, rp_bn;
int kinvlen, rplen;
bool refAdded = false;
try
{
key.DangerousAddRef(ref refAdded);
var ret = EcPspParameter(key, ref MemoryMarshal.GetReference(sha256), len, out kinv_bn, out kinvlen,
out rp_bn, out rplen);
if (!ret)
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
using (kinv_bn)
using (rp_bn)
{
var par = new PspParameter
{
Kinv = Crypto.ExtractBignum(kinv_bn, kinvlen),
Rp = Crypto.ExtractBignum(rp_bn, rplen)
};
return par;
}
}
finally
{
if (refAdded)
key.DangerousRelease();
}
}
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcPspParameter")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EcPspParameter(SafeEcKeyHandle ecKey, ref byte sha256, int len, out SafeBignumHandle kinv,
out int kinvlen, out SafeBignumHandle rp, out int rplen);
}
}

View File

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
internal static partial class Interop
{
internal static partial class Crypto
{
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcKeyDestroy")]
internal static extern void EcKeyDestroy(IntPtr a);
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcKeyUpRef")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EcKeyUpRef(IntPtr r);
}
}

View File

@ -762,7 +762,7 @@ namespace PspCrypto
static int kirk_CMD0(Span<byte> outbuff, ReadOnlySpan<byte> inbuff, int size, bool generate_trash)
{
KIRK_CMD1_HEADER header = Utils.AsRef<KIRK_CMD1_HEADER>(outbuff);
KIRK_CMD1_HEADER header = MemoryMarshal.AsRef<KIRK_CMD1_HEADER>(outbuff);
// header_keys keys = Utils.AsRef<header_keys>(outbuff);
int chk_size;
Aes k1;
@ -817,7 +817,7 @@ namespace PspCrypto
static int kirk_CMD1(Span<byte> outbuff, ReadOnlySpan<byte> inbuff, int size)
{
KIRK_CMD1_HEADER header = Utils.AsRef<KIRK_CMD1_HEADER>(inbuff);
KIRK_CMD1_HEADER header = MemoryMarshal.AsRef<KIRK_CMD1_HEADER>(inbuff);
// header_keys keys; //0-15 AES key, 16-31 CMAC key
Aes k1;
@ -831,7 +831,7 @@ namespace PspCrypto
if (header.ecdsa_hash == 1)
{
KIRK_CMD1_ECDSA_HEADER eheader = Utils.AsRef<KIRK_CMD1_ECDSA_HEADER>(inbuff);
KIRK_CMD1_ECDSA_HEADER eheader = MemoryMarshal.AsRef<KIRK_CMD1_ECDSA_HEADER>(inbuff);
var curve = ECDsaHelper.SetCurve(KeyVault.ec_p, KeyVault.ec_a, KeyVault.ec_b1, KeyVault.ec_N1, KeyVault.Gx1,
KeyVault.Gy1);
unsafe
@ -867,7 +867,7 @@ namespace PspCrypto
static int kirk_CMD4(Span<byte> outbuff, ReadOnlySpan<byte> inbuff, int size)
{
KIRK_AES128CBC_HEADER header = Utils.AsRef<KIRK_AES128CBC_HEADER>(inbuff);
KIRK_AES128CBC_HEADER header = MemoryMarshal.AsRef<KIRK_AES128CBC_HEADER>(inbuff);
byte[] key;
Aes aes;
@ -892,7 +892,7 @@ namespace PspCrypto
static int kirk_CMD7(Span<byte> outbuff, ReadOnlySpan<byte> inbuff, int size)
{
KIRK_AES128CBC_HEADER header = Utils.AsRef<KIRK_AES128CBC_HEADER>(inbuff);
KIRK_AES128CBC_HEADER header = MemoryMarshal.AsRef<KIRK_AES128CBC_HEADER>(inbuff);
byte[] key;
Aes aes;
@ -915,7 +915,7 @@ namespace PspCrypto
static int kirk_CMD10(ReadOnlySpan<byte> inbuff, int insize)
{
KIRK_CMD1_HEADER header = Utils.AsRef<KIRK_CMD1_HEADER>(inbuff);
KIRK_CMD1_HEADER header = MemoryMarshal.AsRef<KIRK_CMD1_HEADER>(inbuff);
// header_keys keys; //0-15 AES key, 16-31 CMAC key
Span<byte> cmac_header_hash = stackalloc byte[16];
Span<byte> cmac_data_hash = stackalloc byte[16];
@ -951,7 +951,7 @@ namespace PspCrypto
static int kirk_CMD11(Span<byte> outbuff, ReadOnlySpan<byte> inbuff, int size)
{
KIRK_SHA1_HEADER header = Utils.AsRef<KIRK_SHA1_HEADER>(inbuff);
KIRK_SHA1_HEADER header = MemoryMarshal.AsRef<KIRK_SHA1_HEADER>(inbuff);
if (!is_kirk_initialized) return KIRK_NOT_INITIALIZED;
if (header.data_size == 0 || size == 0) return KIRK_DATA_SIZE_ZERO;
@ -1044,7 +1044,7 @@ namespace PspCrypto
static int kirk_CMD16(Span<byte> outbuff, int outsize, ReadOnlySpan<byte> inbuff, int insize)
{
byte[] dec_private = new byte[0x20];
KIRK_CMD16_BUFFER signbuf = Utils.AsRef<KIRK_CMD16_BUFFER>(inbuff);
KIRK_CMD16_BUFFER signbuf = MemoryMarshal.AsRef<KIRK_CMD16_BUFFER>(inbuff);
//ECDSA_SIG sig = BufferToStruct<ECDSA_SIG>(outbuff);
if (insize != 0x34) return KIRK_INVALID_SIZE;
@ -1071,7 +1071,7 @@ namespace PspCrypto
static int kirk_CMD17(ReadOnlySpan<byte> inbuff, int insize)
{
KIRK_CMD17_BUFFER sig = Utils.AsRef<KIRK_CMD17_BUFFER>(inbuff);
KIRK_CMD17_BUFFER sig = MemoryMarshal.AsRef<KIRK_CMD17_BUFFER>(inbuff);
if (insize != 0x64) return KIRK_INVALID_SIZE;
@ -1080,7 +1080,7 @@ namespace PspCrypto
unsafe
{
var ecdsa = ECDsaHelper.Create(curve, sig.public_key.x, sig.public_key.y);
ECDsa ecdsa = ECDsaHelper.Create(curve, sig.public_key.x, sig.public_key.y);
if (ecdsa.VerifyHash(sig.message_hash, sig.signature.sig))
{

View File

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.0" />
<PackageReference Include="DotNetZip" Version="1.16.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>

View File

@ -1,38 +0,0 @@
using System;
using System.Security.Cryptography;
namespace PspCrypto
{
public class RijndaelMod : Aes
{
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
{
return CreateTransform(rgbKey, encrypting: false);
}
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
{
return CreateTransform(rgbKey, encrypting: true);
}
public override void GenerateIV()
{
}
public override void GenerateKey()
{
byte[] key = new byte[KeySize / BitsPerByte];
RandomNumberGenerator.Fill(key);
Key = key;
}
private ICryptoTransform CreateTransform(byte[] rgbKey, bool encrypting)
{
if (rgbKey == null)
throw new ArgumentNullException(nameof(rgbKey));
return new RijndaelModTransform(rgbKey, BlockSizeValue, encrypting);
}
private const int BitsPerByte = 8;
}
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More