mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Update AesCtrCounterExtendedStorage for 14.0.0
This commit is contained in:
parent
398a142b27
commit
2241a7ced3
1 changed files with 43 additions and 22 deletions
|
@ -17,11 +17,11 @@ namespace LibHac.FsSystem;
|
||||||
/// <remarks><para>The base data used for this storage comes with a table of ranges and counter values that are used
|
/// <remarks><para>The base data used for this storage comes with a table of ranges and counter values that are used
|
||||||
/// to decrypt each range. This encryption scheme is used for encrypting content updates so that no counter values
|
/// to decrypt each range. This encryption scheme is used for encrypting content updates so that no counter values
|
||||||
/// are ever reused.</para>
|
/// are ever reused.</para>
|
||||||
/// <para>Based on FS 13.1.0 (nnSdk 13.4.0)</para></remarks>
|
/// <para>Based on FS 14.1.0 (nnSdk 14.3.0)</para></remarks>
|
||||||
public class AesCtrCounterExtendedStorage : IStorage
|
public class AesCtrCounterExtendedStorage : IStorage
|
||||||
{
|
{
|
||||||
public delegate Result DecryptFunction(Span<byte> destination, int index, ReadOnlySpan<byte> encryptedKey,
|
public delegate Result DecryptFunction(Span<byte> destination, int index, int generation,
|
||||||
ReadOnlySpan<byte> iv, ReadOnlySpan<byte> source);
|
ReadOnlySpan<byte> encryptedKey, ReadOnlySpan<byte> iv, ReadOnlySpan<byte> source);
|
||||||
|
|
||||||
public interface IDecryptor : IDisposable
|
public interface IDecryptor : IDisposable
|
||||||
{
|
{
|
||||||
|
@ -32,9 +32,16 @@ public class AesCtrCounterExtendedStorage : IStorage
|
||||||
public struct Entry
|
public struct Entry
|
||||||
{
|
{
|
||||||
public Array8<byte> Offset;
|
public Array8<byte> Offset;
|
||||||
public int Reserved;
|
public Encryption EncryptionValue;
|
||||||
|
public Array3<byte> Reserved;
|
||||||
public int Generation;
|
public int Generation;
|
||||||
|
|
||||||
|
public enum Encryption : byte
|
||||||
|
{
|
||||||
|
Encrypted = 0,
|
||||||
|
NotEncrypted = 1
|
||||||
|
}
|
||||||
|
|
||||||
public void SetOffset(long value)
|
public void SetOffset(long value)
|
||||||
{
|
{
|
||||||
BinaryPrimitives.WriteInt64LittleEndian(Offset.Items, value);
|
BinaryPrimitives.WriteInt64LittleEndian(Offset.Items, value);
|
||||||
|
@ -74,9 +81,9 @@ public class AesCtrCounterExtendedStorage : IStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result CreateExternalDecryptor(ref UniqueRef<IDecryptor> outDecryptor,
|
public static Result CreateExternalDecryptor(ref UniqueRef<IDecryptor> outDecryptor,
|
||||||
DecryptFunction decryptFunction, int keyIndex)
|
DecryptFunction decryptFunction, int keyIndex, int keyGeneration)
|
||||||
{
|
{
|
||||||
using var decryptor = new UniqueRef<IDecryptor>(new ExternalDecryptor(decryptFunction, keyIndex));
|
using var decryptor = new UniqueRef<IDecryptor>(new ExternalDecryptor(decryptFunction, keyIndex, keyGeneration));
|
||||||
|
|
||||||
if (!decryptor.HasValue)
|
if (!decryptor.HasValue)
|
||||||
return ResultFs.AllocationMemoryFailedInAesCtrCounterExtendedStorageA.Log();
|
return ResultFs.AllocationMemoryFailedInAesCtrCounterExtendedStorageA.Log();
|
||||||
|
@ -159,9 +166,18 @@ public class AesCtrCounterExtendedStorage : IStorage
|
||||||
Assert.SdkRequiresGreaterEqual(counterOffset, 0);
|
Assert.SdkRequiresGreaterEqual(counterOffset, 0);
|
||||||
Assert.SdkRequiresNotNull(in decryptor);
|
Assert.SdkRequiresNotNull(in decryptor);
|
||||||
|
|
||||||
Result rc = _table.Initialize(allocator, in nodeStorage, in entryStorage, NodeSize, Unsafe.SizeOf<Entry>(),
|
Result rc;
|
||||||
entryCount);
|
|
||||||
if (rc.IsFailure()) return rc.Miss();
|
if (entryCount > 0)
|
||||||
|
{
|
||||||
|
rc = _table.Initialize(allocator, in nodeStorage, in entryStorage, NodeSize, Unsafe.SizeOf<Entry>(),
|
||||||
|
entryCount);
|
||||||
|
if (rc.IsFailure()) return rc.Miss();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_table.Initialize(NodeSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
rc = dataStorage.GetSize(out long dataStorageSize);
|
rc = dataStorage.GetSize(out long dataStorageSize);
|
||||||
if (rc.IsFailure()) return rc.Miss();
|
if (rc.IsFailure()) return rc.Miss();
|
||||||
|
@ -279,20 +295,23 @@ public class AesCtrCounterExtendedStorage : IStorage
|
||||||
long readSize = Math.Min(remainingSize, dataSize);
|
long readSize = Math.Min(remainingSize, dataSize);
|
||||||
Assert.SdkLessEqual(readSize, destination.Length);
|
Assert.SdkLessEqual(readSize, destination.Length);
|
||||||
|
|
||||||
// Create the counter for the first data block we're decrypting.
|
if (entry.EncryptionValue == Entry.Encryption.Encrypted)
|
||||||
long counterOffset = _counterOffset + entryStartOffset + dataOffset;
|
|
||||||
var upperIv = new NcaAesCtrUpperIv
|
|
||||||
{
|
{
|
||||||
Generation = (uint)entry.Generation,
|
// Create the counter for the first data block we're decrypting.
|
||||||
SecureValue = _secureValue
|
long counterOffset = _counterOffset + entryStartOffset + dataOffset;
|
||||||
};
|
var upperIv = new NcaAesCtrUpperIv
|
||||||
|
{
|
||||||
|
Generation = (uint)entry.Generation,
|
||||||
|
SecureValue = _secureValue
|
||||||
|
};
|
||||||
|
|
||||||
Unsafe.SkipInit(out Array16<byte> counter);
|
Unsafe.SkipInit(out Array16<byte> counter);
|
||||||
AesCtrStorage.MakeIv(counter.Items, upperIv.Value, counterOffset);
|
AesCtrStorage.MakeIv(counter.Items, upperIv.Value, counterOffset);
|
||||||
|
|
||||||
// Decrypt the data from the current entry.
|
// Decrypt the data from the current entry.
|
||||||
rc = _decryptor.Get.Decrypt(currentData.Slice(0, (int)dataSize), _key, counter);
|
rc = _decryptor.Get.Decrypt(currentData.Slice(0, (int)dataSize), _key, counter);
|
||||||
if (rc.IsFailure()) return rc.Miss();
|
if (rc.IsFailure()) return rc.Miss();
|
||||||
|
}
|
||||||
|
|
||||||
// Advance the current offsets.
|
// Advance the current offsets.
|
||||||
currentData = currentData.Slice((int)dataSize);
|
currentData = currentData.Slice((int)dataSize);
|
||||||
|
@ -402,13 +421,15 @@ public class AesCtrCounterExtendedStorage : IStorage
|
||||||
{
|
{
|
||||||
private DecryptFunction _decryptFunction;
|
private DecryptFunction _decryptFunction;
|
||||||
private int _keyIndex;
|
private int _keyIndex;
|
||||||
|
private int _keyGeneration;
|
||||||
|
|
||||||
public ExternalDecryptor(DecryptFunction decryptFunction, int keyIndex)
|
public ExternalDecryptor(DecryptFunction decryptFunction, int keyIndex, int keyGeneration)
|
||||||
{
|
{
|
||||||
Assert.SdkRequiresNotNull(decryptFunction);
|
Assert.SdkRequiresNotNull(decryptFunction);
|
||||||
|
|
||||||
_decryptFunction = decryptFunction;
|
_decryptFunction = decryptFunction;
|
||||||
_keyIndex = keyIndex;
|
_keyIndex = keyIndex;
|
||||||
|
_keyGeneration = keyGeneration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() { }
|
public void Dispose() { }
|
||||||
|
@ -435,7 +456,7 @@ public class AesCtrCounterExtendedStorage : IStorage
|
||||||
Span<byte> dstBuffer = destination.Slice(currentOffset, currentSize);
|
Span<byte> dstBuffer = destination.Slice(currentOffset, currentSize);
|
||||||
Span<byte> workBuffer = pooledBuffer.GetBuffer().Slice(0, currentSize);
|
Span<byte> workBuffer = pooledBuffer.GetBuffer().Slice(0, currentSize);
|
||||||
|
|
||||||
Result rc = _decryptFunction(workBuffer, _keyIndex, encryptedKey, counter, dstBuffer);
|
Result rc = _decryptFunction(workBuffer, _keyIndex, _keyGeneration, encryptedKey, counter, dstBuffer);
|
||||||
if (rc.IsFailure()) return rc.Miss();
|
if (rc.IsFailure()) return rc.Miss();
|
||||||
|
|
||||||
workBuffer.CopyTo(dstBuffer);
|
workBuffer.CopyTo(dstBuffer);
|
||||||
|
|
Loading…
Reference in a new issue