Skip to content

Commit

Permalink
Add KeyManagedEncryptedEnv and AESBlockCipher (facebook#151)
Browse files Browse the repository at this point in the history
Summary:
Introduce `KeyManagedEncryptedEnv` which wraps around `EncryptedEnv` but provides an `KeyManager` API to enable key management per file. Also implements `AESBlockCipher` with OpenSSL.

Test Plan:
not tested yet. will update.

Signed-off-by: Yi Wu <[email protected]>
Signed-off-by: tabokie <[email protected]>
  • Loading branch information
yiwu-arbug authored and acelyc111 committed Aug 1, 2023
1 parent e95d27f commit f0c7d77
Show file tree
Hide file tree
Showing 15 changed files with 769 additions and 11 deletions.
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ option(WITH_SNAPPY "build with SNAPPY" OFF)
option(WITH_LZ4 "build with lz4" OFF)
option(WITH_ZLIB "build with zlib" OFF)
option(WITH_ZSTD "build with zstd" OFF)
option(WITH_OPENSSL "build with openssl" OFF)
option(WITH_WINDOWS_UTF8_FILENAMES "use UTF8 as characterset for opening files, regardles of the system code page" OFF)
if (WITH_WINDOWS_UTF8_FILENAMES)
add_definitions(-DROCKSDB_WINDOWS_UTF8_FILENAMES)
Expand Down Expand Up @@ -174,6 +175,14 @@ else()
include_directories(${ZSTD_INCLUDE_DIR})
list(APPEND THIRDPARTY_LIBS zstd::zstd)
endif()

if(WITH_OPENSSL)
find_package(OpenSSL REQUIRED)
add_definitions(-DOPENSSL)
include_directories(${OPENSSL_INCLUDE_DIR})
# Only the crypto library is needed.
list(APPEND THIRDPARTY_LIBS ${OPENSSL_CRYPTO_LIBRARIES})
endif()
endif()

option(WITH_MD_LIBRARY "build with MD" ON)
Expand Down Expand Up @@ -736,6 +745,7 @@ set(SOURCES
db/write_controller.cc
db/write_stall_stats.cc
db/write_thread.cc
encryption/encryption.cc
env/composite_env.cc
env/env.cc
env/env_chroot.cc
Expand Down
1 change: 1 addition & 0 deletions TARGETS
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
"db/write_controller.cc",
"db/write_stall_stats.cc",
"db/write_thread.cc",
"encryption/encryption.cc",
"env/composite_env.cc",
"env/env.cc",
"env/env_chroot.cc",
Expand Down
13 changes: 13 additions & 0 deletions build_tools/build_detect_platform
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,19 @@ EOF
fi
fi

if ! test $ROCKSDB_DISABLE_OPENSSL; then
# Test whether OpenSSL library is installed
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
#include <openssl/crypto.h>
int main() {}
EOF
if [ "$?" = 0 ]; then
COMMON_FLAGS="$COMMON_FLAGS -DOPENSSL"
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lcrypto"
JAVA_LDFLAGS="$JAVA_LDFLAGS -lcrypto"
fi
fi

if ! test $ROCKSDB_DISABLE_PTHREAD_MUTEX_ADAPTIVE_NP; then
# Test whether PTHREAD_MUTEX_ADAPTIVE_NP mutex type is available
$CXX $PLATFORM_CXXFLAGS -x c++ - -o test.o 2>/dev/null <<EOF
Expand Down
3 changes: 2 additions & 1 deletion db/db_options_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1058,10 +1058,11 @@ TEST_F(DBOptionsTest, CompactionReadaheadSizeChange) {
}

TEST_F(DBOptionsTest, FIFOTtlBackwardCompatible) {
Options options;
Options options = CurrentOptions();
options.compaction_style = kCompactionStyleFIFO;
options.write_buffer_size = 10 << 10; // 10KB
options.create_if_missing = true;
options.max_open_files = -1;
options.env = CurrentOptions().env;
options.num_levels = 1;

Expand Down
2 changes: 1 addition & 1 deletion db/db_properties_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1897,7 +1897,7 @@ TEST_F(DBPropertiesTest, BlobCacheProperties) {
}

TEST_F(DBPropertiesTest, BlockCacheProperties) {
Options options;
Options options = CurrentOptions();
uint64_t value;

options.env = CurrentOptions().env;
Expand Down
3 changes: 3 additions & 0 deletions db/db_test2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2735,6 +2735,9 @@ TEST_F(DBTest2, ReadAmpBitmap) {

#ifndef OS_SOLARIS // GetUniqueIdFromFile is not implemented
TEST_F(DBTest2, ReadAmpBitmapLiveInCacheAfterDBClose) {
if (getenv("ENCRYPTED_ENV")) {
return;
}
{
const int kIdBufLen = 100;
char id_buf[kIdBufLen];
Expand Down
24 changes: 15 additions & 9 deletions db/db_test_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ int64_t MaybeCurrentTime(Env* env) {
}
} // anonymous namespace

#ifdef OPENSSL
const std::string TestKeyManager::default_key =
"\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34"
"\x56\x78\x12\x34\x56\x78";
const std::string TestKeyManager::default_iv =
"\xaa\xbb\xcc\xdd\xaa\xbb\xcc\xdd\xaa\xbb\xcc\xdd\xaa\xbb\xcc\xdd";
#endif

// Special Env used to delay background operations

SpecialEnv::SpecialEnv(Env* base, bool time_elapse_only_sleep)
Expand Down Expand Up @@ -71,15 +79,13 @@ DBTestBase::DBTestBase(const std::string path, bool env_do_fsync)
mem_env_ = MockEnv::Create(base_env, base_env->GetSystemClock());
}
if (getenv("ENCRYPTED_ENV")) {
std::shared_ptr<EncryptionProvider> provider;
std::string provider_id = getenv("ENCRYPTED_ENV");
if (provider_id.find("=") == std::string::npos &&
!EndsWith(provider_id, "://test")) {
provider_id = provider_id + "://test";
}
EXPECT_OK(EncryptionProvider::CreateFromString(ConfigOptions(), provider_id,
&provider));
encrypted_env_ = NewEncryptedEnv(mem_env_ ? mem_env_ : base_env, provider);
#ifdef OPENSSL
std::shared_ptr<encryption::KeyManager> key_manager(new TestKeyManager);
encrypted_env_ = NewKeyManagedEncryptedEnv(Env::Default(), key_manager);
#else
fprintf(stderr, "EncryptedEnv is not available without OpenSSL.");
assert(false);
#endif
}
env_ = new SpecialEnv(encrypted_env_ ? encrypted_env_
: (mem_env_ ? mem_env_ : base_env));
Expand Down
36 changes: 36 additions & 0 deletions db/db_test_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "rocksdb/compaction_filter.h"
#include "rocksdb/convenience.h"
#include "rocksdb/db.h"
#include "rocksdb/encryption.h"
#include "rocksdb/env.h"
#include "rocksdb/file_system.h"
#include "rocksdb/filter_policy.h"
Expand All @@ -55,6 +56,41 @@
namespace ROCKSDB_NAMESPACE {
class MockEnv;

// TODO(yiwu): Use InMemoryKeyManager instead for tests.
#ifdef OPENSSL
class TestKeyManager : public encryption::KeyManager {
public:
virtual ~TestKeyManager() = default;

static const std::string default_key;
static const std::string default_iv;

Status GetFile(const std::string& /*fname*/,
encryption::FileEncryptionInfo* file_info) override {
file_info->method = encryption::EncryptionMethod::kAES192_CTR;
file_info->key = default_key;
file_info->iv = default_iv;
return Status::OK();
}

Status NewFile(const std::string& /*fname*/,
encryption::FileEncryptionInfo* file_info) override {
file_info->method = encryption::EncryptionMethod::kAES192_CTR;
file_info->key = default_key;
file_info->iv = default_iv;
return Status::OK();
}

Status DeleteFile(const std::string&) override { return Status::OK(); }
Status LinkFile(const std::string&, const std::string&) override {
return Status::OK();
}
Status RenameFile(const std::string&, const std::string&) override {
return Status::OK();
}
};
#endif

namespace anon {
class AtomicCounter {
public:
Expand Down
15 changes: 15 additions & 0 deletions db/db_wal_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,9 @@ INSTANTIATE_TEST_CASE_P(
// at the end of any of the logs
// - We do not expect to open the data store for corruption
TEST_P(DBWALTestWithParams, kTolerateCorruptedTailRecords) {
if (getenv("ENCRYPTED_ENV")) {
return;
}
bool trunc = std::get<0>(GetParam()); // Corruption style
// Corruption offset position
int corrupt_offset = std::get<1>(GetParam());
Expand Down Expand Up @@ -1493,6 +1496,9 @@ TEST_P(DBWALTestWithParams, kAbsoluteConsistency) {
// We don't expect the data store to be opened if there is any inconsistency
// between WAL and SST files
TEST_F(DBWALTest, kPointInTimeRecoveryCFConsistency) {
if (getenv("ENCRYPTED_ENV")) {
return;
}
Options options = CurrentOptions();
options.avoid_flush_during_recovery = true;

Expand Down Expand Up @@ -1700,6 +1706,9 @@ TEST_F(DBWALTest, FixSyncWalOnObseletedWalWithNewManifestCausingMissingWAL) {
// - We expect to open data store under all circumstances
// - We expect only data upto the point where the first error was encountered
TEST_P(DBWALTestWithParams, kPointInTimeRecovery) {
if (getenv("ENCRYPTED_ENV")) {
return;
}
const int maxkeys =
RecoveryTestHelper::kWALFilesCount * RecoveryTestHelper::kKeysPerWALFile;

Expand Down Expand Up @@ -1760,6 +1769,9 @@ TEST_P(DBWALTestWithParams, kPointInTimeRecovery) {
// - We expect to open the data store under all scenarios
// - We expect to have recovered records past the corruption zone
TEST_P(DBWALTestWithParams, kSkipAnyCorruptedRecords) {
if (getenv("ENCRYPTED_ENV")) {
return;
}
bool trunc = std::get<0>(GetParam()); // Corruption style
// Corruption offset position
int corrupt_offset = std::get<1>(GetParam());
Expand Down Expand Up @@ -1969,6 +1981,9 @@ TEST_F(DBWALTest, RecoverWithoutFlushMultipleCF) {
// 4. Open again. See if it can correctly handle previous corruption.
TEST_P(DBWALTestWithParamsVaryingRecoveryMode,
RecoverFromCorruptedWALWithoutFlush) {
if (getenv("ENCRYPTED_ENV")) {
return;
}
const int kAppendKeys = 100;
Options options = CurrentOptions();
options.avoid_flush_during_recovery = true;
Expand Down
Loading

0 comments on commit f0c7d77

Please sign in to comment.