Skip to content

Commit 113b363

Browse files
author
yiwu-arbug
authored
Add KeyManagedEncryptedEnv and AESBlockCipher (#151)
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 <yiwu@pingcap.com>
1 parent 906258c commit 113b363

18 files changed

+784
-29
lines changed

.travis.yml

+9-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ addons:
2525
- libsnappy-dev
2626
- mingw-w64
2727
- zlib1g-dev
28+
- libssl-dev
2829
env:
2930
- TEST_GROUP=platform_dependent # 16-18 minutes
3031
- TEST_GROUP=1 # 33-35 minutes
@@ -36,6 +37,7 @@ env:
3637
- JOB_NAME=lite_build # 3-4 minutes
3738
# Build examples
3839
- JOB_NAME=examples # 5-7 minutes
40+
- JOB_NAME=encrypted_env # 16-18 minutes
3941

4042
matrix:
4143
exclude:
@@ -49,13 +51,15 @@ matrix:
4951
env: TEST_GROUP=4
5052
- os : linux
5153
compiler: clang
52-
- os : osx
54+
- os: osx
5355
compiler: gcc
56+
- os: osx
57+
env: JOB_NAME=encrypted_env
5458

5559
# https://docs.travis-ci.com/user/caching/#ccache-cache
5660
install:
5761
- if [ "${TRAVIS_OS_NAME}" == osx ]; then
58-
brew install ccache zstd lz4 snappy xz;
62+
brew install ccache zstd lz4 snappy xz openssl;
5963
PATH=$PATH:/usr/local/opt/ccache/libexec;
6064
fi
6165

@@ -91,6 +95,9 @@ script:
9195
examples)
9296
OPT=-DTRAVIS V=1 make -j4 static_lib && cd examples && make -j4
9397
;;
98+
encrypted_env)
99+
OPT=-DTRAVIS V=1 ROCKSDBTESTS_END=db_block_cache_test ENCRYPTED_ENV=1 make -j4 all_but_some_tests check_some
100+
;;
94101
esac
95102
notifications:
96103
email:

CMakeLists.txt

+10
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ option(WITH_SNAPPY "build with SNAPPY" OFF)
5555
option(WITH_LZ4 "build with lz4" OFF)
5656
option(WITH_ZLIB "build with zlib" OFF)
5757
option(WITH_ZSTD "build with zstd" OFF)
58+
option(WITH_OPENSSL "build with openssl" OFF)
5859
option(WITH_WINDOWS_UTF8_FILENAMES "use UTF8 as characterset for opening files, regardles of the system code page" OFF)
5960
if (WITH_WINDOWS_UTF8_FILENAMES)
6061
add_definitions(-DROCKSDB_WINDOWS_UTF8_FILENAMES)
@@ -131,6 +132,14 @@ else()
131132
include_directories(${ZSTD_INCLUDE_DIR})
132133
list(APPEND THIRDPARTY_LIBS ${ZSTD_LIBRARIES})
133134
endif()
135+
136+
if(WITH_OPENSSL)
137+
find_package(OpenSSL REQUIRED)
138+
add_definitions(-DOPENSSL)
139+
include_directories(${OPENSSL_INCLUDE_DIR})
140+
# Only the crypto library is needed.
141+
list(APPEND THIRDPARTY_LIBS ${OPENSSL_CRYPTO_LIBRARIES})
142+
endif()
134143
endif()
135144

136145
string(TIMESTAMP GIT_DATE_TIME "%Y/%m/%d %H:%M:%S" UTC)
@@ -545,6 +554,7 @@ set(SOURCES
545554
db/write_batch_base.cc
546555
db/write_controller.cc
547556
db/write_thread.cc
557+
encryption/encryption.cc
548558
env/env.cc
549559
env/env_chroot.cc
550560
env/env_encryption.cc

build_tools/build_detect_platform

+13
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,19 @@ EOF
406406
fi
407407
fi
408408

409+
if ! test $ROCKSDB_DISABLE_OPENSSL; then
410+
# Test whether OpenSSL library is installed
411+
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
412+
#include <openssl/crypto.h>
413+
int main() {}
414+
EOF
415+
if [ "$?" = 0 ]; then
416+
COMMON_FLAGS="$COMMON_FLAGS -DOPENSSL"
417+
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lcrypto"
418+
JAVA_LDFLAGS="$JAVA_LDFLAGS -lcrypto"
419+
fi
420+
fi
421+
409422
if ! test $ROCKSDB_DISABLE_PTHREAD_MUTEX_ADAPTIVE_NP; then
410423
# Test whether PTHREAD_MUTEX_ADAPTIVE_NP mutex type is available
411424
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF

db/db_basic_test.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ TEST_F(DBBasicTest, DBClose) {
938938

939939
TEST_F(DBBasicTest, DBCloseFlushError) {
940940
std::unique_ptr<FaultInjectionTestEnv> fault_injection_env(
941-
new FaultInjectionTestEnv(Env::Default()));
941+
new FaultInjectionTestEnv(env_));
942942
Options options = GetDefaultOptions();
943943
options.create_if_missing = true;
944944
options.manual_wal_flush = true;

db/db_options_test.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ TEST_F(DBOptionsTest, MaxOpenFilesChange) {
602602
}
603603

604604
TEST_F(DBOptionsTest, SanitizeDelayedWriteRate) {
605-
Options options;
605+
Options options = CurrentOptions();
606606
options.delayed_write_rate = 0;
607607
Reopen(options);
608608
ASSERT_EQ(16 * 1024 * 1024, dbfull()->GetDBOptions().delayed_write_rate);
@@ -748,10 +748,11 @@ TEST_F(DBOptionsTest, CompactionReadaheadSizeChange) {
748748
}
749749

750750
TEST_F(DBOptionsTest, FIFOTtlBackwardCompatible) {
751-
Options options;
751+
Options options = CurrentOptions();
752752
options.compaction_style = kCompactionStyleFIFO;
753753
options.write_buffer_size = 10 << 10; // 10KB
754754
options.create_if_missing = true;
755+
options.max_open_files = -1;
755756

756757
ASSERT_OK(TryReopen(options));
757758

db/db_properties_test.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,7 @@ TEST_F(DBPropertiesTest, NeedCompactHintPersistentTest) {
14061406
}
14071407

14081408
TEST_F(DBPropertiesTest, EstimateNumKeysUnderflow) {
1409-
Options options;
1409+
Options options = CurrentOptions();
14101410
Reopen(options);
14111411
Put("foo", "bar");
14121412
Delete("foo");
@@ -1417,7 +1417,7 @@ TEST_F(DBPropertiesTest, EstimateNumKeysUnderflow) {
14171417
}
14181418

14191419
TEST_F(DBPropertiesTest, EstimateOldestKeyTime) {
1420-
std::unique_ptr<MockTimeEnv> mock_env(new MockTimeEnv(Env::Default()));
1420+
std::unique_ptr<MockTimeEnv> mock_env(new MockTimeEnv(env_));
14211421
uint64_t oldest_key_time = 0;
14221422
Options options;
14231423
options.env = mock_env.get();
@@ -1517,7 +1517,7 @@ TEST_F(DBPropertiesTest, SstFilesSize) {
15171517
};
15181518
std::shared_ptr<TestListener> listener = std::make_shared<TestListener>();
15191519

1520-
Options options;
1520+
Options options = CurrentOptions();
15211521
options.disable_auto_compactions = true;
15221522
options.listeners.push_back(listener);
15231523
Reopen(options);
@@ -1599,7 +1599,7 @@ TEST_F(DBPropertiesTest, MinObsoleteSstNumberToKeep) {
15991599
}
16001600

16011601
TEST_F(DBPropertiesTest, BlockCacheProperties) {
1602-
Options options;
1602+
Options options = CurrentOptions();
16031603
uint64_t value;
16041604

16051605
// Block cache properties are not available for tables other than

db/db_test2.cc

+19-8
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,9 @@ TEST_F(DBTest2, ReadAmpBitmap) {
21452145

21462146
#ifndef OS_SOLARIS // GetUniqueIdFromFile is not implemented
21472147
TEST_F(DBTest2, ReadAmpBitmapLiveInCacheAfterDBClose) {
2148+
if (getenv("ENCRYPTED_ENV")) {
2149+
return;
2150+
}
21482151
{
21492152
const int kIdBufLen = 100;
21502153
char id_buf[kIdBufLen];
@@ -2706,7 +2709,7 @@ TEST_F(DBTest2, RateLimitedCompactionReads) {
27062709
// Make sure DB can be reopen with reduced number of levels, given no file
27072710
// is on levels higher than the new num_levels.
27082711
TEST_F(DBTest2, ReduceLevel) {
2709-
Options options;
2712+
Options options = CurrentOptions();
27102713
options.disable_auto_compactions = true;
27112714
options.num_levels = 7;
27122715
Reopen(options);
@@ -2732,7 +2735,7 @@ TEST_F(DBTest2, ReduceLevel) {
27322735

27332736
// Test that ReadCallback is actually used in both memtbale and sst tables
27342737
TEST_F(DBTest2, ReadCallbackTest) {
2735-
Options options;
2738+
Options options = CurrentOptions();
27362739
options.disable_auto_compactions = true;
27372740
options.num_levels = 7;
27382741
Reopen(options);
@@ -2990,7 +2993,8 @@ TEST_F(DBTest2, TraceAndReplay) {
29902993
column_families.push_back(
29912994
ColumnFamilyDescriptor("pikachu", ColumnFamilyOptions()));
29922995
std::vector<ColumnFamilyHandle*> handles;
2993-
ASSERT_OK(DB::Open(DBOptions(), dbname2, column_families, &handles, &db2));
2996+
ASSERT_OK(
2997+
DB::Open(CurrentOptions(), dbname2, column_families, &handles, &db2));
29942998

29952999
env_->SleepForMicroseconds(100);
29963000
// Verify that the keys don't already exist
@@ -3065,7 +3069,8 @@ TEST_F(DBTest2, TraceWithLimit) {
30653069
column_families.push_back(
30663070
ColumnFamilyDescriptor("pikachu", ColumnFamilyOptions()));
30673071
std::vector<ColumnFamilyHandle*> handles;
3068-
ASSERT_OK(DB::Open(DBOptions(), dbname2, column_families, &handles, &db2));
3072+
ASSERT_OK(
3073+
DB::Open(CurrentOptions(), dbname2, column_families, &handles, &db2));
30693074

30703075
env_->SleepForMicroseconds(100);
30713076
// Verify that the keys don't already exist
@@ -3133,7 +3138,8 @@ TEST_F(DBTest2, TraceWithSampling) {
31333138
column_families.push_back(
31343139
ColumnFamilyDescriptor("pikachu", ColumnFamilyOptions()));
31353140
std::vector<ColumnFamilyHandle*> handles;
3136-
ASSERT_OK(DB::Open(DBOptions(), dbname2, column_families, &handles, &db2));
3141+
ASSERT_OK(
3142+
DB::Open(CurrentOptions(), dbname2, column_families, &handles, &db2));
31373143

31383144
env_->SleepForMicroseconds(100);
31393145
ASSERT_TRUE(db2->Get(ro, handles[0], "a", &value).IsNotFound());
@@ -3233,7 +3239,8 @@ TEST_F(DBTest2, TraceWithFilter) {
32333239
column_families.push_back(
32343240
ColumnFamilyDescriptor("pikachu", ColumnFamilyOptions()));
32353241
std::vector<ColumnFamilyHandle*> handles;
3236-
ASSERT_OK(DB::Open(DBOptions(), dbname2, column_families, &handles, &db2));
3242+
ASSERT_OK(
3243+
DB::Open(CurrentOptions(), dbname2, column_families, &handles, &db2));
32373244

32383245
env_->SleepForMicroseconds(100);
32393246
// Verify that the keys don't already exist
@@ -3279,7 +3286,8 @@ TEST_F(DBTest2, TraceWithFilter) {
32793286
handles.clear();
32803287

32813288
DB* db3 = nullptr;
3282-
ASSERT_OK(DB::Open(DBOptions(), dbname3, column_families, &handles, &db3));
3289+
ASSERT_OK(
3290+
DB::Open(CurrentOptions(), dbname3, column_families, &handles, &db3));
32833291

32843292
env_->SleepForMicroseconds(100);
32853293
// Verify that the keys don't already exist
@@ -3334,6 +3342,9 @@ TEST_F(DBTest2, TraceWithFilter) {
33343342
#endif // ROCKSDB_LITE
33353343

33363344
TEST_F(DBTest2, PinnableSliceAndMmapReads) {
3345+
if (getenv("ENCRYPTED_ENV")) {
3346+
return;
3347+
}
33373348
Options options = CurrentOptions();
33383349
options.allow_mmap_reads = true;
33393350
options.max_open_files = 100;
@@ -3612,7 +3623,7 @@ TEST_F(DBTest2, TestCompactFiles) {
36123623
});
36133624
SyncPoint::GetInstance()->EnableProcessing();
36143625

3615-
Options options;
3626+
Options options = CurrentOptions();
36163627
options.num_levels = 2;
36173628
options.disable_auto_compactions = true;
36183629
Reopen(options);

db/db_test_util.cc

+15-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414

1515
namespace rocksdb {
1616

17+
#ifdef OPENSSL
18+
const std::string TestKeyManager::default_key =
19+
"\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34\x56\x78\x12\x34"
20+
"\x56\x78\x12\x34\x56\x78";
21+
const std::string TestKeyManager::default_iv =
22+
"\xaa\xbb\xcc\xdd\xaa\xbb\xcc\xdd\xaa\xbb\xcc\xdd\xaa\xbb\xcc\xdd";
23+
#endif
24+
1725
// Special Env used to delay background operations
1826

1927
SpecialEnv::SpecialEnv(Env* base)
@@ -68,8 +76,13 @@ DBTestBase::DBTestBase(const std::string path)
6876
}
6977
#ifndef ROCKSDB_LITE
7078
if (getenv("ENCRYPTED_ENV")) {
71-
encrypted_env_ = NewEncryptedEnv(mem_env_ ? mem_env_ : base_env,
72-
new CTREncryptionProvider(rot13Cipher_));
79+
#ifdef OPENSSL
80+
std::shared_ptr<encryption::KeyManager> key_manager(new TestKeyManager);
81+
encrypted_env_ = NewKeyManagedEncryptedEnv(Env::Default(), key_manager);
82+
#else
83+
fprintf(stderr, "EncryptedEnv is not available without OpenSSL.");
84+
assert(false);
85+
#endif
7386
}
7487
#endif // !ROCKSDB_LITE
7588
env_ = new SpecialEnv(encrypted_env_ ? encrypted_env_

db/db_test_util.h

+37
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,45 @@
5252
#include "util/string_util.h"
5353
#include "utilities/merge_operators.h"
5454

55+
#include "rocksdb/encryption.h"
56+
5557
namespace rocksdb {
5658

59+
//TODO(yiwu): Use InMemoryKeyManager instead for tests.
60+
#ifdef OPENSSL
61+
class TestKeyManager : public encryption::KeyManager {
62+
public:
63+
virtual ~TestKeyManager() = default;
64+
65+
static const std::string default_key;
66+
static const std::string default_iv;
67+
68+
Status GetFile(const std::string& /*fname*/,
69+
encryption::FileEncryptionInfo* file_info) override {
70+
file_info->method = encryption::EncryptionMethod::kAES192_CTR;
71+
file_info->key = default_key;
72+
file_info->iv = default_iv;
73+
return Status::OK();
74+
}
75+
76+
Status NewFile(const std::string& /*fname*/,
77+
encryption::FileEncryptionInfo* file_info) override {
78+
file_info->method = encryption::EncryptionMethod::kAES192_CTR;
79+
file_info->key = default_key;
80+
file_info->iv = default_iv;
81+
return Status::OK();
82+
}
83+
84+
Status DeleteFile(const std::string&) override { return Status::OK(); }
85+
Status LinkFile(const std::string&, const std::string&) override {
86+
return Status::OK();
87+
}
88+
Status RenameFile(const std::string&, const std::string&) override {
89+
return Status::OK();
90+
}
91+
};
92+
#endif
93+
5794
namespace anon {
5895
class AtomicCounter {
5996
public:

db/db_wal_test.cc

+15
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,9 @@ class RecoveryTestHelper {
948948
// at the end of any of the logs
949949
// - We do not expect to open the data store for corruption
950950
TEST_F(DBWALTest, kTolerateCorruptedTailRecords) {
951+
if (getenv("ENCRYPTED_ENV")) {
952+
return;
953+
}
951954
const int jstart = RecoveryTestHelper::kWALFileOffset;
952955
const int jend = jstart + RecoveryTestHelper::kWALFilesCount;
953956

@@ -1019,6 +1022,9 @@ TEST_F(DBWALTest, kAbsoluteConsistency) {
10191022
// We don't expect the data store to be opened if there is any inconsistency
10201023
// between WAL and SST files
10211024
TEST_F(DBWALTest, kPointInTimeRecoveryCFConsistency) {
1025+
if (getenv("ENCRYPTED_ENV")) {
1026+
return;
1027+
}
10221028
Options options = CurrentOptions();
10231029
options.avoid_flush_during_recovery = true;
10241030

@@ -1052,6 +1058,9 @@ TEST_F(DBWALTest, kPointInTimeRecoveryCFConsistency) {
10521058
// - We expect to open data store under all circumstances
10531059
// - We expect only data upto the point where the first error was encountered
10541060
TEST_F(DBWALTest, kPointInTimeRecovery) {
1061+
if (getenv("ENCRYPTED_ENV")) {
1062+
return;
1063+
}
10551064
const int jstart = RecoveryTestHelper::kWALFileOffset;
10561065
const int jend = jstart + RecoveryTestHelper::kWALFilesCount;
10571066
const int maxkeys =
@@ -1103,6 +1112,9 @@ TEST_F(DBWALTest, kPointInTimeRecovery) {
11031112
// - We expect to open the data store under all scenarios
11041113
// - We expect to have recovered records past the corruption zone
11051114
TEST_F(DBWALTest, kSkipAnyCorruptedRecords) {
1115+
if (getenv("ENCRYPTED_ENV")) {
1116+
return;
1117+
}
11061118
const int jstart = RecoveryTestHelper::kWALFileOffset;
11071119
const int jend = jstart + RecoveryTestHelper::kWALFilesCount;
11081120

@@ -1310,6 +1322,9 @@ TEST_F(DBWALTest, RecoverWithoutFlushMultipleCF) {
13101322
// 3. Append more data without flushing, which creates new WAL log.
13111323
// 4. Open again. See if it can correctly handle previous corruption.
13121324
TEST_F(DBWALTest, RecoverFromCorruptedWALWithoutFlush) {
1325+
if (getenv("ENCRYPTED_ENV")) {
1326+
return;
1327+
}
13131328
const int jstart = RecoveryTestHelper::kWALFileOffset;
13141329
const int jend = jstart + RecoveryTestHelper::kWALFilesCount;
13151330
const int kAppendKeys = 100;

0 commit comments

Comments
 (0)