summaryrefslogtreecommitdiff
path: root/src/core/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/crypto')
-rw-r--r--src/core/crypto/partition_data_manager.cpp131
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
28using namespace Common; 30using namespace Common;
29 31
@@ -45,36 +47,6 @@ struct Package2Header {
45}; 47};
46static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size."); 48static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size.");
47 49
48struct INIHeader {
49 u32_le magic;
50 u32_le size;
51 u32_le process_count;
52 INSERT_PADDING_BYTES(4);
53};
54static_assert(sizeof(INIHeader) == 0x10, "INIHeader has incorrect size.");
55
56struct SectionHeader {
57 u32_le offset;
58 u32_le size_decompressed;
59 u32_le size_compressed;
60 u32_le attribute;
61};
62static_assert(sizeof(SectionHeader) == 0x10, "SectionHeader has incorrect size.");
63
64struct 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};
76static_assert(sizeof(KIPHeader) == 0x100, "KIPHeader has incorrect size.");
77
78const std::array<SHA256Hash, 0x10> source_hashes{ 50const 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
173static 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
232static u8 CalculateMaxKeyblobSourceHash() { 145static 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}