mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Implement function in NCA class to re-encrypt decrypted NCAs
This commit is contained in:
parent
c56c8ba8ed
commit
e0ddf17945
2 changed files with 31 additions and 18 deletions
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
|
||||||
namespace LibHac.FsSystem
|
namespace LibHac.FsSystem
|
||||||
|
@ -9,24 +9,27 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
private readonly byte[] _tempBuffer;
|
private readonly byte[] _tempBuffer;
|
||||||
|
|
||||||
private Aes128XtsTransform _decryptor;
|
private Aes128XtsTransform _readTransform;
|
||||||
private Aes128XtsTransform _encryptor;
|
private Aes128XtsTransform _writeTransform;
|
||||||
|
|
||||||
private readonly byte[] _key1;
|
private readonly byte[] _key1;
|
||||||
private readonly byte[] _key2;
|
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)
|
: base(baseStorage, sectorSize, leaveOpen)
|
||||||
{
|
{
|
||||||
if (key == null) throw new NullReferenceException(nameof(key));
|
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");
|
if (key.Length != BlockSize * 2) throw new ArgumentException(nameof(key), $"Key must be {BlockSize * 2} bytes long");
|
||||||
|
|
||||||
_tempBuffer = new byte[sectorSize];
|
_tempBuffer = new byte[sectorSize];
|
||||||
|
_decryptRead = decryptRead;
|
||||||
_key1 = key.Slice(0, BlockSize).ToArray();
|
_key1 = key.Slice(0, BlockSize).ToArray();
|
||||||
_key2 = key.Slice(BlockSize, 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)
|
: base(baseStorage, sectorSize, leaveOpen)
|
||||||
{
|
{
|
||||||
if (key1 == null) throw new NullReferenceException(nameof(key1));
|
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");
|
if (key1.Length != BlockSize || key1.Length != BlockSize) throw new ArgumentException($"Keys must be {BlockSize} bytes long");
|
||||||
|
|
||||||
_tempBuffer = new byte[sectorSize];
|
_tempBuffer = new byte[sectorSize];
|
||||||
|
_decryptRead = decryptRead;
|
||||||
_key1 = key1.ToArray();
|
_key1 = key1.ToArray();
|
||||||
_key2 = key2.ToArray();
|
_key2 = key2.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -43,12 +47,12 @@ namespace LibHac.FsSystem
|
||||||
int size = destination.Length;
|
int size = destination.Length;
|
||||||
long sectorIndex = offset / SectorSize;
|
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));
|
Result rc = base.DoRead(offset, _tempBuffer.AsSpan(0, size));
|
||||||
if (rc.IsFailure()) return rc;
|
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);
|
_tempBuffer.AsSpan(0, size).CopyTo(destination);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -59,10 +63,10 @@ namespace LibHac.FsSystem
|
||||||
int size = source.Length;
|
int size = source.Length;
|
||||||
long sectorIndex = offset / SectorSize;
|
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);
|
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));
|
return base.DoWrite(offset, _tempBuffer.AsSpan(0, size));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -19,9 +19,13 @@ 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);
|
||||||
|
bool encrypted = magic[0] != 'N' && magic[1] != 'C' && magic[2] != 'A';
|
||||||
|
|
||||||
Keyset = keyset;
|
Keyset = keyset;
|
||||||
BaseStorage = storage;
|
BaseStorage = storage;
|
||||||
Header = new NcaHeader(keyset, storage);
|
Header = encrypted ? new NcaHeader(keyset, storage) : new NcaHeader(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetDecryptedKey(int index)
|
public byte[] GetDecryptedKey(int index)
|
||||||
|
@ -117,7 +121,7 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
return Header.IsSectionEnabled(index);
|
return Header.IsSectionEnabled(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IStorage OpenEncryptedStorage(int index)
|
private IStorage OpenSectionStorage(int index)
|
||||||
{
|
{
|
||||||
if (!SectionExists(index)) throw new ArgumentException(nameof(index), Messages.NcaSectionMissing);
|
if (!SectionExists(index)) throw new ArgumentException(nameof(index), Messages.NcaSectionMissing);
|
||||||
|
|
||||||
|
@ -215,7 +219,7 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
|
|
||||||
public IStorage OpenRawStorage(int index)
|
public IStorage OpenRawStorage(int index)
|
||||||
{
|
{
|
||||||
IStorage encryptedStorage = OpenEncryptedStorage(index);
|
IStorage encryptedStorage = OpenSectionStorage(index);
|
||||||
IStorage decryptedStorage = OpenDecryptedStorage(encryptedStorage, index);
|
IStorage decryptedStorage = OpenDecryptedStorage(encryptedStorage, index);
|
||||||
|
|
||||||
return decryptedStorage;
|
return decryptedStorage;
|
||||||
|
@ -353,10 +357,12 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
return OpenStorageWithPatch(patchNca, GetSectionIndexFromType(type), integrityCheckLevel);
|
return OpenStorageWithPatch(patchNca, GetSectionIndexFromType(type), integrityCheckLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage OpenDecryptedNca()
|
public IStorage OpenDecryptedNca() => TransformNca(true);
|
||||||
|
|
||||||
|
public IStorage TransformNca(bool decrypting)
|
||||||
{
|
{
|
||||||
var builder = new ConcatenationStorageBuilder();
|
var builder = new ConcatenationStorageBuilder();
|
||||||
builder.Add(OpenDecryptedHeaderStorage(), 0);
|
builder.Add(TransformHeaderStorage(decrypting), 0);
|
||||||
|
|
||||||
for (int i = 0; i < NcaHeader.SectionCount; i++)
|
for (int i = 0; i < NcaHeader.SectionCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -499,7 +505,9 @@ namespace LibHac.FsSystem.NcaUtils
|
||||||
return new HierarchicalIntegrityVerificationStorage(initInfo, integrityCheckLevel, leaveOpen);
|
return new HierarchicalIntegrityVerificationStorage(initInfo, integrityCheckLevel, leaveOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage OpenDecryptedHeaderStorage()
|
public IStorage OpenDecryptedHeaderStorage() => TransformHeaderStorage(true);
|
||||||
|
|
||||||
|
public IStorage TransformHeaderStorage(bool decrypting)
|
||||||
{
|
{
|
||||||
long firstSectionOffset = long.MaxValue;
|
long firstSectionOffset = long.MaxValue;
|
||||||
bool hasEnabledSection = false;
|
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, decrypting), 1, true);
|
||||||
|
|
||||||
IStorage header = new CachedStorage(new Aes128XtsStorage(BaseStorage.Slice(0, headerSize), Keyset.HeaderKey, NcaHeader.HeaderSectorSize, true), 1, true);
|
|
||||||
int version = ReadHeaderVersion(header);
|
int version = ReadHeaderVersion(header);
|
||||||
|
|
||||||
if (version == 2)
|
if (version == 2)
|
||||||
|
|
Loading…
Reference in a new issue