summaryrefslogtreecommitdiff
path: root/src/core/crypto/key_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/crypto/key_manager.cpp')
-rw-r--r--src/core/crypto/key_manager.cpp139
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
327std::optional<Key128> DeriveSDSeed() { 328std::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
567KeyManager::KeyManager() { 577KeyManager::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
592static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { 601static 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
600void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { 609void 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
697void 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
706bool KeyManager::BaseDeriveNecessary() const { 711bool 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 {
766template <size_t Size> 771template <size_t Size>
767void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname, 772void 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
795void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { 805void 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
863bool KeyManager::KeyFileExists(bool title) { 873bool 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
880void KeyManager::DeriveSDSeedLazy() { 887void 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