diff options
| author | 2018-08-16 17:01:32 -0400 | |
|---|---|---|
| committer | 2018-08-23 11:52:44 -0400 | |
| commit | c4845df3d4b9fc3fc19dd936af87090ffb3fbdf2 (patch) | |
| tree | 7bca82326831ee20fc73a4fb2d609825cce8fad3 /src | |
| parent | aes_util: Make XTSTranscode stricter about sizes (diff) | |
| download | yuzu-c4845df3d4b9fc3fc19dd936af87090ffb3fbdf2.tar.gz yuzu-c4845df3d4b9fc3fc19dd936af87090ffb3fbdf2.tar.xz yuzu-c4845df3d4b9fc3fc19dd936af87090ffb3fbdf2.zip | |
xts_encryption_layer: Implement XTSEncryptionLayer
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/crypto/xts_encryption_layer.cpp | 54 | ||||
| -rw-r--r-- | src/core/crypto/xts_encryption_layer.h | 26 | ||||
| -rw-r--r-- | src/core/file_sys/content_archive.cpp | 2 |
3 files changed, 81 insertions, 1 deletions
diff --git a/src/core/crypto/xts_encryption_layer.cpp b/src/core/crypto/xts_encryption_layer.cpp new file mode 100644 index 000000000..431099580 --- /dev/null +++ b/src/core/crypto/xts_encryption_layer.cpp | |||
| @@ -0,0 +1,54 @@ | |||
| 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 <cstring> | ||
| 6 | #include "common/assert.h" | ||
| 7 | #include "core/crypto/xts_encryption_layer.h" | ||
| 8 | |||
| 9 | namespace Core::Crypto { | ||
| 10 | |||
| 11 | XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_) | ||
| 12 | : EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {} | ||
| 13 | |||
| 14 | size_t XTSEncryptionLayer::Read(u8* data, size_t length, size_t offset) const { | ||
| 15 | if (length == 0) | ||
| 16 | return 0; | ||
| 17 | |||
| 18 | const auto sector_offset = offset & 0x3FFF; | ||
| 19 | if (sector_offset == 0) { | ||
| 20 | if (length % 0x4000 == 0) { | ||
| 21 | std::vector<u8> raw = base->ReadBytes(length, offset); | ||
| 22 | cipher.XTSTranscode(raw.data(), raw.size(), data, offset / 0x4000, 0x4000, Op::Decrypt); | ||
| 23 | return raw.size(); | ||
| 24 | } | ||
| 25 | if (length > 0x4000) { | ||
| 26 | const auto rem = length % 0x4000; | ||
| 27 | const auto read = length - rem; | ||
| 28 | return Read(data, read, offset) + Read(data + read, rem, offset + read); | ||
| 29 | } | ||
| 30 | std::vector<u8> buffer = base->ReadBytes(0x4000, offset); | ||
| 31 | if (buffer.size() < 0x4000) | ||
| 32 | buffer.resize(0x4000); | ||
| 33 | cipher.XTSTranscode(buffer.data(), buffer.size(), buffer.data(), offset / 0x4000, 0x4000, | ||
| 34 | Op::Decrypt); | ||
| 35 | std::memcpy(data, buffer.data(), std::min(buffer.size(), length)); | ||
| 36 | return std::min(buffer.size(), length); | ||
| 37 | } | ||
| 38 | |||
| 39 | // offset does not fall on block boundary (0x4000) | ||
| 40 | std::vector<u8> block = base->ReadBytes(0x4000, offset - sector_offset); | ||
| 41 | if (block.size() < 0x4000) | ||
| 42 | block.resize(0x4000); | ||
| 43 | cipher.XTSTranscode(block.data(), block.size(), block.data(), (offset - sector_offset) / 0x4000, | ||
| 44 | 0x4000, Op::Decrypt); | ||
| 45 | const size_t read = 0x4000 - sector_offset; | ||
| 46 | |||
| 47 | if (length + sector_offset < 0x4000) { | ||
| 48 | std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read)); | ||
| 49 | return std::min<u64>(length, read); | ||
| 50 | } | ||
| 51 | std::memcpy(data, block.data() + sector_offset, read); | ||
| 52 | return read + Read(data + read, length - read, offset + read); | ||
| 53 | } | ||
| 54 | } // namespace Core::Crypto | ||
diff --git a/src/core/crypto/xts_encryption_layer.h b/src/core/crypto/xts_encryption_layer.h new file mode 100644 index 000000000..1e1acaf4a --- /dev/null +++ b/src/core/crypto/xts_encryption_layer.h | |||
| @@ -0,0 +1,26 @@ | |||
| 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 <vector> | ||
| 8 | #include "core/crypto/aes_util.h" | ||
| 9 | #include "core/crypto/encryption_layer.h" | ||
| 10 | #include "core/crypto/key_manager.h" | ||
| 11 | |||
| 12 | namespace Core::Crypto { | ||
| 13 | |||
| 14 | // Sits on top of a VirtualFile and provides XTS-mode AES decription. | ||
| 15 | class XTSEncryptionLayer : public EncryptionLayer { | ||
| 16 | public: | ||
| 17 | XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key); | ||
| 18 | |||
| 19 | size_t Read(u8* data, size_t length, size_t offset) const override; | ||
| 20 | |||
| 21 | private: | ||
| 22 | // Must be mutable as operations modify cipher contexts. | ||
| 23 | mutable AESCipher<Key256> cipher; | ||
| 24 | }; | ||
| 25 | |||
| 26 | } // namespace Core::Crypto | ||
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 47afcad9b..008e11d8c 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -178,7 +178,7 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting | |||
| 178 | return std::static_pointer_cast<VfsFile>(out); | 178 | return std::static_pointer_cast<VfsFile>(out); |
| 179 | } | 179 | } |
| 180 | case NCASectionCryptoType::XTS: | 180 | case NCASectionCryptoType::XTS: |
| 181 | // TODO(DarkLordZach): Implement XTSEncryptionLayer. | 181 | // TODO(DarkLordZach): Find a test case for XTS-encrypted NCAs |
| 182 | default: | 182 | default: |
| 183 | LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}", | 183 | LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}", |
| 184 | static_cast<u8>(s_header.raw.header.crypto_type)); | 184 | static_cast<u8>(s_header.raw.header.crypto_type)); |