diff options
| author | 2018-09-23 21:03:00 -0400 | |
|---|---|---|
| committer | 2018-10-07 13:15:11 -0400 | |
| commit | a57aac5772bc4cfde06faa68c75e7d8ef546dbee (patch) | |
| tree | ad8829ed14a24865cc388b49d13005009dcafc6b /src/core/crypto/key_manager.cpp | |
| parent | key_manager: Add BIS key getter (diff) | |
| download | yuzu-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
Diffstat (limited to 'src/core/crypto/key_manager.cpp')
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 209 |
1 files changed, 209 insertions, 0 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 | ||
| 265 | bool 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 | |||
| 265 | bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const { | 287 | bool 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 | ||
| 437 | static 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 | |||
| 445 | void 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 | } | ||
| 612 | void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) { | ||
| 613 | if (key == Key128{}) | ||
| 614 | return; | ||
| 615 | SetKey(id, key, field1, field2); | ||
| 616 | } | ||
| 617 | |||
| 618 | void KeyManager::SetKeyWrapped(S256KeyType id, Key256 key, u64 field1, u64 field2) { | ||
| 619 | if (key == Key256{}) | ||
| 620 | return; | ||
| 621 | SetKey(id, key, field1, field2); | ||
| 622 | } | ||
| 623 | |||
| 415 | const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { | 624 | const 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", |