diff options
| author | 2018-07-28 21:39:42 -0400 | |
|---|---|---|
| committer | 2018-08-01 00:16:54 -0400 | |
| commit | 239a3113e4c6a53a2c7b12e67a0f21afae24b0aa (patch) | |
| tree | 027bc4288f08be240d0b9b2a5f6c6431e76b8b4f | |
| parent | Extract mbedtls to cpp file (diff) | |
| download | yuzu-239a3113e4c6a53a2c7b12e67a0f21afae24b0aa.tar.gz yuzu-239a3113e4c6a53a2c7b12e67a0f21afae24b0aa.tar.xz yuzu-239a3113e4c6a53a2c7b12e67a0f21afae24b0aa.zip | |
Make XCI comply to review and style guidelines
Diffstat (limited to '')
| -rw-r--r-- | src/core/crypto/aes_util.cpp | 82 | ||||
| -rw-r--r-- | src/core/crypto/aes_util.h | 13 | ||||
| -rw-r--r-- | src/core/crypto/ctr_encryption_layer.cpp | 20 | ||||
| -rw-r--r-- | src/core/crypto/ctr_encryption_layer.h | 15 | ||||
| -rw-r--r-- | src/core/crypto/encryption_layer.cpp | 4 | ||||
| -rw-r--r-- | src/core/crypto/encryption_layer.h | 5 | ||||
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 376 | ||||
| -rw-r--r-- | src/core/crypto/key_manager.h | 77 | ||||
| -rw-r--r-- | src/core/file_sys/card_image.cpp | 15 | ||||
| -rw-r--r-- | src/core/file_sys/content_archive.cpp | 48 | ||||
| -rw-r--r-- | src/core/file_sys/content_archive.h | 5 | ||||
| -rw-r--r-- | src/core/file_sys/vfs.cpp | 7 | ||||
| -rw-r--r-- | src/core/loader/xci.cpp | 7 | ||||
| -rw-r--r-- | src/core/loader/xci.h | 3 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 15 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 13 |
16 files changed, 223 insertions, 482 deletions
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp index a9646e52f..4690af5f8 100644 --- a/src/core/crypto/aes_util.cpp +++ b/src/core/crypto/aes_util.cpp | |||
| @@ -2,58 +2,69 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <mbedtls/cipher.h> | ||
| 5 | #include "core/crypto/aes_util.h" | 6 | #include "core/crypto/aes_util.h" |
| 6 | #include "mbedtls/cipher.h" | 7 | #include "core/crypto/key_manager.h" |
| 7 | 8 | ||
| 8 | namespace Core::Crypto { | 9 | namespace Core::Crypto { |
| 9 | static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), "CTR mode is incorrect."); | ||
| 10 | static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), "ECB mode is incorrect."); | ||
| 11 | static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), "XTS mode is incorrect."); | ||
| 12 | 10 | ||
| 13 | template<typename Key, size_t KeySize> | 11 | static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), |
| 14 | Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) { | 12 | "CTR has incorrect value."); |
| 15 | mbedtls_cipher_init(encryption_context.get()); | 13 | static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), |
| 16 | mbedtls_cipher_init(decryption_context.get()); | 14 | "ECB has incorrect value."); |
| 15 | static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), | ||
| 16 | "XTS has incorrect value."); | ||
| 17 | |||
| 18 | // Structure to hide mbedtls types from header file | ||
| 19 | struct CipherContext { | ||
| 20 | mbedtls_cipher_context_t encryption_context; | ||
| 21 | mbedtls_cipher_context_t decryption_context; | ||
| 22 | }; | ||
| 23 | |||
| 24 | template <typename Key, size_t KeySize> | ||
| 25 | Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) | ||
| 26 | : ctx(std::make_unique<CipherContext>()) { | ||
| 27 | mbedtls_cipher_init(&ctx->encryption_context); | ||
| 28 | mbedtls_cipher_init(&ctx->decryption_context); | ||
| 17 | 29 | ||
| 18 | ASSERT_MSG((mbedtls_cipher_setup( | 30 | ASSERT_MSG((mbedtls_cipher_setup( |
| 19 | encryption_context.get(), | 31 | &ctx->encryption_context, |
| 20 | mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) || | 32 | mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) || |
| 21 | mbedtls_cipher_setup(decryption_context.get(), | 33 | mbedtls_cipher_setup( |
| 22 | mbedtls_cipher_info_from_type( | 34 | &ctx->decryption_context, |
| 23 | static_cast<mbedtls_cipher_type_t>(mode)))) == 0, | 35 | mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode)))) == 0, |
| 24 | "Failed to initialize mbedtls ciphers."); | 36 | "Failed to initialize mbedtls ciphers."); |
| 25 | 37 | ||
| 26 | ASSERT( | 38 | ASSERT( |
| 27 | !mbedtls_cipher_setkey(encryption_context.get(), key.data(), KeySize * 8, MBEDTLS_ENCRYPT)); | 39 | !mbedtls_cipher_setkey(&ctx->encryption_context, key.data(), KeySize * 8, MBEDTLS_ENCRYPT)); |
| 28 | ASSERT( | 40 | ASSERT( |
| 29 | !mbedtls_cipher_setkey(decryption_context.get(), key.data(), KeySize * 8, MBEDTLS_DECRYPT)); | 41 | !mbedtls_cipher_setkey(&ctx->decryption_context, key.data(), KeySize * 8, MBEDTLS_DECRYPT)); |
| 30 | //"Failed to set key on mbedtls ciphers."); | 42 | //"Failed to set key on mbedtls ciphers."); |
| 31 | } | 43 | } |
| 32 | 44 | ||
| 33 | template<typename Key, size_t KeySize> | 45 | template <typename Key, size_t KeySize> |
| 34 | AESCipher<Key, KeySize>::~AESCipher() { | 46 | AESCipher<Key, KeySize>::~AESCipher() { |
| 35 | mbedtls_cipher_free(encryption_context.get()); | 47 | mbedtls_cipher_free(&ctx->encryption_context); |
| 36 | mbedtls_cipher_free(decryption_context.get()); | 48 | mbedtls_cipher_free(&ctx->decryption_context); |
| 37 | } | 49 | } |
| 38 | 50 | ||
| 39 | template<typename Key, size_t KeySize> | 51 | template <typename Key, size_t KeySize> |
| 40 | void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) { | 52 | void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) { |
| 41 | ASSERT_MSG((mbedtls_cipher_set_iv(encryption_context.get(), iv.data(), iv.size()) || | 53 | ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) || |
| 42 | mbedtls_cipher_set_iv(decryption_context.get(), iv.data(), iv.size())) == 0, | 54 | mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0, |
| 43 | "Failed to set IV on mbedtls ciphers."); | 55 | "Failed to set IV on mbedtls ciphers."); |
| 44 | } | 56 | } |
| 45 | 57 | ||
| 46 | template<typename Key, size_t KeySize> | 58 | template <typename Key, size_t KeySize> |
| 47 | void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) { | 59 | void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) { |
| 48 | size_t written = 0; | 60 | size_t written = 0; |
| 49 | 61 | ||
| 50 | const auto context = op == Op::Encrypt ? encryption_context.get() : decryption_context.get(); | 62 | const auto context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context; |
| 51 | 63 | ||
| 52 | mbedtls_cipher_reset(context); | 64 | mbedtls_cipher_reset(context); |
| 53 | 65 | ||
| 54 | if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) { | 66 | if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) { |
| 55 | mbedtls_cipher_update(context, src, size, | 67 | mbedtls_cipher_update(context, src, size, dest, &written); |
| 56 | dest, &written); | ||
| 57 | if (written != size) | 68 | if (written != size) |
| 58 | LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.", | 69 | LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.", |
| 59 | size, written); | 70 | size, written); |
| @@ -62,11 +73,9 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op | |||
| 62 | 73 | ||
| 63 | for (size_t offset = 0; offset < size; offset += block_size) { | 74 | for (size_t offset = 0; offset < size; offset += block_size) { |
| 64 | auto length = std::min<size_t>(block_size, size - offset); | 75 | auto length = std::min<size_t>(block_size, size - offset); |
| 65 | mbedtls_cipher_update(context, src + offset, length, | 76 | mbedtls_cipher_update(context, src + offset, length, dest + offset, &written); |
| 66 | dest + offset, &written); | ||
| 67 | if (written != length) | 77 | if (written != length) |
| 68 | LOG_WARNING(Crypto, | 78 | LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.", |
| 69 | "Not all data was decrypted requested={:016X}, actual={:016X}.", | ||
| 70 | length, written); | 79 | length, written); |
| 71 | } | 80 | } |
| 72 | } | 81 | } |
| @@ -74,9 +83,9 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op | |||
| 74 | mbedtls_cipher_finish(context, nullptr, nullptr); | 83 | mbedtls_cipher_finish(context, nullptr, nullptr); |
| 75 | } | 84 | } |
| 76 | 85 | ||
| 77 | template<typename Key, size_t KeySize> | 86 | template <typename Key, size_t KeySize> |
| 78 | void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, | 87 | void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, |
| 79 | Op op) { | 88 | size_t sector_size, Op op) { |
| 80 | if (size % sector_size > 0) { | 89 | if (size % sector_size > 0) { |
| 81 | LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size."); | 90 | LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size."); |
| 82 | return; | 91 | return; |
| @@ -84,12 +93,11 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, | |||
| 84 | 93 | ||
| 85 | for (size_t i = 0; i < size; i += sector_size) { | 94 | for (size_t i = 0; i < size; i += sector_size) { |
| 86 | SetIV(CalculateNintendoTweak(sector_id++)); | 95 | SetIV(CalculateNintendoTweak(sector_id++)); |
| 87 | Transcode<u8, u8>(src + i, sector_size, | 96 | Transcode<u8, u8>(src + i, sector_size, dest + i, op); |
| 88 | dest + i, op); | ||
| 89 | } | 97 | } |
| 90 | } | 98 | } |
| 91 | 99 | ||
| 92 | template<typename Key, size_t KeySize> | 100 | template <typename Key, size_t KeySize> |
| 93 | std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id) { | 101 | std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id) { |
| 94 | std::vector<u8> out(0x10); | 102 | std::vector<u8> out(0x10); |
| 95 | for (size_t i = 0xF; i <= 0xF; --i) { | 103 | for (size_t i = 0xF; i <= 0xF; --i) { |
| @@ -101,4 +109,4 @@ std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id | |||
| 101 | 109 | ||
| 102 | template class AESCipher<Key128>; | 110 | template class AESCipher<Key128>; |
| 103 | template class AESCipher<Key256>; | 111 | template class AESCipher<Key256>; |
| 104 | } \ No newline at end of file | 112 | } // namespace Core::Crypto \ No newline at end of file |
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h index 5c09718b2..fa77d5560 100644 --- a/src/core/crypto/aes_util.h +++ b/src/core/crypto/aes_util.h | |||
| @@ -20,7 +20,7 @@ enum class Op { | |||
| 20 | Decrypt, | 20 | Decrypt, |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | struct mbedtls_cipher_context_t; | 23 | struct CipherContext; |
| 24 | 24 | ||
| 25 | template <typename Key, size_t KeySize = sizeof(Key)> | 25 | template <typename Key, size_t KeySize = sizeof(Key)> |
| 26 | class AESCipher { | 26 | class AESCipher { |
| @@ -44,15 +44,16 @@ public: | |||
| 44 | template <typename Source, typename Dest> | 44 | template <typename Source, typename Dest> |
| 45 | void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id, | 45 | void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id, |
| 46 | size_t sector_size, Op op) { | 46 | size_t sector_size, Op op) { |
| 47 | XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id, sector_size, op); | 47 | XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id, |
| 48 | sector_size, op); | ||
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, Op op); | 51 | void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, |
| 52 | Op op); | ||
| 51 | 53 | ||
| 52 | private: | 54 | private: |
| 53 | std::unique_ptr<mbedtls_cipher_context_t> encryption_context; | 55 | std::unique_ptr<CipherContext> ctx; |
| 54 | std::unique_ptr<mbedtls_cipher_context_t> decryption_context; | ||
| 55 | 56 | ||
| 56 | static std::vector<u8> CalculateNintendoTweak(size_t sector_id); | 57 | static std::vector<u8> CalculateNintendoTweak(size_t sector_id); |
| 57 | }; | 58 | }; |
| 58 | } // namespace Crypto | 59 | } // namespace Core::Crypto |
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp index 6a0d396ed..5dbc257e5 100644 --- a/src/core/crypto/ctr_encryption_layer.cpp +++ b/src/core/crypto/ctr_encryption_layer.cpp | |||
| @@ -6,7 +6,8 @@ | |||
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/crypto/ctr_encryption_layer.h" | 7 | #include "core/crypto/ctr_encryption_layer.h" |
| 8 | 8 | ||
| 9 | namespace Crypto { | 9 | namespace Core::Crypto { |
| 10 | |||
| 10 | CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) | 11 | CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) |
| 11 | : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), | 12 | : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), |
| 12 | iv(16, 0) {} | 13 | iv(16, 0) {} |
| @@ -21,29 +22,28 @@ size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { | |||
| 21 | std::vector<u8> raw = base->ReadBytes(length, offset); | 22 | std::vector<u8> raw = base->ReadBytes(length, offset); |
| 22 | if (raw.size() != length) | 23 | if (raw.size() != length) |
| 23 | return Read(data, raw.size(), offset); | 24 | return Read(data, raw.size(), offset); |
| 24 | cipher.Transcode(raw.data(), length, data, Op::DECRYPT); | 25 | cipher.Transcode(raw.data(), length, data, Op::Decrypt); |
| 25 | return length; | 26 | return length; |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | // offset does not fall on block boundary (0x10) | 29 | // offset does not fall on block boundary (0x10) |
| 29 | std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset); | 30 | std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset); |
| 30 | UpdateIV(base_offset + offset - sector_offset); | 31 | UpdateIV(base_offset + offset - sector_offset); |
| 31 | cipher.Transcode(block.data(), block.size(), block.data(), Op::DECRYPT); | 32 | cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt); |
| 32 | size_t read = 0x10 - sector_offset; | 33 | size_t read = 0x10 - sector_offset; |
| 33 | 34 | ||
| 34 | if (length + sector_offset < 0x10) { | 35 | if (length + sector_offset < 0x10) { |
| 35 | memcpy_s(data, length, block.data() + sector_offset, std::min<u64>(length, read)); | 36 | memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); |
| 36 | return read; | 37 | return read; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | memcpy_s(data, length, block.data() + sector_offset, read); | 40 | memcpy(data, block.data() + sector_offset, read); |
| 40 | return read + Read(data + read, length - read, offset + read); | 41 | return read + Read(data + read, length - read, offset + read); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | void CTREncryptionLayer::SetIV(std::vector<u8> iv_) { | 44 | void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) { |
| 44 | const auto length = std::min<size_t>(iv_.size(), iv.size()); | 45 | const auto length = std::min(iv_.size(), iv.size()); |
| 45 | for (size_t i = 0; i < length; ++i) | 46 | iv.assign(iv_.cbegin(), iv_.cbegin() + length); |
| 46 | iv[i] = iv_[i]; | ||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | void CTREncryptionLayer::UpdateIV(size_t offset) const { | 49 | void CTREncryptionLayer::UpdateIV(size_t offset) const { |
| @@ -54,4 +54,4 @@ void CTREncryptionLayer::UpdateIV(size_t offset) const { | |||
| 54 | } | 54 | } |
| 55 | cipher.SetIV(iv); | 55 | cipher.SetIV(iv); |
| 56 | } | 56 | } |
| 57 | } // namespace Crypto | 57 | } // namespace Core::Crypto |
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h index fe53e714b..697d7c6a5 100644 --- a/src/core/crypto/ctr_encryption_layer.h +++ b/src/core/crypto/ctr_encryption_layer.h | |||
| @@ -4,19 +4,20 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "aes_util.h" | 7 | #include "core/crypto/aes_util.h" |
| 8 | #include "encryption_layer.h" | 8 | #include "core/crypto/encryption_layer.h" |
| 9 | #include "key_manager.h" | 9 | #include "core/crypto/key_manager.h" |
| 10 | 10 | ||
| 11 | namespace Crypto { | 11 | namespace Core::Crypto { |
| 12 | 12 | ||
| 13 | // Sits on top of a VirtualFile and provides CTR-mode AES decription. | 13 | // Sits on top of a VirtualFile and provides CTR-mode AES decription. |
| 14 | struct CTREncryptionLayer : public EncryptionLayer { | 14 | class CTREncryptionLayer : public EncryptionLayer { |
| 15 | public: | ||
| 15 | CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset); | 16 | CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset); |
| 16 | 17 | ||
| 17 | size_t Read(u8* data, size_t length, size_t offset) const override; | 18 | size_t Read(u8* data, size_t length, size_t offset) const override; |
| 18 | 19 | ||
| 19 | void SetIV(std::vector<u8> iv); | 20 | void SetIV(const std::vector<u8>& iv); |
| 20 | 21 | ||
| 21 | private: | 22 | private: |
| 22 | size_t base_offset; | 23 | size_t base_offset; |
| @@ -28,4 +29,4 @@ private: | |||
| 28 | void UpdateIV(size_t offset) const; | 29 | void UpdateIV(size_t offset) const; |
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | } // namespace Crypto | 32 | } // namespace Core::Crypto |
diff --git a/src/core/crypto/encryption_layer.cpp b/src/core/crypto/encryption_layer.cpp index 4e243051e..4204527e3 100644 --- a/src/core/crypto/encryption_layer.cpp +++ b/src/core/crypto/encryption_layer.cpp | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "core/crypto/encryption_layer.h" | 5 | #include "core/crypto/encryption_layer.h" |
| 6 | 6 | ||
| 7 | namespace Crypto { | 7 | namespace Core::Crypto { |
| 8 | 8 | ||
| 9 | EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {} | 9 | EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {} |
| 10 | 10 | ||
| @@ -39,4 +39,4 @@ size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) { | |||
| 39 | bool EncryptionLayer::Rename(std::string_view name) { | 39 | bool EncryptionLayer::Rename(std::string_view name) { |
| 40 | return base->Rename(name); | 40 | return base->Rename(name); |
| 41 | } | 41 | } |
| 42 | } // namespace Crypto | 42 | } // namespace Core::Crypto |
diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h index 2312870d8..84f11bf5e 100644 --- a/src/core/crypto/encryption_layer.h +++ b/src/core/crypto/encryption_layer.h | |||
| @@ -3,9 +3,10 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | |||
| 6 | #include "core/file_sys/vfs.h" | 7 | #include "core/file_sys/vfs.h" |
| 7 | 8 | ||
| 8 | namespace Crypto { | 9 | namespace Core::Crypto { |
| 9 | 10 | ||
| 10 | // Basically non-functional class that implements all of the methods that are irrelevant to an | 11 | // Basically non-functional class that implements all of the methods that are irrelevant to an |
| 11 | // EncryptionLayer. Reduces duplicate code. | 12 | // EncryptionLayer. Reduces duplicate code. |
| @@ -27,4 +28,4 @@ protected: | |||
| 27 | FileSys::VirtualFile base; | 28 | FileSys::VirtualFile base; |
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 30 | } // namespace Crypto | 31 | } // namespace Core::Crypto |
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 05c6a70a2..ea20bc31b 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -5,238 +5,15 @@ | |||
| 5 | #include <fstream> | 5 | #include <fstream> |
| 6 | #include <locale> | 6 | #include <locale> |
| 7 | #include <sstream> | 7 | #include <sstream> |
| 8 | #include <mbedtls/sha256.h> | ||
| 8 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 10 | #include "common/common_paths.h" | ||
| 11 | #include "common/file_util.h" | ||
| 9 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 10 | #include "core/crypto/key_manager.h" | 13 | #include "core/crypto/key_manager.h" |
| 11 | #include "mbedtls/sha256.h" | 14 | #include "core/settings.h" |
| 12 | 15 | ||
| 13 | namespace Crypto { | 16 | namespace Core::Crypto { |
| 14 | KeyManager keys = {}; | ||
| 15 | |||
| 16 | std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> KeyManager::s128_hash_prod = { | ||
| 17 | {{S128KeyType::MASTER, 0, 0}, | ||
| 18 | "0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32}, | ||
| 19 | {{S128KeyType::MASTER, 1, 0}, | ||
| 20 | "4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32}, | ||
| 21 | {{S128KeyType::MASTER, 2, 0}, | ||
| 22 | "79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32}, | ||
| 23 | {{S128KeyType::MASTER, 3, 0}, | ||
| 24 | "4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32}, | ||
| 25 | {{S128KeyType::MASTER, 4, 0}, | ||
| 26 | "75ff1d95d26113550ee6fcc20acb58e97edeb3a2ff52543ed5aec63bdcc3da50"_array32}, | ||
| 27 | {{S128KeyType::PACKAGE1, 0, 0}, | ||
| 28 | "4543CD1B7CAD7EE0466A3DE2086A0EF923805DCEA6C741541CDDB14F54F97B40"_array32}, | ||
| 29 | {{S128KeyType::PACKAGE1, 1, 0}, | ||
| 30 | "4A11DA019D26470C9B805F1721364830DC0096DD66EAC453B0D14455E5AF5CF8"_array32}, | ||
| 31 | {{S128KeyType::PACKAGE1, 2, 0}, | ||
| 32 | "CCA867360B3318246FBF0B8A86473176ED486DFE229772B941A02E84D50A3155"_array32}, | ||
| 33 | {{S128KeyType::PACKAGE1, 3, 0}, | ||
| 34 | "E65C383CDF526DFFAA77682868EBFA9535EE60D8075C961BBC1EDE5FBF7E3C5F"_array32}, | ||
| 35 | {{S128KeyType::PACKAGE1, 4, 0}, | ||
| 36 | "28ae73d6ae8f7206fca549e27097714e599df1208e57099416ff429b71370162"_array32}, | ||
| 37 | {{S128KeyType::PACKAGE2, 0, 0}, | ||
| 38 | "94D6F38B9D0456644E21DFF4707D092B70179B82D1AA2F5B6A76B8F9ED948264"_array32}, | ||
| 39 | {{S128KeyType::PACKAGE2, 1, 0}, | ||
| 40 | "7794F24FA879D378FEFDC8776B949B88AD89386410BE9025D463C619F1530509"_array32}, | ||
| 41 | {{S128KeyType::PACKAGE2, 2, 0}, | ||
| 42 | "5304BDDE6AC8E462961B5DB6E328B1816D245D36D6574BB78938B74D4418AF35"_array32}, | ||
| 43 | {{S128KeyType::PACKAGE2, 3, 0}, | ||
| 44 | "BE1E52C4345A979DDD4924375B91C902052C2E1CF8FBF2FAA42E8F26D5125B60"_array32}, | ||
| 45 | {{S128KeyType::PACKAGE2, 4, 0}, | ||
| 46 | "631b45d349ab8f76a050fe59512966fb8dbaf0755ef5b6903048bf036cfa611e"_array32}, | ||
| 47 | {{S128KeyType::TITLEKEK, 0, 0}, | ||
| 48 | "C2FA30CAC6AE1680466CB54750C24550E8652B3B6F38C30B49DADF067B5935E9"_array32}, | ||
| 49 | {{S128KeyType::TITLEKEK, 1, 0}, | ||
| 50 | "0D6B8F3746AD910D36438A859C11E8BE4310112425D63751D09B5043B87DE598"_array32}, | ||
| 51 | {{S128KeyType::TITLEKEK, 2, 0}, | ||
| 52 | "D09E18D3DB6BC7393536896F728528736FBEFCDD15C09D9D612FDE5C7BDCD821"_array32}, | ||
| 53 | {{S128KeyType::TITLEKEK, 3, 0}, | ||
| 54 | "47C6F9F7E99BB1F56DCDC93CDBD340EA82DCCD74DD8F3535ADA20ECF79D438ED"_array32}, | ||
| 55 | {{S128KeyType::TITLEKEK, 4, 0}, | ||
| 56 | "128610de8424cb29e08f9ee9a81c9e6ffd3c6662854aad0c8f937e0bcedc4d88"_array32}, | ||
| 57 | {{S128KeyType::ETICKET_RSA_KEK, 0, 0}, | ||
| 58 | "46cccf288286e31c931379de9efa288c95c9a15e40b00a4c563a8be244ece515"_array32}, | ||
| 59 | {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 60 | "592957F44FE5DB5EC6B095F568910E31A226D3B7FE42D64CFB9CE4051E90AEB6"_array32}, | ||
| 61 | {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 62 | "C2252A0FBF9D339ABC3D681351D00452F926E7CA0C6CA85F659078DE3FA647F3"_array32}, | ||
| 63 | {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 64 | "7C7722824B2F7C4938C40F3EA93E16CB69D3285EB133490EF8ECCD2C4B52DF41"_array32}, | ||
| 65 | {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 66 | "AFBB8EBFB2094F1CF71E330826AE06D64414FCA128C464618DF30EED92E62BE6"_array32}, | ||
| 67 | {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 68 | "5dc10eb81918da3f2fa90f69c8542511963656cfb31fb7c779581df8faf1f2f5"_array32}, | ||
| 69 | {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 70 | "AA2C65F0E27F730807A13F2ED5B99BE5183165B87C50B6ED48F5CAC2840687EB"_array32}, | ||
| 71 | {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 72 | "860185F2313A14F7006A029CB21A52750E7718C1E94FFB98C0AE2207D1A60165"_array32}, | ||
| 73 | {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 74 | "7283FB1EFBD42438DADF363FDB776ED355C98737A2AAE75D0E9283CE1C12A2E4"_array32}, | ||
| 75 | {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 76 | "9881C2D3AB70B14C8AA12016FC73ADAD93C6AD9FB59A9ECAD312B6F89E2413EC"_array32}, | ||
| 77 | {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 78 | "eaa6a8d242b89e174928fa9549a0f66ec1562e2576fac896f438a2b3c1fb6005"_array32}, | ||
| 79 | {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 80 | "194CF6BD14554DA8D457E14CBFE04E55C8FB8CA52E0AFB3D7CB7084AE435B801"_array32}, | ||
| 81 | {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 82 | "CE1DB7BB6E5962384889DB7A396AFD614F82F69DC38A33D2DEAF47F3E4B964B7"_array32}, | ||
| 83 | {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 84 | "42238DE5685DEF4FDE7BE42C0097CEB92447006386D6B5D5AAA2C9AFD2E28422"_array32}, | ||
| 85 | {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 86 | "1F6847F268E9D9C5D1AD4D7E226A63B833BF02071446957A962EF065521879C1"_array32}, | ||
| 87 | {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 88 | "644007f9913c3602399d4d75cc34faeb7f1faad18b23e34187b16fdc45f4980f"_array32}, | ||
| 89 | }; | ||
| 90 | |||
| 91 | std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> KeyManager::s256_hash_prod = { | ||
| 92 | {{S256KeyType::HEADER, 0, 0}, | ||
| 93 | "8E03DE24818D96CE4F2A09B43AF979E679974F7570713A61EED8B314864A11D5"_array32}, | ||
| 94 | {{S256KeyType::SD_SAVE, 0, 0}, | ||
| 95 | "13020ee72d0f8b8f9112dc738b829fdb017102499a7c2259b52aeefc0a273f5c"_array32}, | ||
| 96 | {{S256KeyType::SD_NCA, 0, 0}, | ||
| 97 | "8a1c05b4f88bae5b04d77f632e6acfc8893c4a05fd701f53585daafc996b532a"_array32}, | ||
| 98 | }; | ||
| 99 | |||
| 100 | // TODO(DarkLordZach): Find missing hashes for dev keys. | ||
| 101 | |||
| 102 | std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> KeyManager::s128_hash_dev = { | ||
| 103 | {{S128KeyType::MASTER, 0, 0}, | ||
| 104 | "779dd8b533a2fb670f27b308cb8d0151c4a107568b817429172b7f80aa592c25"_array32}, | ||
| 105 | {{S128KeyType::MASTER, 1, 0}, | ||
| 106 | "0175c8bc49771576f75527be719098db4ebaf77707206749415663aa3a9ea9cc"_array32}, | ||
| 107 | {{S128KeyType::MASTER, 2, 0}, | ||
| 108 | "4f0b4d724e5a8787268157c7ce0767c26d2e2021832aa7020f306d6e260eea42"_array32}, | ||
| 109 | {{S128KeyType::MASTER, 3, 0}, | ||
| 110 | "7b5a29586c1f84f66fbfabb94518fc45408bb8e5445253d063dda7cfef2a818c"_array32}, | ||
| 111 | {{S128KeyType::MASTER, 4, 0}, | ||
| 112 | "87a61dbb05a8755de7fe069562aab38ebfb266c9eb835f09fa62dacc89c98341"_array32}, | ||
| 113 | {{S128KeyType::PACKAGE1, 0, 0}, | ||
| 114 | "166510bc63ae50391ebe4ee4ff90ca31cd0e2dd0ff6be839a2f573ec146cc23a"_array32}, | ||
| 115 | {{S128KeyType::PACKAGE1, 1, 0}, | ||
| 116 | "f74cd01b86743139c920ec54a8116c669eea805a0be1583e13fc5bc8de68645b"_array32}, | ||
| 117 | {{S128KeyType::PACKAGE1, 2, 0}, | ||
| 118 | "d0cdecd513bb6aa3d9dc6244c977dc8a5a7ea157d0a8747d79e7581146e1f768"_array32}, | ||
| 119 | {{S128KeyType::PACKAGE1, 3, 0}, | ||
| 120 | "aa39394d626b3b79f5b7ccc07378b5996b6d09bf0eb6771b0b40c9077fbfde8c"_array32}, | ||
| 121 | {{S128KeyType::PACKAGE1, 4, 0}, | ||
| 122 | "8f4754b8988c0e673fc2bbea0534cdd6075c815c9270754ae980aef3e4f0a508"_array32}, | ||
| 123 | {{S128KeyType::PACKAGE2, 0, 0}, | ||
| 124 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 125 | {{S128KeyType::PACKAGE2, 1, 0}, | ||
| 126 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 127 | {{S128KeyType::PACKAGE2, 2, 0}, | ||
| 128 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 129 | {{S128KeyType::PACKAGE2, 3, 0}, | ||
| 130 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 131 | {{S128KeyType::PACKAGE2, 4, 0}, | ||
| 132 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 133 | {{S128KeyType::TITLEKEK, 0, 0}, | ||
| 134 | "C2FA30CAC6AE1680466CB54750C24550E8652B3B6F38C30B49DADF067B5935E9"_array32}, | ||
| 135 | {{S128KeyType::TITLEKEK, 1, 0}, | ||
| 136 | "0D6B8F3746AD910D36438A859C11E8BE4310112425D63751D09B5043B87DE598"_array32}, | ||
| 137 | {{S128KeyType::TITLEKEK, 2, 0}, | ||
| 138 | "D09E18D3DB6BC7393536896F728528736FBEFCDD15C09D9D612FDE5C7BDCD821"_array32}, | ||
| 139 | {{S128KeyType::TITLEKEK, 3, 0}, | ||
| 140 | "47C6F9F7E99BB1F56DCDC93CDBD340EA82DCCD74DD8F3535ADA20ECF79D438ED"_array32}, | ||
| 141 | {{S128KeyType::TITLEKEK, 4, 0}, | ||
| 142 | "128610de8424cb29e08f9ee9a81c9e6ffd3c6662854aad0c8f937e0bcedc4d88"_array32}, | ||
| 143 | {{S128KeyType::ETICKET_RSA_KEK, 0, 0}, | ||
| 144 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 145 | {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 146 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 147 | {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 148 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 149 | {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 150 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 151 | {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 152 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 153 | {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Application)}, | ||
| 154 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 155 | {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 156 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 157 | {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 158 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 159 | {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 160 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 161 | {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 162 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 163 | {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}, | ||
| 164 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 165 | {{S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 166 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 167 | {{S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 168 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 169 | {{S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 170 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 171 | {{S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 172 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 173 | {{S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::System)}, | ||
| 174 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 175 | }; | ||
| 176 | |||
| 177 | std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> KeyManager::s256_hash_dev = { | ||
| 178 | {{S256KeyType::HEADER, 0, 0}, | ||
| 179 | "ecde86a76e37ac4fd7591d3aa55c00cc77d8595fc27968052ec18a177d939060"_array32}, | ||
| 180 | {{S256KeyType::SD_SAVE, 0, 0}, | ||
| 181 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 182 | {{S256KeyType::SD_NCA, 0, 0}, | ||
| 183 | "0000000000000000000000000000000000000000000000000000000000000000"_array32}, | ||
| 184 | }; | ||
| 185 | |||
| 186 | std::unordered_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { | ||
| 187 | {"master_key_00", {S128KeyType::MASTER, 0, 0}}, | ||
| 188 | {"master_key_01", {S128KeyType::MASTER, 1, 0}}, | ||
| 189 | {"master_key_02", {S128KeyType::MASTER, 2, 0}}, | ||
| 190 | {"master_key_03", {S128KeyType::MASTER, 3, 0}}, | ||
| 191 | {"master_key_04", {S128KeyType::MASTER, 4, 0}}, | ||
| 192 | {"package1_key_00", {S128KeyType::PACKAGE1, 0, 0}}, | ||
| 193 | {"package1_key_01", {S128KeyType::PACKAGE1, 1, 0}}, | ||
| 194 | {"package1_key_02", {S128KeyType::PACKAGE1, 2, 0}}, | ||
| 195 | {"package1_key_03", {S128KeyType::PACKAGE1, 3, 0}}, | ||
| 196 | {"package1_key_04", {S128KeyType::PACKAGE1, 4, 0}}, | ||
| 197 | {"package2_key_00", {S128KeyType::PACKAGE2, 0, 0}}, | ||
| 198 | {"package2_key_01", {S128KeyType::PACKAGE2, 1, 0}}, | ||
| 199 | {"package2_key_02", {S128KeyType::PACKAGE2, 2, 0}}, | ||
| 200 | {"package2_key_03", {S128KeyType::PACKAGE2, 3, 0}}, | ||
| 201 | {"package2_key_04", {S128KeyType::PACKAGE2, 4, 0}}, | ||
| 202 | {"titlekek_00", {S128KeyType::TITLEKEK, 0, 0}}, | ||
| 203 | {"titlekek_01", {S128KeyType::TITLEKEK, 1, 0}}, | ||
| 204 | {"titlekek_02", {S128KeyType::TITLEKEK, 2, 0}}, | ||
| 205 | {"titlekek_03", {S128KeyType::TITLEKEK, 3, 0}}, | ||
| 206 | {"titlekek_04", {S128KeyType::TITLEKEK, 4, 0}}, | ||
| 207 | {"eticket_rsa_kek", {S128KeyType::ETICKET_RSA_KEK, 0, 0}}, | ||
| 208 | {"key_area_key_application_00", | ||
| 209 | {S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Application)}}, | ||
| 210 | {"key_area_key_application_01", | ||
| 211 | {S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Application)}}, | ||
| 212 | {"key_area_key_application_02", | ||
| 213 | {S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Application)}}, | ||
| 214 | {"key_area_key_application_03", | ||
| 215 | {S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Application)}}, | ||
| 216 | {"key_area_key_application_04", | ||
| 217 | {S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Application)}}, | ||
| 218 | {"key_area_key_ocean_00", {S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}}, | ||
| 219 | {"key_area_key_ocean_01", {S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}}, | ||
| 220 | {"key_area_key_ocean_02", {S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}}, | ||
| 221 | {"key_area_key_ocean_03", {S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}}, | ||
| 222 | {"key_area_key_ocean_04", {S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}}, | ||
| 223 | {"key_area_key_system_00", | ||
| 224 | {S128KeyType::KEY_AREA, 0, static_cast<u64>(KeyAreaKeyType::System)}}, | ||
| 225 | {"key_area_key_system_01", | ||
| 226 | {S128KeyType::KEY_AREA, 1, static_cast<u64>(KeyAreaKeyType::System)}}, | ||
| 227 | {"key_area_key_system_02", | ||
| 228 | {S128KeyType::KEY_AREA, 2, static_cast<u64>(KeyAreaKeyType::System)}}, | ||
| 229 | {"key_area_key_system_03", | ||
| 230 | {S128KeyType::KEY_AREA, 3, static_cast<u64>(KeyAreaKeyType::System)}}, | ||
| 231 | {"key_area_key_system_04", | ||
| 232 | {S128KeyType::KEY_AREA, 4, static_cast<u64>(KeyAreaKeyType::System)}}, | ||
| 233 | }; | ||
| 234 | |||
| 235 | std::unordered_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = { | ||
| 236 | {"header_key", {S256KeyType::HEADER, 0, 0}}, | ||
| 237 | {"sd_card_save_key", {S256KeyType::SD_SAVE, 0, 0}}, | ||
| 238 | {"sd_card_nca_key", {S256KeyType::SD_NCA, 0, 0}}, | ||
| 239 | }; | ||
| 240 | 17 | ||
| 241 | static u8 ToHexNibble(char c1) { | 18 | static u8 ToHexNibble(char c1) { |
| 242 | if (c1 >= 65 && c1 <= 70) | 19 | if (c1 >= 65 && c1 <= 70) |
| @@ -271,8 +48,20 @@ std::array<u8, 32> operator""_array32(const char* str, size_t len) { | |||
| 271 | return HexStringToArray<32>(str); | 48 | return HexStringToArray<32>(str); |
| 272 | } | 49 | } |
| 273 | 50 | ||
| 274 | void KeyManager::SetValidationMode(bool dev) { | 51 | KeyManager::KeyManager() { |
| 275 | dev_mode = dev; | 52 | // Initialize keys |
| 53 | std::string keys_dir = FileUtil::GetHactoolConfigurationPath(); | ||
| 54 | if (Settings::values.use_dev_keys) { | ||
| 55 | dev_mode = true; | ||
| 56 | if (FileUtil::Exists(keys_dir + DIR_SEP + "dev.keys")) | ||
| 57 | LoadFromFile(keys_dir + DIR_SEP + "dev.keys", false); | ||
| 58 | } else { | ||
| 59 | dev_mode = false; | ||
| 60 | if (FileUtil::Exists(keys_dir + DIR_SEP + "prod.keys")) | ||
| 61 | LoadFromFile(keys_dir + DIR_SEP + "prod.keys", false); | ||
| 62 | } | ||
| 63 | if (FileUtil::Exists(keys_dir + DIR_SEP + "title.keys")) | ||
| 64 | LoadFromFile(keys_dir + DIR_SEP + "title.keys", true); | ||
| 276 | } | 65 | } |
| 277 | 66 | ||
| 278 | void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) { | 67 | void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) { |
| @@ -299,7 +88,7 @@ void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) { | |||
| 299 | auto rights_id_raw = HexStringToArray<16>(out[0]); | 88 | auto rights_id_raw = HexStringToArray<16>(out[0]); |
| 300 | u128 rights_id = *reinterpret_cast<std::array<u64, 2>*>(&rights_id_raw); | 89 | u128 rights_id = *reinterpret_cast<std::array<u64, 2>*>(&rights_id_raw); |
| 301 | Key128 key = HexStringToArray<16>(out[1]); | 90 | Key128 key = HexStringToArray<16>(out[1]); |
| 302 | SetKey(S128KeyType::TITLEKEY, key, rights_id[1], rights_id[0]); | 91 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); |
| 303 | } else { | 92 | } else { |
| 304 | std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower); | 93 | std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower); |
| 305 | if (s128_file_id.find(out[0]) != s128_file_id.end()) { | 94 | if (s128_file_id.find(out[0]) != s128_file_id.end()) { |
| @@ -315,24 +104,24 @@ void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) { | |||
| 315 | } | 104 | } |
| 316 | } | 105 | } |
| 317 | 106 | ||
| 318 | bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) { | 107 | bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const { |
| 319 | return s128_keys.find({id, field1, field2}) != s128_keys.end(); | 108 | return s128_keys.find({id, field1, field2}) != s128_keys.end(); |
| 320 | } | 109 | } |
| 321 | 110 | ||
| 322 | bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) { | 111 | bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) const { |
| 323 | return s256_keys.find({id, field1, field2}) != s256_keys.end(); | 112 | return s256_keys.find({id, field1, field2}) != s256_keys.end(); |
| 324 | } | 113 | } |
| 325 | 114 | ||
| 326 | Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) { | 115 | Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const { |
| 327 | if (!HasKey(id, field1, field2)) | 116 | if (!HasKey(id, field1, field2)) |
| 328 | return {}; | 117 | return {}; |
| 329 | return s128_keys[{id, field1, field2}]; | 118 | return s128_keys.at({id, field1, field2}); |
| 330 | } | 119 | } |
| 331 | 120 | ||
| 332 | Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) { | 121 | Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const { |
| 333 | if (!HasKey(id, field1, field2)) | 122 | if (!HasKey(id, field1, field2)) |
| 334 | return {}; | 123 | return {}; |
| 335 | return s256_keys[{id, field1, field2}]; | 124 | return s256_keys.at({id, field1, field2}); |
| 336 | } | 125 | } |
| 337 | 126 | ||
| 338 | void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { | 127 | void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { |
| @@ -343,68 +132,53 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { | |||
| 343 | s256_keys[{id, field1, field2}] = key; | 132 | s256_keys[{id, field1, field2}] = key; |
| 344 | } | 133 | } |
| 345 | 134 | ||
| 346 | bool KeyManager::ValidateKey(S128KeyType key, u64 field1, u64 field2) { | 135 | std::unordered_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { |
| 347 | auto& hash = dev_mode ? s128_hash_dev : s128_hash_prod; | 136 | {"master_key_00", {S128KeyType::Master, 0, 0}}, |
| 348 | 137 | {"master_key_01", {S128KeyType::Master, 1, 0}}, | |
| 349 | KeyIndex<S128KeyType> id = {key, field1, field2}; | 138 | {"master_key_02", {S128KeyType::Master, 2, 0}}, |
| 350 | if (key == S128KeyType::SD_SEED || key == S128KeyType::TITLEKEY || | 139 | {"master_key_03", {S128KeyType::Master, 3, 0}}, |
| 351 | hash.find(id) == hash.end()) { | 140 | {"master_key_04", {S128KeyType::Master, 4, 0}}, |
| 352 | LOG_WARNING(Crypto, "Could not validate [{}]", id.DebugInfo()); | 141 | {"package1_key_00", {S128KeyType::Package1, 0, 0}}, |
| 353 | return true; | 142 | {"package1_key_01", {S128KeyType::Package1, 1, 0}}, |
| 354 | } | 143 | {"package1_key_02", {S128KeyType::Package1, 2, 0}}, |
| 355 | 144 | {"package1_key_03", {S128KeyType::Package1, 3, 0}}, | |
| 356 | if (!HasKey(key, field1, field2)) { | 145 | {"package1_key_04", {S128KeyType::Package1, 4, 0}}, |
| 357 | LOG_CRITICAL(Crypto, | 146 | {"package2_key_00", {S128KeyType::Package2, 0, 0}}, |
| 358 | "System has requested validation of [{}], but user has not added it. Add this " | 147 | {"package2_key_01", {S128KeyType::Package2, 1, 0}}, |
| 359 | "key to use functionality.", | 148 | {"package2_key_02", {S128KeyType::Package2, 2, 0}}, |
| 360 | id.DebugInfo()); | 149 | {"package2_key_03", {S128KeyType::Package2, 3, 0}}, |
| 361 | return false; | 150 | {"package2_key_04", {S128KeyType::Package2, 4, 0}}, |
| 362 | } | 151 | {"titlekek_00", {S128KeyType::Titlekek, 0, 0}}, |
| 363 | 152 | {"titlekek_01", {S128KeyType::Titlekek, 1, 0}}, | |
| 364 | SHA256Hash key_hash{}; | 153 | {"titlekek_02", {S128KeyType::Titlekek, 2, 0}}, |
| 365 | const auto a_key = GetKey(key, field1, field2); | 154 | {"titlekek_03", {S128KeyType::Titlekek, 3, 0}}, |
| 366 | mbedtls_sha256(a_key.data(), a_key.size(), key_hash.data(), 0); | 155 | {"titlekek_04", {S128KeyType::Titlekek, 4, 0}}, |
| 367 | if (key_hash != hash[id]) { | 156 | {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, |
| 368 | LOG_CRITICAL(Crypto, | 157 | {"key_area_key_application_00", |
| 369 | "The hash of the provided key for [{}] does not match the one on file. This " | 158 | {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Application)}}, |
| 370 | "means you probably have an incorrect key. If you believe this to be in " | 159 | {"key_area_key_application_01", |
| 371 | "error, contact the yuzu devs.", | 160 | {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Application)}}, |
| 372 | id.DebugInfo()); | 161 | {"key_area_key_application_02", |
| 373 | return false; | 162 | {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Application)}}, |
| 374 | } | 163 | {"key_area_key_application_03", |
| 375 | 164 | {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Application)}}, | |
| 376 | return true; | 165 | {"key_area_key_application_04", |
| 377 | } | 166 | {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Application)}}, |
| 378 | 167 | {"key_area_key_ocean_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}}, | |
| 379 | bool KeyManager::ValidateKey(S256KeyType key, u64 field1, u64 field2) { | 168 | {"key_area_key_ocean_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}}, |
| 380 | auto& hash = dev_mode ? s256_hash_dev : s256_hash_prod; | 169 | {"key_area_key_ocean_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}}, |
| 381 | 170 | {"key_area_key_ocean_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}}, | |
| 382 | KeyIndex<S256KeyType> id = {key, field1, field2}; | 171 | {"key_area_key_ocean_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}}, |
| 383 | if (hash.find(id) == hash.end()) { | 172 | {"key_area_key_system_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::System)}}, |
| 384 | LOG_ERROR(Crypto, "Could not validate [{}]", id.DebugInfo()); | 173 | {"key_area_key_system_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::System)}}, |
| 385 | return true; | 174 | {"key_area_key_system_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::System)}}, |
| 386 | } | 175 | {"key_area_key_system_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::System)}}, |
| 387 | 176 | {"key_area_key_system_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::System)}}, | |
| 388 | if (!HasKey(key, field1, field2)) { | 177 | }; |
| 389 | LOG_ERROR(Crypto, | ||
| 390 | "System has requested validation of [{}], but user has not added it. Add this " | ||
| 391 | "key to use functionality.", | ||
| 392 | id.DebugInfo()); | ||
| 393 | return false; | ||
| 394 | } | ||
| 395 | |||
| 396 | SHA256Hash key_hash{}; | ||
| 397 | const auto a_key = GetKey(key, field1, field2); | ||
| 398 | mbedtls_sha256(a_key.data(), a_key.size(), key_hash.data(), 0); | ||
| 399 | if (key_hash != hash[id]) { | ||
| 400 | LOG_CRITICAL(Crypto, | ||
| 401 | "The hash of the provided key for [{}] does not match the one on file. This " | ||
| 402 | "means you probably have an incorrect key. If you believe this to be in " | ||
| 403 | "error, contact the yuzu devs.", | ||
| 404 | id.DebugInfo()); | ||
| 405 | return false; | ||
| 406 | } | ||
| 407 | 178 | ||
| 408 | return true; | 179 | std::unordered_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = { |
| 409 | } | 180 | {"header_key", {S256KeyType::Header, 0, 0}}, |
| 410 | } // namespace Crypto | 181 | {"sd_card_save_key", {S256KeyType::SDSave, 0, 0}}, |
| 182 | {"sd_card_nca_key", {S256KeyType::SDNCA, 0, 0}}, | ||
| 183 | }; | ||
| 184 | } // namespace Core::Crypto | ||
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index b892a83f2..e04f1d49f 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h | |||
| @@ -3,36 +3,37 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | |||
| 6 | #include <array> | 7 | #include <array> |
| 7 | #include <unordered_map> | 8 | #include <unordered_map> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | #include <fmt/format.h> | 10 | #include <fmt/format.h> |
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | 12 | ||
| 12 | namespace Crypto { | 13 | namespace Core::Crypto { |
| 13 | 14 | ||
| 14 | typedef std::array<u8, 0x10> Key128; | 15 | using Key128 = std::array<u8, 0x10>; |
| 15 | typedef std::array<u8, 0x20> Key256; | 16 | using Key256 = std::array<u8, 0x20>; |
| 16 | typedef std::array<u8, 0x20> SHA256Hash; | 17 | using SHA256Hash = std::array<u8, 0x20>; |
| 17 | 18 | ||
| 18 | static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); | 19 | static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); |
| 19 | static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big."); | 20 | static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big."); |
| 20 | 21 | ||
| 21 | enum class S256KeyType : u64 { | 22 | enum class S256KeyType : u64 { |
| 22 | HEADER, // | 23 | Header, // |
| 23 | SD_SAVE, // | 24 | SDSave, // |
| 24 | SD_NCA, // | 25 | SDNCA, // |
| 25 | }; | 26 | }; |
| 26 | 27 | ||
| 27 | enum class S128KeyType : u64 { | 28 | enum class S128KeyType : u64 { |
| 28 | MASTER, // f1=crypto revision | 29 | Master, // f1=crypto revision |
| 29 | PACKAGE1, // f1=crypto revision | 30 | Package1, // f1=crypto revision |
| 30 | PACKAGE2, // f1=crypto revision | 31 | Package2, // f1=crypto revision |
| 31 | TITLEKEK, // f1=crypto revision | 32 | Titlekek, // f1=crypto revision |
| 32 | ETICKET_RSA_KEK, // | 33 | ETicketRSAKek, // |
| 33 | KEY_AREA, // f1=crypto revision f2=type {app, ocean, system} | 34 | KeyArea, // f1=crypto revision f2=type {app, ocean, system} |
| 34 | SD_SEED, // | 35 | SDSeed, // |
| 35 | TITLEKEY, // f1=rights id LSB f2=rights id MSB | 36 | Titlekey, // f1=rights id LSB f2=rights id MSB |
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 38 | enum class KeyAreaKeyType : u8 { | 39 | enum class KeyAreaKeyType : u8 { |
| @@ -47,7 +48,7 @@ struct KeyIndex { | |||
| 47 | u64 field1; | 48 | u64 field1; |
| 48 | u64 field2; | 49 | u64 field2; |
| 49 | 50 | ||
| 50 | std::string DebugInfo() { | 51 | std::string DebugInfo() const { |
| 51 | u8 key_size = 16; | 52 | u8 key_size = 16; |
| 52 | if (std::is_same_v<KeyType, S256KeyType>) | 53 | if (std::is_same_v<KeyType, S256KeyType>) |
| 53 | key_size = 32; | 54 | key_size = 32; |
| @@ -60,15 +61,20 @@ struct KeyIndex { | |||
| 60 | 61 | ||
| 61 | template <typename KeyType> | 62 | template <typename KeyType> |
| 62 | bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) { | 63 | bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) { |
| 63 | return lhs.type == rhs.type && lhs.field1 == rhs.field1 && lhs.field2 == rhs.field2; | 64 | return std::tie(lhs.type, lhs.field1, lhs.field2) == std::tie(rhs.type, rhs.field1, rhs.field2); |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | } // namespace Crypto | 67 | template <typename KeyType> |
| 68 | bool operator!=(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) { | ||
| 69 | return !operator==(lhs, rhs); | ||
| 70 | } | ||
| 71 | |||
| 72 | } // namespace Core::Crypto | ||
| 67 | 73 | ||
| 68 | namespace std { | 74 | namespace std { |
| 69 | template <typename KeyType> | 75 | template <typename KeyType> |
| 70 | struct hash<Crypto::KeyIndex<KeyType>> { | 76 | struct hash<Core::Crypto::KeyIndex<KeyType>> { |
| 71 | size_t operator()(const Crypto::KeyIndex<KeyType>& k) const { | 77 | size_t operator()(const Core::Crypto::KeyIndex<KeyType>& k) const { |
| 72 | using std::hash; | 78 | using std::hash; |
| 73 | 79 | ||
| 74 | return ((hash<u64>()(static_cast<u64>(k.type)) ^ (hash<u64>()(k.field1) << 1)) >> 1) ^ | 80 | return ((hash<u64>()(static_cast<u64>(k.type)) ^ (hash<u64>()(k.field1) << 1)) >> 1) ^ |
| @@ -77,41 +83,32 @@ struct hash<Crypto::KeyIndex<KeyType>> { | |||
| 77 | }; | 83 | }; |
| 78 | } // namespace std | 84 | } // namespace std |
| 79 | 85 | ||
| 80 | namespace Crypto { | 86 | namespace Core::Crypto { |
| 81 | 87 | ||
| 82 | std::array<u8, 0x10> operator"" _array16(const char* str, size_t len); | 88 | std::array<u8, 0x10> operator"" _array16(const char* str, size_t len); |
| 83 | std::array<u8, 0x20> operator"" _array32(const char* str, size_t len); | 89 | std::array<u8, 0x20> operator"" _array32(const char* str, size_t len); |
| 84 | 90 | ||
| 85 | struct KeyManager { | 91 | class KeyManager { |
| 86 | void SetValidationMode(bool dev); | 92 | public: |
| 87 | void LoadFromFile(std::string_view filename, bool is_title_keys); | 93 | KeyManager(); |
| 88 | 94 | ||
| 89 | bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0); | 95 | bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
| 90 | bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0); | 96 | bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
| 91 | 97 | ||
| 92 | Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0); | 98 | Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
| 93 | Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0); | 99 | Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
| 94 | 100 | ||
| 95 | void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); | 101 | void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); |
| 96 | void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); | 102 | void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); |
| 97 | 103 | ||
| 98 | bool ValidateKey(S128KeyType key, u64 field1 = 0, u64 field2 = 0); | ||
| 99 | bool ValidateKey(S256KeyType key, u64 field1 = 0, u64 field2 = 0); | ||
| 100 | |||
| 101 | private: | 104 | private: |
| 102 | std::unordered_map<KeyIndex<S128KeyType>, Key128> s128_keys; | 105 | std::unordered_map<KeyIndex<S128KeyType>, Key128> s128_keys; |
| 103 | std::unordered_map<KeyIndex<S256KeyType>, Key256> s256_keys; | 106 | std::unordered_map<KeyIndex<S256KeyType>, Key256> s256_keys; |
| 104 | 107 | ||
| 105 | bool dev_mode = false; | 108 | bool dev_mode; |
| 109 | void LoadFromFile(std::string_view filename, bool is_title_keys); | ||
| 106 | 110 | ||
| 107 | static std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> s128_hash_prod; | ||
| 108 | static std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> s256_hash_prod; | ||
| 109 | static std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> s128_hash_dev; | ||
| 110 | static std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> s256_hash_dev; | ||
| 111 | static std::unordered_map<std::string, KeyIndex<S128KeyType>> s128_file_id; | 111 | static std::unordered_map<std::string, KeyIndex<S128KeyType>> s128_file_id; |
| 112 | static std::unordered_map<std::string, KeyIndex<S256KeyType>> s256_file_id; | 112 | static std::unordered_map<std::string, KeyIndex<S256KeyType>> s256_file_id; |
| 113 | }; | 113 | }; |
| 114 | 114 | } // namespace Core::Crypto | |
| 115 | extern KeyManager keys; | ||
| 116 | |||
| 117 | } // namespace Crypto | ||
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 5ff09a362..3c1dbf46c 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -30,8 +30,8 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) { | |||
| 30 | return; | 30 | return; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | const static std::array<std::string, 0x4> partition_names = {"update", "normal", "secure", | 33 | static constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure", |
| 34 | "logo"}; | 34 | "logo"}; |
| 35 | 35 | ||
| 36 | for (XCIPartition partition : | 36 | for (XCIPartition partition : |
| 37 | {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) { | 37 | {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) { |
| @@ -93,12 +93,9 @@ VirtualDir XCI::GetLogoPartition() const { | |||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { | 95 | std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { |
| 96 | for (const auto& nca : ncas) { | 96 | auto iter = std::find_if(ncas.begin(), ncas.end(), |
| 97 | if (nca->GetType() == type) | 97 | [type](std::shared_ptr<NCA> nca) { return nca->GetType() == type; }); |
| 98 | return nca; | 98 | return iter == ncas.end() ? nullptr : *iter; |
| 99 | } | ||
| 100 | |||
| 101 | return nullptr; | ||
| 102 | } | 99 | } |
| 103 | 100 | ||
| 104 | VirtualFile XCI::GetNCAFileByType(NCAContentType type) const { | 101 | VirtualFile XCI::GetNCAFileByType(NCAContentType type) const { |
| @@ -133,7 +130,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { | |||
| 133 | return Loader::ResultStatus::ErrorInvalidFormat; | 130 | return Loader::ResultStatus::ErrorInvalidFormat; |
| 134 | } | 131 | } |
| 135 | 132 | ||
| 136 | for (VirtualFile file : partitions[static_cast<size_t>(part)]->GetFiles()) { | 133 | for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) { |
| 137 | if (file->GetExtension() != "nca") | 134 | if (file->GetExtension() != "nca") |
| 138 | continue; | 135 | continue; |
| 139 | auto nca = std::make_shared<NCA>(file); | 136 | auto nca = std::make_shared<NCA>(file); |
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index add01974e..952dc7068 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -9,10 +9,9 @@ | |||
| 9 | #include "core/crypto/aes_util.h" | 9 | #include "core/crypto/aes_util.h" |
| 10 | #include "core/crypto/ctr_encryption_layer.h" | 10 | #include "core/crypto/ctr_encryption_layer.h" |
| 11 | #include "core/file_sys/content_archive.h" | 11 | #include "core/file_sys/content_archive.h" |
| 12 | #include "core/file_sys/romfs.h" | ||
| 12 | #include "core/file_sys/vfs_offset.h" | 13 | #include "core/file_sys/vfs_offset.h" |
| 13 | #include "core/loader/loader.h" | 14 | #include "core/loader/loader.h" |
| 14 | #include "mbedtls/cipher.h" | ||
| 15 | #include "romfs.h" | ||
| 16 | 15 | ||
| 17 | namespace FileSys { | 16 | namespace FileSys { |
| 18 | 17 | ||
| @@ -77,7 +76,7 @@ bool IsValidNCA(const NCAHeader& header) { | |||
| 77 | return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); | 76 | return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); |
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) { | 79 | Core::Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) { |
| 81 | u8 master_key_id = header.crypto_type; | 80 | u8 master_key_id = header.crypto_type; |
| 82 | if (header.crypto_type_2 > master_key_id) | 81 | if (header.crypto_type_2 > master_key_id) |
| 83 | master_key_id = header.crypto_type_2; | 82 | master_key_id = header.crypto_type_2; |
| @@ -85,16 +84,12 @@ Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) { | |||
| 85 | --master_key_id; | 84 | --master_key_id; |
| 86 | 85 | ||
| 87 | std::vector<u8> key_area(header.key_area.begin(), header.key_area.end()); | 86 | std::vector<u8> key_area(header.key_area.begin(), header.key_area.end()); |
| 88 | if (!Crypto::keys.ValidateKey(Crypto::S128KeyType::KEY_AREA, master_key_id, header.key_index)) { | 87 | Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( |
| 89 | status = Loader::ResultStatus::ErrorEncrypted; | 88 | keys.GetKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index), |
| 90 | return {}; | 89 | Core::Crypto::Mode::ECB); |
| 91 | } | 90 | cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt); |
| 92 | Crypto::AESCipher<Crypto::Key128> cipher( | ||
| 93 | Crypto::keys.GetKey(Crypto::S128KeyType::KEY_AREA, master_key_id, header.key_index), | ||
| 94 | Crypto::Mode::ECB); | ||
| 95 | cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Crypto::Op::DECRYPT); | ||
| 96 | 91 | ||
| 97 | Crypto::Key128 out; | 92 | Core::Crypto::Key128 out; |
| 98 | if (type == NCASectionCryptoType::XTS) | 93 | if (type == NCASectionCryptoType::XTS) |
| 99 | std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); | 94 | std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); |
| 100 | else if (type == NCASectionCryptoType::CTR) | 95 | else if (type == NCASectionCryptoType::CTR) |
| @@ -102,8 +97,8 @@ Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) { | |||
| 102 | else | 97 | else |
| 103 | LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}", | 98 | LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}", |
| 104 | static_cast<u8>(type)); | 99 | static_cast<u8>(type)); |
| 105 | 100 | u128 out_128{}; | |
| 106 | u128 out_128 = *reinterpret_cast<u128*>(&out); | 101 | memcpy(out_128.data(), out.data(), 16); |
| 107 | LOG_DEBUG(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}", | 102 | LOG_DEBUG(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}", |
| 108 | master_key_id, header.key_index, out_128[1], out_128[0]); | 103 | master_key_id, header.key_index, out_128[1], out_128[0]); |
| 109 | 104 | ||
| @@ -121,9 +116,9 @@ VirtualFile NCA::Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_o | |||
| 121 | case NCASectionCryptoType::CTR: | 116 | case NCASectionCryptoType::CTR: |
| 122 | LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); | 117 | LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); |
| 123 | { | 118 | { |
| 124 | auto out = std::make_shared<Crypto::CTREncryptionLayer>( | 119 | auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>( |
| 125 | std::move(in), GetKeyAreaKey(NCASectionCryptoType::CTR), starting_offset); | 120 | std::move(in), GetKeyAreaKey(NCASectionCryptoType::CTR), starting_offset); |
| 126 | std::vector<u8> iv(16, 0); | 121 | std::vector<u8> iv(16); |
| 127 | for (u8 i = 0; i < 8; ++i) | 122 | for (u8 i = 0; i < 8; ++i) |
| 128 | iv[i] = header.raw.section_ctr[0x8 - i - 1]; | 123 | iv[i] = header.raw.section_ctr[0x8 - i - 1]; |
| 129 | out->SetIV(iv); | 124 | out->SetIV(iv); |
| @@ -146,13 +141,10 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) { | |||
| 146 | 141 | ||
| 147 | if (!IsValidNCA(header)) { | 142 | if (!IsValidNCA(header)) { |
| 148 | NCAHeader dec_header{}; | 143 | NCAHeader dec_header{}; |
| 149 | if (!Crypto::keys.ValidateKey(Crypto::S256KeyType::HEADER)) { | 144 | Core::Crypto::AESCipher<Core::Crypto::Key256> cipher( |
| 150 | status = Loader::ResultStatus::ErrorEncrypted; | 145 | keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS); |
| 151 | return; | 146 | cipher.XTSTranscode(&header, sizeof(NCAHeader), &dec_header, 0, 0x200, |
| 152 | } | 147 | Core::Crypto::Op::Decrypt); |
| 153 | Crypto::AESCipher<Crypto::Key256> cipher(Crypto::keys.GetKey(Crypto::S256KeyType::HEADER), | ||
| 154 | Crypto::Mode::XTS); | ||
| 155 | cipher.XTSTranscode(&header, sizeof(NCAHeader), &dec_header, 0, 0x200, Crypto::Op::DECRYPT); | ||
| 156 | if (IsValidNCA(dec_header)) { | 148 | if (IsValidNCA(dec_header)) { |
| 157 | header = dec_header; | 149 | header = dec_header; |
| 158 | encrypted = true; | 150 | encrypted = true; |
| @@ -171,14 +163,10 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) { | |||
| 171 | 163 | ||
| 172 | if (encrypted) { | 164 | if (encrypted) { |
| 173 | auto raw = file->ReadBytes(length_sections, SECTION_HEADER_OFFSET); | 165 | auto raw = file->ReadBytes(length_sections, SECTION_HEADER_OFFSET); |
| 174 | if (!Crypto::keys.ValidateKey(Crypto::S256KeyType::HEADER)) { | 166 | Core::Crypto::AESCipher<Core::Crypto::Key256> cipher( |
| 175 | status = Loader::ResultStatus::ErrorEncrypted; | 167 | keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS); |
| 176 | return; | ||
| 177 | } | ||
| 178 | Crypto::AESCipher<Crypto::Key256> cipher(Crypto::keys.GetKey(Crypto::S256KeyType::HEADER), | ||
| 179 | Crypto::Mode::XTS); | ||
| 180 | cipher.XTSTranscode(raw.data(), length_sections, sections.data(), 2, SECTION_HEADER_SIZE, | 168 | cipher.XTSTranscode(raw.data(), length_sections, sections.data(), 2, SECTION_HEADER_SIZE, |
| 181 | Crypto::Op::DECRYPT); | 169 | Core::Crypto::Op::Decrypt); |
| 182 | } else { | 170 | } else { |
| 183 | file->ReadBytes(sections.data(), length_sections, SECTION_HEADER_OFFSET); | 171 | file->ReadBytes(sections.data(), length_sections, SECTION_HEADER_OFFSET); |
| 184 | } | 172 | } |
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index d9ad3bf7e..153142b06 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -9,12 +9,12 @@ | |||
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "core/loader/loader.h" | ||
| 13 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 14 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 15 | #include "common/swap.h" | 14 | #include "common/swap.h" |
| 16 | #include "core/crypto/key_manager.h" | 15 | #include "core/crypto/key_manager.h" |
| 17 | #include "core/file_sys/partition_filesystem.h" | 16 | #include "core/file_sys/partition_filesystem.h" |
| 17 | #include "core/loader/loader.h" | ||
| 18 | 18 | ||
| 19 | namespace FileSys { | 19 | namespace FileSys { |
| 20 | enum class NCAContentType : u8 { | 20 | enum class NCAContentType : u8 { |
| @@ -107,7 +107,8 @@ private: | |||
| 107 | 107 | ||
| 108 | bool encrypted; | 108 | bool encrypted; |
| 109 | 109 | ||
| 110 | Crypto::Key128 GetKeyAreaKey(NCASectionCryptoType type); | 110 | Core::Crypto::KeyManager keys; |
| 111 | Core::Crypto::Key128 GetKeyAreaKey(NCASectionCryptoType type); | ||
| 111 | 112 | ||
| 112 | VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset); | 113 | VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset); |
| 113 | }; | 114 | }; |
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 57d0aeb85..dae1c16ef 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -297,10 +297,9 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block | |||
| 297 | 297 | ||
| 298 | if (f1_vs != f2_vs) | 298 | if (f1_vs != f2_vs) |
| 299 | return false; | 299 | return false; |
| 300 | for (size_t j = 0; j < f1_vs; ++j) { | 300 | auto iters = std::mismatch(f1_v.begin(), f1_v.end(), f2_v.begin(), f2_v.end()); |
| 301 | if (f1_v[j] != f2_v[j]) | 301 | if (iters.first != f1_v.end() && iters.second != f2_v.end()) |
| 302 | return false; | 302 | return false; |
| 303 | } | ||
| 304 | } | 303 | } |
| 305 | 304 | ||
| 306 | return true; | 305 | return true; |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 9759e33d1..b4de5bd16 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -28,14 +28,17 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) | |||
| 28 | nca_loader(std::make_unique<AppLoader_NCA>( | 28 | nca_loader(std::make_unique<AppLoader_NCA>( |
| 29 | xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} | 29 | xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} |
| 30 | 30 | ||
| 31 | AppLoader_XCI::~AppLoader_XCI() = default; | ||
| 32 | |||
| 31 | FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) { | 33 | FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) { |
| 32 | FileSys::XCI xci(file); | 34 | FileSys::XCI xci(file); |
| 33 | 35 | ||
| 34 | if (xci.GetStatus() == ResultStatus::Success && | 36 | if (xci.GetStatus() == ResultStatus::Success && |
| 35 | xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr && | 37 | xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr && |
| 36 | AppLoader_NCA::IdentifyType(xci.GetNCAFileByType(FileSys::NCAContentType::Program)) == | 38 | AppLoader_NCA::IdentifyType(xci.GetNCAFileByType(FileSys::NCAContentType::Program)) == |
| 37 | FileType::NCA) | 39 | FileType::NCA) { |
| 38 | return FileType::XCI; | 40 | return FileType::XCI; |
| 41 | } | ||
| 39 | 42 | ||
| 40 | return FileType::Error; | 43 | return FileType::Error; |
| 41 | } | 44 | } |
| @@ -62,6 +65,4 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { | |||
| 62 | return nca_loader->ReadProgramId(out_program_id); | 65 | return nca_loader->ReadProgramId(out_program_id); |
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | AppLoader_XCI::~AppLoader_XCI() = default; | ||
| 66 | |||
| 67 | } // namespace Loader | 68 | } // namespace Loader |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index a9cee1ca3..2a09caa5f 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -13,6 +13,7 @@ namespace Loader { | |||
| 13 | class AppLoader_XCI final : public AppLoader { | 13 | class AppLoader_XCI final : public AppLoader { |
| 14 | public: | 14 | public: |
| 15 | explicit AppLoader_XCI(FileSys::VirtualFile file); | 15 | explicit AppLoader_XCI(FileSys::VirtualFile file); |
| 16 | ~AppLoader_XCI(); | ||
| 16 | 17 | ||
| 17 | /** | 18 | /** |
| 18 | * Returns the type of the file | 19 | * Returns the type of the file |
| @@ -30,8 +31,6 @@ public: | |||
| 30 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 31 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 31 | ResultStatus ReadProgramId(u64& out_program_id) override; | 32 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 32 | 33 | ||
| 33 | ~AppLoader_XCI(); | ||
| 34 | |||
| 35 | private: | 34 | private: |
| 36 | FileSys::ProgramMetadata metadata; | 35 | FileSys::ProgramMetadata metadata; |
| 37 | 36 | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d3523e6ac..c274e5e2b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include <QMessageBox> | 13 | #include <QMessageBox> |
| 14 | #include <QtGui> | 14 | #include <QtGui> |
| 15 | #include <QtWidgets> | 15 | #include <QtWidgets> |
| 16 | #include <core/crypto/key_manager.h> | ||
| 17 | #include "common/common_paths.h" | 16 | #include "common/common_paths.h" |
| 18 | #include "common/logging/backend.h" | 17 | #include "common/logging/backend.h" |
| 19 | #include "common/logging/filter.h" | 18 | #include "common/logging/filter.h" |
| @@ -24,6 +23,7 @@ | |||
| 24 | #include "common/scope_exit.h" | 23 | #include "common/scope_exit.h" |
| 25 | #include "common/string_util.h" | 24 | #include "common/string_util.h" |
| 26 | #include "core/core.h" | 25 | #include "core/core.h" |
| 26 | #include "core/crypto/key_manager.h" | ||
| 27 | #include "core/gdbstub/gdbstub.h" | 27 | #include "core/gdbstub/gdbstub.h" |
| 28 | #include "core/loader/loader.h" | 28 | #include "core/loader/loader.h" |
| 29 | #include "core/settings.h" | 29 | #include "core/settings.h" |
| @@ -89,19 +89,6 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { | |||
| 89 | ui.setupUi(this); | 89 | ui.setupUi(this); |
| 90 | statusBar()->hide(); | 90 | statusBar()->hide(); |
| 91 | 91 | ||
| 92 | // Initialize keys | ||
| 93 | std::string keys_dir = FileUtil::GetHactoolConfigurationPath(); | ||
| 94 | if (Settings::values.use_dev_keys) { | ||
| 95 | Crypto::keys.SetValidationMode(true); | ||
| 96 | if (FileUtil::Exists(keys_dir + DIR_SEP + "dev.keys")) | ||
| 97 | Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "dev.keys", false); | ||
| 98 | } else { | ||
| 99 | if (FileUtil::Exists(keys_dir + DIR_SEP + "prod.keys")) | ||
| 100 | Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "prod.keys", false); | ||
| 101 | } | ||
| 102 | if (FileUtil::Exists(keys_dir + DIR_SEP + "title.keys")) | ||
| 103 | Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "title.keys", true); | ||
| 104 | |||
| 105 | default_theme_paths = QIcon::themeSearchPaths(); | 92 | default_theme_paths = QIcon::themeSearchPaths(); |
| 106 | UpdateUITheme(); | 93 | UpdateUITheme(); |
| 107 | 94 | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 955e2ba14..97a8e13f0 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -73,19 +73,6 @@ static void InitializeLogging() { | |||
| 73 | int main(int argc, char** argv) { | 73 | int main(int argc, char** argv) { |
| 74 | Config config; | 74 | Config config; |
| 75 | 75 | ||
| 76 | // Initialize keys | ||
| 77 | std::string keys_dir = FileUtil::GetHactoolConfigurationPath(); | ||
| 78 | if (Settings::values.use_dev_keys) { | ||
| 79 | Crypto::keys.SetValidationMode(true); | ||
| 80 | if (FileUtil::Exists(keys_dir + DIR_SEP + "dev.keys")) | ||
| 81 | Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "dev.keys", false); | ||
| 82 | } else { | ||
| 83 | if (FileUtil::Exists(keys_dir + DIR_SEP + "prod.keys")) | ||
| 84 | Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "prod.keys", false); | ||
| 85 | } | ||
| 86 | if (FileUtil::Exists(keys_dir + DIR_SEP + "title.keys")) | ||
| 87 | Crypto::keys.LoadFromFile(keys_dir + DIR_SEP + "title.keys", true); | ||
| 88 | |||
| 89 | int option_index = 0; | 76 | int option_index = 0; |
| 90 | bool use_gdbstub = Settings::values.use_gdbstub; | 77 | bool use_gdbstub = Settings::values.use_gdbstub; |
| 91 | u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port); | 78 | u32 gdb_port = static_cast<u32>(Settings::values.gdbstub_port); |