diff --git a/NDecrypt.N3DS/CIATool.cs b/NDecrypt.N3DS/CIATool.cs
index c822d31..0355f7c 100644
--- a/NDecrypt.N3DS/CIATool.cs
+++ b/NDecrypt.N3DS/CIATool.cs
@@ -25,29 +25,9 @@ namespace NDecrypt.N3DS
private readonly bool _development;
///
- /// Set of all KeyX values
+ /// Set of all partition keys
///
- private readonly BigInteger[] KeyXMap = new BigInteger[8];
-
- ///
- /// Set of all KeyX2C values
- ///
- private readonly BigInteger[] KeyX2CMap = new BigInteger[8];
-
- ///
- /// Set of all KeyY values
- ///
- private readonly BigInteger[] KeyYMap = new BigInteger[8];
-
- ///
- /// Set of all KeyY values
- ///
- private readonly BigInteger[] NormalKeyMap = new BigInteger[8];
-
- ///
- /// Set of all KeyY values
- ///
- private readonly BigInteger[] NormalKey2CMap = new BigInteger[8];
+ private readonly PartitionKeys[] KeysMap = new PartitionKeys[8];
public CIATool(bool development, DecryptArgs decryptArgs)
{
@@ -82,11 +62,11 @@ namespace NDecrypt.N3DS
try
{
// Open the read and write on the same file for inplace processing
- using var reader = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- using var writer = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
+ using var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ using var output = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
// Deserialize the CIA information
- var cia = ReadCIA(reader);
+ var cia = ReadCIA(input);
if (cia == null)
{
Console.WriteLine("Error: Not a 3DS CIA!");
@@ -94,7 +74,7 @@ namespace NDecrypt.N3DS
}
// Process all NCCH partitions
- ProcessAllPartitions(cia, encrypt, force, reader, writer);
+ ProcessAllPartitions(cia, encrypt, force, input, output);
return false;
}
@@ -112,13 +92,13 @@ namespace NDecrypt.N3DS
/// CIA representing the 3DS CIA file
/// Indicates if the file should be encrypted or decrypted
/// Indicates if the operation should be forced
- /// Stream representing the input
- /// Stream representing the output
+ /// Stream representing the input
+ /// Stream representing the output
private void ProcessAllPartitions(CIA cia,
bool encrypt,
bool force,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// Iterate over all NCCH partitions
for (int p = 0; p < cia.Partitions!.Length; p++)
@@ -127,7 +107,7 @@ namespace NDecrypt.N3DS
if (ncchHeader == null)
continue;
- ProcessPartition(ncchHeader, p, encrypt, force, reader, writer);
+ ProcessPartition(ncchHeader, p, encrypt, force, input, output);
}
}
@@ -138,14 +118,14 @@ namespace NDecrypt.N3DS
/// Index of the partition
/// Indicates if the file should be encrypted or decrypted
/// Indicates if the operation should be forced
- /// Stream representing the input
- /// Stream representing the output
+ /// Stream representing the input
+ /// Stream representing the output
private void ProcessPartition(NCCHHeader ncchHeader,
int partitionIndex,
bool encrypt,
bool force,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// If we're forcing the operation, tell the user
if (force)
@@ -166,22 +146,22 @@ namespace NDecrypt.N3DS
SetEncryptionKeys(ncchHeader, partitionIndex, encrypt);
// Process the extended header
- ProcessExtendedHeader(ncchHeader, partitionIndex, tableEntry, encrypt, reader, writer);
+ ProcessExtendedHeader(ncchHeader, partitionIndex, tableEntry, encrypt, input, output);
// If we're encrypting, encrypt the filesystems and update the flags
if (encrypt)
{
- EncryptExeFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
- EncryptRomFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
- UpdateEncryptCryptoAndMasks(ncchHeader, partitionIndex, tableEntry, writer);
+ EncryptExeFS(ncchHeader, partitionIndex, tableEntry, input, output);
+ EncryptRomFS(ncchHeader, partitionIndex, tableEntry, input, output);
+ UpdateEncryptCryptoAndMasks(ncchHeader, partitionIndex, tableEntry, output);
}
// If we're decrypting, decrypt the filesystems and update the flags
else
{
- DecryptExeFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
- DecryptRomFS(ncchHeader, partitionIndex, tableEntry, reader, writer);
- UpdateDecryptCryptoAndMasks(ncchHeader, tableEntry, writer);
+ DecryptExeFS(ncchHeader, partitionIndex, tableEntry, input, output);
+ DecryptRomFS(ncchHeader, partitionIndex, tableEntry, input, output);
+ UpdateDecryptCryptoAndMasks(ncchHeader, tableEntry, output);
}
}
@@ -193,17 +173,8 @@ namespace NDecrypt.N3DS
/// Indicates if the file should be encrypted or decrypted
private void SetEncryptionKeys(NCCHHeader ncchHeader, int partitionIndex, bool encrypt)
{
- KeyXMap[partitionIndex] = 0;
- KeyX2CMap[partitionIndex] = _development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
-
- // Backup headers can't have a KeyY value set
- if (ncchHeader.RSA2048Signature != null)
- KeyYMap[partitionIndex] = new BigInteger(ncchHeader.RSA2048Signature.Take(16).Reverse().ToArray());
- else
- KeyYMap[partitionIndex] = new BigInteger(0);
-
- NormalKeyMap[partitionIndex] = 0x00;
- NormalKey2CMap[partitionIndex] = RotateLeft((RotateLeft(KeyX2CMap[partitionIndex], 2, 128) ^ KeyYMap[partitionIndex]) + _decryptArgs.AESHardwareConstant, 87, 128);
+ // Get partition-specific values
+ byte[]? rsaSignature = ncchHeader.RSA2048Signature;
// TODO: Figure out what sane defaults for these values are
// Set the header to use based on mode
@@ -221,37 +192,8 @@ namespace NDecrypt.N3DS
method = ncchHeader.Flags.CryptoMethod;
}
- if (masks.HasFlag(BitMasks.FixedCryptoKey))
- {
- NormalKeyMap[partitionIndex] = 0x00;
- NormalKey2CMap[partitionIndex] = 0x00;
- Console.WriteLine("Encryption Method: Zero Key");
- }
- else
- {
- if (method == CryptoMethod.Original)
- {
- KeyXMap[partitionIndex] = _development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C;
- Console.WriteLine("Encryption Method: Key 0x2C");
- }
- else if (method == CryptoMethod.Seven)
- {
- KeyXMap[partitionIndex] = _development ? _decryptArgs.DevKeyX0x25 : _decryptArgs.KeyX0x25;
- Console.WriteLine("Encryption Method: Key 0x25");
- }
- else if (method == CryptoMethod.NineThree)
- {
- KeyXMap[partitionIndex] = _development ? _decryptArgs.DevKeyX0x18 : _decryptArgs.KeyX0x18;
- Console.WriteLine("Encryption Method: Key 0x18");
- }
- else if (method == CryptoMethod.NineSix)
- {
- KeyXMap[partitionIndex] = _development ? _decryptArgs.DevKeyX0x1B : _decryptArgs.KeyX0x1B;
- Console.WriteLine("Encryption Method: Key 0x1B");
- }
-
- NormalKeyMap[partitionIndex] = RotateLeft((RotateLeft(KeyXMap[partitionIndex], 2, 128) ^ KeyYMap[partitionIndex]) + _decryptArgs.AESHardwareConstant, 87, 128);
- }
+ // Get the partition keys
+ KeysMap[partitionIndex] = new PartitionKeys(_decryptArgs, rsaSignature, masks, method, _development);
}
///
@@ -261,28 +203,28 @@ namespace NDecrypt.N3DS
/// 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
+ /// Stream representing the input
+ /// Stream representing the output
private bool ProcessExtendedHeader(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
bool encrypt,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // mediaUnitSize;
if (ncchHeader.ExtendedHeaderSizeInBytes > 0)
{
- reader.Seek((tableEntry.Offset * mediaUnitSize) + 0x200, SeekOrigin.Begin);
- writer.Seek((tableEntry.Offset * mediaUnitSize) + 0x200, SeekOrigin.Begin);
+ input.Seek((tableEntry.Offset * mediaUnitSize) + 0x200, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset * mediaUnitSize) + 0x200, SeekOrigin.Begin);
Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");
- var cipher = CreateAESCipher(NormalKey2CMap[partitionIndex], ncchHeader.PlainIV(), encrypt);
- writer.Write(cipher.ProcessBytes(reader.ReadBytes(Constants.CXTExtendedDataHeaderLength)));
- writer.Flush();
+ var cipher = CreateAESCipher(KeysMap[partitionIndex].NormalKey2C, ncchHeader.PlainIV(), encrypt);
+ output.Write(cipher.ProcessBytes(input.ReadBytes(Constants.CXTExtendedDataHeaderLength)));
+ output.Flush();
return true;
}
else
@@ -299,20 +241,20 @@ namespace NDecrypt.N3DS
/// 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
+ /// Stream representing the input
+ /// Stream representing the output
private void ProcessExeFSFileEntries(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
bool encrypt,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // mediaUnitSize;
- reader.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
- var exefsHeader = N3DSDeserializer.ParseExeFSHeader(reader);
+ input.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
+ var exefsHeader = N3DSDeserializer.ParseExeFSHeader(input);
// If the header failed to read, log and return
if (exefsHeader?.FileHeaders == null)
@@ -333,26 +275,26 @@ namespace NDecrypt.N3DS
byte[] exefsIVWithOffsetForHeader = AddToByteArray(ncchHeader.ExeFSIV(), (int)ctroffset);
- var firstCipher = CreateAESCipher(NormalKeyMap[partitionIndex], exefsIVWithOffsetForHeader, encrypt);
- var secondCipher = CreateAESCipher(NormalKey2CMap[partitionIndex], exefsIVWithOffsetForHeader, !encrypt);
+ var firstCipher = CreateAESCipher(KeysMap[partitionIndex].NormalKey, exefsIVWithOffsetForHeader, encrypt);
+ var secondCipher = CreateAESCipher(KeysMap[partitionIndex].NormalKey2C, 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);
+ input.Seek((((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) + 1) * mediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);
+ output.Seek((((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) + 1) * mediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);
if (datalenM > 0)
{
for (int i = 0; i < datalenM; i++)
{
- writer.Write(secondCipher.ProcessBytes(firstCipher.ProcessBytes(reader.ReadBytes(1024 * 1024))));
- writer.Flush();
+ output.Write(secondCipher.ProcessBytes(firstCipher.ProcessBytes(input.ReadBytes(1024 * 1024))));
+ output.Flush();
Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {i} / {datalenM + 1} mb...");
}
}
if (datalenB > 0)
{
- writer.Write(secondCipher.DoFinal(firstCipher.DoFinal(reader.ReadBytes((int)datalenB))));
- writer.Flush();
+ output.Write(secondCipher.DoFinal(firstCipher.DoFinal(input.ReadBytes((int)datalenB))));
+ output.Flush();
}
Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.FileName}... {datalenM + 1} / {datalenM + 1} mb... Done!\r\n");
@@ -366,26 +308,26 @@ namespace NDecrypt.N3DS
/// 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
+ /// Stream representing the input
+ /// Stream representing the output
private void ProcessExeFSFilenameTable(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
bool encrypt,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // mediaUnitSize;
- reader.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
- writer.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
+ input.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
Console.WriteLine($"Partition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");
- var exeFSFilenameTable = CreateAESCipher(NormalKey2CMap[partitionIndex], ncchHeader.ExeFSIV(), encrypt);
- writer.Write(exeFSFilenameTable.ProcessBytes(reader.ReadBytes((int)mediaUnitSize)));
- writer.Flush();
+ var exeFSFilenameTable = CreateAESCipher(KeysMap[partitionIndex].NormalKey2C, ncchHeader.ExeFSIV(), encrypt);
+ output.Write(exeFSFilenameTable.ProcessBytes(input.ReadBytes((int)mediaUnitSize)));
+ output.Flush();
}
///
@@ -395,14 +337,14 @@ namespace NDecrypt.N3DS
/// 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
+ /// Stream representing the input
+ /// Stream representing the output
private void ProcessExeFS(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
bool encrypt,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // mediaUnitSize;
@@ -413,23 +355,23 @@ namespace NDecrypt.N3DS
byte[] exefsIVWithOffset = AddToByteArray(ncchHeader.ExeFSIV(), ctroffsetE);
- var exeFS = CreateAESCipher(NormalKey2CMap[partitionIndex], exefsIVWithOffset, encrypt);
+ var exeFS = CreateAESCipher(KeysMap[partitionIndex].NormalKey2C, exefsIVWithOffset, encrypt);
- reader.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * mediaUnitSize, SeekOrigin.Begin);
- writer.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * mediaUnitSize, SeekOrigin.Begin);
+ input.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * mediaUnitSize, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * mediaUnitSize, SeekOrigin.Begin);
if (exefsSizeM > 0)
{
for (int i = 0; i < exefsSizeM; i++)
{
- writer.Write(exeFS.ProcessBytes(reader.ReadBytes(1024 * 1024)));
- writer.Flush();
+ output.Write(exeFS.ProcessBytes(input.ReadBytes(1024 * 1024)));
+ output.Flush();
Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {i} / {exefsSizeM + 1} mb");
}
}
if (exefsSizeB > 0)
{
- writer.Write(exeFS.DoFinal(reader.ReadBytes(exefsSizeB)));
- writer.Flush();
+ output.Write(exeFS.DoFinal(input.ReadBytes(exefsSizeB)));
+ output.Flush();
}
Console.Write($"\rPartition {partitionIndex} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": {exefsSizeM + 1} / {exefsSizeM + 1} mb... Done!\r\n");
@@ -445,13 +387,13 @@ namespace NDecrypt.N3DS
/// NCCH header representing the partition
/// Index of the partition
/// PartitionTableEntry header representing the partition
- /// Stream representing the input
- /// Stream representing the output
+ /// Stream representing the input
+ /// Stream representing the output
private void DecryptExeFS(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// If the ExeFS size is 0, we log and return
if (ncchHeader.ExeFSSizeInMediaUnits == 0)
@@ -461,14 +403,14 @@ namespace NDecrypt.N3DS
}
// Decrypt the filename table
- ProcessExeFSFilenameTable(ncchHeader, partitionIndex, tableEntry, encrypt: false, reader, writer);
+ ProcessExeFSFilenameTable(ncchHeader, partitionIndex, tableEntry, encrypt: false, input, output);
// For all but the original crypto method, process each of the files in the table
if (ncchHeader.Flags!.CryptoMethod != CryptoMethod.Original)
- ProcessExeFSFileEntries(ncchHeader, partitionIndex, tableEntry, encrypt: false, reader, writer);
+ ProcessExeFSFileEntries(ncchHeader, partitionIndex, tableEntry, encrypt: false, input, output);
// Decrypt the rest of the ExeFS
- ProcessExeFS(ncchHeader, partitionIndex, tableEntry, encrypt: false, reader, writer);
+ ProcessExeFS(ncchHeader, partitionIndex, tableEntry, encrypt: false, input, output);
}
///
@@ -477,14 +419,14 @@ namespace NDecrypt.N3DS
/// NCCH header representing the partition
/// Index of the partition
/// PartitionTableEntry header representing the partition
- /// Stream representing the input
- /// Stream representing the output
+ /// Stream representing the input
+ /// Stream representing the output
/// TODO: See how much can be extracted into a common method with Encrypt
private void DecryptRomFS(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // ncsdHeader.MediaUnitSize;
@@ -499,23 +441,23 @@ namespace NDecrypt.N3DS
long romfsSizeM = (int)((long)(ncchHeader.RomFSSizeInMediaUnits * mediaUnitSize) / (1024 * 1024));
int romfsSizeB = (int)((long)(ncchHeader.RomFSSizeInMediaUnits * mediaUnitSize) % (1024 * 1024));
- var cipher = CreateAESCipher(NormalKeyMap[partitionIndex], ncchHeader.RomFSIV(), encrypt: false);
+ var cipher = CreateAESCipher(KeysMap[partitionIndex].NormalKey, ncchHeader.RomFSIV(), encrypt: false);
- reader.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
- writer.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
+ input.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
if (romfsSizeM > 0)
{
for (int i = 0; i < romfsSizeM; i++)
{
- writer.Write(cipher.ProcessBytes(reader.ReadBytes(1024 * 1024)));
- writer.Flush();
+ output.Write(cipher.ProcessBytes(input.ReadBytes(1024 * 1024)));
+ output.Flush();
Console.Write($"\rPartition {partitionIndex} RomFS: Decrypting: {i} / {romfsSizeM + 1} mb");
}
}
if (romfsSizeB > 0)
{
- writer.Write(cipher.DoFinal(reader.ReadBytes(romfsSizeB)));
- writer.Flush();
+ output.Write(cipher.DoFinal(input.ReadBytes(romfsSizeB)));
+ output.Flush();
}
Console.Write($"\rPartition {partitionIndex} RomFS: Decrypting: {romfsSizeM + 1} / {romfsSizeM + 1} mb... Done!\r\n");
@@ -526,26 +468,26 @@ namespace NDecrypt.N3DS
///
/// NCCH header representing the partition
/// PartitionTableEntry header representing the partition
- /// Stream representing the output
+ /// Stream representing the output
private void UpdateDecryptCryptoAndMasks(NCCHHeader ncchHeader,
PartitionTableEntry tableEntry,
- Stream writer)
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // ncsdHeader.MediaUnitSize;
// Write the new CryptoMethod
- writer.Seek((tableEntry.Offset * mediaUnitSize) + 0x18B, SeekOrigin.Begin);
- writer.Write((byte)CryptoMethod.Original);
- writer.Flush();
+ output.Seek((tableEntry.Offset * mediaUnitSize) + 0x18B, SeekOrigin.Begin);
+ output.Write((byte)CryptoMethod.Original);
+ output.Flush();
// Write the new BitMasks flag
- writer.Seek((tableEntry.Offset * mediaUnitSize) + 0x18F, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset * mediaUnitSize) + 0x18F, SeekOrigin.Begin);
BitMasks flag = ncchHeader.Flags!.BitMasks;
flag &= (BitMasks)((byte)(BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator) ^ 0xFF);
flag |= BitMasks.NoCrypto;
- writer.Write((byte)flag);
- writer.Flush();
+ output.Write((byte)flag);
+ output.Flush();
}
#endregion
@@ -558,13 +500,13 @@ namespace NDecrypt.N3DS
/// NCCH header representing the partition
/// Index of the partition
/// PartitionTableEntry header representing the partition
- /// Stream representing the input
- /// Stream representing the output
+ /// Stream representing the input
+ /// Stream representing the output
private void EncryptExeFS(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// If the ExeFS size is 0, we log and return
if (ncchHeader.ExeFSSizeInMediaUnits == 0)
@@ -579,10 +521,10 @@ namespace NDecrypt.N3DS
// ProcessExeFSFileEntries(ncchHeader, reader, writer);
// Encrypt the filename table
- ProcessExeFSFilenameTable(ncchHeader, partitionIndex, tableEntry, encrypt: true, reader, writer);
+ ProcessExeFSFilenameTable(ncchHeader, partitionIndex, tableEntry, encrypt: true, input, output);
// Encrypt the rest of the ExeFS
- ProcessExeFS(ncchHeader, partitionIndex, tableEntry, encrypt: true, reader, writer);
+ ProcessExeFS(ncchHeader, partitionIndex, tableEntry, encrypt: true, input, output);
}
///
@@ -591,14 +533,14 @@ namespace NDecrypt.N3DS
/// NCCH header representing the partition
/// Index of the partition
/// PartitionTableEntry header representing the partition
- /// Stream representing the input
- /// Stream representing the output
+ /// Stream representing the input
+ /// Stream representing the output
/// TODO: See how much can be extracted into a common method with Decrypt
private void EncryptRomFS(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
- Stream reader,
- Stream writer)
+ Stream input,
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // ncsdHeader.MediaUnitSize;
@@ -623,28 +565,28 @@ namespace NDecrypt.N3DS
//}
//else
//{
- KeyXMap[partitionIndex] = (_development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C);
- NormalKeyMap[partitionIndex] = RotateLeft((RotateLeft(KeyXMap[partitionIndex], 2, 128) ^ KeyYMap[partitionIndex]) + _decryptArgs.AESHardwareConstant, 87, 128);
+ KeysMap[partitionIndex].KeyX = (_development ? _decryptArgs.DevKeyX0x2C : _decryptArgs.KeyX0x2C);
+ KeysMap[partitionIndex].NormalKey = RotateLeft((RotateLeft(KeysMap[partitionIndex].KeyX, 2, 128) ^ KeysMap[partitionIndex].KeyY) + _decryptArgs.AESHardwareConstant, 87, 128);
//}
}
- var cipher = CreateAESCipher(NormalKeyMap[partitionIndex], ncchHeader.RomFSIV(), encrypt: true);
+ var cipher = CreateAESCipher(KeysMap[partitionIndex].NormalKey, ncchHeader.RomFSIV(), encrypt: true);
- reader.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
- writer.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
+ input.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset + ncchHeader.RomFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
if (romfsSizeM > 0)
{
for (int i = 0; i < romfsSizeM; i++)
{
- writer.Write(cipher.ProcessBytes(reader.ReadBytes(1024 * 1024)));
- writer.Flush();
+ output.Write(cipher.ProcessBytes(input.ReadBytes(1024 * 1024)));
+ output.Flush();
Console.Write($"\rPartition {partitionIndex} RomFS: Encrypting: {i} / {romfsSizeM + 1} mb");
}
}
if (romfsSizeB > 0)
{
- writer.Write(cipher.DoFinal(reader.ReadBytes(romfsSizeB)));
- writer.Flush();
+ output.Write(cipher.DoFinal(input.ReadBytes(romfsSizeB)));
+ output.Flush();
}
Console.Write($"\rPartition {partitionIndex} RomFS: Encrypting: {romfsSizeM + 1} / {romfsSizeM + 1} mb... Done!\r\n");
@@ -656,38 +598,38 @@ namespace NDecrypt.N3DS
/// NCCH header representing the partition
/// Index of the partition
/// PartitionTableEntry header representing the partition
- /// Stream representing the output
+ /// Stream representing the output
private void UpdateEncryptCryptoAndMasks(NCCHHeader ncchHeader,
int partitionIndex,
PartitionTableEntry tableEntry,
- Stream writer)
+ Stream output)
{
// TODO: Determine how to figure out the MediaUnitSize without an NCSD header. Is it a default value?
uint mediaUnitSize = 0x200; // ncsdHeader.MediaUnitSize;
// Write the new CryptoMethod
- writer.Seek((tableEntry.Offset * mediaUnitSize) + 0x18B, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset * mediaUnitSize) + 0x18B, SeekOrigin.Begin);
// For partitions 1 and up, set crypto-method to 0x00
if (partitionIndex > 0)
- writer.Write((byte)CryptoMethod.Original);
+ output.Write((byte)CryptoMethod.Original);
// TODO: Determine how to figure out the original crypto method, if possible
// If partition 0, restore crypto-method from backup flags
//else
// writer.Write((byte)ciaHeader.BackupHeader.Flags.CryptoMethod);
- writer.Flush();
+ output.Flush();
// Write the new BitMasks flag
- writer.Seek((tableEntry.Offset * mediaUnitSize) + 0x18F, SeekOrigin.Begin);
+ output.Seek((tableEntry.Offset * mediaUnitSize) + 0x18F, SeekOrigin.Begin);
BitMasks flag = ncchHeader.Flags!.BitMasks;
flag &= (BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator | BitMasks.NoCrypto) ^ (BitMasks)0xFF;
// TODO: Determine how to figure out the original crypto method, if possible
//flag |= (BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator) & ciaHeader.BackupHeader.Flags.BitMasks;
- writer.Write((byte)flag);
- writer.Flush();
+ output.Write((byte)flag);
+ output.Flush();
}
#endregion
@@ -697,13 +639,13 @@ namespace NDecrypt.N3DS
///
/// Read from a stream and get a CIA header, if possible
///
- /// Stream representing the input
+ /// Stream representing the input
/// CIA header object, null on error
- private static CIA? ReadCIA(Stream reader)
+ private static CIA? ReadCIA(Stream input)
{
try
{
- return CIADeserializer.DeserializeStream(reader);
+ return CIADeserializer.DeserializeStream(input);
}
catch
{