diff options
Diffstat (limited to 'src/core/crypto/key_manager.cpp')
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 39 |
1 files changed, 26 insertions, 13 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index a59a7e1f5..fd0786068 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -98,7 +98,7 @@ std::array<u8, 144> DecryptKeyblob(const std::array<u8, 176>& encrypted_keyblob, | |||
| 98 | return keyblob; | 98 | return keyblob; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void KeyManager::DeriveGeneralPurposeKeys(u8 crypto_revision) { | 101 | void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) { |
| 102 | const auto kek_generation_source = | 102 | const auto kek_generation_source = |
| 103 | GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)); | 103 | GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)); |
| 104 | const auto key_generation_source = | 104 | const auto key_generation_source = |
| @@ -147,31 +147,38 @@ boost::optional<Key128> DeriveSDSeed() { | |||
| 147 | "rb+"); | 147 | "rb+"); |
| 148 | if (!save_43.IsOpen()) | 148 | if (!save_43.IsOpen()) |
| 149 | return boost::none; | 149 | return boost::none; |
| 150 | |||
| 150 | const FileUtil::IOFile sd_private( | 151 | const FileUtil::IOFile sd_private( |
| 151 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+"); | 152 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+"); |
| 152 | if (!sd_private.IsOpen()) | 153 | if (!sd_private.IsOpen()) |
| 153 | return boost::none; | 154 | return boost::none; |
| 154 | 155 | ||
| 155 | sd_private.Seek(0, SEEK_SET); | ||
| 156 | std::array<u8, 0x10> private_seed{}; | 156 | std::array<u8, 0x10> private_seed{}; |
| 157 | if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != 0x10) | 157 | if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) { |
| 158 | return boost::none; | 158 | return boost::none; |
| 159 | } | ||
| 159 | 160 | ||
| 160 | std::array<u8, 0x10> buffer{}; | 161 | std::array<u8, 0x10> buffer{}; |
| 161 | std::size_t offset = 0; | 162 | std::size_t offset = 0; |
| 162 | for (; offset + 0x10 < save_43.GetSize(); ++offset) { | 163 | for (; offset + 0x10 < save_43.GetSize(); ++offset) { |
| 163 | save_43.Seek(offset, SEEK_SET); | 164 | if (!save_43.Seek(offset, SEEK_SET)) { |
| 165 | return boost::none; | ||
| 166 | } | ||
| 167 | |||
| 164 | save_43.ReadBytes(buffer.data(), buffer.size()); | 168 | save_43.ReadBytes(buffer.data(), buffer.size()); |
| 165 | if (buffer == private_seed) | 169 | if (buffer == private_seed) { |
| 166 | break; | 170 | break; |
| 171 | } | ||
| 167 | } | 172 | } |
| 168 | 173 | ||
| 169 | if (offset + 0x10 >= save_43.GetSize()) | 174 | if (!save_43.Seek(offset + 0x10, SEEK_SET)) { |
| 170 | return boost::none; | 175 | return boost::none; |
| 176 | } | ||
| 171 | 177 | ||
| 172 | Key128 seed{}; | 178 | Key128 seed{}; |
| 173 | save_43.Seek(offset + 0x10, SEEK_SET); | 179 | if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) { |
| 174 | save_43.ReadBytes(seed.data(), seed.size()); | 180 | return boost::none; |
| 181 | } | ||
| 175 | return seed; | 182 | return seed; |
| 176 | } | 183 | } |
| 177 | 184 | ||
| @@ -234,7 +241,9 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) { | |||
| 234 | return {}; | 241 | return {}; |
| 235 | 242 | ||
| 236 | std::vector<u8> buffer(ticket_save.GetSize()); | 243 | std::vector<u8> buffer(ticket_save.GetSize()); |
| 237 | ticket_save.ReadBytes(buffer.data(), buffer.size()); | 244 | if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { |
| 245 | return {}; | ||
| 246 | } | ||
| 238 | 247 | ||
| 239 | std::vector<TicketRaw> out; | 248 | std::vector<TicketRaw> out; |
| 240 | u32 magic{}; | 249 | u32 magic{}; |
| @@ -261,6 +270,9 @@ static std::array<u8, size> operator^(const std::array<u8, size>& lhs, | |||
| 261 | 270 | ||
| 262 | template <size_t target_size, size_t in_size> | 271 | template <size_t target_size, size_t in_size> |
| 263 | static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) { | 272 | static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) { |
| 273 | // Avoids truncation overflow within the loop below. | ||
| 274 | static_assert(target_size <= 0xFF); | ||
| 275 | |||
| 264 | std::array<u8, in_size + 4> seed_exp{}; | 276 | std::array<u8, in_size + 4> seed_exp{}; |
| 265 | std::memcpy(seed_exp.data(), seed.data(), in_size); | 277 | std::memcpy(seed_exp.data(), seed.data(), in_size); |
| 266 | 278 | ||
| @@ -268,7 +280,7 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) { | |||
| 268 | size_t i = 0; | 280 | size_t i = 0; |
| 269 | while (out.size() < target_size) { | 281 | while (out.size() < target_size) { |
| 270 | out.resize(out.size() + 0x20); | 282 | out.resize(out.size() + 0x20); |
| 271 | seed_exp[in_size + 3] = i; | 283 | seed_exp[in_size + 3] = static_cast<u8>(i); |
| 272 | mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0); | 284 | mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0); |
| 273 | ++i; | 285 | ++i; |
| 274 | } | 286 | } |
| @@ -299,10 +311,11 @@ boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, | |||
| 299 | std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); | 311 | std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); |
| 300 | if (cert_authority == 0) | 312 | if (cert_authority == 0) |
| 301 | return boost::none; | 313 | return boost::none; |
| 302 | if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) | 314 | if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) { |
| 303 | LOG_INFO(Crypto, | 315 | LOG_INFO(Crypto, |
| 304 | "Attempting to parse ticket with non-standard certificate authority {:08X}.", | 316 | "Attempting to parse ticket with non-standard certificate authority {:08X}.", |
| 305 | cert_authority); | 317 | cert_authority); |
| 318 | } | ||
| 306 | 319 | ||
| 307 | Key128 rights_id; | 320 | Key128 rights_id; |
| 308 | std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); | 321 | std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); |
| @@ -871,9 +884,9 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { | |||
| 871 | "/system/save/80000000000000e2", | 884 | "/system/save/80000000000000e2", |
| 872 | "rb+"); | 885 | "rb+"); |
| 873 | 886 | ||
| 887 | const auto blob2 = GetTicketblob(save2); | ||
| 874 | auto res = GetTicketblob(save1); | 888 | auto res = GetTicketblob(save1); |
| 875 | const auto res2 = GetTicketblob(save2); | 889 | res.insert(res.end(), blob2.begin(), blob2.end()); |
| 876 | std::copy(res2.begin(), res2.end(), std::back_inserter(res)); | ||
| 877 | 890 | ||
| 878 | for (const auto& raw : res) { | 891 | for (const auto& raw : res) { |
| 879 | const auto pair = ParseTicket(raw, rsa_key); | 892 | const auto pair = ParseTicket(raw, rsa_key); |