Kaynağa Gözat

key_manager: Add accessors/helpers for ticket management

Zach Hilman 7 yıl önce
ebeveyn
işleme
e35fac2054
2 değiştirilmiş dosya ile 100 ekleme ve 14 silme
  1. 86 14
      src/core/crypto/key_manager.cpp
  2. 14 0
      src/core/crypto/key_manager.h

+ 86 - 14
src/core/crypto/key_manager.cpp

@@ -135,6 +135,28 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) {
     }
     }
 }
 }
 
 
+RSAKeyPair<2048> KeyManager::GetETicketRSAKey() {
+    if (eticket_extended_kek == std::array<u8, 576>{} || !HasKey(S128KeyType::ETicketRSAKek))
+        return {};
+
+    const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek);
+
+    std::vector<u8> extended_iv(0x10);
+    std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size());
+    std::array<u8, 0x230> extended_dec{};
+    AESCipher<Key128> rsa_1(eticket_final, Mode::CTR);
+    rsa_1.SetIV(extended_iv);
+    rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10,
+                    extended_dec.data(), Op::Decrypt);
+
+    RSAKeyPair<2048> rsa_key{};
+    std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size());
+    std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size());
+    std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size());
+
+    return rsa_key;
+}
+
 Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) {
 Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) {
     AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB);
     AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB);
     Key128 mac_key{};
     Key128 mac_key{};
@@ -450,6 +472,8 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
 
 
                 const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16);
                 const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16);
                 encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]);
                 encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]);
+            } else if (out[0].compare(0, 20, "eticket_extended_kek") == 0) {
+                eticket_extended_kek = Common::HexStringToArray<576>(out[1]);
             } else {
             } else {
                 for (const auto& kv : KEYS_VARIABLE_LENGTH) {
                 for (const auto& kv : KEYS_VARIABLE_LENGTH) {
                     if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2))
                     if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2))
@@ -862,20 +886,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
     // Titlekeys
     // Titlekeys
     data.DecryptProdInfo(GetBISKey(0));
     data.DecryptProdInfo(GetBISKey(0));
 
 
-    const auto eticket_extended_kek = data.GetETicketExtendedKek();
+    eticket_extended_kek = data.GetETicketExtendedKek();
+    WriteKeyToFile(KeyCategory::Console, "eticket_extended_kek", eticket_extended_kek);
+    PopulateTickets();
+}
 
 
-    std::vector<u8> extended_iv(0x10);
-    std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size());
-    std::array<u8, 0x230> extended_dec{};
-    AESCipher<Key128> rsa_1(eticket_final, Mode::CTR);
-    rsa_1.SetIV(extended_iv);
-    rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10,
-                    extended_dec.data(), Op::Decrypt);
+void KeyManager::PopulateTickets() {
+    const auto rsa_key = GetETicketRSAKey();
 
 
-    RSAKeyPair<2048> rsa_key{};
-    std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size());
-    std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size());
-    std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size());
+    if (rsa_key == RSAKeyPair<2048>{})
+        return;
+
+    if (!common_tickets.empty() && !personal_tickets.empty())
+        return;
 
 
     const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
     const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
                                      "/system/save/80000000000000e1",
                                      "/system/save/80000000000000e1",
@@ -886,15 +909,24 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
 
 
     const auto blob2 = GetTicketblob(save2);
     const auto blob2 = GetTicketblob(save2);
     auto res = GetTicketblob(save1);
     auto res = GetTicketblob(save1);
+    const auto idx = res.size();
     res.insert(res.end(), blob2.begin(), blob2.end());
     res.insert(res.end(), blob2.begin(), blob2.end());
 
 
-    for (const auto& raw : res) {
-        const auto pair = ParseTicket(raw, rsa_key);
+    for (std::size_t i = 0; i < res.size(); ++i) {
+        const auto common = i < idx;
+        const auto pair = ParseTicket(res[i], rsa_key);
         if (!pair)
         if (!pair)
             continue;
             continue;
         const auto& [rid, key] = *pair;
         const auto& [rid, key] = *pair;
         u128 rights_id;
         u128 rights_id;
         std::memcpy(rights_id.data(), rid.data(), rid.size());
         std::memcpy(rights_id.data(), rid.data(), rid.size());
+
+        if (common) {
+            common_tickets[rights_id] = res[i];
+        } else {
+            personal_tickets[rights_id] = res[i];
+        }
+
         SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
         SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
     }
     }
 }
 }
@@ -997,6 +1029,46 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
     DeriveBase();
     DeriveBase();
 }
 }
 
 
+const std::map<u128, TicketRaw>& KeyManager::GetCommonTickets() const {
+    return common_tickets;
+}
+
+const std::map<u128, TicketRaw>& KeyManager::GetPersonalizedTickets() const {
+    return personal_tickets;
+}
+
+bool KeyManager::AddTicketCommon(TicketRaw raw) {
+    const auto rsa_key = GetETicketRSAKey();
+    if (rsa_key == RSAKeyPair<2048>{})
+        return false;
+
+    const auto pair = ParseTicket(raw, rsa_key);
+    if (!pair)
+        return false;
+    const auto& [rid, key] = *pair;
+    u128 rights_id;
+    std::memcpy(rights_id.data(), rid.data(), rid.size());
+    common_tickets[rights_id] = raw;
+    SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
+    return true;
+}
+
+bool KeyManager::AddTicketPersonalized(TicketRaw raw) {
+    const auto rsa_key = GetETicketRSAKey();
+    if (rsa_key == RSAKeyPair<2048>{})
+        return false;
+
+    const auto pair = ParseTicket(raw, rsa_key);
+    if (!pair)
+        return false;
+    const auto& [rid, key] = *pair;
+    u128 rights_id;
+    std::memcpy(rights_id.data(), rid.data(), rid.size());
+    common_tickets[rights_id] = raw;
+    SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
+    return true;
+}
+
 const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
 const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
     {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
     {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
     {"eticket_rsa_kek_source",
     {"eticket_rsa_kek_source",

+ 14 - 0
src/core/crypto/key_manager.h

@@ -165,15 +165,27 @@ public:
     bool BaseDeriveNecessary() const;
     bool BaseDeriveNecessary() const;
     void DeriveBase();
     void DeriveBase();
     void DeriveETicket(PartitionDataManager& data);
     void DeriveETicket(PartitionDataManager& data);
+    void PopulateTickets();
 
 
     void PopulateFromPartitionData(PartitionDataManager& data);
     void PopulateFromPartitionData(PartitionDataManager& data);
 
 
+    const std::map<u128, TicketRaw>& GetCommonTickets() const;
+    const std::map<u128, TicketRaw>& GetPersonalizedTickets() const;
+
+    bool AddTicketCommon(TicketRaw raw);
+    bool AddTicketPersonalized(TicketRaw raw);
+
 private:
 private:
     std::map<KeyIndex<S128KeyType>, Key128> s128_keys;
     std::map<KeyIndex<S128KeyType>, Key128> s128_keys;
     std::map<KeyIndex<S256KeyType>, Key256> s256_keys;
     std::map<KeyIndex<S256KeyType>, Key256> s256_keys;
 
 
+    // Map from rights ID to ticket
+    std::map<u128, TicketRaw> common_tickets;
+    std::map<u128, TicketRaw> personal_tickets;
+
     std::array<std::array<u8, 0xB0>, 0x20> encrypted_keyblobs{};
     std::array<std::array<u8, 0xB0>, 0x20> encrypted_keyblobs{};
     std::array<std::array<u8, 0x90>, 0x20> keyblobs{};
     std::array<std::array<u8, 0x90>, 0x20> keyblobs{};
+    std::array<u8, 576> eticket_extended_kek{};
 
 
     bool dev_mode;
     bool dev_mode;
     void LoadFromFile(const std::string& filename, bool is_title_keys);
     void LoadFromFile(const std::string& filename, bool is_title_keys);
@@ -185,6 +197,8 @@ private:
 
 
     void DeriveGeneralPurposeKeys(std::size_t crypto_revision);
     void DeriveGeneralPurposeKeys(std::size_t crypto_revision);
 
 
+    RSAKeyPair<2048> GetETicketRSAKey();
+
     void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
     void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
     void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
     void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);