|
|
|
@ -20,67 +20,49 @@ std::size_t XTSEncryptionLayer::Read(u8* data, std::size_t length, std::size_t o |
|
|
|
if (length == 0) |
|
|
|
return 0; |
|
|
|
|
|
|
|
constexpr std::size_t PrefetchSectors = 4; |
|
|
|
|
|
|
|
auto* out = data; |
|
|
|
std::size_t remaining = length; |
|
|
|
std::size_t current_offset = offset; |
|
|
|
std::size_t total_read = 0; |
|
|
|
// Handle initial unaligned part within a sector.
|
|
|
|
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{}; |
|
|
|
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); |
|
|
|
|
|
|
|
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; |
|
|
|
offset += to_copy; |
|
|
|
length -= to_copy; |
|
|
|
total_read += to_copy; |
|
|
|
} |
|
|
|
} else { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (length > 0) { |
|
|
|
// Process aligned middle inplace, in sector sized multiples.
|
|
|
|
while (length >= XTS_SECTOR_SIZE) { |
|
|
|
const std::size_t req = (length / XTS_SECTOR_SIZE) * XTS_SECTOR_SIZE; |
|
|
|
const std::size_t got = base->Read(data, req, offset); |
|
|
|
if (got == 0) { |
|
|
|
std::array<u8, XTS_SECTOR_SIZE> sector{}; |
|
|
|
|
|
|
|
while (remaining > 0) { |
|
|
|
const std::size_t sector_index = current_offset / XTS_SECTOR_SIZE; |
|
|
|
const std::size_t sector_offset = current_offset % XTS_SECTOR_SIZE; |
|
|
|
|
|
|
|
const std::size_t sectors_to_read = std::min<std::size_t>(PrefetchSectors, |
|
|
|
(remaining + sector_offset + |
|
|
|
XTS_SECTOR_SIZE - 1) / |
|
|
|
XTS_SECTOR_SIZE); |
|
|
|
|
|
|
|
for (std::size_t s = 0; s < sectors_to_read && remaining > 0; ++s) { |
|
|
|
const std::size_t index = sector_index + s; |
|
|
|
const std::size_t read_offset = index * XTS_SECTOR_SIZE; |
|
|
|
const std::size_t got = base->Read(sector.data(), XTS_SECTOR_SIZE, read_offset); |
|
|
|
if (got == 0) |
|
|
|
return total_read; |
|
|
|
} |
|
|
|
const std::size_t got_rounded = got - (got % XTS_SECTOR_SIZE); |
|
|
|
if (got_rounded > 0) { |
|
|
|
cipher.XTSTranscode(data, got_rounded, data, offset / XTS_SECTOR_SIZE, XTS_SECTOR_SIZE, Op::Decrypt); |
|
|
|
data += got_rounded; |
|
|
|
offset += got_rounded; |
|
|
|
length -= got_rounded; |
|
|
|
total_read += got_rounded; |
|
|
|
} |
|
|
|
// If we didn't get a full sector next, break to handle tail.
|
|
|
|
if (got_rounded != got) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
// Handle tail within a sector, if any.
|
|
|
|
if (length > 0) { |
|
|
|
std::array<u8, XTS_SECTOR_SIZE> block{}; |
|
|
|
const std::size_t got = base->Read(block.data(), XTS_SECTOR_SIZE, offset); |
|
|
|
if (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(), |
|
|
|
offset / XTS_SECTOR_SIZE, XTS_SECTOR_SIZE, Op::Decrypt); |
|
|
|
const std::size_t to_copy = std::min<std::size_t>(length, got); |
|
|
|
std::memcpy(data, block.data(), to_copy); |
|
|
|
total_read += to_copy; |
|
|
|
} |
|
|
|
|
|
|
|
if (got < XTS_SECTOR_SIZE) |
|
|
|
std::memset(sector.data() + got, 0, XTS_SECTOR_SIZE - got); |
|
|
|
|
|
|
|
cipher.XTSTranscode(sector.data(), XTS_SECTOR_SIZE, sector.data(), index, XTS_SECTOR_SIZE, |
|
|
|
Op::Decrypt); |
|
|
|
|
|
|
|
const std::size_t local_offset = (s == 0) ? sector_offset : 0; |
|
|
|
const std::size_t available = XTS_SECTOR_SIZE - local_offset; |
|
|
|
const std::size_t to_copy = std::min<std::size_t>(available, remaining); |
|
|
|
std::memcpy(out, sector.data() + local_offset, to_copy); |
|
|
|
|
|
|
|
out += to_copy; |
|
|
|
current_offset += to_copy; |
|
|
|
remaining -= to_copy; |
|
|
|
total_read += to_copy; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return total_read; |
|
|
|
} |
|
|
|
} // namespace Core::Crypto
|