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
|
||||
{
|
||||
private Keyset Keyset { get; }
|
||||
private bool IsEncrypted { get; set; }
|
||||
private bool IsEncrypted => Header.IsEncrypted;
|
||||
|
||||
private byte[] Nca0KeyArea { get; set; }
|
||||
private IStorage Nca0TransformedBody { get; set; }
|
||||
|
@ -25,13 +25,9 @@ namespace LibHac.FsSystem.NcaUtils
|
|||
|
||||
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;
|
||||
BaseStorage = storage;
|
||||
Header = IsEncrypted ? new NcaHeader(keyset, storage) : new NcaHeader(storage);
|
||||
Header = new NcaHeader(keyset, storage);
|
||||
}
|
||||
|
||||
public byte[] GetDecryptedKey(int index)
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
|
|||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Crypto;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSystem.NcaUtils
|
||||
|
@ -17,21 +18,15 @@ namespace LibHac.FsSystem.NcaUtils
|
|||
|
||||
private readonly Memory<byte> _header;
|
||||
|
||||
public NcaVersion FormatVersion { get; private set; }
|
||||
|
||||
public NcaHeader(IStorage headerStorage)
|
||||
{
|
||||
_header = new byte[HeaderSize];
|
||||
Span<byte> headerSpan = _header.Span;
|
||||
headerStorage.Read(0, headerSpan).ThrowIfFailure();
|
||||
|
||||
FormatVersion = DetectNcaVersion(headerSpan);
|
||||
}
|
||||
public NcaVersion FormatVersion { get; }
|
||||
public bool IsEncrypted { get; }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -200,10 +195,22 @@ namespace LibHac.FsSystem.NcaUtils
|
|||
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];
|
||||
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[] key2 = keyset.HeaderKey.AsSpan(0x10, 0x10).ToArray();
|
||||
|
@ -240,7 +247,30 @@ namespace LibHac.FsSystem.NcaUtils
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue