diff options
Diffstat (limited to '')
| -rw-r--r-- | src/common/file_util.cpp | 2 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/crypto/aes_util.cpp | 102 | ||||
| -rw-r--r-- | src/core/crypto/aes_util.h | 106 | ||||
| -rw-r--r-- | src/core/file_sys/content_archive.h | 3 |
5 files changed, 127 insertions, 87 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 89004c3c0..a26702f54 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -739,7 +739,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) { | |||
| 739 | std::string GetHactoolConfigurationPath() { | 739 | std::string GetHactoolConfigurationPath() { |
| 740 | #ifdef _WIN32 | 740 | #ifdef _WIN32 |
| 741 | char path[MAX_PATH]; | 741 | char path[MAX_PATH]; |
| 742 | if (SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path) != S_OK) | 742 | if (SHGetFolderPathA(nullptr, CSIDL_PROFILE, nullptr, 0, path) != S_OK) |
| 743 | return ""; | 743 | return ""; |
| 744 | std::string local_path = Common::StringFromFixedZeroTerminatedBuffer(path, MAX_PATH); | 744 | std::string local_path = Common::StringFromFixedZeroTerminatedBuffer(path, MAX_PATH); |
| 745 | return local_path + "\\.switch"; | 745 | return local_path + "\\.switch"; |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a69ee9146..528d96a58 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -12,6 +12,7 @@ add_library(core STATIC | |||
| 12 | core_timing.h | 12 | core_timing.h |
| 13 | core_timing_util.cpp | 13 | core_timing_util.cpp |
| 14 | core_timing_util.h | 14 | core_timing_util.h |
| 15 | crypto/aes_util.cpp | ||
| 15 | crypto/aes_util.h | 16 | crypto/aes_util.h |
| 16 | crypto/encryption_layer.cpp | 17 | crypto/encryption_layer.cpp |
| 17 | crypto/encryption_layer.h | 18 | crypto/encryption_layer.h |
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp index 46326cdec..a9646e52f 100644 --- a/src/core/crypto/aes_util.cpp +++ b/src/core/crypto/aes_util.cpp | |||
| @@ -2,5 +2,103 @@ | |||
| 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 | namespace Crypto { | 5 | #include "core/crypto/aes_util.h" |
| 6 | } // namespace Crypto | 6 | #include "mbedtls/cipher.h" |
| 7 | |||
| 8 | namespace Core::Crypto { | ||
| 9 | static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR), "CTR mode is incorrect."); | ||
| 10 | static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB), "ECB mode is incorrect."); | ||
| 11 | static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS), "XTS mode is incorrect."); | ||
| 12 | |||
| 13 | template<typename Key, size_t KeySize> | ||
| 14 | Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode) { | ||
| 15 | mbedtls_cipher_init(encryption_context.get()); | ||
| 16 | mbedtls_cipher_init(decryption_context.get()); | ||
| 17 | |||
| 18 | ASSERT_MSG((mbedtls_cipher_setup( | ||
| 19 | encryption_context.get(), | ||
| 20 | mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) || | ||
| 21 | mbedtls_cipher_setup(decryption_context.get(), | ||
| 22 | mbedtls_cipher_info_from_type( | ||
| 23 | static_cast<mbedtls_cipher_type_t>(mode)))) == 0, | ||
| 24 | "Failed to initialize mbedtls ciphers."); | ||
| 25 | |||
| 26 | ASSERT( | ||
| 27 | !mbedtls_cipher_setkey(encryption_context.get(), key.data(), KeySize * 8, MBEDTLS_ENCRYPT)); | ||
| 28 | ASSERT( | ||
| 29 | !mbedtls_cipher_setkey(decryption_context.get(), key.data(), KeySize * 8, MBEDTLS_DECRYPT)); | ||
| 30 | //"Failed to set key on mbedtls ciphers."); | ||
| 31 | } | ||
| 32 | |||
| 33 | template<typename Key, size_t KeySize> | ||
| 34 | AESCipher<Key, KeySize>::~AESCipher() { | ||
| 35 | mbedtls_cipher_free(encryption_context.get()); | ||
| 36 | mbedtls_cipher_free(decryption_context.get()); | ||
| 37 | } | ||
| 38 | |||
| 39 | template<typename Key, size_t KeySize> | ||
| 40 | void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) { | ||
| 41 | ASSERT_MSG((mbedtls_cipher_set_iv(encryption_context.get(), iv.data(), iv.size()) || | ||
| 42 | mbedtls_cipher_set_iv(decryption_context.get(), iv.data(), iv.size())) == 0, | ||
| 43 | "Failed to set IV on mbedtls ciphers."); | ||
| 44 | } | ||
| 45 | |||
| 46 | template<typename Key, size_t KeySize> | ||
| 47 | void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) { | ||
| 48 | size_t written = 0; | ||
| 49 | |||
| 50 | const auto context = op == Op::Encrypt ? encryption_context.get() : decryption_context.get(); | ||
| 51 | |||
| 52 | mbedtls_cipher_reset(context); | ||
| 53 | |||
| 54 | if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) { | ||
| 55 | mbedtls_cipher_update(context, src, size, | ||
| 56 | dest, &written); | ||
| 57 | if (written != size) | ||
| 58 | LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.", | ||
| 59 | size, written); | ||
| 60 | } else { | ||
| 61 | const auto block_size = mbedtls_cipher_get_block_size(context); | ||
| 62 | |||
| 63 | for (size_t offset = 0; offset < size; offset += block_size) { | ||
| 64 | auto length = std::min<size_t>(block_size, size - offset); | ||
| 65 | mbedtls_cipher_update(context, src + offset, length, | ||
| 66 | dest + offset, &written); | ||
| 67 | if (written != length) | ||
| 68 | LOG_WARNING(Crypto, | ||
| 69 | "Not all data was decrypted requested={:016X}, actual={:016X}.", | ||
| 70 | length, written); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | mbedtls_cipher_finish(context, nullptr, nullptr); | ||
| 75 | } | ||
| 76 | |||
| 77 | template<typename Key, size_t KeySize> | ||
| 78 | void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, | ||
| 79 | Op op) { | ||
| 80 | if (size % sector_size > 0) { | ||
| 81 | LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size."); | ||
| 82 | return; | ||
| 83 | } | ||
| 84 | |||
| 85 | for (size_t i = 0; i < size; i += sector_size) { | ||
| 86 | SetIV(CalculateNintendoTweak(sector_id++)); | ||
| 87 | Transcode<u8, u8>(src + i, sector_size, | ||
| 88 | dest + i, op); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | template<typename Key, size_t KeySize> | ||
| 93 | std::vector<u8> AESCipher<Key, KeySize>::CalculateNintendoTweak(size_t sector_id) { | ||
| 94 | std::vector<u8> out(0x10); | ||
| 95 | for (size_t i = 0xF; i <= 0xF; --i) { | ||
| 96 | out[i] = sector_id & 0xFF; | ||
| 97 | sector_id >>= 8; | ||
| 98 | } | ||
| 99 | return out; | ||
| 100 | } | ||
| 101 | |||
| 102 | template class AESCipher<Key128>; | ||
| 103 | template class AESCipher<Key256>; | ||
| 104 | } \ No newline at end of file | ||
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h index 9807b9234..5c09718b2 100644 --- a/src/core/crypto/aes_util.h +++ b/src/core/crypto/aes_util.h | |||
| @@ -6,113 +6,53 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "core/file_sys/vfs.h" | 8 | #include "core/file_sys/vfs.h" |
| 9 | #include "mbedtls/cipher.h" | ||
| 10 | 9 | ||
| 11 | namespace Crypto { | 10 | namespace Core::Crypto { |
| 12 | 11 | ||
| 13 | enum class Mode { | 12 | enum class Mode { |
| 14 | CTR = MBEDTLS_CIPHER_AES_128_CTR, | 13 | CTR = 11, |
| 15 | ECB = MBEDTLS_CIPHER_AES_128_ECB, | 14 | ECB = 2, |
| 16 | XTS = MBEDTLS_CIPHER_AES_128_XTS, | 15 | XTS = 70, |
| 17 | }; | 16 | }; |
| 18 | 17 | ||
| 19 | enum class Op { | 18 | enum class Op { |
| 20 | ENCRYPT, | 19 | Encrypt, |
| 21 | DECRYPT, | 20 | Decrypt, |
| 22 | }; | 21 | }; |
| 23 | 22 | ||
| 23 | struct mbedtls_cipher_context_t; | ||
| 24 | |||
| 24 | template <typename Key, size_t KeySize = sizeof(Key)> | 25 | template <typename Key, size_t KeySize = sizeof(Key)> |
| 25 | struct AESCipher { | 26 | class AESCipher { |
| 26 | static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8."); | 27 | 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 | static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256."); |
| 28 | 29 | ||
| 29 | AESCipher(Key key, Mode mode) { | 30 | public: |
| 30 | mbedtls_cipher_init(&encryption_context); | 31 | AESCipher(Key key, Mode mode); |
| 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 | 32 | ||
| 48 | ~AESCipher() { | 33 | ~AESCipher(); |
| 49 | mbedtls_cipher_free(&encryption_context); | ||
| 50 | mbedtls_cipher_free(&decryption_context); | ||
| 51 | } | ||
| 52 | 34 | ||
| 53 | void SetIV(std::vector<u8> iv) { | 35 | 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 | 36 | ||
| 59 | template <typename Source, typename Dest> | 37 | template <typename Source, typename Dest> |
| 60 | void Transcode(const Source* src, size_t size, Dest* dest, Op op) { | 38 | void Transcode(const Source* src, size_t size, Dest* dest, Op op) { |
| 61 | size_t written = 0; | 39 | Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op); |
| 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 | } | 40 | } |
| 89 | 41 | ||
| 42 | void Transcode(const u8* src, size_t size, u8* dest, Op op); | ||
| 43 | |||
| 90 | template <typename Source, typename Dest> | 44 | template <typename Source, typename Dest> |
| 91 | 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, |
| 92 | size_t sector_size, Op op) { | 46 | size_t sector_size, Op op) { |
| 93 | if (size % sector_size > 0) { | 47 | XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id, sector_size, op); |
| 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 | } | 48 | } |
| 104 | 49 | ||
| 50 | void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size, Op op); | ||
| 51 | |||
| 105 | private: | 52 | private: |
| 106 | mbedtls_cipher_context_t encryption_context; | 53 | std::unique_ptr<mbedtls_cipher_context_t> encryption_context; |
| 107 | mbedtls_cipher_context_t decryption_context; | 54 | std::unique_ptr<mbedtls_cipher_context_t> decryption_context; |
| 108 | 55 | ||
| 109 | static std::vector<u8> CalculateNintendoTweak(size_t sector_id) { | 56 | 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 | }; | 57 | }; |
| 118 | } // namespace Crypto | 58 | } // namespace Crypto |
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 1e8d9c8ae..d9ad3bf7e 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "core/loader/loader.h" | ||
| 12 | #include "common/common_funcs.h" | 13 | #include "common/common_funcs.h" |
| 13 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 14 | #include "common/swap.h" | 15 | #include "common/swap.h" |
| @@ -108,7 +109,7 @@ private: | |||
| 108 | 109 | ||
| 109 | Crypto::Key128 GetKeyAreaKey(NCASectionCryptoType type); | 110 | Crypto::Key128 GetKeyAreaKey(NCASectionCryptoType type); |
| 110 | 111 | ||
| 111 | VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, size_t starting_offset); | 112 | VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset); |
| 112 | }; | 113 | }; |
| 113 | 114 | ||
| 114 | } // namespace FileSys | 115 | } // namespace FileSys |