9 Commits
0.2.3 ... 0.2.4

Author SHA1 Message Date
Matt Nadareski
c8f8a7d99c Bump version to 0.2.4 2022-10-31 10:30:52 -07:00
Matt Nadareski
3ee8c2e79b Update csproj files with full info 2022-10-31 10:27:56 -07:00
Matt Nadareski
7d263886da Force reader buffer refresh to omit stale data 2022-10-27 16:41:22 -07:00
Matt Nadareski
6d1b23ffec Be less clever in code to make debugging easier 2022-10-27 15:28:34 -07:00
Matt Nadareski
92d1c3c5e5 Split NDecrypt.Library; add build targets 2022-10-27 11:27:13 -07:00
Matt Nadareski
855a353e90 Reverse library and exe naming 2022-10-27 11:06:06 -07:00
Matt Nadareski
6dac45f973 Update BouncyCastle to 1.9.0 2022-09-27 13:35:07 -07:00
Matt Nadareski
a6337e0864 Drop .NET 5 support 2022-09-27 12:27:16 -07:00
Matt Nadareski
778d5d4ffc Fix hashing because of .NET 6 2022-09-27 12:19:53 -07:00
47 changed files with 168 additions and 156 deletions

View File

@@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net48;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\NDecrypt\NDecrypt.csproj" />
</ItemGroup>
</Project>

View File

@@ -2,9 +2,9 @@ using System;
using System.IO;
using System.Linq;
using System.Numerics;
using NDecrypt.Tools;
using NDecrypt.Core.Tools;
namespace NDecrypt
namespace NDecrypt.Core
{
public class DecryptArgs
{

View File

@@ -5,9 +5,9 @@ using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace NDecrypt
namespace NDecrypt.Core
{
internal static class Helper
public static class Helper
{
/// <summary>
/// Add an integer value to a number represented by a byte array

View File

@@ -1,4 +1,4 @@
namespace NDecrypt
namespace NDecrypt.Core
{
public interface ITool
{

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<Authors>Matt Nadareski</Authors>
<Copyright>Copyright (c)2018-2022 Matt Nadareski</Copyright>
<RepositoryUrl>https://github.com/SabreTools/NDecrypt</RepositoryUrl>
<Version>0.2.4</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" />
</ItemGroup>
</Project>

View File

@@ -1,6 +1,6 @@
using System;
namespace NDecrypt.Tools
namespace NDecrypt.Core.Tools
{
/// <summary>
/// Available hashing types

View File

@@ -2,7 +2,7 @@
using System.Linq;
using System.Security.Cryptography;
namespace NDecrypt.Tools
namespace NDecrypt.Core.Tools
{
/// <summary>
/// Async hashing class wraper

View File

@@ -4,7 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
namespace NDecrypt.Tools
namespace NDecrypt.Core.Tools
{
public class IniReader : IDisposable
{

View File

@@ -2,8 +2,9 @@ using System;
using System.IO;
using System.Linq;
using System.Numerics;
using NDecrypt.Core;
using NDecrypt.N3DS.Headers;
using static NDecrypt.Helper;
using static NDecrypt.Core.Helper;
namespace NDecrypt.N3DS
{

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<Authors>Matt Nadareski</Authors>
<Copyright>Copyright (c)2018-2022 Matt Nadareski</Copyright>
<RepositoryUrl>https://github.com/SabreTools/NDecrypt</RepositoryUrl>
<Version>0.2.4</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\NDecrypt.Core\NDecrypt.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -2,8 +2,9 @@
using System.IO;
using System.Linq;
using System.Numerics;
using NDecrypt.Core;
using NDecrypt.N3DS.Headers;
using static NDecrypt.Helper;
using static NDecrypt.Core.Helper;
namespace NDecrypt.N3DS
{
@@ -242,7 +243,9 @@ namespace NDecrypt.N3DS
Console.WriteLine($"Partition {ncchHeader.PartitionNumber} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");
var cipher = CreateAESCipher(ncchHeader.NormalKey2C, ncchHeader.PlainIV, decryptArgs.Encrypt);
writer.Write(cipher.ProcessBytes(reader.ReadBytes(Constants.CXTExtendedDataHeaderLength)));
byte[] readBytes = reader.ReadBytes(Constants.CXTExtendedDataHeaderLength);
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);
writer.Flush();
return true;
}
@@ -294,7 +297,10 @@ namespace NDecrypt.N3DS
{
for (int i = 0; i < datalenM; i++)
{
writer.Write(secondCipher.ProcessBytes(firstCipher.ProcessBytes(reader.ReadBytes(1024 * 1024))));
byte[] readBytes = reader.ReadBytes(1024 * 1024);
byte[] firstProcessedBytes = firstCipher.ProcessBytes(readBytes);
byte[] secondProcessedBytes = secondCipher.ProcessBytes(firstProcessedBytes);
writer.Write(secondProcessedBytes);
writer.Flush();
Console.Write($"\rPartition {ncchHeader.PartitionNumber} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {fileHeader.ReadableFileName}... {i} / {datalenM + 1} mb...");
}
@@ -302,7 +308,10 @@ namespace NDecrypt.N3DS
if (datalenB > 0)
{
writer.Write(secondCipher.DoFinal(firstCipher.DoFinal(reader.ReadBytes((int)datalenB))));
byte[] readBytes = reader.ReadBytes((int)datalenB);
byte[] firstFinalBytes = firstCipher.DoFinal(readBytes);
byte[] secondFinalBytes = secondCipher.DoFinal(firstFinalBytes);
writer.Write(secondFinalBytes);
writer.Flush();
}
@@ -324,8 +333,15 @@ namespace NDecrypt.N3DS
Console.WriteLine($"Partition {ncchHeader.PartitionNumber} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");
var exeFSFilenameTable = CreateAESCipher(ncchHeader.NormalKey2C, ncchHeader.ExeFSIV, decryptArgs.Encrypt);
writer.Write(exeFSFilenameTable.ProcessBytes(reader.ReadBytes((int)ncsdHeader.MediaUnitSize)));
var cipher = CreateAESCipher(ncchHeader.NormalKey2C, ncchHeader.ExeFSIV, decryptArgs.Encrypt);
byte[] readBytes = reader.ReadBytes((int)ncsdHeader.MediaUnitSize);
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);
#if NET6_0_OR_GREATER
// In .NET 6.0, this operation is not picked up by the reader, so we have to force it to reload its buffer
reader.BaseStream.Seek(0, SeekOrigin.Begin);
#endif
writer.Flush();
}
@@ -344,7 +360,7 @@ namespace NDecrypt.N3DS
byte[] exefsIVWithOffset = AddToByteArray(ncchHeader.ExeFSIV, ctroffsetE);
var exeFS = CreateAESCipher(ncchHeader.NormalKey2C, exefsIVWithOffset, decryptArgs.Encrypt);
var cipher = CreateAESCipher(ncchHeader.NormalKey2C, exefsIVWithOffset, decryptArgs.Encrypt);
reader.BaseStream.Seek((ncchHeader.Entry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * ncsdHeader.MediaUnitSize, SeekOrigin.Begin);
writer.BaseStream.Seek((ncchHeader.Entry.Offset + ncchHeader.ExeFSOffsetInMediaUnits + 1) * ncsdHeader.MediaUnitSize, SeekOrigin.Begin);
@@ -352,14 +368,18 @@ namespace NDecrypt.N3DS
{
for (int i = 0; i < exefsSizeM; i++)
{
writer.Write(exeFS.ProcessBytes(reader.ReadBytes(1024 * 1024)));
byte[] readBytes = reader.ReadBytes(1024 * 1024);
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);
writer.Flush();
Console.Write($"\rPartition {ncchHeader.PartitionNumber} ExeFS: " + (decryptArgs.Encrypt ? "Encrypting" : "Decrypting") + $": {i} / {exefsSizeM + 1} mb");
}
}
if (exefsSizeB > 0)
{
writer.Write(exeFS.DoFinal(reader.ReadBytes(exefsSizeB)));
byte[] readBytes = reader.ReadBytes(exefsSizeB);
byte[] finalBytes = cipher.DoFinal(readBytes);
writer.Write(finalBytes);
writer.Flush();
}
@@ -425,14 +445,18 @@ namespace NDecrypt.N3DS
{
for (int i = 0; i < romfsSizeM; i++)
{
writer.Write(cipher.ProcessBytes(reader.ReadBytes(1024 * 1024)));
byte[] readBytes = reader.ReadBytes(1024 * 1024);
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);
writer.Flush();
Console.Write($"\rPartition {ncchHeader.PartitionNumber} RomFS: Decrypting: {i} / {romfsSizeM + 1} mb");
}
}
if (romfsSizeB > 0)
{
writer.Write(cipher.DoFinal(reader.ReadBytes(romfsSizeB)));
byte[] readBytes = reader.ReadBytes(romfsSizeB);
byte[] finalBytes = cipher.DoFinal(readBytes);
writer.Write(finalBytes);
writer.Flush();
}
@@ -534,14 +558,18 @@ namespace NDecrypt.N3DS
{
for (int i = 0; i < romfsSizeM; i++)
{
writer.Write(cipher.ProcessBytes(reader.ReadBytes(1024 * 1024)));
byte[] readBytes = reader.ReadBytes(1024 * 1024);
byte[] processedBytes = cipher.ProcessBytes(readBytes);
writer.Write(processedBytes);
writer.Flush();
Console.Write($"\rPartition {ncchHeader.PartitionNumber} RomFS: Encrypting: {i} / {romfsSizeM + 1} mb");
}
}
if (romfsSizeB > 0)
{
writer.Write(cipher.DoFinal(reader.ReadBytes(romfsSizeB)));
byte[] readBytes = reader.ReadBytes(romfsSizeB);
byte[] finalBytes = cipher.DoFinal(readBytes);
writer.Write(finalBytes);
writer.Flush();
}

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using NDecrypt.Core;
using NDecrypt.Nitro.Headers;
namespace NDecrypt.Nitro

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
<Authors>Matt Nadareski</Authors>
<Copyright>Copyright (c)2018-2022 Matt Nadareski</Copyright>
<RepositoryUrl>https://github.com/SabreTools/NDecrypt</RepositoryUrl>
<Version>0.2.4</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\NDecrypt.Core\NDecrypt.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,16 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.156
# Visual Studio Version 17
VisualStudioVersion = 17.3.32922.545
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{31CE0445-F693-4C9A-B6CD-499C38CFF7FE}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NDecrypt", "NDecrypt\NDecrypt.csproj", "{91C54370-5741-4742-B2E9-EC498551AD1C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NDecrypt", "NDecrypt\NDecrypt.csproj", "{05566793-831F-4AE1-A6D2-F9214F36618E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NDecrypt.CMD", "NDecrypt.CMD\NDecrypt.CMD.csproj", "{05566793-831F-4AE1-A6D2-F9214F36618E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NDecrypt.Core", "NDecrypt.Core\NDecrypt.Core.csproj", "{91C54370-5741-4742-B2E9-EC498551AD1C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NDecrypt.N3DS", "NDecrypt.N3DS\NDecrypt.N3DS.csproj", "{F0A33533-B248-4D62-95CC-47DFC9721A11}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NDecrypt.Nitro", "NDecrypt.Nitro\NDecrypt.Nitro.csproj", "{1D2AE261-86FE-44E4-A7D3-C43AA5FB8523}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -18,14 +22,22 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{91C54370-5741-4742-B2E9-EC498551AD1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91C54370-5741-4742-B2E9-EC498551AD1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91C54370-5741-4742-B2E9-EC498551AD1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91C54370-5741-4742-B2E9-EC498551AD1C}.Release|Any CPU.Build.0 = Release|Any CPU
{05566793-831F-4AE1-A6D2-F9214F36618E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{05566793-831F-4AE1-A6D2-F9214F36618E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{05566793-831F-4AE1-A6D2-F9214F36618E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{05566793-831F-4AE1-A6D2-F9214F36618E}.Release|Any CPU.Build.0 = Release|Any CPU
{91C54370-5741-4742-B2E9-EC498551AD1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91C54370-5741-4742-B2E9-EC498551AD1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91C54370-5741-4742-B2E9-EC498551AD1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91C54370-5741-4742-B2E9-EC498551AD1C}.Release|Any CPU.Build.0 = Release|Any CPU
{F0A33533-B248-4D62-95CC-47DFC9721A11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0A33533-B248-4D62-95CC-47DFC9721A11}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0A33533-B248-4D62-95CC-47DFC9721A11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0A33533-B248-4D62-95CC-47DFC9721A11}.Release|Any CPU.Build.0 = Release|Any CPU
{1D2AE261-86FE-44E4-A7D3-C43AA5FB8523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D2AE261-86FE-44E4-A7D3-C43AA5FB8523}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D2AE261-86FE-44E4-A7D3-C43AA5FB8523}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D2AE261-86FE-44E4-A7D3-C43AA5FB8523}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -3,10 +3,9 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Compress.ThreadReaders;
using NDecrypt.Tools;
using NDecrypt.Core.Tools;
namespace NDecrypt.CMD
namespace NDecrypt
{
internal static class HashingHelper
{
@@ -39,10 +38,8 @@ namespace NDecrypt.CMD
};
// Initialize the hashing helpers
var loadBuffer = new ThreadLoadBuffer(inputStream);
int buffersize = 3 * 1024 * 1024;
byte[] buffer0 = new byte[buffersize];
byte[] buffer1 = new byte[buffersize];
byte[] buffer = new byte[buffersize];
/*
Please note that some of the following code is adapted from
@@ -52,38 +49,26 @@ namespace NDecrypt.CMD
been tweaked to better fit this code base.
*/
// Pre load the first buffer
// Pre load the buffer
int next = buffersize > size ? (int)size : buffersize;
int current = inputStream.Read(buffer, 0, next);
long refsize = size;
int next = refsize > buffersize ? buffersize : (int)refsize;
inputStream.Read(buffer0, 0, next);
int current = next;
refsize -= next;
bool bufferSelect = true;
while (current > 0)
while (refsize > 0)
{
// Trigger the buffer load on the second buffer
next = refsize > buffersize ? buffersize : (int)refsize;
if (next > 0)
loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next);
byte[] buffer = bufferSelect ? buffer0 : buffer1;
// Run hashes in parallel
Parallel.ForEach(hashers, h => h.Process(buffer, current));
if (current > 0)
Parallel.ForEach(hashers, h => h.Process(buffer, current));
// Load the next buffer
refsize -= current;
next = buffersize > refsize ? (int)refsize : buffersize;
// Wait for the load buffer worker, if needed
if (next > 0)
loadBuffer.Wait();
// Setup for the next hashing step
current = next;
refsize -= next;
bufferSelect = !bufferSelect;
current = inputStream.Read(buffer, 0, next);
}
// Finalize all hashing helpers
loadBuffer.Finish();
Parallel.ForEach(hashers, h => h.Terminate());
// Get the results
@@ -94,7 +79,6 @@ namespace NDecrypt.CMD
+ $"SHA256: {ByteArrayToString(hashers.First(h => h.HashType == Hash.SHA256).GetHash()) ?? ""}\n";
// Dispose of the hashers
loadBuffer.Dispose();
hashers.ForEach(h => h.Dispose());
return result;

View File

@@ -1,11 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<TargetFrameworks>net48;netcoreapp3.1;net6.0</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputType>Exe</OutputType>
<Title>NDecrypt</Title>
<AssemblyName>NDecrypt</AssemblyName>
<Description>DS/3DS Encryption Tool</Description>
<Authors>Matt Nadareski</Authors>
<Product>NDecrypt</Product>
<Copyright>Copyright (c)2018-2022 Matt Nadareski</Copyright>
<RepositoryUrl>https://github.com/SabreTools/NDecrypt</RepositoryUrl>
<Version>0.2.4</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.NetCore" Version="1.8.10" />
<ProjectReference Include="..\NDecrypt.Core\NDecrypt.Core.csproj" />
<ProjectReference Include="..\NDecrypt.N3DS\NDecrypt.N3DS.csproj" />
<ProjectReference Include="..\NDecrypt.Nitro\NDecrypt.Nitro.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,10 +1,11 @@
using System;
using System.IO;
using System.Reflection;
using NDecrypt.Core;
using NDecrypt.N3DS;
using NDecrypt.Nitro;
namespace NDecrypt.CMD
namespace NDecrypt
{
class Program
{

View File

@@ -1,79 +0,0 @@
using System;
using System.IO;
using System.Threading;
namespace Compress.ThreadReaders
{
public class ThreadLoadBuffer : IDisposable
{
private readonly AutoResetEvent _waitEvent;
private readonly AutoResetEvent _outEvent;
private readonly Thread _tWorker;
private byte[] _buffer;
private int _size;
private readonly Stream _ds;
private bool _finished;
public bool errorState;
public int SizeRead;
public ThreadLoadBuffer(Stream ds)
{
_waitEvent = new AutoResetEvent(false);
_outEvent = new AutoResetEvent(false);
_finished = false;
_ds = ds;
errorState = false;
_tWorker = new Thread(MainLoop);
_tWorker.Start();
}
public void Dispose()
{
_waitEvent.Close();
_outEvent.Close();
}
private void MainLoop()
{
while (true)
{
_waitEvent.WaitOne();
if (_finished)
{
break;
}
try
{
SizeRead = _ds.Read(_buffer, 0, _size);
}
catch (Exception)
{
errorState = true;
}
_outEvent.Set();
}
}
public void Trigger(byte[] buffer, int size)
{
_buffer = buffer;
_size = size;
_waitEvent.Set();
}
public void Wait()
{
_outEvent.WaitOne();
}
public void Finish()
{
_finished = true;
_waitEvent.Set();
_tWorker.Join();
}
}
}