public byte[] GetDecryptedTitleKey() { int keyRevision = Utilities.GetMasterKeyRevision(Header.KeyGeneration); byte[] titleKek = KeySet.TitleKeks[keyRevision].DataRo.ToArray(); var rightsId = new RightsId(Header.RightsId); if (KeySet.ExternalKeySet.Get(rightsId, out AccessKey accessKey).IsFailure()) { throw new MissingKeyException("Missing NCA title key.", rightsId.ToString(), KeyType.Title); } if (titleKek.IsZeros()) { string keyName = $"titlekek_{keyRevision:x2}"; throw new MissingKeyException("Unable to decrypt title key.", keyName, KeyType.Common); } byte[] encryptedKey = accessKey.Value.ToArray(); byte[] decryptedKey = new byte[Aes.KeySize128]; Aes.DecryptEcb128(encryptedKey, decryptedKey, titleKek); return(decryptedKey); }
private static void DeriveKeyBlobKeys(KeySet s) { if (s.SecureBootKey.IsZeros() || s.TsecKey.IsZeros()) { return; } bool haveKeyBlobMacKeySource = !s.MasterKeySource.IsZeros(); var temp = new AesKey(); for (int i = 0; i < KeySet.UsedKeyBlobCount; i++) { if (s.KeyBlobKeySources[i].IsZeros()) { continue; } Aes.DecryptEcb128(s.KeyBlobKeySources[i], temp, s.TsecKey); Aes.DecryptEcb128(temp, s.KeyBlobKeys[i], s.SecureBootKey); if (!haveKeyBlobMacKeySource) { continue; } Aes.DecryptEcb128(s.KeyBlobMacKeySource, s.KeyBlobMacKeys[i], s.KeyBlobKeys[i]); } }
public byte[] GetDecryptedKey(int index) { if (index < 0 || index > 3) { throw new ArgumentOutOfRangeException(nameof(index)); } // Handle old NCA0s that use different key area encryption if (Header.FormatVersion == NcaVersion.Nca0FixedKey || Header.FormatVersion == NcaVersion.Nca0RsaOaep) { return(GetDecryptedKeyAreaNca0().AsSpan(0x10 * index, 0x10).ToArray()); } int keyRevision = Utilities.GetMasterKeyRevision(Header.KeyGeneration); byte[] keyAreaKey = KeySet.KeyAreaKeys[keyRevision][Header.KeyAreaKeyIndex].DataRo.ToArray(); if (keyAreaKey.IsZeros()) { string keyName = $"key_area_key_{KakNames[Header.KeyAreaKeyIndex]}_{keyRevision:x2}"; throw new MissingKeyException("Unable to decrypt NCA section.", keyName, KeyType.Common); } byte[] encryptedKey = Header.GetEncryptedKey(index).ToArray(); byte[] decryptedKey = new byte[Aes.KeySize128]; Aes.DecryptEcb128(encryptedKey, decryptedKey, keyAreaKey); return(decryptedKey); }
public static void DeriveSdCardKeys(KeySet s) { var sdKek = new AesKey(); var tempKey = new AesXtsKey(); GenerateKek(s.MasterKeys[0], s.SdCardKekSource, sdKek, s.AesKekGenerationSource, s.AesKeyGenerationSource); for (int k = 0; k < KeySet.SdCardKeyIdCount; k++) { for (int i = 0; i < 4; i++) { tempKey.Data64[i] = s.SdCardKeySources[k].Data64[i] ^ s.SdCardEncryptionSeed.Data64[i & 1]; } tempKey.Data64[0] = s.SdCardKeySources[k].Data64[0] ^ s.SdCardEncryptionSeed.Data64[0]; tempKey.Data64[1] = s.SdCardKeySources[k].Data64[1] ^ s.SdCardEncryptionSeed.Data64[1]; tempKey.Data64[2] = s.SdCardKeySources[k].Data64[2] ^ s.SdCardEncryptionSeed.Data64[0]; tempKey.Data64[3] = s.SdCardKeySources[k].Data64[3] ^ s.SdCardEncryptionSeed.Data64[1]; Aes.DecryptEcb128(tempKey, s.SdCardEncryptionKeys[k], sdKek); } // Derive sd card save key if (!s.SeedUniqueSaveMacKekSource.IsZeros() && !s.SeedUniqueSaveMacKeySource.IsZeros()) { var keySource = new AesKey(); keySource.Data64[0] = s.SeedUniqueSaveMacKeySource.Data64[0] ^ s.SdCardEncryptionSeed.Data64[0]; keySource.Data64[1] = s.SeedUniqueSaveMacKeySource.Data64[1] ^ s.SdCardEncryptionSeed.Data64[1]; GenerateKek(s.MasterKeys[0], s.SeedUniqueSaveMacKekSource, sdKek, s.AesKekGenerationSource, null); Aes.DecryptEcb128(keySource, s.SeedUniqueSaveMacKey, sdKek); } }
private static void PopulateOldMasterKeys(KeySet s) { ReadOnlySpan <AesKey> keyVectors = MasterKeyVectors(s); // Find the newest master key we have int newestMasterKey = -1; for (int i = keyVectors.Length - 1; i >= 0; i--) { if (!s.MasterKeys[i].IsZeros()) { newestMasterKey = i; break; } } if (newestMasterKey == -1) { return; } // Don't populate old master keys unless the newest master key is valid if (!TestKeyGeneration(s, newestMasterKey)) { return; } // Decrypt all previous master keys for (int i = newestMasterKey; i > 0; i--) { Aes.DecryptEcb128(keyVectors[i], s.MasterKeys[i - 1], s.MasterKeys[i]); } }
private static void DerivePerConsoleKeys(KeySet s) { // Todo: Dev and newer key generations var kek = new AesKey(); // Derive the device key if (!s.PerConsoleKeySource.IsZeros() && !s.KeyBlobKeys[0].IsZeros()) { Aes.DecryptEcb128(s.PerConsoleKeySource, s.DeviceKey, s.KeyBlobKeys[0]); } // Derive device-unique save keys for (int i = 0; i < s.DeviceUniqueSaveMacKeySources.Length; i++) { if (!s.DeviceUniqueSaveMacKekSource.IsZeros() && !s.DeviceUniqueSaveMacKeySources[i].IsZeros() && !s.DeviceKey.IsZeros()) { GenerateKek(s.DeviceKey, s.DeviceUniqueSaveMacKekSource, kek, s.AesKekGenerationSource, null); Aes.DecryptEcb128(s.DeviceUniqueSaveMacKeySources[i], s.DeviceUniqueSaveMacKeys[i], kek); } } // Derive BIS keys if (s.DeviceKey.IsZeros() || s.BisKekSource.IsZeros() || s.AesKekGenerationSource.IsZeros() || s.AesKeyGenerationSource.IsZeros() || s.RetailSpecificAesKeySource.IsZeros()) { return; } // If the user doesn't provide bis_key_source_03 we can assume it's the same as bis_key_source_02 if (s.BisKeySources[3].IsZeros() && !s.BisKeySources[2].IsZeros()) { s.BisKeySources[3] = s.BisKeySources[2]; } Aes.DecryptEcb128(s.RetailSpecificAesKeySource, kek, s.DeviceKey); if (!s.BisKeySources[0].IsZeros()) { Aes.DecryptEcb128(s.BisKeySources[0], s.BisKeys[0], kek); } GenerateKek(s.DeviceKey, s.BisKekSource, kek, s.AesKekGenerationSource, s.AesKeyGenerationSource); for (int i = 1; i < 4; i++) { if (!s.BisKeySources[i].IsZeros()) { Aes.DecryptEcb128(s.BisKeySources[i], s.BisKeys[i], kek); } } }
private static void DeriveNcaHeaderKey(KeySet s) { if (s.HeaderKekSource.IsZeros() || s.HeaderKeySource.IsZeros() || s.MasterKeys[0].IsZeros()) { return; } var headerKek = new AesKey(); GenerateKek(s.MasterKeys[0], s.HeaderKekSource, headerKek, s.AesKekGenerationSource, s.AesKeyGenerationSource); Aes.DecryptEcb128(s.HeaderKeySource, s.HeaderKey, headerKek); }
private static void Derive620MasterKeks(KeySet s) { for (int i = KeySet.UsedKeyBlobCount; i < KeySet.KeyRevisionCount; i++) { // Key revisions >= 8 all use the same TSEC root key int tsecRootKeyIndex = Math.Min(i, 8) - KeySet.UsedKeyBlobCount; if (s.TsecRootKeys[tsecRootKeyIndex].IsZeros() || s.MasterKekSources[i].IsZeros()) { continue; } Aes.DecryptEcb128(s.MasterKekSources[i], s.MasterKeks[i], s.TsecRootKeys[tsecRootKeyIndex]); } }
private static void DeriveMasterKeys(KeySet s) { if (s.MasterKeySource.IsZeros()) { return; } for (int i = 0; i < KeySet.KeyRevisionCount; i++) { if (s.MasterKeks[i].IsZeros()) { continue; } Aes.DecryptEcb128(s.MasterKeySource, s.MasterKeys[i], s.MasterKeks[i]); } }
private static void GenerateKek(ReadOnlySpan <byte> key, ReadOnlySpan <byte> src, Span <byte> dest, ReadOnlySpan <byte> kekSeed, ReadOnlySpan <byte> keySeed) { var kek = new AesKey(); var srcKek = new AesKey(); Aes.DecryptEcb128(kekSeed, kek, key); Aes.DecryptEcb128(src, srcKek, kek); if (!keySeed.IsZeros()) { Aes.DecryptEcb128(keySeed, dest, srcKek); } else { srcKek.Data.CopyTo(dest); } }
/// <summary> /// Check if the master key of the specified generation is correct. /// </summary> /// <param name="s">The <see cref="KeySet"/> to test.</param> /// <param name="generation">The generation to test.</param> /// <returns><see langword="true"/> if the key is correct.</returns> private static bool TestKeyGeneration(KeySet s, int generation) { ReadOnlySpan <AesKey> keyVectors = MasterKeyVectors(s); // Decrypt the vector chain until we get Master Key 0 AesKey key = s.MasterKeys[generation]; for (int i = generation; i > 0; i--) { Aes.DecryptEcb128(keyVectors[i], key, key); } // Decrypt the zeros with Master Key 0 Aes.DecryptEcb128(keyVectors[0], key, key); // If we don't get zeros, MasterKeys[generation] is incorrect return(key.IsZeros()); }
private static void DerivePerGenerationKeys(KeySet s) { bool haveKakSource0 = !s.KeyAreaKeyApplicationSource.IsZeros(); bool haveKakSource1 = !s.KeyAreaKeyOceanSource.IsZeros(); bool haveKakSource2 = !s.KeyAreaKeySystemSource.IsZeros(); bool haveTitleKekSource = !s.TitleKekSource.IsZeros(); bool havePackage2KeySource = !s.Package2KeySource.IsZeros(); for (int i = 0; i < KeySet.KeyRevisionCount; i++) { if (s.MasterKeys[i].IsZeros()) { continue; } if (haveKakSource0) { GenerateKek(s.MasterKeys[i], s.KeyAreaKeyApplicationSource, s.KeyAreaKeys[i][0], s.AesKekGenerationSource, s.AesKeyGenerationSource); } if (haveKakSource1) { GenerateKek(s.MasterKeys[i], s.KeyAreaKeyOceanSource, s.KeyAreaKeys[i][1], s.AesKekGenerationSource, s.AesKeyGenerationSource); } if (haveKakSource2) { GenerateKek(s.MasterKeys[i], s.KeyAreaKeySystemSource, s.KeyAreaKeys[i][2], s.AesKekGenerationSource, s.AesKeyGenerationSource); } if (haveTitleKekSource) { Aes.DecryptEcb128(s.TitleKekSource, s.TitleKeks[i], s.MasterKeys[i]); } if (havePackage2KeySource) { Aes.DecryptEcb128(s.Package2KeySource, s.Package2Keys[i], s.MasterKeys[i]); } } }