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; } Crypto.DecryptEcb(TsecKey, KeyblobKeySources[i], temp, 0x10); Crypto.DecryptEcb(SecureBootKey, temp, KeyblobKeys[i], 0x10); if (!haveKeyblobMacKeySource) { continue; } Crypto.DecryptEcb(KeyblobKeys[i], KeyblobMacKeySource, KeyblobMacKeys[i], 0x10); } }
private void ReadKeyblobs() { var masterKek = new byte[0x10]; bool haveMasterKeySource = !MasterKeySource.IsEmpty(); for (int i = 0; i < 0x20; i++) { if (Keyblobs[i].IsEmpty()) { continue; } Array.Copy(Keyblobs[i], 0x80, Package1Keys[i], 0, 0x10); if (!haveMasterKeySource) { continue; } Array.Copy(Keyblobs[i], masterKek, 0x10); Crypto.DecryptEcb(masterKek, MasterKeySource, MasterKeys[i], 0x10); } }
public void DeriveSdCardKeys() { var sdKek = new byte[0x10]; Crypto.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++) { Crypto.DecryptEcb(sdKek, SdCardKeySourcesSpecific[k], SdCardKeys[k], 0x20); } // 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]); } Crypto.GenerateKek(MasterKeys[0], SaveMacSdCardKekSource, sdKek, AesKekGenerationSource, null); Crypto.DecryptEcb(sdKek, keySource, SaveMacSdCardKey, 0x10); } }
private void Derive620MasterKeks() { for (int i = UsedKeyblobCount; i < 0x20; i++) { if (TsecRootKeys[i - UsedKeyblobCount].IsEmpty() || MasterKekSources[i].IsEmpty()) { continue; } Crypto.DecryptEcb(TsecRootKeys[i - UsedKeyblobCount], MasterKekSources[i], MasterKeks[i], 0x10); } }
private void DeriveNcaHeaderKey() { if (HeaderKekSource.IsEmpty() || HeaderKeySource.IsEmpty() || MasterKeys[0].IsEmpty()) { return; } var headerKek = new byte[0x10]; Crypto.GenerateKek(MasterKeys[0], HeaderKekSource, headerKek, AesKekGenerationSource, AesKeyGenerationSource); Crypto.DecryptEcb(headerKek, HeaderKeySource, HeaderKey, 0x20); }
private void DerivePerConsoleKeys() { var kek = new byte[0x10]; // Derive the device key if (!PerConsoleKeySource.IsEmpty() && !KeyblobKeys[0].IsEmpty()) { Crypto.DecryptEcb(KeyblobKeys[0], PerConsoleKeySource, DeviceKey, 0x10); } // Derive save key if (!SaveMacKekSource.IsEmpty() && !SaveMacKeySource.IsEmpty() && !DeviceKey.IsEmpty()) { Crypto.GenerateKek(DeviceKey, SaveMacKekSource, kek, AesKekGenerationSource, null); Crypto.DecryptEcb(kek, SaveMacKeySource, SaveMacKey, 0x10); } // 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); } Crypto.DecryptEcb(DeviceKey, RetailSpecificAesKeySource, kek, 0x10); if (!BisKeySource[0].IsEmpty()) { Crypto.DecryptEcb(kek, BisKeySource[0], BisKeys[0], 0x20); } Crypto.GenerateKek(DeviceKey, BisKekSource, kek, AesKekGenerationSource, AesKeyGenerationSource); for (int i = 1; i < 4; i++) { if (!BisKeySource[i].IsEmpty()) { Crypto.DecryptEcb(kek, BisKeySource[i], BisKeys[i], 0x20); } } }
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); } }
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) { Crypto.GenerateKek(MasterKeys[i], KeyAreaKeyApplicationSource, KeyAreaKeys[i][0], AesKekGenerationSource, AesKeyGenerationSource); } if (haveKakSource1) { Crypto.GenerateKek(MasterKeys[i], KeyAreaKeyOceanSource, KeyAreaKeys[i][1], AesKekGenerationSource, AesKeyGenerationSource); } if (haveKakSource2) { Crypto.GenerateKek(MasterKeys[i], KeyAreaKeySystemSource, KeyAreaKeys[i][2], AesKekGenerationSource, AesKeyGenerationSource); } if (haveTitleKekSource) { Crypto.DecryptEcb(MasterKeys[i], TitleKekSource, TitleKeks[i], 0x10); } if (havePackage2KeySource) { Crypto.DecryptEcb(MasterKeys[i], Package2KeySource, Package2Keys[i], 0x10); } } }
public void DeriveSdCardKeys() { var sdKek = new byte[0x10]; Crypto.GenerateKek(MasterKeys[0], SdCardKekSource, sdKek, AesKekGenerationSource, AesKeyGenerationSource); for (int k = 0; k < SdCardKeySources.Length; k++) { for (int i = 0; i < 0x20; i++) { SdCardKeySourcesSpecific[k][i] = (byte)(SdCardKeySources[k][i] ^ SdSeed[i & 0xF]); } } for (int k = 0; k < SdCardKeySourcesSpecific.Length; k++) { Crypto.DecryptEcb(sdKek, SdCardKeySourcesSpecific[k], SdCardKeys[k], 0x20); } }
private void DeriveKeys(Keyset keyset, string sdPath, IStorage storage) { var validationHashKey = new byte[0x60]; storage.Read(validationHashKey, 0x20); // Try both the NCA and save key sources and pick the one that works for (int k = 0; k < 2; k++) { var naxSpecificKeys = Util.CreateJaggedArray <byte[][]>(2, 0x10); var hashKey = new byte[0x10]; Array.Copy(keyset.SdCardKeys[k], hashKey, 0x10); // Use the sd path to generate the kek for this NAX0 var hash = new HMACSHA256(hashKey); byte[] sdPathBytes = Encoding.ASCII.GetBytes(sdPath); byte[] checksum = hash.ComputeHash(sdPathBytes, 0, sdPathBytes.Length); Array.Copy(checksum, 0, naxSpecificKeys[0], 0, 0x10); Array.Copy(checksum, 0x10, naxSpecificKeys[1], 0, 0x10); // Decrypt this NAX0's keys Crypto.DecryptEcb(naxSpecificKeys[0], EncKeys[0], Keys[0], 0x10); Crypto.DecryptEcb(naxSpecificKeys[1], EncKeys[1], Keys[1], 0x10); Array.Copy(Keys[0], 0, Key, 0, 0x10); Array.Copy(Keys[1], 0, Key, 0x10, 0x10); // Copy the decrypted keys into the NAX0 header and use that for the HMAC key // for validating that the keys are correct Array.Copy(Keys[0], 0, validationHashKey, 8, 0x10); Array.Copy(Keys[1], 0, validationHashKey, 0x18, 0x10); var validationHash = new HMACSHA256(validationHashKey); byte[] validationMac = validationHash.ComputeHash(keyset.SdCardKeys[k], 0x10, 0x10); if (Util.ArraysEqual(Hmac, validationMac)) { return; } } throw new ArgumentException("NAX0 key derivation failed."); }
private void DerivePerConsoleKeys() { var kek = new byte[0x10]; // Derive the device key if (!PerConsoleKeySource.IsEmpty() && !KeyblobKeys[0].IsEmpty()) { Crypto.DecryptEcb(KeyblobKeys[0], PerConsoleKeySource, DeviceKey, 0x10); } // Derive save key if (!SaveMacKekSource.IsEmpty() && !SaveMacKeySource.IsEmpty() && !DeviceKey.IsEmpty()) { Crypto.GenerateKek(DeviceKey, SaveMacKekSource, kek, AesKekGenerationSource, null); Crypto.DecryptEcb(kek, SaveMacKeySource, SaveMacKey, 0x10); } // Derive BIS keys if (DeviceKey.IsEmpty() || BisKeySource[0].IsEmpty() || BisKeySource[1].IsEmpty() || BisKeySource[2].IsEmpty() || BisKekSource.IsEmpty() || AesKekGenerationSource.IsEmpty() || AesKeyGenerationSource.IsEmpty() || RetailSpecificAesKeySource.IsEmpty()) { return; } Crypto.DecryptEcb(DeviceKey, RetailSpecificAesKeySource, kek, 0x10); Crypto.DecryptEcb(kek, BisKeySource[0], BisKeys[0], 0x20); Crypto.GenerateKek(DeviceKey, BisKekSource, kek, AesKekGenerationSource, AesKeyGenerationSource); Crypto.DecryptEcb(kek, BisKeySource[1], BisKeys[1], 0x20); Crypto.DecryptEcb(kek, BisKeySource[2], BisKeys[2], 0x20); // BIS keys 2 and 3 are the same Array.Copy(BisKeys[2], BisKeys[3], 0x20); }