mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add ExternalKeySet. Use C# 8.0
This commit is contained in:
parent
d7f3e94577
commit
d291500b28
16 changed files with 266 additions and 59 deletions
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common
|
||||
|
@ -6,13 +7,14 @@ namespace LibHac.Common
|
|||
/// <summary>
|
||||
/// A generic 128-bit ID value.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct Id128 : IEquatable<Id128>, IComparable<Id128>, IComparable
|
||||
{
|
||||
public readonly ulong High;
|
||||
public readonly ulong Low;
|
||||
|
||||
public static readonly Id128 InvalidId = new Id128(0, 0);
|
||||
public static Id128 Zero => default;
|
||||
|
||||
public Id128(ulong high, ulong low)
|
||||
{
|
||||
|
@ -28,6 +30,8 @@ namespace LibHac.Common
|
|||
Low = longs[1];
|
||||
}
|
||||
|
||||
public override string ToString() => AsBytes().ToHexString();
|
||||
|
||||
public bool Equals(Id128 other)
|
||||
{
|
||||
return High == other.High && Low == other.Low;
|
||||
|
@ -48,11 +52,9 @@ namespace LibHac.Common
|
|||
|
||||
public int CompareTo(Id128 other)
|
||||
{
|
||||
// ReSharper disable ImpureMethodCallOnReadonlyValueField
|
||||
int highComparison = High.CompareTo(other.High);
|
||||
if (highComparison != 0) return highComparison;
|
||||
return Low.CompareTo(other.Low);
|
||||
// ReSharper restore ImpureMethodCallOnReadonlyValueField
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
|
@ -61,7 +63,7 @@ namespace LibHac.Common
|
|||
return obj is Id128 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(Id128)}");
|
||||
}
|
||||
|
||||
public void ToBytes(Span<byte> output)
|
||||
public readonly void ToBytes(Span<byte> output)
|
||||
{
|
||||
Span<ulong> longs = MemoryMarshal.Cast<byte, ulong>(output);
|
||||
|
||||
|
@ -69,33 +71,17 @@ namespace LibHac.Common
|
|||
longs[1] = Low;
|
||||
}
|
||||
|
||||
public static bool operator ==(Id128 left, Id128 right)
|
||||
public ReadOnlySpan<byte> AsBytes()
|
||||
{
|
||||
return left.Equals(right);
|
||||
return SpanHelpers.AsByteSpan(ref this);
|
||||
}
|
||||
|
||||
public static bool operator !=(Id128 left, Id128 right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
public static bool operator <(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) < 0;
|
||||
}
|
||||
public static bool operator ==(Id128 left, Id128 right) => left.Equals(right);
|
||||
public static bool operator !=(Id128 left, Id128 right) => !left.Equals(right);
|
||||
|
||||
public static bool operator >(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) > 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) <= 0;
|
||||
}
|
||||
|
||||
public static bool operator >=(Id128 left, Id128 right)
|
||||
{
|
||||
return left.CompareTo(right) >= 0;
|
||||
}
|
||||
public static bool operator <(Id128 left, Id128 right) => left.CompareTo(right) < 0;
|
||||
public static bool operator >(Id128 left, Id128 right) => left.CompareTo(right) > 0;
|
||||
public static bool operator <=(Id128 left, Id128 right) => left.CompareTo(right) <= 0;
|
||||
public static bool operator >=(Id128 left, Id128 right) => left.CompareTo(right) >= 0;
|
||||
}
|
||||
}
|
||||
|
|
48
src/LibHac/Common/Key128.cs
Normal file
48
src/LibHac/Common/Key128.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common
|
||||
{
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct Key128 : IEquatable<Key128>
|
||||
{
|
||||
private readonly ulong _dummy1;
|
||||
private readonly ulong _dummy2;
|
||||
|
||||
public Span<byte> Value => SpanHelpers.AsByteSpan(ref this);
|
||||
|
||||
public Key128(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
ReadOnlySpan<ulong> longs = MemoryMarshal.Cast<byte, ulong>(bytes);
|
||||
|
||||
_dummy1 = longs[0];
|
||||
_dummy2 = longs[1];
|
||||
}
|
||||
|
||||
public override string ToString() => Value.ToHexString();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Key128 key && Equals(key);
|
||||
}
|
||||
|
||||
public bool Equals(Key128 other)
|
||||
{
|
||||
return _dummy1 == other._dummy1 &&
|
||||
_dummy2 == other._dummy2;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hashCode = -1653217991;
|
||||
hashCode = hashCode * -1521134295 + _dummy1.GetHashCode();
|
||||
hashCode = hashCode * -1521134295 + _dummy2.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public static bool operator ==(Key128 left, Key128 right) => left.Equals(right);
|
||||
public static bool operator !=(Key128 left, Key128 right) => !(left == right);
|
||||
}
|
||||
}
|
|
@ -121,7 +121,7 @@ namespace LibHac.Fs
|
|||
|
||||
if (!openMode.HasFlag(OpenMode.AllowAppend))
|
||||
{
|
||||
return ResultFs.AllowAppendRequiredForImplicitExtension.Log();
|
||||
return ResultFs.FileExtensionWithoutOpenModeAllowAppend.Log();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
public static Result InsufficientFreeSpace => new Result(ModuleFs, 30);
|
||||
public static Result MountNameAlreadyExists => new Result(ModuleFs, 60);
|
||||
|
||||
public static Result PartitionNotFound => new Result(ModuleFs, 1001);
|
||||
public static Result TargetNotFound => new Result(ModuleFs, 1002);
|
||||
public static Result ExternalKeyNotFound => new Result(ModuleFs, 1004);
|
||||
|
||||
public static Result NotImplemented => new Result(ModuleFs, 3001);
|
||||
public static Result Result3002 => new Result(ModuleFs, 3002);
|
||||
|
@ -80,9 +82,11 @@
|
|||
public static Result InvalidSize => new Result(ModuleFs, 6062);
|
||||
public static Result NullArgument => new Result(ModuleFs, 6063);
|
||||
public static Result InvalidMountName => new Result(ModuleFs, 6065);
|
||||
public static Result ExtensionSizeTooLarge => new Result(ModuleFs, 6066);
|
||||
public static Result ExtensionSizeInvalid => new Result(ModuleFs, 6067);
|
||||
|
||||
public static Result InvalidOpenModeOperation => new Result(ModuleFs, 6200);
|
||||
public static Result AllowAppendRequiredForImplicitExtension => new Result(ModuleFs, 6201);
|
||||
public static Result FileExtensionWithoutOpenModeAllowAppend => new Result(ModuleFs, 6201);
|
||||
public static Result InvalidOpenModeForRead => new Result(ModuleFs, 6202);
|
||||
public static Result InvalidOpenModeForWrite => new Result(ModuleFs, 6203);
|
||||
|
||||
|
@ -105,11 +109,16 @@
|
|||
public static Result UnsupportedOperationInPartitionFileSetSize => new Result(ModuleFs, 6376);
|
||||
|
||||
public static Result PermissionDenied => new Result(ModuleFs, 6400);
|
||||
public static Result ExternalKeyAlreadyRegistered => new Result(ModuleFs, 6452);
|
||||
public static Result WriteStateUnflushed => new Result(ModuleFs, 6454);
|
||||
public static Result WritableFileOpen => new Result(ModuleFs, 6457);
|
||||
|
||||
|
||||
public static Result MappingTableFull => new Result(ModuleFs, 6706);
|
||||
public static Result AllocationTableInsufficientFreeBlocks => new Result(ModuleFs, 6707);
|
||||
public static Result OpenCountLimit => new Result(ModuleFs, 6709);
|
||||
|
||||
public static Result RemapStorageMapFull => new Result(ModuleFs, 6811);
|
||||
|
||||
public static Result Result6902 => new Result(ModuleFs, 6902);
|
||||
public static Result MountNameNotFound => new Result(ModuleFs, 6905);
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
[DebuggerDisplay("{DebugDisplay(),nq}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct RightsId : IEquatable<RightsId>, IComparable<RightsId>, IComparable
|
||||
{
|
||||
|
@ -19,12 +21,21 @@ namespace LibHac.Fs
|
|||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
|
||||
public string DebugDisplay()
|
||||
{
|
||||
ReadOnlySpan<byte> highBytes = AsBytes().Slice(0, 8);
|
||||
ReadOnlySpan<byte> lowBytes = AsBytes().Slice(8, 8);
|
||||
|
||||
return $"{highBytes.ToHexString()} {lowBytes.ToHexString()}";
|
||||
}
|
||||
|
||||
public bool Equals(RightsId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is RightsId other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(RightsId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
|
@ -33,9 +44,13 @@ namespace LibHac.Fs
|
|||
return obj is RightsId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(RightsId)}");
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
public ReadOnlySpan<byte> AsBytes()
|
||||
{
|
||||
return SpanHelpers.AsByteSpan(ref this);
|
||||
}
|
||||
|
||||
public static bool operator ==(RightsId left, RightsId right) => left.Equals(right);
|
||||
public static bool operator !=(RightsId left, RightsId right) => !left.Equals(right);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace LibHac.Fs
|
|||
{
|
||||
public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
return MountSystemSaveData(fs, mountName, spaceId, saveDataId, UserId.EmptyId);
|
||||
return MountSystemSaveData(fs, mountName, spaceId, saveDataId, UserId.Zero);
|
||||
}
|
||||
|
||||
public static Result MountSystemSaveData(this FileSystemClient fs, U8Span mountName,
|
||||
|
@ -72,19 +72,19 @@ namespace LibHac.Fs
|
|||
public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, ulong ownerId, long size,
|
||||
long journalSize, uint flags)
|
||||
{
|
||||
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.EmptyId, ownerId, size, journalSize, flags);
|
||||
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.Zero, ownerId, size, journalSize, flags);
|
||||
}
|
||||
|
||||
public static Result CreateSystemSaveData(this FileSystemClient fs, ulong saveDataId, long size,
|
||||
long journalSize, uint flags)
|
||||
{
|
||||
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.EmptyId, 0, size, journalSize, flags);
|
||||
return CreateSystemSaveData(fs, SaveDataSpaceId.System, saveDataId, UserId.Zero, 0, size, journalSize, flags);
|
||||
}
|
||||
|
||||
public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId,
|
||||
ulong ownerId, long size, long journalSize, uint flags)
|
||||
{
|
||||
return CreateSystemSaveData(fs, spaceId, saveDataId, UserId.EmptyId, ownerId, size, journalSize, flags);
|
||||
return CreateSystemSaveData(fs, spaceId, saveDataId, UserId.Zero, ownerId, size, journalSize, flags);
|
||||
}
|
||||
|
||||
public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId)
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
[DebuggerDisplay("{ToString(),nq}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct UserId : IEquatable<UserId>, IComparable<UserId>, IComparable
|
||||
{
|
||||
public static readonly UserId EmptyId = new UserId(0, 0);
|
||||
public static UserId Zero => default;
|
||||
|
||||
public readonly Id128 Id;
|
||||
|
||||
|
@ -21,12 +23,16 @@ namespace LibHac.Fs
|
|||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"0x{Id.High:x8}{Id.Low:x8}";
|
||||
}
|
||||
|
||||
public bool Equals(UserId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is UserId other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(UserId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
|
@ -35,9 +41,13 @@ namespace LibHac.Fs
|
|||
return obj is UserId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(UserId)}");
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
public ReadOnlySpan<byte> AsBytes()
|
||||
{
|
||||
return SpanHelpers.AsByteSpan(ref this);
|
||||
}
|
||||
|
||||
public static bool operator ==(UserId left, UserId right) => left.Equals(right);
|
||||
public static bool operator !=(UserId left, UserId right) => !left.Equals(right);
|
||||
|
||||
|
|
108
src/LibHac/FsService/ExternalKeySet.cs
Normal file
108
src/LibHac/FsService/ExternalKeySet.cs
Normal file
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Spl;
|
||||
|
||||
namespace LibHac.FsService
|
||||
{
|
||||
public class ExternalKeySet
|
||||
{
|
||||
private readonly object _locker = new object();
|
||||
|
||||
private Dictionary<RightsId, AccessKey> ExternalKeys { get; set; } = new Dictionary<RightsId, AccessKey>();
|
||||
|
||||
public Result Add(RightsId rightsId, AccessKey key)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (ExternalKeys.TryGetValue(rightsId, out AccessKey existingKey))
|
||||
{
|
||||
if (key == existingKey)
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
return ResultFs.ExternalKeyAlreadyRegistered.Log();
|
||||
}
|
||||
|
||||
ExternalKeys.Add(rightsId, key);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Get(RightsId rightsId, out AccessKey key)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (ExternalKeys.TryGetValue(rightsId, out key))
|
||||
{
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
return ResultFs.ExternalKeyNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(RightsId rightsId)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return ExternalKeys.ContainsKey(rightsId);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(RightsId rightsId)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
return ExternalKeys.Remove(rightsId);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
ExternalKeys.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public List<(RightsId rightsId, AccessKey key)> ToList()
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
var list = new List<(RightsId rightsId, AccessKey key)>(ExternalKeys.Count);
|
||||
|
||||
foreach (KeyValuePair<RightsId, AccessKey> kvp in ExternalKeys)
|
||||
{
|
||||
list.Add((kvp.Key, kvp.Value));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public void TrimExcess() => TrimExcess(0);
|
||||
|
||||
public void TrimExcess(int capacity)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
int newCapacity = Math.Max(capacity, ExternalKeys.Count);
|
||||
#if NETCOREAPP
|
||||
ExternalKeys.TrimExcess(newCapacity);
|
||||
#else
|
||||
var trimmedDict = new Dictionary<RightsId, AccessKey>(newCapacity);
|
||||
|
||||
foreach (KeyValuePair<RightsId, AccessKey> kvp in ExternalKeys)
|
||||
{
|
||||
trimmedDict.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
ExternalKeys = trimmedDict;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -147,7 +147,7 @@ namespace LibHac.FsService
|
|||
private Result OpenSaveDataFileSystemImpl(out IFileSystem fileSystem, out ulong saveDataId,
|
||||
SaveDataSpaceId spaceId, ref SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData)
|
||||
{
|
||||
bool hasFixedId = attribute.SaveDataId != 0 && attribute.UserId.Id == Id128.InvalidId;
|
||||
bool hasFixedId = attribute.SaveDataId != 0 && attribute.UserId == UserId.Zero;
|
||||
|
||||
if (hasFixedId)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem.RomFs;
|
||||
using LibHac.Spl;
|
||||
|
||||
namespace LibHac.FsSystem.NcaUtils
|
||||
{
|
||||
|
@ -47,9 +48,9 @@ namespace LibHac.FsSystem.NcaUtils
|
|||
int keyRevision = Util.GetMasterKeyRevision(Header.KeyGeneration);
|
||||
byte[] titleKek = Keyset.TitleKeks[keyRevision];
|
||||
|
||||
if (!Keyset.TitleKeys.TryGetValue(Header.RightsId.ToArray(), out byte[] encryptedKey))
|
||||
if (Keyset.ExternalKeySet.Get(new RightsId(Header.RightsId), out AccessKey accessKey).IsFailure())
|
||||
{
|
||||
throw new MissingKeyException("Missing NCA title key.", Header.RightsId.ToHexString(), KeyType.Title);
|
||||
throw new MissingKeyException("Missing NCA title key.", Header.RightsId.ToString(), KeyType.Title);
|
||||
}
|
||||
|
||||
if (titleKek.IsEmpty())
|
||||
|
@ -58,6 +59,7 @@ namespace LibHac.FsSystem.NcaUtils
|
|||
throw new MissingKeyException("Unable to decrypt title key.", keyName, KeyType.Common);
|
||||
}
|
||||
|
||||
byte[] encryptedKey = accessKey.Value.ToArray();
|
||||
var decryptedKey = new byte[Crypto.Aes128Size];
|
||||
|
||||
Crypto.DecryptEcb(titleKek, encryptedKey, decryptedKey, Crypto.Aes128Size);
|
||||
|
@ -89,7 +91,7 @@ namespace LibHac.FsSystem.NcaUtils
|
|||
|
||||
if (Header.HasRightsId)
|
||||
{
|
||||
return Keyset.TitleKeys.ContainsKey(Header.RightsId.ToArray()) &&
|
||||
return Keyset.ExternalKeySet.Contains(new RightsId(Header.RightsId)) &&
|
||||
!Keyset.TitleKeks[keyRevision].IsEmpty();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,10 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsService;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Spl;
|
||||
|
||||
namespace LibHac
|
||||
{
|
||||
|
@ -129,7 +132,7 @@ namespace LibHac
|
|||
0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F
|
||||
};
|
||||
|
||||
public Dictionary<byte[], byte[]> TitleKeys { get; } = new Dictionary<byte[], byte[]>(new ByteArray128BitComparer());
|
||||
public ExternalKeySet ExternalKeySet { get; } = new ExternalKeySet();
|
||||
|
||||
public void SetSdSeed(byte[] sdseed)
|
||||
{
|
||||
|
@ -402,6 +405,7 @@ namespace LibHac
|
|||
if (filename != null) ReadMainKeys(keyset, filename, AllKeyDict, logger);
|
||||
if (consoleKeysFilename != null) ReadMainKeys(keyset, consoleKeysFilename, AllKeyDict, logger);
|
||||
if (titleKeysFilename != null) ReadTitleKeys(keyset, titleKeysFilename, logger);
|
||||
keyset.ExternalKeySet.TrimExcess();
|
||||
keyset.DeriveKeys(logger);
|
||||
}
|
||||
|
||||
|
@ -507,7 +511,7 @@ namespace LibHac
|
|||
continue;
|
||||
}
|
||||
|
||||
keyset.TitleKeys[rightsId] = titleKey;
|
||||
keyset.ExternalKeySet.Add(new RightsId(rightsId), new AccessKey(titleKey)).ThrowIfFailure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -557,9 +561,9 @@ namespace LibHac
|
|||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (KeyValuePair<byte[], byte[]> kv in keyset.TitleKeys.OrderBy(x => x.Key.ToHexString()))
|
||||
foreach ((RightsId rightsId, AccessKey key) kv in keyset.ExternalKeySet.ToList().OrderBy(x => x.rightsId.ToString()))
|
||||
{
|
||||
string line = $"{kv.Key.ToHexString()} = {kv.Value.ToHexString()}";
|
||||
string line = $"{kv.rightsId} = {kv.key}";
|
||||
sb.AppendLine(line);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.1;netstandard2.0;net46</TargetFrameworks>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Ncm
|
||||
{
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct ContentId : IEquatable<ContentId>, IComparable<ContentId>, IComparable
|
||||
{
|
||||
|
@ -19,12 +21,13 @@ namespace LibHac.Ncm
|
|||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
|
||||
public bool Equals(ContentId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is ContentId other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(ContentId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
|
@ -33,9 +36,13 @@ namespace LibHac.Ncm
|
|||
return obj is ContentId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ContentId)}");
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
public ReadOnlySpan<byte> AsBytes()
|
||||
{
|
||||
return SpanHelpers.AsByteSpan(ref this);
|
||||
}
|
||||
|
||||
public static bool operator ==(ContentId left, ContentId right) => left.Equals(right);
|
||||
public static bool operator !=(ContentId left, ContentId right) => !left.Equals(right);
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
namespace LibHac.Ncm
|
||||
{
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct PlaceHolderId : IEquatable<PlaceHolderId>, IComparable<PlaceHolderId>, IComparable
|
||||
{
|
||||
|
@ -19,12 +21,13 @@ namespace LibHac.Ncm
|
|||
Id = new Id128(uid);
|
||||
}
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
|
||||
public bool Equals(PlaceHolderId other) => Id == other.Id;
|
||||
public override bool Equals(object obj) => obj is PlaceHolderId other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => Id.GetHashCode();
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public int CompareTo(PlaceHolderId other) => Id.CompareTo(other.Id);
|
||||
|
||||
public int CompareTo(object obj)
|
||||
|
@ -33,9 +36,13 @@ namespace LibHac.Ncm
|
|||
return obj is PlaceHolderId other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(PlaceHolderId)}");
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
public void ToBytes(Span<byte> output) => Id.ToBytes(output);
|
||||
|
||||
public ReadOnlySpan<byte> AsBytes()
|
||||
{
|
||||
return SpanHelpers.AsByteSpan(ref this);
|
||||
}
|
||||
|
||||
public static bool operator ==(PlaceHolderId left, PlaceHolderId right) => left.Equals(right);
|
||||
public static bool operator !=(PlaceHolderId left, PlaceHolderId right) => !left.Equals(right);
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
|
||||
|
@ -8,13 +7,23 @@ namespace LibHac.Spl
|
|||
{
|
||||
[DebuggerDisplay("{ToString()}")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct AccessKey
|
||||
public struct AccessKey : IEquatable<AccessKey>
|
||||
{
|
||||
private long _dummy1;
|
||||
private long _dummy2;
|
||||
private readonly Key128 Key;
|
||||
|
||||
public Span<byte> Key => SpanHelpers.CreateSpan(ref Unsafe.As<long, byte>(ref _dummy1), 0x10);
|
||||
public ReadOnlySpan<byte> Value => SpanHelpers.AsByteSpan(ref this);
|
||||
|
||||
public override string ToString() => Key.ToHexString();
|
||||
public AccessKey(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
Key = new Key128(bytes);
|
||||
}
|
||||
|
||||
public override string ToString() => Key.ToString();
|
||||
|
||||
public override bool Equals(object obj) => obj is AccessKey key && Equals(key);
|
||||
public bool Equals(AccessKey other) => Key.Equals(other.Key);
|
||||
public override int GetHashCode() => Key.GetHashCode();
|
||||
public static bool operator ==(AccessKey left, AccessKey right) => left.Equals(right);
|
||||
public static bool operator !=(AccessKey left, AccessKey right) => !(left == right);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -354,7 +354,9 @@ namespace LibHac
|
|||
|
||||
public static string ToHexString(this byte[] bytes) => ToHexString(bytes.AsSpan());
|
||||
|
||||
public static string ToHexString(this Span<byte> bytes)
|
||||
public static string ToHexString(this Span<byte> bytes) => ToHexString((ReadOnlySpan<byte>)bytes);
|
||||
|
||||
public static string ToHexString(this ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
uint[] lookup32 = Lookup32;
|
||||
var result = new char[bytes.Length * 2];
|
||||
|
|
Loading…
Reference in a new issue