diff options
Diffstat (limited to 'src/core/crypto')
-rw-r--r-- | src/core/crypto/aes_util.cpp | 51 | ||||
-rw-r--r-- | src/core/crypto/aes_util.h | 14 | ||||
-rw-r--r-- | src/core/crypto/ctr_encryption_layer.cpp | 13 | ||||
-rw-r--r-- | src/core/crypto/ctr_encryption_layer.h | 8 | ||||
-rw-r--r-- | src/core/crypto/encryption_layer.cpp | 6 | ||||
-rw-r--r-- | src/core/crypto/encryption_layer.h | 8 | ||||
-rw-r--r-- | src/core/crypto/key_manager.cpp | 25 | ||||
-rw-r--r-- | src/core/crypto/key_manager.h | 13 | ||||
-rw-r--r-- | src/core/crypto/xts_encryption_layer.cpp | 4 | ||||
-rw-r--r-- | src/core/crypto/xts_encryption_layer.h | 2 |
10 files changed, 89 insertions, 55 deletions
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp index 72e4bed67..4be76bb43 100644 --- a/src/core/crypto/aes_util.cpp +++ b/src/core/crypto/aes_util.cpp @@ -10,9 +10,9 @@ namespace Core::Crypto { namespace { -std::vector<u8> CalculateNintendoTweak(size_t sector_id) { +std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) { std::vector<u8> out(0x10); - for (size_t i = 0xF; i <= 0xF; --i) { + for (std::size_t i = 0xF; i <= 0xF; --i) { out[i] = sector_id & 0xFF; sector_id >>= 8; } @@ -20,11 +20,14 @@ std::vector<u8> CalculateNintendoTweak(size_t sector_id) { } } // Anonymous namespace -static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), +static_assert(static_cast<std::size_t>(Mode::CTR) == + static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_CTR), "CTR has incorrect value."); -static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), +static_assert(static_cast<std::size_t>(Mode::ECB) == + static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_ECB), "ECB has incorrect value."); -static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), +static_assert(static_cast<std::size_t>(Mode::XTS) == + static_cast<std::size_t>(MBEDTLS_CIPHER_AES_128_XTS), "XTS has incorrect value."); // Structure to hide mbedtls types from header file @@ -33,7 +36,7 @@ struct CipherContext { mbedtls_cipher_context_t decryption_context; }; -template <typename Key, size_t KeySize> +template <typename Key, std::size_t KeySize> Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) : ctx(std::make_unique<CipherContext>()) { mbedtls_cipher_init(&ctx->encryption_context); @@ -54,26 +57,26 @@ Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) //"Failed to set key on mbedtls ciphers."); } -template <typename Key, size_t KeySize> +template <typename Key, std::size_t KeySize> AESCipher<Key, KeySize>::~AESCipher() { mbedtls_cipher_free(&ctx->encryption_context); mbedtls_cipher_free(&ctx->decryption_context); } -template <typename Key, size_t KeySize> +template <typename Key, std::size_t KeySize> void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) { ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) || mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0, "Failed to set IV on mbedtls ciphers."); } -template <typename Key, size_t KeySize> -void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) const { +template <typename Key, std::size_t KeySize> +void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const { auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context; mbedtls_cipher_reset(context); - size_t written = 0; + std::size_t written = 0; if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) { mbedtls_cipher_update(context, src, size, dest, &written); if (written != size) { @@ -82,11 +85,25 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op } } else { const auto block_size = mbedtls_cipher_get_block_size(context); + if (size < block_size) { + std::vector<u8> block(block_size); + std::memcpy(block.data(), src, size); + Transcode(block.data(), block.size(), block.data(), op); + std::memcpy(dest, block.data(), size); + return; + } - for (size_t offset = 0; offset < size; offset += block_size) { - auto length = std::min<size_t>(block_size, size - offset); + for (std::size_t offset = 0; offset < size; offset += block_size) { + auto length = std::min<std::size_t>(block_size, size - offset); mbedtls_cipher_update(context, src + offset, length, dest + offset, &written); if (written != length) { + if (length < block_size) { + std::vector<u8> block(block_size); + std::memcpy(block.data(), src + offset, length); + Transcode(block.data(), block.size(), block.data(), op); + std::memcpy(dest + offset, block.data(), length); + return; + } LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.", length, written); } @@ -96,12 +113,12 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op mbedtls_cipher_finish(context, nullptr, nullptr); } -template <typename Key, size_t KeySize> -void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, - size_t sector_size, Op op) { +template <typename Key, std::size_t KeySize> +void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8* dest, + std::size_t sector_id, std::size_t sector_size, Op op) { ASSERT_MSG(size % sector_size == 0, "XTS decryption size must be a multiple of sector size."); - for (size_t i = 0; i < size; i += sector_size) { + for (std::size_t i = 0; i < size; i += sector_size) { SetIV(CalculateNintendoTweak(sector_id++)); Transcode<u8, u8>(src + i, sector_size, dest + i, op); } diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h index 8ce9d6612..edc4ab910 100644 --- a/src/core/crypto/aes_util.h +++ b/src/core/crypto/aes_util.h @@ -25,7 +25,7 @@ enum class Op { Decrypt, }; -template <typename Key, size_t KeySize = sizeof(Key)> +template <typename Key, std::size_t KeySize = sizeof(Key)> class AESCipher { static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8."); static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256."); @@ -38,25 +38,25 @@ public: void SetIV(std::vector<u8> iv); template <typename Source, typename Dest> - void Transcode(const Source* src, size_t size, Dest* dest, Op op) const { + void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const { static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>, "Transcode source and destination types must be trivially copyable."); Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op); } - void Transcode(const u8* src, size_t size, u8* dest, Op op) const; + void Transcode(const u8* src, std::size_t size, u8* dest, Op op) const; template <typename Source, typename Dest> - void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id, - size_t sector_size, Op op) { + void XTSTranscode(const Source* src, std::size_t size, Dest* dest, std::size_t sector_id, + std::size_t sector_size, Op op) { static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>, "XTSTranscode source and destination types must be trivially copyable."); XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id, sector_size, op); } - void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, - Op op); + void XTSTranscode(const u8* src, std::size_t size, u8* dest, std::size_t sector_id, + std::size_t sector_size, Op op); private: std::unique_ptr<CipherContext> ctx; diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp index 3ea60dbd0..902841c77 100644 --- a/src/core/crypto/ctr_encryption_layer.cpp +++ b/src/core/crypto/ctr_encryption_layer.cpp @@ -8,11 +8,12 @@ namespace Core::Crypto { -CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) +CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, + std::size_t base_offset) : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), iv(16, 0) {} -size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { +std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const { if (length == 0) return 0; @@ -21,14 +22,14 @@ size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { UpdateIV(base_offset + offset); std::vector<u8> raw = base->ReadBytes(length, offset); cipher.Transcode(raw.data(), raw.size(), data, Op::Decrypt); - return raw.size(); + return length; } // offset does not fall on block boundary (0x10) std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset); UpdateIV(base_offset + offset - sector_offset); cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt); - size_t read = 0x10 - sector_offset; + std::size_t read = 0x10 - sector_offset; if (length + sector_offset < 0x10) { std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); @@ -43,9 +44,9 @@ void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) { iv.assign(iv_.cbegin(), iv_.cbegin() + length); } -void CTREncryptionLayer::UpdateIV(size_t offset) const { +void CTREncryptionLayer::UpdateIV(std::size_t offset) const { offset >>= 4; - for (size_t i = 0; i < 8; ++i) { + for (std::size_t i = 0; i < 8; ++i) { iv[16 - i - 1] = offset & 0xFF; offset >>= 8; } diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h index 11b8683c7..a7bf810f4 100644 --- a/src/core/crypto/ctr_encryption_layer.h +++ b/src/core/crypto/ctr_encryption_layer.h @@ -14,20 +14,20 @@ namespace Core::Crypto { // Sits on top of a VirtualFile and provides CTR-mode AES decription. class CTREncryptionLayer : public EncryptionLayer { public: - CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset); + CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset); - size_t Read(u8* data, size_t length, size_t offset) const override; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; void SetIV(const std::vector<u8>& iv); private: - size_t base_offset; + std::size_t base_offset; // Must be mutable as operations modify cipher contexts. mutable AESCipher<Key128> cipher; mutable std::vector<u8> iv; - void UpdateIV(size_t offset) const; + void UpdateIV(std::size_t offset) const; }; } // namespace Core::Crypto diff --git a/src/core/crypto/encryption_layer.cpp b/src/core/crypto/encryption_layer.cpp index 4204527e3..4c377d7d4 100644 --- a/src/core/crypto/encryption_layer.cpp +++ b/src/core/crypto/encryption_layer.cpp @@ -12,11 +12,11 @@ std::string EncryptionLayer::GetName() const { return base->GetName(); } -size_t EncryptionLayer::GetSize() const { +std::size_t EncryptionLayer::GetSize() const { return base->GetSize(); } -bool EncryptionLayer::Resize(size_t new_size) { +bool EncryptionLayer::Resize(std::size_t new_size) { return false; } @@ -32,7 +32,7 @@ bool EncryptionLayer::IsReadable() const { return true; } -size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) { +std::size_t EncryptionLayer::Write(const u8* data, std::size_t length, std::size_t offset) { return 0; } diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h index 7f05af9b4..53619cb38 100644 --- a/src/core/crypto/encryption_layer.h +++ b/src/core/crypto/encryption_layer.h @@ -15,15 +15,15 @@ class EncryptionLayer : public FileSys::VfsFile { public: explicit EncryptionLayer(FileSys::VirtualFile base); - size_t Read(u8* data, size_t length, size_t offset) const override = 0; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override = 0; std::string GetName() const override; - size_t GetSize() const override; - bool Resize(size_t new_size) override; + std::size_t GetSize() const override; + bool Resize(std::size_t new_size) override; std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override; bool IsWritable() const override; bool IsReadable() const override; - size_t Write(const u8* data, size_t length, size_t offset) override; + std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; bool Rename(std::string_view name) override; protected: diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 0b6c07de8..bf3a70944 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -8,12 +8,15 @@ #include <locale> #include <sstream> #include <string_view> +#include <tuple> +#include <vector> #include "common/common_paths.h" #include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" #include "core/crypto/aes_util.h" #include "core/crypto/key_manager.h" +#include "core/loader/loader.h" #include "core/settings.h" namespace Core::Crypto { @@ -51,7 +54,7 @@ boost::optional<Key128> DeriveSDSeed() { return boost::none; std::array<u8, 0x10> buffer{}; - size_t offset = 0; + std::size_t offset = 0; for (; offset + 0x10 < save_43.GetSize(); ++offset) { save_43.Seek(offset, SEEK_SET); save_43.ReadBytes(buffer.data(), buffer.size()); @@ -102,7 +105,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManag // Combine sources and seed for (auto& source : sd_key_sources) { - for (size_t i = 0; i < source.size(); ++i) + for (std::size_t i = 0; i < source.size(); ++i) source[i] ^= sd_seed[i & 0xF]; } @@ -204,7 +207,7 @@ Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const { return s256_keys.at({id, field1, field2}); } -template <size_t Size> +template <std::size_t Size> void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key) { const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); @@ -228,18 +231,28 @@ void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, } void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { - const auto iter = std::find_if( + if (s128_keys.find({id, field1, field2}) != s128_keys.end()) + return; + if (id == S128KeyType::Titlekey) { + Key128 rights_id; + std::memcpy(rights_id.data(), &field2, sizeof(u64)); + std::memcpy(rights_id.data() + sizeof(u64), &field1, sizeof(u64)); + WriteKeyToFile(true, Common::HexArrayToString(rights_id), key); + } + const auto iter2 = std::find_if( s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) { return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == std::tie(id, field1, field2); }); - if (iter != s128_file_id.end()) - WriteKeyToFile(id == S128KeyType::Titlekey, iter->first, key); + if (iter2 != s128_file_id.end()) + WriteKeyToFile(false, iter2->first, key); s128_keys[{id, field1, field2}] = key; } void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { + if (s256_keys.find({id, field1, field2}) != s256_keys.end()) + return; const auto iter = std::find_if( s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) { diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 7ca3e6cbc..978eec8dc 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -6,16 +6,19 @@ #include <array> #include <string> -#include <string_view> -#include <type_traits> -#include <vector> #include <boost/container/flat_map.hpp> +#include <boost/optional.hpp> #include <fmt/format.h> #include "common/common_types.h" -#include "core/loader/loader.h" + +namespace Loader { +enum class ResultStatus : u16; +} namespace Core::Crypto { +constexpr u64 TICKET_FILE_TITLEKEY_OFFSET = 0x180; + using Key128 = std::array<u8, 0x10>; using Key256 = std::array<u8, 0x20>; using SHA256Hash = std::array<u8, 0x20>; @@ -105,7 +108,7 @@ private: void LoadFromFile(const std::string& filename, bool is_title_keys); void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, const std::string& filename, bool title); - template <size_t Size> + template <std::size_t Size> void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key); static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id; diff --git a/src/core/crypto/xts_encryption_layer.cpp b/src/core/crypto/xts_encryption_layer.cpp index c10832cfe..8f0ba4ee7 100644 --- a/src/core/crypto/xts_encryption_layer.cpp +++ b/src/core/crypto/xts_encryption_layer.cpp @@ -14,7 +14,7 @@ constexpr u64 XTS_SECTOR_SIZE = 0x4000; XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_) : EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {} -size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const { +std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const { if (length == 0) return 0; @@ -46,7 +46,7 @@ size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const { 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; + const std::size_t read = XTS_SECTOR_SIZE - sector_offset; if (length + sector_offset < XTS_SECTOR_SIZE) { std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); diff --git a/src/core/crypto/xts_encryption_layer.h b/src/core/crypto/xts_encryption_layer.h index 7a1f1dc64..5f8f00fe7 100644 --- a/src/core/crypto/xts_encryption_layer.h +++ b/src/core/crypto/xts_encryption_layer.h @@ -15,7 +15,7 @@ class XTSEncryptionLayer : public EncryptionLayer { public: XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key); - size_t Read(u8* data, size_t length, size_t offset) const override; + std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; private: // Must be mutable as operations modify cipher contexts. |