diff --git a/NDecrypt.Core/DecryptArgs.cs b/NDecrypt.Core/DecryptArgs.cs
index 6d763e0..7bade87 100644
--- a/NDecrypt.Core/DecryptArgs.cs
+++ b/NDecrypt.Core/DecryptArgs.cs
@@ -10,11 +10,6 @@ namespace NDecrypt.Core
{
#region Common Fields
- ///
- /// Flag to indicate operation
- ///
- public bool Encrypt { get; set; } = true;
-
///
/// Flag to indicate forcing the operation
///
diff --git a/NDecrypt.Core/ITool.cs b/NDecrypt.Core/ITool.cs
index 98419f5..5b09130 100644
--- a/NDecrypt.Core/ITool.cs
+++ b/NDecrypt.Core/ITool.cs
@@ -2,6 +2,16 @@
{
public interface ITool
{
- bool ProcessFile();
+ ///
+ /// Attempts to encrypt an input file
+ ///
+ /// True if the file could be encrypted, false otherwise
+ bool EncryptFile();
+
+ ///
+ /// Attempts to decrypt an input file
+ ///
+ /// True if the file could be decrypted, false otherwise
+ bool DecryptFile();
}
}
diff --git a/NDecrypt.N3DS/CIATool.cs b/NDecrypt.N3DS/CIATool.cs
index 59dfb31..f47c74d 100644
--- a/NDecrypt.N3DS/CIATool.cs
+++ b/NDecrypt.N3DS/CIATool.cs
@@ -57,10 +57,17 @@ namespace NDecrypt.N3DS
#region Common Methods
+ ///
+ public bool EncryptFile() => ProcessFile(encrypt: true);
+
+ ///
+ public bool DecryptFile() => ProcessFile(encrypt: false);
+
///
/// Process an input file given the input values
///
- public bool ProcessFile()
+ /// Indicates if the file should be encrypted or decrypted
+ private bool ProcessFile(bool encrypt)
{
// Ensure the constants are all set
if (decryptArgs.IsReady != true)
@@ -84,7 +91,7 @@ namespace NDecrypt.N3DS
}
// Process all NCCH partitions
- ProcessAllPartitions(cia, reader, writer);
+ ProcessAllPartitions(cia, encrypt, reader, writer);
return false;
}
@@ -100,9 +107,10 @@ namespace NDecrypt.N3DS
/// Process all partitions in the content file data of a CIA header
///
/// CIA representing the 3DS CIA file
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessAllPartitions(CIA cia, Stream reader, Stream writer)
+ private void ProcessAllPartitions(CIA cia, bool encrypt, Stream reader, Stream writer)
{
// Iterate over all NCCH partitions
for (int p = 0; p < cia.Partitions!.Length; p++)
@@ -111,19 +119,21 @@ namespace NDecrypt.N3DS
if (ncchHeader == null)
continue;
- ProcessPartition(p, ncchHeader, reader, writer);
+ ProcessPartition(ncchHeader, p, encrypt, reader, writer);
}
}
///
/// Process a single partition
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessPartition(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void ProcessPartition(NCCHHeader ncchHeader,
+ int partitionIndex,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -133,9 +143,9 @@ namespace NDecrypt.N3DS
Console.WriteLine($"Partition {partitionIndex} is not verified due to force flag being set.");
}
// If we're not forcing the operation, check if the 'NoCrypto' bit is set
- else if (ncchHeader.Flags!.PossblyDecrypted() ^ decryptArgs.Encrypt)
+ else if (ncchHeader.Flags!.PossblyDecrypted() ^ encrypt)
{
- Console.WriteLine($"Partition {partitionIndex}: Already " + (decryptArgs.Encrypt ? "Encrypted" : "Decrypted") + "?...");
+ Console.WriteLine($"Partition {partitionIndex}: Already " + (encrypt ? "Encrypted" : "Decrypted") + "?...");
return;
}
@@ -143,24 +153,24 @@ namespace NDecrypt.N3DS
var tableEntry = new PartitionTableEntry();
// Determine the Keys to be used
- SetEncryptionKeys(partitionIndex, ncchHeader);
+ SetEncryptionKeys(ncchHeader, partitionIndex, encrypt);
// Process the extended header
- ProcessExtendedHeader(partitionIndex, ncchHeader, tableEntry, reader, writer);
+ ProcessExtendedHeader(ncchHeader, partitionIndex, tableEntry, encrypt, reader, writer);
// If we're encrypting, encrypt the filesystems and update the flags
- if (decryptArgs.Encrypt)
+ if (encrypt)
{
- EncryptExeFS(partitionIndex, ncchHeader, tableEntry, reader, writer);
- EncryptRomFS(partitionIndex, ncchHeader, tableEntry, reader, writer);
- UpdateEncryptCryptoAndMasks(partitionIndex, ncchHeader, tableEntry, writer);
+ EncryptExeFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
+ EncryptRomFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
+ UpdateEncryptCryptoAndMasks(ncchHeader, partitionIndex, tableEntry, writer);
}
// If we're decrypting, decrypt the filesystems and update the flags
else
{
- DecryptExeFS(partitionIndex, ncchHeader, tableEntry, reader, writer);
- DecryptRomFS(partitionIndex, ncchHeader, tableEntry, reader, writer);
+ DecryptExeFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
+ DecryptRomFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
UpdateDecryptCryptoAndMasks(ncchHeader, tableEntry, writer);
}
}
@@ -168,9 +178,10 @@ namespace NDecrypt.N3DS
///
/// Determine the set of keys to be used for encryption or decryption
///
- /// Index of the partition
/// NCCH header representing the partition
- private void SetEncryptionKeys(int partitionIndex, NCCHHeader ncchHeader)
+ /// Index of the partition
+ /// Indicates if the file should be encrypted or decrypted
+ private void SetEncryptionKeys(NCCHHeader ncchHeader, int partitionIndex, bool encrypt)
{
KeyX[partitionIndex] = 0;
KeyX2C[partitionIndex] = decryptArgs.Development ? decryptArgs.DevKeyX0x2C : decryptArgs.KeyX0x2C;
@@ -188,7 +199,7 @@ namespace NDecrypt.N3DS
// Set the header to use based on mode
BitMasks masks = BitMasks.NoCrypto;
CryptoMethod method = CryptoMethod.Original;
- if (decryptArgs.Encrypt)
+ if (encrypt)
{
// TODO: Can we actually re-encrypt a CIA?
//masks = ciaHeader.BackupHeader.Flags.BitMasks;
@@ -236,14 +247,16 @@ namespace NDecrypt.N3DS
///
/// Process the extended header, if it exists
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private bool ProcessExtendedHeader(int partitionIndex,
- NCCHHeader ncchHeader,
+ private bool ProcessExtendedHeader(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -255,9 +268,9 @@ namespace NDecrypt.N3DS
reader.Seek((tableEntry.Offset * mediaUnitSize) + 0x200, SeekOrigin.Begin);
writer.Seek((tableEntry.Offset * mediaUnitSize) + 0x200, SeekOrigin.Begin);
- Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");
+ Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");
- var cipher = CreateAESCipher(NormalKey2C[partitionIndex], ncchHeader.PlainIV(), decryptArgs.Encrypt);
+ var cipher = CreateAESCipher(NormalKey2C[partitionIndex], ncchHeader.PlainIV(), encrypt);
writer.Write(cipher.ProcessBytes(reader.ReadBytes(Constants.CXTExtendedDataHeaderLength)));
writer.Flush();
return true;
@@ -272,14 +285,16 @@ namespace NDecrypt.N3DS
///
/// Process the extended header, if it exists
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessExeFSFileEntries(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void ProcessExeFSFileEntries(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -308,8 +323,8 @@ namespace NDecrypt.N3DS
byte[] exefsIVWithOffsetForHeader = AddToByteArray(ncchHeader.ExeFSIV(), (int)ctroffset);
- var firstCipher = CreateAESCipher(NormalKey[partitionIndex], exefsIVWithOffsetForHeader, decryptArgs.Encrypt);
- var secondCipher = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffsetForHeader, !decryptArgs.Encrypt);
+ var firstCipher = CreateAESCipher(NormalKey[partitionIndex], exefsIVWithOffsetForHeader, encrypt);
+ var secondCipher = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffsetForHeader, !encrypt);
reader.Seek((((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) + 1) * mediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);
writer.Seek((((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) + 1) * mediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);
@@ -320,7 +335,7 @@ namespace NDecrypt.N3DS
{
writer.Write(secondCipher.ProcessBytes(firstCipher.ProcessBytes(reader.ReadBytes(1024 * 1024))));
writer.Flush();
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {i} / {datalenM + 1} mb...");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {i} / {datalenM + 1} mb...");
}
}
@@ -330,21 +345,23 @@ namespace NDecrypt.N3DS
writer.Flush();
}
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {datalenM + 1} / {datalenM + 1} mb... Done!\r\n");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {datalenM + 1} / {datalenM + 1} mb... Done!\r\n");
}
}
///
/// Process the ExeFS Filename Table
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessExeFSFilenameTable(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void ProcessExeFSFilenameTable(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -354,9 +371,9 @@ namespace NDecrypt.N3DS
reader.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
writer.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
- Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");
+ Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");
- var exeFSFilenameTable = CreateAESCipher(NormalKey2C[partitionIndex], ncchHeader.ExeFSIV(), decryptArgs.Encrypt);
+ var exeFSFilenameTable = CreateAESCipher(NormalKey2C[partitionIndex], ncchHeader.ExeFSIV(), encrypt);
writer.Write(exeFSFilenameTable.ProcessBytes(reader.ReadBytes((int)mediaUnitSize)));
writer.Flush();
}
@@ -364,14 +381,16 @@ namespace NDecrypt.N3DS
///
/// Process the ExeFS, if it exists
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessExeFS(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void ProcessExeFS(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -384,7 +403,7 @@ namespace NDecrypt.N3DS
byte[] exefsIVWithOffset = AddToByteArray(ncchHeader.ExeFSIV(), ctroffsetE);
- var exeFS = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffset, decryptArgs.Encrypt);
+ var exeFS = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffset, encrypt);
reader.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * mediaUnitSize, SeekOrigin.Begin);
writer.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * mediaUnitSize, SeekOrigin.Begin);
@@ -394,7 +413,7 @@ namespace NDecrypt.N3DS
{
writer.Write(exeFS.ProcessBytes(reader.ReadBytes(1024 * 1024)));
writer.Flush();
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {i} / {exefsSizeM + 1} mb");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {i} / {exefsSizeM + 1} mb");
}
}
if (exefsSizeB > 0)
@@ -403,7 +422,7 @@ namespace NDecrypt.N3DS
writer.Flush();
}
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {exefsSizeM + 1} / {exefsSizeM + 1} mb... Done!\r\n");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {exefsSizeM + 1} / {exefsSizeM + 1} mb... Done!\r\n");
}
#endregion
@@ -413,13 +432,13 @@ namespace NDecrypt.N3DS
///
/// Decrypt the ExeFS, if it exists
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
/// Stream representing the input
/// Stream representing the output
- private void DecryptExeFS(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void DecryptExeFS(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
Stream reader,
Stream writer)
@@ -432,27 +451,27 @@ namespace NDecrypt.N3DS
}
// Decrypt the filename table
- ProcessExeFSFilenameTable(partitionIndex, ncchHeader, tableEntry, reader, writer);
+ ProcessExeFSFilenameTable(ncchHeader, partitionIndex, tableEntry, encrypt: false, reader, writer);
// For all but the original crypto method, process each of the files in the table
if (ncchHeader.Flags!.CryptoMethod != CryptoMethod.Original)
- ProcessExeFSFileEntries(partitionIndex, ncchHeader, tableEntry, reader, writer);
+ ProcessExeFSFileEntries(ncchHeader, partitionIndex, tableEntry, encrypt: false, reader, writer);
// Decrypt the rest of the ExeFS
- ProcessExeFS(partitionIndex, ncchHeader, tableEntry, reader, writer);
+ ProcessExeFS(ncchHeader, partitionIndex, tableEntry, encrypt: false, reader, writer);
}
///
/// Decrypt the RomFS, if it exists
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
/// Stream representing the input
/// Stream representing the output
/// TODO: See how much can be extracted into a common method with Encrypt
- private void DecryptRomFS(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void DecryptRomFS(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
Stream reader,
Stream writer)
@@ -470,7 +489,7 @@ namespace NDecrypt.N3DS
long romfsSizeM = (int)((long)(ncchHeader.RomFSSizeInMediaUnits * mediaUnitSize) / (1024 * 1024));
int romfsSizeB = (int)((long)(ncchHeader.RomFSSizeInMediaUnits * mediaUnitSize) % (1024 * 1024));
- var cipher = CreateAESCipher(NormalKey[partitionIndex], ncchHeader.RomFSIV(), decryptArgs.Encrypt);
+ var cipher = CreateAESCipher(NormalKey[partitionIndex], ncchHeader.RomFSIV(), encrypt: false);
reader.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
writer.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
@@ -526,13 +545,13 @@ namespace NDecrypt.N3DS
///
/// Encrypt the ExeFS, if it exists
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
/// Stream representing the input
/// Stream representing the output
- private void EncryptExeFS(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void EncryptExeFS(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
Stream reader,
Stream writer)
@@ -550,23 +569,23 @@ namespace NDecrypt.N3DS
// ProcessExeFSFileEntries(ncchHeader, reader, writer);
// Encrypt the filename table
- ProcessExeFSFilenameTable(partitionIndex, ncchHeader, tableEntry, reader, writer);
+ ProcessExeFSFilenameTable(ncchHeader, partitionIndex, tableEntry, encrypt: true, reader, writer);
// Encrypt the rest of the ExeFS
- ProcessExeFS(partitionIndex, ncchHeader, tableEntry, reader, writer);
+ ProcessExeFS(ncchHeader, partitionIndex, tableEntry, encrypt: true, reader, writer);
}
///
/// Encrypt the RomFS, if it exists
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
/// Stream representing the input
/// Stream representing the output
/// TODO: See how much can be extracted into a common method with Decrypt
- private void EncryptRomFS(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void EncryptRomFS(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
Stream reader,
Stream writer)
@@ -599,7 +618,7 @@ namespace NDecrypt.N3DS
//}
}
- var cipher = CreateAESCipher(NormalKey[partitionIndex], ncchHeader.RomFSIV(), decryptArgs.Encrypt);
+ var cipher = CreateAESCipher(NormalKey[partitionIndex], ncchHeader.RomFSIV(), encrypt: true);
reader.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
writer.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
@@ -624,12 +643,12 @@ namespace NDecrypt.N3DS
///
/// Update the CryptoMethod and BitMasks for the encrypted partition
///
- /// Index of the partition
/// NCCH header representing the partition
+ /// Index of the partition
/// PartitionTableEntry header representing the partition
/// Stream representing the output
- private void UpdateEncryptCryptoAndMasks(int partitionIndex,
- NCCHHeader ncchHeader,
+ private void UpdateEncryptCryptoAndMasks(NCCHHeader ncchHeader,
+ int partitionIndex,
PartitionTableEntry tableEntry,
Stream writer)
{
diff --git a/NDecrypt.N3DS/ThreeDSTool.cs b/NDecrypt.N3DS/ThreeDSTool.cs
index 57a608e..7e1a786 100644
--- a/NDecrypt.N3DS/ThreeDSTool.cs
+++ b/NDecrypt.N3DS/ThreeDSTool.cs
@@ -55,10 +55,17 @@ namespace NDecrypt.N3DS
#region Common Methods
+ ///
+ public bool EncryptFile() => ProcessFile(encrypt: true);
+
+ ///
+ public bool DecryptFile() => ProcessFile(encrypt: false);
+
///
/// Process an input file given the input values
///
- public bool ProcessFile()
+ /// Indicates if the file should be encrypted or decrypted
+ private bool ProcessFile(bool encrypt)
{
// Ensure the constants are all set
if (decryptArgs.IsReady != true)
@@ -82,7 +89,7 @@ namespace NDecrypt.N3DS
}
// Process all 8 NCCH partitions
- ProcessAllPartitions(cart, reader, writer);
+ ProcessAllPartitions(cart, encrypt, reader, writer);
return true;
}
@@ -98,9 +105,10 @@ namespace NDecrypt.N3DS
/// Process all partitions in the partition table of an NCSD header
///
/// Cart representing the 3DS file
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessAllPartitions(Cart cart, Stream reader, Stream writer)
+ private void ProcessAllPartitions(Cart cart, bool encrypt, Stream reader, Stream writer)
{
// Check the partitions table
if (cart.Header?.PartitionsTable == null)
@@ -119,7 +127,7 @@ namespace NDecrypt.N3DS
continue;
}
- ProcessPartition(cart, partitionIndex, reader, writer);
+ ProcessPartition(cart, partitionIndex, encrypt, reader, writer);
}
}
@@ -128,10 +136,12 @@ namespace NDecrypt.N3DS
///
/// Cart representing the 3DS file
/// Index of the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
private void ProcessPartition(Cart cart,
int partitionIndex,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -141,20 +151,20 @@ namespace NDecrypt.N3DS
Console.WriteLine($"Partition {partitionIndex} is not verified due to force flag being set.");
}
// If we're not forcing the operation, check if the 'NoCrypto' bit is set
- else if (cart.Partitions![partitionIndex]!.Flags!.PossblyDecrypted() ^ decryptArgs.Encrypt)
+ else if (cart.Partitions![partitionIndex]!.Flags!.PossblyDecrypted() ^ encrypt)
{
- Console.WriteLine($"Partition {partitionIndex}: Already " + (decryptArgs.Encrypt ? "Encrypted" : "Decrypted") + "?...");
+ Console.WriteLine($"Partition {partitionIndex}: Already " + (encrypt ? "Encrypted" : "Decrypted") + "?...");
return;
}
// Determine the Keys to be used
- SetEncryptionKeys(cart, partitionIndex);
+ SetEncryptionKeys(cart, partitionIndex, encrypt);
// Process the extended header
- ProcessExtendedHeader(cart, partitionIndex, reader, writer);
+ ProcessExtendedHeader(cart, partitionIndex, encrypt, reader, writer);
// If we're encrypting, encrypt the filesystems and update the flags
- if (decryptArgs.Encrypt)
+ if (encrypt)
{
EncryptExeFS(cart, partitionIndex, reader, writer);
EncryptRomFS(cart, partitionIndex, reader, writer);
@@ -175,7 +185,8 @@ namespace NDecrypt.N3DS
///
/// Cart representing the 3DS file
/// Index of the partition
- private void SetEncryptionKeys(Cart cart, int partitionIndex)
+ /// Indicates if the file should be encrypted or decrypted
+ private void SetEncryptionKeys(Cart cart, int partitionIndex, bool encrypt)
{
// Get the backup header
var backupHeader = cart.CardInfoHeader!.InitialData!.BackupHeader;
@@ -196,7 +207,7 @@ namespace NDecrypt.N3DS
// Set the header to use based on mode
BitMasks masks;
CryptoMethod method;
- if (decryptArgs.Encrypt)
+ if (encrypt)
{
masks = backupHeader!.Flags!.BitMasks;
method = backupHeader.Flags.CryptoMethod;
@@ -245,10 +256,12 @@ namespace NDecrypt.N3DS
///
/// Cart representing the 3DS file
/// Index of the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
private bool ProcessExtendedHeader(Cart cart,
int partitionIndex,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -262,10 +275,10 @@ namespace NDecrypt.N3DS
reader.Seek(partitionOffset + 0x200, SeekOrigin.Begin);
writer.Seek(partitionOffset + 0x200, SeekOrigin.Begin);
- Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");
+ Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");
// Create the Plain AES cipher for this partition
- var cipher = CreateAESCipher(NormalKey2C[partitionIndex], cart.PlainIV(partitionIndex), decryptArgs.Encrypt);
+ var cipher = CreateAESCipher(NormalKey2C[partitionIndex], cart.PlainIV(partitionIndex), encrypt);
// Process the extended header
byte[] readBytes = reader.ReadBytes(Constants.CXTExtendedDataHeaderLength);
@@ -290,11 +303,13 @@ namespace NDecrypt.N3DS
/// Process the extended header, if it exists
///
/// Cart representing the 3DS file
- /// PartitionTableEntry header representing the partition
+ /// Index of the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
private void ProcessExeFSFileEntries(Cart cart,
int partitionIndex,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -327,8 +342,8 @@ namespace NDecrypt.N3DS
// 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);
+ var firstCipher = CreateAESCipher(NormalKey[partitionIndex], exefsIVWithOffsetForHeader, encrypt);
+ var secondCipher = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffsetForHeader, !encrypt);
// Seek to the file entry
reader.Seek(exeFsOffset + fileHeader.FileOffset, SeekOrigin.Begin);
@@ -344,7 +359,7 @@ namespace NDecrypt.N3DS
byte[] secondProcessedBytes = secondCipher.ProcessBytes(firstProcessedBytes);
writer.Write(secondProcessedBytes);
writer.Flush();
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {i} / {datalenM + 1} mb...");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {i} / {datalenM + 1} mb...");
}
}
@@ -358,7 +373,7 @@ namespace NDecrypt.N3DS
writer.Flush();
}
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {datalenM + 1} / {datalenM + 1} mb... Done!\r\n");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {datalenM + 1} / {datalenM + 1} mb... Done!\r\n");
}
}
@@ -367,10 +382,12 @@ namespace NDecrypt.N3DS
///
/// Cart representing the 3DS file
/// Index of the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
private void ProcessExeFSFilenameTable(Cart cart,
int partitionIndex,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -383,10 +400,10 @@ namespace NDecrypt.N3DS
reader.Seek(exeFsHeaderOffset, SeekOrigin.Begin);
writer.Seek(exeFsHeaderOffset, SeekOrigin.Begin);
- Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");
+ Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");
// Create the ExeFS AES cipher for this partition
- var cipher = CreateAESCipher(NormalKey2C[partitionIndex], cart.ExeFSIV(partitionIndex), decryptArgs.Encrypt);
+ var cipher = CreateAESCipher(NormalKey2C[partitionIndex], cart.ExeFSIV(partitionIndex), encrypt);
// Process the filename table
byte[] readBytes = reader.ReadBytes((int)cart.MediaUnitSize());
@@ -405,10 +422,12 @@ namespace NDecrypt.N3DS
///
/// Cart representing the 3DS file
/// Index of the partition
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
private bool ProcessExeFS(Cart cart,
int partitionIndex,
+ bool encrypt,
Stream reader,
Stream writer)
{
@@ -432,7 +451,7 @@ namespace NDecrypt.N3DS
// Create the ExeFS AES cipher for this partition
byte[] exefsIVWithOffset = AddToByteArray(cart.ExeFSIV(partitionIndex), ctroffsetE);
- var cipher = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffset, decryptArgs.Encrypt);
+ var cipher = CreateAESCipher(NormalKey2C[partitionIndex], exefsIVWithOffset, encrypt);
// Seek to the ExeFS
reader.Seek(exeFsOffset, SeekOrigin.Begin);
@@ -447,7 +466,7 @@ namespace NDecrypt.N3DS
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);
writer.Flush();
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {i} / {exefsSizeM + 1} mb");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {i} / {exefsSizeM + 1} mb");
}
}
@@ -460,7 +479,7 @@ namespace NDecrypt.N3DS
writer.Flush();
}
- Console.Write($"\rPartition {partitionIndex} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {exefsSizeM + 1} / {exefsSizeM + 1} mb... Done!\r\n");
+ Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {exefsSizeM + 1} / {exefsSizeM + 1} mb... Done!\r\n");
return true;
}
@@ -488,14 +507,14 @@ namespace NDecrypt.N3DS
}
// Decrypt the filename table
- ProcessExeFSFilenameTable(cart, partitionIndex, reader, writer);
+ ProcessExeFSFilenameTable(cart, partitionIndex, encrypt: false, reader, writer);
// For all but the original crypto method, process each of the files in the table
if (cart.Partitions![partitionIndex]!.Flags!.CryptoMethod != CryptoMethod.Original)
- ProcessExeFSFileEntries(cart, partitionIndex, reader, writer);
+ ProcessExeFSFileEntries(cart, partitionIndex, encrypt: false, reader, writer);
// Decrypt the rest of the ExeFS
- ProcessExeFS(cart, partitionIndex, reader, writer);
+ ProcessExeFS(cart, partitionIndex, encrypt: false, reader, writer);
}
///
@@ -529,7 +548,7 @@ namespace NDecrypt.N3DS
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);
+ var cipher = CreateAESCipher(NormalKey[partitionIndex], cart.RomFSIV(partitionIndex), encrypt: false);
// Seek to the RomFS
reader.Seek(romFsOffset, SeekOrigin.Begin);
@@ -619,13 +638,13 @@ namespace NDecrypt.N3DS
// For all but the original crypto method, process each of the files in the table
if (backupHeader!.Flags!.CryptoMethod != CryptoMethod.Original)
- ProcessExeFSFileEntries(cart, partitionIndex, reader, writer);
+ ProcessExeFSFileEntries(cart, partitionIndex, encrypt: true, reader, writer);
// Encrypt the filename table
- ProcessExeFSFilenameTable(cart, partitionIndex, reader, writer);
+ ProcessExeFSFilenameTable(cart, partitionIndex, encrypt: true, reader, writer);
// Encrypt the rest of the ExeFS
- ProcessExeFS(cart, partitionIndex, reader, writer);
+ ProcessExeFS(cart, partitionIndex, encrypt: true, reader, writer);
}
///
@@ -677,7 +696,7 @@ namespace NDecrypt.N3DS
}
// Create the RomFS AES cipher for this partition
- var cipher = CreateAESCipher(NormalKey[partitionIndex], cart.RomFSIV(partitionIndex), decryptArgs.Encrypt);
+ var cipher = CreateAESCipher(NormalKey[partitionIndex], cart.RomFSIV(partitionIndex), encrypt: true);
// Seek to the RomFS
reader.Seek(romFsOffset, SeekOrigin.Begin);
diff --git a/NDecrypt.Nitro/DSTool.cs b/NDecrypt.Nitro/DSTool.cs
index f72974e..36a92f3 100644
--- a/NDecrypt.Nitro/DSTool.cs
+++ b/NDecrypt.Nitro/DSTool.cs
@@ -33,10 +33,17 @@ namespace NDecrypt.Nitro
this.decryptArgs = decryptArgs;
}
+ ///
+ public bool EncryptFile() => ProcessFile(encrypt: true);
+
+ ///
+ public bool DecryptFile() => ProcessFile(encrypt: false);
+
///
/// Process an input file given the input values
///
- public bool ProcessFile()
+ /// Indicates if the file should be encrypted or decrypted
+ private bool ProcessFile(bool encrypt)
{
try
{
@@ -53,7 +60,7 @@ namespace NDecrypt.Nitro
}
// Process the secure area
- ProcessSecureArea(cart, reader, writer);
+ ProcessSecureArea(cart, encrypt, reader, writer);
return true;
}
@@ -69,9 +76,10 @@ namespace NDecrypt.Nitro
/// Process secure area in the DS/DSi file
/// s
/// Cart representing the DS file
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessSecureArea(Cart cart, Stream reader, Stream writer)
+ private void ProcessSecureArea(Cart cart, bool encrypt, Stream reader, Stream writer)
{
// If we're forcing the operation, tell the user
if (decryptArgs.Force)
@@ -87,16 +95,16 @@ namespace NDecrypt.Nitro
Console.WriteLine("File has an empty secure area, cannot proceed");
return;
}
- else if (decryptArgs.Encrypt ^ isDecrypted.Value)
+ else if (encrypt ^ isDecrypted.Value)
{
- Console.WriteLine("File is already " + (decryptArgs.Encrypt ? "encrypted" : "decrypted"));
+ Console.WriteLine("File is already " + (encrypt ? "encrypted" : "decrypted"));
return;
}
}
- ProcessARM9(cart.CommonHeader!, reader, writer);
+ ProcessARM9(cart.CommonHeader!, encrypt, reader, writer);
- Console.WriteLine("File has been " + (decryptArgs.Encrypt ? "encrypted" : "decrypted"));
+ Console.WriteLine("File has been " + (encrypt ? "encrypted" : "decrypted"));
}
///
@@ -162,9 +170,10 @@ namespace NDecrypt.Nitro
/// Process the secure ARM9 region of the file, if possible
///
/// CommonHeader representing the DS header
+ /// Indicates if the file should be encrypted or decrypted
/// Stream representing the input
/// Stream representing the output
- private void ProcessARM9(CommonHeader commonHeader, Stream reader, Stream writer)
+ private void ProcessARM9(CommonHeader commonHeader, bool encrypt, Stream reader, Stream writer)
{
// Seek to the beginning of the secure area
reader.Seek(0x4000, SeekOrigin.Begin);
@@ -176,13 +185,13 @@ namespace NDecrypt.Nitro
// Perform the initialization steps
Init1(commonHeader);
- if (!decryptArgs.Encrypt) Decrypt(ref p1, ref p0);
+ if (!encrypt) Decrypt(ref p1, ref p0);
_arg2[1] <<= 1;
_arg2[2] >>= 1;
Init2();
// If we're decrypting, set the proper flags
- if (!decryptArgs.Encrypt)
+ if (!encrypt)
{
Decrypt(ref p1, ref p0);
if (p0 == Constants.MAGIC30 && p1 == Constants.MAGIC34)
@@ -206,7 +215,7 @@ namespace NDecrypt.Nitro
p0 = reader.ReadUInt32();
p1 = reader.ReadUInt32();
- if (decryptArgs.Encrypt)
+ if (encrypt)
Encrypt(ref p1, ref p0);
else
Decrypt(ref p1, ref p0);
@@ -218,7 +227,7 @@ namespace NDecrypt.Nitro
}
// Replace the header explicitly if we're encrypting
- if (decryptArgs.Encrypt)
+ if (encrypt)
{
reader.Seek(0x4000, SeekOrigin.Begin);
writer.Seek(0x4000, SeekOrigin.Begin);
diff --git a/NDecrypt/Program.cs b/NDecrypt/Program.cs
index 0645cf6..77c7147 100644
--- a/NDecrypt/Program.cs
+++ b/NDecrypt/Program.cs
@@ -30,14 +30,15 @@ namespace NDecrypt
return;
}
+ bool encrypt;
var decryptArgs = new DecryptArgs();
if (args[0] == "decrypt" || args[0] == "d")
{
- decryptArgs.Encrypt = false;
+ encrypt = false;
}
else if (args[0] == "encrypt" || args[0] == "e")
{
- decryptArgs.Encrypt = true;
+ encrypt = true;
}
else
{
@@ -113,13 +114,13 @@ namespace NDecrypt
{
if (File.Exists(args[i]))
{
- ProcessPath(args[i], decryptArgs, outputHashes);
+ ProcessPath(args[i], encrypt, decryptArgs, outputHashes);
}
else if (Directory.Exists(args[i]))
{
foreach (string file in Directory.EnumerateFiles(args[i], "*", SearchOption.AllDirectories))
{
- ProcessPath(file, decryptArgs, outputHashes);
+ ProcessPath(file, encrypt, decryptArgs, outputHashes);
}
}
else
@@ -133,15 +134,29 @@ namespace NDecrypt
/// Display a basic help text
///
/// Path to the file to process
+ /// Indicates if the file should be encrypted or decrypted
/// DecryptArgs to use during processing
/// True to write out a hashfile, false otherwise
- private static void ProcessPath(string path, DecryptArgs decryptArgs, bool outputHashes)
+ private static void ProcessPath(string path, bool encrypt, DecryptArgs decryptArgs, bool outputHashes)
{
Console.WriteLine(path);
+
ITool? tool = DeriveTool(path, decryptArgs);
- if (tool?.ProcessFile() != true)
- Console.WriteLine("Processing failed!");
- else if (outputHashes)
+ if (tool == null)
+ return;
+
+ if (encrypt && !tool.EncryptFile())
+ {
+ Console.WriteLine("Encryption failed!");
+ return;
+ }
+ else if (!encrypt && !tool.DecryptFile())
+ {
+ Console.WriteLine("Decryption failed!");
+ return;
+ }
+
+ if (outputHashes)
WriteHashes(path);
}