Skip to content

Commit

Permalink
Standardize comments in 3DS
Browse files Browse the repository at this point in the history
  • Loading branch information
mnadareski committed Aug 8, 2024
1 parent 344d69c commit 96ed279
Showing 1 changed file with 79 additions and 25 deletions.
104 changes: 79 additions & 25 deletions NDecrypt.N3DS/ThreeDSTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,24 @@ private bool ProcessExtendedHeader(Cart cart,

if (cart.Partitions![partitionIndex]!.ExtendedHeaderSizeInBytes > 0)
{
// Seek to the extended header
reader.BaseStream.Seek(partitionOffset + 0x200, SeekOrigin.Begin);
writer.BaseStream.Seek(partitionOffset + 0x200, SeekOrigin.Begin);

Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");

// Create the Plain AES cipher for this partition
var cipher = CreateAESCipher(NormalKey2C[partitionIndex], cart.PlainIV(partitionIndex), decryptArgs.Encrypt);

// Process the extended header
byte[] readBytes = reader.ReadBytes(Constants.CXTExtendedDataHeaderLength);
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);

#if NET6_0_OR_GREATER
// In .NET 6.0, this operation is not picked up by the reader, so we have to force it to reload its buffer
reader.BaseStream.Seek(0, SeekOrigin.Begin);
#endif
writer.Flush();
return true;
}
Expand All @@ -289,9 +298,11 @@ private void ProcessExeFSFileEntries(Cart cart,
{
// Get required offsets
uint partitionOffsetMU = cart.Header!.PartitionsTable![partitionIndex]!.Offset;
uint exeFsOffset = cart.Partitions![partitionIndex]!.ExeFSOffsetInMediaUnits;
uint exeFsOffsetMU = cart.Partitions![partitionIndex]!.ExeFSOffsetInMediaUnits;
uint exeFsHeaderOffset = (partitionOffsetMU + exeFsOffsetMU) * cart.MediaUnitSize();
uint exeFsOffset = (partitionOffsetMU + exeFsOffsetMU + 1) * cart.MediaUnitSize();

reader.BaseStream.Seek((partitionOffsetMU + exeFsOffset) * cart.MediaUnitSize(), SeekOrigin.Begin);
reader.BaseStream.Seek(exeFsHeaderOffset, SeekOrigin.Begin);
var exefsHeader = Serializer.ReadExeFSHeader(reader);

// If the header failed to read, log and return
Expand All @@ -307,18 +318,21 @@ private void ProcessExeFSFileEntries(Cart cart,
if (fileHeader == null || !fileHeader.IsCodeBinary())
continue;

// Get MiB-aligned block count and extra byte count
uint datalenM = ((fileHeader.FileSize) / (1024 * 1024));
uint datalenB = ((fileHeader.FileSize) % (1024 * 1024));
uint ctroffset = ((fileHeader.FileOffset + cart.MediaUnitSize()) / 0x10);

// Create the ExeFS AES ciphers for this partition
byte[] exefsIVWithOffsetForHeader = AddToByteArray(cart.ExeFSIV(partitionIndex), (int)ctroffset);

var firstCipher = CreateAESCipher(NormalKey[partitionIndex], exefsIVWithOffsetForHeader, decryptArgs.Encrypt);
var secondCipher = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffsetForHeader, !decryptArgs.Encrypt);

reader.BaseStream.Seek(((partitionOffsetMU + exeFsOffset + 1) * cart.MediaUnitSize()) + fileHeader.FileOffset, SeekOrigin.Begin);
writer.BaseStream.Seek(((partitionOffsetMU + exeFsOffset + 1) * cart.MediaUnitSize()) + fileHeader.FileOffset, SeekOrigin.Begin);
// Seek to the file entry
reader.BaseStream.Seek(exeFsOffset + fileHeader.FileOffset, SeekOrigin.Begin);
writer.BaseStream.Seek(exeFsOffset + fileHeader.FileOffset, SeekOrigin.Begin);

// Process MiB-aligned data
if (datalenM > 0)
{
for (int i = 0; i < datalenM; i++)
Expand All @@ -332,6 +346,7 @@ private void ProcessExeFSFileEntries(Cart cart,
}
}

// Process additional data
if (datalenB > 0)
{
byte[] readBytes = reader.ReadBytes((int)datalenB);
Expand Down Expand Up @@ -359,14 +374,19 @@ private void ProcessExeFSFilenameTable(Cart cart,
{
// Get required offsets
uint partitionOffsetMU = cart.Header!.PartitionsTable![partitionIndex]!.Offset;
uint exeFsOffset = cart.Partitions![partitionIndex]!.ExeFSOffsetInMediaUnits;
uint exeFsOffsetMU = cart.Partitions![partitionIndex]!.ExeFSOffsetInMediaUnits;
uint exeFsHeaderOffset = (partitionOffsetMU + exeFsOffsetMU) * cart.MediaUnitSize();

reader.BaseStream.Seek((partitionOffsetMU + exeFsOffset) * cart.MediaUnitSize(), SeekOrigin.Begin);
writer.BaseStream.Seek((partitionOffsetMU + exeFsOffset) * cart.MediaUnitSize(), SeekOrigin.Begin);
// Seek to the ExeFS header
reader.BaseStream.Seek(exeFsHeaderOffset, SeekOrigin.Begin);
writer.BaseStream.Seek(exeFsHeaderOffset, SeekOrigin.Begin);

Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");

// Create the ExeFS AES cipher for this partition
var cipher = CreateAESCipher(NormalKey2C[partitionIndex], cart.ExeFSIV(partitionIndex), decryptArgs.Encrypt);

// Process the filename table
byte[] readBytes = reader.ReadBytes((int)cart.MediaUnitSize());
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);
Expand All @@ -385,25 +405,38 @@ private void ProcessExeFSFilenameTable(Cart cart,
/// <param name="partitionIndex">Index of the partition</param>
/// <param name="reader">BinaryReader representing the input stream</param>
/// <param name="writer">BinaryWriter representing the output stream</param>
private void ProcessExeFS(Cart cart,
private bool ProcessExeFS(Cart cart,
int partitionIndex,
BinaryReader reader,
BinaryWriter writer)
{
// Get required offsets
uint partitionOffsetMU = cart.Header!.PartitionsTable![partitionIndex]!.Offset;
uint exeFsOffset = cart.Partitions![partitionIndex]!.ExeFSOffsetInMediaUnits;
uint exeFsOffsetMU = cart.Partitions![partitionIndex]!.ExeFSOffsetInMediaUnits;
uint exeFsOffset = (partitionOffsetMU + exeFsOffsetMU + 1) * cart.MediaUnitSize();

int exefsSizeM = (int)((long)((cart.Partitions![partitionIndex]!.ExeFSSizeInMediaUnits - 1) * cart.MediaUnitSize()) / (1024 * 1024));
int exefsSizeB = (int)((long)((cart.Partitions![partitionIndex]!.ExeFSSizeInMediaUnits - 1) * cart.MediaUnitSize()) % (1024 * 1024));
// If the RomFS offset is 0, we log and return
if (exeFsOffsetMU == 0)
{
Console.WriteLine($"Partition {partitionIndex} RomFS: No Data... Skipping...");
return false;
}

// Get MiB-aligned block count and extra byte count
uint exeFsSize = (cart.Partitions![partitionIndex]!.ExeFSSizeInMediaUnits - 1) * cart.MediaUnitSize();
int exefsSizeM = (int)((long)exeFsSize / (1024 * 1024));
int exefsSizeB = (int)((long)exeFsSize % (1024 * 1024));
int ctroffsetE = (int)(cart.MediaUnitSize() / 0x10);

// Create the ExeFS AES cipher for this partition
byte[] exefsIVWithOffset = AddToByteArray(cart.ExeFSIV(partitionIndex), ctroffsetE);

var cipher = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffset, decryptArgs.Encrypt);

reader.BaseStream.Seek((partitionOffsetMU + exeFsOffset + 1) * cart.MediaUnitSize(), SeekOrigin.Begin);
writer.BaseStream.Seek((partitionOffsetMU + exeFsOffset + 1) * cart.MediaUnitSize(), SeekOrigin.Begin);
// Seek to the ExeFS
reader.BaseStream.Seek(exeFsOffset, SeekOrigin.Begin);
writer.BaseStream.Seek(exeFsOffset, SeekOrigin.Begin);

// Process MiB-aligned data
if (exefsSizeM > 0)
{
for (int i = 0; i < exefsSizeM; i++)
Expand All @@ -415,6 +448,8 @@ private void ProcessExeFS(Cart cart,
Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {i} / {exefsSizeM + 1} mb");
}
}

// Process additional data
if (exefsSizeB > 0)
{
byte[] readBytes = reader.ReadBytes(exefsSizeB);
Expand All @@ -424,6 +459,7 @@ private void ProcessExeFS(Cart cart,
}

Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {exefsSizeM + 1} / {exefsSizeM + 1} mb... Done!\r\n");
return true;
}

#endregion
Expand Down Expand Up @@ -468,7 +504,7 @@ private void DecryptExeFS(Cart cart,
/// <param name="reader">BinaryReader representing the input stream</param>
/// <param name="writer">BinaryWriter representing the output stream</param>
/// TODO: See how much can be extracted into a common method with Encrypt
private void DecryptRomFS(Cart cart,
private bool DecryptRomFS(Cart cart,
int partitionIndex,
BinaryReader reader,
BinaryWriter writer)
Expand All @@ -482,17 +518,22 @@ private void DecryptRomFS(Cart cart,
if (romFsOffsetMU == 0)
{
Console.WriteLine($"Partition {partitionIndex} RomFS: No Data... Skipping...");
return;
return false;
}

// Get MiB-aligned block count and extra byte count
uint romFsSize = cart.Partitions![partitionIndex]!.RomFSSizeInMediaUnits * cart.MediaUnitSize();
long romfsSizeM = (int)((long)romFsSize / (1024 * 1024));
int romfsSizeB = (int)((long)romFsSize % (1024 * 1024));

// Create the RomFS AES cipher for this partition
var cipher = CreateAESCipher(NormalKey[partitionIndex], cart.RomFSIV(partitionIndex), decryptArgs.Encrypt);

// Seek to the RomFS
reader.BaseStream.Seek(romFsOffset, SeekOrigin.Begin);
writer.BaseStream.Seek(romFsOffset, SeekOrigin.Begin);

// Process MiB-aligned data
if (romfsSizeM > 0)
{
for (int i = 0; i < romfsSizeM; i++)
Expand All @@ -504,6 +545,8 @@ private void DecryptRomFS(Cart cart,
Console.Write($"\rPartition {partitionIndex} RomFS: Decrypting: {i} / {romfsSizeM + 1} mb");
}
}

// Process additional data
if (romfsSizeB > 0)
{
byte[] readBytes = reader.ReadBytes(romfsSizeB);
Expand All @@ -513,6 +556,7 @@ private void DecryptRomFS(Cart cart,
}

Console.Write($"\rPartition {partitionIndex} RomFS: Decrypting: {romfsSizeM + 1} / {romfsSizeM + 1} mb... Done!\r\n");
return true;
}

/// <summary>
Expand All @@ -521,7 +565,7 @@ private void DecryptRomFS(Cart cart,
/// <param name="cart">Cart representing the 3DS file</param>
/// <param name="partitionIndex">Index of the partition</param>
/// <param name="writer">BinaryWriter representing the output stream</param>
private void UpdateDecryptCryptoAndMasks(Cart cart, int partitionIndex, BinaryWriter writer)
private static void UpdateDecryptCryptoAndMasks(Cart cart, int partitionIndex, BinaryWriter writer)
{
// Get required offsets
uint partitionOffsetMU = cart.Header!.PartitionsTable![partitionIndex]!.Offset;
Expand All @@ -532,8 +576,10 @@ private void UpdateDecryptCryptoAndMasks(Cart cart, int partitionIndex, BinaryWr
writer.Write((byte)CryptoMethod.Original);
writer.Flush();

// Write the new BitMasks flag
// Seek to the BitMasks location
writer.BaseStream.Seek(partitionOffset + 0x18F, SeekOrigin.Begin);

// Write the new BitMasks flag
BitMasks flag = cart.Partitions![partitionIndex]!.Flags!.BitMasks;
flag &= (BitMasks)((byte)(BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator) ^ 0xFF);
flag |= BitMasks.NoCrypto;
Expand Down Expand Up @@ -586,7 +632,7 @@ private void EncryptExeFS(Cart cart,
/// <param name="reader">BinaryReader representing the input stream</param>
/// <param name="writer">BinaryWriter representing the output stream</param>
/// TODO: See how much can be extracted into a common method with Decrypt
private void EncryptRomFS(Cart cart,
private bool EncryptRomFS(Cart cart,
int partitionIndex,
BinaryReader reader,
BinaryWriter writer)
Expand All @@ -603,9 +649,10 @@ private void EncryptRomFS(Cart cart,
if (romFsOffsetMU == 0)
{
Console.WriteLine($"Partition {partitionIndex} RomFS: No Data... Skipping...");
return;
return false;
}

// Get MiB-aligned block count and extra byte count
uint romFsSize = cart.Partitions![partitionIndex]!.RomFSSizeInMediaUnits * cart.MediaUnitSize();
long romfsSizeM = (int)((long)romFsSize / (1024 * 1024));
int romfsSizeB = (int)((long)romFsSize % (1024 * 1024));
Expand All @@ -624,10 +671,14 @@ private void EncryptRomFS(Cart cart,
}
}

// Create the RomFS AES cipher for this partition
var cipher = CreateAESCipher(NormalKey[partitionIndex], cart.RomFSIV(partitionIndex), decryptArgs.Encrypt);

// Seek to the RomFS
reader.BaseStream.Seek(romFsOffset, SeekOrigin.Begin);
writer.BaseStream.Seek(romFsOffset, SeekOrigin.Begin);

// Process MiB-aligned data
if (romfsSizeM > 0)
{
for (int i = 0; i < romfsSizeM; i++)
Expand All @@ -639,6 +690,8 @@ private void EncryptRomFS(Cart cart,
Console.Write($"\rPartition {partitionIndex} RomFS: Encrypting: {i} / {romfsSizeM + 1} mb");
}
}

// Process additional data
if (romfsSizeB > 0)
{
byte[] readBytes = reader.ReadBytes(romfsSizeB);
Expand All @@ -648,6 +701,7 @@ private void EncryptRomFS(Cart cart,
}

Console.Write($"\rPartition {partitionIndex} RomFS: Encrypting: {romfsSizeM + 1} / {romfsSizeM + 1} mb... Done!\r\n");
return true;
}

/// <summary>
Expand All @@ -669,17 +723,17 @@ private static void UpdateEncryptCryptoAndMasks(Cart cart, int partitionIndex, B
writer.BaseStream.Seek(partitionOffset + 0x18B, SeekOrigin.Begin);

// For partitions 1 and up, set crypto-method to 0x00
// If partition 0, restore crypto-method from backup flags
if (partitionIndex > 0)
writer.Write((byte)CryptoMethod.Original);

// If partition 0, restore crypto-method from backup flags
else
writer.Write((byte)backupHeader!.Flags!.CryptoMethod);

writer.Flush();

// Write the new BitMasks flag
// Seek to the BitMasks location
writer.BaseStream.Seek(partitionOffset + 0x18F, SeekOrigin.Begin);

// Write the new BitMasks flag
BitMasks flag = cart.Partitions![partitionIndex]!.Flags!.BitMasks;
flag &= (BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator | BitMasks.NoCrypto) ^ (BitMasks)0xFF;
flag |= (BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator) & backupHeader!.Flags!.BitMasks;
Expand Down

0 comments on commit 96ed279

Please sign in to comment.