summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Zach Hilman2018-09-23 21:03:00 -0400
committerGravatar Zach Hilman2018-10-07 13:15:11 -0400
commita57aac5772bc4cfde06faa68c75e7d8ef546dbee (patch)
treead8829ed14a24865cc388b49d13005009dcafc6b
parentkey_manager: Add BIS key getter (diff)
downloadyuzu-a57aac5772bc4cfde06faa68c75e7d8ef546dbee.tar.gz
yuzu-a57aac5772bc4cfde06faa68c75e7d8ef546dbee.tar.xz
yuzu-a57aac5772bc4cfde06faa68c75e7d8ef546dbee.zip
key_manager: Add base key derivation
Derives master keys, game encryption keys, and package1/2 keys
-rw-r--r--src/core/crypto/key_manager.cpp209
-rw-r--r--src/core/crypto/key_manager.h15
2 files changed, 220 insertions, 4 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 9cb7124d2..b37b09772 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -262,6 +262,28 @@ void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string&
262 LoadFromFile(dir2 + DIR_SEP + filename, title); 262 LoadFromFile(dir2 + DIR_SEP + filename, title);
263} 263}
264 264
265bool KeyManager::BaseDeriveNecessary() {
266 const auto check_key_existence = [this](auto key_type, u64 index1 = 0, u64 index2 = 0) {
267 return !HasKey(key_type, index1, index2);
268 };
269
270 if (check_key_existence(S256KeyType::Header))
271 return true;
272
273 for (size_t i = 0; i < CURRENT_CRYPTO_REVISION; ++i) {
274 if (check_key_existence(S128KeyType::Master, i) ||
275 check_key_existence(S128KeyType::KeyArea, i,
276 static_cast<u64>(KeyAreaKeyType::Application)) ||
277 check_key_existence(S128KeyType::KeyArea, i, static_cast<u64>(KeyAreaKeyType::Ocean)) ||
278 check_key_existence(S128KeyType::KeyArea, i,
279 static_cast<u64>(KeyAreaKeyType::System)) ||
280 check_key_existence(S128KeyType::Titlekek, i))
281 return true;
282 }
283
284 return false;
285}
286
265bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const { 287bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const {
266 return s128_keys.find({id, field1, field2}) != s128_keys.end(); 288 return s128_keys.find({id, field1, field2}) != s128_keys.end();
267} 289}
@@ -412,6 +434,193 @@ void KeyManager::DeriveSDSeedLazy() {
412 SetKey(S128KeyType::SDSeed, res.get()); 434 SetKey(S128KeyType::SDSeed, res.get());
413} 435}
414 436
437static Key128 CalculateCMAC(const u8* source, size_t size, Key128 key) {
438 Key128 out{};
439
440 mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key.data(), 0x80,
441 source, size, out.data());
442 return out;
443}
444
445void KeyManager::DeriveBase() {
446 if (!BaseDeriveNecessary())
447 return;
448
449 if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC))
450 return;
451
452 const auto has_bis = [this](u64 id) {
453 return HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Crypto)) &&
454 HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Tweak));
455 };
456
457 const auto copy_bis = [this](u64 id_from, u64 id_to) {
458 SetKey(S128KeyType::BIS,
459 GetKey(S128KeyType::BIS, id_from, static_cast<u64>(BISKeyType::Crypto)), id_to,
460 static_cast<u64>(BISKeyType::Crypto));
461
462 SetKey(S128KeyType::BIS,
463 GetKey(S128KeyType::BIS, id_from, static_cast<u64>(BISKeyType::Tweak)), id_to,
464 static_cast<u64>(BISKeyType::Tweak));
465 };
466
467 if (has_bis(2) && !has_bis(3))
468 copy_bis(2, 3);
469 else if (has_bis(3) && !has_bis(2))
470 copy_bis(3, 2);
471
472 std::bitset<32> revisions{};
473 revisions.set();
474 for (size_t i = 0; i < 32; ++i) {
475 if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob), i) ||
476 encrypted_keyblobs[i] == std::array<u8, 0xB0>{})
477 revisions.reset(i);
478 }
479
480 if (!revisions.any())
481 return;
482
483 const auto sbk = GetKey(S128KeyType::SecureBoot);
484 const auto tsec = GetKey(S128KeyType::TSEC);
485 const auto master_source = GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Master));
486 const auto kek_generation_source =
487 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration));
488 const auto key_generation_source =
489 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration));
490
491 for (size_t i = 0; i < 32; ++i) {
492 if (!revisions[i])
493 continue;
494
495 // Derive keyblob key
496 const auto key = DeriveKeyblobKey(
497 sbk, tsec, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob), i));
498
499 SetKey(S128KeyType::Keyblob, key, i);
500
501 // Derive keyblob MAC key
502 if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)))
503 continue;
504
505 const auto mac_source =
506 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC));
507
508 AESCipher<Key128> mac_cipher(key, Mode::ECB);
509 Key128 mac_key{};
510 mac_cipher.Transcode(mac_source.data(), mac_key.size(), mac_key.data(), Op::Decrypt);
511
512 SetKey(S128KeyType::KeyblobMAC, mac_key, i);
513
514 Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key);
515 if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0)
516 continue;
517
518 // Decrypt keyblob
519 bool has_keyblob = keyblobs[i] != std::array<u8, 0x90>{};
520
521 AESCipher<Key128> cipher(key, Mode::CTR);
522 cipher.SetIV(std::vector<u8>(encrypted_keyblobs[i].data() + 0x10,
523 encrypted_keyblobs[i].data() + 0x20));
524 cipher.Transcode(encrypted_keyblobs[i].data() + 0x20, keyblobs[i].size(),
525 keyblobs[i].data(), Op::Decrypt);
526
527 if (!has_keyblob) {
528 WriteKeyToFile<0x90>(KeyCategory::Console, fmt::format("keyblob_{:02X}", i),
529 keyblobs[i]);
530 }
531
532 Key128 package1{};
533 std::memcpy(package1.data(), keyblobs[i].data() + 0x80, sizeof(Key128));
534 SetKey(S128KeyType::Package1, package1, i);
535
536 // Derive master key
537 if (HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Master))) {
538 Key128 master_root{};
539 std::memcpy(master_root.data(), keyblobs[i].data(), sizeof(Key128));
540
541 AESCipher<Key128> master_cipher(master_root, Mode::ECB);
542
543 Key128 master{};
544 master_cipher.Transcode(master_source.data(), master_source.size(), master.data(),
545 Op::Decrypt);
546 SetKey(S128KeyType::Master, master, i);
547 }
548 }
549
550 revisions.set();
551 for (size_t i = 0; i < 32; ++i) {
552 if (!HasKey(S128KeyType::Master, i))
553 revisions.reset(i);
554 }
555
556 if (!revisions.any())
557 return;
558
559 for (size_t i = 0; i < 32; ++i) {
560 if (!revisions[i])
561 continue;
562
563 // Derive general purpose keys
564 if (HasKey(S128KeyType::Master, i)) {
565 for (auto kak_type :
566 {KeyAreaKeyType::Application, KeyAreaKeyType::Ocean, KeyAreaKeyType::System}) {
567 if (HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
568 static_cast<u64>(kak_type))) {
569 const auto source =
570 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
571 static_cast<u64>(kak_type));
572 const auto kek =
573 GenerateKeyEncryptionKey(source, GetKey(S128KeyType::Master, i),
574 kek_generation_source, key_generation_source);
575 SetKey(S128KeyType::KeyArea, kek, i, static_cast<u64>(kak_type));
576 }
577 }
578
579 AESCipher<Key128> master_cipher(GetKey(S128KeyType::Master, i), Mode::ECB);
580 for (auto key_type : {SourceKeyType::Titlekek, SourceKeyType::Package2}) {
581 if (HasKey(S128KeyType::Source, static_cast<u64>(key_type))) {
582 Key128 key{};
583 master_cipher.Transcode(
584 GetKey(S128KeyType::Source, static_cast<u64>(key_type)).data(), key.size(),
585 key.data(), Op::Decrypt);
586 SetKey(key_type == SourceKeyType::Titlekek ? S128KeyType::Titlekek
587 : S128KeyType::Package2,
588 key, i);
589 }
590 }
591 }
592 }
593
594 if (HasKey(S128KeyType::Master, 0) &&
595 HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)) &&
596 HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)) &&
597 HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek)) &&
598 HasKey(S256KeyType::HeaderSource)) {
599 const auto header_kek = GenerateKeyEncryptionKey(
600 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek)),
601 GetKey(S128KeyType::Master, 0),
602 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)),
603 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)));
604 SetKey(S128KeyType::HeaderKek, header_kek);
605
606 AESCipher<Key128> header_cipher(header_kek, Mode::ECB);
607 Key256 out = GetKey(S256KeyType::HeaderSource);
608 header_cipher.Transcode(out.data(), out.size(), out.data(), Op::Decrypt);
609 SetKey(S256KeyType::Header, out);
610 }
611}
612void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) {
613 if (key == Key128{})
614 return;
615 SetKey(id, key, field1, field2);
616}
617
618void KeyManager::SetKeyWrapped(S256KeyType id, Key256 key, u64 field1, u64 field2) {
619 if (key == Key256{})
620 return;
621 SetKey(id, key, field1, field2);
622}
623
415const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { 624const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
416 {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, 625 {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
417 {"eticket_rsa_kek_source", 626 {"eticket_rsa_kek_source",
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index a729fa7a0..8de65ec4e 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -138,9 +138,12 @@ public:
138 // 8*43 and the private file to exist. 138 // 8*43 and the private file to exist.
139 void DeriveSDSeedLazy(); 139 void DeriveSDSeedLazy();
140 140
141 bool BaseDeriveNecessary();
142 void DeriveBase();
141private: 143private:
142 boost::container::flat_map<KeyIndex<S128KeyType>, Key128> s128_keys; 144 std::map<KeyIndex<S128KeyType>, Key128> s128_keys;
143 boost::container::flat_map<KeyIndex<S256KeyType>, Key256> s256_keys; 145 std::map<KeyIndex<S256KeyType>, Key256> s256_keys;
146
144 std::array<std::array<u8, 0xB0>, 0x20> encrypted_keyblobs{}; 147 std::array<std::array<u8, 0xB0>, 0x20> encrypted_keyblobs{};
145 std::array<std::array<u8, 0x90>, 0x20> keyblobs{}; 148 std::array<std::array<u8, 0x90>, 0x20> keyblobs{};
146 149
@@ -148,8 +151,12 @@ private:
148 void LoadFromFile(const std::string& filename, bool is_title_keys); 151 void LoadFromFile(const std::string& filename, bool is_title_keys);
149 void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, 152 void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
150 const std::string& filename, bool title); 153 const std::string& filename, bool title);
151 template <std::size_t Size> 154 template <size_t Size>
152 void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key); 155 void WriteKeyToFile(KeyCategory category, std::string_view keyname,
156 const std::array<u8, Size>& key);
157
158 void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
159 void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
153 160
154 static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id; 161 static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
155 static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id; 162 static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id;