From 71c96a1e64bc75baa74917c73f0a83b7dbe2d679 Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 10 Mar 2026 11:33:49 -0600 Subject: [PATCH 1/5] - Making BasicXorEncryptor more readable. - Adding internal documentation and comments for guidance to future implementations. - Adding a PrintableTypedValuesBuffer function to the TypedValuesBuffer class for debugging. --- .../encryptors/basic_xor_encryptor.cpp | 215 ++++++++++-------- .../encryptors/basic_xor_encryptor.h | 13 ++ src/processing/typed_buffer.h | 1 + src/processing/typed_buffer_values.h | 34 +++ src/processing/typed_buffer_values_test.cpp | 61 ++++- 5 files changed, 224 insertions(+), 100 deletions(-) diff --git a/src/processing/encryptors/basic_xor_encryptor.cpp b/src/processing/encryptors/basic_xor_encryptor.cpp index 974a891..8598830 100644 --- a/src/processing/encryptors/basic_xor_encryptor.cpp +++ b/src/processing/encryptors/basic_xor_encryptor.cpp @@ -31,12 +31,12 @@ using namespace dbps::external; // Functions for encrypting and decrypting byte arrays. // --------------------------------------------------------------------------- -static std::vector EncryptByteArray(tcb::span data, const std::string& key_id) { +std::vector BasicXorEncryptor::XorEncrypt(tcb::span data, const std::string& key_id) { if (data.empty()) { return {}; } if (key_id.empty()) { - throw std::invalid_argument("EncryptByteArray: key must not be empty for non-empty data"); + throw std::invalid_argument("XorEncrypt: key must not be empty for non-empty data"); } std::vector out(data.size()); std::hash hasher; @@ -48,8 +48,8 @@ static std::vector EncryptByteArray(tcb::span data, cons return out; } -static std::vector DecryptByteArray(tcb::span data, const std::string& key_id) { - return EncryptByteArray(data, key_id); +std::vector BasicXorEncryptor::XorDecrypt(tcb::span data, const std::string& key_id) { + return XorEncrypt(data, key_id); } // --------------------------------------------------------------------------- @@ -57,11 +57,11 @@ static std::vector DecryptByteArray(tcb::span data, cons // --------------------------------------------------------------------------- std::vector BasicXorEncryptor::EncryptBlock(tcb::span data) { - return EncryptByteArray(data, key_id_); + return XorEncrypt(data, key_id_); } std::vector BasicXorEncryptor::DecryptBlock(tcb::span data) { - return DecryptByteArray(data, key_id_); + return XorDecrypt(data, key_id_); } // --------------------------------------------------------------------------- @@ -71,79 +71,114 @@ std::vector BasicXorEncryptor::DecryptBlock(tcb::span da // Fixed: [0x01][uint32 count][uint32 elem_size] // Variable: [0x00][uint32 count] // +// NOTE ON TYPE-SPECIFIC ENCRYPTION: +// +// The current implementation encrypts each element by interpreting the elements a plain bytes, +// not utilizing the specific type of the buffer elements (INT32, INT64, etc.). +// +// A more sophisticated implementation could take advantage of the specific element type +// to call type-specific encryption functions, if the underlying library supports them. +// +// For example, a type-specific encryption per element could look like: +// for (size_t i = 0; i < input_buffer.GetNumElements(); ++i) { +// int32_t int_value = input_buffer.GetElement(i); // e.g. int32_t for TypedBufferI32 +// auto encrypted = library.EncryptInt32(typed_value, key_id); +// output_buffer.SetElement(i, encrypted); +// } +// // --------------------------------------------------------------------------- -std::vector BasicXorEncryptor::EncryptValueList( - const TypedValuesBuffer& typed_buffer) { +template +std::vector BasicXorEncryptor::EncryptTypedElements( + const TypedBuffer& input_buffer, const std::string& key_id) { + constexpr bool is_fixed = TypedBuffer::is_fixed_sized; + constexpr size_t prefix_length = is_fixed ? kFixedHeaderLength : kVariableHeaderLength; + const size_t num_elements = input_buffer.GetNumElements(); + + // If there are no elements, return an empty buffer with the header. + if (num_elements == 0) { + std::vector result(prefix_length); + WriteHeader(result, {is_fixed, 0, 0}); + return result; + } - std::cout << "EncryptValueList context: column=" << column_name_ - << " user=" << user_id_ << " key=" << key_id_ - << " datatype=" << dbps::enum_utils::to_string(datatype_) << std::endl; - - // TODO: Make EncryptValueList/DecryptValueList more readable: - // - Implement a simpler way of accessing Variant TypedBuffer if possible. - // - Replace unnecesary use of lambdas and removing other unnecessary complexity. - return std::visit([&](const auto& input_buffer) -> std::vector { - using BufferType = std::decay_t; - constexpr bool is_fixed = BufferType::is_fixed_sized; - const size_t num_elements = input_buffer.GetNumElements(); - constexpr size_t prefix_length = is_fixed ? kFixedHeaderLength : kVariableHeaderLength; - - // Empty buffer, return empty vector with header. - if (num_elements == 0) { - std::vector result(prefix_length); - WriteHeader(result, {is_fixed, 0, 0}); - return result; + // Encrypt the elements by traversing the typed input buffer and encrypt each element separately: + // - Create an output raw-bytes buffer to capture the encrypted elements as bytes. + // - For each element: read its raw bytes, encrypt them, write into the output buffer. + // - Finalize the output buffer into a contiguous byte vector. + + std::vector final_buffer; + size_t element_size = 0; + + // Encrypt fixed-size elements + if constexpr (is_fixed) { + element_size = input_buffer.GetElementSize(); + TypedBufferRawBytesFixedSized output_buffer{ + num_elements, prefix_length, RawBytesFixedSizedCodec{element_size}}; + size_t output_index = 0; + for (const auto raw_bytes : input_buffer.raw_elements()) { + auto encrypted = XorEncrypt(raw_bytes, key_id); + output_buffer.SetElement(output_index, tcb::span(encrypted)); + output_index++; } - - auto encrypt_into = [&](auto& output_buffer) -> std::vector { - size_t output_index = 0; - for (const auto raw_bytes : input_buffer.raw_elements()) { - auto encrypted = EncryptByteArray(raw_bytes, key_id_); - output_buffer.SetElement(output_index, tcb::span(encrypted)); - output_index++; - } - return output_buffer.FinalizeAndTakeBuffer(); - }; - - std::vector final_buffer; - size_t element_size = 0; - if constexpr (is_fixed) { - element_size = input_buffer.GetElementSize(); - TypedBufferRawBytesFixedSized output_buffer{ - num_elements, prefix_length, RawBytesFixedSizedCodec{element_size}}; - final_buffer = encrypt_into(output_buffer); - } else { - auto reserved_bytes_hint = input_buffer.GetRawBufferSize(); - TypedBufferRawBytesVariableSized output_buffer{ - num_elements, reserved_bytes_hint, true, prefix_length}; - final_buffer = encrypt_into(output_buffer); + final_buffer = output_buffer.FinalizeAndTakeBuffer(); + } + + // Encrypt variable-size elements + else { + TypedBufferRawBytesVariableSized output_buffer{ + num_elements, input_buffer.GetRawBufferSize(), true, prefix_length}; + size_t output_index = 0; + for (const auto raw_bytes : input_buffer.raw_elements()) { + auto encrypted = XorEncrypt(raw_bytes, key_id); + output_buffer.SetElement(output_index, tcb::span(encrypted)); + output_index++; } - WriteHeader(final_buffer, {is_fixed, - static_cast(num_elements), - static_cast(element_size)}); - return final_buffer; + final_buffer = output_buffer.FinalizeAndTakeBuffer(); + } + + // Write the header to the final buffer and return it. + WriteHeader(final_buffer, {is_fixed, + static_cast(num_elements), + static_cast(element_size)}); + return final_buffer; +} +std::vector BasicXorEncryptor::EncryptValueList( + const TypedValuesBuffer& typed_buffer) { + + // Printable context string for logging + // std::string context_str = std::string("Context parameters:") + // + "\n column_name: " + column_name_ + // + "\n user_id: " + user_id_ + // + "\n key_id: " + key_id_ + // + "\n application_context: " + application_context_ + // + "\n datatype: " + std::string(dbps::enum_utils::to_string(datatype_)); + + // Printable typed buffer string for logging -- Commented out by default to avoid performance impact. + // std::string typed_buffer_str = TypedValuesBufferToString(typed_buffer); + + // std::visit extracts the concrete buffer type from the TypedValuesBuffer variant + // and forwards it to EncryptTypedElements, which handles all buffer types generically. + return std::visit([&](const auto& input_buffer) { + return EncryptTypedElements(input_buffer, key_id_); }, typed_buffer); } // --------------------------------------------------------------------------- // Value-level decryption (bytes in -> TypedValuesBuffer out) // -// Parses the header, then wraps the full span (with prefix_size) as a -// TypedBufferRawBytes... read buffer so the buffer skips the header -// automatically. Output is the correctly-typed buffer matching datatype_. +// Parses the header, then creates a correctly-typed buffer matching datatype_ (INT32, INT64, etc.). +// Calls the byte-array decryptor to decrypt the elements into the typed buffer. // --------------------------------------------------------------------------- -// Helper function to decrypt fixed-size buffer into a specific output TypedBuffer type. -template -static OutputBuffer DecryptFixedIntoBuffer( - const TypedBufferRawBytesFixedSized& encrypted_buffer, - const std::string& key_id, - OutputBuffer output_buffer) { +// Helper function to decrypt fixed-size elements into the output TypedBuffer type. +template +TypedBuffer BasicXorEncryptor::DecryptFixedSizedElementsIntoTypedBuffer( + const TypedBufferRawBytesFixedSized& encrypted_buffer, const std::string& key_id, TypedBuffer output_buffer) { size_t output_index = 0; for (const auto raw_bytes : encrypted_buffer.raw_elements()) { - auto decrypted_bytes = DecryptByteArray(raw_bytes, key_id); + auto decrypted_bytes = XorDecrypt(raw_bytes, key_id); output_buffer.SetRawElement(output_index, tcb::span(decrypted_bytes)); output_index++; } @@ -153,57 +188,57 @@ static OutputBuffer DecryptFixedIntoBuffer( TypedValuesBuffer BasicXorEncryptor::DecryptValueList( tcb::span encrypted_bytes) { - // During decryption, the number of elements can be obtained from the header, - // no need to calculate it from the encrypted_buffer. auto header = ReadHeader(encrypted_bytes); auto num_elements = static_cast(header.num_elements); + // Decrypt fixed-size elements if (header.is_fixed) { + + // Create a fixed-sized byte buffer for reading the encrypted elements. TypedBufferRawBytesFixedSized encrypted_buffer{ - encrypted_bytes, kFixedHeaderLength, - RawBytesFixedSizedCodec{header.element_size}}; + encrypted_bytes, kFixedHeaderLength, RawBytesFixedSizedCodec{header.element_size}}; - // TODO: This is leaking Parquet-specific types into the encryptor, which should be agnostic of Parquet. - // This is needed because on the returned bytes we are not saving a type information. - // We could annotate the generating bytes by simply updating the 1st byte of the header to indicate the type. + // Populate a typed buffer with the decrypted elements in the corresponding type. switch (datatype_) { case Type::INT32: - return DecryptFixedIntoBuffer(encrypted_buffer, key_id_, TypedBufferI32{num_elements}); + return DecryptFixedSizedElementsIntoTypedBuffer( + encrypted_buffer, key_id_, TypedBufferI32{num_elements}); case Type::INT64: - return DecryptFixedIntoBuffer(encrypted_buffer, key_id_, TypedBufferI64{num_elements}); + return DecryptFixedSizedElementsIntoTypedBuffer( + encrypted_buffer, key_id_, TypedBufferI64{num_elements}); case Type::INT96: - return DecryptFixedIntoBuffer(encrypted_buffer, key_id_, TypedBufferInt96{num_elements}); + return DecryptFixedSizedElementsIntoTypedBuffer( + encrypted_buffer, key_id_, TypedBufferInt96{num_elements}); case Type::FLOAT: - return DecryptFixedIntoBuffer(encrypted_buffer, key_id_, TypedBufferFloat{num_elements}); + return DecryptFixedSizedElementsIntoTypedBuffer( + encrypted_buffer, key_id_, TypedBufferFloat{num_elements}); case Type::DOUBLE: - return DecryptFixedIntoBuffer(encrypted_buffer, key_id_, TypedBufferDouble{num_elements}); - case Type::FIXED_LEN_BYTE_ARRAY: { - TypedBufferRawBytesFixedSized output_buffer{ - num_elements, 0, RawBytesFixedSizedCodec{header.element_size}}; - size_t output_index = 0; - for (const auto element : encrypted_buffer) { - auto decrypted_bytes = DecryptByteArray(element, key_id_); - output_buffer.SetElement(output_index, tcb::span(decrypted_bytes)); - output_index++; - } - return output_buffer; - } + return DecryptFixedSizedElementsIntoTypedBuffer( + encrypted_buffer, key_id_, TypedBufferDouble{num_elements}); + case Type::FIXED_LEN_BYTE_ARRAY: + return DecryptFixedSizedElementsIntoTypedBuffer( + encrypted_buffer, key_id_, + TypedBufferRawBytesFixedSized{num_elements, 0, RawBytesFixedSizedCodec{header.element_size}}); default: throw InvalidInputException( std::string("DecryptValueList: unsupported fixed-size datatype: ") + std::string(dbps::enum_utils::to_string(datatype_))); } - } else { - TypedBufferRawBytesVariableSized encrypted_buffer{ - encrypted_bytes, kVariableHeaderLength}; + } + + // Decrypt variable-size elements + else { + // Create a variable-sized byte buffer for reading the encrypted elements. + TypedBufferRawBytesVariableSized encrypted_buffer{ encrypted_bytes, kVariableHeaderLength}; switch (datatype_) { + // Create a BYTE-ARRAY typed buffer for storing the decrypted elements. case Type::BYTE_ARRAY: { auto reserved_bytes_hint = encrypted_buffer.GetRawBufferSize(); TypedBufferRawBytesVariableSized output_buffer{num_elements, reserved_bytes_hint, true}; size_t output_index = 0; for (const auto element : encrypted_buffer) { - auto decrypted_bytes = DecryptByteArray(element, key_id_); + auto decrypted_bytes = XorDecrypt(element, key_id_); output_buffer.SetElement(output_index, tcb::span(decrypted_bytes)); output_index++; } diff --git a/src/processing/encryptors/basic_xor_encryptor.h b/src/processing/encryptors/basic_xor_encryptor.h index d29693a..ef8f1b2 100644 --- a/src/processing/encryptors/basic_xor_encryptor.h +++ b/src/processing/encryptors/basic_xor_encryptor.h @@ -61,5 +61,18 @@ class DBPS_EXPORT BasicXorEncryptor : public DBPSEncryptor { std::vector EncryptValueList(const TypedValuesBuffer& typed_buffer) override; TypedValuesBuffer DecryptValueList(tcb::span encrypted_bytes) override; + +private: + static std::vector XorEncrypt(tcb::span data, const std::string& key_id); + static std::vector XorDecrypt(tcb::span data, const std::string& key_id); + + template + static std::vector EncryptTypedElements( + const InputBuffer& input_buffer, const std::string& key_id); + + template + static TypedBuffer DecryptFixedSizedElementsIntoTypedBuffer( + const TypedBufferRawBytesFixedSized& encrypted_buffer, + const std::string& key_id, TypedBuffer output_buffer); }; diff --git a/src/processing/typed_buffer.h b/src/processing/typed_buffer.h index 588bd62..b99d810 100644 --- a/src/processing/typed_buffer.h +++ b/src/processing/typed_buffer.h @@ -41,6 +41,7 @@ class ByteBuffer { public: using value_type = typename Codec::value_type; static constexpr bool is_fixed_sized = Codec::is_fixed_sized; + static constexpr std::string_view type_name() noexcept { return Codec::type_name(); } // Constructor for read-only buffer for both fixed-sized and variable-sized elements. // Elements are stored contiguously in the span. diff --git a/src/processing/typed_buffer_values.h b/src/processing/typed_buffer_values.h index 4589b80..3db6547 100644 --- a/src/processing/typed_buffer_values.h +++ b/src/processing/typed_buffer_values.h @@ -17,6 +17,8 @@ #pragma once +#include +#include #include #include "typed_buffer_codecs.h" #include "typed_buffer.h" @@ -56,4 +58,36 @@ using TypedValuesBuffer = std::variant< TypedBufferRawBytesFixedSized, TypedBufferRawBytesVariableSized >; + +// Printable string representation of the typed buffer +inline std::string PrintableTypedValuesBuffer(const TypedValuesBuffer& buffer) { + return std::visit([](const auto& typed_buffer) -> std::string { + using BufferType = std::decay_t; + using ValueType = typename BufferType::value_type; + + std::ostringstream out; + const size_t num_elements = typed_buffer.GetNumElements(); + + out << BufferType::type_name() << " (" << num_elements << " elements):\n"; + + size_t i = 0; + for (const auto element : typed_buffer) { + if constexpr (std::is_same_v) { + out << " [" << i << "] [" << element.lo << ", " + << element.mid << ", " << element.hi << "]\n"; + } else if constexpr (std::is_same_v) { + out << " [" << i << "] \"" << element + << "\" (length: " << element.size() << ")\n"; + } else if constexpr (std::is_same_v>) { + out << " [" << i << "] <" << element.size() << " bytes>\n"; + } else { + out << " [" << i << "] " << element << "\n"; + } + ++i; + } + + return out.str(); + }, buffer); +} + } // namespace dbps::processing diff --git a/src/processing/typed_buffer_values_test.cpp b/src/processing/typed_buffer_values_test.cpp index cbb73f5..38d6843 100644 --- a/src/processing/typed_buffer_values_test.cpp +++ b/src/processing/typed_buffer_values_test.cpp @@ -27,16 +27,7 @@ #include "bytes_utils.h" #include "exceptions.h" -using dbps::processing::ByteBuffer; -using dbps::processing::Int96; -using dbps::processing::PlainValueCodec; -using dbps::processing::StringFixedSizedCodec; -using dbps::processing::StringVariableSizedCodec; -using dbps::processing::TypedBufferFloat; -using dbps::processing::TypedBufferI32; -using dbps::processing::TypedBufferInt96; -using dbps::processing::TypedBufferStringFixedSized; -using dbps::processing::TypedBufferStringVariableSized; +using namespace dbps::processing; // ============================================================================= // INT32 @@ -544,3 +535,53 @@ TEST(TypedBufferValuesTest, StringVariableSized_UTF8_WriteRoundTrip) { EXPECT_EQ(reader.GetElement(2), "Emoji: 🚀🌟💻"); EXPECT_EQ(reader.GetElement(3), "Ελληνικά"); } + +// ============================================================================= +// TypedValuesBufferToString +// ============================================================================= + +TEST(TypedBufferValuesTest, TypedValuesBufferToString_BasicUsage) { + // --- INT32: construct from raw bytes (creates a read buffer) --- + std::vector i32_bytes; + append_i32_le(i32_bytes, 42); + append_i32_le(i32_bytes, -1); + append_i32_le(i32_bytes, 100); + + TypedValuesBuffer i32_variant = TypedBufferI32{tcb::span(i32_bytes)}; + std::string i32_str = PrintableTypedValuesBuffer(i32_variant); + + EXPECT_NE(i32_str.find("INT32"), std::string::npos); + EXPECT_NE(i32_str.find("3 elements"), std::string::npos); + EXPECT_NE(i32_str.find("42"), std::string::npos); + EXPECT_NE(i32_str.find("-1"), std::string::npos); + EXPECT_NE(i32_str.find("100"), std::string::npos); + + // --- FLOAT: construct from raw bytes --- + std::vector float_bytes; + append_f32_le(float_bytes, 3.14f); + append_f32_le(float_bytes, -0.5f); + + TypedValuesBuffer float_variant = TypedBufferFloat{tcb::span(float_bytes)}; + std::string float_str = PrintableTypedValuesBuffer(float_variant); + + EXPECT_NE(float_str.find("FLOAT"), std::string::npos); + EXPECT_NE(float_str.find("2 elements"), std::string::npos); + + // --- Variable BYTE_ARRAY: write, finalize, then read --- + const uint8_t blob1[] = {0xDE, 0xAD}; + const uint8_t blob2[] = {0xBE, 0xEF, 0xCA, 0xFE}; + + TypedBufferRawBytesVariableSized writer(2u, 64u, true); + writer.SetElement(0, tcb::span(blob1)); + writer.SetElement(1, tcb::span(blob2)); + + std::vector raw_finalized = writer.FinalizeAndTakeBuffer(); + TypedValuesBuffer raw_variant = + TypedBufferRawBytesVariableSized{tcb::span(raw_finalized)}; + std::string raw_str = PrintableTypedValuesBuffer(raw_variant); + + EXPECT_NE(raw_str.find("raw bytes (variable-length)"), std::string::npos); + EXPECT_NE(raw_str.find("2 elements"), std::string::npos); + EXPECT_NE(raw_str.find("2 bytes"), std::string::npos); + EXPECT_NE(raw_str.find("4 bytes"), std::string::npos); +} From 36b65936c20c3c7df71e22875722e57daf100abd Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 10 Mar 2026 11:53:47 -0600 Subject: [PATCH 2/5] - Small example update. --- src/processing/encryptors/basic_xor_encryptor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/processing/encryptors/basic_xor_encryptor.cpp b/src/processing/encryptors/basic_xor_encryptor.cpp index 8598830..d516f85 100644 --- a/src/processing/encryptors/basic_xor_encryptor.cpp +++ b/src/processing/encryptors/basic_xor_encryptor.cpp @@ -80,10 +80,10 @@ std::vector BasicXorEncryptor::DecryptBlock(tcb::span da // to call type-specific encryption functions, if the underlying library supports them. // // For example, a type-specific encryption per element could look like: -// for (size_t i = 0; i < input_buffer.GetNumElements(); ++i) { -// int32_t int_value = input_buffer.GetElement(i); // e.g. int32_t for TypedBufferI32 -// auto encrypted = library.EncryptInt32(typed_value, key_id); -// output_buffer.SetElement(i, encrypted); +// size_t i = 0; +// for (const int32_t element : input_buffer) { // e.g. int32_t for TypedBufferI32 +// auto encrypted = library.EncryptInt32(element, key_id); +// output_buffer.SetElement(i++, encrypted); // } // // --------------------------------------------------------------------------- From d7c6d15e2c7cc8b9529e1a7454937e20a27b15a8 Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 10 Mar 2026 11:59:14 -0600 Subject: [PATCH 3/5] Example fix. --- src/processing/encryptors/basic_xor_encryptor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/processing/encryptors/basic_xor_encryptor.cpp b/src/processing/encryptors/basic_xor_encryptor.cpp index d516f85..60dfb1f 100644 --- a/src/processing/encryptors/basic_xor_encryptor.cpp +++ b/src/processing/encryptors/basic_xor_encryptor.cpp @@ -156,7 +156,7 @@ std::vector BasicXorEncryptor::EncryptValueList( // + "\n datatype: " + std::string(dbps::enum_utils::to_string(datatype_)); // Printable typed buffer string for logging -- Commented out by default to avoid performance impact. - // std::string typed_buffer_str = TypedValuesBufferToString(typed_buffer); + // std::string typed_buffer_str = PrintableTypedValuesBuffer(typed_buffer); // std::visit extracts the concrete buffer type from the TypedValuesBuffer variant // and forwards it to EncryptTypedElements, which handles all buffer types generically. From 6001d1a2afb626d1ea69f57227076f4a61ab2aca Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 10 Mar 2026 13:27:55 -0600 Subject: [PATCH 4/5] - Small variable name change for clarity. --- src/processing/encryptors/basic_xor_encryptor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/processing/encryptors/basic_xor_encryptor.cpp b/src/processing/encryptors/basic_xor_encryptor.cpp index 60dfb1f..65dbbd7 100644 --- a/src/processing/encryptors/basic_xor_encryptor.cpp +++ b/src/processing/encryptors/basic_xor_encryptor.cpp @@ -126,8 +126,9 @@ std::vector BasicXorEncryptor::EncryptTypedElements( // Encrypt variable-size elements else { + auto reserved_bytes_hint = input_buffer.GetRawBufferSize(); TypedBufferRawBytesVariableSized output_buffer{ - num_elements, input_buffer.GetRawBufferSize(), true, prefix_length}; + num_elements, reserved_bytes_hint, true, prefix_length}; size_t output_index = 0; for (const auto raw_bytes : input_buffer.raw_elements()) { auto encrypted = XorEncrypt(raw_bytes, key_id); From d21d13686815c20a2e7f777b1ff5e6c68e80dc4e Mon Sep 17 00:00:00 2001 From: Alejandro Valerio Date: Tue, 10 Mar 2026 16:13:20 -0600 Subject: [PATCH 5/5] - Refined comments in basic_xor_encryptor.cpp --- src/processing/encryptors/basic_xor_encryptor.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/processing/encryptors/basic_xor_encryptor.cpp b/src/processing/encryptors/basic_xor_encryptor.cpp index 65dbbd7..44b8d18 100644 --- a/src/processing/encryptors/basic_xor_encryptor.cpp +++ b/src/processing/encryptors/basic_xor_encryptor.cpp @@ -73,13 +73,18 @@ std::vector BasicXorEncryptor::DecryptBlock(tcb::span da // // NOTE ON TYPE-SPECIFIC ENCRYPTION: // -// The current implementation encrypts each element by interpreting the elements a plain bytes, +// While this version of EncryptValueList is aware of types, the implementation ignores the type +// of the TypeValuesBuffer. It encrypts each element by interpreting the elements a plain bytes, // not utilizing the specific type of the buffer elements (INT32, INT64, etc.). // // A more sophisticated implementation could take advantage of the specific element type // to call type-specific encryption functions, if the underlying library supports them. // +// Further, a context-aware encryptor can additionally take advantage of the app_context, +// user_id, and column_name to further customize the encryption process, refined access control, etc. +// // For example, a type-specific encryption per element could look like: +// assert(input_buffer.IsTypedBufferI32()); // size_t i = 0; // for (const int32_t element : input_buffer) { // e.g. int32_t for TypedBufferI32 // auto encrypted = library.EncryptInt32(element, key_id);