Implement function in NCA class to re-encrypt decrypted NCAs

This commit is contained in:
Xpl0itR 2020-07-16 19:31:57 +01:00 committed by Alex Barney
parent c56c8ba8ed
commit e0ddf17945
2 changed files with 31 additions and 18 deletions

View file

@ -1,4 +1,4 @@
using System;
using System;
using LibHac.Fs;
namespace LibHac.FsSystem
@ -9,24 +9,27 @@ namespace LibHac.FsSystem
private readonly byte[] _tempBuffer;
private Aes128XtsTransform _decryptor;
private Aes128XtsTransform _encryptor;
private Aes128XtsTransform _readTransform;
private Aes128XtsTransform _writeTransform;
private readonly byte[] _key1;
private readonly byte[] _key2;
public Aes128XtsStorage(IStorage baseStorage, Span<byte> key, int sectorSize, bool leaveOpen)
private readonly bool _decryptRead;
public Aes128XtsStorage(IStorage baseStorage, Span<byte> key, int sectorSize, bool leaveOpen, bool decryptRead = true)
: base(baseStorage, sectorSize, leaveOpen)
{
if (key == null) throw new NullReferenceException(nameof(key));
if (key.Length != BlockSize * 2) throw new ArgumentException(nameof(key), $"Key must be {BlockSize * 2} bytes long");
_tempBuffer = new byte[sectorSize];
_decryptRead = decryptRead;
_key1 = key.Slice(0, BlockSize).ToArray();
_key2 = key.Slice(BlockSize, BlockSize).ToArray();
}
public Aes128XtsStorage(IStorage baseStorage, Span<byte> key1, Span<byte> key2, int sectorSize, bool leaveOpen)
public Aes128XtsStorage(IStorage baseStorage, Span<byte> key1, Span<byte> key2, int sectorSize, bool leaveOpen, bool decryptRead = true)
: base(baseStorage, sectorSize, leaveOpen)
{
if (key1 == null) throw new NullReferenceException(nameof(key1));
@ -34,6 +37,7 @@ namespace LibHac.FsSystem
if (key1.Length != BlockSize || key1.Length != BlockSize) throw new ArgumentException($"Keys must be {BlockSize} bytes long");
_tempBuffer = new byte[sectorSize];
_decryptRead = decryptRead;
_key1 = key1.ToArray();
_key2 = key2.ToArray();
}
@ -43,12 +47,12 @@ namespace LibHac.FsSystem
int size = destination.Length;
long sectorIndex = offset / SectorSize;
if (_decryptor == null) _decryptor = new Aes128XtsTransform(_key1, _key2, true);
if (_readTransform == null) _readTransform = new Aes128XtsTransform(_key1, _key2, _decryptRead);
Result rc = base.DoRead(offset, _tempBuffer.AsSpan(0, size));
if (rc.IsFailure()) return rc;
_decryptor.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex);
_readTransform.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex);
_tempBuffer.AsSpan(0, size).CopyTo(destination);
return Result.Success;
@ -59,10 +63,10 @@ namespace LibHac.FsSystem
int size = source.Length;
long sectorIndex = offset / SectorSize;
if (_encryptor == null) _encryptor = new Aes128XtsTransform(_key1, _key2, false);
if (_writeTransform == null) _writeTransform = new Aes128XtsTransform(_key1, _key2, !_decryptRead);
source.CopyTo(_tempBuffer);
_encryptor.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex);
_writeTransform.TransformBlock(_tempBuffer, 0, size, (ulong)sectorIndex);
return base.DoWrite(offset, _tempBuffer.AsSpan(0, size));
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@ -19,9 +19,13 @@ namespace LibHac.FsSystem.NcaUtils
public Nca(Keyset keyset, IStorage storage)
{
Span<byte> magic = stackalloc byte[3];
storage.Read(0x200, magic);
bool encrypted = magic[0] != 'N' && magic[1] != 'C' && magic[2] != 'A';
Keyset = keyset;
BaseStorage = storage;
Header = new NcaHeader(keyset, storage);
Header = encrypted ? new NcaHeader(keyset, storage) : new NcaHeader(storage);
}
public byte[] GetDecryptedKey(int index)
@ -117,7 +121,7 @@ namespace LibHac.FsSystem.NcaUtils
return Header.IsSectionEnabled(index);
}
private IStorage OpenEncryptedStorage(int index)
private IStorage OpenSectionStorage(int index)
{
if (!SectionExists(index)) throw new ArgumentException(nameof(index), Messages.NcaSectionMissing);
@ -215,7 +219,7 @@ namespace LibHac.FsSystem.NcaUtils
public IStorage OpenRawStorage(int index)
{
IStorage encryptedStorage = OpenEncryptedStorage(index);
IStorage encryptedStorage = OpenSectionStorage(index);
IStorage decryptedStorage = OpenDecryptedStorage(encryptedStorage, index);
return decryptedStorage;
@ -353,10 +357,12 @@ namespace LibHac.FsSystem.NcaUtils
return OpenStorageWithPatch(patchNca, GetSectionIndexFromType(type), integrityCheckLevel);
}
public IStorage OpenDecryptedNca()
public IStorage OpenDecryptedNca() => TransformNca(true);
public IStorage TransformNca(bool decrypting)
{
var builder = new ConcatenationStorageBuilder();
builder.Add(OpenDecryptedHeaderStorage(), 0);
builder.Add(TransformHeaderStorage(decrypting), 0);
for (int i = 0; i < NcaHeader.SectionCount; i++)
{
@ -499,7 +505,9 @@ namespace LibHac.FsSystem.NcaUtils
return new HierarchicalIntegrityVerificationStorage(initInfo, integrityCheckLevel, leaveOpen);
}
public IStorage OpenDecryptedHeaderStorage()
public IStorage OpenDecryptedHeaderStorage() => TransformHeaderStorage(true);
public IStorage TransformHeaderStorage(bool decrypting)
{
long firstSectionOffset = long.MaxValue;
bool hasEnabledSection = false;
@ -514,9 +522,10 @@ namespace LibHac.FsSystem.NcaUtils
}
}
long headerSize = hasEnabledSection ? NcaHeader.HeaderSize : firstSectionOffset;
long headerSize = hasEnabledSection ? firstSectionOffset : NcaHeader.HeaderSize;
IStorage header = new CachedStorage(new Aes128XtsStorage(BaseStorage.Slice(0, headerSize), Keyset.HeaderKey, NcaHeader.HeaderSectorSize, true), 1, true);
IStorage header = new CachedStorage(new Aes128XtsStorage(BaseStorage.Slice(0, headerSize), Keyset.HeaderKey, NcaHeader.HeaderSectorSize, true, decrypting), 1, true);
int version = ReadHeaderVersion(header);
if (version == 2)