diff --git a/src/LibHac/Keyset.cs b/src/LibHac/Keyset.cs
index e8ea15ef..e40b5b1a 100644
--- a/src/LibHac/Keyset.cs
+++ b/src/LibHac/Keyset.cs
@@ -10,12 +10,20 @@ namespace LibHac
{
public class Keyset
{
+ ///
+ /// The number of keyblobs that were used for < 6.2.0 crypto
+ ///
+ private const int UsedKeyblobCount = 6;
+
public byte[][] KeyblobKeys { get; } = Util.CreateJaggedArray(0x20, 0x10);
public byte[][] KeyblobMacKeys { get; } = Util.CreateJaggedArray(0x20, 0x10);
public byte[][] EncryptedKeyblobs { get; } = Util.CreateJaggedArray(0x20, 0xB0);
public byte[][] Keyblobs { get; } = Util.CreateJaggedArray(0x20, 0x90);
public byte[][] KeyblobKeySources { get; } = Util.CreateJaggedArray(0x20, 0x10);
public byte[] KeyblobMacKeySource { get; } = new byte[0x10];
+ public byte[][] TsecRootKeys { get; } = Util.CreateJaggedArray(0x20, 0x10);
+ public byte[][] MasterKekSources { get; } = Util.CreateJaggedArray(0x20, 0x10);
+ public byte[][] MasterKeks { get; } = Util.CreateJaggedArray(0x20, 0x10);
public byte[] MasterKeySource { get; } = new byte[0x10];
public byte[][] MasterKeys { get; } = Util.CreateJaggedArray(0x20, 0x10);
public byte[][] Package1Keys { get; } = Util.CreateJaggedArray(0x20, 0x10);
@@ -28,29 +36,31 @@ namespace LibHac
public byte[] KeyAreaKeySystemSource { get; } = new byte[0x10];
public byte[] SaveMacKekSource { get; } = new byte[0x10];
public byte[] SaveMacKeySource { get; } = new byte[0x10];
- public byte[] TitlekekSource { get; } = new byte[0x10];
+ public byte[] TitleKekSource { get; } = new byte[0x10];
public byte[] HeaderKekSource { get; } = new byte[0x10];
public byte[] SdCardKekSource { get; } = new byte[0x10];
public byte[][] SdCardKeySources { get; } = Util.CreateJaggedArray(2, 0x20);
- public byte[][] SdCardKeySourcesSpecific { get; } = Util.CreateJaggedArray(2, 0x20);
public byte[] HeaderKeySource { get; } = new byte[0x20];
public byte[] HeaderKey { get; } = new byte[0x20];
public byte[] XciHeaderKey { get; } = new byte[0x10];
- public byte[][] Titlekeks { get; } = Util.CreateJaggedArray(0x20, 0x10);
+ public byte[][] TitleKeks { get; } = Util.CreateJaggedArray(0x20, 0x10);
public byte[][][] KeyAreaKeys { get; } = Util.CreateJaggedArray(0x20, 3, 0x10);
- public byte[] SaveMacKey { get; } = new byte[0x10];
- public byte[][] SdCardKeys { get; } = Util.CreateJaggedArray(2, 0x20);
public byte[] EticketRsaKek { get; } = new byte[0x10];
public byte[] RetailSpecificAesKeySource { get; } = new byte[0x10];
public byte[] PerConsoleKeySource { get; } = new byte[0x10];
public byte[] BisKekSource { get; } = new byte[0x10];
- public byte[][] BisKeySource { get; } = Util.CreateJaggedArray(3, 0x20);
+ public byte[][] BisKeySource { get; } = Util.CreateJaggedArray(4, 0x20);
+ public byte[] SslRsaKek { get; } = new byte[0x10];
+ // Device-specific keys
public byte[] SecureBootKey { get; } = new byte[0x10];
public byte[] TsecKey { get; } = new byte[0x10];
public byte[] DeviceKey { get; } = new byte[0x10];
public byte[][] BisKeys { get; } = Util.CreateJaggedArray(4, 0x20);
+ public byte[] SaveMacKey { get; } = new byte[0x10];
public byte[] SdSeed { get; } = new byte[0x10];
+ public byte[][] SdCardKeySourcesSpecific { get; } = Util.CreateJaggedArray(2, 0x20);
+ public byte[][] SdCardKeys { get; } = Util.CreateJaggedArray(2, 0x20);
public RSAParameters EticketExtKeyRsa { get; set; }
@@ -128,6 +138,9 @@ namespace LibHac
DecryptKeyblobs(logger);
ReadKeyblobs();
+ Derive620MasterKeks();
+ DeriveMasterKeys();
+
DerivePerConsoleKeys();
DerivePerFirmwareKeys();
DeriveNcaHeaderKey();
@@ -141,7 +154,7 @@ namespace LibHac
bool haveKeyblobMacKeySource = !MasterKeySource.IsEmpty();
var temp = new byte[0x10];
- for (int i = 0; i < 0x20; i++)
+ for (int i = 0; i < UsedKeyblobCount; i++)
{
if (KeyblobKeySources[i].IsEmpty()) continue;
@@ -160,7 +173,7 @@ namespace LibHac
var expectedCmac = new byte[0x10];
var counter = new byte[0x10];
- for (int i = 0; i < 0x20; i++)
+ for (int i = 0; i < UsedKeyblobCount; i++)
{
if (KeyblobKeys[i].IsEmpty() || KeyblobMacKeys[i].IsEmpty() || EncryptedKeyblobs[i].IsEmpty())
{
@@ -187,21 +200,34 @@ namespace LibHac
private void ReadKeyblobs()
{
- var masterKek = new byte[0x10];
-
- bool haveMasterKeySource = !MasterKeySource.IsEmpty();
-
- for (int i = 0; i < 0x20; i++)
+ for (int i = 0; i < UsedKeyblobCount; i++)
{
if (Keyblobs[i].IsEmpty()) continue;
Array.Copy(Keyblobs[i], 0x80, Package1Keys[i], 0, 0x10);
+ Array.Copy(Keyblobs[i], MasterKeks[i], 0x10);
+ }
+ }
- if (!haveMasterKeySource) continue;
+ private void Derive620MasterKeks()
+ {
+ for (int i = UsedKeyblobCount; i < 0x20; i++)
+ {
+ if (TsecRootKeys[i].IsEmpty() || MasterKekSources[i].IsEmpty()) continue;
- Array.Copy(Keyblobs[i], masterKek, 0x10);
+ Crypto.DecryptEcb(TsecRootKeys[i], MasterKekSources[i], MasterKeks[i], 0x10);
+ }
+ }
- Crypto.DecryptEcb(masterKek, MasterKeySource, MasterKeys[i], 0x10);
+ private void DeriveMasterKeys()
+ {
+ if (MasterKeySource.IsEmpty()) return;
+
+ for (int i = 0; i < 0x20; i++)
+ {
+ if (MasterKeks[i].IsEmpty()) continue;
+
+ Crypto.DecryptEcb(MasterKeks[i], MasterKeySource, MasterKeys[i], 0x10);
}
}
@@ -252,7 +278,7 @@ namespace LibHac
bool haveKakSource0 = !KeyAreaKeyApplicationSource.IsEmpty();
bool haveKakSource1 = !KeyAreaKeyOceanSource.IsEmpty();
bool haveKakSource2 = !KeyAreaKeySystemSource.IsEmpty();
- bool haveTitleKekSource = !TitlekekSource.IsEmpty();
+ bool haveTitleKekSource = !TitleKekSource.IsEmpty();
bool havePackage2KeySource = !Package2KeySource.IsEmpty();
for (int i = 0; i < 0x20; i++)
@@ -282,7 +308,7 @@ namespace LibHac
if (haveTitleKekSource)
{
- Crypto.DecryptEcb(MasterKeys[i], TitlekekSource, Titlekeks[i], 0x10);
+ Crypto.DecryptEcb(MasterKeys[i], TitleKekSource, TitleKeks[i], 0x10);
}
if (havePackage2KeySource)
@@ -322,7 +348,7 @@ namespace LibHac
}
}
- internal static readonly string[] KakNames = {"application", "ocean", "system"};
+ internal static readonly string[] KakNames = { "application", "ocean", "system" };
}
public static class ExternalKeys
@@ -514,7 +540,7 @@ namespace LibHac
new KeyValue("key_area_key_application_source", 0x10, set => set.KeyAreaKeyApplicationSource),
new KeyValue("key_area_key_ocean_source", 0x10, set => set.KeyAreaKeyOceanSource),
new KeyValue("key_area_key_system_source", 0x10, set => set.KeyAreaKeySystemSource),
- new KeyValue("titlekek_source", 0x10, set => set.TitlekekSource),
+ new KeyValue("titlekek_source", 0x10, set => set.TitleKekSource),
new KeyValue("header_kek_source", 0x10, set => set.HeaderKekSource),
new KeyValue("header_key_source", 0x20, set => set.HeaderKeySource),
new KeyValue("header_key", 0x20, set => set.HeaderKey),
@@ -531,7 +557,7 @@ namespace LibHac
new KeyValue("bis_kek_source", 0x10, set => set.BisKekSource),
new KeyValue("save_mac_kek_source", 0x10, set => set.SaveMacKekSource),
new KeyValue("save_mac_key_source", 0x10, set => set.SaveMacKeySource),
- new KeyValue("save_mac_key", 0x10, set => set.SaveMacKey)
+ new KeyValue("ssl_rsa_kek", 0x10, set => set.SslRsaKek)
};
for (int slot = 0; slot < 0x20; slot++)
@@ -539,16 +565,19 @@ namespace LibHac
int i = slot;
keys.Add(new KeyValue($"keyblob_key_source_{i:x2}", 0x10, set => set.KeyblobKeySources[i]));
keys.Add(new KeyValue($"keyblob_{i:x2}", 0x90, set => set.Keyblobs[i]));
+ keys.Add(new KeyValue($"tsec_root_key_{i:x2}", 0x10, set => set.TsecRootKeys[i]));
keys.Add(new KeyValue($"master_key_{i:x2}", 0x10, set => set.MasterKeys[i]));
+ keys.Add(new KeyValue($"master_kek_{i:x2}", 0x10, set => set.MasterKeks[i]));
+ keys.Add(new KeyValue($"master_kek_source_{i:x2}", 0x10, set => set.MasterKekSources[i]));
keys.Add(new KeyValue($"package1_key_{i:x2}", 0x10, set => set.Package1Keys[i]));
keys.Add(new KeyValue($"package2_key_{i:x2}", 0x10, set => set.Package2Keys[i]));
- keys.Add(new KeyValue($"titlekek_{i:x2}", 0x10, set => set.Titlekeks[i]));
+ keys.Add(new KeyValue($"titlekek_{i:x2}", 0x10, set => set.TitleKeks[i]));
keys.Add(new KeyValue($"key_area_key_application_{i:x2}", 0x10, set => set.KeyAreaKeys[i][0]));
keys.Add(new KeyValue($"key_area_key_ocean_{i:x2}", 0x10, set => set.KeyAreaKeys[i][1]));
keys.Add(new KeyValue($"key_area_key_system_{i:x2}", 0x10, set => set.KeyAreaKeys[i][2]));
}
- for (int slot = 0; slot < 3; slot++)
+ for (int slot = 0; slot < 4; slot++)
{
int i = slot;
keys.Add(new KeyValue($"bis_key_source_{i:x2}", 0x20, set => set.BisKeySource[i]));
@@ -564,7 +593,8 @@ namespace LibHac
new KeyValue("secure_boot_key", 0x10, set => set.SecureBootKey),
new KeyValue("tsec_key", 0x10, set => set.TsecKey),
new KeyValue("device_key", 0x10, set => set.DeviceKey),
- new KeyValue("sd_seed", 0x10, set => set.SdSeed)
+ new KeyValue("sd_seed", 0x10, set => set.SdSeed),
+ new KeyValue("save_mac_key", 0x10, set => set.SaveMacKey)
};
for (int slot = 0; slot < 0x20; slot++)
diff --git a/src/LibHac/Nca.cs b/src/LibHac/Nca.cs
index 6a0baf66..341ee4c1 100644
--- a/src/LibHac/Nca.cs
+++ b/src/LibHac/Nca.cs
@@ -48,13 +48,13 @@ namespace LibHac
}
else if (keyset.TitleKeys.TryGetValue(Header.RightsId, out byte[] titleKey))
{
- if (keyset.Titlekeks[CryptoType].IsEmpty())
+ if (keyset.TitleKeks[CryptoType].IsEmpty())
{
MissingKeyName = $"titlekek_{CryptoType:x2}";
}
TitleKey = titleKey;
- Crypto.DecryptEcb(keyset.Titlekeks[CryptoType], titleKey, TitleKeyDec, 0x10);
+ Crypto.DecryptEcb(keyset.TitleKeks[CryptoType], titleKey, TitleKeyDec, 0x10);
DecryptedKeys[2] = TitleKeyDec;
}
else
diff --git a/src/LibHac/Util.cs b/src/LibHac/Util.cs
index 5a93e623..cb2a3329 100644
--- a/src/LibHac/Util.cs
+++ b/src/LibHac/Util.cs
@@ -424,6 +424,8 @@ namespace LibHac
case 3: return "4.0.0-4.1.0";
case 4: return "5.0.0-5.1.0";
case 5: return "6.0.0-6.0.1";
+ case 6: return "6.2.0";
+ case 7: return "7.0.0";
default: return "Unknown";
}
}