Skip to content

Commit 95d39e4

Browse files
committed
- Quick-n-dirty refactor the BasicEncryptor to use a more efficient encryption algorithm
1 parent de86ac0 commit 95d39e4

2 files changed

Lines changed: 211 additions & 1 deletion

File tree

src/processing/encryptors/basic_encryptor.cpp

Lines changed: 207 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <iostream>
2323
#include <cstdlib>
2424
#include <chrono>
25+
#include <cstring>
26+
#include <limits>
2527
#include "../value_encryption_utils.h"
2628

2729
using 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

7088
std::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+
153359
TypedListValues BasicEncryptor::DecryptValueList(
154360
const std::vector<uint8_t>& encrypted_bytes) {
155361

src/processing/encryptors/basic_encryptor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ class DBPS_EXPORT BasicEncryptor : public DBPSEncryptor {
6363
std::vector<uint8_t> EncryptValueList(
6464
const TypedListValues& typed_list) override;
6565

66+
// Legacy implementation kept for reference/perf comparison
67+
std::vector<uint8_t> EncryptValueList_OLD(
68+
const TypedListValues& typed_list);
69+
6670
TypedListValues DecryptValueList(
6771
const std::vector<uint8_t>& encrypted_bytes) override;
6872
};

0 commit comments

Comments
 (0)