This commit is contained in:
Deterous
2023-11-01 17:48:40 +13:00
parent 743f3210a3
commit fd18b425d1
5 changed files with 128 additions and 140 deletions
+11 -3
View File
@@ -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");
}
}
}
+95 -92
View File
@@ -8,8 +8,9 @@ using System.Text;
namespace LibIRD
{
/// <summary>
/// ISO Rebuild Data: Generation and writing to IRD file
/// ISO Rebuild Data
/// </summary>
/// <remarks>Generates IRD fields and writes to an IRD file</remarks>
public class IRD : PS3ISO
{
#region Constants
@@ -18,7 +19,7 @@ namespace LibIRD
/// IRD file signature
/// </summary>
/// <remarks>"3IRD"</remarks>
private static readonly byte[] Magic = new byte[] { 0x33, 0x49, 0x52, 0x44 };
private static readonly byte[] Magic = { 0x33, 0x49, 0x52, 0x44 };
/// <summary>
/// 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
/// <summary>
/// Extra Config, usually 0x0000
/// Extra Config
/// </summary>
public ushort ExtraConfig { get; set; } = 0x0000;
/// <remarks>Reserved, usually set to 0x0000</remarks>
public ushort ExtraConfig { get; set; } = 0x0000; // Default to zero
/// <summary>
/// Attachments, usually 0x0000
/// Attachments
/// </summary>
public ushort Attachments { get; set; } = 0x0000;
/// <remarks>Reserved, usually set to 0x0000</remarks>
public ushort Attachments { get; set; } = 0x0000; // Default to zero
/// <summary>
/// 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();
}
/// <summary>
@@ -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
/// </summary>
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
}
/// <summary>
@@ -228,78 +231,78 @@ namespace LibIRD
/// <summary>
/// Constructor that reads required fields from .getkey.log file
/// </summary>
/// <param name="isoPath"></param>
/// <param name="getKeyLog"></param>
/// <param name="isoPath">Path to the ISO</param>
/// <param name="getKeyLog">Path to the .getkey.log file</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="InvalidDataException"></exception>
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
/// <summary>
/// Write IRD data to file
/// </summary>
/// <param name="irdPath">Path to IRD file to be written to</param>
/// <param name="irdPath">Path to the ISO</param>
/// <exception cref="ArgumentNullException"></exception>
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
+1 -1
View File
@@ -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);
+20 -43
View File
@@ -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[,]
+1 -1
View File
@@ -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();
}