From bb138640308faa9a3c98fe8f438da99bd9132025 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 29 Jan 2023 22:26:34 -0700 Subject: [PATCH] Add more TSEC key generation --- build/CodeGen/IncludedKeys.txt | 4 + src/LibHac/Common/Keys/DefaultKeySet.cs | 49 ++++---- src/LibHac/Common/Keys/ExternalKeyWriter.cs | 40 ++++--- src/LibHac/Common/Keys/KeyDerivation.cs | 120 +++++++++++++++++--- src/LibHac/Common/Keys/KeyInfo.cs | 14 ++- src/LibHac/Common/Keys/KeySet.cs | 36 ++++-- 6 files changed, 196 insertions(+), 67 deletions(-) diff --git a/build/CodeGen/IncludedKeys.txt b/build/CodeGen/IncludedKeys.txt index 5f0b46db..36debb10 100644 --- a/build/CodeGen/IncludedKeys.txt +++ b/build/CodeGen/IncludedKeys.txt @@ -1,3 +1,7 @@ +tsec_auth_signature_00 = A77B86586AE1B03D4FFBA3ADA8F8DE32 +tsec_auth_signature_01 = A3FFB0F6BC49A06DF2FC791697D81D32 +tsec_auth_signature_02 = 0B55CC0820E6307FD087479EAA2E7F98 + keyblob_mac_key_source = 59C7FB6FBE9BBE87656B15C0537336A5 keyblob_key_source_00 = DF206F594454EFDC7074483B0DED9FD3 keyblob_key_source_01 = 0C25615D684CEB421C2379EA822512AC diff --git a/src/LibHac/Common/Keys/DefaultKeySet.cs b/src/LibHac/Common/Keys/DefaultKeySet.cs index 58366e6a..482caa91 100644 --- a/src/LibHac/Common/Keys/DefaultKeySet.cs +++ b/src/LibHac/Common/Keys/DefaultKeySet.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; +using static LibHac.Common.Keys.KeySet; using Type = LibHac.Common.Keys.KeyInfo.KeyType; namespace LibHac.Common.Keys; @@ -103,40 +104,42 @@ internal static partial class DefaultKeySet keys.Add(new KeyInfo(11, Type.DeviceRoot, "tsec_key", (set, _) => set.TsecKey)); keys.Add(new KeyInfo(12, Type.DeviceDrvd, "device_key", (set, _) => set.DeviceKey)); - keys.Add(new KeyInfo(20, Type.CommonRoot, "tsec_root_kek", (set, _) => set.TsecRootKek)); - keys.Add(new KeyInfo(21, Type.CommonRoot, "package1_mac_kek", (set, _) => set.Package1MacKek)); - keys.Add(new KeyInfo(22, Type.CommonRoot, "package1_kek", (set, _) => set.Package1Kek)); + keys.Add(new KeyInfo(15, Type.CommonRootSame, "tsec_secret", 0, TsecSecretCount, (set, i) => set.TsecSecrets[i])); + + keys.Add(new KeyInfo(20, Type.CommonRoot, "tsec_root_kek", 0, TsecKeyRevisionCount, (set, i) => set.TsecRootKeks[i])); + keys.Add(new KeyInfo(22, Type.CommonRoot, "package1_mac_kek", 0, TsecKeyRevisionCount, (set, i) => set.Package1MacKeks[i])); + keys.Add(new KeyInfo(24, Type.CommonRoot, "package1_kek", 0, TsecKeyRevisionCount, (set, i) => set.Package1Keks[i])); - keys.Add(new KeyInfo(30, Type.CommonRoot, "tsec_auth_signature", 0, 0x20, (set, i) => set.TsecAuthSignatures[i])); + keys.Add(new KeyInfo(30, Type.CommonSeed, "tsec_auth_signature", 0, TsecKeyRevisionCount, (set, i) => set.TsecAuthSignatures[i])); - keys.Add(new KeyInfo(40, Type.CommonRoot, "tsec_root_key", 0, 0x20, (set, i) => set.TsecRootKeys[i])); + keys.Add(new KeyInfo(40, Type.CommonRoot, "tsec_root_key", 0, TsecKeyRevisionCount, (set, i) => set.TsecRootKeys[i])); keys.Add(new KeyInfo(50, Type.CommonSeed, "keyblob_mac_key_source", (set, _) => set.KeyBlobMacKeySource)); - keys.Add(new KeyInfo(51, Type.CommonSeed, "keyblob_key_source", 0, 6, (set, i) => set.KeyBlobKeySources[i])); + keys.Add(new KeyInfo(51, Type.CommonSeed, "keyblob_key_source", 0, UsedKeyBlobCount, (set, i) => set.KeyBlobKeySources[i])); - keys.Add(new KeyInfo(55, Type.DeviceDrvd, "keyblob_key", 0, 6, (set, i) => set.KeyBlobKeys[i])); + keys.Add(new KeyInfo(55, Type.DeviceDrvd, "keyblob_key", 0, UsedKeyBlobCount, (set, i) => set.KeyBlobKeys[i])); - keys.Add(new KeyInfo(60, Type.DeviceDrvd, "keyblob_mac_key", 0, 6, (set, i) => set.KeyBlobMacKeys[i])); + keys.Add(new KeyInfo(60, Type.DeviceDrvd, "keyblob_mac_key", 0, UsedKeyBlobCount, (set, i) => set.KeyBlobMacKeys[i])); - keys.Add(new KeyInfo(70, Type.DeviceRoot, "encrypted_keyblob", 0, 6, (set, i) => set.EncryptedKeyBlobs[i].Bytes)); + keys.Add(new KeyInfo(70, Type.DeviceRoot, "encrypted_keyblob", 0, UsedKeyBlobCount, (set, i) => set.EncryptedKeyBlobs[i].Bytes)); - keys.Add(new KeyInfo(80, Type.CommonRoot, "keyblob", 0, 6, (set, i) => set.KeyBlobs[i].Bytes)); + keys.Add(new KeyInfo(80, Type.CommonRoot, "keyblob", 0, UsedKeyBlobCount, (set, i) => set.KeyBlobs[i].Bytes)); - keys.Add(new KeyInfo(90, Type.CommonSeed, "master_kek_source", 6, 0x20, (set, i) => set.MasterKekSources[i])); + keys.Add(new KeyInfo(90, Type.CommonSeed, "master_kek_source", UsedKeyBlobCount, KeyRevisionCount, (set, i) => set.MasterKekSources[i])); keys.Add(new KeyInfo(100, Type.CommonRoot, "mariko_bek", (set, _) => set.MarikoBek)); keys.Add(new KeyInfo(101, Type.CommonRoot, "mariko_kek", (set, _) => set.MarikoKek)); - keys.Add(new KeyInfo(110, Type.CommonRoot, "mariko_aes_class_key", 0, 0xC, (set, i) => set.MarikoAesClassKeys[i])); - keys.Add(new KeyInfo(120, Type.CommonSeedDiff, "mariko_master_kek_source", 0, 0x20, (set, i) => set.MarikoMasterKekSources[i])); - keys.Add(new KeyInfo(130, Type.CommonDrvd, "master_kek", 0, 0x20, (set, i) => set.MasterKeks[i])); + keys.Add(new KeyInfo(110, Type.CommonRoot, "mariko_aes_class_key", 0, MarikoAesClassKeyCount, (set, i) => set.MarikoAesClassKeys[i])); + keys.Add(new KeyInfo(120, Type.CommonSeedDiff, "mariko_master_kek_source", 0, KeyRevisionCount, (set, i) => set.MarikoMasterKekSources[i])); + keys.Add(new KeyInfo(130, Type.CommonDrvd, "master_kek", 0, KeyRevisionCount, (set, i) => set.MasterKeks[i])); keys.Add(new KeyInfo(140, Type.CommonSeed, "master_key_source", (set, _) => set.MasterKeySource)); - keys.Add(new KeyInfo(150, Type.CommonDrvd, "master_key", 0, 0x20, (set, i) => set.MasterKeys[i])); + keys.Add(new KeyInfo(150, Type.CommonDrvd, "master_key", 0, KeyRevisionCount, (set, i) => set.MasterKeys[i])); - keys.Add(new KeyInfo(160, Type.CommonDrvd, "package1_key", 0, 0x20, (set, i) => set.Package1Keys[i])); - keys.Add(new KeyInfo(170, Type.CommonDrvd, "package1_mac_key", 6, 0x20, (set, i) => set.Package1MacKeys[i])); + keys.Add(new KeyInfo(160, Type.CommonDrvd, "package1_key", 0, KeyRevisionCount, (set, i) => set.Package1Keys[i])); + keys.Add(new KeyInfo(170, Type.CommonDrvd, "package1_mac_key", UsedKeyBlobCount, KeyRevisionCount, (set, i) => set.Package1MacKeys[i])); keys.Add(new KeyInfo(180, Type.CommonSeed, "package2_key_source", (set, _) => set.Package2KeySource)); - keys.Add(new KeyInfo(190, Type.CommonDrvd, "package2_key", 0, 0x20, (set, i) => set.Package2Keys[i])); + keys.Add(new KeyInfo(190, Type.CommonDrvd, "package2_key", 0, KeyRevisionCount, (set, i) => set.Package2Keys[i])); keys.Add(new KeyInfo(200, Type.CommonSeed, "bis_kek_source", (set, _) => set.BisKekSource)); keys.Add(new KeyInfo(201, Type.CommonSeed, "bis_key_source", 0, 4, (set, i) => set.BisKeySources[i])); @@ -149,7 +152,7 @@ internal static partial class DefaultKeySet keys.Add(new KeyInfo(213, Type.CommonSeed, "aes_key_generation_source", (set, _) => set.AesKeyGenerationSource)); keys.Add(new KeyInfo(214, Type.CommonSeed, "titlekek_source", (set, _) => set.TitleKekSource)); - keys.Add(new KeyInfo(220, Type.CommonDrvd, "titlekek", 0, 0x20, (set, i) => set.TitleKeks[i])); + keys.Add(new KeyInfo(220, Type.CommonDrvd, "titlekek", 0, KeyRevisionCount, (set, i) => set.TitleKeks[i])); keys.Add(new KeyInfo(230, Type.CommonSeed, "header_kek_source", (set, _) => set.HeaderKekSource)); keys.Add(new KeyInfo(231, Type.CommonSeed, "header_key_source", (set, _) => set.HeaderKeySource)); @@ -175,15 +178,15 @@ internal static partial class DefaultKeySet keys.Add(new KeyInfo(263, Type.CommonSeed, "sd_card_nca_key_source", (set, _) => set.SdCardKeySources[1])); keys.Add(new KeyInfo(264, Type.CommonSeed, "sd_card_custom_storage_key_source", (set, _) => set.SdCardKeySources[2])); - keys.Add(new KeyInfo(270, Type.CommonSeedDiff, "xci_header_key", (set, _) => set.XciHeaderKey)); + keys.Add(new KeyInfo(270, Type.CommonRoot, "xci_header_key", (set, _) => set.XciHeaderKey)); keys.Add(new KeyInfo(271, Type.CommonRoot, "xci_t1_titlekey_kek", 0, 0x10, (set, i) => set.GcTitleKeyKeks[i])); keys.Add(new KeyInfo(280, Type.CommonRoot, "eticket_rsa_kek", (set, _) => set.ETicketRsaKek)); keys.Add(new KeyInfo(281, Type.CommonRoot, "ssl_rsa_kek", (set, _) => set.SslRsaKek)); - keys.Add(new KeyInfo(290, Type.CommonDrvd, "key_area_key_application", 0, 0x20, (set, i) => set.KeyAreaKeys[i][0])); - keys.Add(new KeyInfo(300, Type.CommonDrvd, "key_area_key_ocean", 0, 0x20, (set, i) => set.KeyAreaKeys[i][1])); - keys.Add(new KeyInfo(310, Type.CommonDrvd, "key_area_key_system", 0, 0x20, (set, i) => set.KeyAreaKeys[i][2])); + keys.Add(new KeyInfo(290, Type.CommonDrvd, "key_area_key_application", 0, KeyRevisionCount, (set, i) => set.KeyAreaKeys[i][0])); + keys.Add(new KeyInfo(300, Type.CommonDrvd, "key_area_key_ocean", 0, KeyRevisionCount, (set, i) => set.KeyAreaKeys[i][1])); + keys.Add(new KeyInfo(310, Type.CommonDrvd, "key_area_key_system", 0, KeyRevisionCount, (set, i) => set.KeyAreaKeys[i][2])); return keys; } diff --git a/src/LibHac/Common/Keys/ExternalKeyWriter.cs b/src/LibHac/Common/Keys/ExternalKeyWriter.cs index e718780b..b6926e64 100644 --- a/src/LibHac/Common/Keys/ExternalKeyWriter.cs +++ b/src/LibHac/Common/Keys/ExternalKeyWriter.cs @@ -12,26 +12,34 @@ namespace LibHac.Common.Keys; public static class ExternalKeyWriter { - public static void PrintKeys(KeySet keySet, StringBuilder sb, List keys, Type filter, bool isDev) + public static void PrintKeys(KeySet keySet, StringBuilder sb, List keys, Type filter, bool onlyPrintDifferentDevKeys) { if (keys.Count == 0) return; - string devSuffix = isDev ? "_dev" : string.Empty; + string devSuffix = onlyPrintDifferentDevKeys ? "_dev" : string.Empty; int maxNameLength = keys.Max(x => x.NameLength); int currentGroup = 0; - // Todo: Better filtering bool FilterMatches(KeyInfo keyInfo) { - Type filter1 = filter & (Type.Common | Type.Device); - Type filter2 = filter & (Type.Root | Type.Seed | Type.Derived); - Type filter3 = filter & Type.DifferentDev; + // If we're only printing dev-only keys, skip keys that are the same in both prod and dev environments. + if (onlyPrintDifferentDevKeys && !keyInfo.Type.HasFlag(Type.DifferentDev)) + return false; - // Skip sub-filters that have no flags set - return (filter1 == 0 || (filter1 & keyInfo.Type) != 0) && - (filter2 == 0 || (filter2 & keyInfo.Type) != 0) && - filter3 == (filter3 & keyInfo.Type) || - isDev && keyInfo.Type.HasFlag(Type.DifferentDev); + // A KeyType contains two sub-types that specify how a key is used in the cryptosystem, and whether a key + // is shared between all consoles or is console-unique. Each of these types are filtered separately. + // A key must match both of these sub-types to pass through the filter. + // A value of 0 for a sub-filter means that any value of the filtered sub-type is allowed. + const Type distributionTypeMask = Type.Common | Type.Device; + const Type derivationTypeMask = Type.Root | Type.Seed | Type.Derived; + + Type distributionTypeFilter = filter & distributionTypeMask; + Type derivationTypeFilter = filter & derivationTypeMask; + + bool matchesDistributionTypeFilter = distributionTypeFilter == 0 || (distributionTypeFilter & keyInfo.Type) != 0; + bool matchesDerivationTypeFilter = derivationTypeFilter == 0 || (derivationTypeFilter & keyInfo.Type) != 0; + + return matchesDistributionTypeFilter && matchesDerivationTypeFilter; } bool isFirstPrint = true; @@ -118,8 +126,7 @@ public static class ExternalKeyWriter public static string PrintCommonKeys(KeySet keySet) { var sb = new StringBuilder(); - PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Root | Type.Seed | Type.Derived, - false); + PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common, false); return sb.ToString(); } @@ -146,7 +153,7 @@ public static class ExternalKeyWriter { sb.AppendLine(); keySet.SetMode(KeySet.Mode.Dev); - PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Seed | Type.DifferentDev, true); + PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Seed, true); keySet.SetMode(KeySet.Mode.Prod); } @@ -159,12 +166,11 @@ public static class ExternalKeyWriter var sb = new StringBuilder(); keySet.SetMode(KeySet.Mode.Prod); - PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Root | Type.Seed | Type.Derived, - false); + PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common, false); sb.AppendLine(); keySet.SetMode(KeySet.Mode.Dev); - PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Root | Type.Derived, true); + PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common, true); keySet.SetMode(originalMode); return sb.ToString(); diff --git a/src/LibHac/Common/Keys/KeyDerivation.cs b/src/LibHac/Common/Keys/KeyDerivation.cs index 3297e6a5..b7a017eb 100644 --- a/src/LibHac/Common/Keys/KeyDerivation.cs +++ b/src/LibHac/Common/Keys/KeyDerivation.cs @@ -1,18 +1,21 @@ using System; using System.Runtime.InteropServices; using LibHac.Crypto; +using LibHac.Diag; namespace LibHac.Common.Keys; internal static class KeyDerivation { + private const int HoviSeedSize = 0x10; + public static void DeriveAllKeys(KeySet keySet, IProgressReport logger = null) { DeriveKeyBlobKeys(keySet); DecryptKeyBlobs(keySet, logger); ReadKeyBlobs(keySet); - Derive620Keys(keySet); + DeriveTsecKeys(keySet); Derive620MasterKeks(keySet); DeriveMarikoMasterKeks(keySet); DeriveMasterKeys(keySet); @@ -46,6 +49,9 @@ internal static class KeyDerivation private static void DecryptKeyBlobs(KeySet s, IProgressReport logger = null) { + if (s.CurrentMode == KeySet.Mode.Dev) + return; + var cmac = new AesCmac(); for (int i = 0; i < KeySet.UsedKeyBlobCount; i++) @@ -78,33 +84,115 @@ internal static class KeyDerivation } } - private static void Derive620Keys(KeySet s) + private enum HoviSeedType { - bool haveTsecRootKek = !s.TsecRootKek.IsZeros(); - bool havePackage1MacKek = !s.Package1MacKek.IsZeros(); - bool havePackage1Kek = !s.Package1Kek.IsZeros(); + Encryption, + Signature, + Kek, + + // TSEC directly uses the value generated by this (no key derivation) to encrypt pk11's AES IV that's found + // at 0x6FF0 in package1. When decrypting pk11, TSEC will overwrite the unencrypted IV in package1 with the + // encrypted IV. + IvEncryption + } - for (int i = KeySet.UsedKeyBlobCount; i < KeySet.KeyRevisionCount; i++) + private static void DeriveTsecKeys(KeySet s) + { + AesKey secret26 = s.TsecSecrets[0x26]; + bool haveSecret26 = !secret26.IsZeros(); + bool isProd = s.CurrentMode == KeySet.Mode.Prod; + + for (int i = 0; i < KeySet.TsecKeyRevisionCount; i++) { - if (s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount].IsZeros()) - continue; + if (s.TsecAuthSignatures[i].IsZeros()) continue; - if (haveTsecRootKek) + if (haveSecret26) { - Aes.EncryptEcb128(s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount], - s.TsecRootKeys[i - KeySet.UsedKeyBlobCount], s.TsecRootKek); + DeriveTsecKeyFromSecret(i, HoviSeedType.Encryption, isProd, secret26, s.Package1Keks[i]); + DeriveTsecKeyFromSecret(i, HoviSeedType.Signature, isProd, secret26, s.Package1MacKeks[i]); + DeriveTsecKeyFromSecret(i, HoviSeedType.Kek, isProd, secret26, s.TsecRootKeks[i]); } - if (havePackage1MacKek) + if (!s.Package1Keks[i].IsZeros()) { - Aes.EncryptEcb128(s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount], s.Package1MacKeys[i], - s.Package1MacKek); + Aes.EncryptEcb128(s.TsecAuthSignatures[i], s.Package1Keys[KeySet.UsedKeyBlobCount + i], s.Package1Keks[i]); } - if (havePackage1Kek) + if (!s.Package1MacKeks[i].IsZeros()) { - Aes.EncryptEcb128(s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount], s.Package1Keys[i], s.Package1Kek); + Aes.EncryptEcb128(s.TsecAuthSignatures[i], s.Package1MacKeys[KeySet.UsedKeyBlobCount + i], s.Package1MacKeks[i]); } + + if (!s.TsecRootKeks[i].IsZeros()) + { + Aes.EncryptEcb128(s.TsecAuthSignatures[i], s.TsecRootKeys[i], s.TsecRootKeks[i]); + } + } + + static void DeriveTsecKeyFromSecret(int keyVersion, HoviSeedType type, bool isProd, ReadOnlySpan secret, Span output) + { + Span hoviSeed = stackalloc byte[HoviSeedSize]; + GenerateHoviSeed(hoviSeed, type, isProd); + + // The third version of the post-6.2.0 TSEC firmwares changed how these keys are derived. Instead of + // encrypting the seed, they now decrypt the seed. + if (keyVersion <= 1) + { + Aes.EncryptEcb128(hoviSeed, output, secret); + } + else + { + Aes.DecryptEcb128(hoviSeed, output, secret); + } + } + } + + private static void GenerateHoviSeed(Span outSeed, HoviSeedType type, bool isProd) + { + const uint part1Hov = 0x49564F48; // HOVI + const uint part2Sig = 0x4749535F; // _SIG + const uint part2Kek = 0x4B454B5F; // _KEK + const uint part2Enc = 0x434E455F; // _ENC + const uint part3Key = 0x59454B5F; // _KEY + const uint part4Prd = 0x4452505F; // _PRD + const uint part4Dev = 0x5645445F; // _DEV + const uint part4Iv1 = 0x3156495F; // _IV1 + + Assert.GreaterEqual(outSeed.Length, HoviSeedSize); + + Span seed = MemoryMarshal.Cast(outSeed); + + seed[0] = part1Hov; + + switch (type) + { + case HoviSeedType.Encryption: + seed[1] = part2Enc; + break; + case HoviSeedType.Signature: + seed[1] = part2Sig; + break; + case HoviSeedType.Kek: + seed[1] = part2Kek; + break; + case HoviSeedType.IvEncryption: + seed[1] = part2Enc; + break; + } + + seed[2] = part3Key; + + if (type == HoviSeedType.IvEncryption) + { + seed[3] = part4Iv1; + } + else if (isProd) + { + seed[3] = part4Prd; + } + else + { + seed[3] = part4Dev; } } diff --git a/src/LibHac/Common/Keys/KeyInfo.cs b/src/LibHac/Common/Keys/KeyInfo.cs index f5e427ca..d5c945ee 100644 --- a/src/LibHac/Common/Keys/KeyInfo.cs +++ b/src/LibHac/Common/Keys/KeyInfo.cs @@ -17,8 +17,17 @@ public readonly struct KeyInfo [Flags] public enum KeyType : byte { + // These two flags specify whether a key is common to all consoles or is console-unique. + // Only one of these flags should be set at a time. Common = 1 << 0, Device = 1 << 1, + + // These three flags specify how a key is obtained. Only one of these flags should be set at a time. + // Root keys are generally used to transform the key seeds into actual keys. + // These root keys are usually not supposed to be exposed outside of TrustZone or the TSEC firmware. + // Other root keys might be stored directly in system software and used without transforming the key first. + // Seeds are generally stored as plaintext in system software and are used as seeds to generate the actual keys. + // Derived keys are the keys that are generated from the key seeds. Root = 1 << 2, Seed = 1 << 3, Derived = 1 << 4, @@ -26,10 +35,11 @@ public readonly struct KeyInfo /// Specifies that a seed is different in prod and dev. DifferentDev = 1 << 5, - CommonRoot = Common | Root, + CommonRoot = Common | Root | DifferentDev, + CommonRootSame = Common | Root, CommonSeed = Common | Seed, CommonSeedDiff = Common | Seed | DifferentDev, - CommonDrvd = Common | Derived, + CommonDrvd = Common | Derived | DifferentDev, DeviceRoot = Device | Root, DeviceDrvd = Device | Derived } diff --git a/src/LibHac/Common/Keys/KeySet.cs b/src/LibHac/Common/Keys/KeySet.cs index 240d07f1..8bdb2f70 100644 --- a/src/LibHac/Common/Keys/KeySet.cs +++ b/src/LibHac/Common/Keys/KeySet.cs @@ -23,6 +23,15 @@ public class KeySet internal const int UsedKeyBlobCount = 6; internal const int SdCardKeyIdCount = 3; internal const int KeyRevisionCount = 0x20; + internal const int TsecSecretCount = 0x40; + internal const int MarikoAesClassKeyCount = 0xC; + + /// + /// The number of slots reserved for current and future TSEC FW revisions. + /// 8 was semi-arbitrarily chosen because there are only 3 FW revisions used for >= 6.2.0 crypto as of Jan 2023, + /// and it's unlikely that many more will be issued. + /// + internal const int TsecKeyRevisionCount = 8; private AllKeys _keys; private Mode _mode = Mode.Prod; @@ -30,6 +39,7 @@ public class KeySet public ref AllKeys KeyStruct => ref _keys; public Mode CurrentMode => _mode; + private ref TsecSecrets Secrets => ref _keys.TsecSecrets; private ref RootKeys RootKeys => ref _mode == Mode.Dev ? ref _keys.RootKeysDev : ref _keys.RootKeysProd; private ref StoredKeys StoredKeys => ref _mode == Mode.Dev ? ref _keys.StoredKeysDev : ref _keys.StoredKeysProd; private ref DerivedKeys DerivedKeys => ref _mode == Mode.Dev ? ref _keys.DerivedKeysDev : ref _keys.DerivedKeysProd; @@ -49,10 +59,12 @@ public class KeySet public Span KeyBlobs => RootKeys.KeyBlobs.Items; public Span KeyBlobKeySources => _keys.KeySeeds.KeyBlobKeySources.Items; public ref AesKey KeyBlobMacKeySource => ref _keys.KeySeeds.KeyBlobMacKeySource; - public ref AesKey TsecRootKek => ref RootKeys.TsecRootKek; - public ref AesKey Package1MacKek => ref RootKeys.Package1MacKek; - public ref AesKey Package1Kek => ref RootKeys.Package1Kek; - public Span TsecAuthSignatures => RootKeys.TsecAuthSignatures.Items; + + public Span TsecSecrets => Secrets.Secrets.Items; + public Span TsecRootKeks => RootKeys.TsecRootKeks.Items; + public Span Package1MacKeks => RootKeys.Package1MacKeks.Items; + public Span Package1Keks => RootKeys.Package1Keks.Items; + public Span TsecAuthSignatures => _keys.KeySeeds.TsecAuthSignatures.Items; public Span TsecRootKeys => RootKeys.TsecRootKeys.Items; public Span MasterKekSources => _keys.KeySeeds.MasterKekSources.Items; public Span GcTitleKeyKeks => RootKeys.GcTitleKeyKeks.Items; @@ -263,6 +275,7 @@ public class KeySet public struct AllKeys { + public TsecSecrets TsecSecrets; public RootKeys RootKeysDev; public RootKeys RootKeysProd; public KeySeeds KeySeeds; @@ -278,6 +291,11 @@ public struct AllKeys public RsaKeys RsaKeys; } +public struct TsecSecrets +{ + public Array64 Secrets; +} + public struct RootKeys { // Mariko keys. The AES class keys are currently unused. @@ -291,13 +309,12 @@ public struct RootKeys public Array32 KeyBlobs; // Used by TSEC in >= 6.2.0 Erista firmware - public Array32 TsecAuthSignatures; - public AesKey TsecRootKek; - public AesKey Package1MacKek; - public AesKey Package1Kek; + public Array8 TsecRootKeks; + public Array8 Package1MacKeks; + public Array8 Package1Keks; // Derived by TSEC. This is the first public root key for >= 6.2.0 Erista - public Array32 TsecRootKeys; + public Array8 TsecRootKeys; // Used to decrypt the title keys found in an XCI's initial data public Array16 GcTitleKeyKeks; @@ -305,6 +322,7 @@ public struct RootKeys public struct KeySeeds { + public Array8 TsecAuthSignatures; public Array32 KeyBlobKeySources; public AesKey KeyBlobMacKeySource; public Array32 MasterKekSources;