diff options
| author | 2019-04-10 10:22:04 -0400 | |
|---|---|---|
| committer | 2019-07-07 21:38:33 -0400 | |
| commit | e35fac205406c6d485bd755c4260a69f312eeaf6 (patch) | |
| tree | 3cd23d06902fc9c8339716be849265d8dda7b281 /src/core/crypto/key_manager.cpp | |
| parent | key_manager: Add equality operator for RSAKeyPair (diff) | |
| download | yuzu-e35fac205406c6d485bd755c4260a69f312eeaf6.tar.gz yuzu-e35fac205406c6d485bd755c4260a69f312eeaf6.tar.xz yuzu-e35fac205406c6d485bd755c4260a69f312eeaf6.zip | |
key_manager: Add accessors/helpers for ticket management
Diffstat (limited to 'src/core/crypto/key_manager.cpp')
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 100 |
1 files changed, 86 insertions, 14 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 6dd633363..ef139902d 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -135,6 +135,28 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) { | |||
| 135 | } | 135 | } |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | RSAKeyPair<2048> KeyManager::GetETicketRSAKey() { | ||
| 139 | if (eticket_extended_kek == std::array<u8, 576>{} || !HasKey(S128KeyType::ETicketRSAKek)) | ||
| 140 | return {}; | ||
| 141 | |||
| 142 | const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek); | ||
| 143 | |||
| 144 | std::vector<u8> extended_iv(0x10); | ||
| 145 | std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); | ||
| 146 | std::array<u8, 0x230> extended_dec{}; | ||
| 147 | AESCipher<Key128> rsa_1(eticket_final, Mode::CTR); | ||
| 148 | rsa_1.SetIV(extended_iv); | ||
| 149 | rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10, | ||
| 150 | extended_dec.data(), Op::Decrypt); | ||
| 151 | |||
| 152 | RSAKeyPair<2048> rsa_key{}; | ||
| 153 | std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); | ||
| 154 | std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); | ||
| 155 | std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); | ||
| 156 | |||
| 157 | return rsa_key; | ||
| 158 | } | ||
| 159 | |||
| 138 | Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) { | 160 | Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) { |
| 139 | AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB); | 161 | AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB); |
| 140 | Key128 mac_key{}; | 162 | Key128 mac_key{}; |
| @@ -450,6 +472,8 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { | |||
| 450 | 472 | ||
| 451 | const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16); | 473 | const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16); |
| 452 | encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]); | 474 | encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]); |
| 475 | } else if (out[0].compare(0, 20, "eticket_extended_kek") == 0) { | ||
| 476 | eticket_extended_kek = Common::HexStringToArray<576>(out[1]); | ||
| 453 | } else { | 477 | } else { |
| 454 | for (const auto& kv : KEYS_VARIABLE_LENGTH) { | 478 | for (const auto& kv : KEYS_VARIABLE_LENGTH) { |
| 455 | if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) | 479 | if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) |
| @@ -862,20 +886,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { | |||
| 862 | // Titlekeys | 886 | // Titlekeys |
| 863 | data.DecryptProdInfo(GetBISKey(0)); | 887 | data.DecryptProdInfo(GetBISKey(0)); |
| 864 | 888 | ||
| 865 | const auto eticket_extended_kek = data.GetETicketExtendedKek(); | 889 | eticket_extended_kek = data.GetETicketExtendedKek(); |
| 890 | WriteKeyToFile(KeyCategory::Console, "eticket_extended_kek", eticket_extended_kek); | ||
| 891 | PopulateTickets(); | ||
| 892 | } | ||
| 866 | 893 | ||
| 867 | std::vector<u8> extended_iv(0x10); | 894 | void KeyManager::PopulateTickets() { |
| 868 | std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); | 895 | const auto rsa_key = GetETicketRSAKey(); |
| 869 | std::array<u8, 0x230> extended_dec{}; | ||
| 870 | AESCipher<Key128> rsa_1(eticket_final, Mode::CTR); | ||
| 871 | rsa_1.SetIV(extended_iv); | ||
| 872 | rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10, | ||
| 873 | extended_dec.data(), Op::Decrypt); | ||
| 874 | 896 | ||
| 875 | RSAKeyPair<2048> rsa_key{}; | 897 | if (rsa_key == RSAKeyPair<2048>{}) |
| 876 | std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); | 898 | return; |
| 877 | std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); | 899 | |
| 878 | std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); | 900 | if (!common_tickets.empty() && !personal_tickets.empty()) |
| 901 | return; | ||
| 879 | 902 | ||
| 880 | const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | 903 | const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + |
| 881 | "/system/save/80000000000000e1", | 904 | "/system/save/80000000000000e1", |
| @@ -886,15 +909,24 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { | |||
| 886 | 909 | ||
| 887 | const auto blob2 = GetTicketblob(save2); | 910 | const auto blob2 = GetTicketblob(save2); |
| 888 | auto res = GetTicketblob(save1); | 911 | auto res = GetTicketblob(save1); |
| 912 | const auto idx = res.size(); | ||
| 889 | res.insert(res.end(), blob2.begin(), blob2.end()); | 913 | res.insert(res.end(), blob2.begin(), blob2.end()); |
| 890 | 914 | ||
| 891 | for (const auto& raw : res) { | 915 | for (std::size_t i = 0; i < res.size(); ++i) { |
| 892 | const auto pair = ParseTicket(raw, rsa_key); | 916 | const auto common = i < idx; |
| 917 | const auto pair = ParseTicket(res[i], rsa_key); | ||
| 893 | if (!pair) | 918 | if (!pair) |
| 894 | continue; | 919 | continue; |
| 895 | const auto& [rid, key] = *pair; | 920 | const auto& [rid, key] = *pair; |
| 896 | u128 rights_id; | 921 | u128 rights_id; |
| 897 | std::memcpy(rights_id.data(), rid.data(), rid.size()); | 922 | std::memcpy(rights_id.data(), rid.data(), rid.size()); |
| 923 | |||
| 924 | if (common) { | ||
| 925 | common_tickets[rights_id] = res[i]; | ||
| 926 | } else { | ||
| 927 | personal_tickets[rights_id] = res[i]; | ||
| 928 | } | ||
| 929 | |||
| 898 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | 930 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); |
| 899 | } | 931 | } |
| 900 | } | 932 | } |
| @@ -997,6 +1029,46 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) { | |||
| 997 | DeriveBase(); | 1029 | DeriveBase(); |
| 998 | } | 1030 | } |
| 999 | 1031 | ||
| 1032 | const std::map<u128, TicketRaw>& KeyManager::GetCommonTickets() const { | ||
| 1033 | return common_tickets; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | const std::map<u128, TicketRaw>& KeyManager::GetPersonalizedTickets() const { | ||
| 1037 | return personal_tickets; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | bool KeyManager::AddTicketCommon(TicketRaw raw) { | ||
| 1041 | const auto rsa_key = GetETicketRSAKey(); | ||
| 1042 | if (rsa_key == RSAKeyPair<2048>{}) | ||
| 1043 | return false; | ||
| 1044 | |||
| 1045 | const auto pair = ParseTicket(raw, rsa_key); | ||
| 1046 | if (!pair) | ||
| 1047 | return false; | ||
| 1048 | const auto& [rid, key] = *pair; | ||
| 1049 | u128 rights_id; | ||
| 1050 | std::memcpy(rights_id.data(), rid.data(), rid.size()); | ||
| 1051 | common_tickets[rights_id] = raw; | ||
| 1052 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | ||
| 1053 | return true; | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | bool KeyManager::AddTicketPersonalized(TicketRaw raw) { | ||
| 1057 | const auto rsa_key = GetETicketRSAKey(); | ||
| 1058 | if (rsa_key == RSAKeyPair<2048>{}) | ||
| 1059 | return false; | ||
| 1060 | |||
| 1061 | const auto pair = ParseTicket(raw, rsa_key); | ||
| 1062 | if (!pair) | ||
| 1063 | return false; | ||
| 1064 | const auto& [rid, key] = *pair; | ||
| 1065 | u128 rights_id; | ||
| 1066 | std::memcpy(rights_id.data(), rid.data(), rid.size()); | ||
| 1067 | common_tickets[rights_id] = raw; | ||
| 1068 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | ||
| 1069 | return true; | ||
| 1070 | } | ||
| 1071 | |||
| 1000 | const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { | 1072 | const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { |
| 1001 | {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, | 1073 | {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, |
| 1002 | {"eticket_rsa_kek_source", | 1074 | {"eticket_rsa_kek_source", |