mirror of
https://github.com/SabreTools/NDecrypt.git
synced 2026-02-06 05:35:23 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7415a21d5c | ||
|
|
f349389994 | ||
|
|
a046bd4152 | ||
|
|
51a8f0c9df | ||
|
|
0449c16a01 | ||
|
|
7638d7dbf8 | ||
|
|
387bf46e5a | ||
|
|
6d257dc1e3 | ||
|
|
91d816e359 |
@@ -47,22 +47,31 @@ namespace NDecrypt
|
||||
if (!File.Exists(filename))
|
||||
return false;
|
||||
|
||||
// Open the read and write on the same file for inplace processing
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)))
|
||||
try
|
||||
{
|
||||
NDSHeader header = NDSHeader.Read(reader);
|
||||
if (header == null)
|
||||
// Open the read and write on the same file for inplace processing
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)))
|
||||
{
|
||||
Console.WriteLine("Error: Not a DS or DSi Rom!");
|
||||
return false;
|
||||
NDSHeader header = NDSHeader.Read(reader);
|
||||
if (header == null)
|
||||
{
|
||||
Console.WriteLine("Error: Not a DS or DSi Rom!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Process the secure area
|
||||
ProcessSecureArea(header, reader, writer);
|
||||
}
|
||||
|
||||
// Process the secure area
|
||||
ProcessSecureArea(header, reader, writer);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine($"An error has occurred. {filename} may be corrupted if it was partially processed.");
|
||||
Console.WriteLine("Please check that the file was a valid DS or DSi file and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +128,10 @@ namespace NDecrypt
|
||||
|
||||
// Improperly decrypted empty secure area (decrypt empty with woodsec)
|
||||
else if ((firstValue == 0xE386C397 && secondValue == 0x82775B7E)
|
||||
|| (firstValue == 0xF98415B8 && secondValue == 0x698068FC))
|
||||
|| (firstValue == 0xF98415B8 && secondValue == 0x698068FC)
|
||||
|| (firstValue == 0xA71329EE && secondValue == 0x2A1D4C38)
|
||||
|| (firstValue == 0xC44DCC48 && secondValue == 0x38B6F8CB)
|
||||
|| (firstValue == 0x3A9323B5 && secondValue == 0xC0387241))
|
||||
{
|
||||
Console.WriteLine("Improperly decrypted empty secure area found. Should be encrypted to get proper value.");
|
||||
return true;
|
||||
@@ -136,7 +148,9 @@ namespace NDecrypt
|
||||
// Properly decrypted nonstandard value (mastering issue)
|
||||
else if ((firstValue == 0xD0D48B67 && secondValue == 0x39392F23) // Dragon Quest 5 (EU)
|
||||
|| (firstValue == 0x014A191A && secondValue == 0xA5C470B9) // Dragon Quest 5 (USA)
|
||||
|| (firstValue == 0x7829BC8D && secondValue == 0x9968EF44)) // Dragon Quest 5 (JP)
|
||||
|| (firstValue == 0x7829BC8D && secondValue == 0x9968EF44) // Dragon Quest 5 (JP)
|
||||
|| (firstValue == 0xC4A15AB8 && secondValue == 0xD2E667C8) // Prince of Persia (EU)
|
||||
|| (firstValue == 0xD5E97D20 && secondValue == 0x21B2A159)) // Prince of Persia (USA)
|
||||
{
|
||||
Console.WriteLine("Decrypted secure area for known, nonstandard value found.");
|
||||
return true;
|
||||
@@ -149,13 +163,6 @@ namespace NDecrypt
|
||||
return true;
|
||||
}
|
||||
|
||||
// Properly encrypted prototype value
|
||||
else if (firstValue == 0xA71329EE && secondValue == 0x2A1D4C38)
|
||||
{
|
||||
Console.WriteLine("Encrypted secure area for prototype found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Standard decryption values
|
||||
return firstValue == 0xE7FFDEFF && secondValue == 0xE7FFDEFF;
|
||||
}
|
||||
|
||||
@@ -51,14 +51,18 @@ namespace NDecrypt.N3DS
|
||||
/// <summary>
|
||||
/// Represents if all of the keys have been initialized properly
|
||||
/// </summary>
|
||||
public static bool IsReady { get; private set; }
|
||||
public static bool? IsReady { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Setup all of the necessary constants
|
||||
/// </summary>
|
||||
/// <remarks>keys.bin should be in little endian format</remarks>
|
||||
static Constants()
|
||||
public static void Init()
|
||||
{
|
||||
// If we're already attempted to set the constants, don't try to again
|
||||
if (IsReady != null)
|
||||
return;
|
||||
|
||||
string keyfile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "keys.bin");
|
||||
if (!File.Exists(keyfile))
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using NDecrypt.N3DS;
|
||||
|
||||
namespace NDecrypt
|
||||
{
|
||||
@@ -43,14 +42,6 @@ namespace NDecrypt
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure the constants are all set
|
||||
new Constants();
|
||||
if (!Constants.IsReady)
|
||||
{
|
||||
Console.WriteLine("Could not read keys from keys.bin. Please make sure the file exists and try again");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = start; i < args.Length; i++)
|
||||
{
|
||||
if (File.Exists(args[i]))
|
||||
@@ -68,10 +59,11 @@ namespace NDecrypt
|
||||
Console.WriteLine("Processing failed!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{args[i]} is not a file or folder. Please check your spelling and formatting and try again.");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Press Enter to Exit...");
|
||||
Console.Read();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,7 +75,18 @@ namespace NDecrypt
|
||||
if (!string.IsNullOrWhiteSpace(err))
|
||||
Console.WriteLine($"Error: {err}");
|
||||
|
||||
Console.WriteLine("Usage: NDecrypt.exe (decrypt|encrypt) [-dev] [-f] <file|dir> ...");
|
||||
Console.WriteLine(@"Usage: NDecrypt.exe <opeation> [flags] <path> ...
|
||||
|
||||
Possible values for <operation>:
|
||||
e, encrypt - Encrypt the input files
|
||||
d, decrypt - Decrypt the input files
|
||||
|
||||
Possible values for [flags] (one or more can be used):
|
||||
-dev, --development - Enable using development keys, if available
|
||||
-f, --force - Force operation by avoiding sanity checks
|
||||
|
||||
<path> can be any file or folder that contains uncompressed items.
|
||||
More than one path can be specified at a time.");
|
||||
}
|
||||
|
||||
private enum RomType
|
||||
@@ -126,8 +129,9 @@ namespace NDecrypt
|
||||
/// <returns>RomType value, if possible</returns>
|
||||
private static RomType DetermineRomType(string filename)
|
||||
{
|
||||
if (filename.EndsWith(".nds", StringComparison.OrdinalIgnoreCase)
|
||||
|| filename.EndsWith(".srl", StringComparison.OrdinalIgnoreCase))
|
||||
if (filename.EndsWith(".nds", StringComparison.OrdinalIgnoreCase) // Standard carts
|
||||
|| filename.EndsWith(".srl", StringComparison.OrdinalIgnoreCase) // Development carts/images
|
||||
|| filename.EndsWith(".ids", StringComparison.OrdinalIgnoreCase)) // iQue DS Carts
|
||||
return RomType.NDS;
|
||||
|
||||
else if (filename.EndsWith(".dsi", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -44,27 +44,44 @@ namespace NDecrypt
|
||||
/// </summary>
|
||||
public bool ProcessFile()
|
||||
{
|
||||
// Ensure the constants are all set
|
||||
Constants.Init();
|
||||
if (Constants.IsReady != true)
|
||||
{
|
||||
Console.WriteLine("Could not read keys from keys.bin. Please make sure the file exists and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure we have a file to process first
|
||||
Console.WriteLine(filename);
|
||||
if (!File.Exists(filename))
|
||||
return false;
|
||||
|
||||
// Open the read and write on the same file for inplace processing
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)))
|
||||
try
|
||||
{
|
||||
NCSDHeader header = NCSDHeader.Read(reader, development);
|
||||
if (header == null)
|
||||
// Open the read and write on the same file for inplace processing
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)))
|
||||
{
|
||||
Console.WriteLine("Error: Not a 3DS Rom!");
|
||||
return false;
|
||||
NCSDHeader header = NCSDHeader.Read(reader, development);
|
||||
if (header == null)
|
||||
{
|
||||
Console.WriteLine("Error: Not a 3DS Rom!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Process all 8 NCCH partitions
|
||||
ProcessAllPartitions(header, reader, writer);
|
||||
}
|
||||
|
||||
// Process all 8 NCCH partitions
|
||||
ProcessAllPartitions(header, reader, writer);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine($"An error has occurred. {filename} may be corrupted if it was partially processed.");
|
||||
Console.WriteLine("Please check that the file was a valid 3DS or New 3DS file and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
32
README.md
32
README.md
@@ -16,20 +16,27 @@ This tool allows you to encrypt and decrypt your personally dumped NDS and N3DS
|
||||
|
||||
## So how do I use this?
|
||||
|
||||
NDecrypt.exe <flag> [-dev] <file|dir> ...
|
||||
NDecrypt.exe <operation> [flags] <path> ...
|
||||
|
||||
Possible values for <flag>:
|
||||
encrypt, e - Encrypt the incoming files
|
||||
decrypt, d - Decrypt the incoming files
|
||||
Possible values for <operation>:
|
||||
e, encrypt - Encrypt the input files
|
||||
d, decrypt - Decrypt the input files
|
||||
|
||||
Possible values for [flags] (one or more can be used):
|
||||
-dev, --development - Enable using development keys, if available
|
||||
-f, --force - Force operation by avoiding sanity checks
|
||||
|
||||
<path> can be any file or folder that contains uncompressed items.
|
||||
More than one path can be specified at a time.
|
||||
|
||||
|
||||
**Note:** This overwrites the incoming files, so make backups if you're working on your original, personal dumps.
|
||||
**Note:** This overwrites the input files, so make backups if you're working on your original, personal dumps.
|
||||
|
||||
**Note:** Mixed folders or inputs are also accepted, you can decrypt or encrypt multiple files, regardless of their type. This being said, you can only do encrypt OR decrypt at one time.
|
||||
|
||||
## I feel like something is missing...
|
||||
|
||||
You are! In fact, you may be asking, "Hey, what was that `keys.bin` you mentioned??". I'm glad you asked. It's used only for N3DS files. Since some people don't like reading code, you need the 9 16-bit keys in little endian format (most common extraction methods produce big endian, so keep that in mind). It's recommended that you fill with 0x00 if you don't have access to a particular value so it doesn't mess up the read. They need to be in the following order:
|
||||
You are! In fact, you may be asking, "Hey, what was that `keys.bin` you mentioned??". I'm glad you asked. It's used only for Nintendo 3DS and New 3DS files. Since some people don't like reading code, you need the 9 16-bit keys in little endian format (most common extraction methods produce big endian, so keep that in mind). It's recommended that you fill with 0x00 if you don't have access to a particular value so it doesn't mess up the read. They need to be in the following order:
|
||||
|
||||
- Hardware constant
|
||||
- KeyX0x10
|
||||
@@ -41,7 +48,18 @@ You are! In fact, you may be asking, "Hey, what was that `keys.bin` you mentione
|
||||
- DevKeyX0x25
|
||||
- DevKeyX0x2C
|
||||
|
||||
The last 4 are only required if you use the `-dev` flag. Once again, don't ask for these, please. If you're missing a required key, then things won't work. Don't blame me, blame society. Or something.
|
||||
The last 4 are only required if you use the `-dev` flag. Once again, don't ask for these, please. If you're missing a required key, then things won't work. Don't blame me, blame society. Or something. And yes, I'll fix this being required across the board at some point.
|
||||
|
||||
## But does it work?
|
||||
|
||||
As much as I'd like to think that this program is entirely without flaws, numbers need to speak for themselves sometimes. Here's a list of the supported sets and their current compatibility percentages with woodsec and the Python scripts (as of 2020-12-16):
|
||||
|
||||
- **Nintendo DS** - >99% compatible (Both encryption and decryption)
|
||||
- **Nintendo DSi** - 100% compatible (Both encryption and decryption)
|
||||
- **Nintendo 3DS** - 100% compatible (Decryption only, encryption is currently being tested)
|
||||
- **Nintendo New 3DS** - 100% compatible (Both encryption and decryption)
|
||||
|
||||
Please note the above numbers are based on the current, documented values, not necessarily what is correct. For example, in the Nintendo DS set, there are issues with prototype and unlicensed cartridges, all of which have strange, potentially hacky values in their secure areas.
|
||||
|
||||
## Anything else?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user