summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/crypto/aes_util.cpp82
-rw-r--r--src/core/crypto/aes_util.h13
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp20
-rw-r--r--src/core/crypto/ctr_encryption_layer.h15
-rw-r--r--src/core/crypto/encryption_layer.cpp4
-rw-r--r--src/core/crypto/encryption_layer.h5
-rw-r--r--src/core/crypto/key_manager.cpp376
-rw-r--r--src/core/crypto/key_manager.h77
-rw-r--r--src/core/file_sys/card_image.cpp15
-rw-r--r--src/core/file_sys/content_archive.cpp48
-rw-r--r--src/core/file_sys/content_archive.h5
-rw-r--r--src/core/file_sys/vfs.cpp7
-rw-r--r--src/core/loader/xci.cpp7
-rw-r--r--src/core/loader/xci.h3
-rw-r--r--src/yuzu/main.cpp15
-rw-r--r--src/yuzu_cmd/yuzu.cpp13
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
8namespace Core::Crypto { 9namespace Core::Crypto {
9static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), "CTR mode is incorrect.");
10static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), "ECB mode is incorrect.");
11static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), "XTS mode is incorrect.");
12 10
13template<typename Key, size_t KeySize> 11static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR),
14Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) { 12 "CTR has incorrect value.");
15 mbedtls_cipher_init(encryption_context.get()); 13static_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.");
15static_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
19struct CipherContext {
20 mbedtls_cipher_context_t encryption_context;
21 mbedtls_cipher_context_t decryption_context;
22};
23
24template <typename Key, size_t KeySize>
25Crypto::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
33template<typename Key, size_t KeySize> 45template <typename Key, size_t KeySize>
34AESCipher<Key, KeySize>::~AESCipher() { 46AESCipher<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
39template<typename Key, size_t KeySize> 51template <typename Key, size_t KeySize>
40void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) { 52void 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
46template<typename Key, size_t KeySize> 58template <typename Key, size_t KeySize>
47void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) { 59void 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
77template<typename Key, size_t KeySize> 86template <typename Key, size_t KeySize>
78void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, 87void 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
92template<typename Key, size_t KeySize> 100template <typename Key, size_t KeySize>
93std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id) { 101std::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
102template class AESCipher<Key128>; 110template class AESCipher<Key128>;
103template class AESCipher<Key256>; 111template 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
23struct mbedtls_cipher_context_t; 23struct CipherContext;
24 24
25template <typename Key, size_t KeySize = sizeof(Key)> 25template <typename Key, size_t KeySize = sizeof(Key)>
26class AESCipher { 26class 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
52private: 54private:
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
9namespace Crypto { 9namespace Core::Crypto {
10
10CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) 11CTREncryptionLayer::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
43void CTREncryptionLayer::SetIV(std::vector<u8> iv_) { 44void 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
49void CTREncryptionLayer::UpdateIV(size_t offset) const { 49void 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
11namespace Crypto { 11namespace 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.
14struct CTREncryptionLayer : public EncryptionLayer { 14class CTREncryptionLayer : public EncryptionLayer {
15public:
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
21private: 22private:
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
7namespace Crypto { 7namespace Core::Crypto {
8 8
9EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {} 9EncryptionLayer::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) {
39bool EncryptionLayer::Rename(std::string_view name) { 39bool 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
8namespace Crypto { 9namespace 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
13namespace Crypto { 16namespace Core::Crypto {
14KeyManager keys = {};
15
16std::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
91std::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
102std::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
177std::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
186std::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
235std::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
241static u8 ToHexNibble(char c1) { 18static 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
274void KeyManager::SetValidationMode(bool dev) { 51KeyManager::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
278void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) { 67void 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
318bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) { 107bool 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
322bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) { 111bool 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
326Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) { 115Key128 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
332Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) { 121Key256 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
338void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { 127void 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
346bool KeyManager::ValidateKey(S128KeyType key, u64 field1, u64 field2) { 135std::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)}},
379bool 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; 179std::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
12namespace Crypto { 13namespace Core::Crypto {
13 14
14typedef std::array<u8, 0x10> Key128; 15using Key128 = std::array<u8, 0x10>;
15typedef std::array<u8, 0x20> Key256; 16using Key256 = std::array<u8, 0x20>;
16typedef std::array<u8, 0x20> SHA256Hash; 17using SHA256Hash = std::array<u8, 0x20>;
17 18
18static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); 19static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big.");
19static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big."); 20static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big.");
20 21
21enum class S256KeyType : u64 { 22enum class S256KeyType : u64 {
22 HEADER, // 23 Header, //
23 SD_SAVE, // 24 SDSave, //
24 SD_NCA, // 25 SDNCA, //
25}; 26};
26 27
27enum class S128KeyType : u64 { 28enum 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
38enum class KeyAreaKeyType : u8 { 39enum 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
61template <typename KeyType> 62template <typename KeyType>
62bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) { 63bool 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 67template <typename KeyType>
68bool operator!=(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
69 return !operator==(lhs, rhs);
70}
71
72} // namespace Core::Crypto
67 73
68namespace std { 74namespace std {
69template <typename KeyType> 75template <typename KeyType>
70struct hash<Crypto::KeyIndex<KeyType>> { 76struct 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
80namespace Crypto { 86namespace Core::Crypto {
81 87
82std::array<u8, 0x10> operator"" _array16(const char* str, size_t len); 88std::array<u8, 0x10> operator"" _array16(const char* str, size_t len);
83std::array<u8, 0x20> operator"" _array32(const char* str, size_t len); 89std::array<u8, 0x20> operator"" _array32(const char* str, size_t len);
84 90
85struct KeyManager { 91class KeyManager {
86 void SetValidationMode(bool dev); 92public:
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
101private: 104private:
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
115extern 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
95std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { 95std::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
104VirtualFile XCI::GetNCAFileByType(NCAContentType type) const { 101VirtualFile 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
17namespace FileSys { 16namespace 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
80Crypto::Key128 NCA::GetKeyAreaKey(NCASectionCryptoType type) { 79Core::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
19namespace FileSys { 19namespace FileSys {
20enum class NCAContentType : u8 { 20enum 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
31AppLoader_XCI::~AppLoader_XCI() = default;
32
31FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) { 33FileType 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
65AppLoader_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 {
13class AppLoader_XCI final : public AppLoader { 13class AppLoader_XCI final : public AppLoader {
14public: 14public:
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
35private: 34private:
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() {
73int main(int argc, char** argv) { 73int 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);