From fd18b425d1b0d7f75c6dc6108c2f2709d277f937 Mon Sep 17 00:00:00 2001 From: Deterous <138427222+Deterous@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:48:40 +1300 Subject: [PATCH] Cleanup --- BuildIRD/BuildIRD.cs | 14 ++- LibIRD/IRD.cs | 187 +++++++++++++++++++------------------ LibIRD/PS3ISO.cs | 2 +- LibIRD/Utilities.cs | 63 ++++--------- PrintParams/PrintParams.cs | 2 +- 5 files changed, 128 insertions(+), 140 deletions(-) diff --git a/BuildIRD/BuildIRD.cs b/BuildIRD/BuildIRD.cs index 7a5038e..99d74f6 100644 --- a/BuildIRD/BuildIRD.cs +++ b/BuildIRD/BuildIRD.cs @@ -1,5 +1,6 @@ using LibIRD; using System; +using System.Text; namespace BuildIRD { @@ -7,12 +8,19 @@ namespace BuildIRD { static void Main() { - byte[] discKey = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + Console.OutputEncoding = Encoding.UTF8; + + // Create new reproducible redump-style IRD with a key + byte[] discKey = new byte[] { 0x1A, 0x2D, 0x88, 0xFC, 0x19, 0x37, 0x27, 0x44, 0x11, 0x5E, 0xE9, 0x83, 0xA0, 0x47, 0xE2, 0xD5 }; IRD ird1 = new ReIRD("./game.iso", discKey); - IRD ird2 = new ReIRD("./game.iso", "./log.getkey.log"); ird1.Write("./test1.ird"); + Console.WriteLine("IRD for " + ird1.Title + " created"); + + // Create new reproducible redump-style IRD with a GetKey log + string logPath = "./log.getkey.log"; + IRD ird2 = new ReIRD("./game.iso", logPath); ird2.Write("./test2.ird"); - Console.WriteLine(ird1.Title); + Console.WriteLine("IRD for " + ird2.Title + " created"); } } } diff --git a/LibIRD/IRD.cs b/LibIRD/IRD.cs index da246b9..b0cc17e 100644 --- a/LibIRD/IRD.cs +++ b/LibIRD/IRD.cs @@ -8,8 +8,9 @@ using System.Text; namespace LibIRD { /// - /// ISO Rebuild Data: Generation and writing to IRD file + /// ISO Rebuild Data /// + /// Generates IRD fields and writes to an IRD file public class IRD : PS3ISO { #region Constants @@ -18,7 +19,7 @@ namespace LibIRD /// IRD file signature /// /// "3IRD" - private static readonly byte[] Magic = new byte[] { 0x33, 0x49, 0x52, 0x44 }; + private static readonly byte[] Magic = { 0x33, 0x49, 0x52, 0x44 }; /// /// AES CBC Encryption Key for Data 1 (Disc Key) @@ -66,14 +67,16 @@ namespace LibIRD public uint UID { get; set; } = 0x00000000; // Default to zeroed UID /// - /// Extra Config, usually 0x0000 + /// Extra Config /// - public ushort ExtraConfig { get; set; } = 0x0000; + /// Reserved, usually set to 0x0000 + public ushort ExtraConfig { get; set; } = 0x0000; // Default to zero /// - /// Attachments, usually 0x0000 + /// Attachments /// - public ushort Attachments { get; set; } = 0x0000; + /// Reserved, usually set to 0x0000 + public ushort Attachments { get; set; } = 0x0000; // Default to zero /// /// D1 key @@ -139,12 +142,12 @@ namespace LibIRD private protected void GenerateD1(byte[] key) { // Validate key - if (key == null || key.Length <= 0) + if (key == null) throw new ArgumentNullException(nameof(key)); if (key.Length != 16) throw new ArgumentException("Disc Key must be a byte array of length 16", nameof(key)); - // AES decryption + // Setup AES decryption using Aes aes = Aes.Create() ?? throw new InvalidOperationException("AES not available. Change your system settings"); // Set AES settings @@ -154,14 +157,14 @@ namespace LibIRD aes.Mode = CipherMode.CBC; // Perform AES decryption - using ICryptoTransform decryptor = aes.CreateDecryptor(); - MemoryStream ms = new(); - CryptoStream cs = new(ms, decryptor, CryptoStreamMode.Write); + using MemoryStream stream = new(); + using ICryptoTransform dec = aes.CreateDecryptor(); + using CryptoStream cs = new(stream, dec, CryptoStreamMode.Write); cs.Write(key, 0, 16); cs.FlushFinalBlock(); - Data1Key = ms.ToArray(); - ms.Close(); - cs.Close(); + + // Save decrypted key to field + Data1Key = stream.ToArray(); } /// @@ -173,12 +176,12 @@ namespace LibIRD private protected void GenerateD2(byte[] id) { // Validate id - if (id == null || id.Length <= 0) + if (id == null) throw new ArgumentNullException(nameof(id)); if (id.Length != 16) throw new ArgumentException("Disc ID must be a byte array of length 16", nameof(id)); - // AES encryption + // Setup AES encryption using Aes aes = Aes.Create() ?? throw new InvalidOperationException("AES not available. Change your system settings"); // Set AES settings @@ -188,14 +191,14 @@ namespace LibIRD aes.Mode = CipherMode.CBC; // Perform AES encryption - using ICryptoTransform encryptor = aes.CreateEncryptor(); - MemoryStream ms = new(); - CryptoStream cs = new(ms, encryptor, CryptoStreamMode.Write); + using MemoryStream stream = new(); + using ICryptoTransform enc = aes.CreateEncryptor(); + using CryptoStream cs = new(stream, enc, CryptoStreamMode.Write); cs.Write(id, 0, 16); cs.FlushFinalBlock(); - Data2Key = ms.ToArray(); - ms.Close(); - cs.Close(); + + // Save encrypted key to field + Data2Key = stream.ToArray(); } #endregion @@ -207,7 +210,7 @@ namespace LibIRD /// private protected IRD(string isoPath) : base(isoPath) { - // Assumes that derived class will set private variables and generate in its own constructor + // Assumes that internally derived class will set D1/D2/PIC in its own constructor } /// @@ -228,78 +231,78 @@ namespace LibIRD /// /// Constructor that reads required fields from .getkey.log file /// - /// - /// + /// Path to the ISO + /// Path to the .getkey.log file + /// + /// public IRD(string isoPath, string getKeyLog) : base(isoPath) { // Validate .getkey.log file path - if (getKeyLog == null || !File.Exists(getKeyLog)) + if (getKeyLog == null) throw new ArgumentNullException(nameof(getKeyLog)); - - // Initialise fields - byte[] discKey; - byte[] discID; - byte[] discPIC; + if (!File.Exists(getKeyLog)) + throw new FileNotFoundException(nameof(getKeyLog)); // Read from .getkey.log file - using (var sr = File.OpenText(getKeyLog)) + using StreamReader sr = File.OpenText(getKeyLog); + + // Determine whether GetKey was successful + string line; + while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("get_dec_key succeeded!") == false) ; + if (line == null) + throw new InvalidDataException(".getkey.log contains errors"); + + // Look for Disc Key in log + byte[] discKey; + while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("disc_key = ") == false) ; + if (line == null) + throw new InvalidDataException("Could not find Disc Key in .getkey.log"); + // Get Disc Key from log + string discKeyStr = line["disc_key = ".Length..]; + // Validate Disc Key from log + if (discKeyStr.Length != 32) + throw new InvalidDataException("Unexpected Disc Key in .getkey.log"); + // Convert Disc Key to byte array + discKey = Utilities.HexToBytes(discKeyStr); + + // Read Disc ID + byte[] discID; + while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("disc_id = ") == false) ; + if (line == null) + throw new InvalidDataException("Could not find Disc ID in .getkey.log"); + // Get Disc ID from log + string discIDStr = line["disc_id = ".Length..]; + // Validate Disc ID from log + if (discIDStr.Length != 32) + throw new InvalidDataException("Unexpected Disc ID in .getkey.log"); + // Replace X's in Disc ID with 00000001 + discIDStr = discIDStr[..24] + "00000001"; + // Convert Disc ID to byte array + discID = Utilities.HexToBytes(discIDStr); + + // Look for PIC in log + byte[] discPIC; + while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("PIC:") == false) ; + if (line == null) + throw new InvalidDataException("Could not find PIC in .getkey.log"); + // Get PIC from log + string discPICStr = ""; + for (int i = 0; i < 8; i++) + discPICStr += sr.ReadLine() ?? throw new InvalidDataException("Incomplete PIC in .getkey.log"); + // Validate PIC from log + if (discPICStr.Length != 256) + throw new InvalidDataException("Unexpected PIC in .getkey.log"); + // Convert PIC to byte array + discPIC = Utilities.HexToBytes(discPICStr[..230]); + + // Double check for warnings in .getkey.log + while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("WARNING") == false && line.Trim().StartsWith("SUCCESS") == false) { - string line; - - // Determine whether GetKey was successful - while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("get_dec_key succeeded!") == false) ; - if (line == null) + string t = line.Trim(); + if (t.StartsWith("WARNING")) throw new InvalidDataException(".getkey.log contains errors"); - - // Look for Disc Key in log - while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("disc_key = ") == false) ; - if (line == null) - throw new InvalidDataException("Could not find Disc Key in .getkey.log"); - // Get Disc Key from log - string discKeyStr = line["disc_key = ".Length..]; - // Validate Disc Key from log - if (discKeyStr.Length != 32) - throw new InvalidDataException("Unexpected Disc Key in .getkey.log"); - // Convert Disc Key to byte array - discKey = Utilities.HexToBytes(discKeyStr); - - // Read Disc ID - while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("disc_id = ") == false) ; - if (line == null) - throw new InvalidDataException("Could not find Disc ID in .getkey.log"); - // Get Disc ID from log - string discIDStr = line["disc_id = ".Length..]; - // Validate Disc ID from log - if (discIDStr.Length != 32) - throw new InvalidDataException("Unexpected Disc ID in .getkey.log"); - // Replace X's in Disc ID with 00000001 - discIDStr = discIDStr[..24] + "00000001"; - // Convert Disc ID to byte array - discID = Utilities.HexToBytes(discIDStr); - - // Look for PIC in log - while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("PIC:") == false) ; - if (line == null) - throw new InvalidDataException("Could not find PIC in .getkey.log"); - // Get PIC from log - string discPICStr = ""; - for (int i = 0; i < 8; i++) - discPICStr += sr.ReadLine() ?? throw new InvalidDataException("Incomplete PIC in .getkey.log"); - // Validate PIC from log - if (discPICStr.Length != 256) - throw new InvalidDataException("Unexpected PIC in .getkey.log"); - // Convert PIC to byte array - discPIC = Utilities.HexToBytes(discPICStr[..230]); - - // Check for warnings in .getkey.log - while ((line = sr.ReadLine()) != null && line.Trim().StartsWith("WARNING") == false && line.Trim().StartsWith("SUCCESS") == false) - { - string t = line.Trim(); - if (t.StartsWith("WARNING")) - throw new InvalidDataException(".getkey.log contains errors"); - else if (t.StartsWith("SUCCESS")) - break; - } + else if (t.StartsWith("SUCCESS")) + break; } // Parse DiscKey, DiscID, and PIC @@ -315,15 +318,16 @@ namespace LibIRD /// /// Write IRD data to file /// - /// Path to IRD file to be written to + /// Path to the ISO + /// public void Write(string irdPath) { // Validate irdPath if (irdPath == null || irdPath.Length <= 0) throw new ArgumentNullException(nameof(irdPath)); - // Create new stream to write to - MemoryStream stream = new(); + // Create new stream to uncompressed IRD contents + using MemoryStream stream = new(); // Write IRD data to stream in order using (BinaryWriter bw = new(stream, Encoding.UTF8, true)) @@ -410,7 +414,7 @@ namespace LibIRD bw.Write(UID); } - // Calculate the little-endian 32-bit "IEEE 802.3" CRC value of the entire stream + // Calculate the little-endian 32-bit "IEEE 802.3" CRC value of the IRD contents so far stream.Position = 0; Crc32 crc32 = new(); crc32.Append(stream); @@ -426,7 +430,6 @@ namespace LibIRD // Write entire gzipped IRD stream to file stream.Position = 0; stream.CopyTo(gzStream); - stream.Close(); } #endregion diff --git a/LibIRD/PS3ISO.cs b/LibIRD/PS3ISO.cs index e69e4fc..cb4b138 100644 --- a/LibIRD/PS3ISO.cs +++ b/LibIRD/PS3ISO.cs @@ -195,7 +195,7 @@ namespace LibIRD RegionHashes = new byte[RegionCount][]; for (int i = 0; i < RegionCount; i++) RegionHashes[i] = NullMD5; - FileCount = 1; + FileCount = 13; FileKeys = new ulong[FileCount]; for (int i = 0; i < FileCount; i++) FileKeys[i] = (ulong)(i * 16); diff --git a/LibIRD/Utilities.cs b/LibIRD/Utilities.cs index c4d28f6..16c6915 100644 --- a/LibIRD/Utilities.cs +++ b/LibIRD/Utilities.cs @@ -5,53 +5,30 @@ namespace LibIRD internal class Utilities { // Helper function to convert a hex string to a byte array - // Source: https://codereview.stackexchange.com/a/53846 + // Original source: https://codereview.stackexchange.com/a/53846 private static int HexToInt(char c) { - switch (c) + return c switch { - case '0': - return 0; - case '1': - return 1; - case '2': - return 2; - case '3': - return 3; - case '4': - return 4; - case '5': - return 5; - case '6': - return 6; - case '7': - return 7; - case '8': - return 8; - case '9': - return 9; - case 'a': - case 'A': - return 10; - case 'b': - case 'B': - return 11; - case 'c': - case 'C': - return 12; - case 'd': - case 'D': - return 13; - case 'e': - case 'E': - return 14; - case 'f': - case 'F': - return 15; - default: - throw new FormatException("Unrecognized hex char " + c); - } + '0' => 0, + '1' => 1, + '2' => 2, + '3' => 3, + '4' => 4, + '5' => 5, + '6' => 6, + '7' => 7, + '8' => 8, + '9' => 9, + 'a' or 'A' => 10, + 'b' or 'B' => 11, + 'c' or 'C' => 12, + 'd' or 'D' => 13, + 'e' or 'E' => 14, + 'f' or 'F' => 15, + _ => throw new FormatException("Unrecognized hex char " + c), + }; } private static readonly byte[,] ByteLookup = new byte[,] diff --git a/PrintParams/PrintParams.cs b/PrintParams/PrintParams.cs index 64b4f78..3948a8c 100644 --- a/PrintParams/PrintParams.cs +++ b/PrintParams/PrintParams.cs @@ -12,7 +12,7 @@ namespace PrintParams if (File.Exists(filename)) { - ParamSFO paramSFO = new ParamSFO("./PARAM.SFO"); + ParamSFO paramSFO = new("./PARAM.SFO"); Console.WriteLine(paramSFO["TITLE_ID"]); paramSFO.Print(); }