2222#include < iostream>
2323#include < cstdlib>
2424#include < chrono>
25+ #include < cstring>
26+ #include < limits>
2527#include " ../value_encryption_utils.h"
2628
2729using namespace dbps ::value_encryption_utils;
@@ -65,6 +67,22 @@ namespace {
6567 const char * env = std::getenv (" DBPS_LOG_VALUE_ENCRYPT_TIMING" );
6668 return env == nullptr || std::string (env) == " 1" ;
6769 }
70+
71+ void EncryptBytesInto (const uint8_t * data, size_t len, const std::string& key_id, uint8_t * out) {
72+ if (len == 0 ) {
73+ return ;
74+ }
75+ if (key_id.empty ()) {
76+ throw std::invalid_argument (" EncryptBytesInto: key must not be empty for non-empty data" );
77+ }
78+
79+ std::hash<std::string> hasher;
80+ size_t key_hash = hasher (key_id);
81+ for (size_t i = 0 ; i < len; ++i) {
82+ out[i] = data[i] ^ (key_hash & 0xFF );
83+ key_hash = (key_hash << 1 ) | (key_hash >> 31 );
84+ }
85+ }
6886}
6987
7088std::vector<uint8_t > BasicEncryptor::EncryptBlock (const std::vector<uint8_t >& data) {
@@ -76,7 +94,7 @@ std::vector<uint8_t> BasicEncryptor::DecryptBlock(const std::vector<uint8_t>& da
7694 return DecryptByteArray (data, key_id_);
7795}
7896
79- std::vector<uint8_t > BasicEncryptor::EncryptValueList (
97+ std::vector<uint8_t > BasicEncryptor::EncryptValueList_OLD (
8098 const TypedListValues& typed_list) {
8199
82100 const bool log_timings = ShouldLogValueEncryptionTiming ();
@@ -150,6 +168,194 @@ std::vector<uint8_t> BasicEncryptor::EncryptValueList(
150168 return concatenated_encrypted_bytes;
151169} // EncryptValueList
152170
171+ std::vector<uint8_t > BasicEncryptor::EncryptValueList (
172+ const TypedListValues& typed_list) {
173+
174+ const bool log_timings = ShouldLogValueEncryptionTiming ();
175+ using Clock = std::chrono::steady_clock;
176+ std::vector<std::pair<std::string, long long >> timings;
177+
178+ auto time_step = [&](const char * label, const std::function<void ()>& fn) {
179+ if (!log_timings) {
180+ fn ();
181+ return ;
182+ }
183+ auto start = Clock::now ();
184+ fn ();
185+ auto end = Clock::now ();
186+ auto micros = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count ();
187+ timings.emplace_back (label, micros);
188+ };
189+
190+ if (ShouldLogValueEncryption ()) {
191+ // Printout the typed list.
192+ auto print_result = TypedListToString (typed_list);
193+ if (print_result.length () > 1000 ) {
194+ std::cout << " Encrypt value - Decoded plaintext data (first 1000 chars):\n "
195+ << print_result.substr (0 , 1000 ) << " ...\n " ;
196+ } else {
197+ std::cout << " Encrypt value - Decoded plaintext data:\n " << print_result << " \n " ;
198+ }
199+
200+ // Printout the additional context parameters.
201+ std::cout << " Context parameters:\n "
202+ << " column_name: " << column_name_ << " \n "
203+ << " user_id: " << user_id_ << " \n "
204+ << " key_id: " << key_id_ << " \n "
205+ << " application_context: " << application_context_ << " \n "
206+ << " datatype: " << dbps::enum_utils::to_string (datatype_) << " \n " ;
207+ }
208+
209+ const std::string key_id_copy = key_id_;
210+ std::vector<uint8_t > concatenated_encrypted_bytes;
211+
212+ size_t total_capacity = 0 ;
213+ uint32_t count = 0 ;
214+
215+ time_step (" ComputeEncryptedSize" , [&]() {
216+ std::visit ([&](const auto & vec) {
217+ using VecT = std::decay_t <decltype (vec)>;
218+ using ElemT = typename VecT::value_type;
219+ if (vec.size () > static_cast <size_t >(std::numeric_limits<uint32_t >::max ())) {
220+ throw InvalidInputException (" Too many elements to serialize into uint32 count" );
221+ }
222+ count = static_cast <uint32_t >(vec.size ());
223+ total_capacity = 4 ;
224+ for (size_t i = 0 ; i < vec.size (); ++i) {
225+ size_t elem_size = 0 ;
226+ if constexpr (std::is_same_v<ElemT, int32_t > || std::is_same_v<ElemT, float >) {
227+ elem_size = 4 ;
228+ } else if constexpr (std::is_same_v<ElemT, int64_t > || std::is_same_v<ElemT, double >) {
229+ elem_size = 8 ;
230+ } else if constexpr (std::is_same_v<ElemT, std::array<uint32_t , 3 >>) {
231+ elem_size = 12 ;
232+ } else if constexpr (std::is_same_v<ElemT, std::string>) {
233+ elem_size = vec[i].size ();
234+ } else {
235+ static_assert (sizeof (ElemT) == 0 , " Unsupported element type in TypedListValues" );
236+ }
237+
238+ if (elem_size > static_cast <size_t >(std::numeric_limits<uint32_t >::max ())) {
239+ throw InvalidInputException (" Element size exceeds uint32 capacity" );
240+ }
241+ total_capacity += 4 + elem_size;
242+ }
243+ }, typed_list);
244+ });
245+
246+ time_step (" EncryptIntoBuffer" , [&]() {
247+ concatenated_encrypted_bytes.resize (total_capacity);
248+ size_t offset = 0 ;
249+ auto write_u32_le = [&](uint32_t v) {
250+ concatenated_encrypted_bytes[offset + 0 ] = static_cast <uint8_t >(v & 0xFF );
251+ concatenated_encrypted_bytes[offset + 1 ] = static_cast <uint8_t >((v >> 8 ) & 0xFF );
252+ concatenated_encrypted_bytes[offset + 2 ] = static_cast <uint8_t >((v >> 16 ) & 0xFF );
253+ concatenated_encrypted_bytes[offset + 3 ] = static_cast <uint8_t >((v >> 24 ) & 0xFF );
254+ offset += 4 ;
255+ };
256+
257+ write_u32_le (count);
258+
259+ std::visit ([&](const auto & vec) {
260+ using VecT = std::decay_t <decltype (vec)>;
261+ using ElemT = typename VecT::value_type;
262+
263+ for (size_t i = 0 ; i < vec.size (); ++i) {
264+ size_t elem_size = 0 ;
265+ if constexpr (std::is_same_v<ElemT, int32_t >) {
266+ elem_size = 4 ;
267+ write_u32_le (static_cast <uint32_t >(elem_size));
268+ uint8_t raw[4 ];
269+ const uint32_t v = static_cast <uint32_t >(vec[i]);
270+ raw[0 ] = static_cast <uint8_t >(v & 0xFF );
271+ raw[1 ] = static_cast <uint8_t >((v >> 8 ) & 0xFF );
272+ raw[2 ] = static_cast <uint8_t >((v >> 16 ) & 0xFF );
273+ raw[3 ] = static_cast <uint8_t >((v >> 24 ) & 0xFF );
274+ EncryptBytesInto (raw, elem_size, key_id_copy, concatenated_encrypted_bytes.data () + offset);
275+ offset += elem_size;
276+ } else if constexpr (std::is_same_v<ElemT, int64_t >) {
277+ elem_size = 8 ;
278+ write_u32_le (static_cast <uint32_t >(elem_size));
279+ uint8_t raw[8 ];
280+ const uint64_t v = static_cast <uint64_t >(vec[i]);
281+ raw[0 ] = static_cast <uint8_t >(v & 0xFF );
282+ raw[1 ] = static_cast <uint8_t >((v >> 8 ) & 0xFF );
283+ raw[2 ] = static_cast <uint8_t >((v >> 16 ) & 0xFF );
284+ raw[3 ] = static_cast <uint8_t >((v >> 24 ) & 0xFF );
285+ raw[4 ] = static_cast <uint8_t >((v >> 32 ) & 0xFF );
286+ raw[5 ] = static_cast <uint8_t >((v >> 40 ) & 0xFF );
287+ raw[6 ] = static_cast <uint8_t >((v >> 48 ) & 0xFF );
288+ raw[7 ] = static_cast <uint8_t >((v >> 56 ) & 0xFF );
289+ EncryptBytesInto (raw, elem_size, key_id_copy, concatenated_encrypted_bytes.data () + offset);
290+ offset += elem_size;
291+ } else if constexpr (std::is_same_v<ElemT, float >) {
292+ elem_size = 4 ;
293+ write_u32_le (static_cast <uint32_t >(elem_size));
294+ uint32_t bits = 0 ;
295+ std::memcpy (&bits, &vec[i], sizeof (bits));
296+ uint8_t raw[4 ];
297+ raw[0 ] = static_cast <uint8_t >(bits & 0xFF );
298+ raw[1 ] = static_cast <uint8_t >((bits >> 8 ) & 0xFF );
299+ raw[2 ] = static_cast <uint8_t >((bits >> 16 ) & 0xFF );
300+ raw[3 ] = static_cast <uint8_t >((bits >> 24 ) & 0xFF );
301+ EncryptBytesInto (raw, elem_size, key_id_copy, concatenated_encrypted_bytes.data () + offset);
302+ offset += elem_size;
303+ } else if constexpr (std::is_same_v<ElemT, double >) {
304+ elem_size = 8 ;
305+ write_u32_le (static_cast <uint32_t >(elem_size));
306+ uint64_t bits = 0 ;
307+ std::memcpy (&bits, &vec[i], sizeof (bits));
308+ uint8_t raw[8 ];
309+ raw[0 ] = static_cast <uint8_t >(bits & 0xFF );
310+ raw[1 ] = static_cast <uint8_t >((bits >> 8 ) & 0xFF );
311+ raw[2 ] = static_cast <uint8_t >((bits >> 16 ) & 0xFF );
312+ raw[3 ] = static_cast <uint8_t >((bits >> 24 ) & 0xFF );
313+ raw[4 ] = static_cast <uint8_t >((bits >> 32 ) & 0xFF );
314+ raw[5 ] = static_cast <uint8_t >((bits >> 40 ) & 0xFF );
315+ raw[6 ] = static_cast <uint8_t >((bits >> 48 ) & 0xFF );
316+ raw[7 ] = static_cast <uint8_t >((bits >> 56 ) & 0xFF );
317+ EncryptBytesInto (raw, elem_size, key_id_copy, concatenated_encrypted_bytes.data () + offset);
318+ offset += elem_size;
319+ } else if constexpr (std::is_same_v<ElemT, std::array<uint32_t , 3 >>) {
320+ elem_size = 12 ;
321+ write_u32_le (static_cast <uint32_t >(elem_size));
322+ uint8_t raw[12 ];
323+ for (int j = 0 ; j < 3 ; ++j) {
324+ const uint32_t w = vec[i][j];
325+ raw[j * 4 + 0 ] = static_cast <uint8_t >(w & 0xFF );
326+ raw[j * 4 + 1 ] = static_cast <uint8_t >((w >> 8 ) & 0xFF );
327+ raw[j * 4 + 2 ] = static_cast <uint8_t >((w >> 16 ) & 0xFF );
328+ raw[j * 4 + 3 ] = static_cast <uint8_t >((w >> 24 ) & 0xFF );
329+ }
330+ EncryptBytesInto (raw, elem_size, key_id_copy, concatenated_encrypted_bytes.data () + offset);
331+ offset += elem_size;
332+ } else if constexpr (std::is_same_v<ElemT, std::string>) {
333+ elem_size = vec[i].size ();
334+ write_u32_le (static_cast <uint32_t >(elem_size));
335+ if (elem_size > 0 ) {
336+ EncryptBytesInto (reinterpret_cast <const uint8_t *>(vec[i].data ()),
337+ elem_size,
338+ key_id_copy,
339+ concatenated_encrypted_bytes.data () + offset);
340+ offset += elem_size;
341+ }
342+ } else {
343+ static_assert (sizeof (ElemT) == 0 , " Unsupported element type in TypedListValues" );
344+ }
345+ }
346+ }, typed_list);
347+ });
348+
349+ if (log_timings) {
350+ std::cout << " EncryptValueList timings (microseconds):\n " ;
351+ for (const auto & entry : timings) {
352+ std::cout << " " << entry.first << " : " << entry.second << " \n " ;
353+ }
354+ }
355+
356+ return concatenated_encrypted_bytes;
357+ } // EncryptValueList
358+
153359TypedListValues BasicEncryptor::DecryptValueList (
154360 const std::vector<uint8_t >& encrypted_bytes) {
155361
0 commit comments