|
|
|
@ -6,11 +6,11 @@ |
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <array>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <boost/container/static_vector.hpp>
|
|
|
|
#include "common/alignment.h"
|
|
|
|
#include "common/swap.h"
|
|
|
|
#include "core/file_sys/fssystem/fssystem_aes_xts_storage.h"
|
|
|
|
#include "core/file_sys/fssystem/fssystem_nca_header.h"
|
|
|
|
#include "core/file_sys/fssystem/fssystem_utility.h"
|
|
|
|
|
|
|
|
namespace FileSys { |
|
|
|
@ -45,18 +45,12 @@ AesXtsStorage::AesXtsStorage(VirtualFile base, const void* key1, const void* key |
|
|
|
|
|
|
|
size_t AesXtsStorage::Read(u8* buffer, size_t size, size_t offset) const { |
|
|
|
// Allow zero-size reads.
|
|
|
|
if (size == 0) { |
|
|
|
if (size == 0) |
|
|
|
return size; |
|
|
|
} |
|
|
|
|
|
|
|
// Ensure buffer is valid.
|
|
|
|
// Ensure buffer is valid and we can only read at block aligned offsets.
|
|
|
|
ASSERT(buffer != nullptr); |
|
|
|
|
|
|
|
// We can only read at block aligned offsets.
|
|
|
|
ASSERT(Common::IsAligned(offset, AesBlockSize)); |
|
|
|
ASSERT(Common::IsAligned(size, AesBlockSize)); |
|
|
|
|
|
|
|
// Read the data.
|
|
|
|
ASSERT(Common::IsAligned(offset, AesBlockSize) && Common::IsAligned(size, AesBlockSize)); |
|
|
|
m_base_storage->Read(buffer, size, offset); |
|
|
|
|
|
|
|
// Setup the counter.
|
|
|
|
@ -64,29 +58,21 @@ size_t AesXtsStorage::Read(u8* buffer, size_t size, size_t offset) const { |
|
|
|
std::memcpy(ctr.data(), m_iv.data(), IvSize); |
|
|
|
AddCounter(ctr.data(), IvSize, offset / m_block_size); |
|
|
|
|
|
|
|
// Handle any unaligned data before the start.
|
|
|
|
// Handle any unaligned data before the start; then read said data into a local pooled
|
|
|
|
// buffer that resides on the stack, do not use the global memory allocator this is a
|
|
|
|
// very tiny (512 bytes) buffer so should be fine to keep on the stack (Nca::XtsBlockSize wide buffer)
|
|
|
|
size_t processed_size = 0; |
|
|
|
if ((offset % m_block_size) != 0) { |
|
|
|
// Decrypt into our pooled stack buffer (max bound = NCA::XtsBlockSize)
|
|
|
|
boost::container::static_vector<u8, NcaHeader::XtsBlockSize> tmp_buf; |
|
|
|
// Determine the size of the pre-data read.
|
|
|
|
const size_t skip_size = |
|
|
|
static_cast<size_t>(offset - Common::AlignDown(offset, m_block_size)); |
|
|
|
const size_t data_size = (std::min)(size, m_block_size - skip_size); |
|
|
|
|
|
|
|
// Decrypt into a thread-local pooled buffer to avoid per-call allocations.
|
|
|
|
{ |
|
|
|
thread_local std::vector<u8> tmp_buf; |
|
|
|
if (tmp_buf.size() < m_block_size) { |
|
|
|
tmp_buf.resize(m_block_size); |
|
|
|
} |
|
|
|
std::fill_n(tmp_buf.begin(), m_block_size, u8{0}); |
|
|
|
auto const skip_size = size_t(offset - Common::AlignDown(offset, m_block_size)); |
|
|
|
auto const data_size = (std::min)(size, m_block_size - skip_size); |
|
|
|
std::fill_n(tmp_buf.begin(), skip_size, u8{0}); |
|
|
|
std::memcpy(tmp_buf.data() + skip_size, buffer, data_size); |
|
|
|
|
|
|
|
m_cipher->SetIV(ctr); |
|
|
|
m_cipher->Transcode(tmp_buf.data(), m_block_size, tmp_buf.data(), |
|
|
|
Core::Crypto::Op::Decrypt); |
|
|
|
|
|
|
|
m_cipher->Transcode(tmp_buf.data(), m_block_size, tmp_buf.data(), Core::Crypto::Op::Decrypt); |
|
|
|
std::memcpy(buffer, tmp_buf.data() + skip_size, data_size); |
|
|
|
} |
|
|
|
|
|
|
|
AddCounter(ctr.data(), IvSize, 1); |
|
|
|
processed_size += data_size; |
|
|
|
@ -94,20 +80,16 @@ size_t AesXtsStorage::Read(u8* buffer, size_t size, size_t offset) const { |
|
|
|
} |
|
|
|
|
|
|
|
// Decrypt aligned chunks.
|
|
|
|
char* cur = reinterpret_cast<char*>(buffer) + processed_size; |
|
|
|
size_t remaining = size - processed_size; |
|
|
|
while (remaining > 0) { |
|
|
|
const size_t cur_size = (std::min)(m_block_size, remaining); |
|
|
|
|
|
|
|
auto* cur = buffer + processed_size; |
|
|
|
for (size_t remaining = size - processed_size; remaining > 0; ) { |
|
|
|
auto const cur_size = (std::min)(m_block_size, remaining); |
|
|
|
m_cipher->SetIV(ctr); |
|
|
|
m_cipher->Transcode(cur, cur_size, cur, Core::Crypto::Op::Decrypt); |
|
|
|
|
|
|
|
auto* char_cur = reinterpret_cast<char*>(cur); //same repr cur - diff signedness
|
|
|
|
m_cipher->Transcode(char_cur, cur_size, char_cur, Core::Crypto::Op::Decrypt); |
|
|
|
remaining -= cur_size; |
|
|
|
cur += cur_size; |
|
|
|
|
|
|
|
AddCounter(ctr.data(), IvSize, 1); |
|
|
|
} |
|
|
|
|
|
|
|
return size; |
|
|
|
} |
|
|
|
|
|
|
|
|