From 82ea1cf35a2b10bb7a2cfbaa0d9bac98fe5bb182 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:08:41 -0400 Subject: [PATCH 01/14] key_manager: Remove unnecessary seek in DeriveSDSeed() Given the file is opened a few lines above and no operations are done, other than check if the file is in a valid state, the read/write pointer will always be at the beginning of the file. --- src/core/crypto/key_manager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index a59a7e1f5..4ade67d23 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -152,7 +152,6 @@ boost::optional DeriveSDSeed() { if (!sd_private.IsOpen()) return boost::none; - sd_private.Seek(0, SEEK_SET); std::array private_seed{}; if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != 0x10) return boost::none; From ef5639bfbbeb7d83bd66e3faf3e88e4aa1e05a6e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:12:00 -0400 Subject: [PATCH 02/14] key_manager: Don't assume file seeks and reads will always succeed Given the filesystem should always be assumed to be volatile, we should check and bail out if a seek operation isn't successful. This'll prevent potentially writing/returning garbage data from the function in rare cases. This also allows removing a check to see if an offset is within the bounds of a file before perfoming a seek operation. If a seek is attempted beyond the end of a file, it will fail, so this essentially combines two checks into one in one place. --- src/core/crypto/key_manager.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 4ade67d23..14d53bef9 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -147,30 +147,38 @@ boost::optional DeriveSDSeed() { "rb+"); if (!save_43.IsOpen()) return boost::none; + const FileUtil::IOFile sd_private( FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+"); if (!sd_private.IsOpen()) return boost::none; std::array private_seed{}; - if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != 0x10) + if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) { return boost::none; + } std::array buffer{}; std::size_t offset = 0; for (; offset + 0x10 < save_43.GetSize(); ++offset) { - save_43.Seek(offset, SEEK_SET); + if (!save_43.Seek(offset, SEEK_SET)) { + return boost::none; + } + save_43.ReadBytes(buffer.data(), buffer.size()); - if (buffer == private_seed) + if (buffer == private_seed) { break; + } } - if (offset + 0x10 >= save_43.GetSize()) + if (!save_43.Seek(offset + 0x10, SEEK_SET)) { return boost::none; + } Key128 seed{}; - save_43.Seek(offset + 0x10, SEEK_SET); - save_43.ReadBytes(seed.data(), seed.size()); + if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) { + return boost::none; + } return seed; } @@ -233,7 +241,9 @@ std::vector GetTicketblob(const FileUtil::IOFile& ticket_save) { return {}; std::vector buffer(ticket_save.GetSize()); - ticket_save.ReadBytes(buffer.data(), buffer.size()); + if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { + return {}; + } std::vector out; u32 magic{}; From e70c08b543f1af569a59c672f707128cc31d341d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:14:38 -0400 Subject: [PATCH 03/14] key_manager: Brace long conditional body If a conditional (or it's body) travels more than one line, it should be braced. --- src/core/crypto/key_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 14d53bef9..1d77fda79 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -308,10 +308,11 @@ boost::optional> ParseTicket(const TicketRaw& ticket, std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); if (cert_authority == 0) return boost::none; - if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) + if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) { LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority {:08X}.", cert_authority); + } Key128 rights_id; std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); From 06898263f6ef8dc4294a8c7554023320c27b957c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:28:15 -0400 Subject: [PATCH 04/14] key_manager: Use std::vector's insert() instead of std::copy with a back_inserter If the data is unconditionally being appended to the back of a std::vector, we can just directly insert it there without the need to insert all of the elements one-by-one with a std::back_inserter. --- src/core/crypto/key_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 1d77fda79..d2ce4f5bf 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -881,9 +881,9 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { "/system/save/80000000000000e2", "rb+"); + const auto blob2 = GetTicketblob(save2); auto res = GetTicketblob(save1); - const auto res2 = GetTicketblob(save2); - std::copy(res2.begin(), res2.end(), std::back_inserter(res)); + res.insert(res.end(), blob2.begin(), blob2.end()); for (const auto& raw : res) { const auto pair = ParseTicket(raw, rsa_key); From aaca7543f0a13d7a052d08d1e1a4dbf51a18c441 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:33:45 -0400 Subject: [PATCH 05/14] partition_data_manager: Remove unused includes Gets unused includes out of the headers and moves them into the cpp file if they're used there instead. --- src/core/crypto/partition_data_manager.cpp | 3 +-- src/core/crypto/partition_data_manager.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index d1c04e98d..4baf8ccc5 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "common/assert.h" #include "common/common_funcs.h" @@ -19,7 +18,7 @@ #include "common/hex_util.h" #include "common/logging/log.h" #include "common/string_util.h" -#include "core/crypto/ctr_encryption_layer.h" +#include "common/swap.h" #include "core/crypto/key_manager.h" #include "core/crypto/partition_data_manager.h" #include "core/crypto/xts_encryption_layer.h" diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h index 45c7fecfa..0822a949c 100644 --- a/src/core/crypto/partition_data_manager.h +++ b/src/core/crypto/partition_data_manager.h @@ -5,9 +5,7 @@ #pragma once #include -#include "common/common_funcs.h" #include "common/common_types.h" -#include "common/swap.h" #include "core/file_sys/vfs_types.h" namespace Core::Crypto { From e96d69c328ff217de01e457250504d08dfe785ca Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:36:23 -0400 Subject: [PATCH 06/14] partition_data_manager: Amend constructor initializer list order Orders the members in the exact order they would be initialized. This also prevents compiler warnings about this sort of thing. --- src/core/crypto/partition_data_manager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index 4baf8ccc5..7c3d9661d 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -313,13 +313,14 @@ PartitionDataManager::PartitionDataManager(FileSys::VirtualDir sysdata_dir) FindFileInDirWithNames(sysdata_dir, "BCPKG2-5-Repair-Main"), FindFileInDirWithNames(sysdata_dir, "BCPKG2-6-Repair-Sub"), }), + prodinfo(FindFileInDirWithNames(sysdata_dir, "PRODINFO")), secure_monitor(FindFileInDirWithNames(sysdata_dir, "secmon")), package1_decrypted(FindFileInDirWithNames(sysdata_dir, "pkg1_decr")), secure_monitor_bytes(secure_monitor == nullptr ? std::vector{} : secure_monitor->ReadAllBytes()), package1_decrypted_bytes(package1_decrypted == nullptr ? std::vector{} - : package1_decrypted->ReadAllBytes()), - prodinfo(FindFileInDirWithNames(sysdata_dir, "PRODINFO")) {} + : package1_decrypted->ReadAllBytes()) { +} PartitionDataManager::~PartitionDataManager() = default; From d257a3b56cac582fe296994b98f050e7b8f39056 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:39:02 -0400 Subject: [PATCH 07/14] partition_data_manager: Take VirtualFile by const reference in constructor Given the VirtualFile instance isn't stored into the class as a data member, or written to, this can just be turned into a const reference, as the constructor doesn't need to make a copy of it. --- src/core/crypto/partition_data_manager.cpp | 2 +- src/core/crypto/partition_data_manager.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index 7c3d9661d..ff46aad7c 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -301,7 +301,7 @@ FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir, return nullptr; } -PartitionDataManager::PartitionDataManager(FileSys::VirtualDir sysdata_dir) +PartitionDataManager::PartitionDataManager(const FileSys::VirtualDir& sysdata_dir) : boot0(FindFileInDirWithNames(sysdata_dir, "BOOT0")), fuses(FindFileInDirWithNames(sysdata_dir, "fuse")), kfuses(FindFileInDirWithNames(sysdata_dir, "kfuse")), diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h index 0822a949c..c5a492a92 100644 --- a/src/core/crypto/partition_data_manager.h +++ b/src/core/crypto/partition_data_manager.h @@ -23,7 +23,7 @@ class PartitionDataManager { public: static const u8 MAX_KEYBLOB_SOURCE_HASH; - explicit PartitionDataManager(FileSys::VirtualDir sysdata_dir); + explicit PartitionDataManager(const FileSys::VirtualDir& sysdata_dir); ~PartitionDataManager(); // BOOT0 From f56a8da46a58c0a4a1ce2570038a7060de29a18c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 08:52:34 -0400 Subject: [PATCH 08/14] partition_data_manager: Dehardcode array bounds Instead, we can make it part of the type and make named variables for them, so they only require one definition (and if they ever change for whatever reason, they only need to be changed in one spot). --- src/core/crypto/partition_data_manager.cpp | 10 +++++----- src/core/crypto/partition_data_manager.h | 9 +++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index ff46aad7c..bef8cdaf0 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -332,18 +332,18 @@ FileSys::VirtualFile PartitionDataManager::GetBoot0Raw() const { return boot0; } -std::array PartitionDataManager::GetEncryptedKeyblob(u8 index) const { - if (HasBoot0() && index < 32) +PartitionDataManager::EncryptedKeyBlob PartitionDataManager::GetEncryptedKeyblob(u8 index) const { + if (HasBoot0() && index < NUM_ENCRYPTED_KEYBLOBS) return GetEncryptedKeyblobs()[index]; return {}; } -std::array, 32> PartitionDataManager::GetEncryptedKeyblobs() const { +PartitionDataManager::EncryptedKeyBlobs PartitionDataManager::GetEncryptedKeyblobs() const { if (!HasBoot0()) return {}; - std::array, 32> out{}; - for (size_t i = 0; i < 0x20; ++i) + EncryptedKeyBlobs out{}; + for (size_t i = 0; i < out.size(); ++i) boot0->Read(out[i].data(), out[i].size(), 0x180000 + i * 0x200); return out; } diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h index c5a492a92..7c9c4410a 100644 --- a/src/core/crypto/partition_data_manager.h +++ b/src/core/crypto/partition_data_manager.h @@ -22,6 +22,11 @@ enum class Package2Type { class PartitionDataManager { public: static const u8 MAX_KEYBLOB_SOURCE_HASH; + static constexpr std::size_t NUM_ENCRYPTED_KEYBLOBS = 32; + static constexpr std::size_t ENCRYPTED_KEYBLOB_SIZE = 0xB0; + + using EncryptedKeyBlob = std::array; + using EncryptedKeyBlobs = std::array; explicit PartitionDataManager(const FileSys::VirtualDir& sysdata_dir); ~PartitionDataManager(); @@ -29,8 +34,8 @@ public: // BOOT0 bool HasBoot0() const; FileSys::VirtualFile GetBoot0Raw() const; - std::array GetEncryptedKeyblob(u8 index) const; - std::array, 0x20> GetEncryptedKeyblobs() const; + EncryptedKeyBlob GetEncryptedKeyblob(u8 index) const; + EncryptedKeyBlobs GetEncryptedKeyblobs() const; std::vector GetSecureMonitor() const; std::array GetPackage2KeySource() const; std::array GetAESKekGenerationSource() const; From 6da2ed4232d3b3ecde7a04621c554f66de558fab Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 09:13:19 -0400 Subject: [PATCH 09/14] key_manager/partition_data_manager: Silence truncation compiler warnings --- src/core/crypto/key_manager.cpp | 7 +++++-- src/core/crypto/key_manager.h | 2 +- src/core/crypto/partition_data_manager.cpp | 12 +++++++----- src/core/crypto/partition_data_manager.h | 4 ++-- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index d2ce4f5bf..fd0786068 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -98,7 +98,7 @@ std::array DecryptKeyblob(const std::array& encrypted_keyblob, return keyblob; } -void KeyManager::DeriveGeneralPurposeKeys(u8 crypto_revision) { +void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) { const auto kek_generation_source = GetKey(S128KeyType::Source, static_cast(SourceKeyType::AESKekGeneration)); const auto key_generation_source = @@ -270,6 +270,9 @@ static std::array operator^(const std::array& lhs, template static std::array MGF1(const std::array& seed) { + // Avoids truncation overflow within the loop below. + static_assert(target_size <= 0xFF); + std::array seed_exp{}; std::memcpy(seed_exp.data(), seed.data(), in_size); @@ -277,7 +280,7 @@ static std::array MGF1(const std::array& seed) { size_t i = 0; while (out.size() < target_size) { out.resize(out.size() + 0x20); - seed_exp[in_size + 3] = i; + seed_exp[in_size + 3] = static_cast(i); mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0); ++i; } diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index a41abbdfc..cccb3c0ae 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -175,7 +175,7 @@ private: void WriteKeyToFile(KeyCategory category, std::string_view keyname, const std::array& key); - void DeriveGeneralPurposeKeys(u8 crypto_revision); + void DeriveGeneralPurposeKeys(std::size_t crypto_revision); void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index bef8cdaf0..51d89508b 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -332,7 +332,8 @@ FileSys::VirtualFile PartitionDataManager::GetBoot0Raw() const { return boot0; } -PartitionDataManager::EncryptedKeyBlob PartitionDataManager::GetEncryptedKeyblob(u8 index) const { +PartitionDataManager::EncryptedKeyBlob PartitionDataManager::GetEncryptedKeyblob( + std::size_t index) const { if (HasBoot0() && index < NUM_ENCRYPTED_KEYBLOBS) return GetEncryptedKeyblobs()[index]; return {}; @@ -389,7 +390,7 @@ std::array PartitionDataManager::GetKeyblobMACKeySource() const { return FindKeyFromHex(package1_decrypted_bytes, source_hashes[0]); } -std::array PartitionDataManager::GetKeyblobKeySource(u8 revision) const { +std::array PartitionDataManager::GetKeyblobKeySource(std::size_t revision) const { if (keyblob_source_hashes[revision] == SHA256Hash{}) { LOG_WARNING(Crypto, "No keyblob source hash for crypto revision {:02X}! Cannot derive keys...", @@ -456,11 +457,12 @@ void PartitionDataManager::DecryptPackage2(std::array, 0x20> if (file->ReadObject(&header) != sizeof(Package2Header)) return; - u8 revision = 0xFF; + std::size_t revision = 0xFF; if (header.magic != Common::MakeMagic('P', 'K', '2', '1')) { - for (size_t i = 0; i < package2_keys.size(); ++i) { - if (AttemptDecrypt(package2_keys[i], header)) + for (std::size_t i = 0; i < package2_keys.size(); ++i) { + if (AttemptDecrypt(package2_keys[i], header)) { revision = i; + } } } diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h index 7c9c4410a..9e448f720 100644 --- a/src/core/crypto/partition_data_manager.h +++ b/src/core/crypto/partition_data_manager.h @@ -34,7 +34,7 @@ public: // BOOT0 bool HasBoot0() const; FileSys::VirtualFile GetBoot0Raw() const; - EncryptedKeyBlob GetEncryptedKeyblob(u8 index) const; + EncryptedKeyBlob GetEncryptedKeyblob(std::size_t index) const; EncryptedKeyBlobs GetEncryptedKeyblobs() const; std::vector GetSecureMonitor() const; std::array GetPackage2KeySource() const; @@ -46,7 +46,7 @@ public: std::vector GetPackage1Decrypted() const; std::array GetMasterKeySource() const; std::array GetKeyblobMACKeySource() const; - std::array GetKeyblobKeySource(u8 revision) const; + std::array GetKeyblobKeySource(std::size_t revision) const; // Fuses bool HasFuses() const; From bc2196bb090e14a71f47bb6a41a35529116dcf66 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 09:16:27 -0400 Subject: [PATCH 10/14] partition_data_manager: Remove commented out code Commented out code shouldn't be left in without a reason indicating why in a comment. --- src/core/crypto/partition_data_manager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index 51d89508b..056119c04 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -480,8 +480,6 @@ void PartitionDataManager::DecryptPackage2(std::array, 0x20> cipher.SetIV(s1_iv); cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt); - // package2_decrypted[static_cast(type)] = s1; - INIHeader ini; std::memcpy(&ini, c.data(), sizeof(INIHeader)); if (ini.magic != Common::MakeMagic('I', 'N', 'I', '1')) From 3d9df49619a44bacda8c02fea60e63d9a7aa22fc Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 09:20:19 -0400 Subject: [PATCH 11/14] partition_data_manager: Move IV data to where it's needed in DecryptPackage2() Given it's only used in one spot and has a fairly generic name, we can just specify it directly in the function call. This also the benefit of automatically moving it. --- src/core/crypto/partition_data_manager.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index 056119c04..e364affba 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -469,15 +469,13 @@ void PartitionDataManager::DecryptPackage2(std::array, 0x20> if (header.magic != Common::MakeMagic('P', 'K', '2', '1')) return; - const std::vector s1_iv(header.section_ctr[1].begin(), header.section_ctr[1].end()); - const auto a = std::make_shared( file, header.section_size[1], header.section_size[0] + sizeof(Package2Header)); auto c = a->ReadAllBytes(); AESCipher cipher(package2_keys[revision], Mode::CTR); - cipher.SetIV(s1_iv); + cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()}); cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt); INIHeader ini; From e0c76226ad3a100637348d822d2c5d7047f78bda Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 09:23:34 -0400 Subject: [PATCH 12/14] partition_data_manager: Take package2_keys by const reference These are only ever read from, so we don't need to make a copy of all the keys here. --- src/core/crypto/partition_data_manager.cpp | 2 +- src/core/crypto/partition_data_manager.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index e364affba..6862a0884 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -447,7 +447,7 @@ bool AttemptDecrypt(const std::array& key, Package2Header& header) { return false; } -void PartitionDataManager::DecryptPackage2(std::array, 0x20> package2_keys, +void PartitionDataManager::DecryptPackage2(const std::array& package2_keys, Package2Type type) { FileSys::VirtualFile file = std::make_shared( package2[static_cast(type)], diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h index 9e448f720..0ad007c72 100644 --- a/src/core/crypto/partition_data_manager.h +++ b/src/core/crypto/partition_data_manager.h @@ -60,7 +60,8 @@ public: // Package2 bool HasPackage2(Package2Type type = Package2Type::NormalMain) const; FileSys::VirtualFile GetPackage2Raw(Package2Type type = Package2Type::NormalMain) const; - void DecryptPackage2(std::array, 0x20> package2, Package2Type type); + void DecryptPackage2(const std::array, 0x20>& package2_keys, + Package2Type type); const std::vector& GetPackage2FSDecompressed( Package2Type type = Package2Type::NormalMain) const; std::array GetKeyAreaKeyApplicationSource( From 781fd7983cf543fc98685a38c82c5dd4576514dc Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 09:27:07 -0400 Subject: [PATCH 13/14] partition_data_manager: Remove unused std::map instance within DecryptPackage2() Aside from emplacing elements into the map, the map itself is never actually queried for contained data. --- src/core/crypto/partition_data_manager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index 6862a0884..a311ad846 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -483,14 +483,12 @@ void PartitionDataManager::DecryptPackage2(const std::array& packa if (ini.magic != Common::MakeMagic('I', 'N', 'I', '1')) return; - std::map kips{}; u64 offset = sizeof(INIHeader); for (size_t i = 0; i < ini.process_count; ++i) { KIPHeader kip; std::memcpy(&kip, c.data() + offset, sizeof(KIPHeader)); if (kip.magic != Common::MakeMagic('K', 'I', 'P', '1')) return; - kips.emplace(offset, kip); const auto name = Common::StringFromFixedZeroTerminatedBuffer(kip.name.data(), kip.name.size()); From 6467b01de2debf86db8c409160ab50d24d32149e Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 13 Oct 2018 09:30:09 -0400 Subject: [PATCH 14/14] partition_data_manager: Reserve and insert data within output vector in DecryptPackage2() We can just reserve the memory then perform successive insertions instead of needing to use memcpy. This also avoids the need to zero out the output vector's memory before performing the insertions. We can also std::move the output std::vector into the destination so that we don't need to make a completely new copy of the vector, getting rid of an unnecessary allocation. Additionally, we can use iterators to determine the beginning and end ranges of the std::vector instances that comprise the output vector, as the end of one range just becomes the beginning for the next successive range, and since std::vector's iterator constructor copies data within the range [begin, end), this is more straightforward and gets rid of the need to have an offset variable that keeps getting incremented to determine where to do the next std::memcpy. --- src/core/crypto/partition_data_manager.cpp | 36 ++++++++++------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index a311ad846..ed5e2b145 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -499,33 +499,29 @@ void PartitionDataManager::DecryptPackage2(const std::array& packa continue; } - std::vector text(kip.sections[0].size_compressed); - std::vector rodata(kip.sections[1].size_compressed); - std::vector data(kip.sections[2].size_compressed); + const u64 initial_offset = sizeof(KIPHeader) + offset; + const auto text_begin = c.cbegin() + initial_offset; + const auto text_end = text_begin + kip.sections[0].size_compressed; + const std::vector text = DecompressBLZ({text_begin, text_end}); - u64 offset_sec = sizeof(KIPHeader) + offset; - std::memcpy(text.data(), c.data() + offset_sec, text.size()); - offset_sec += text.size(); - std::memcpy(rodata.data(), c.data() + offset_sec, rodata.size()); - offset_sec += rodata.size(); - std::memcpy(data.data(), c.data() + offset_sec, data.size()); + const auto rodata_end = text_end + kip.sections[1].size_compressed; + const std::vector rodata = DecompressBLZ({text_end, rodata_end}); - offset += sizeof(KIPHeader) + kip.sections[0].size_compressed + - kip.sections[1].size_compressed + kip.sections[2].size_compressed; + const auto data_end = rodata_end + kip.sections[2].size_compressed; + const std::vector data = DecompressBLZ({rodata_end, data_end}); - text = DecompressBLZ(text); - rodata = DecompressBLZ(rodata); - data = DecompressBLZ(data); + std::vector out; + out.reserve(text.size() + rodata.size() + data.size()); + out.insert(out.end(), text.begin(), text.end()); + out.insert(out.end(), rodata.begin(), rodata.end()); + out.insert(out.end(), data.begin(), data.end()); - std::vector out(text.size() + rodata.size() + data.size()); - std::memcpy(out.data(), text.data(), text.size()); - std::memcpy(out.data() + text.size(), rodata.data(), rodata.size()); - std::memcpy(out.data() + text.size() + rodata.size(), data.data(), data.size()); + offset += sizeof(KIPHeader) + out.size(); if (name == "FS") - package2_fs[static_cast(type)] = out; + package2_fs[static_cast(type)] = std::move(out); else if (name == "spl") - package2_spl[static_cast(type)] = out; + package2_spl[static_cast(type)] = std::move(out); } }