From b215adde4e4a71297338bf251fcfc8ca0ee81aa0 Mon Sep 17 00:00:00 2001 From: SilicaAndPina Date: Wed, 26 Aug 2020 00:23:16 +1200 Subject: [PATCH] Update code --- CHOVY-KIRK/CHOVY-KIRK.vcxproj | 2 + CHOVY-KIRK/CHOVY-KIRK.vcxproj.filters | 6 + CHOVY-SIGN/App.config | 12 +- CHOVY-SIGN/CHOVY-SIGN.csproj | 7 +- CHOVY-SIGN/CHOVYPopsBuilder.cs | 4 +- CHOVY-SIGN/CHOVYPspBuilder.cs | 93 +++--- CHOVY-SIGN/DataUtils.cs | 26 +- CHOVY-SIGN/packages.config | 6 - CHOVY-SIGN/pbp.cs | 394 +++++++++++++++++++++++++- 9 files changed, 488 insertions(+), 62 deletions(-) delete mode 100644 CHOVY-SIGN/packages.config diff --git a/CHOVY-KIRK/CHOVY-KIRK.vcxproj b/CHOVY-KIRK/CHOVY-KIRK.vcxproj index ea60855..05df53e 100644 --- a/CHOVY-KIRK/CHOVY-KIRK.vcxproj +++ b/CHOVY-KIRK/CHOVY-KIRK.vcxproj @@ -163,6 +163,7 @@ + @@ -174,6 +175,7 @@ + diff --git a/CHOVY-KIRK/CHOVY-KIRK.vcxproj.filters b/CHOVY-KIRK/CHOVY-KIRK.vcxproj.filters index b1c7b7b..2e12caf 100644 --- a/CHOVY-KIRK/CHOVY-KIRK.vcxproj.filters +++ b/CHOVY-KIRK/CHOVY-KIRK.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + @@ -65,5 +68,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/CHOVY-SIGN/App.config b/CHOVY-SIGN/App.config index d1428ad..771054e 100644 --- a/CHOVY-SIGN/App.config +++ b/CHOVY-SIGN/App.config @@ -1,6 +1,14 @@ - + - + + + + + + + + + diff --git a/CHOVY-SIGN/CHOVY-SIGN.csproj b/CHOVY-SIGN/CHOVY-SIGN.csproj index 709fb62..891ad05 100644 --- a/CHOVY-SIGN/CHOVY-SIGN.csproj +++ b/CHOVY-SIGN/CHOVY-SIGN.csproj @@ -52,7 +52,13 @@ ..\packages\HtmlAgilityPack.1.11.24\lib\Net45\HtmlAgilityPack.dll + + ..\packages\System.Buffers.4.5.1\lib\netstandard1.1\System.Buffers.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll + @@ -453,7 +459,6 @@ Resources.resx True - SettingsSingleFileGenerator Settings.Designer.cs diff --git a/CHOVY-SIGN/CHOVYPopsBuilder.cs b/CHOVY-SIGN/CHOVYPopsBuilder.cs index 4eb7639..c5c6718 100644 --- a/CHOVY-SIGN/CHOVYPopsBuilder.cs +++ b/CHOVY-SIGN/CHOVYPopsBuilder.cs @@ -204,11 +204,11 @@ namespace CHOVY_SIGN PSVIMGStream LicensePsvimg = new PSVIMGStream(File.OpenRead(BackupPath), Key); PSVIMGFileStream EbootPbp = new PSVIMGFileStream(GamePsvimg, "/EBOOT.PBP"); - byte[] VersionKey = pbp.GetVersionKeyPs1(EbootPbp); + byte[] VersionKey = Pbp.GetVersionKeyPs1(EbootPbp); string VerKey = BitConverter.ToString(VersionKey).Replace("-", ""); WriteSetting("VersionKey", VerKey); - string ContentID = pbp.GetContentIdPS1(EbootPbp); + string ContentID = Pbp.GetContentIdPS1(EbootPbp); PSVIMGFileStream LicenseRif = new PSVIMGFileStream(LicensePsvimg, "/" + ContentID + ".rif"); byte[] LicenseRifBytes = new byte[LicenseRif.Length]; LicenseRif.Read(LicenseRifBytes, 0x00, LicenseRifBytes.Length); diff --git a/CHOVY-SIGN/CHOVYPspBuilder.cs b/CHOVY-SIGN/CHOVYPspBuilder.cs index 2bf61b2..4cff496 100644 --- a/CHOVY-SIGN/CHOVYPspBuilder.cs +++ b/CHOVY-SIGN/CHOVYPspBuilder.cs @@ -5,7 +5,6 @@ using ParamSfo; using PSVIMGTOOLS; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.IO; using System.Media; @@ -18,33 +17,40 @@ namespace CHOVY_SIGN public partial class CHOVYPspBuilder : Form { bool MutedAudio = false; - public byte[] GetSfo(string ISOFile) + + public static byte[] FromHex(string hex) { - FileStream ISO = File.OpenRead(ISOFile); + hex = hex.Replace("-", ""); + byte[] raw = new byte[hex.Length / 2]; + for (int i = 0; i < raw.Length; i++) + { + raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); + } + return raw; + } - DiscUtils.Iso9660.CDReader cdr = new DiscUtils.Iso9660.CDReader(ISO, false); - Stream ParamSfo = cdr.OpenFile(@"PSP_GAME\PARAM.SFO", FileMode.Open,FileAccess.Read); + public byte[] ReadFileFromISO(string ISOFile, string FilePath) + { + try + { + FileStream ISO = File.OpenRead(ISOFile); - byte[] Sfo = new byte[ParamSfo.Length]; - ParamSfo.Read(Sfo, 0x00, (int)ParamSfo.Length); - ISO.Close(); - - return Sfo; + DiscUtils.Iso9660.CDReader cdr = new DiscUtils.Iso9660.CDReader(ISO, false); + Stream FileStr = cdr.OpenFile(FilePath, FileMode.Open, FileAccess.Read); + + byte[] FileBytes = new byte[FileStr.Length]; + FileStr.Read(FileBytes, 0x00, (int)FileStr.Length); + ISO.Close(); + + return FileBytes; + } + catch(Exception) + { + return new byte[0x00]; + } } - public byte[] GetIcon(string ISOFile) - { - FileStream ISO = File.OpenRead(ISOFile); - DiscUtils.Iso9660.CDReader cdr = new DiscUtils.Iso9660.CDReader(ISO, false); - Stream ParamSfo = cdr.OpenFile(@"PSP_GAME\ICON0.PNG", FileMode.Open, FileAccess.Read); - byte[] Icon0 = new byte[ParamSfo.Length]; - ParamSfo.Read(Icon0, 0x00, (int)ParamSfo.Length); - ISO.Close(); - - return Icon0; - - } public static string GetTitleID(string ISOFile) { FileStream ISO = File.OpenRead(ISOFile); @@ -71,6 +77,7 @@ namespace CHOVY_SIGN return isMini; } + public string ReadSetting(string Setting) { string Value = ""; @@ -218,19 +225,27 @@ namespace CHOVY_SIGN TotalProgress.Maximum = 100; Status.Text = "Overthrowing The PSPEMU Monarchy 0%"; - string BootupImage = ""; - if (isMini(ISOPath.Text)) - { - BootupImage = Path.Combine(Application.StartupPath, "_tmp", "minis.png"); - Resources.MINIS.Save(BootupImage); - } - else - { - BootupImage = Path.Combine(Application.StartupPath, "_tmp", "chovy.png"); - Resources.ChovyLogo.Save(BootupImage); - } - Process signnp = pbp.GenPbpFromIso(ISOPath.Text, EbootFile, ContentID, Versionkey.Text, CompressPBP.Checked, BootupImage); + + // Try New System + FileStream EbootStream = File.OpenWrite(EbootFile); + FileStream IsoStream = File.OpenRead(ISOPath.Text); + Bitmap BootupImage; + if (isMini(ISOPath.Text)) + BootupImage = Resources.MINIS; + else + BootupImage = Resources.ChovyLogo; + + byte[] ParamSfo = ReadFileFromISO(ISOPath.Text, @"PSP_GAME\PARAM.SFO"); + byte[] Icon0 = ReadFileFromISO(ISOPath.Text, @"PSP_GAME\ICON0.PNG"); + byte[] Icon1 = ReadFileFromISO(ISOPath.Text, @"PSP_GAME\ICON1.PMF"); + byte[] Pic0 = ReadFileFromISO(ISOPath.Text, @"PSP_GAME\PIC0.PNG"); + byte[] Pic1 = ReadFileFromISO(ISOPath.Text, @"PSP_GAME\PIC1.PNG"); + byte[] Snd0 = ReadFileFromISO(ISOPath.Text, @"PSP_GAME\SND0.AT3"); + + Pbp.BuildPbp(EbootStream, IsoStream, CompressPBP.Checked, FromHex(Versionkey.Text), BootupImage, ContentID, ParamSfo, Icon0, Icon1, Pic0, Pic1, Snd0); + + /*Process signnp = pbp.GenPbpFromIso(ISOPath.Text, EbootFile, ContentID, Versionkey.Text, CompressPBP.Checked, BootupImage); while (!signnp.HasExited) { string Progress = signnp.StandardOutput.ReadLine(); @@ -242,7 +257,7 @@ namespace CHOVY_SIGN Status.Text = "Overthrowing The PSPEMU Monarchy " + ProgressInt.ToString() + "%"; } Application.DoEvents(); - } + }*/ TotalProgress.Value = 0; Status.Text = "Signing the Declaration of Independance 0%"; @@ -250,7 +265,7 @@ namespace CHOVY_SIGN Thread thrd = new Thread(() => { - int ChovyGenRes = pbp.gen__sce_ebootpbp(EbootFile, IntAid, EbootSignature); + int ChovyGenRes = Pbp.gen__sce_ebootpbp(EbootFile, IntAid, EbootSignature); if (!File.Exists(EbootSignature) || ChovyGenRes != 0) { MessageBox.Show("CHOVY-GEN Failed! Please check CHOVY.DLL exists\nand that the Microsoft Visual C++ 2015 Redistributable Update 3 RC is installed"); @@ -369,8 +384,6 @@ namespace CHOVY_SIGN string SceSysWorkDir = Path.Combine(BackupWorkDir, "sce_sys"); Directory.CreateDirectory(SceSysWorkDir); - byte[] ParamSfo = GetSfo(ISOPath.Text); - byte[] Icon0 = GetIcon(ISOPath.Text); File.WriteAllBytes(Path.Combine(SceSysWorkDir, "param.sfo"), ParamSfo); File.WriteAllBytes(Path.Combine(SceSysWorkDir, "icon0.png"), Icon0); @@ -489,11 +502,11 @@ namespace CHOVY_SIGN PSVIMGStream LicensePsvimg = new PSVIMGStream(File.OpenRead(BackupPath), Key); PSVIMGFileStream EbootPbp = new PSVIMGFileStream(GamePsvimg, "/EBOOT.PBP"); - byte[] VersionKey = pbp.GetVersionKey(EbootPbp); + byte[] VersionKey = Pbp.GetVersionKey(EbootPbp); string VerKey = BitConverter.ToString(VersionKey).Replace("-", ""); WriteSetting("VersionKey", VerKey); - string ContentID = pbp.GetContentId(EbootPbp); + string ContentID = Pbp.GetContentId(EbootPbp); PSVIMGFileStream LicenseRif = new PSVIMGFileStream(LicensePsvimg, "/"+ ContentID+ ".rif"); byte[] LicenseRifBytes = new byte[LicenseRif.Length]; LicenseRif.Read(LicenseRifBytes, 0x00, LicenseRifBytes.Length); diff --git a/CHOVY-SIGN/DataUtils.cs b/CHOVY-SIGN/DataUtils.cs index 248d3a2..2b7ee84 100644 --- a/CHOVY-SIGN/DataUtils.cs +++ b/CHOVY-SIGN/DataUtils.cs @@ -12,7 +12,31 @@ namespace BasicDataTypes byte[] TextBytes = Encoding.UTF8.GetBytes(Text); Array.ConstrainedCopy(TextBytes, 0, str, Index, TextBytes.Length); } - + public static void CopyUInt16(byte[] str, UInt16 Value, int Index) + { + byte[] ValueBytes = BitConverter.GetBytes(Value); + Array.ConstrainedCopy(ValueBytes, 0, str, Index, ValueBytes.Length); + } + public static void CopyInt16(byte[] str, Int16 Value, int Index) + { + byte[] ValueBytes = BitConverter.GetBytes(Value); + Array.ConstrainedCopy(ValueBytes, 0, str, Index, ValueBytes.Length); + } + public static void CopyUInt64(byte[] str, UInt64 Value, int Index) + { + byte[] ValueBytes = BitConverter.GetBytes(Value); + Array.ConstrainedCopy(ValueBytes, 0, str, Index, ValueBytes.Length); + } + public static void CopyInt64(byte[] str, Int64 Value, int Index) + { + byte[] ValueBytes = BitConverter.GetBytes(Value); + Array.ConstrainedCopy(ValueBytes, 0, str, Index, ValueBytes.Length); + } + public static void CopyUInt32(byte[] str, UInt32 Value, int Index) + { + byte[] ValueBytes = BitConverter.GetBytes(Value); + Array.ConstrainedCopy(ValueBytes, 0, str, Index, ValueBytes.Length); + } public static void CopyInt32(byte[] str, Int32 Value, int Index) { byte[] ValueBytes = BitConverter.GetBytes(Value); diff --git a/CHOVY-SIGN/packages.config b/CHOVY-SIGN/packages.config deleted file mode 100644 index a96581d..0000000 --- a/CHOVY-SIGN/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CHOVY-SIGN/pbp.cs b/CHOVY-SIGN/pbp.cs index 97ad396..7c95f84 100644 --- a/CHOVY-SIGN/pbp.cs +++ b/CHOVY-SIGN/pbp.cs @@ -1,4 +1,5 @@ using BasicDataTypes; +using DiscUtils.Streams; using ParamSfo; using System; using System.Diagnostics; @@ -6,12 +7,13 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; +using System.Runtime.Remoting.Messaging; using System.Text; using System.Windows.Forms; namespace CHOVY_SIGN { - class pbp + class Pbp { unsafe struct MAC_KEY @@ -21,7 +23,13 @@ namespace CHOVY_SIGN fixed byte pad[0xF]; int pad_size; } - + unsafe struct CIPHER_KEY + { + UInt32 type; + UInt32 seed; + fixed byte key[16]; + } + const int KIRK_CMD_DECRYPT_PRIVATE = 1; const int KIRK_CMD_2 = 2; const int KIRK_CMD_3 = 3; @@ -45,21 +53,33 @@ namespace CHOVY_SIGN // PSP [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] + private unsafe static extern int lzrc_compress(byte[] outData, int out_len, byte[] inData, int in_len); + [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int kirk_init(); [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] + private unsafe static extern void encrypt_kirk16_private(byte[] dA_out, byte[] dA_dec); + [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] + private unsafe static extern void decrypt_kirk16_private(byte[] dA_out, byte[] dA_dec); + [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] + private unsafe static extern int bbmac_build_final2(int type, byte[] mac); + [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] + private unsafe static extern int bbmac_getkey(MAC_KEY* mkey, byte[] bbmac, byte[] vkey); + [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] private unsafe static extern int sceDrmBBMacInit(MAC_KEY *mkey, int type); [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] private unsafe static extern int sceDrmBBMacUpdate(MAC_KEY *mkey, byte[] buf, int size); [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] - private unsafe static extern int sceDrmBBMacFinal2(MAC_KEY* mkey, byte[] outp, byte[] vkey); + private unsafe static extern int sceDrmBBMacFinal(MAC_KEY* mkey, byte[] outp, byte[] vkey); [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] - private unsafe static extern int bbmac_getkey(MAC_KEY *mkey, byte[] bbmac, byte[] vkey); + private unsafe static extern int sceDrmBBMacFinal2(MAC_KEY* mkey, byte[] outp, byte[] vkey); [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] private unsafe static extern int sceUtilsBufferCopyWithRange(byte[] outbuff, int outsize, byte[] inbuff, int insize, int cmd); [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] - private unsafe static extern void encrypt_kirk16_private(byte[] dA_out, byte[] dA_dec); + private unsafe static extern int sceDrmBBCipherInit(CIPHER_KEY* ckey, int type, int mode, byte[] header_key, byte[] version_key, UInt32 seed); [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] - private unsafe static extern void decrypt_kirk16_private(byte[] dA_out, byte[] dA_dec); + private unsafe static extern int sceDrmBBCipherUpdate(CIPHER_KEY* ckey, byte[] data, int size); + [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] + private unsafe static extern int sceDrmBBCipherFinal(CIPHER_KEY* ckey); // PS1 [DllImport("CHOVY-KIRK.dll", CallingConvention = CallingConvention.Cdecl)] @@ -212,6 +232,10 @@ namespace CHOVY_SIGN return VERSION_KEY; } + // Normally this is dependant on if a version key is used (and thus the app is npdrm_free) + // Howevver vita does not accept npdrm_free PSP apps + const int NP_FLAGS = 0x2; + const int RATIO_LIMIT = 90; public static byte[] HashSfo(byte[] DataPspBytes, byte[] SfoBytes) { int SfoSize = SfoBytes.Length + 0x30; @@ -272,9 +296,6 @@ namespace CHOVY_SIGN public static byte[] BuildDataPsp(byte[] Startdat, string ContentId, byte[] SfoBytes) { - int NP_FLAGS = 0x2; - // Normally this is dependant on if a version key is used (and thus the app is npdrm_free) - // Howevver vita does not accept npdrm_free PSP apps int DataPspSize = 0x594; if (Startdat.Length != 0) DataPspSize += Convert.ToInt32(Startdat.Length + 0xC); @@ -334,13 +355,366 @@ namespace CHOVY_SIGN SfoStream.Dispose(); return OutputBytes; } - public static void BuildPbp(Stream str, Bitmap start_image, string content_id, byte[] param_sfo,byte[] icon0, byte[] icon1pmf, byte[] pic0, byte[] pic1, byte[] sndat3) + + public static byte[] BuildDataPsar() + { + int DataPsarSize = 0x100; + byte[] DataPsar = new byte[DataPsarSize]; + return DataPsar; + } + + unsafe public static byte[] BuildNpumdimgHeader(int iso_size, int iso_blocks, int block_basis, string content_id, int np_flags, byte[] version_key, byte[] header_key, byte[] data_key) + { + byte[] NpumdimgHeader = new byte[0x100]; // Header Size + + DataUtils.CopyString(NpumdimgHeader, "NPUMDIMG", 0); + + DataUtils.CopyInt32(NpumdimgHeader, np_flags, 0x8); + DataUtils.CopyInt32(NpumdimgHeader, block_basis, 0xC); + + DataUtils.CopyString(NpumdimgHeader, content_id, 0x10); + + // NpuimgBody + DataUtils.CopyInt16(NpumdimgHeader, 0x800, 0x40); // Sector Size + + if (iso_size > 0x40000000) + DataUtils.CopyUInt16(NpumdimgHeader, 0xE001, 0x42); + else + DataUtils.CopyUInt16(NpumdimgHeader, 0xE000, 0x42); + + DataUtils.CopyUInt32(NpumdimgHeader, 0, 0x44); + DataUtils.CopyUInt32(NpumdimgHeader, 0x1010, 0x48); + DataUtils.CopyUInt32(NpumdimgHeader, 0x0, 0x4C); + DataUtils.CopyUInt32(NpumdimgHeader, 0x0, 0x50); + DataUtils.CopyUInt32(NpumdimgHeader, 0x0, 0x54); // LBA Start + DataUtils.CopyUInt32(NpumdimgHeader, 0x0, 0x58); + + if (((iso_blocks * block_basis) - 1) > 0x6C0BF) + DataUtils.CopyInt32(NpumdimgHeader, 0x6C0BF, 0x5C); // Number of Sectors + else + DataUtils.CopyInt32(NpumdimgHeader, (iso_blocks * block_basis) - 1, 0x5C); // Number of Sectors + + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x60); + DataUtils.CopyInt32(NpumdimgHeader, (iso_blocks * block_basis) - 1, 0x64); // LBA End + DataUtils.CopyInt32(NpumdimgHeader, 0x01003FFE, 0x68); + DataUtils.CopyInt32(NpumdimgHeader, 0x100, 0x6C); // Block Entry Offset + + String DiscId = content_id.Substring(7, 4) + "-" + content_id.Substring(11, 5); + DataUtils.CopyString(NpumdimgHeader, DiscId, 0x70); // Disc Id + + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x80); // Header Start Offset + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x84); + NpumdimgHeader[0x88] = 0; + NpumdimgHeader[0x89] = 0; // bbmac param + NpumdimgHeader[0x8A] = 0; + NpumdimgHeader[0x8C] = 0; + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x8C); + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x90); + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x94); + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x98); + DataUtils.CopyInt32(NpumdimgHeader, 0x00, 0x9C); + + // NpuimgBody + + Array.ConstrainedCopy(header_key, 0, NpumdimgHeader, 0xA0, header_key.Length); + Array.ConstrainedCopy(data_key, 0, NpumdimgHeader, 0xB0, data_key.Length); + + // Generate Padding + byte[] PaddingBytes = new byte[0x8]; + sceUtilsBufferCopyWithRange(PaddingBytes, PaddingBytes.Length, null, 0, KIRK_CMD_PRNG); + Array.ConstrainedCopy(PaddingBytes, 0, NpumdimgHeader, 0xD0, PaddingBytes.Length); // Padding Area + + // Prepare buffers to encrypt the NPUMDIMG body. + MAC_KEY mck; + CIPHER_KEY bck; + + // Encrypt NPUMDIMG body. + byte[] ToEncrypt = new byte[0x60]; + Array.ConstrainedCopy(NpumdimgHeader, 0x40, ToEncrypt, 0, ToEncrypt.Length); + sceDrmBBCipherInit(&bck, 1, 2, header_key, version_key, 0); + sceDrmBBCipherUpdate(&bck, ToEncrypt, 0x60); + sceDrmBBCipherFinal(&bck); + + + // Generate header hash. + byte[] header_hash = new byte[0x10]; + + sceDrmBBMacInit(&mck, 3); + sceDrmBBMacUpdate(&mck, NpumdimgHeader, 0xC0); + sceDrmBBMacFinal(&mck, header_hash, version_key); + bbmac_build_final2(3, header_hash); + + Array.ConstrainedCopy(header_hash, 0, NpumdimgHeader, 0xC0, header_hash.Length); + + // Prepare the signature hash input buffer. + byte[] NpumdimgSha1InBuf = new byte[0xD8 + 0x4]; + byte[] NpuimgHash = new byte[0x14]; + + // Setup Hash + DataUtils.CopyInt32(NpumdimgSha1InBuf, 0xD8, 0); + Array.ConstrainedCopy(NpumdimgHeader, 0x00, NpumdimgSha1InBuf, 0x04, NpumdimgSha1InBuf.Length - 0x4); + + // Hash the input buffer. + if (sceUtilsBufferCopyWithRange(NpuimgHash, NpuimgHash.Length, NpumdimgSha1InBuf, NpumdimgSha1InBuf.Length, KIRK_CMD_SHA1_HASH) != 0) + { + throw new Exception("Failed to generate SHA1 hash for NPUMDIMG header!"); + } + + + byte[] NpumdimgSignInBuf = new byte[0x34]; + byte[] NpumdimgSignature = new byte[0x28]; + + // Create ECDSA key pair. + byte[] NpumdimgKeypair = new byte[0x3C]; + + Array.ConstrainedCopy(npumdimg_private_key, 0, NpumdimgKeypair, 0, npumdimg_private_key.Length); + Array.ConstrainedCopy(npumdimg_public_key, 0, NpumdimgKeypair, npumdimg_private_key.Length, npumdimg_public_key.Length); + + // Encrypt NPUMDIMG private key. + byte[] NpumdimgPrivateKeyEnc = new byte[0x20]; + encrypt_kirk16_private(NpumdimgPrivateKeyEnc, NpumdimgKeypair); + + // Generate ECDSA signature. + Array.ConstrainedCopy(NpumdimgPrivateKeyEnc, 0x00, NpumdimgSignInBuf, 0, NpumdimgPrivateKeyEnc.Length); + Array.ConstrainedCopy(NpuimgHash, 0x00, NpumdimgSignInBuf, NpumdimgPrivateKeyEnc.Length, NpuimgHash.Length); + if (sceUtilsBufferCopyWithRange(NpumdimgSignature, NpumdimgSignature.Length, NpumdimgSignInBuf, NpumdimgSignInBuf.Length, KIRK_CMD_ECDSA_SIGN) != 0) + { + throw new Exception("ERROR: Failed to generate ECDSA signature for NPUMDIMG header!"); + } + + // Verify the generated ECDSA signature. + byte[] TestSignature = new byte[0x64]; + Array.ConstrainedCopy(npumdimg_public_key, 0, TestSignature, 0, npumdimg_public_key.Length); + Array.ConstrainedCopy(NpuimgHash, 0, TestSignature, npumdimg_public_key.Length, NpuimgHash.Length); + Array.ConstrainedCopy(NpumdimgSignature, 0, TestSignature, npumdimg_public_key.Length + NpuimgHash.Length, NpumdimgSignature.Length); + if (sceUtilsBufferCopyWithRange(null, 0, TestSignature, 0x64, KIRK_CMD_ECDSA_VERIFY) != 0) + { + throw new Exception("ECDSA signature for NPUMDIMG header is invalid!"); + } + + // Finally put ECDSA signature into header. + Array.ConstrainedCopy(NpumdimgSignature, 0, NpumdimgHeader, 0xD8, NpumdimgSignature.Length); + + return NpumdimgSignature; + } + unsafe public static void SignIso(Stream BaseStr, Stream Iso, string ContentId, byte[] VersionKey, bool Compress) + { + MAC_KEY MKey; + CIPHER_KEY CKey; + + Int64 IsoSize = Iso.Length; + Int64 TableOffset = Convert.ToInt64(BaseStr.Position); + int BlockBasis = 0x10; + int BlockSize = BlockBasis * 2048; + Int64 IsoBlocks = (IsoSize + BlockSize - 1) / BlockSize; + Int64 TableSize = IsoBlocks * 0x20; + Int64 NpOffset = TableOffset - 0x100; + + + // Generate Random Header Key + byte[] HeaderKey = new byte[0x10]; + sceUtilsBufferCopyWithRange(HeaderKey, HeaderKey.Length, null, 0, KIRK_CMD_PRNG); + + byte[] TableBuffer = new byte[TableSize]; + BaseStr.Write(TableBuffer, 0x00, TableBuffer.Length); + + // Write ISO Blocks + byte[] IsoBuffer = new byte[BlockSize * 2]; + byte[] LZRCBuffer = new byte[BlockSize * 2]; + byte[] Tb = new byte[0x20]; + byte[] WBuf; + Int64 IsoOffset = 0x100 + TableSize; + int WSize, LZRCSize, Ratio; + int TbOffset = 0; + for (int i = 0; i < IsoBlocks; i++) + { + Array.Clear(IsoBuffer, 0, IsoBuffer.Length); + Array.Clear(LZRCBuffer, 0, IsoBuffer.Length); + Array.Clear(Tb, 0, Tb.Length); + + TbOffset = i * 0x20; + Array.ConstrainedCopy(TableBuffer, TbOffset, Tb, 0, Tb.Length); + + if ((Iso.Length + BlockSize) > IsoSize) + { + int Remaining = Convert.ToInt32(IsoSize - Iso.Length); + Iso.Read(IsoBuffer, 0x00, Remaining); + WSize = Remaining; + } + else + { + Iso.Read(IsoBuffer, 0x01, BlockSize); + WSize = BlockSize; + } + + WBuf = IsoBuffer; + + if (Compress) + { + LZRCSize = lzrc_compress(LZRCBuffer, BlockSize * 2, IsoBuffer, BlockSize); + Ratio = (LZRCSize * 100) / BlockSize; + + if (Ratio < RATIO_LIMIT) + { + WBuf = LZRCBuffer; + WSize = (LZRCSize + 15) & ~15; + } + } + + // Set table entry. + DataUtils.CopyInt32(Tb, Convert.ToInt32(IsoOffset), 0x10); + DataUtils.CopyInt32(Tb, WSize, 0x14); + DataUtils.CopyInt32(Tb, 0, 0x18); + DataUtils.CopyInt32(Tb, 0, 0x1C); + + // Encrypt Block + sceDrmBBCipherInit(&CKey, 1, 2, HeaderKey, VersionKey, Convert.ToUInt32((IsoOffset >> 4))); + sceDrmBBCipherUpdate(&CKey, WBuf, WSize); + sceDrmBBCipherFinal(&CKey); + + // Build MAC. + sceDrmBBMacInit(&MKey, 3); + sceDrmBBMacUpdate(&MKey, WBuf, WSize); + sceDrmBBMacFinal(&MKey, Tb, VersionKey); + + bbmac_build_final2(3, Tb); + + // Encrypt table. + byte[] EncTb = encrypt_table(Tb); + + // Write ISO data. + WSize = (WSize + 15) & ~15; + BaseStr.Write(WBuf, 0x00, WSize); + + // Update offset. + IsoOffset += WSize; + + // Copy TB Back + Array.ConstrainedCopy(EncTb, 0, TableBuffer, TbOffset, EncTb.Length); + + } + + // Generate data key. + byte[] DataKey = new byte[0x10]; + sceDrmBBMacInit(&MKey, 3); + sceDrmBBMacUpdate(&MKey, TableBuffer, Convert.ToInt32(TableSize)); + sceDrmBBMacFinal(&MKey, DataKey, VersionKey); + bbmac_build_final2(3, DataKey); + + byte[] NpumdimgHeader = BuildNpumdimgHeader(Convert.ToInt32(IsoSize), Convert.ToInt32(IsoBlocks), BlockBasis, ContentId, NP_FLAGS, VersionKey, HeaderKey, DataKey); + BaseStr.Seek(NpOffset, SeekOrigin.Begin); + BaseStr.Write(NpumdimgHeader, 0x00, NpumdimgHeader.Length); + BaseStr.Seek(TableOffset, SeekOrigin.Begin); + BaseStr.Write(TableBuffer, 0x00, TableBuffer.Length); + + return; + } + + public static UInt32[] ByteArrayToUint32Array(byte[] ByteArray) + { + UInt32[] decode = new UInt32[ByteArray.Length / 4]; + System.Buffer.BlockCopy(ByteArray, 0, decode, 0, ByteArray.Length); + return decode; + } + public static byte[] UInt32ArrayToByteArray(UInt32[] Uint32Array) + { + byte[] decode = new byte[Uint32Array.Length * 4]; + System.Buffer.BlockCopy(Uint32Array, 0, decode, 0, Uint32Array.Length); + return decode; + } + public static byte[] encrypt_table(byte[] table) + { + + UInt32[] p = ByteArrayToUint32Array(table); + UInt32 k0, k1, k2, k3; + + k0 = p[0] ^ p[1]; + k1 = p[1] ^ p[2]; + k2 = p[0] ^ p[3]; + k3 = p[2] ^ p[3]; + + p[4] ^= k3; + p[5] ^= k1; + p[6] ^= k2; + p[7] ^= k0; + + return UInt32ArrayToByteArray(p); + } + public static void BuildPbp(Stream Str, Stream Iso, bool Compress, byte[] VersionKey, Bitmap start_image, string content_id, byte[] param_sfo,byte[] icon0, byte[] icon1pmf, byte[] pic0, byte[] pic1, byte[] sndat3) { kirk_init(); + byte[] NewSfo = PatchSfo(param_sfo, content_id); byte[] StartData = BuildStartData(start_image); byte[] DataPsp = BuildDataPsp(StartData, content_id, NewSfo); + byte[] DataPsar = BuildDataPsar(); + + // Build Header + int PbpHeaderSize = icon0.Length + icon1pmf.Length + pic0.Length + pic1.Length + sndat3.Length + param_sfo.Length + DataPsp.Length; + Str.Seek(0x00, SeekOrigin.Begin); + Str.SetLength(PbpHeaderSize + 4096); + DataUtils.WriteInt32(Str, 0x50425000); + DataUtils.WriteInt32(Str, 0x00010001); + + int OffsetToWrite = 0x28; + // Write Sfo + Str.Seek(0x08, SeekOrigin.Begin); // SFO Offset + DataUtils.WriteInt32(Str, OffsetToWrite); + Str.Seek(OffsetToWrite, SeekOrigin.Begin); + Str.Write(NewSfo, 0x00, NewSfo.Length); + OffsetToWrite += NewSfo.Length; + + //Write Icon0 + Str.Seek(0x0C, SeekOrigin.Begin); // Icon0 Offset + DataUtils.WriteInt32(Str, OffsetToWrite); + Str.Seek(OffsetToWrite, SeekOrigin.Begin); + Str.Write(icon0, 0x00, icon0.Length); + OffsetToWrite += icon0.Length; + + + //Write Icon1 + Str.Seek(0x10, SeekOrigin.Begin); // Icon1 Offset + DataUtils.WriteInt32(Str, OffsetToWrite); + Str.Seek(OffsetToWrite, SeekOrigin.Begin); + Str.Write(icon1pmf, 0x00, icon1pmf.Length); + OffsetToWrite += icon1pmf.Length; + + //Write Pic0 + Str.Seek(0x14, SeekOrigin.Begin); // Pic0 Offset + DataUtils.WriteInt32(Str, OffsetToWrite); + Str.Seek(OffsetToWrite, SeekOrigin.Begin); + Str.Write(pic0, 0x00, pic0.Length); + OffsetToWrite += pic0.Length; + + //Write SND0 + Str.Seek(0x1C, SeekOrigin.Begin); // SND0 Offset + DataUtils.WriteInt32(Str, OffsetToWrite); + Str.Seek(OffsetToWrite, SeekOrigin.Begin); + Str.Write(sndat3, 0x00, sndat3.Length); + OffsetToWrite += sndat3.Length; + + //Write DATAPSP + Str.Seek(0x20, SeekOrigin.Begin); // DATAPSP Offset + DataUtils.WriteInt32(Str, OffsetToWrite); + Str.Seek(OffsetToWrite, SeekOrigin.Begin); + Str.Write(DataPsp, 0x00, DataPsp.Length); + OffsetToWrite += DataPsp.Length; + + // DATA.PSAR is 0x100 aligned. + OffsetToWrite = (OffsetToWrite + 15) & ~15; + while ((OffsetToWrite % 0x100) != 0) + OffsetToWrite += 0x10; + + // Write DaTAPSAR + Str.Seek(0x24, SeekOrigin.Begin); // DATAPSAR Offset + DataUtils.WriteInt32(Str, OffsetToWrite); + Str.Seek(OffsetToWrite, SeekOrigin.Begin); + Str.Write(DataPsar, 0x00, DataPsar.Length); + OffsetToWrite += DataPsar.Length; + + // Sign ISO Contents. + SignIso(Str, Iso, content_id, VersionKey, Compress); } public static int gen__sce_ebootpbp(string EbootFile, UInt64 AID, string OutSceebootpbpFile) {