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;
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue