2019-04-06 21:58:08 -07:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.IO;
|
2025-02-19 15:47:05 -05:00
|
|
|
|
using System.Text;
|
2026-06-12 09:36:25 -04:00
|
|
|
|
using SabreTools.Security.Cryptography;
|
|
|
|
|
|
using SabreTools.Wrappers;
|
2019-04-06 21:58:08 -07:00
|
|
|
|
|
2024-10-13 23:59:44 -04:00
|
|
|
|
namespace NDecrypt.Core
|
2019-04-06 21:58:08 -07:00
|
|
|
|
{
|
2026-03-22 00:41:08 -04:00
|
|
|
|
public class ThreeDSProcessor : ICartProcessor
|
2019-04-06 21:58:08 -07:00
|
|
|
|
{
|
2021-09-26 21:36:55 -07:00
|
|
|
|
/// <summary>
|
2026-06-12 09:36:25 -04:00
|
|
|
|
/// Encryption settings for processing
|
2021-09-26 21:36:55 -07:00
|
|
|
|
/// </summary>
|
2026-06-12 09:36:25 -04:00
|
|
|
|
private readonly N3DSEncryptionSettings _settings;
|
2026-03-22 00:38:38 -04:00
|
|
|
|
|
2026-06-12 09:36:25 -04:00
|
|
|
|
public ThreeDSProcessor(N3DSEncryptionSettings settings)
|
2019-04-06 21:58:08 -07:00
|
|
|
|
{
|
2026-06-12 09:36:25 -04:00
|
|
|
|
_settings = settings;
|
2019-04-06 21:58:08 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-19 15:36:36 -05:00
|
|
|
|
#region Decrypt
|
2024-10-12 00:59:07 -04:00
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
2025-09-06 18:09:54 -04:00
|
|
|
|
public bool DecryptFile(string input, string? output, bool force)
|
2019-04-06 21:58:08 -07:00
|
|
|
|
{
|
2020-12-17 11:30:34 -08:00
|
|
|
|
try
|
2019-04-06 21:58:08 -07:00
|
|
|
|
{
|
2025-09-06 18:14:39 -04:00
|
|
|
|
// If the output is provided, copy the input file
|
2026-01-25 17:20:06 -05:00
|
|
|
|
if (output is not null)
|
2025-09-06 19:35:51 -04:00
|
|
|
|
File.Copy(input, output, overwrite: true);
|
2025-09-06 18:14:39 -04:00
|
|
|
|
else
|
|
|
|
|
|
output = input;
|
|
|
|
|
|
|
|
|
|
|
|
// Open the output file for processing
|
|
|
|
|
|
using var reader = File.Open(output, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
|
|
|
|
using var writer = File.Open(output, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
2024-08-08 15:49:36 -04:00
|
|
|
|
|
2024-08-08 14:01:42 -04:00
|
|
|
|
// Deserialize the cart information
|
2025-09-06 18:04:24 -04:00
|
|
|
|
var cart = N3DS.Create(reader);
|
2026-01-25 17:20:06 -05:00
|
|
|
|
if (cart?.Model is null)
|
2019-04-06 21:58:08 -07:00
|
|
|
|
{
|
2024-08-08 14:01:42 -04:00
|
|
|
|
Console.WriteLine("Error: Not a 3DS cart image!");
|
|
|
|
|
|
return false;
|
2019-04-06 21:58:08 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-13 23:08:48 -04:00
|
|
|
|
// Decrypt all 8 NCCH partitions
|
2026-06-12 09:36:25 -04:00
|
|
|
|
cart.DecryptAllPartitions(force,
|
|
|
|
|
|
reader,
|
|
|
|
|
|
writer,
|
|
|
|
|
|
_settings.Development,
|
|
|
|
|
|
_settings.AESHardwareConstant,
|
|
|
|
|
|
_settings.KeyX0x18,
|
|
|
|
|
|
_settings.DevKeyX0x18,
|
|
|
|
|
|
_settings.KeyX0x1B,
|
|
|
|
|
|
_settings.DevKeyX0x1B,
|
|
|
|
|
|
_settings.KeyX0x25,
|
|
|
|
|
|
_settings.DevKeyX0x25,
|
|
|
|
|
|
_settings.KeyX0x2C,
|
|
|
|
|
|
_settings.DevKeyX0x2C);
|
2020-12-17 11:30:34 -08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
2025-09-06 18:14:39 -04:00
|
|
|
|
Console.WriteLine($"An error has occurred. {output} may be corrupted if it was partially processed.");
|
2021-09-26 23:20:06 -07:00
|
|
|
|
Console.WriteLine("Please check that the file was a valid 3DS or New 3DS cart image and try again.");
|
2020-12-17 11:30:34 -08:00
|
|
|
|
return false;
|
2019-04-06 21:58:08 -07:00
|
|
|
|
}
|
2020-12-15 13:30:28 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Encrypt
|
|
|
|
|
|
|
2025-02-19 15:36:36 -05:00
|
|
|
|
/// <inheritdoc/>
|
2025-09-06 18:09:54 -04:00
|
|
|
|
public bool EncryptFile(string input, string? output, bool force)
|
2025-02-19 15:36:36 -05:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-09-06 18:14:39 -04:00
|
|
|
|
// If the output is provided, copy the input file
|
2026-01-25 17:20:06 -05:00
|
|
|
|
if (output is not null)
|
2025-09-06 19:35:51 -04:00
|
|
|
|
File.Copy(input, output, overwrite: true);
|
2025-09-06 18:14:39 -04:00
|
|
|
|
else
|
|
|
|
|
|
output = input;
|
|
|
|
|
|
|
|
|
|
|
|
// Open the output file for processing
|
|
|
|
|
|
using var reader = File.Open(output, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
|
|
|
|
using var writer = File.Open(output, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
|
2025-02-19 15:36:36 -05:00
|
|
|
|
|
|
|
|
|
|
// Deserialize the cart information
|
2025-09-06 18:04:24 -04:00
|
|
|
|
var cart = N3DS.Create(reader);
|
2026-01-25 17:20:06 -05:00
|
|
|
|
if (cart?.Model is null)
|
2025-02-19 15:36:36 -05:00
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Error: Not a 3DS cart image!");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Encrypt all 8 NCCH partitions
|
2026-06-12 09:36:25 -04:00
|
|
|
|
cart.EncryptAllPartitions(force,
|
|
|
|
|
|
reader,
|
|
|
|
|
|
writer,
|
|
|
|
|
|
_settings.Development,
|
|
|
|
|
|
_settings.AESHardwareConstant,
|
|
|
|
|
|
_settings.KeyX0x18,
|
|
|
|
|
|
_settings.DevKeyX0x18,
|
|
|
|
|
|
_settings.KeyX0x1B,
|
|
|
|
|
|
_settings.DevKeyX0x1B,
|
|
|
|
|
|
_settings.KeyX0x25,
|
|
|
|
|
|
_settings.DevKeyX0x25,
|
|
|
|
|
|
_settings.KeyX0x2C,
|
|
|
|
|
|
_settings.DevKeyX0x2C);
|
2025-02-19 15:36:36 -05:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
2025-09-06 18:14:39 -04:00
|
|
|
|
Console.WriteLine($"An error has occurred. {output} may be corrupted if it was partially processed.");
|
2025-02-19 15:36:36 -05:00
|
|
|
|
Console.WriteLine("Please check that the file was a valid 3DS or New 3DS cart image and try again.");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-15 13:30:28 -08:00
|
|
|
|
#endregion
|
2025-02-19 15:47:05 -05:00
|
|
|
|
|
2025-02-19 15:36:36 -05:00
|
|
|
|
#region Info
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
|
|
public string? GetInformation(string filename)
|
|
|
|
|
|
{
|
2025-02-19 15:47:05 -05:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// Open the file for reading
|
|
|
|
|
|
using var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
|
|
|
|
|
|
|
|
|
|
// Deserialize the cart information
|
|
|
|
|
|
var cart = N3DS.Create(input);
|
2026-01-25 17:20:06 -05:00
|
|
|
|
if (cart?.Model is null)
|
2025-02-19 15:47:05 -05:00
|
|
|
|
return "Error: Not a 3DS cart image!";
|
|
|
|
|
|
|
|
|
|
|
|
// Get a string builder for the status
|
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
|
|
// Iterate over all 8 NCCH partitions
|
|
|
|
|
|
for (int p = 0; p < 8; p++)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool decrypted = cart.PossiblyDecrypted(p);
|
2025-02-19 21:10:52 -05:00
|
|
|
|
sb.AppendLine($"\tPartition {p}: {(decrypted ? "Decrypted" : "Encrypted")}");
|
2025-02-19 15:47:05 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return the status for all partitions
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine(ex);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-02-19 15:36:36 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2019-04-06 21:58:08 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|