summaryrefslogtreecommitdiffstats
path: root/src/core/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/crypto')
-rw-r--r--src/core/crypto/key_manager.cpp100
-rw-r--r--src/core/crypto/key_manager.h14
2 files changed, 100 insertions, 14 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 6dd633363..ef139902d 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/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) {
AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB);
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);
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 {
for (const auto& kv : KEYS_VARIABLE_LENGTH) {
if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2))
@@ -862,20 +886,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
// Titlekeys
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) +
"/system/save/80000000000000e1",
@@ -886,15 +909,24 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
const auto blob2 = GetTicketblob(save2);
auto res = GetTicketblob(save1);
+ const auto idx = res.size();
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)
continue;
const auto& [rid, key] = *pair;
u128 rights_id;
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]);
}
}
@@ -997,6 +1029,46 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
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 = {
{"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
{"eticket_rsa_kek_source",
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index 589b25696..8a67b172d 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -165,15 +165,27 @@ public:
bool BaseDeriveNecessary() const;
void DeriveBase();
void DeriveETicket(PartitionDataManager& data);
+ void PopulateTickets();
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:
std::map<KeyIndex<S128KeyType>, Key128> s128_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, 0x90>, 0x20> keyblobs{};
+ std::array<u8, 576> eticket_extended_kek{};
bool dev_mode;
void LoadFromFile(const std::string& filename, bool is_title_keys);
@@ -185,6 +197,8 @@ private:
void DeriveGeneralPurposeKeys(std::size_t crypto_revision);
+ RSAKeyPair<2048> GetETicketRSAKey();
+
void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);