From da45fdf2b218a75911b4b15014843352eba89fd9 Mon Sep 17 00:00:00 2001 From: Siyuan Ren Date: Sat, 16 Mar 2024 13:33:29 +0800 Subject: [PATCH] Replace lite stream write block with multi write --- sources/lite_stream.cpp | 95 +++++++++++++++++++++++------------------ sources/lite_stream.h | 9 +++- sources/streams.cpp | 4 +- test/test_streams.cpp | 2 +- 4 files changed, 63 insertions(+), 47 deletions(-) diff --git a/sources/lite_stream.cpp b/sources/lite_stream.cpp index 9a4325e4..8239c31a 100644 --- a/sources/lite_stream.cpp +++ b/sources/lite_stream.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -101,11 +102,11 @@ AESGCMCryptStream::AESGCMCryptStream(std::shared_ptr stream, generate_random(id.data(), id.size()); m_stream->write(id.data(), 0, id.size()); m_padding_size = calc.compute_padding(id); - m_auxiliary.reset(new byte[sizeof(std::uint32_t) + m_padding_size]); + m_auxiliary.resize(sizeof(std::uint32_t) + m_padding_size, 0); if (m_padding_size) { - generate_random(m_auxiliary.get(), sizeof(std::uint32_t) + m_padding_size); - m_stream->write(m_auxiliary.get() + sizeof(std::uint32_t), id.size(), m_padding_size); + generate_random(m_auxiliary.data(), m_auxiliary.size()); + m_stream->write(m_auxiliary.data() + sizeof(std::uint32_t), id.size(), m_padding_size); } } else if (rc != id.size()) @@ -115,9 +116,9 @@ AESGCMCryptStream::AESGCMCryptStream(std::shared_ptr stream, else { m_padding_size = calc.compute_padding(id); - m_auxiliary.reset(new byte[sizeof(std::uint32_t) + m_padding_size]); + m_auxiliary.resize(sizeof(std::uint32_t) + m_padding_size, 0); if (m_padding_size - && m_stream->read(m_auxiliary.get() + sizeof(std::uint32_t), id.size(), m_padding_size) + && m_stream->read(m_auxiliary.data() + sizeof(std::uint32_t), id.size(), m_padding_size) != m_padding_size) throwInvalidArgumentException("Invalid padding in the underlying file"); } @@ -128,9 +129,6 @@ AESGCMCryptStream::AESGCMCryptStream(std::shared_ptr stream, } calc.compute_session_key(id, session_key); - - m_buffer.reset(new byte[get_underlying_block_size()]); - // The null iv is only a placeholder; it will replaced during encryption and decryption const byte null_iv[12] = {0}; m_encryptor.SetKeyWithIV( @@ -175,16 +173,21 @@ AESGCMCryptStream::read_multi_blocks(offset_type start_block, offset_type end_bl } else { + if (is_all_zeros(start_data, get_iv_size())) + { + WARN_LOG("Null IV for block number %d indicates a potential bug in securefs", + i / get_underlying_block_size() + start_block); + } to_little_endian( static_cast(i / get_underlying_block_size() + start_block), - m_auxiliary.get()); + m_auxiliary.data()); bool success = m_decryptor.DecryptAndVerify(static_cast(output), end_data - get_mac_size(), get_mac_size(), start_data, static_cast(get_iv_size()), - m_auxiliary.get(), - sizeof(std::uint32_t) + m_padding_size, + m_auxiliary.data(), + m_auxiliary.size(), start_data + get_iv_size(), this_block_virtual_size); @@ -196,40 +199,50 @@ AESGCMCryptStream::read_multi_blocks(offset_type start_block, offset_type end_bl return transformed_read_len; } -void AESGCMCryptStream::write_block(offset_type block_number, const void* input, length_type size) +void AESGCMCryptStream::write_multi_blocks(offset_type start_block, + offset_type end_block, + offset_type end_residue, + const void* input) { - if (block_number > MAX_BLOCKS) - throw StreamTooLongException(MAX_BLOCKS * get_block_size(), - block_number * get_block_size()); - - auto underlying_offset = block_number * get_underlying_block_size() + get_header_size(); - auto underlying_size = size + get_iv_size() + get_mac_size(); + if (end_block > MAX_BLOCKS) + throw StreamTooLongException(MAX_BLOCKS * get_block_size(), end_block * get_block_size()); - if (is_all_zeros(input, size)) + std::vector buffer( + (end_block - start_block) * get_underlying_block_size() + + (end_residue <= 0 ? 0 : end_residue + get_iv_size() + get_mac_size())); + for (length_type i = 0; i < buffer.size();) { - memset(m_buffer.get(), 0, underlying_size); - m_stream->write(m_buffer.get(), underlying_offset, underlying_size); - return; + auto this_block_underlying_size = std::min(get_underlying_block_size(), buffer.size() - i); + auto this_block_virtual_size = this_block_underlying_size - get_mac_size() - get_iv_size(); + if (this_block_virtual_size > 0) + { + auto* start_data = buffer.data() + i; + auto* end_data = start_data + this_block_underlying_size; + auto* iv = start_data; + auto* ciphertext = iv + get_iv_size(); + auto* mac = end_data - get_mac_size(); + to_little_endian(static_cast(start_block + i / get_underlying_block_size()), + m_auxiliary.data()); + do + { + generate_random(iv, get_iv_size()); + } while (is_all_zeros(iv, get_iv_size())); + m_encryptor.EncryptAndAuthenticate(ciphertext, + mac, + get_mac_size(), + iv, + static_cast(get_iv_size()), + m_auxiliary.data(), + m_auxiliary.size(), + static_cast(input), + this_block_virtual_size); + } + input = static_cast(input) + this_block_virtual_size; + i += this_block_underlying_size; } - - to_little_endian(static_cast(block_number), m_auxiliary.get()); - - do - { - generate_random(m_buffer.get(), get_iv_size()); - } while (is_all_zeros(m_buffer.get(), get_iv_size())); - - m_encryptor.EncryptAndAuthenticate(m_buffer.get() + get_iv_size(), - m_buffer.get() + get_iv_size() + size, - get_mac_size(), - m_buffer.get(), - static_cast(get_iv_size()), - m_auxiliary.get(), - sizeof(std::uint32_t) + m_padding_size, - static_cast(input), - size); - - m_stream->write(m_buffer.get(), underlying_offset, underlying_size); + m_stream->write(buffer.data(), + start_block * get_underlying_block_size() + get_header_size(), + buffer.size()); } length_type AESGCMCryptStream::size() const diff --git a/sources/lite_stream.h b/sources/lite_stream.h index fc7da544..4ad833ef 100644 --- a/sources/lite_stream.h +++ b/sources/lite_stream.h @@ -1,7 +1,9 @@ #pragma once +#include "mystring.h" #include "streams.h" +#include #include #include #include @@ -27,7 +29,7 @@ class AESGCMCryptStream : public BlockBasedStream CryptoPP::GCM::Encryption m_encryptor; CryptoPP::GCM::Decryption m_decryptor; std::shared_ptr m_stream; - std::unique_ptr m_buffer, m_auxiliary; + absl::InlinedVector m_auxiliary; unsigned m_iv_size, m_padding_size; bool m_check; @@ -61,7 +63,10 @@ class AESGCMCryptStream : public BlockBasedStream length_type read_multi_blocks(offset_type start_block, offset_type end_block, void* output) override; - void write_block(offset_type block_number, const void* input, length_type size) override; + void write_multi_blocks(offset_type start_block, + offset_type end_block, + offset_type end_residue, + const void* input) override; void adjust_logical_size(length_type length) override; diff --git a/sources/streams.cpp b/sources/streams.cpp index 346497c9..872c0875 100644 --- a/sources/streams.cpp +++ b/sources/streams.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -23,7 +22,6 @@ #include #include #include -#include namespace securefs { @@ -314,7 +312,7 @@ void BlockBasedStream::unchecked_resize(length_type current_size, length_type ne CryptoPP::AlignedSecByteBlock buffer(m_block_size); memset(buffer.data(), 0, buffer.size()); (void)read_multi_blocks(block_num, block_num + 1, buffer.data()); - write_block(block_num, buffer.data(), residue); + write_multi_blocks(block_num, block_num, residue, buffer.data()); } } else diff --git a/test/test_streams.cpp b/test/test_streams.cpp index 012e9420..51d637bf 100644 --- a/test/test_streams.cpp +++ b/test/test_streams.cpp @@ -66,7 +66,7 @@ namespace static void test(securefs::StreamBase& stream, unsigned times) { - const char* stream_type_name = typeid(stream).name(); + std::string_view stream_type_name = typeid(stream).name(); CAPTURE(stream_type_name); securefs::MemoryStream memory_stream; stream.resize(0);