mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Avoid false positives in detection of unencrypted NCAs
This commit is contained in:
parent
a07e17c369
commit
30273bf3ef
2 changed files with 46 additions and 20 deletions
|
@ -14,7 +14,7 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
public class Nca
|
public class Nca
|
||||||
{
|
{
|
||||||
private Keyset Keyset { get; }
|
private Keyset Keyset { get; }
|
||||||
private bool IsEncrypted { get; set; }
|
private bool IsEncrypted => Header.IsEncrypted;
|
||||||
|
|
||||||
private byte[] Nca0KeyArea { get; set; }
|
private byte[] Nca0KeyArea { get; set; }
|
||||||
private IStorage Nca0TransformedBody { get; set; }
|
private IStorage Nca0TransformedBody { get; set; }
|
||||||
|
@ -25,13 +25,9 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
|
|
||||||
public Nca(Keyset keyset, IStorage storage)
|
public Nca(Keyset keyset, IStorage storage)
|
||||||
{
|
{
|
||||||
Span<byte> magic = stackalloc byte[3];
|
|
||||||
storage.Read(0x200, magic);
|
|
||||||
IsEncrypted = magic[0] != 'N' && magic[1] != 'C' && magic[2] != 'A';
|
|
||||||
|
|
||||||
Keyset = keyset;
|
Keyset = keyset;
|
||||||
BaseStorage = storage;
|
BaseStorage = storage;
|
||||||
Header = IsEncrypted ? new NcaHeader(keyset, storage) : new NcaHeader(storage);
|
Header = new NcaHeader(keyset, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetDecryptedKey(int index)
|
public byte[] GetDecryptedKey(int index)
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Crypto;
|
using LibHac.Crypto;
|
||||||
|
using LibHac.Diag;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
|
||||||
namespace LibHac.FsSystem.NcaUtils
|
namespace LibHac.FsSystem.NcaUtils
|
||||||
|
@ -17,21 +18,15 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
|
|
||||||
private readonly Memory<byte> _header;
|
private readonly Memory<byte> _header;
|
||||||
|
|
||||||
public NcaVersion FormatVersion { get; private set; }
|
public NcaVersion FormatVersion { get; }
|
||||||
|
public bool IsEncrypted { get; }
|
||||||
public NcaHeader(IStorage headerStorage)
|
|
||||||
{
|
|
||||||
_header = new byte[HeaderSize];
|
|
||||||
Span<byte> headerSpan = _header.Span;
|
|
||||||
headerStorage.Read(0, headerSpan).ThrowIfFailure();
|
|
||||||
|
|
||||||
FormatVersion = DetectNcaVersion(headerSpan);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NcaHeader(Keyset keyset, IStorage headerStorage)
|
public NcaHeader(Keyset keyset, IStorage headerStorage)
|
||||||
{
|
{
|
||||||
_header = DecryptHeader(keyset, headerStorage);
|
(byte[] header, bool isEncrypted) = DecryptHeader(keyset, headerStorage);
|
||||||
|
|
||||||
|
_header = header;
|
||||||
|
IsEncrypted = isEncrypted;
|
||||||
FormatVersion = DetectNcaVersion(_header.Span);
|
FormatVersion = DetectNcaVersion(_header.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,10 +195,22 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
return (long)blockIndex * BlockSize;
|
return (long)blockIndex * BlockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] DecryptHeader(Keyset keyset, IStorage storage)
|
private static (byte[] header, bool isEncrypted) DecryptHeader(Keyset keyset, IStorage storage)
|
||||||
{
|
{
|
||||||
var buf = new byte[HeaderSize];
|
var buf = new byte[HeaderSize];
|
||||||
storage.Read(0, buf);
|
storage.Read(0, buf).ThrowIfFailure();
|
||||||
|
|
||||||
|
if (CheckIfDecrypted(buf))
|
||||||
|
{
|
||||||
|
int decVersion = buf[0x203] - '0';
|
||||||
|
|
||||||
|
if (decVersion != 0 && decVersion != 2 && decVersion != 3)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"NCA version {decVersion} is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (buf, false);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] key1 = keyset.HeaderKey.AsSpan(0, 0x10).ToArray();
|
byte[] key1 = keyset.HeaderKey.AsSpan(0, 0x10).ToArray();
|
||||||
byte[] key2 = keyset.HeaderKey.AsSpan(0x10, 0x10).ToArray();
|
byte[] key2 = keyset.HeaderKey.AsSpan(0x10, 0x10).ToArray();
|
||||||
|
@ -240,7 +247,30 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
throw new NotSupportedException($"NCA version {version} is not supported.");
|
throw new NotSupportedException($"NCA version {version} is not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return (buf, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CheckIfDecrypted(ReadOnlySpan<byte> header)
|
||||||
|
{
|
||||||
|
Assert.AssertTrue(header.Length >= 0x400);
|
||||||
|
|
||||||
|
// Check the magic value
|
||||||
|
if (header[0x200] != 'N' || header[0x201] != 'C' || header[0x202] != 'A')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check the version in the magic value
|
||||||
|
if (!StringUtils.IsDigit(header[0x203]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Is the distribution type valid?
|
||||||
|
if (header[0x204] > (int)DistributionType.GameCard)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Is the content type valid?
|
||||||
|
if (header[0x205] > (int)NcaContentType.PublicData)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NcaVersion DetectNcaVersion(ReadOnlySpan<byte> header)
|
private static NcaVersion DetectNcaVersion(ReadOnlySpan<byte> header)
|
||||||
|
|
Loading…
Reference in a new issue