diff options
author | Zach Hilman <zachhilman@gmail.com> | 2018-08-19 03:14:57 +0200 |
---|---|---|
committer | Zach Hilman <zachhilman@gmail.com> | 2018-08-23 17:53:30 +0200 |
commit | 42dc856ce136c75f587649863ec5bd936ba8b07a (patch) | |
tree | 5b270705a38cc4187a5634f753c9caa2f398dfb8 | |
parent | key_manager: Add support for autogenerated keys (diff) | |
download | yuzu-42dc856ce136c75f587649863ec5bd936ba8b07a.tar yuzu-42dc856ce136c75f587649863ec5bd936ba8b07a.tar.gz yuzu-42dc856ce136c75f587649863ec5bd936ba8b07a.tar.bz2 yuzu-42dc856ce136c75f587649863ec5bd936ba8b07a.tar.lz yuzu-42dc856ce136c75f587649863ec5bd936ba8b07a.tar.xz yuzu-42dc856ce136c75f587649863ec5bd936ba8b07a.tar.zst yuzu-42dc856ce136c75f587649863ec5bd936ba8b07a.zip |
-rw-r--r-- | src/core/crypto/key_manager.cpp | 2 | ||||
-rw-r--r-- | src/core/crypto/xts_encryption_layer.cpp | 33 | ||||
-rw-r--r-- | src/core/file_sys/xts_archive.cpp | 25 | ||||
-rw-r--r-- | src/core/file_sys/xts_archive.h | 10 |
4 files changed, 38 insertions, 32 deletions
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 994ac4eec..acf635a65 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -102,7 +102,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManag AESCipher<Key128> cipher(sd_kek, Mode::ECB); for (size_t i = 0; i < 2; ++i) { - for (size_t j = 0; j < 0x20; ++j) + for (size_t j = 0; j < sd_key_sources[i].size(); ++j) sd_key_sources[i][j] ^= sd_seed[j & 0xF]; cipher.Transcode(sd_key_sources[i].data(), sd_key_sources[i].size(), sd_keys[i].data(), Op::Decrypt); diff --git a/src/core/crypto/xts_encryption_layer.cpp b/src/core/crypto/xts_encryption_layer.cpp index 431099580..c6e5df1ce 100644 --- a/src/core/crypto/xts_encryption_layer.cpp +++ b/src/core/crypto/xts_encryption_layer.cpp @@ -8,6 +8,8 @@ namespace Core::Crypto { +constexpr u64 XTS_SECTOR_SIZE = 0x4000; + XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_) : EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {} @@ -17,34 +19,35 @@ size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const { const auto sector_offset = offset & 0x3FFF; if (sector_offset == 0) { - if (length % 0x4000 == 0) { + if (length % XTS_SECTOR_SIZE == 0) { std::vector<u8> raw = base->ReadBytes(length, offset); - cipher.XTSTranscode(raw.data(), raw.size(), data, offset / 0x4000, 0x4000, Op::Decrypt); + cipher.XTSTranscode(raw.data(), raw.size(), data, offset / XTS_SECTOR_SIZE, + XTS_SECTOR_SIZE, Op::Decrypt); return raw.size(); } - if (length > 0x4000) { - const auto rem = length % 0x4000; + if (length > XTS_SECTOR_SIZE) { + const auto rem = length % XTS_SECTOR_SIZE; const auto read = length - rem; return Read(data, read, offset) + Read(data + read, rem, offset + read); } - std::vector<u8> buffer = base->ReadBytes(0x4000, offset); - if (buffer.size() < 0x4000) - buffer.resize(0x4000); - cipher.XTSTranscode(buffer.data(), buffer.size(), buffer.data(), offset / 0x4000, 0x4000, - Op::Decrypt); + std::vector<u8> buffer = base->ReadBytes(XTS_SECTOR_SIZE, offset); + if (buffer.size() < XTS_SECTOR_SIZE) + buffer.resize(XTS_SECTOR_SIZE); + cipher.XTSTranscode(buffer.data(), buffer.size(), buffer.data(), offset / XTS_SECTOR_SIZE, + XTS_SECTOR_SIZE, Op::Decrypt); std::memcpy(data, buffer.data(), std::min(buffer.size(), length)); return std::min(buffer.size(), length); } // offset does not fall on block boundary (0x4000) std::vector<u8> block = base->ReadBytes(0x4000, offset - sector_offset); - if (block.size() < 0x4000) - block.resize(0x4000); - cipher.XTSTranscode(block.data(), block.size(), block.data(), (offset - sector_offset) / 0x4000, - 0x4000, Op::Decrypt); - const size_t read = 0x4000 - sector_offset; + if (block.size() < XTS_SECTOR_SIZE) + block.resize(XTS_SECTOR_SIZE); + cipher.XTSTranscode(block.data(), block.size(), block.data(), + (offset - sector_offset) / XTS_SECTOR_SIZE, XTS_SECTOR_SIZE, Op::Decrypt); + const size_t read = XTS_SECTOR_SIZE - sector_offset; - if (length + sector_offset < 0x4000) { + if (length + sector_offset < XTS_SECTOR_SIZE) { std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); return std::min<u64>(length, read); } diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index 54be31916..605c1a283 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -19,6 +19,8 @@ namespace FileSys { +constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000; + template <typename SourceData, typename SourceKey, typename Destination> static bool CalculateHMAC256(Destination* out, const SourceKey* key, size_t key_length, const SourceData* data, size_t data_length) { @@ -67,14 +69,14 @@ NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id) Common::HexArrayToString(nca_id, false))); } -Loader::ResultStatus NAX::Parse(std::string path) { +Loader::ResultStatus NAX::Parse(std::string_view path) { if (file->ReadObject(header.get()) != sizeof(NAXHeader)) return Loader::ResultStatus::ErrorBadNAXHeader; if (header->magic != Common::MakeMagic('N', 'A', 'X', '0')) return Loader::ResultStatus::ErrorBadNAXHeader; - if (file->GetSize() < 0x4000 + header->file_size) + if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size) return Loader::ResultStatus::ErrorIncorrectNAXFileSize; keys.DeriveSDSeedLazy(); @@ -87,14 +89,14 @@ Loader::ResultStatus NAX::Parse(std::string path) { const auto enc_keys = header->key_area; size_t i = 0; - for (; i < 2; ++i) { + for (; i < sd_keys.size(); ++i) { std::array<Core::Crypto::Key128, 2> nax_keys{}; - if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, path.c_str(), + if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, std::string(path).c_str(), path.size())) { return Loader::ResultStatus::ErrorNAXKeyHMACFailed; } - for (size_t j = 0; j < 2; ++j) { + for (size_t j = 0; j < nax_keys.size(); ++j) { Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(nax_keys[j], Core::Crypto::Mode::ECB); cipher.Transcode(enc_keys[j].data(), 0x10, header->key_area[j].data(), @@ -117,28 +119,29 @@ Loader::ResultStatus NAX::Parse(std::string path) { type = static_cast<NAXContentType>(i); Core::Crypto::Key256 final_key{}; - memcpy(final_key.data(), &header->key_area, 0x20); - const auto enc_file = std::make_shared<OffsetVfsFile>(file, header->file_size, 0x4000); + std::memcpy(final_key.data(), &header->key_area, final_key.size()); + const auto enc_file = + std::make_shared<OffsetVfsFile>(file, header->file_size, NAX_HEADER_PADDING_SIZE); dec_file = std::make_shared<Core::Crypto::XTSEncryptionLayer>(enc_file, final_key); return Loader::ResultStatus::Success; } -Loader::ResultStatus NAX::GetStatus() { +Loader::ResultStatus NAX::GetStatus() const { return status; } -VirtualFile NAX::GetDecrypted() { +VirtualFile NAX::GetDecrypted() const { return dec_file; } -std::shared_ptr<NCA> NAX::AsNCA() { +std::shared_ptr<NCA> NAX::AsNCA() const { if (type == NAXContentType::NCA) return std::make_shared<NCA>(GetDecrypted()); return nullptr; } -NAXContentType NAX::GetContentType() { +NAXContentType NAX::GetContentType() const { return type; } diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h index 4e44f634a..5249ad026 100644 --- a/src/core/file_sys/xts_archive.h +++ b/src/core/file_sys/xts_archive.h @@ -33,13 +33,13 @@ public: explicit NAX(VirtualFile file); explicit NAX(VirtualFile file, std::array<u8, 0x10> nca_id); - Loader::ResultStatus GetStatus(); + Loader::ResultStatus GetStatus() const; - VirtualFile GetDecrypted(); + VirtualFile GetDecrypted() const; - std::shared_ptr<NCA> AsNCA(); + std::shared_ptr<NCA> AsNCA() const; - NAXContentType GetContentType(); + NAXContentType GetContentType() const; std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; @@ -53,7 +53,7 @@ protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; private: - Loader::ResultStatus Parse(std::string path); + Loader::ResultStatus Parse(std::string_view path); std::unique_ptr<NAXHeader> header; |