diff options
Diffstat (limited to 'src/core/crypto')
| -rw-r--r-- | src/core/crypto/partition_data_manager.cpp | 131 |
1 files changed, 13 insertions, 118 deletions
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index ed0775444..01a969be9 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp | |||
| @@ -22,8 +22,10 @@ | |||
| 22 | #include "core/crypto/key_manager.h" | 22 | #include "core/crypto/key_manager.h" |
| 23 | #include "core/crypto/partition_data_manager.h" | 23 | #include "core/crypto/partition_data_manager.h" |
| 24 | #include "core/crypto/xts_encryption_layer.h" | 24 | #include "core/crypto/xts_encryption_layer.h" |
| 25 | #include "core/file_sys/kernel_executable.h" | ||
| 25 | #include "core/file_sys/vfs.h" | 26 | #include "core/file_sys/vfs.h" |
| 26 | #include "core/file_sys/vfs_offset.h" | 27 | #include "core/file_sys/vfs_offset.h" |
| 28 | #include "core/file_sys/vfs_vector.h" | ||
| 27 | 29 | ||
| 28 | using namespace Common; | 30 | using namespace Common; |
| 29 | 31 | ||
| @@ -45,36 +47,6 @@ struct Package2Header { | |||
| 45 | }; | 47 | }; |
| 46 | static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size."); | 48 | static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size."); |
| 47 | 49 | ||
| 48 | struct INIHeader { | ||
| 49 | u32_le magic; | ||
| 50 | u32_le size; | ||
| 51 | u32_le process_count; | ||
| 52 | INSERT_PADDING_BYTES(4); | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(INIHeader) == 0x10, "INIHeader has incorrect size."); | ||
| 55 | |||
| 56 | struct SectionHeader { | ||
| 57 | u32_le offset; | ||
| 58 | u32_le size_decompressed; | ||
| 59 | u32_le size_compressed; | ||
| 60 | u32_le attribute; | ||
| 61 | }; | ||
| 62 | static_assert(sizeof(SectionHeader) == 0x10, "SectionHeader has incorrect size."); | ||
| 63 | |||
| 64 | struct KIPHeader { | ||
| 65 | u32_le magic; | ||
| 66 | std::array<char, 12> name; | ||
| 67 | u64_le title_id; | ||
| 68 | u32_le category; | ||
| 69 | u8 priority; | ||
| 70 | u8 core; | ||
| 71 | INSERT_PADDING_BYTES(1); | ||
| 72 | u8 flags; | ||
| 73 | std::array<SectionHeader, 6> sections; | ||
| 74 | std::array<u32, 0x20> capabilities; | ||
| 75 | }; | ||
| 76 | static_assert(sizeof(KIPHeader) == 0x100, "KIPHeader has incorrect size."); | ||
| 77 | |||
| 78 | const std::array<SHA256Hash, 0x10> source_hashes{ | 50 | const std::array<SHA256Hash, 0x10> source_hashes{ |
| 79 | "B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source | 51 | "B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source |
| 80 | "7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source | 52 | "7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source |
| @@ -170,65 +142,6 @@ const std::array<SHA256Hash, 0x20> master_key_hashes{ | |||
| 170 | "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F | 142 | "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F |
| 171 | }; | 143 | }; |
| 172 | 144 | ||
| 173 | static std::vector<u8> DecompressBLZ(const std::vector<u8>& in) { | ||
| 174 | const auto data_size = in.size() - 0xC; | ||
| 175 | |||
| 176 | u32 compressed_size{}; | ||
| 177 | u32 init_index{}; | ||
| 178 | u32 additional_size{}; | ||
| 179 | std::memcpy(&compressed_size, in.data() + data_size, sizeof(u32)); | ||
| 180 | std::memcpy(&init_index, in.data() + data_size + 0x4, sizeof(u32)); | ||
| 181 | std::memcpy(&additional_size, in.data() + data_size + 0x8, sizeof(u32)); | ||
| 182 | |||
| 183 | std::vector<u8> out(in.size() + additional_size); | ||
| 184 | |||
| 185 | if (compressed_size == in.size()) | ||
| 186 | std::memcpy(out.data(), in.data() + in.size() - compressed_size, compressed_size); | ||
| 187 | else | ||
| 188 | std::memcpy(out.data(), in.data(), compressed_size); | ||
| 189 | |||
| 190 | auto index = in.size() - init_index; | ||
| 191 | auto out_index = out.size(); | ||
| 192 | |||
| 193 | while (out_index > 0) { | ||
| 194 | --index; | ||
| 195 | auto control = in[index]; | ||
| 196 | for (size_t i = 0; i < 8; ++i) { | ||
| 197 | if ((control & 0x80) > 0) { | ||
| 198 | ASSERT(index >= 2); | ||
| 199 | index -= 2; | ||
| 200 | u64 segment_offset = in[index] | in[index + 1] << 8; | ||
| 201 | u64 segment_size = ((segment_offset >> 12) & 0xF) + 3; | ||
| 202 | segment_offset &= 0xFFF; | ||
| 203 | segment_offset += 3; | ||
| 204 | |||
| 205 | if (out_index < segment_size) | ||
| 206 | segment_size = out_index; | ||
| 207 | |||
| 208 | ASSERT(out_index >= segment_size); | ||
| 209 | |||
| 210 | out_index -= segment_size; | ||
| 211 | |||
| 212 | for (size_t j = 0; j < segment_size; ++j) { | ||
| 213 | ASSERT(out_index + j + segment_offset < out.size()); | ||
| 214 | out[out_index + j] = out[out_index + j + segment_offset]; | ||
| 215 | } | ||
| 216 | } else { | ||
| 217 | ASSERT(out_index >= 1); | ||
| 218 | --out_index; | ||
| 219 | --index; | ||
| 220 | out[out_index] = in[index]; | ||
| 221 | } | ||
| 222 | |||
| 223 | control <<= 1; | ||
| 224 | if (out_index == 0) | ||
| 225 | return out; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | return out; | ||
| 230 | } | ||
| 231 | |||
| 232 | static u8 CalculateMaxKeyblobSourceHash() { | 145 | static u8 CalculateMaxKeyblobSourceHash() { |
| 233 | for (s8 i = 0x1F; i >= 0; --i) { | 146 | for (s8 i = 0x1F; i >= 0; --i) { |
| 234 | if (keyblob_source_hashes[i] != SHA256Hash{}) | 147 | if (keyblob_source_hashes[i] != SHA256Hash{}) |
| @@ -478,37 +391,22 @@ void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& packa | |||
| 478 | cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()}); | 391 | cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()}); |
| 479 | cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt); | 392 | cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt); |
| 480 | 393 | ||
| 481 | INIHeader ini; | 394 | const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c); |
| 482 | std::memcpy(&ini, c.data(), sizeof(INIHeader)); | 395 | const FileSys::INI ini{ini_file}; |
| 483 | if (ini.magic != Common::MakeMagic('I', 'N', 'I', '1')) | 396 | if (ini.GetStatus() != Loader::ResultStatus::Success) |
| 484 | return; | 397 | return; |
| 485 | 398 | ||
| 486 | u64 offset = sizeof(INIHeader); | 399 | for (const auto& kip : ini.GetKIPs()) { |
| 487 | for (size_t i = 0; i < ini.process_count; ++i) { | 400 | if (kip.GetStatus() != Loader::ResultStatus::Success) |
| 488 | KIPHeader kip; | ||
| 489 | std::memcpy(&kip, c.data() + offset, sizeof(KIPHeader)); | ||
| 490 | if (kip.magic != Common::MakeMagic('K', 'I', 'P', '1')) | ||
| 491 | return; | 401 | return; |
| 492 | 402 | ||
| 493 | const auto name = | 403 | if (kip.GetName() != "FS" && kip.GetName() != "spl") { |
| 494 | Common::StringFromFixedZeroTerminatedBuffer(kip.name.data(), kip.name.size()); | ||
| 495 | |||
| 496 | if (name != "FS" && name != "spl") { | ||
| 497 | offset += sizeof(KIPHeader) + kip.sections[0].size_compressed + | ||
| 498 | kip.sections[1].size_compressed + kip.sections[2].size_compressed; | ||
| 499 | continue; | 404 | continue; |
| 500 | } | 405 | } |
| 501 | 406 | ||
| 502 | const u64 initial_offset = sizeof(KIPHeader) + offset; | 407 | const auto& text = kip.GetTextSection(); |
| 503 | const auto text_begin = c.cbegin() + initial_offset; | 408 | const auto& rodata = kip.GetRODataSection(); |
| 504 | const auto text_end = text_begin + kip.sections[0].size_compressed; | 409 | const auto& data = kip.GetDataSection(); |
| 505 | const std::vector<u8> text = DecompressBLZ({text_begin, text_end}); | ||
| 506 | |||
| 507 | const auto rodata_end = text_end + kip.sections[1].size_compressed; | ||
| 508 | const std::vector<u8> rodata = DecompressBLZ({text_end, rodata_end}); | ||
| 509 | |||
| 510 | const auto data_end = rodata_end + kip.sections[2].size_compressed; | ||
| 511 | const std::vector<u8> data = DecompressBLZ({rodata_end, data_end}); | ||
| 512 | 410 | ||
| 513 | std::vector<u8> out; | 411 | std::vector<u8> out; |
| 514 | out.reserve(text.size() + rodata.size() + data.size()); | 412 | out.reserve(text.size() + rodata.size() + data.size()); |
| @@ -516,12 +414,9 @@ void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& packa | |||
| 516 | out.insert(out.end(), rodata.begin(), rodata.end()); | 414 | out.insert(out.end(), rodata.begin(), rodata.end()); |
| 517 | out.insert(out.end(), data.begin(), data.end()); | 415 | out.insert(out.end(), data.begin(), data.end()); |
| 518 | 416 | ||
| 519 | offset += sizeof(KIPHeader) + kip.sections[0].size_compressed + | 417 | if (kip.GetName() == "FS") |
| 520 | kip.sections[1].size_compressed + kip.sections[2].size_compressed; | ||
| 521 | |||
| 522 | if (name == "FS") | ||
| 523 | package2_fs[static_cast<size_t>(type)] = std::move(out); | 418 | package2_fs[static_cast<size_t>(type)] = std::move(out); |
| 524 | else if (name == "spl") | 419 | else if (kip.GetName() == "spl") |
| 525 | package2_spl[static_cast<size_t>(type)] = std::move(out); | 420 | package2_spl[static_cast<size_t>(type)] = std::move(out); |
| 526 | } | 421 | } |
| 527 | } | 422 | } |