diff options
Diffstat (limited to 'src/core/crypto/key_manager.cpp')
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 139 |
1 files changed, 76 insertions, 63 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index a4b739c63..fb451a423 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -18,8 +18,9 @@ | |||
| 18 | #include <mbedtls/cmac.h> | 18 | #include <mbedtls/cmac.h> |
| 19 | #include <mbedtls/sha256.h> | 19 | #include <mbedtls/sha256.h> |
| 20 | #include "common/common_funcs.h" | 20 | #include "common/common_funcs.h" |
| 21 | #include "common/common_paths.h" | 21 | #include "common/fs/file.h" |
| 22 | #include "common/file_util.h" | 22 | #include "common/fs/fs.h" |
| 23 | #include "common/fs/path_util.h" | ||
| 23 | #include "common/hex_util.h" | 24 | #include "common/hex_util.h" |
| 24 | #include "common/logging/log.h" | 25 | #include "common/logging/log.h" |
| 25 | #include "common/settings.h" | 26 | #include "common/settings.h" |
| @@ -325,46 +326,55 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) | |||
| 325 | } | 326 | } |
| 326 | 327 | ||
| 327 | std::optional<Key128> DeriveSDSeed() { | 328 | std::optional<Key128> DeriveSDSeed() { |
| 328 | const Common::FS::IOFile save_43(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + | 329 | const auto system_save_43_path = |
| 329 | "/system/save/8000000000000043", | 330 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000043"; |
| 330 | "rb+"); | 331 | const Common::FS::IOFile save_43{system_save_43_path, Common::FS::FileAccessMode::Read, |
| 332 | Common::FS::FileType::BinaryFile}; | ||
| 333 | |||
| 331 | if (!save_43.IsOpen()) { | 334 | if (!save_43.IsOpen()) { |
| 332 | return std::nullopt; | 335 | return std::nullopt; |
| 333 | } | 336 | } |
| 334 | 337 | ||
| 335 | const Common::FS::IOFile sd_private(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) + | 338 | const auto sd_private_path = |
| 336 | "/Nintendo/Contents/private", | 339 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "Nintendo/Contents/private"; |
| 337 | "rb+"); | 340 | |
| 341 | const Common::FS::IOFile sd_private{sd_private_path, Common::FS::FileAccessMode::Read, | ||
| 342 | Common::FS::FileType::BinaryFile}; | ||
| 343 | |||
| 338 | if (!sd_private.IsOpen()) { | 344 | if (!sd_private.IsOpen()) { |
| 339 | return std::nullopt; | 345 | return std::nullopt; |
| 340 | } | 346 | } |
| 341 | 347 | ||
| 342 | std::array<u8, 0x10> private_seed{}; | 348 | std::array<u8, 0x10> private_seed{}; |
| 343 | if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) { | 349 | if (sd_private.Read(private_seed) != private_seed.size()) { |
| 344 | return std::nullopt; | 350 | return std::nullopt; |
| 345 | } | 351 | } |
| 346 | 352 | ||
| 347 | std::array<u8, 0x10> buffer{}; | 353 | std::array<u8, 0x10> buffer{}; |
| 348 | std::size_t offset = 0; | 354 | s64 offset = 0; |
| 349 | for (; offset + 0x10 < save_43.GetSize(); ++offset) { | 355 | for (; offset + 0x10 < static_cast<s64>(save_43.GetSize()); ++offset) { |
| 350 | if (!save_43.Seek(offset, SEEK_SET)) { | 356 | if (!save_43.Seek(offset)) { |
| 357 | return std::nullopt; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (save_43.Read(buffer) != buffer.size()) { | ||
| 351 | return std::nullopt; | 361 | return std::nullopt; |
| 352 | } | 362 | } |
| 353 | 363 | ||
| 354 | save_43.ReadBytes(buffer.data(), buffer.size()); | ||
| 355 | if (buffer == private_seed) { | 364 | if (buffer == private_seed) { |
| 356 | break; | 365 | break; |
| 357 | } | 366 | } |
| 358 | } | 367 | } |
| 359 | 368 | ||
| 360 | if (!save_43.Seek(offset + 0x10, SEEK_SET)) { | 369 | if (!save_43.Seek(offset + 0x10)) { |
| 361 | return std::nullopt; | 370 | return std::nullopt; |
| 362 | } | 371 | } |
| 363 | 372 | ||
| 364 | Key128 seed{}; | 373 | Key128 seed{}; |
| 365 | if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) { | 374 | if (save_43.Read(seed) != seed.size()) { |
| 366 | return std::nullopt; | 375 | return std::nullopt; |
| 367 | } | 376 | } |
| 377 | |||
| 368 | return seed; | 378 | return seed; |
| 369 | } | 379 | } |
| 370 | 380 | ||
| @@ -435,7 +445,7 @@ std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save) { | |||
| 435 | } | 445 | } |
| 436 | 446 | ||
| 437 | std::vector<u8> buffer(ticket_save.GetSize()); | 447 | std::vector<u8> buffer(ticket_save.GetSize()); |
| 438 | if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { | 448 | if (ticket_save.Read(buffer) != buffer.size()) { |
| 439 | return {}; | 449 | return {}; |
| 440 | } | 450 | } |
| 441 | 451 | ||
| @@ -566,27 +576,26 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, | |||
| 566 | 576 | ||
| 567 | KeyManager::KeyManager() { | 577 | KeyManager::KeyManager() { |
| 568 | // Initialize keys | 578 | // Initialize keys |
| 569 | const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath(); | 579 | const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); |
| 570 | const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); | ||
| 571 | 580 | ||
| 572 | if (!Common::FS::Exists(yuzu_keys_dir)) { | 581 | if (!Common::FS::CreateDir(yuzu_keys_dir)) { |
| 573 | Common::FS::CreateDir(yuzu_keys_dir); | 582 | LOG_ERROR(Core, "Failed to create the keys directory."); |
| 574 | } | 583 | } |
| 575 | 584 | ||
| 576 | if (Settings::values.use_dev_keys) { | 585 | if (Settings::values.use_dev_keys) { |
| 577 | dev_mode = true; | 586 | dev_mode = true; |
| 578 | AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false); | 587 | LoadFromFile(yuzu_keys_dir / "dev.keys", false); |
| 579 | AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "dev.keys_autogenerated", false); | 588 | LoadFromFile(yuzu_keys_dir / "dev.keys_autogenerated", false); |
| 580 | } else { | 589 | } else { |
| 581 | dev_mode = false; | 590 | dev_mode = false; |
| 582 | AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "prod.keys", false); | 591 | LoadFromFile(yuzu_keys_dir / "prod.keys", false); |
| 583 | AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "prod.keys_autogenerated", false); | 592 | LoadFromFile(yuzu_keys_dir / "prod.keys_autogenerated", false); |
| 584 | } | 593 | } |
| 585 | 594 | ||
| 586 | AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "title.keys", true); | 595 | LoadFromFile(yuzu_keys_dir / "title.keys", true); |
| 587 | AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", true); | 596 | LoadFromFile(yuzu_keys_dir / "title.keys_autogenerated", true); |
| 588 | AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "console.keys", false); | 597 | LoadFromFile(yuzu_keys_dir / "console.keys", false); |
| 589 | AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "console.keys_autogenerated", false); | 598 | LoadFromFile(yuzu_keys_dir / "console.keys_autogenerated", false); |
| 590 | } | 599 | } |
| 591 | 600 | ||
| 592 | static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { | 601 | static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { |
| @@ -597,9 +606,14 @@ static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_ | |||
| 597 | [](u8 c) { return std::isxdigit(c); }); | 606 | [](u8 c) { return std::isxdigit(c); }); |
| 598 | } | 607 | } |
| 599 | 608 | ||
| 600 | void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { | 609 | void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_title_keys) { |
| 610 | if (!Common::FS::Exists(file_path)) { | ||
| 611 | return; | ||
| 612 | } | ||
| 613 | |||
| 601 | std::ifstream file; | 614 | std::ifstream file; |
| 602 | Common::FS::OpenFStream(file, filename, std::ios_base::in); | 615 | Common::FS::OpenFileStream(file, file_path, std::ios_base::in); |
| 616 | |||
| 603 | if (!file.is_open()) { | 617 | if (!file.is_open()) { |
| 604 | return; | 618 | return; |
| 605 | } | 619 | } |
| @@ -694,15 +708,6 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { | |||
| 694 | } | 708 | } |
| 695 | } | 709 | } |
| 696 | 710 | ||
| 697 | void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, | ||
| 698 | const std::string& filename, bool title) { | ||
| 699 | if (Common::FS::Exists(dir1 + DIR_SEP + filename)) { | ||
| 700 | LoadFromFile(dir1 + DIR_SEP + filename, title); | ||
| 701 | } else if (Common::FS::Exists(dir2 + DIR_SEP + filename)) { | ||
| 702 | LoadFromFile(dir2 + DIR_SEP + filename, title); | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | bool KeyManager::BaseDeriveNecessary() const { | 711 | bool KeyManager::BaseDeriveNecessary() const { |
| 707 | const auto check_key_existence = [this](auto key_type, u64 index1 = 0, u64 index2 = 0) { | 712 | const auto check_key_existence = [this](auto key_type, u64 index1 = 0, u64 index2 = 0) { |
| 708 | return !HasKey(key_type, index1, index2); | 713 | return !HasKey(key_type, index1, index2); |
| @@ -766,30 +771,35 @@ Key256 KeyManager::GetBISKey(u8 partition_id) const { | |||
| 766 | template <size_t Size> | 771 | template <size_t Size> |
| 767 | void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname, | 772 | void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname, |
| 768 | const std::array<u8, Size>& key) { | 773 | const std::array<u8, Size>& key) { |
| 769 | const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); | 774 | const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); |
| 775 | |||
| 770 | std::string filename = "title.keys_autogenerated"; | 776 | std::string filename = "title.keys_autogenerated"; |
| 777 | |||
| 771 | if (category == KeyCategory::Standard) { | 778 | if (category == KeyCategory::Standard) { |
| 772 | filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated"; | 779 | filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated"; |
| 773 | } else if (category == KeyCategory::Console) { | 780 | } else if (category == KeyCategory::Console) { |
| 774 | filename = "console.keys_autogenerated"; | 781 | filename = "console.keys_autogenerated"; |
| 775 | } | 782 | } |
| 776 | 783 | ||
| 777 | const auto path = yuzu_keys_dir + DIR_SEP + filename; | 784 | const auto path = yuzu_keys_dir / filename; |
| 778 | const auto add_info_text = !Common::FS::Exists(path); | 785 | const auto add_info_text = !Common::FS::Exists(path); |
| 779 | Common::FS::CreateFullPath(path); | 786 | |
| 780 | Common::FS::IOFile file{path, "a"}; | 787 | Common::FS::IOFile file{path, Common::FS::FileAccessMode::Append, |
| 788 | Common::FS::FileType::TextFile}; | ||
| 789 | |||
| 781 | if (!file.IsOpen()) { | 790 | if (!file.IsOpen()) { |
| 782 | return; | 791 | return; |
| 783 | } | 792 | } |
| 793 | |||
| 784 | if (add_info_text) { | 794 | if (add_info_text) { |
| 785 | file.WriteString( | 795 | void(file.WriteString( |
| 786 | "# This file is autogenerated by Yuzu\n" | 796 | "# This file is autogenerated by Yuzu\n" |
| 787 | "# It serves to store keys that were automatically generated from the normal keys\n" | 797 | "# It serves to store keys that were automatically generated from the normal keys\n" |
| 788 | "# If you are experiencing issues involving keys, it may help to delete this file\n"); | 798 | "# If you are experiencing issues involving keys, it may help to delete this file\n")); |
| 789 | } | 799 | } |
| 790 | 800 | ||
| 791 | file.WriteString(fmt::format("\n{} = {}", keyname, Common::HexToString(key))); | 801 | void(file.WriteString(fmt::format("\n{} = {}", keyname, Common::HexToString(key)))); |
| 792 | AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, filename, category == KeyCategory::Title); | 802 | LoadFromFile(path, category == KeyCategory::Title); |
| 793 | } | 803 | } |
| 794 | 804 | ||
| 795 | void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { | 805 | void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { |
| @@ -861,20 +871,17 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { | |||
| 861 | } | 871 | } |
| 862 | 872 | ||
| 863 | bool KeyManager::KeyFileExists(bool title) { | 873 | bool KeyManager::KeyFileExists(bool title) { |
| 864 | const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath(); | 874 | const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); |
| 865 | const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); | 875 | |
| 866 | if (title) { | 876 | if (title) { |
| 867 | return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "title.keys") || | 877 | return Common::FS::Exists(yuzu_keys_dir / "title.keys"); |
| 868 | Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "title.keys"); | ||
| 869 | } | 878 | } |
| 870 | 879 | ||
| 871 | if (Settings::values.use_dev_keys) { | 880 | if (Settings::values.use_dev_keys) { |
| 872 | return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") || | 881 | return Common::FS::Exists(yuzu_keys_dir / "dev.keys"); |
| 873 | Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys"); | ||
| 874 | } | 882 | } |
| 875 | 883 | ||
| 876 | return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") || | 884 | return Common::FS::Exists(yuzu_keys_dir / "prod.keys"); |
| 877 | Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys"); | ||
| 878 | } | 885 | } |
| 879 | 886 | ||
| 880 | void KeyManager::DeriveSDSeedLazy() { | 887 | void KeyManager::DeriveSDSeedLazy() { |
| @@ -1115,15 +1122,21 @@ void KeyManager::PopulateTickets() { | |||
| 1115 | return; | 1122 | return; |
| 1116 | } | 1123 | } |
| 1117 | 1124 | ||
| 1118 | const Common::FS::IOFile save1(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + | 1125 | const auto system_save_e1_path = |
| 1119 | "/system/save/80000000000000e1", | 1126 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/80000000000000e1"; |
| 1120 | "rb+"); | 1127 | |
| 1121 | const Common::FS::IOFile save2(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + | 1128 | const Common::FS::IOFile save_e1{system_save_e1_path, Common::FS::FileAccessMode::Read, |
| 1122 | "/system/save/80000000000000e2", | 1129 | Common::FS::FileType::BinaryFile}; |
| 1123 | "rb+"); | 1130 | |
| 1131 | const auto system_save_e2_path = | ||
| 1132 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/80000000000000e2"; | ||
| 1133 | |||
| 1134 | const Common::FS::IOFile save_e2{system_save_e2_path, Common::FS::FileAccessMode::Read, | ||
| 1135 | Common::FS::FileType::BinaryFile}; | ||
| 1136 | |||
| 1137 | const auto blob2 = GetTicketblob(save_e2); | ||
| 1138 | auto res = GetTicketblob(save_e1); | ||
| 1124 | 1139 | ||
| 1125 | const auto blob2 = GetTicketblob(save2); | ||
| 1126 | auto res = GetTicketblob(save1); | ||
| 1127 | const auto idx = res.size(); | 1140 | const auto idx = res.size(); |
| 1128 | res.insert(res.end(), blob2.begin(), blob2.end()); | 1141 | res.insert(res.end(), blob2.begin(), blob2.end()); |
| 1129 | 1142 | ||