3
0
Fork 0
forked from suyu/suyu

key_manager: Add accessors/helpers for ticket management

This commit is contained in:
Zach Hilman 2019-04-10 10:22:04 -04:00
parent 5275fd2789
commit e35fac2054
2 changed files with 100 additions and 14 deletions

View file

@ -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); void KeyManager::PopulateTickets() {
std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size()); const auto rsa_key = GetETicketRSAKey();
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{}; if (rsa_key == RSAKeyPair<2048>{})
std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size()); return;
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 (!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) { for (std::size_t i = 0; i < res.size(); ++i) {
const auto pair = ParseTicket(raw, rsa_key); 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",

View file

@ -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);