2023-04-17 19:00:52 +00:00
using Li.Progress ;
using GameBuilder.Pops ;
2023-04-16 19:48:32 +00:00
using GameBuilder.Psp ;
2023-04-19 09:58:07 +00:00
using LibChovy ;
2023-04-23 08:15:11 +00:00
using LibChovy.VersionKey ;
2023-04-24 11:53:22 +00:00
using System.Text ;
2023-06-09 09:06:44 +00:00
using Vita.ContentManager ;
using PspCrypto ;
2023-04-16 19:48:32 +00:00
namespace ChovySign_CLI
{
internal class Program
{
private static ArgumentParsingMode mode = ArgumentParsingMode . ARG ;
private static List < string > parameters = new List < string > ( ) ;
2023-06-09 09:06:44 +00:00
private static string [ ] discs = new string [ ] { } ;
2023-04-16 19:48:32 +00:00
private static bool pspCompress = false ;
private static string? popsDiscName ;
2023-06-09 09:06:44 +00:00
private static byte [ ] ? popsIcon0File ;
private static byte [ ] ? popsPic0File ;
2023-04-16 19:48:32 +00:00
private static PbpMode ? pbpMode = null ;
2023-04-19 09:58:07 +00:00
private static NpDrmRif ? rifFile = null ;
2023-04-16 19:48:32 +00:00
private static NpDrmInfo ? drmInfo = null ;
2023-04-24 11:53:22 +00:00
2023-06-09 09:06:44 +00:00
// cma
private static bool devKit = false ;
private static bool packagePsvImg = true ;
private static string? outputFolder = null ;
// --vkey-gen
2023-04-24 11:53:22 +00:00
private static byte [ ] ? actDat = null ;
private static byte [ ] ? idps = null ;
private static string? rifFolder = null ;
2023-06-09 09:06:44 +00:00
// --pops-eboot-sign
private static byte [ ] ? ebootElf = null ;
private static byte [ ] ? configBin = null ;
2023-04-16 19:48:32 +00:00
enum PbpMode
{
PSP = 0 ,
POPS = 1 ,
PCENGINE = 2 ,
NEOGEO = 3
}
enum ArgumentParsingMode
{
2023-06-09 09:06:44 +00:00
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
2023-04-16 19:48:32 +00:00
}
public static int Error ( string errorMsg , int ret )
{
Console . Error . WriteLine ( "ERROR: " + errorMsg ) ;
return ret ;
}
public static byte [ ] StringToByteArray ( string hex )
{
return Enumerable . Range ( 0 , hex . Length ) . Where ( x = > x % 2 = = 0 ) . Select ( x = > Convert . ToByte ( hex . Substring ( x , 2 ) , 16 ) ) . ToArray ( ) ;
}
private static void onProgress ( ProgressInfo info )
{
2023-04-17 19:00:52 +00:00
string msg = info . CurrentProcess + " " + info . ProgressInt . ToString ( ) + "% (" + info . Done + "/" + info . Remain + ")" ;
int spaceLen = ( Console . WindowWidth - msg . Length ) - 2 ;
string emptySpace = " " ;
for ( int i = 0 ; i < spaceLen ; i + + )
emptySpace + = " " ;
Console . Write ( msg + emptySpace + "\r" ) ;
2023-04-16 19:48:32 +00:00
}
2023-04-24 11:53:22 +00:00
private static void generateKeysTxt ( )
{
if ( rifFolder is null | | actDat is null | | idps is null ) return ;
UInt64 accountId = BitConverter . ToUInt64 ( actDat , 0x8 ) ;
if ( File . Exists ( "KEYS.TXT" ) )
KeysTxtMethod . KeysTxt = File . ReadAllText ( "KEYS.TXT" ) ;
else
File . WriteAllText ( "KEYS.TXT" , KeysTxtMethod . KeysTxt ) ;
HashSet < string > knownKeys = new HashSet < string > ( ) ;
foreach ( string contentId in KeysTxtMethod . ContentIds )
knownKeys . Add ( contentId ) ;
StringBuilder addKeys = new StringBuilder ( ) ;
foreach ( string rifFile in Directory . GetFiles ( rifFolder , "*.rif" ) )
{
NpDrmRif rif = new NpDrmRif ( File . ReadAllBytes ( rifFile ) ) ;
if ( knownKeys . Contains ( rif . ContentId ) ) continue ;
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 ( "-" , "" ) ;
string [ ] keysTxtLine = new string [ ] { rif . ContentId , keys [ 0 ] , keys [ 1 ] , keys [ 2 ] , keys [ 3 ] } ;
string keysTxt = String . Join ( ' ' , keysTxtLine ) ;
addKeys . AppendLine ( keysTxt ) ;
Console . WriteLine ( keysTxt ) ;
}
File . AppendAllText ( "KEYS.TXT" , addKeys . ToString ( ) ) ;
}
2023-04-16 19:48:32 +00:00
private static int complete ( )
{
switch ( mode )
{
case ArgumentParsingMode . POPS_DISC :
2023-06-09 09:06:44 +00:00
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 ) ;
2023-04-16 19:48:32 +00:00
discs = parameters . ToArray ( ) ;
break ;
case ArgumentParsingMode . PSP_UMD :
2023-06-09 09:06:44 +00:00
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 ) ;
2023-04-16 19:48:32 +00:00
discs = new string [ 1 ] ;
discs [ 0 ] = parameters [ 0 ] ;
if ( parameters . Count > 1 )
pspCompress = parameters [ 1 ] . ToLowerInvariant ( ) = = "true" ;
else
pspCompress = false ;
break ;
case ArgumentParsingMode . VERSIONKEY :
if ( parameters . Count ! = 3 ) return Error ( "--vkey: expect 3 arguments. (" + parameters . Count + " given)" , 4 ) ;
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 ] ) ) ;
break ;
case ArgumentParsingMode . VERSIONKEY_GENERATOR :
if ( parameters . Count ! = 4 ) return Error ( "--vkey-gen: expect 4 arguments. (" + parameters . Count + " given)" , 4 ) ;
drmInfo = ActRifMethod . GetVersionKey ( File . ReadAllBytes ( parameters [ 0 ] ) , File . ReadAllBytes ( parameters [ 1 ] ) , StringToByteArray ( parameters [ 2 ] ) , int . Parse ( parameters [ 3 ] ) ) ;
break ;
case ArgumentParsingMode . POPS_INFO :
2023-04-19 09:58:07 +00:00
if ( parameters . Count < 2 ) return Error ( "--pops-info takes at least 1 arguments (" + parameters . Count + " given)" , 4 ) ;
2023-04-16 19:48:32 +00:00
if ( parameters . Count > 3 ) return Error ( "--pops-info takes no more than 3 arguments(" + parameters . Count + " given)" , 4 ) ;
popsDiscName = parameters [ 0 ] ;
2023-06-09 09:06:44 +00:00
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 ] ) ;
2023-04-16 19:48:32 +00:00
break ;
2023-04-24 11:53:22 +00:00
case ArgumentParsingMode . KEYS_TXT_GEN :
if ( parameters . Count ! = 3 ) return Error ( "--keys-txt-gen takes 3 arguments, (" + parameters . Count + " given)" , 4 ) ;
actDat = File . ReadAllBytes ( parameters [ 0 ] ) ;
idps = StringToByteArray ( parameters [ 1 ] ) ;
rifFolder = parameters [ 2 ] ;
break ;
2023-06-09 09:06:44 +00:00
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 ;
2023-04-19 09:58:07 +00:00
case ArgumentParsingMode . RIF :
if ( parameters . Count ! = 1 ) return Error ( "--rif expects only 1 argument," , 4 ) ;
rifFile = new NpDrmRif ( File . ReadAllBytes ( parameters [ 0 ] ) ) ;
break ;
2023-04-16 19:48:32 +00:00
}
mode = ArgumentParsingMode . ARG ;
parameters . Clear ( ) ;
return 0 ;
}
public static int Main ( string [ ] args )
{
2023-04-17 19:00:52 +00:00
if ( args . Length = = 0 )
2023-04-16 19:48:32 +00:00
{
Console . WriteLine ( "Chovy-Sign v2 (CLI)" ) ;
Console . WriteLine ( "--pops [disc1.cue] [disc2.cue] [disc3.cue] ... (up to 5)" ) ;
2023-04-19 09:58:07 +00:00
Console . WriteLine ( "--pops-info [game title] [icon0.png] (optional) [pic1.png] (optional)" ) ;
2023-06-09 09:06:44 +00:00
Console . WriteLine ( "--pops-eboot [eboot.elf] [config.bin] (optional)" ) ;
2023-04-16 19:48:32 +00:00
Console . WriteLine ( "--psp [umd.iso] [compress; true/false] (optional)" ) ;
2023-06-09 09:06:44 +00:00
2023-04-19 09:58:07 +00:00
Console . WriteLine ( "--rif [GAME.RIF]" ) ;
2023-06-09 09:06:44 +00:00
2023-04-19 09:58:07 +00:00
Console . WriteLine ( "--devkit (Use 000000000000 account id)" ) ;
2023-06-09 09:06:44 +00:00
Console . WriteLine ( "--no-psvimg (Disable creating a .psvimg file)" ) ;
Console . WriteLine ( "--output-folder [output_folder]" ) ;
2023-04-16 19:48:32 +00:00
Console . WriteLine ( "--vkey [versionkey] [contentid] [key_index]" ) ;
Console . WriteLine ( "--vkey-extract [eboot.pbp]" ) ;
Console . WriteLine ( "--vkey-gen [act.dat] [license.rif] [console_id] [key_index]" ) ;
2023-06-09 09:06:44 +00:00
2023-04-24 11:53:22 +00:00
Console . WriteLine ( "--keys-txt-gen [act.dat] [console_id] [psp_license_folder]" ) ;
2023-04-16 19:48:32 +00:00
}
foreach ( string arg in args )
{
if ( arg . StartsWith ( "--" ) ) { int ret = complete ( ) ; if ( ret ! = 0 ) return ret ; }
switch ( mode )
{
case ArgumentParsingMode . ARG :
switch ( arg )
{
case "--pops" :
mode = ArgumentParsingMode . POPS_DISC ;
if ( pbpMode is not null )
return Error ( "pbpMode is already set to: " + pbpMode . ToString ( ) + " cannot do that *and* POPS" , 2 ) ;
pbpMode = PbpMode . POPS ;
break ;
case "--pops-info" :
mode = ArgumentParsingMode . POPS_INFO ;
break ;
case "--psp" :
mode = ArgumentParsingMode . PSP_UMD ;
if ( pbpMode is not null )
return Error ( "pbpMode is already set to: " + pbpMode . ToString ( ) + " cannot do that *and* PSP" , 2 ) ;
pbpMode = PbpMode . PSP ;
break ;
case "--vkey" :
mode = ArgumentParsingMode . VERSIONKEY ;
if ( drmInfo is not null )
return Error ( "versionkey is already set" , 3 ) ;
break ;
case "--vkey-extract" :
mode = ArgumentParsingMode . VERSIONKEY_EXTRACT ;
if ( drmInfo is not null )
return Error ( "versionkey is already set" , 3 ) ;
break ;
case "--vkey-gen" :
mode = ArgumentParsingMode . VERSIONKEY_GENERATOR ;
if ( drmInfo is not null )
return Error ( "versionkey is already set" , 3 ) ;
2023-04-19 09:58:07 +00:00
break ;
2023-04-24 11:53:22 +00:00
case "--keys-txt-gen" :
mode = ArgumentParsingMode . KEYS_TXT_GEN ;
if ( rifFolder is not null )
return Error ( "rif folder already set" , 3 ) ;
break ;
2023-04-19 09:58:07 +00:00
case "--rif" :
mode = ArgumentParsingMode . RIF ;
if ( rifFile is not null )
return Error ( "rif is already set" , 3 ) ;
break ;
2023-06-09 09:06:44 +00:00
case "--pops-eboot" :
mode = ArgumentParsingMode . POPS_EBOOT ;
break ;
case "--output-folder" :
mode = ArgumentParsingMode . CMA_OUTPUT_FOLDER ;
break ;
case "--no-psvimg" :
packagePsvImg = false ;
break ;
2023-04-19 09:58:07 +00:00
case "--devkit" :
devKit = true ;
2023-04-16 19:48:32 +00:00
break ;
default :
return Error ( "Unknown argument: " + arg , 1 ) ;
}
break ;
case ArgumentParsingMode . VERSIONKEY :
case ArgumentParsingMode . VERSIONKEY_GENERATOR :
case ArgumentParsingMode . VERSIONKEY_EXTRACT :
case ArgumentParsingMode . PSP_UMD :
case ArgumentParsingMode . POPS_DISC :
2023-06-09 09:06:44 +00:00
case ArgumentParsingMode . POPS_EBOOT :
2023-04-16 19:48:32 +00:00
case ArgumentParsingMode . POPS_INFO :
2023-04-19 09:58:07 +00:00
case ArgumentParsingMode . RIF :
2023-04-16 19:48:32 +00:00
default :
parameters . Add ( arg ) ;
break ;
}
}
int res = complete ( ) ;
if ( res ! = 0 ) return res ;
2023-04-24 11:53:22 +00:00
generateKeysTxt ( ) ;
2023-04-16 19:48:32 +00:00
if ( drmInfo is null ) return Error ( "no versionkey was found, exiting" , 6 ) ;
2023-04-24 11:53:22 +00:00
//Console.WriteLine("Version Key: " + BitConverter.ToString(drmInfo.VersionKey).Replace("-", "") + ", " + drmInfo.KeyIndex);
2023-04-16 22:14:13 +00:00
if ( pbpMode is null ) return Error ( "no pbp mode was set, exiting" , 7 ) ;
2023-04-16 20:51:24 +00:00
if ( pbpMode = = PbpMode . PSP & & drmInfo . KeyIndex ! = 2 )
2023-06-09 09:06:44 +00:00
return Error ( "KeyType is " + drmInfo . KeyIndex + ", but PBP mode is PSP, you cant do that .. please use a type 2 versionkey." , 8 ) ;
2023-04-16 19:48:32 +00:00
2023-04-16 20:51:24 +00:00
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 ) ;
2023-04-16 19:48:32 +00:00
2023-04-19 09:58:07 +00:00
if ( rifFile is null )
return Error ( "Rif is not set, use --rif to specify base game RIF" , 8 ) ;
2023-06-09 09:06:44 +00:00
2023-04-19 09:58:07 +00:00
ChovySign csign = new ChovySign ( ) ;
csign . RegisterCallback ( onProgress ) ;
2023-04-16 19:48:32 +00:00
if ( pbpMode = = PbpMode . POPS )
{
2023-04-19 09:58:07 +00:00
PopsParameters popsParameters = new PopsParameters ( drmInfo , rifFile ) ;
foreach ( string disc in discs )
popsParameters . AddCd ( disc ) ;
if ( popsDiscName is not null )
popsParameters . Name = popsDiscName ;
2023-06-09 09:06:44 +00:00
if ( popsIcon0File is not null )
popsParameters . Icon0 = popsIcon0File ;
2023-04-16 19:48:32 +00:00
2023-06-09 09:06:44 +00:00
popsParameters . CreatePsvImg = packagePsvImg ;
2023-04-19 09:58:07 +00:00
popsParameters . Account . Devkit = devKit ;
2023-04-16 19:48:32 +00:00
2023-06-09 09:06:44 +00:00
// Allow for custom eboot.elf and configs
popsParameters . ConfigBinOverride = configBin ;
popsParameters . EbootElfOverride = ebootElf ;
2023-04-19 09:58:07 +00:00
csign . Go ( popsParameters ) ;
2023-04-16 19:48:32 +00:00
}
else if ( pbpMode = = PbpMode . PSP )
{
2023-04-19 09:58:07 +00:00
PspParameters pspParameters = new PspParameters ( drmInfo , rifFile ) ;
pspParameters . Account . Devkit = devKit ;
2023-06-09 09:06:44 +00:00
pspParameters . CreatePsvImg = packagePsvImg ;
2023-04-19 09:58:07 +00:00
pspParameters . Compress = pspCompress ;
pspParameters . Umd = new UmdInfo ( discs . First ( ) ) ;
csign . Go ( pspParameters ) ;
2023-04-16 19:48:32 +00:00
}
return 0 ;
}
}
}