Skip to content

Commit 478d40a

Browse files
committed
refactor: encapsulate vector/array keys into Obfuscation
1 parent 377aab8 commit 478d40a

13 files changed

+136
-85
lines changed

src/bench/obfuscation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ static void ObfuscationBench(benchmark::Bench& bench)
1313
{
1414
FastRandomContext frc{/*fDeterministic=*/true};
1515
auto data{frc.randbytes<std::byte>(1024)};
16-
const auto key{frc.randbytes<Obfuscation::KEY_SIZE>()};
16+
const Obfuscation obfuscation{frc.randbytes<Obfuscation::KEY_SIZE>()};
1717

1818
size_t offset{0};
1919
bench.batch(data.size()).unit("byte").run([&] {
20-
Obfuscation().Xor(data, key, offset++); // mutated differently each time
20+
obfuscation(data, offset++); // mutated differently each time
2121
ankerl::nanobench::doNotOptimizeAway(data);
2222
});
2323
}

src/dbwrapper.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void CDBBatch::Clear()
174174
void CDBBatch::WriteImpl(std::span<const std::byte> key, DataStream& ssValue)
175175
{
176176
leveldb::Slice slKey(CharCast(key.data()), key.size());
177-
ssValue.Xor(dbwrapper_private::GetObfuscation(parent));
177+
dbwrapper_private::GetObfuscation(parent)(ssValue);
178178
leveldb::Slice slValue(CharCast(ssValue.data()), ssValue.size());
179179
m_impl_batch->batch.Put(slKey, slValue);
180180
}
@@ -249,15 +249,14 @@ CDBWrapper::CDBWrapper(const DBParams& params)
249249
LogPrintf("Finished database compaction of %s\n", fs::PathToString(params.path));
250250
}
251251

252-
m_obfuscation = std::vector<uint8_t>(Obfuscation::KEY_SIZE, '\000'); // Needed for unobfuscated Read()/Write() below
252+
assert(!m_obfuscation); // Needed for unobfuscated Read()/Write() below
253253
if (!Read(OBFUSCATION_KEY_KEY, m_obfuscation) && params.obfuscate && IsEmpty()) {
254254
// Generate, write and read back the new obfuscation key, making sure we don't obfuscate the key itself
255255
Write(OBFUSCATION_KEY_KEY, FastRandomContext{}.randbytes(Obfuscation::KEY_SIZE));
256256
Read(OBFUSCATION_KEY_KEY, m_obfuscation);
257-
LogInfo("Wrote new obfuscation key for %s: %s", fs::PathToString(params.path), HexStr(m_obfuscation));
257+
LogInfo("Wrote new obfuscation key for %s: %s", fs::PathToString(params.path), m_obfuscation.HexKey());
258258
}
259-
LogInfo("Using obfuscation key for %s: %s", fs::PathToString(params.path), HexStr(m_obfuscation));
260-
259+
LogInfo("Using obfuscation key for %s: %s", fs::PathToString(params.path), m_obfuscation.HexKey());
261260
}
262261

263262
CDBWrapper::~CDBWrapper()
@@ -385,7 +384,7 @@ void CDBIterator::Next() { m_impl_iter->iter->Next(); }
385384

386385
namespace dbwrapper_private {
387386

388-
const std::vector<unsigned char>& GetObfuscation(const CDBWrapper &w)
387+
const Obfuscation& GetObfuscation(const CDBWrapper& w)
389388
{
390389
return w.m_obfuscation;
391390
}

src/dbwrapper.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include <optional>
1919
#include <stdexcept>
2020
#include <string>
21-
#include <vector>
2221

2322
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
2423
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
@@ -63,8 +62,7 @@ namespace dbwrapper_private {
6362
* Database obfuscation should be considered an implementation detail of the
6463
* specific database.
6564
*/
66-
const std::vector<unsigned char>& GetObfuscation(const CDBWrapper &w);
67-
65+
const Obfuscation& GetObfuscation(const CDBWrapper&);
6866
}; // namespace dbwrapper_private
6967

7068
bool DestroyDB(const std::string& path_str);
@@ -166,7 +164,7 @@ class CDBIterator
166164
template<typename V> bool GetValue(V& value) {
167165
try {
168166
DataStream ssValue{GetValueImpl()};
169-
ssValue.Xor(dbwrapper_private::GetObfuscation(parent));
167+
dbwrapper_private::GetObfuscation(parent)(ssValue);
170168
ssValue >> value;
171169
} catch (const std::exception&) {
172170
return false;
@@ -179,16 +177,16 @@ struct LevelDBContext;
179177

180178
class CDBWrapper
181179
{
182-
friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscation(const CDBWrapper &w);
180+
friend const Obfuscation& dbwrapper_private::GetObfuscation(const CDBWrapper&);
183181
private:
184182
//! holds all leveldb-specific fields of this class
185183
std::unique_ptr<LevelDBContext> m_db_context;
186184

187185
//! the name of this database
188186
std::string m_name;
189187

190-
//! a key used for optional XOR-obfuscation of the database
191-
std::vector<unsigned char> m_obfuscation;
188+
//! optional XOR-obfuscation of the database
189+
Obfuscation m_obfuscation;
192190

193191
//! obfuscation key storage key, null-prefixed to avoid collisions
194192
inline static const std::string OBFUSCATION_KEY_KEY{"\000obfuscate_key", 14}; // explicit size to avoid truncation at leading \0
@@ -223,7 +221,7 @@ class CDBWrapper
223221
}
224222
try {
225223
DataStream ssValue{MakeByteSpan(*strValue)};
226-
ssValue.Xor(m_obfuscation);
224+
m_obfuscation(ssValue);
227225
ssValue >> value;
228226
} catch (const std::exception&) {
229227
return false;

src/node/blockstorage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ static auto InitBlocksdirXorKey(const BlockManager::Options& opts)
11741174
};
11751175
}
11761176
LogInfo("Using obfuscation key for blocksdir *.dat files (%s): '%s'\n", fs::PathToString(opts.blocks_dir), HexStr(obfuscation));
1177-
return std::vector<std::byte>{obfuscation.begin(), obfuscation.end()};
1177+
return Obfuscation{obfuscation};
11781178
}
11791179

11801180
BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts)

src/node/blockstorage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class BlockManager
235235

236236
const bool m_prune_mode;
237237

238-
const std::vector<std::byte> m_obfuscation;
238+
const Obfuscation m_obfuscation;
239239

240240
/** Dirty block index entries. */
241241
std::set<CBlockIndex*> m_dirty_blockindex;

src/node/mempool_persist.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
6464
if (version == MEMPOOL_DUMP_VERSION_NO_XOR_KEY) {
6565
file.SetObfuscation({});
6666
} else if (version == MEMPOOL_DUMP_VERSION) {
67-
std::vector<std::byte> obfuscation(Obfuscation::KEY_SIZE);
67+
Obfuscation obfuscation;
6868
file >> obfuscation;
6969
file.SetObfuscation(obfuscation);
7070
} else {
@@ -183,8 +183,7 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mock
183183
file << version;
184184

185185
if (!pool.m_opts.persist_v1_dat) {
186-
std::vector<std::byte> obfuscation(Obfuscation::KEY_SIZE);
187-
FastRandomContext{}.fillrand(obfuscation);
186+
const Obfuscation obfuscation{FastRandomContext{}.randbytes<Obfuscation::KEY_SIZE>()};
188187
file << obfuscation;
189188
file.SetObfuscation(obfuscation);
190189
} else {

src/streams.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010

1111
#include <array>
1212

13-
AutoFile::AutoFile(std::FILE* file, std::vector<std::byte> obfuscation)
14-
: m_file{file}, m_obfuscation{std::move(obfuscation)}
13+
AutoFile::AutoFile(std::FILE* file, const Obfuscation& obfuscation) : m_file{file}, m_obfuscation{obfuscation}
1514
{
1615
if (!IsNull()) {
1716
auto pos{std::ftell(m_file)};
@@ -22,12 +21,12 @@ AutoFile::AutoFile(std::FILE* file, std::vector<std::byte> obfuscation)
2221
std::size_t AutoFile::detail_fread(std::span<std::byte> dst)
2322
{
2423
if (!m_file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr");
25-
size_t ret = std::fread(dst.data(), 1, dst.size(), m_file);
26-
if (!m_obfuscation.empty()) {
27-
if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::read: position unknown");
28-
Obfuscation().Xor(dst.subspan(0, ret), m_obfuscation, *m_position);
24+
const size_t ret = std::fread(dst.data(), 1, dst.size(), m_file);
25+
if (m_obfuscation) {
26+
if (!m_position) throw std::ios_base::failure("AutoFile::read: position unknown");
27+
m_obfuscation(dst.subspan(0, ret), *m_position);
2928
}
30-
if (m_position.has_value()) *m_position += ret;
29+
if (m_position) *m_position += ret;
3130
return ret;
3231
}
3332

@@ -82,7 +81,7 @@ void AutoFile::ignore(size_t nSize)
8281
void AutoFile::write(std::span<const std::byte> src)
8382
{
8483
if (!m_file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr");
85-
if (m_obfuscation.empty()) {
84+
if (!m_obfuscation) {
8685
if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) {
8786
throw std::ios_base::failure("AutoFile::write: write failed");
8887
}
@@ -102,9 +101,9 @@ void AutoFile::write(std::span<const std::byte> src)
102101
void AutoFile::write_buffer(std::span<std::byte> src)
103102
{
104103
if (!m_file) throw std::ios_base::failure("AutoFile::write_buffer: file handle is nullptr");
105-
if (m_obfuscation.size()) {
104+
if (m_obfuscation) {
106105
if (!m_position) throw std::ios_base::failure("AutoFile::write_buffer: obfuscation position unknown");
107-
Obfuscation().Xor(src, m_obfuscation, *m_position); // obfuscate in-place
106+
m_obfuscation(src, *m_position); // obfuscate in-place
108107
}
109108
if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) {
110109
throw std::ios_base::failure("AutoFile::write_buffer: write failed");

src/streams.h

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include <limits>
2626
#include <optional>
2727
#include <string>
28-
#include <utility>
2928
#include <vector>
3029

3130
/* Minimal stream for overwriting and/or appending to an existing byte vector
@@ -245,23 +244,13 @@ class DataStream
245244
return (*this);
246245
}
247246

248-
template<typename T>
247+
template <typename T>
249248
DataStream& operator>>(T&& obj)
250249
{
251250
::Unserialize(*this, obj);
252251
return (*this);
253252
}
254253

255-
/**
256-
* XOR the contents of this stream with a certain key.
257-
*
258-
* @param[in] key The key used to XOR the data in this stream.
259-
*/
260-
void Xor(const std::vector<unsigned char>& key)
261-
{
262-
Obfuscation().Xor(MakeWritableByteSpan(*this), MakeByteSpan(key));
263-
}
264-
265254
/** Compute total memory usage of this object (own memory + any dynamic memory). */
266255
size_t GetMemoryUsage() const noexcept;
267256
};
@@ -382,12 +371,12 @@ class AutoFile
382371
{
383372
protected:
384373
std::FILE* m_file;
385-
std::vector<std::byte> m_obfuscation;
374+
Obfuscation m_obfuscation;
386375
std::optional<int64_t> m_position;
387376
bool m_was_written{false};
388377

389378
public:
390-
explicit AutoFile(std::FILE* file, std::vector<std::byte> obfuscation={});
379+
explicit AutoFile(std::FILE* file, const Obfuscation& obfuscation = {});
391380

392381
~AutoFile()
393382
{
@@ -435,7 +424,7 @@ class AutoFile
435424
bool IsNull() const { return m_file == nullptr; }
436425

437426
/** Continue with a different XOR key */
438-
void SetObfuscation(std::vector<std::byte> obfuscation) { m_obfuscation = obfuscation; }
427+
void SetObfuscation(const Obfuscation& obfuscation) { m_obfuscation = obfuscation; }
439428

440429
/** Implementation detail, only used internally. */
441430
std::size_t detail_fread(std::span<std::byte> dst);

src/test/dbwrapper_tests.cpp

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,12 @@
99
#include <util/string.h>
1010

1111
#include <memory>
12+
#include <ranges>
1213

1314
#include <boost/test/unit_test.hpp>
1415

1516
using util::ToString;
1617

17-
// Test if a string consists entirely of null characters
18-
static bool is_null_key(const std::vector<unsigned char>& key) {
19-
bool isnull = true;
20-
21-
for (unsigned int i = 0; i < key.size(); i++)
22-
isnull &= (key[i] == '\x00');
23-
24-
return isnull;
25-
}
26-
2718
BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)
2819

2920
BOOST_AUTO_TEST_CASE(dbwrapper)
@@ -33,7 +24,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
3324
constexpr size_t CACHE_SIZE{1_MiB};
3425
const fs::path path{m_args.GetDataDirBase() / "dbwrapper"};
3526

36-
std::vector<uint8_t> obfuscation_key{};
27+
Obfuscation obfuscation;
3728
std::vector<std::pair<uint8_t, uint256>> key_values{};
3829

3930
// Write values
@@ -42,8 +33,8 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
4233
BOOST_CHECK_EQUAL(obfuscate, !dbw.IsEmpty());
4334

4435
// Ensure that we're doing real obfuscation when obfuscate=true
45-
obfuscation_key = dbwrapper_private::GetObfuscation(dbw);
46-
BOOST_CHECK_EQUAL(obfuscate, !is_null_key(obfuscation_key));
36+
obfuscation = dbwrapper_private::GetObfuscation(dbw);
37+
BOOST_CHECK_EQUAL(obfuscate, dbwrapper_private::GetObfuscation(dbw));
4738

4839
for (uint8_t k{0}; k < 10; ++k) {
4940
uint8_t key{k};
@@ -56,16 +47,16 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
5647
// Verify that the obfuscation key is never obfuscated
5748
{
5849
CDBWrapper dbw{{.path = path, .cache_bytes = CACHE_SIZE, .obfuscate = false}};
59-
BOOST_CHECK(obfuscation_key == dbwrapper_private::GetObfuscation(dbw));
50+
BOOST_CHECK_EQUAL(obfuscation, dbwrapper_private::GetObfuscation(dbw));
6051
}
6152

6253
// Read back the values
6354
{
6455
CDBWrapper dbw{{.path = path, .cache_bytes = CACHE_SIZE, .obfuscate = obfuscate}};
6556

6657
// Ensure obfuscation is read back correctly
67-
BOOST_CHECK(obfuscation_key == dbwrapper_private::GetObfuscation(dbw));
68-
BOOST_CHECK_EQUAL(obfuscate, !is_null_key(obfuscation_key));
58+
BOOST_CHECK_EQUAL(obfuscation, dbwrapper_private::GetObfuscation(dbw));
59+
BOOST_CHECK_EQUAL(obfuscate, dbwrapper_private::GetObfuscation(dbw));
6960

7061
// Verify all written values
7162
for (const auto& [key, expected_value] : key_values) {
@@ -89,7 +80,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)
8980
bool res_bool;
9081

9182
// Ensure that we're doing real obfuscation when obfuscate=true
92-
BOOST_CHECK_EQUAL(obfuscate, !is_null_key(dbwrapper_private::GetObfuscation(dbw)));
83+
BOOST_CHECK_EQUAL(obfuscate, dbwrapper_private::GetObfuscation(dbw));
9384

9485
//Simulate block raw data - "b + block hash"
9586
std::string key_block = "b" + m_rng.rand256().ToString();
@@ -264,7 +255,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
264255
BOOST_CHECK_EQUAL(res2.ToString(), in.ToString());
265256

266257
BOOST_CHECK(!odbw.IsEmpty());
267-
BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscation(odbw))); // The key should be an empty string
258+
BOOST_CHECK(!dbwrapper_private::GetObfuscation(odbw)); // The key should be an empty string
268259

269260
uint256 in2 = m_rng.rand256();
270261
uint256 res3;
@@ -301,7 +292,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
301292
// Check that the key/val we wrote with unobfuscated wrapper doesn't exist
302293
uint256 res2;
303294
BOOST_CHECK(!odbw.Read(key, res2));
304-
BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscation(odbw)));
295+
BOOST_CHECK(dbwrapper_private::GetObfuscation(odbw));
305296

306297
uint256 in2 = m_rng.rand256();
307298
uint256 res3;

src/test/fuzz/autofile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ FUZZ_TARGET(autofile)
2222
const auto key_bytes{ConsumeFixedLengthByteVector<std::byte>(fuzzed_data_provider, Obfuscation::KEY_SIZE)};
2323
AutoFile auto_file{
2424
fuzzed_file_provider.open(),
25-
key_bytes,
25+
Obfuscation{std::span{key_bytes}.first<Obfuscation::KEY_SIZE>()},
2626
};
2727
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100)
2828
{

0 commit comments

Comments
 (0)