diff options
| author | 2018-07-27 23:55:23 -0400 | |
|---|---|---|
| committer | 2018-08-01 00:16:54 -0400 | |
| commit | df5b75694f5abde94ccf05fa6c7a557b1ba9079b (patch) | |
| tree | 70f0cf96b1a9834360fb1c5d5547939693ecd577 /src/core/crypto | |
| parent | Merge pull request #871 from bunnei/audio-config (diff) | |
| download | yuzu-df5b75694f5abde94ccf05fa6c7a557b1ba9079b.tar.gz yuzu-df5b75694f5abde94ccf05fa6c7a557b1ba9079b.tar.xz yuzu-df5b75694f5abde94ccf05fa6c7a557b1ba9079b.zip | |
Remove files that are not used
Diffstat (limited to 'src/core/crypto')
| -rw-r--r-- | src/core/crypto/aes_util.cpp | 6 | ||||
| -rw-r--r-- | src/core/crypto/aes_util.h | 118 | ||||
| -rw-r--r-- | src/core/crypto/ctr_encryption_layer.cpp | 56 | ||||
| -rw-r--r-- | src/core/crypto/ctr_encryption_layer.h | 31 | ||||
| -rw-r--r-- | src/core/crypto/encryption_layer.cpp | 42 | ||||
| -rw-r--r-- | src/core/crypto/encryption_layer.h | 30 | ||||
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 410 | ||||
| -rw-r--r-- | src/core/crypto/key_manager.h | 116 | ||||
| -rw-r--r-- | src/core/crypto/sha_util.cpp | 5 | ||||
| -rw-r--r-- | src/core/crypto/sha_util.h | 20 |
10 files changed, 834 insertions, 0 deletions
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp new file mode 100644 index 000000000..46326cdec --- /dev/null +++ b/src/core/crypto/aes_util.cpp | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | namespace Crypto { | ||
| 6 | } // namespace Crypto | ||
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h new file mode 100644 index 000000000..9807b9234 --- /dev/null +++ b/src/core/crypto/aes_util.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "core/file_sys/vfs.h" | ||
| 9 | #include "mbedtls/cipher.h" | ||
| 10 | |||
| 11 | namespace Crypto { | ||
| 12 | |||
| 13 | enum class Mode { | ||
| 14 | CTR = MBEDTLS_CIPHER_AES_128_CTR, | ||
| 15 | ECB = MBEDTLS_CIPHER_AES_128_ECB, | ||
| 16 | XTS = MBEDTLS_CIPHER_AES_128_XTS, | ||
| 17 | }; | ||
| 18 | |||
| 19 | enum class Op { | ||
| 20 | ENCRYPT, | ||
| 21 | DECRYPT, | ||
| 22 | }; | ||
| 23 | |||
| 24 | template <typename Key, size_t KeySize = sizeof(Key)> | ||
| 25 | struct AESCipher { | ||
| 26 | static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8."); | ||
| 27 | static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256."); | ||
| 28 | |||
| 29 | AESCipher(Key key, Mode mode) { | ||
| 30 | mbedtls_cipher_init(&encryption_context); | ||
| 31 | mbedtls_cipher_init(&decryption_context); | ||
| 32 | |||
| 33 | ASSERT_MSG((mbedtls_cipher_setup( | ||
| 34 | &encryption_context, | ||
| 35 | mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) || | ||
| 36 | mbedtls_cipher_setup(&decryption_context, | ||
| 37 | mbedtls_cipher_info_from_type( | ||
| 38 | static_cast<mbedtls_cipher_type_t>(mode)))) == 0, | ||
| 39 | "Failed to initialize mbedtls ciphers."); | ||
| 40 | |||
| 41 | ASSERT( | ||
| 42 | !mbedtls_cipher_setkey(&encryption_context, key.data(), KeySize * 8, MBEDTLS_ENCRYPT)); | ||
| 43 | ASSERT( | ||
| 44 | !mbedtls_cipher_setkey(&decryption_context, key.data(), KeySize * 8, MBEDTLS_DECRYPT)); | ||
| 45 | //"Failed to set key on mbedtls ciphers."); | ||
| 46 | } | ||
| 47 | |||
| 48 | ~AESCipher() { | ||
| 49 | mbedtls_cipher_free(&encryption_context); | ||
| 50 | mbedtls_cipher_free(&decryption_context); | ||
| 51 | } | ||
| 52 | |||
| 53 | void SetIV(std::vector<u8> iv) { | ||
| 54 | ASSERT_MSG((mbedtls_cipher_set_iv(&encryption_context, iv.data(), iv.size()) || | ||
| 55 | mbedtls_cipher_set_iv(&decryption_context, iv.data(), iv.size())) == 0, | ||
| 56 | "Failed to set IV on mbedtls ciphers."); | ||
| 57 | } | ||
| 58 | |||
| 59 | template <typename Source, typename Dest> | ||
| 60 | void Transcode(const Source* src, size_t size, Dest* dest, Op op) { | ||
| 61 | size_t written = 0; | ||
| 62 | |||
| 63 | const auto context = op == Op::ENCRYPT ? &encryption_context : &decryption_context; | ||
| 64 | |||
| 65 | mbedtls_cipher_reset(context); | ||
| 66 | |||
| 67 | if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) { | ||
| 68 | mbedtls_cipher_update(context, reinterpret_cast<const u8*>(src), size, | ||
| 69 | reinterpret_cast<u8*>(dest), &written); | ||
| 70 | if (written != size) | ||
| 71 | LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.", | ||
| 72 | size, written); | ||
| 73 | } else { | ||
| 74 | const auto block_size = mbedtls_cipher_get_block_size(context); | ||
| 75 | |||
| 76 | for (size_t offset = 0; offset < size; offset += block_size) { | ||
| 77 | auto length = std::min<size_t>(block_size, size - offset); | ||
| 78 | mbedtls_cipher_update(context, reinterpret_cast<const u8*>(src) + offset, length, | ||
| 79 | reinterpret_cast<u8*>(dest) + offset, &written); | ||
| 80 | if (written != length) | ||
| 81 | LOG_WARNING(Crypto, | ||
| 82 | "Not all data was decrypted requested={:016X}, actual={:016X}.", | ||
| 83 | length, written); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | mbedtls_cipher_finish(context, nullptr, nullptr); | ||
| 88 | } | ||
| 89 | |||
| 90 | template <typename Source, typename Dest> | ||
| 91 | void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id, | ||
| 92 | size_t sector_size, Op op) { | ||
| 93 | if (size % sector_size > 0) { | ||
| 94 | LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size."); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | |||
| 98 | for (size_t i = 0; i < size; i += sector_size) { | ||
| 99 | SetIV(CalculateNintendoTweak(sector_id++)); | ||
| 100 | Transcode<u8, u8>(reinterpret_cast<const u8*>(src) + i, sector_size, | ||
| 101 | reinterpret_cast<u8*>(dest) + i, op); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | private: | ||
| 106 | mbedtls_cipher_context_t encryption_context; | ||
| 107 | mbedtls_cipher_context_t decryption_context; | ||
| 108 | |||
| 109 | static std::vector<u8> CalculateNintendoTweak(size_t sector_id) { | ||
| 110 | std::vector<u8> out(0x10); | ||
| 111 | for (size_t i = 0xF; i <= 0xF; --i) { | ||
| 112 | out[i] = sector_id & 0xFF; | ||
| 113 | sector_id >>= 8; | ||
| 114 | } | ||
| 115 | return out; | ||
| 116 | } | ||
| 117 | }; | ||
| 118 | } // namespace Crypto | ||
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp new file mode 100644 index 000000000..8799496e2 --- /dev/null +++ b/src/core/crypto/ctr_encryption_layer.cpp | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/crypto/ctr_encryption_layer.h" | ||
| 7 | |||
| 8 | namespace Crypto { | ||
| 9 | CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset) | ||
| 10 | : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), | ||
| 11 | iv(16, 0) {} | ||
| 12 | |||
| 13 | size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const { | ||
| 14 | if (length == 0) | ||
| 15 | return 0; | ||
| 16 | |||
| 17 | const auto sector_offset = offset & 0xF; | ||
| 18 | if (sector_offset == 0) { | ||
| 19 | UpdateIV(base_offset + offset); | ||
| 20 | std::vector<u8> raw = base->ReadBytes(length, offset); | ||
| 21 | if (raw.size() != length) | ||
| 22 | return Read(data, raw.size(), offset); | ||
| 23 | cipher.Transcode(raw.data(), length, data, Op::DECRYPT); | ||
| 24 | return length; | ||
| 25 | } | ||
| 26 | |||
| 27 | // offset does not fall on block boundary (0x10) | ||
| 28 | std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset); | ||
| 29 | UpdateIV(base_offset + offset - sector_offset); | ||
| 30 | cipher.Transcode(block.data(), block.size(), block.data(), Op::DECRYPT); | ||
| 31 | size_t read = 0x10 - sector_offset; | ||
| 32 | |||
| 33 | if (length + sector_offset < 0x10) { | ||
| 34 | memcpy_s(data, length, block.data() + sector_offset, std::min<u64>(length, read)); | ||
| 35 | return read; | ||
| 36 | } | ||
| 37 | |||
| 38 | memcpy_s(data, length, block.data() + sector_offset, read); | ||
| 39 | return read + Read(data + read, length - read, offset + read); | ||
| 40 | } | ||
| 41 | |||
| 42 | void CTREncryptionLayer::SetIV(std::vector<u8> iv_) { | ||
| 43 | const auto length = std::min<size_t>(iv_.size(), iv.size()); | ||
| 44 | for (size_t i = 0; i < length; ++i) | ||
| 45 | iv[i] = iv_[i]; | ||
| 46 | } | ||
| 47 | |||
| 48 | void CTREncryptionLayer::UpdateIV(size_t offset) const { | ||
| 49 | offset >>= 4; | ||
| 50 | for (size_t i = 0; i < 8; ++i) { | ||
| 51 | iv[16 - i - 1] = offset & 0xFF; | ||
| 52 | offset >>= 8; | ||
| 53 | } | ||
| 54 | cipher.SetIV(iv); | ||
| 55 | } | ||
| 56 | } // namespace Crypto | ||
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h new file mode 100644 index 000000000..fe53e714b --- /dev/null +++ b/src/core/crypto/ctr_encryption_layer.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "aes_util.h" | ||
| 8 | #include "encryption_layer.h" | ||
| 9 | #include "key_manager.h" | ||
| 10 | |||
| 11 | namespace Crypto { | ||
| 12 | |||
| 13 | // Sits on top of a VirtualFile and provides CTR-mode AES decription. | ||
| 14 | struct CTREncryptionLayer : public EncryptionLayer { | ||
| 15 | CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset); | ||
| 16 | |||
| 17 | size_t Read(u8* data, size_t length, size_t offset) const override; | ||
| 18 | |||
| 19 | void SetIV(std::vector<u8> iv); | ||
| 20 | |||
| 21 | private: | ||
| 22 | size_t base_offset; | ||
| 23 | |||
| 24 | // Must be mutable as operations modify cipher contexts. | ||
| 25 | mutable AESCipher<Key128> cipher; | ||
| 26 | mutable std::vector<u8> iv; | ||
| 27 | |||
| 28 | void UpdateIV(size_t offset) const; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace Crypto | ||
diff --git a/src/core/crypto/encryption_layer.cpp b/src/core/crypto/encryption_layer.cpp new file mode 100644 index 000000000..4e243051e --- /dev/null +++ b/src/core/crypto/encryption_layer.cpp | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/crypto/encryption_layer.h" | ||
| 6 | |||
| 7 | namespace Crypto { | ||
| 8 | |||
| 9 | EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {} | ||
| 10 | |||
| 11 | std::string EncryptionLayer::GetName() const { | ||
| 12 | return base->GetName(); | ||
| 13 | } | ||
| 14 | |||
| 15 | size_t EncryptionLayer::GetSize() const { | ||
| 16 | return base->GetSize(); | ||
| 17 | } | ||
| 18 | |||
| 19 | bool EncryptionLayer::Resize(size_t new_size) { | ||
| 20 | return false; | ||
| 21 | } | ||
| 22 | |||
| 23 | std::shared_ptr<FileSys::VfsDirectory> EncryptionLayer::GetContainingDirectory() const { | ||
| 24 | return base->GetContainingDirectory(); | ||
| 25 | } | ||
| 26 | |||
| 27 | bool EncryptionLayer::IsWritable() const { | ||
| 28 | return false; | ||
| 29 | } | ||
| 30 | |||
| 31 | bool EncryptionLayer::IsReadable() const { | ||
| 32 | return true; | ||
| 33 | } | ||
| 34 | |||
| 35 | size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) { | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | bool EncryptionLayer::Rename(std::string_view name) { | ||
| 40 | return base->Rename(name); | ||
| 41 | } | ||
| 42 | } // namespace Crypto | ||
diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h new file mode 100644 index 000000000..2312870d8 --- /dev/null +++ b/src/core/crypto/encryption_layer.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | #include "core/file_sys/vfs.h" | ||
| 7 | |||
| 8 | namespace Crypto { | ||
| 9 | |||
| 10 | // Basically non-functional class that implements all of the methods that are irrelevant to an | ||
| 11 | // EncryptionLayer. Reduces duplicate code. | ||
| 12 | struct EncryptionLayer : public FileSys::VfsFile { | ||
| 13 | explicit EncryptionLayer(FileSys::VirtualFile base); | ||
| 14 | |||
| 15 | size_t Read(u8* data, size_t length, size_t offset) const override = 0; | ||
| 16 | |||
| 17 | std::string GetName() const override; | ||
| 18 | size_t GetSize() const override; | ||
| 19 | bool Resize(size_t new_size) override; | ||
| 20 | std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override; | ||
| 21 | bool IsWritable() const override; | ||
| 22 | bool IsReadable() const override; | ||
| 23 | size_t Write(const u8* data, size_t length, size_t offset) override; | ||
| 24 | bool Rename(std::string_view name) override; | ||
| 25 | |||
| 26 | protected: | ||
| 27 | FileSys::VirtualFile base; | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace Crypto | ||
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp new file mode 100644 index 000000000..05c6a70a2 --- /dev/null +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -0,0 +1,410 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <fstream> | ||
| 6 | #include <locale> | ||
| 7 | #include <sstream> | ||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/logging/log.h" | ||
| 10 | #include "core/crypto/key_manager.h" | ||
| 11 | #include "mbedtls/sha256.h" | ||
| 12 | |||
| 13 | namespace 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 | |||
| 241 | static u8 ToHexNibble(char c1) { | ||
| 242 | if (c1 >= 65 && c1 <= 70) | ||
| 243 | return c1 - 55; | ||
| 244 | if (c1 >= 97 && c1 <= 102) | ||
| 245 | return c1 - 87; | ||
| 246 | if (c1 >= 48 && c1 <= 57) | ||
| 247 | return c1 - 48; | ||
| 248 | throw std::logic_error("Invalid hex digit"); | ||
| 249 | } | ||
| 250 | |||
| 251 | template <size_t Size> | ||
| 252 | static std::array<u8, Size> HexStringToArray(std::string_view str) { | ||
| 253 | std::array<u8, Size> out{}; | ||
| 254 | for (size_t i = 0; i < 2 * Size; i += 2) { | ||
| 255 | auto d1 = str[i]; | ||
| 256 | auto d2 = str[i + 1]; | ||
| 257 | out[i / 2] = (ToHexNibble(d1) << 4) | ToHexNibble(d2); | ||
| 258 | } | ||
| 259 | return out; | ||
| 260 | } | ||
| 261 | |||
| 262 | std::array<u8, 16> operator""_array16(const char* str, size_t len) { | ||
| 263 | if (len != 32) | ||
| 264 | throw std::logic_error("Not of correct size."); | ||
| 265 | return HexStringToArray<16>(str); | ||
| 266 | } | ||
| 267 | |||
| 268 | std::array<u8, 32> operator""_array32(const char* str, size_t len) { | ||
| 269 | if (len != 64) | ||
| 270 | throw std::logic_error("Not of correct size."); | ||
| 271 | return HexStringToArray<32>(str); | ||
| 272 | } | ||
| 273 | |||
| 274 | void KeyManager::SetValidationMode(bool dev) { | ||
| 275 | dev_mode = dev; | ||
| 276 | } | ||
| 277 | |||
| 278 | void KeyManager::LoadFromFile(std::string_view filename_, bool is_title_keys) { | ||
| 279 | const auto filename = std::string(filename_); | ||
| 280 | std::ifstream file(filename); | ||
| 281 | if (!file.is_open()) | ||
| 282 | return; | ||
| 283 | |||
| 284 | std::string line; | ||
| 285 | while (std::getline(file, line)) { | ||
| 286 | std::vector<std::string> out; | ||
| 287 | std::stringstream stream(line); | ||
| 288 | std::string item; | ||
| 289 | while (std::getline(stream, item, '=')) | ||
| 290 | out.push_back(std::move(item)); | ||
| 291 | |||
| 292 | if (out.size() != 2) | ||
| 293 | continue; | ||
| 294 | |||
| 295 | out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end()); | ||
| 296 | out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end()); | ||
| 297 | |||
| 298 | if (is_title_keys) { | ||
| 299 | auto rights_id_raw = HexStringToArray<16>(out[0]); | ||
| 300 | u128 rights_id = *reinterpret_cast<std::array<u64, 2>*>(&rights_id_raw); | ||
| 301 | Key128 key = HexStringToArray<16>(out[1]); | ||
| 302 | SetKey(S128KeyType::TITLEKEY, key, rights_id[1], rights_id[0]); | ||
| 303 | } else { | ||
| 304 | std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower); | ||
| 305 | if (s128_file_id.find(out[0]) != s128_file_id.end()) { | ||
| 306 | const auto index = s128_file_id[out[0]]; | ||
| 307 | Key128 key = HexStringToArray<16>(out[1]); | ||
| 308 | SetKey(index.type, key, index.field1, index.field2); | ||
| 309 | } else if (s256_file_id.find(out[0]) != s256_file_id.end()) { | ||
| 310 | const auto index = s256_file_id[out[0]]; | ||
| 311 | Key256 key = HexStringToArray<32>(out[1]); | ||
| 312 | SetKey(index.type, key, index.field1, index.field2); | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) { | ||
| 319 | return s128_keys.find({id, field1, field2}) != s128_keys.end(); | ||
| 320 | } | ||
| 321 | |||
| 322 | bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) { | ||
| 323 | return s256_keys.find({id, field1, field2}) != s256_keys.end(); | ||
| 324 | } | ||
| 325 | |||
| 326 | Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) { | ||
| 327 | if (!HasKey(id, field1, field2)) | ||
| 328 | return {}; | ||
| 329 | return s128_keys[{id, field1, field2}]; | ||
| 330 | } | ||
| 331 | |||
| 332 | Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) { | ||
| 333 | if (!HasKey(id, field1, field2)) | ||
| 334 | return {}; | ||
| 335 | return s256_keys[{id, field1, field2}]; | ||
| 336 | } | ||
| 337 | |||
| 338 | void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { | ||
| 339 | s128_keys[{id, field1, field2}] = key; | ||
| 340 | } | ||
| 341 | |||
| 342 | void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { | ||
| 343 | s256_keys[{id, field1, field2}] = key; | ||
| 344 | } | ||
| 345 | |||
| 346 | bool KeyManager::ValidateKey(S128KeyType key, u64 field1, u64 field2) { | ||
| 347 | auto& hash = dev_mode ? s128_hash_dev : s128_hash_prod; | ||
| 348 | |||
| 349 | KeyIndex<S128KeyType> id = {key, field1, field2}; | ||
| 350 | if (key == S128KeyType::SD_SEED || key == S128KeyType::TITLEKEY || | ||
| 351 | hash.find(id) == hash.end()) { | ||
| 352 | LOG_WARNING(Crypto, "Could not validate [{}]", id.DebugInfo()); | ||
| 353 | return true; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (!HasKey(key, field1, field2)) { | ||
| 357 | LOG_CRITICAL(Crypto, | ||
| 358 | "System has requested validation of [{}], but user has not added it. Add this " | ||
| 359 | "key to use functionality.", | ||
| 360 | id.DebugInfo()); | ||
| 361 | return false; | ||
| 362 | } | ||
| 363 | |||
| 364 | SHA256Hash key_hash{}; | ||
| 365 | const auto a_key = GetKey(key, field1, field2); | ||
| 366 | mbedtls_sha256(a_key.data(), a_key.size(), key_hash.data(), 0); | ||
| 367 | if (key_hash != hash[id]) { | ||
| 368 | LOG_CRITICAL(Crypto, | ||
| 369 | "The hash of the provided key for [{}] does not match the one on file. This " | ||
| 370 | "means you probably have an incorrect key. If you believe this to be in " | ||
| 371 | "error, contact the yuzu devs.", | ||
| 372 | id.DebugInfo()); | ||
| 373 | return false; | ||
| 374 | } | ||
| 375 | |||
| 376 | return true; | ||
| 377 | } | ||
| 378 | |||
| 379 | bool KeyManager::ValidateKey(S256KeyType key, u64 field1, u64 field2) { | ||
| 380 | auto& hash = dev_mode ? s256_hash_dev : s256_hash_prod; | ||
| 381 | |||
| 382 | KeyIndex<S256KeyType> id = {key, field1, field2}; | ||
| 383 | if (hash.find(id) == hash.end()) { | ||
| 384 | LOG_ERROR(Crypto, "Could not validate [{}]", id.DebugInfo()); | ||
| 385 | return true; | ||
| 386 | } | ||
| 387 | |||
| 388 | if (!HasKey(key, field1, field2)) { | ||
| 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 | |||
| 408 | return true; | ||
| 409 | } | ||
| 410 | } // namespace Crypto | ||
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h new file mode 100644 index 000000000..155989e46 --- /dev/null +++ b/src/core/crypto/key_manager.h | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | #include <array> | ||
| 7 | #include <unordered_map> | ||
| 8 | #include <vector> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Crypto { | ||
| 12 | |||
| 13 | typedef std::array<u8, 0x10> Key128; | ||
| 14 | typedef std::array<u8, 0x20> Key256; | ||
| 15 | typedef std::array<u8, 0x20> SHA256Hash; | ||
| 16 | |||
| 17 | static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); | ||
| 18 | static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big."); | ||
| 19 | |||
| 20 | enum class S256KeyType : u64 { | ||
| 21 | HEADER, // | ||
| 22 | SD_SAVE, // | ||
| 23 | SD_NCA, // | ||
| 24 | }; | ||
| 25 | |||
| 26 | enum class S128KeyType : u64 { | ||
| 27 | MASTER, // f1=crypto revision | ||
| 28 | PACKAGE1, // f1=crypto revision | ||
| 29 | PACKAGE2, // f1=crypto revision | ||
| 30 | TITLEKEK, // f1=crypto revision | ||
| 31 | ETICKET_RSA_KEK, // | ||
| 32 | KEY_AREA, // f1=crypto revision f2=type {app, ocean, system} | ||
| 33 | SD_SEED, // | ||
| 34 | TITLEKEY, // f1=rights id LSB f2=rights id MSB | ||
| 35 | }; | ||
| 36 | |||
| 37 | enum class KeyAreaKeyType : u8 { | ||
| 38 | Application, | ||
| 39 | Ocean, | ||
| 40 | System, | ||
| 41 | }; | ||
| 42 | |||
| 43 | template <typename KeyType> | ||
| 44 | struct KeyIndex { | ||
| 45 | KeyType type; | ||
| 46 | u64 field1; | ||
| 47 | u64 field2; | ||
| 48 | |||
| 49 | std::string DebugInfo() { | ||
| 50 | u8 key_size = 16; | ||
| 51 | if (std::is_same_v<KeyType, S256KeyType>) | ||
| 52 | key_size = 32; | ||
| 53 | return fmt::format("key_size={:02X}, key={:02X}, field1={:016X}, field2={:016X}", key_size, | ||
| 54 | static_cast<u8>(type), field1, field2); | ||
| 55 | } | ||
| 56 | }; | ||
| 57 | |||
| 58 | // The following two (== and hash) are so KeyIndex can be a key in unordered_map | ||
| 59 | |||
| 60 | template <typename KeyType> | ||
| 61 | bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) { | ||
| 62 | return lhs.type == rhs.type && lhs.field1 == rhs.field1 && lhs.field2 == rhs.field2; | ||
| 63 | } | ||
| 64 | |||
| 65 | } // namespace Crypto | ||
| 66 | |||
| 67 | namespace std { | ||
| 68 | template <typename KeyType> | ||
| 69 | struct hash<Crypto::KeyIndex<KeyType>> { | ||
| 70 | size_t operator()(const Crypto::KeyIndex<KeyType>& k) const { | ||
| 71 | using std::hash; | ||
| 72 | |||
| 73 | return ((hash<u64>()(static_cast<u64>(k.type)) ^ (hash<u64>()(k.field1) << 1)) >> 1) ^ | ||
| 74 | (hash<u64>()(k.field2) << 1); | ||
| 75 | } | ||
| 76 | }; | ||
| 77 | } // namespace std | ||
| 78 | |||
| 79 | namespace Crypto { | ||
| 80 | |||
| 81 | std::array<u8, 0x10> operator"" _array16(const char* str, size_t len); | ||
| 82 | std::array<u8, 0x20> operator"" _array32(const char* str, size_t len); | ||
| 83 | |||
| 84 | struct KeyManager { | ||
| 85 | void SetValidationMode(bool dev); | ||
| 86 | void LoadFromFile(std::string_view filename, bool is_title_keys); | ||
| 87 | |||
| 88 | bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0); | ||
| 89 | bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0); | ||
| 90 | |||
| 91 | Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0); | ||
| 92 | Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0); | ||
| 93 | |||
| 94 | void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); | ||
| 95 | void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); | ||
| 96 | |||
| 97 | bool ValidateKey(S128KeyType key, u64 field1 = 0, u64 field2 = 0); | ||
| 98 | bool ValidateKey(S256KeyType key, u64 field1 = 0, u64 field2 = 0); | ||
| 99 | |||
| 100 | private: | ||
| 101 | std::unordered_map<KeyIndex<S128KeyType>, Key128> s128_keys; | ||
| 102 | std::unordered_map<KeyIndex<S256KeyType>, Key256> s256_keys; | ||
| 103 | |||
| 104 | bool dev_mode = false; | ||
| 105 | |||
| 106 | static std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> s128_hash_prod; | ||
| 107 | static std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> s256_hash_prod; | ||
| 108 | static std::unordered_map<KeyIndex<S128KeyType>, SHA256Hash> s128_hash_dev; | ||
| 109 | static std::unordered_map<KeyIndex<S256KeyType>, SHA256Hash> s256_hash_dev; | ||
| 110 | static std::unordered_map<std::string, KeyIndex<S128KeyType>> s128_file_id; | ||
| 111 | static std::unordered_map<std::string, KeyIndex<S256KeyType>> s256_file_id; | ||
| 112 | }; | ||
| 113 | |||
| 114 | extern KeyManager keys; | ||
| 115 | |||
| 116 | } // namespace Crypto | ||
diff --git a/src/core/crypto/sha_util.cpp b/src/core/crypto/sha_util.cpp new file mode 100644 index 000000000..180008a85 --- /dev/null +++ b/src/core/crypto/sha_util.cpp | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | namespace Crypto {} // namespace Crypto | ||
diff --git a/src/core/crypto/sha_util.h b/src/core/crypto/sha_util.h new file mode 100644 index 000000000..fa3fa9d33 --- /dev/null +++ b/src/core/crypto/sha_util.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "core/file_sys/vfs.h" | ||
| 9 | #include "key_manager.h" | ||
| 10 | #include "mbedtls/cipher.h" | ||
| 11 | |||
| 12 | namespace Crypto { | ||
| 13 | typedef std::array<u8, 0x20> SHA256Hash; | ||
| 14 | |||
| 15 | inline SHA256Hash operator"" _HASH(const char* data, size_t len) { | ||
| 16 | if (len != 0x40) | ||
| 17 | return {}; | ||
| 18 | } | ||
| 19 | |||
| 20 | } // namespace Crypto | ||