public void DeriveSdCardKeys() { var sdKek = new byte[0x10]; GenerateKek(MasterKeys[0], SdCardKekSource, sdKek, AesKekGenerationSource, AesKeyGenerationSource); for (int k = 0; k < SdCardKeyIdCount; k++) { for (int i = 0; i < 0x20; i++) { SdCardKeySourcesSpecific[k][i] = (byte)(SdCardKeySources[k][i] ^ SdSeed[i & 0xF]); } } for (int k = 0; k < SdCardKeyIdCount; k++) { Aes.DecryptEcb128(SdCardKeySourcesSpecific[k], SdCardKeys[k], sdKek); } // Derive sd card save key if (!SaveMacSdCardKekSource.IsEmpty() && !SaveMacSdCardKeySource.IsEmpty()) { var keySource = new byte[0x10]; for (int i = 0; i < 0x10; i++) { keySource[i] = (byte)(SaveMacSdCardKeySource[i] ^ SdSeed[i]); } GenerateKek(MasterKeys[0], SaveMacSdCardKekSource, sdKek, AesKekGenerationSource, null); Aes.DecryptEcb128(keySource, SaveMacSdCardKey, sdKek); } }
private void DecryptKeyblobs(IProgressReport logger = null) { var cmac = new byte[0x10]; var expectedCmac = new byte[0x10]; var counter = new byte[0x10]; for (int i = 0; i < UsedKeyblobCount; i++) { if (KeyblobKeys[i].IsEmpty() || KeyblobMacKeys[i].IsEmpty() || EncryptedKeyblobs[i].IsEmpty()) { continue; } Array.Copy(EncryptedKeyblobs[i], expectedCmac, 0x10); Aes.CalculateCmac(cmac, EncryptedKeyblobs[i].AsSpan(0x10, 0xA0), KeyblobMacKeys[i]); if (!Utilities.ArraysEqual(cmac, expectedCmac)) { logger?.LogMessage($"Warning: Keyblob MAC {i:x2} is invalid. Are SBK/TSEC key correct?"); } Array.Copy(EncryptedKeyblobs[i], 0x10, counter, 0, 0x10); Aes.DecryptCtr128(EncryptedKeyblobs[i].AsSpan(0x20), Keyblobs[i], KeyblobKeys[i], counter); } }
private void DeriveKeyblobKeys() { if (SecureBootKey.IsEmpty() || TsecKey.IsEmpty()) { return; } bool haveKeyblobMacKeySource = !MasterKeySource.IsEmpty(); var temp = new byte[0x10]; for (int i = 0; i < UsedKeyblobCount; i++) { if (KeyblobKeySources[i].IsEmpty()) { continue; } Aes.DecryptEcb128(KeyblobKeySources[i], temp, TsecKey); Aes.DecryptEcb128(temp, KeyblobKeys[i], SecureBootKey); if (!haveKeyblobMacKeySource) { continue; } Aes.DecryptEcb128(KeyblobMacKeySource, KeyblobMacKeys[i], KeyblobKeys[i]); } }
private void Derive620MasterKeks() { for (int i = UsedKeyblobCount; i < 0x20; i++) { if (TsecRootKeys[i - UsedKeyblobCount].IsEmpty() || MasterKekSources[i].IsEmpty()) { continue; } Aes.DecryptEcb128(MasterKekSources[i], MasterKeks[i], TsecRootKeys[i - UsedKeyblobCount]); } }
private void DeriveNcaHeaderKey() { if (HeaderKekSource.IsEmpty() || HeaderKeySource.IsEmpty() || MasterKeys[0].IsEmpty()) { return; } var headerKek = new byte[0x10]; GenerateKek(MasterKeys[0], HeaderKekSource, headerKek, AesKekGenerationSource, AesKeyGenerationSource); Aes.DecryptEcb128(HeaderKeySource, HeaderKey, headerKek); }
private void DerivePerConsoleKeys() { var kek = new byte[0x10]; // Derive the device key if (!PerConsoleKeySource.IsEmpty() && !KeyblobKeys[0].IsEmpty()) { Aes.DecryptEcb128(PerConsoleKeySource, DeviceKey, KeyblobKeys[0]); } // Derive save key if (!SaveMacKekSource.IsEmpty() && !SaveMacKeySource.IsEmpty() && !DeviceKey.IsEmpty()) { GenerateKek(DeviceKey, SaveMacKekSource, kek, AesKekGenerationSource, null); Aes.DecryptEcb128(SaveMacKeySource, SaveMacKey, kek); } // Derive BIS keys if (DeviceKey.IsEmpty() || BisKekSource.IsEmpty() || AesKekGenerationSource.IsEmpty() || AesKeyGenerationSource.IsEmpty() || RetailSpecificAesKeySource.IsEmpty()) { return; } // If the user doesn't provide bis_key_source_03 we can assume it's the same as bis_key_source_02 if (BisKeySource[3].IsEmpty() && !BisKeySource[2].IsEmpty()) { Array.Copy(BisKeySource[2], BisKeySource[3], 0x20); } Aes.DecryptEcb128(RetailSpecificAesKeySource, kek, DeviceKey); if (!BisKeySource[0].IsEmpty()) { Aes.DecryptEcb128(BisKeySource[0], BisKeys[0], kek); } GenerateKek(DeviceKey, BisKekSource, kek, AesKekGenerationSource, AesKeyGenerationSource); for (int i = 1; i < 4; i++) { if (!BisKeySource[i].IsEmpty()) { Aes.DecryptEcb128(BisKeySource[i], BisKeys[i], kek); } } }
public static void GenerateKek(byte[] key, byte[] src, byte[] dest, byte[] kekSeed, byte[] keySeed) { var kek = new byte[Aes.KeySize128]; var srcKek = new byte[Aes.KeySize128]; Aes.DecryptEcb128(kekSeed, kek, key); Aes.DecryptEcb128(src, srcKek, kek); if (keySeed != null) { Aes.DecryptEcb128(keySeed, dest, srcKek); } else { Array.Copy(srcKek, dest, Aes.KeySize128); } }
private static void GenerateKek(ReadOnlySpan <byte> key, ReadOnlySpan <byte> src, Span <byte> dest, ReadOnlySpan <byte> kekSeed, ReadOnlySpan <byte> keySeed) { Span <byte> kek = stackalloc byte[0x10]; Span <byte> srcKek = stackalloc byte[0x10]; Aes.DecryptEcb128(kekSeed, kek, key); Aes.DecryptEcb128(src, srcKek, kek); if (!keySeed.IsEmpty) { Aes.DecryptEcb128(keySeed, dest, srcKek); } else { srcKek.CopyTo(dest); } }
private void DeriveMasterKeys() { if (MasterKeySource.IsEmpty()) { return; } for (int i = 0; i < 0x20; i++) { if (MasterKeks[i].IsEmpty()) { continue; } Aes.DecryptEcb128(MasterKeySource, MasterKeys[i], MasterKeks[i]); } }
private void DerivePerFirmwareKeys() { bool haveKakSource0 = !KeyAreaKeyApplicationSource.IsEmpty(); bool haveKakSource1 = !KeyAreaKeyOceanSource.IsEmpty(); bool haveKakSource2 = !KeyAreaKeySystemSource.IsEmpty(); bool haveTitleKekSource = !TitleKekSource.IsEmpty(); bool havePackage2KeySource = !Package2KeySource.IsEmpty(); for (int i = 0; i < 0x20; i++) { if (MasterKeys[i].IsEmpty()) { continue; } if (haveKakSource0) { GenerateKek(MasterKeys[i], KeyAreaKeyApplicationSource, KeyAreaKeys[i][0], AesKekGenerationSource, AesKeyGenerationSource); } if (haveKakSource1) { GenerateKek(MasterKeys[i], KeyAreaKeyOceanSource, KeyAreaKeys[i][1], AesKekGenerationSource, AesKeyGenerationSource); } if (haveKakSource2) { GenerateKek(MasterKeys[i], KeyAreaKeySystemSource, KeyAreaKeys[i][2], AesKekGenerationSource, AesKeyGenerationSource); } if (haveTitleKekSource) { Aes.DecryptEcb128(TitleKekSource, TitleKeks[i], MasterKeys[i]); } if (havePackage2KeySource) { Aes.DecryptEcb128(Package2KeySource, Package2Keys[i], MasterKeys[i]); } } }