From 1fbacaffb0f44bde912a4e5f5f65055ada71800f Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 6 Sep 2025 16:07:37 -0400 Subject: [PATCH] Take advantage of Wrapper functions for NDS --- NDecrypt.Core/DSTool.cs | 366 ++++------------------------------------ 1 file changed, 32 insertions(+), 334 deletions(-) diff --git a/NDecrypt.Core/DSTool.cs b/NDecrypt.Core/DSTool.cs index 3850468..0898494 100644 --- a/NDecrypt.Core/DSTool.cs +++ b/NDecrypt.Core/DSTool.cs @@ -2,20 +2,12 @@ using System.IO; using System.Text; using SabreTools.IO.Extensions; -using SabreTools.Models.Nitro; -using SabreTools.Serialization.Deserializers; +using SabreTools.Serialization.Wrappers; namespace NDecrypt.Core { public class DSTool : ITool { - #region Encryption process variables - - private uint[] _cardHash = new uint[0x412]; - private uint[] _arg2 = new uint[3]; - - #endregion - /// /// Decryption args to use while processing /// @@ -35,22 +27,31 @@ namespace NDecrypt.Core { // 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); // Deserialize the cart information - var commonHeader = Nitro.ParseCommonHeader(reader); - if (commonHeader == null) + var nitro = Nitro.Create(reader); + if (nitro == null) { Console.WriteLine("Error: Not a DS or DSi Rom!"); return false; } - // Reset state variables - _cardHash = new uint[0x412]; - _arg2 = new uint[3]; + // Ensure the secure area was read + if (nitro.SecureArea == null) + { + Console.WriteLine("Error: Invalid secure area!"); + return false; + } // Encrypt the secure area - EncryptSecureArea(commonHeader, force, reader, writer); + nitro.EncryptSecureArea(_decryptArgs.NitroEncryptionData, force); + + // Write the encrypted secure area + using var writer = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + writer.Seek(0x4000, SeekOrigin.Begin); + writer.Write(nitro.SecureArea); + writer.Flush(); + return true; } catch @@ -61,123 +62,6 @@ namespace NDecrypt.Core } } - /// - /// Encrypt secure area in the DS/DSi file - /// s - /// CommonHeader representing the DS file header - /// Indicates if the operation should be forced - /// Stream representing the input - /// Stream representing the output - private void EncryptSecureArea(CommonHeader commonHeader, bool force, Stream reader, Stream writer) - { - // If we're forcing the operation, tell the user - if (force) - { - Console.WriteLine("File is not verified due to force flag being set."); - } - // If we're not forcing the operation, check to see if we should be proceeding - else - { - bool? isDecrypted = CheckIfDecrypted(reader); - if (isDecrypted == null) - { - Console.WriteLine("File has an empty secure area, cannot proceed"); - return; - } - else if (!isDecrypted.Value) - { - Console.WriteLine("File is already encrypted"); - return; - } - } - - EncryptARM9(commonHeader, reader, writer); - Console.WriteLine("File has been encrypted"); - } - - /// - /// Encrypt 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 EncryptARM9(CommonHeader commonHeader, Stream reader, Stream writer) - { - // Seek to the beginning of the secure area - reader.Seek(0x4000, SeekOrigin.Begin); - writer.Seek(0x4000, SeekOrigin.Begin); - - // Grab the first two blocks - uint p0 = reader.ReadUInt32(); - uint p1 = reader.ReadUInt32(); - - // Perform the initialization steps - Init1(commonHeader); - _arg2[1] <<= 1; - _arg2[2] >>= 1; - Init2(); - - // Ensure alignment - reader.Seek(0x4008, SeekOrigin.Begin); - writer.Seek(0x4008, SeekOrigin.Begin); - - // Loop throgh the main encryption step - uint size = 0x800 - 8; - while (size > 0) - { - p0 = reader.ReadUInt32(); - p1 = reader.ReadUInt32(); - - Encrypt(ref p1, ref p0); - - writer.Write(p0); - writer.Write(p1); - - size -= 8; - } - - // Replace the header explicitly - reader.Seek(0x4000, SeekOrigin.Begin); - writer.Seek(0x4000, SeekOrigin.Begin); - - p0 = reader.ReadUInt32(); - p1 = reader.ReadUInt32(); - - if (p0 == 0xE7FFDEFF && p1 == 0xE7FFDEFF) - { - p0 = Constants.MAGIC30; - p1 = Constants.MAGIC34; - } - - Encrypt(ref p1, ref p0); - Init1(commonHeader); - Encrypt(ref p1, ref p0); - - writer.Write(p0); - writer.Write(p1); - } - - /// - /// Perform an encryption step - /// - /// First unsigned value to use in encryption - /// Second unsigned value to use in encryption - private void Encrypt(ref uint arg1, ref uint arg2) - { - uint a = arg1; - uint b = arg2; - for (int i = 0; i < 16; i++) - { - uint c = _cardHash[i] ^ a; - a = b ^ Lookup(c); - b = c; - } - - arg2 = a ^ _cardHash[16]; - arg1 = b ^ _cardHash[17]; - } - #endregion #region Decrypt @@ -189,22 +73,30 @@ namespace NDecrypt.Core { // 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); // Deserialize the cart information - var commonHeader = Nitro.ParseCommonHeader(reader); - if (commonHeader == null) + var nitro = Nitro.Create(reader); + if (nitro == null) { Console.WriteLine("Error: Not a DS or DSi Rom!"); return false; } - // Reset state variables - _cardHash = new uint[0x412]; - _arg2 = new uint[3]; + // Ensure the secure area was read + if (nitro.SecureArea == null) + { + Console.WriteLine("Error: Invalid secure area!"); + return false; + } // Decrypt the secure area - DecryptSecureArea(commonHeader, force, reader, writer); + nitro.DecryptSecureArea(_decryptArgs.NitroEncryptionData, force); + + // Write the decrypted secure area + using var writer = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + writer.Seek(0x4000, SeekOrigin.Begin); + writer.Write(nitro.SecureArea); + writer.Flush(); return true; } @@ -216,115 +108,6 @@ namespace NDecrypt.Core } } - /// - /// Decrypt secure area in the DS/DSi file - /// s - /// CommonHeader representing the DS file header - /// Indicates if the operation should be forced - /// Stream representing the input - /// Stream representing the output - private void DecryptSecureArea(CommonHeader commonHeader, bool force, Stream reader, Stream writer) - { - // If we're forcing the operation, tell the user - if (force) - { - Console.WriteLine("File is not verified due to force flag being set."); - } - // If we're not forcing the operation, check to see if we should be proceeding - else - { - bool? isDecrypted = CheckIfDecrypted(reader); - if (isDecrypted == null) - { - Console.WriteLine("File has an empty secure area, cannot proceed"); - return; - } - else if (isDecrypted.Value) - { - Console.WriteLine("File is already decrypted"); - return; - } - } - - DecryptARM9(commonHeader, reader, writer); - Console.WriteLine("File has been decrypted"); - } - - /// - /// Decrypt 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 DecryptARM9(CommonHeader commonHeader, Stream reader, Stream writer) - { - // Seek to the beginning of the secure area - reader.Seek(0x4000, SeekOrigin.Begin); - writer.Seek(0x4000, SeekOrigin.Begin); - - // Grab the first two blocks - uint p0 = reader.ReadUInt32(); - uint p1 = reader.ReadUInt32(); - - // Perform the initialization steps - Init1(commonHeader); - Decrypt(ref p1, ref p0); - _arg2[1] <<= 1; - _arg2[2] >>= 1; - Init2(); - - // Set the proper flags - Decrypt(ref p1, ref p0); - if (p0 == Constants.MAGIC30 && p1 == Constants.MAGIC34) - { - p0 = 0xE7FFDEFF; - p1 = 0xE7FFDEFF; - } - - writer.Write(p0); - writer.Write(p1); - - // Ensure alignment - reader.Seek(0x4008, SeekOrigin.Begin); - writer.Seek(0x4008, SeekOrigin.Begin); - - // Loop throgh the main encryption step - uint size = 0x800 - 8; - while (size > 0) - { - p0 = reader.ReadUInt32(); - p1 = reader.ReadUInt32(); - - Decrypt(ref p1, ref p0); - - writer.Write(p0); - writer.Write(p1); - - size -= 8; - } - } - - /// - /// Perform a decryption step - /// - /// First unsigned value to use in decryption - /// Second unsigned value to use in decryption - private void Decrypt(ref uint arg1, ref uint arg2) - { - uint a = arg1; - uint b = arg2; - for (int i = 17; i > 1; i--) - { - uint c = _cardHash[i] ^ a; - a = b ^ Lookup(c); - b = c; - } - - arg1 = b ^ _cardHash[0]; - arg2 = a ^ _cardHash[1]; - } - #endregion #region Info @@ -361,10 +144,6 @@ namespace NDecrypt.Core } } - #endregion - - #region Common - /// /// Determine if the current file is already decrypted or not (or has an empty secure area) /// @@ -456,87 +235,6 @@ namespace NDecrypt.Core return firstValue == 0xE7FFDEFF && secondValue == 0xE7FFDEFF; } - /// - /// First common initialization step - /// - /// CommonHeader representing the DS file - private void Init1(CommonHeader commonHeader) - { - Buffer.BlockCopy(_decryptArgs.NitroEncryptionData, 0, _cardHash, 0, 4 * (1024 + 18)); - _arg2 = [commonHeader.GameCode, commonHeader.GameCode >> 1, commonHeader.GameCode << 1]; - Init2(); - Init2(); - } - - /// - /// Second common initialization step - /// - private void Init2() - { - Encrypt(ref _arg2[2], ref _arg2[1]); - Encrypt(ref _arg2[1], ref _arg2[0]); - - byte[] allBytes =[.. BitConverter.GetBytes(_arg2[0]), - .. BitConverter.GetBytes(_arg2[1]), - .. BitConverter.GetBytes(_arg2[2])]; - - UpdateHashtable(allBytes); - } - - /// - /// Lookup the value from the hashtable - /// - /// Value to lookup in the hashtable - /// Processed value through the hashtable - private uint Lookup(uint v) - { - uint a = (v >> 24) & 0xFF; - uint b = (v >> 16) & 0xFF; - uint c = (v >> 8) & 0xFF; - uint d = (v >> 0) & 0xFF; - - a = _cardHash[a + 18 + 0]; - b = _cardHash[b + 18 + 256]; - c = _cardHash[c + 18 + 512]; - d = _cardHash[d + 18 + 768]; - - return d + (c ^ (b + a)); - } - - /// - /// Update the hashtable - /// - /// Value to update the hashtable with - private void UpdateHashtable(byte[] arg1) - { - for (int j = 0; j < 18; j++) - { - uint r3 = 0; - for (int i = 0; i < 4; i++) - { - r3 <<= 8; - r3 |= arg1[(j * 4 + i) & 7]; - } - - _cardHash[j] ^= r3; - } - - uint tmp1 = 0; - uint tmp2 = 0; - for (int i = 0; i < 18; i += 2) - { - Encrypt(ref tmp1, ref tmp2); - _cardHash[i + 0] = tmp1; - _cardHash[i + 1] = tmp2; - } - for (int i = 0; i < 0x400; i += 2) - { - Encrypt(ref tmp1, ref tmp2); - _cardHash[i + 18 + 0] = tmp1; - _cardHash[i + 18 + 1] = tmp2; - } - } - #endregion } }