Browse Source

use stack pooled vectors

Signed-off-by: lizzie <lizzie@eden-emu.dev>
pull/2750/head
lizzie 5 months ago
committed by crueter
parent
commit
e374baffa8
  1. 13
      src/core/crypto/aes_util.cpp
  2. 24
      src/core/crypto/ctr_encryption_layer.cpp
  3. 33
      src/core/crypto/xts_encryption_layer.cpp
  4. 31
      src/core/file_sys/fssystem/fssystem_aes_ctr_storage.cpp
  5. 56
      src/core/file_sys/fssystem/fssystem_aes_xts_storage.cpp

13
src/core/crypto/aes_util.cpp

@ -73,15 +73,11 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
mbedtls_cipher_reset(context);
// Only ECB strictly requires block sized chunks.
const auto mode = mbedtls_cipher_get_cipher_mode(context);
std::size_t written = 0;
if (mode != MBEDTLS_MODE_ECB) {
if (mbedtls_cipher_get_cipher_mode(context) != MBEDTLS_MODE_ECB) {
mbedtls_cipher_update(context, src, size, dest, &written);
if (written != size) {
LOG_WARNING(Crypto, "Not all data was processed requested={:016X}, actual={:016X}.",
size, written);
}
if (written != size)
LOG_WARNING(Crypto, "Not all data was processed requested={:016X}, actual={:016X}.", size, written);
return;
}
@ -106,8 +102,7 @@ void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* des
std::memcpy(dest + offset, block.data(), length);
return;
}
LOG_WARNING(Crypto, "Not all data was processed requested={:016X}, actual={:016X}.",
length, written);
LOG_WARNING(Crypto, "Not all data was processed requested={:016X}, actual={:016X}.", length, written);
}
}
}

24
src/core/crypto/ctr_encryption_layer.cpp

@ -12,26 +12,18 @@ CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
: EncryptionLayer(std::move(base_)), base_offset(base_offset_), cipher(key_, Mode::CTR) {}
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
if (length == 0) {
if (length == 0)
return 0;
}
std::size_t total_read = 0;
// Handle an initial misaligned portion if needed.
const auto sector_offset = offset & 0xF;
if (sector_offset != 0) {
if (auto const sector_offset = offset & 0xF; sector_offset != 0) {
const std::size_t aligned_off = offset - sector_offset;
std::array<u8, 0x10> block{};
const std::size_t got = base->Read(block.data(), block.size(), aligned_off);
if (got == 0) {
return 0;
}
if (auto const got = base->Read(block.data(), block.size(), aligned_off); got != 0) {
UpdateIV(base_offset + aligned_off);
cipher.Transcode(block.data(), got, block.data(), Op::Decrypt);
const std::size_t to_copy = std::min<std::size_t>(length, got > sector_offset ? got - sector_offset : 0);
auto const to_copy = std::min<std::size_t>(length, got > sector_offset ? got - sector_offset : 0);
if (to_copy > 0) {
std::memcpy(data, block.data() + sector_offset, to_copy);
data += to_copy;
@ -39,12 +31,11 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
length -= to_copy;
total_read += to_copy;
}
} else {
return 0;
}
if (length == 0) {
return total_read;
}
if (length > 0) {
// Now aligned to 0x10
UpdateIV(base_offset + offset);
const std::size_t got = base->Read(data, length, offset);
@ -52,6 +43,7 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
cipher.Transcode(data, got, data, Op::Decrypt);
total_read += got;
}
}
return total_read;
}

33
src/core/crypto/xts_encryption_layer.cpp

@ -17,29 +17,21 @@ XTSEncryptionLayer::XTSEncryptionLayer(FileSys::VirtualFile base_, Key256 key_)
: EncryptionLayer(std::move(base_)), cipher(key_, Mode::XTS) {}
std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
if (length == 0) {
if (length == 0)
return 0;
}
std::size_t total_read = 0;
const std::size_t sector_size = XTS_SECTOR_SIZE;
const std::size_t sector_offset = offset % sector_size;
// Handle initial unaligned part within a sector.
if (sector_offset != 0) {
if (auto const sector_offset = offset % XTS_SECTOR_SIZE; sector_offset != 0) {
const std::size_t aligned_off = offset - sector_offset;
std::array<u8, XTS_SECTOR_SIZE> block{};
std::size_t got = base->Read(block.data(), sector_size, aligned_off);
if (got == 0) {
return 0;
}
if (got < sector_size) {
std::memset(block.data() + got, 0, sector_size - got);
}
cipher.XTSTranscode(block.data(), sector_size, block.data(), aligned_off / sector_size,
sector_size, Op::Decrypt);
if (auto const got = base->Read(block.data(), XTS_SECTOR_SIZE, aligned_off); got > 0) {
if (got < XTS_SECTOR_SIZE)
std::memset(block.data() + got, 0, XTS_SECTOR_SIZE - got);
cipher.XTSTranscode(block.data(), XTS_SECTOR_SIZE, block.data(), aligned_off / XTS_SECTOR_SIZE,
XTS_SECTOR_SIZE, Op::Decrypt);
const std::size_t to_copy = std::min<std::size_t>(length, got > sector_offset ? got - sector_offset : 0);
auto const to_copy = std::min<std::size_t>(length, got > sector_offset ? got - sector_offset : 0);
if (to_copy > 0) {
std::memcpy(data, block.data() + sector_offset, to_copy);
data += to_copy;
@ -47,12 +39,12 @@ std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
length -= to_copy;
total_read += to_copy;
}
} else {
return 0;
}
if (length == 0) {
return total_read;
}
if (length > 0) {
// Process aligned middle inplace, in sector sized multiples.
while (length >= sector_size) {
const std::size_t req = (length / sector_size) * sector_size;
@ -74,7 +66,6 @@ std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
break;
}
}
// Handle tail within a sector, if any.
if (length > 0) {
std::array<u8, XTS_SECTOR_SIZE> block{};
@ -90,7 +81,7 @@ std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
total_read += to_copy;
}
}
}
return total_read;
}
} // namespace Core::Crypto

31
src/core/file_sys/fssystem/fssystem_aes_ctr_storage.cpp

@ -4,8 +4,8 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <boost/container/static_vector.hpp>
#include "common/alignment.h"
#include <vector>
#include "common/swap.h"
#include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h"
#include "core/file_sys/fssystem/fssystem_utility.h"
@ -84,35 +84,24 @@ size_t AesCtrStorage::Write(const u8* buffer, size_t size, size_t offset) {
std::memcpy(ctr.data(), m_iv.data(), IvSize);
AddCounter(ctr.data(), IvSize, offset / BlockSize);
// Loop until all data is written.
size_t remaining = size;
s64 cur_offset = 0;
// Get a pooled buffer.
thread_local std::vector<u8> pooled_buffer;
if (pooled_buffer.size() < BlockSize) {
pooled_buffer.resize(BlockSize);
}
while (remaining > 0) {
// Loop until all data is written using a pooled buffer residing on the stack (blocksize = 0x10)
boost::container::static_vector<u8, BlockSize> pooled_buffer;
for (size_t remaining = size; remaining > 0; ) {
// Determine data we're writing and where.
const size_t write_size = std::min(pooled_buffer.size(), remaining);
auto const write_size = (std::min)(pooled_buffer.size(), remaining);
u8* write_buf = pooled_buffer.data();
// Encrypt the data.
// Encrypt the data and then write it.
m_cipher->SetIV(ctr);
m_cipher->Transcode(buffer, write_size, write_buf, Core::Crypto::Op::Encrypt);
m_base_storage->Write(write_buf, write_size, offset);
// Write the encrypted data.
m_base_storage->Write(write_buf, write_size, offset + cur_offset);
// Advance.
cur_offset += write_size;
// Advance next write chunk
offset += write_size;
remaining -= write_size;
if (remaining > 0) {
if (remaining > 0)
AddCounter(ctr.data(), IvSize, write_size / BlockSize);
}
}
return size;
}

56
src/core/file_sys/fssystem/fssystem_aes_xts_storage.cpp

@ -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;
}

Loading…
Cancel
Save