diff options
| author | 2019-09-05 12:13:14 +1000 | |
|---|---|---|
| committer | 2019-09-05 12:13:14 +1000 | |
| commit | 14d8c1b59405f6f34c92141bd6b7b061a836d81e (patch) | |
| tree | 16181e1299550a4972664025032ac2555a30d281 /src/core/crypto/key_manager.cpp | |
| parent | Merge pull request #2808 from FearlessTobi/port-4866 (diff) | |
| parent | key_manager: Convert Ticket union to std::variant (diff) | |
| download | yuzu-14d8c1b59405f6f34c92141bd6b7b061a836d81e.tar.gz yuzu-14d8c1b59405f6f34c92141bd6b7b061a836d81e.tar.xz yuzu-14d8c1b59405f6f34c92141bd6b7b061a836d81e.zip | |
Merge pull request #2418 from DarkLordZach/srv-es
es: Implement various ticket accessor commands from IEticketService
Diffstat (limited to 'src/core/crypto/key_manager.cpp')
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 241 |
1 files changed, 207 insertions, 34 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 6dd633363..46aceec3d 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | namespace Core::Crypto { | 37 | namespace Core::Crypto { |
| 38 | 38 | ||
| 39 | constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; | 39 | constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; |
| 40 | constexpr u64 FULL_TICKET_SIZE = 0x400; | ||
| 40 | 41 | ||
| 41 | using namespace Common; | 42 | using namespace Common; |
| 42 | 43 | ||
| @@ -55,6 +56,99 @@ const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ | |||
| 55 | {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, | 56 | {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, |
| 56 | }; | 57 | }; |
| 57 | 58 | ||
| 59 | namespace { | ||
| 60 | template <std::size_t Size> | ||
| 61 | bool IsAllZeroArray(const std::array<u8, Size>& array) { | ||
| 62 | return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; }); | ||
| 63 | } | ||
| 64 | } // namespace | ||
| 65 | |||
| 66 | u64 GetSignatureTypeDataSize(SignatureType type) { | ||
| 67 | switch (type) { | ||
| 68 | case SignatureType::RSA_4096_SHA1: | ||
| 69 | case SignatureType::RSA_4096_SHA256: | ||
| 70 | return 0x200; | ||
| 71 | case SignatureType::RSA_2048_SHA1: | ||
| 72 | case SignatureType::RSA_2048_SHA256: | ||
| 73 | return 0x100; | ||
| 74 | case SignatureType::ECDSA_SHA1: | ||
| 75 | case SignatureType::ECDSA_SHA256: | ||
| 76 | return 0x3C; | ||
| 77 | } | ||
| 78 | UNREACHABLE(); | ||
| 79 | } | ||
| 80 | |||
| 81 | u64 GetSignatureTypePaddingSize(SignatureType type) { | ||
| 82 | switch (type) { | ||
| 83 | case SignatureType::RSA_4096_SHA1: | ||
| 84 | case SignatureType::RSA_4096_SHA256: | ||
| 85 | case SignatureType::RSA_2048_SHA1: | ||
| 86 | case SignatureType::RSA_2048_SHA256: | ||
| 87 | return 0x3C; | ||
| 88 | case SignatureType::ECDSA_SHA1: | ||
| 89 | case SignatureType::ECDSA_SHA256: | ||
| 90 | return 0x40; | ||
| 91 | } | ||
| 92 | UNREACHABLE(); | ||
| 93 | } | ||
| 94 | |||
| 95 | SignatureType Ticket::GetSignatureType() const { | ||
| 96 | if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { | ||
| 97 | return ticket->sig_type; | ||
| 98 | } | ||
| 99 | if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { | ||
| 100 | return ticket->sig_type; | ||
| 101 | } | ||
| 102 | if (auto ticket = std::get_if<ECDSATicket>(&data)) { | ||
| 103 | return ticket->sig_type; | ||
| 104 | } | ||
| 105 | |||
| 106 | UNREACHABLE(); | ||
| 107 | } | ||
| 108 | |||
| 109 | TicketData& Ticket::GetData() { | ||
| 110 | if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { | ||
| 111 | return ticket->data; | ||
| 112 | } | ||
| 113 | if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { | ||
| 114 | return ticket->data; | ||
| 115 | } | ||
| 116 | if (auto ticket = std::get_if<ECDSATicket>(&data)) { | ||
| 117 | return ticket->data; | ||
| 118 | } | ||
| 119 | |||
| 120 | UNREACHABLE(); | ||
| 121 | } | ||
| 122 | |||
| 123 | const TicketData& Ticket::GetData() const { | ||
| 124 | if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { | ||
| 125 | return ticket->data; | ||
| 126 | } | ||
| 127 | if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { | ||
| 128 | return ticket->data; | ||
| 129 | } | ||
| 130 | if (auto ticket = std::get_if<ECDSATicket>(&data)) { | ||
| 131 | return ticket->data; | ||
| 132 | } | ||
| 133 | |||
| 134 | UNREACHABLE(); | ||
| 135 | } | ||
| 136 | |||
| 137 | u64 Ticket::GetSize() const { | ||
| 138 | const auto sig_type = GetSignatureType(); | ||
| 139 | |||
| 140 | return sizeof(SignatureType) + GetSignatureTypeDataSize(sig_type) + | ||
| 141 | GetSignatureTypePaddingSize(sig_type) + sizeof(TicketData); | ||
| 142 | } | ||
| 143 | |||
| 144 | Ticket Ticket::SynthesizeCommon(Key128 title_key, const std::array<u8, 16>& rights_id) { | ||
| 145 | RSA2048Ticket out{}; | ||
| 146 | out.sig_type = SignatureType::RSA_2048_SHA256; | ||
| 147 | out.data.rights_id = rights_id; | ||
| 148 | out.data.title_key_common = title_key; | ||
| 149 | return Ticket{out}; | ||
| 150 | } | ||
| 151 | |||
| 58 | Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed) { | 152 | Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed) { |
| 59 | Key128 out{}; | 153 | Key128 out{}; |
| 60 | 154 | ||
| @@ -135,6 +229,27 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) { | |||
| 135 | } | 229 | } |
| 136 | } | 230 | } |
| 137 | 231 | ||
| 232 | RSAKeyPair<2048> KeyManager::GetETicketRSAKey() const { | ||
| 233 | if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek)) | ||
| 234 | return {}; | ||
| 235 | |||
| 236 | const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek); | ||
| 237 | |||
| 238 | std::vector<u8> extended_iv(eticket_extended_kek.begin(), eticket_extended_kek.begin() + 0x10); | ||
| 239 | std::array<u8, 0x230> extended_dec{}; | ||
| 240 | AESCipher<Key128> rsa_1(eticket_final, Mode::CTR); | ||
| 241 | rsa_1.SetIV(extended_iv); | ||
| 242 | rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10, | ||
| 243 | extended_dec.data(), Op::Decrypt); | ||
| 244 | |||
| 245 | RSAKeyPair<2048> rsa_key{}; | ||
| 246 | std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); | ||
| 247 | std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); | ||
| 248 | std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); | ||
| 249 | |||
| 250 | return rsa_key; | ||
| 251 | } | ||
| 252 | |||
| 138 | Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) { | 253 | Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) { |
| 139 | AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB); | 254 | AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB); |
| 140 | Key128 mac_key{}; | 255 | Key128 mac_key{}; |
| @@ -237,7 +352,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke | |||
| 237 | return Loader::ResultStatus::Success; | 352 | return Loader::ResultStatus::Success; |
| 238 | } | 353 | } |
| 239 | 354 | ||
| 240 | std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) { | 355 | std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save) { |
| 241 | if (!ticket_save.IsOpen()) | 356 | if (!ticket_save.IsOpen()) |
| 242 | return {}; | 357 | return {}; |
| 243 | 358 | ||
| @@ -246,14 +361,14 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) { | |||
| 246 | return {}; | 361 | return {}; |
| 247 | } | 362 | } |
| 248 | 363 | ||
| 249 | std::vector<TicketRaw> out; | 364 | std::vector<Ticket> out; |
| 250 | for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { | 365 | for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { |
| 251 | if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && | 366 | if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && |
| 252 | buffer[offset + 3] == 0x0) { | 367 | buffer[offset + 3] == 0x0) { |
| 253 | out.emplace_back(); | 368 | out.emplace_back(); |
| 254 | auto& next = out.back(); | 369 | auto& next = out.back(); |
| 255 | std::memcpy(&next, buffer.data() + offset, sizeof(TicketRaw)); | 370 | std::memcpy(&next, buffer.data() + offset, sizeof(Ticket)); |
| 256 | offset += next.size(); | 371 | offset += FULL_TICKET_SIZE; |
| 257 | } | 372 | } |
| 258 | } | 373 | } |
| 259 | 374 | ||
| @@ -305,29 +420,23 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { | |||
| 305 | return offset; | 420 | return offset; |
| 306 | } | 421 | } |
| 307 | 422 | ||
| 308 | std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, | 423 | std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, |
| 309 | const RSAKeyPair<2048>& key) { | 424 | const RSAKeyPair<2048>& key) { |
| 310 | u32 cert_authority; | 425 | const auto issuer = ticket.GetData().issuer; |
| 311 | std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); | 426 | if (issuer == std::array<u8, 0x40>{}) |
| 312 | if (cert_authority == 0) | ||
| 313 | return {}; | 427 | return {}; |
| 314 | if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) { | 428 | if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { |
| 315 | LOG_INFO(Crypto, | 429 | LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); |
| 316 | "Attempting to parse ticket with non-standard certificate authority {:08X}.", | ||
| 317 | cert_authority); | ||
| 318 | } | 430 | } |
| 319 | 431 | ||
| 320 | Key128 rights_id; | 432 | Key128 rights_id = ticket.GetData().rights_id; |
| 321 | std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); | ||
| 322 | 433 | ||
| 323 | if (rights_id == Key128{}) | 434 | if (rights_id == Key128{}) |
| 324 | return {}; | 435 | return {}; |
| 325 | 436 | ||
| 326 | Key128 key_temp{}; | 437 | if (!std::any_of(ticket.GetData().title_key_common_pad.begin(), |
| 327 | 438 | ticket.GetData().title_key_common_pad.end(), [](u8 b) { return b != 0; })) { | |
| 328 | if (!std::any_of(ticket.begin() + 0x190, ticket.begin() + 0x280, [](u8 b) { return b != 0; })) { | 439 | return std::make_pair(rights_id, ticket.GetData().title_key_common); |
| 329 | std::memcpy(key_temp.data(), ticket.data() + 0x180, key_temp.size()); | ||
| 330 | return std::make_pair(rights_id, key_temp); | ||
| 331 | } | 440 | } |
| 332 | 441 | ||
| 333 | mbedtls_mpi D; // RSA Private Exponent | 442 | mbedtls_mpi D; // RSA Private Exponent |
| @@ -342,7 +451,7 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, | |||
| 342 | 451 | ||
| 343 | mbedtls_mpi_read_binary(&D, key.decryption_key.data(), key.decryption_key.size()); | 452 | mbedtls_mpi_read_binary(&D, key.decryption_key.data(), key.decryption_key.size()); |
| 344 | mbedtls_mpi_read_binary(&N, key.modulus.data(), key.modulus.size()); | 453 | mbedtls_mpi_read_binary(&N, key.modulus.data(), key.modulus.size()); |
| 345 | mbedtls_mpi_read_binary(&S, ticket.data() + 0x180, 0x100); | 454 | mbedtls_mpi_read_binary(&S, ticket.GetData().title_key_block.data(), 0x100); |
| 346 | 455 | ||
| 347 | mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr); | 456 | mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr); |
| 348 | 457 | ||
| @@ -366,6 +475,7 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, | |||
| 366 | return {}; | 475 | return {}; |
| 367 | ASSERT(*offset > 0); | 476 | ASSERT(*offset > 0); |
| 368 | 477 | ||
| 478 | Key128 key_temp{}; | ||
| 369 | std::memcpy(key_temp.data(), m_2.data() + *offset, key_temp.size()); | 479 | std::memcpy(key_temp.data(), m_2.data() + *offset, key_temp.size()); |
| 370 | 480 | ||
| 371 | return std::make_pair(rights_id, key_temp); | 481 | return std::make_pair(rights_id, key_temp); |
| @@ -450,6 +560,8 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { | |||
| 450 | 560 | ||
| 451 | const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16); | 561 | const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16); |
| 452 | encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]); | 562 | encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]); |
| 563 | } else if (out[0].compare(0, 20, "eticket_extended_kek") == 0) { | ||
| 564 | eticket_extended_kek = Common::HexStringToArray<576>(out[1]); | ||
| 453 | } else { | 565 | } else { |
| 454 | for (const auto& kv : KEYS_VARIABLE_LENGTH) { | 566 | for (const auto& kv : KEYS_VARIABLE_LENGTH) { |
| 455 | if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) | 567 | if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) |
| @@ -862,20 +974,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { | |||
| 862 | // Titlekeys | 974 | // Titlekeys |
| 863 | data.DecryptProdInfo(GetBISKey(0)); | 975 | data.DecryptProdInfo(GetBISKey(0)); |
| 864 | 976 | ||
| 865 | const auto eticket_extended_kek = data.GetETicketExtendedKek(); | 977 | eticket_extended_kek = data.GetETicketExtendedKek(); |
| 978 | WriteKeyToFile(KeyCategory::Console, "eticket_extended_kek", eticket_extended_kek); | ||
| 979 | PopulateTickets(); | ||
| 980 | } | ||
| 866 | 981 | ||
| 867 | std::vector<u8> extended_iv(0x10); | 982 | void KeyManager::PopulateTickets() { |
| 868 | std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); | 983 | 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 | 984 | ||
| 875 | RSAKeyPair<2048> rsa_key{}; | 985 | if (rsa_key == RSAKeyPair<2048>{}) |
| 876 | std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); | 986 | return; |
| 877 | std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size()); | 987 | |
| 878 | std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size()); | 988 | if (!common_tickets.empty() && !personal_tickets.empty()) |
| 989 | return; | ||
| 879 | 990 | ||
| 880 | const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | 991 | const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + |
| 881 | "/system/save/80000000000000e1", | 992 | "/system/save/80000000000000e1", |
| @@ -886,19 +997,41 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { | |||
| 886 | 997 | ||
| 887 | const auto blob2 = GetTicketblob(save2); | 998 | const auto blob2 = GetTicketblob(save2); |
| 888 | auto res = GetTicketblob(save1); | 999 | auto res = GetTicketblob(save1); |
| 1000 | const auto idx = res.size(); | ||
| 889 | res.insert(res.end(), blob2.begin(), blob2.end()); | 1001 | res.insert(res.end(), blob2.begin(), blob2.end()); |
| 890 | 1002 | ||
| 891 | for (const auto& raw : res) { | 1003 | for (std::size_t i = 0; i < res.size(); ++i) { |
| 892 | const auto pair = ParseTicket(raw, rsa_key); | 1004 | const auto common = i < idx; |
| 1005 | const auto pair = ParseTicket(res[i], rsa_key); | ||
| 893 | if (!pair) | 1006 | if (!pair) |
| 894 | continue; | 1007 | continue; |
| 895 | const auto& [rid, key] = *pair; | 1008 | const auto& [rid, key] = *pair; |
| 896 | u128 rights_id; | 1009 | u128 rights_id; |
| 897 | std::memcpy(rights_id.data(), rid.data(), rid.size()); | 1010 | std::memcpy(rights_id.data(), rid.data(), rid.size()); |
| 1011 | |||
| 1012 | if (common) { | ||
| 1013 | common_tickets[rights_id] = res[i]; | ||
| 1014 | } else { | ||
| 1015 | personal_tickets[rights_id] = res[i]; | ||
| 1016 | } | ||
| 1017 | |||
| 898 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | 1018 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); |
| 899 | } | 1019 | } |
| 900 | } | 1020 | } |
| 901 | 1021 | ||
| 1022 | void KeyManager::SynthesizeTickets() { | ||
| 1023 | for (const auto& key : s128_keys) { | ||
| 1024 | if (key.first.type != S128KeyType::Titlekey) { | ||
| 1025 | continue; | ||
| 1026 | } | ||
| 1027 | u128 rights_id{key.first.field1, key.first.field2}; | ||
| 1028 | Key128 rights_id_2; | ||
| 1029 | std::memcpy(rights_id_2.data(), rights_id.data(), rights_id_2.size()); | ||
| 1030 | const auto ticket = Ticket::SynthesizeCommon(key.second, rights_id_2); | ||
| 1031 | common_tickets.insert_or_assign(rights_id, ticket); | ||
| 1032 | } | ||
| 1033 | } | ||
| 1034 | |||
| 902 | void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) { | 1035 | void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) { |
| 903 | if (key == Key128{}) | 1036 | if (key == Key128{}) |
| 904 | return; | 1037 | return; |
| @@ -997,6 +1130,46 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) { | |||
| 997 | DeriveBase(); | 1130 | DeriveBase(); |
| 998 | } | 1131 | } |
| 999 | 1132 | ||
| 1133 | const std::map<u128, Ticket>& KeyManager::GetCommonTickets() const { | ||
| 1134 | return common_tickets; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | const std::map<u128, Ticket>& KeyManager::GetPersonalizedTickets() const { | ||
| 1138 | return personal_tickets; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | bool KeyManager::AddTicketCommon(Ticket raw) { | ||
| 1142 | const auto rsa_key = GetETicketRSAKey(); | ||
| 1143 | if (rsa_key == RSAKeyPair<2048>{}) | ||
| 1144 | return false; | ||
| 1145 | |||
| 1146 | const auto pair = ParseTicket(raw, rsa_key); | ||
| 1147 | if (!pair) | ||
| 1148 | return false; | ||
| 1149 | const auto& [rid, key] = *pair; | ||
| 1150 | u128 rights_id; | ||
| 1151 | std::memcpy(rights_id.data(), rid.data(), rid.size()); | ||
| 1152 | common_tickets[rights_id] = raw; | ||
| 1153 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | ||
| 1154 | return true; | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | bool KeyManager::AddTicketPersonalized(Ticket raw) { | ||
| 1158 | const auto rsa_key = GetETicketRSAKey(); | ||
| 1159 | if (rsa_key == RSAKeyPair<2048>{}) | ||
| 1160 | return false; | ||
| 1161 | |||
| 1162 | const auto pair = ParseTicket(raw, rsa_key); | ||
| 1163 | if (!pair) | ||
| 1164 | return false; | ||
| 1165 | const auto& [rid, key] = *pair; | ||
| 1166 | u128 rights_id; | ||
| 1167 | std::memcpy(rights_id.data(), rid.data(), rid.size()); | ||
| 1168 | common_tickets[rights_id] = raw; | ||
| 1169 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | ||
| 1170 | return true; | ||
| 1171 | } | ||
| 1172 | |||
| 1000 | const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { | 1173 | const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { |
| 1001 | {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, | 1174 | {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, |
| 1002 | {"eticket_rsa_kek_source", | 1175 | {"eticket_rsa_kek_source", |