From b7c947fed32468867ca2fc191b786060fbce88b3 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 a59a7e1f57..4ade67d236 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 214d206020a38ff5abeff2bd145e4fcb86bd71da 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 4ade67d236..14d53bef9a 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 5323ae4af4d443b9123b4ec1f00f24da5cde477c 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 14d53bef9a..1d77fda79e 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 f50401aa7f4eff35db6690afe635d7f615bbcf97 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 1d77fda79e..d2ce4f5bf5 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 1b48e3ec0888275fbcd2854a81385e7c963b7ec5 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 d1c04e98df..4baf8ccc5c 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 45c7fecfaf..0822a949c7 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 0581db975afb7a9793205e39d38ef9c1a8bf7772 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 4baf8ccc5c..7c3d9661d4 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 49f255e0b50779f1d4d16fbf6451a570b656998b 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 7c3d9661d4..ff46aad7c4 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 0822a949c7..c5a492a92b 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 8e8fbbc19b4faed97b9168b314e401f194865349 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 ff46aad7c4..bef8cdaf00 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 c5a492a92b..7c9c4410a9 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 e21cda8767466211fdc41fb15ea05f3eb26d9d6a 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 d2ce4f5bf5..fd07860684 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 a41abbdfcd..cccb3c0aec 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 bef8cdaf00..51d89508bd 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 7c9c4410a9..9e448f7205 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 7095c2fa42a100c17438b9e374166fe621c774d4 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 51d89508bd..056119c042 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 461cd4b81cc90d1b2da3f98033247b0a1d406935 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 056119c042..e364affbac 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 283f111f7df7ba241d20100b919f112507d98729 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 e364affbac..6862a08842 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 9e448f7205..0ad007c727 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 20a95f7e909f28df7a0abd78094981db3da97b25 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 6862a08842..a311ad8465 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 18db0f11077e0eb69342d3c17a44f5bdcff968ed 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 a311ad8465..ed5e2b145f 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); } }