This is an automated email from the ASF dual-hosted git repository.
abukor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git
The following commit(s) were added to refs/heads/master by this push:
new de02a34 [encryption] Add encryption support to Env
de02a34 is described below
commit de02a34390f9bdb722be39f96ef9ad9573c0eeeb
Author: Attila Bukor <[email protected]>
AuthorDate: Wed Mar 31 18:57:28 2021 +0200
[encryption] Add encryption support to Env
This commit introduces reading and writing encrypted files through Env.
At this stage, encryption is not usable, as it uses a static dummy key.
Originally, I wanted to use a simple Caesar's cipher like ROT13 until
the rest of the key infra is in place, but then I decided this proof of
concept implementation should also prove that CTR, which is our chosen
mode of operation[1] works for our access patterns, so I ended up using
OpenSSL even in this proof of concept, albeit with a static key and
key size.
[1] https://s.apache.org/kudu-atrest-enc-design
Change-Id: Id5a81b5736a0c1970818dbbc4a234480476b8d41
Reviewed-on: http://gerrit.cloudera.org:8080/17251
Tested-by: Kudu Jenkins
Reviewed-by: Alexey Serbin <[email protected]>
---
src/kudu/util/coding-inl.h | 14 +++
src/kudu/util/env-test.cc | 111 ++++++++++++++++++++++++
src/kudu/util/env.h | 28 ++++--
src/kudu/util/env_posix.cc | 200 +++++++++++++++++++++++++++++++++++++------
src/kudu/util/openssl_util.h | 4 +-
5 files changed, 321 insertions(+), 36 deletions(-)
diff --git a/src/kudu/util/coding-inl.h b/src/kudu/util/coding-inl.h
index a47e9ce..20e639f 100644
--- a/src/kudu/util/coding-inl.h
+++ b/src/kudu/util/coding-inl.h
@@ -86,6 +86,20 @@ inline void InlineEncodeFixed64(uint8_t *buf, uint64_t
value) {
#endif
}
+inline void InlineBigEndianEncodeFixed64(uint8_t* buf, uint64_t value) {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ memcpy(buf, &value, sizeof(value));
+#else
+ buf[0] = (value >> 56) & 0xff;
+ buf[1] = (value >> 48) & 0xff;
+ buf[2] = (value >> 40) & 0xff;
+ buf[3] = (value >> 32) & 0xff;
+ buf[4] = (value >> 24) & 0xff;
+ buf[5] = (value >> 16) & 0xff;
+ buf[6] = (value >> 8) & 0xff;
+ buf[7] = value & 0xff;
+#endif
+}
// Standard Put... routines append to a string
template <class StrType>
diff --git a/src/kudu/util/env-test.cc b/src/kudu/util/env-test.cc
index 287ec6b..5dbe4cf 100644
--- a/src/kudu/util/env-test.cc
+++ b/src/kudu/util/env-test.cc
@@ -1249,4 +1249,115 @@ TEST_F(TestEnv, TestCreateFifo) {
ASSERT_OK(env_->NewFifo(kFifo, &fifo));
}
+TEST_F(TestEnv, TestEncryption) {
+ const string kFile = JoinPathSegments(test_dir_, "encrypted_file");
+ unique_ptr<RWFile> rw;
+ RWFileOptions opts;
+ opts.encrypted = true;
+ ASSERT_OK(env_->NewRWFile(opts, kFile, &rw));
+
+ string kTestData =
+ "Hello world! This text is slightly longer than usual to make sure
multiple blocks are "
+ "encrypted and we can read at unaligned offsets correctly. Lorem ipsum
dolor sit amet, "
+ "consectetur adipiscing elit.";
+
+ string kTestData2 =
+ "We also need to append to this file to make sure initialization vectors
are calculated "
+ "correctly.";
+
+ ASSERT_OK(rw->Write(0, kTestData));
+ ASSERT_OK(rw->Write(kTestData.length(), kTestData2));
+
+ // Setup read parameters
+ constexpr size_t size1 = 9;
+ uint8_t scratch1[size1];
+ Slice result1(scratch1, size1);
+ constexpr size_t size2 = 19;
+ uint8_t scratch2[size2];
+ Slice result2(scratch2, size2);
+ vector<Slice> results = { result1, result2 };
+
+ // Reading back from the RWFile should succeed
+ ASSERT_OK(rw->ReadV(13, results));
+ ASSERT_EQ(result1, "This text");
+ ASSERT_EQ(result2, " is slightly longer");
+
+ ASSERT_OK(rw->Close());
+
+ unique_ptr<RandomAccessFile> unencrpyted;
+ RandomAccessFileOptions unencrpyted_opts;
+ unencrpyted_opts.encrypted = false;
+ ASSERT_OK(env_->NewRandomAccessFile(unencrpyted_opts, kFile, &unencrpyted));
+
+ // Treating it as an unencrypted file should yield garbage and not contain
the
+ // cleartext written to the file.
+ string unencrypted_string;
+ ASSERT_OK(unencrpyted->Read(0, unencrypted_string));
+ ASSERT_EQ(string::npos, unencrypted_string.find("This text is slightly
longer"));
+
+ // Check if the file can be read into a SequentialFile.
+ unique_ptr<SequentialFile> seq_file;
+ SequentialFileOptions seq_opts;
+ seq_opts.encrypted = true;
+ ASSERT_OK(env_->NewSequentialFile(seq_opts, kFile, &seq_file));
+
+ ASSERT_OK(seq_file->Read(&result1));
+ ASSERT_OK(seq_file->Read(&result2));
+ ASSERT_EQ(result1, "Hello wor");
+ ASSERT_EQ(result2, "ld! This text is sl");
+
+ // Check if the file can be read into a RandomAccessFile if treated properly
+ // as an encrypted file.
+ unique_ptr<RandomAccessFile> random;
+ RandomAccessFileOptions random_opts;
+ random_opts.encrypted = true;
+ ASSERT_OK(env_->NewRandomAccessFile(random_opts, kFile, &random));
+ size_t size = kTestData.length() + kTestData2.length();
+ uint8_t scratch[size];
+ Slice result(scratch, size);
+ ASSERT_OK(random->Read(0, result));
+ ASSERT_EQ(kTestData + kTestData2, result);
+
+ // Read a SequentialFile until EOF.
+ ASSERT_OK(env_->NewSequentialFile(seq_opts, kFile, &seq_file));
+ uint8_t scratch3[size + 10];
+ Slice result3(scratch3, size + 10);
+ ASSERT_OK(seq_file->Read(&result3));
+ ASSERT_EQ(kTestData + kTestData2, result3);
+}
+
+TEST_F(TestEnv, TestPreallocatedReadEncryptedFile) {
+ const string kFile = JoinPathSegments(test_dir_, "encrypted_file");
+ unique_ptr<RWFile> rw;
+ RWFileOptions opts;
+ opts.encrypted = true;
+ ASSERT_OK(env_->NewRWFile(opts, kFile, &rw));
+
+ ASSERT_OK(rw->PreAllocate(0, 1024, RWFile::CHANGE_FILE_SIZE));
+
+ size_t size = 10;
+ uint8_t scratch[size];
+ Slice result(scratch, size);
+ vector<Slice> results = {result};
+ ASSERT_OK(rw->ReadV(0, results));
+ ASSERT_TRUE(IsAllZeros(result));
+}
+
+TEST_F(TestEnv, TestEncryptionMultipleSlices) {
+ const string kFile = JoinPathSegments(test_dir_, "encrypted_file");
+ unique_ptr<RWFile> rw;
+ RWFileOptions opts;
+ opts.encrypted = true;
+ ASSERT_OK(env_->NewRWFile(opts, kFile, &rw));
+
+ vector<Slice> data = {"foo", "bar", "hello", "world"};
+
+ ASSERT_OK(rw->WriteV(0, data));
+
+ uint8_t scratch[16];
+ Slice result(scratch, 16);
+ ASSERT_OK(rw->Read(0, result));
+ ASSERT_EQ("foobarhelloworld", result);
+}
+
} // namespace kudu
diff --git a/src/kudu/util/env.h b/src/kudu/util/env.h
index ce436a8..2ed394b 100644
--- a/src/kudu/util/env.h
+++ b/src/kudu/util/env.h
@@ -37,6 +37,7 @@ class WritableFile;
struct RandomAccessFileOptions;
struct RWFileOptions;
struct WritableFileOptions;
+struct SequentialFileOptions;
template <typename T>
class ArrayView;
@@ -84,6 +85,11 @@ class Env {
virtual Status NewSequentialFile(const std::string& fname,
std::unique_ptr<SequentialFile>* result) =
0;
+ // Like the previous NewSequentialFile, but allows options to be specified.
+ virtual Status NewSequentialFile(const SequentialFileOptions& opts,
+ const std::string& fname,
+ std::unique_ptr<SequentialFile>* result) =
0;
+
// Create a brand new random access read-only file with the
// specified name. On success, stores a pointer to the new file in
// *result and returns OK. On failure stores NULL in *result and
@@ -407,10 +413,16 @@ class Fifo : public File {
virtual int write_fd() const = 0;
};
+struct SequentialFileOptions {
+ bool encrypted;
+
+ SequentialFileOptions() : encrypted(false) {}
+};
+
// A file abstraction for reading sequentially through a file
class SequentialFile : public File {
public:
- SequentialFile() { }
+ SequentialFile() {}
// Read up to "result.size" bytes from the file.
// Sets "result.data" to the data that was read.
@@ -482,14 +494,17 @@ struct WritableFileOptions {
// See CreateMode for details.
Env::OpenMode mode;
+ bool encrypted;
+
WritableFileOptions()
- : sync_on_close(false),
- mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE) { }
+ : sync_on_close(false), mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE),
encrypted(false) {}
};
// Options specified when a file is opened for random access.
struct RandomAccessFileOptions {
- RandomAccessFileOptions() {}
+ bool encrypted;
+
+ RandomAccessFileOptions() : encrypted(false) {}
};
// A file abstraction for sequential writing. The implementation
@@ -549,9 +564,10 @@ struct RWFileOptions {
// See CreateMode for details.
Env::OpenMode mode;
+ bool encrypted;
+
RWFileOptions()
- : sync_on_close(false),
- mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE) { }
+ : sync_on_close(false), mode(Env::CREATE_OR_OPEN_WITH_TRUNCATE),
encrypted(false) {}
};
// A file abstraction for both reading and writing. No notion of a built-in
diff --git a/src/kudu/util/env_posix.cc b/src/kudu/util/env_posix.cc
index b25e9c5..eec7e5e 100644
--- a/src/kudu/util/env_posix.cc
+++ b/src/kudu/util/env_posix.cc
@@ -7,6 +7,7 @@
#include <fnmatch.h>
#include <fts.h>
#include <glob.h>
+#include <openssl/ssl.h>
#include <pthread.h>
#include <sys/resource.h>
#include <sys/socket.h>
@@ -49,6 +50,7 @@
#include "kudu/gutil/strings/substitute.h"
#include "kudu/gutil/strings/util.h"
#include "kudu/util/array_view.h"
+#include "kudu/util/coding-inl.h"
#include "kudu/util/debug/trace_event.h"
#include "kudu/util/env.h"
#include "kudu/util/errno.h"
@@ -58,6 +60,7 @@
#include "kudu/util/logging.h"
#include "kudu/util/malloc.h"
#include "kudu/util/monotime.h"
+#include "kudu/util/openssl_util.h"
#include "kudu/util/path_util.h"
#include "kudu/util/scoped_cleanup.h"
#include "kudu/util/slice.h"
@@ -204,6 +207,10 @@ namespace kudu {
const char* const Env::kInjectedFailureStatusMsg = "INJECTED FAILURE";
+const uint8_t kEncryptionBlockSize = 16;
+
+using evp_ctx_unique_ptr = std::unique_ptr<EVP_CIPHER_CTX,
decltype(&EVP_CIPHER_CTX_free)>;
+
namespace {
struct FreeDeleter {
@@ -212,6 +219,12 @@ struct FreeDeleter {
}
};
+// KUDU-3316: This is the key temporarily used for all encrypion. Obviously,
+// this is not secure and MUST be removed and replaced with real keys once the
+// key infra is in place.
+// TODO(abukor): delete this.
+const uint8_t kDummyEncryptionKey[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 42};
+
#if defined(__APPLE__)
// Simulates Linux's fallocate file preallocation API on OS X.
int fallocate(int fd, int mode, off_t offset, off_t len) {
@@ -364,6 +377,90 @@ Status DoOpen(const string& filename, int flags, const
string& reason, int* fd)
return Status::OK();
}
+// Encrypts the data in 'cleartext' and writes it to 'ciphertext'. It requires
+// 'offset' to be set in the file as it's used to set the initialization
vector.
+Status DoEncryptV(const uint8_t* key,
+ uint64_t offset,
+ ArrayView<const Slice> cleartext,
+ ArrayView<Slice> ciphertext) {
+ DCHECK_EQ(cleartext.size(), ciphertext.size());
+ // Set the initialization vector based on the offset.
+ uint8_t iv[16];
+ InlineBigEndianEncodeFixed64(&iv[0], 0);
+ InlineBigEndianEncodeFixed64(&iv[8], offset / kEncryptionBlockSize);
+
+ evp_ctx_unique_ptr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+ OPENSSL_RET_NOT_OK(EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr,
key, iv),
+ "Failed to initialize encryption");
+ size_t offset_mod = offset % kEncryptionBlockSize;
+ if (offset_mod) {
+ unsigned char scratch_clear[kEncryptionBlockSize];
+ unsigned char scratch_cipher[kEncryptionBlockSize];
+ int out_length;
+ OPENSSL_RET_NOT_OK(EVP_EncryptUpdate(ctx.get(), scratch_cipher,
&out_length,
+ scratch_clear, offset_mod),
+ "Failed to encrypt scratch data");
+ DCHECK_LE(out_length, kEncryptionBlockSize);
+ }
+ for (auto i = 0; i < cleartext.size(); ++i) {
+ int out_length;
+ // Normally, EVP_EncryptFinal_ex() would be needed after the last chunk of
+ // data encrypted with EVP_EncryptUpdate(). In Kudu, we only use AES-CTR
+ // which requires no padding or authentication tags, so
+ // EVP_EncryptFinal_ex() doesn't actually add anything.
+ OPENSSL_RET_NOT_OK(EVP_EncryptUpdate(ctx.get(),
+ ciphertext[i].mutable_data(),
+ &out_length,
+ cleartext[i].data(),
+ cleartext[i].size()),
+ "Failed to encrypt data");
+ DCHECK_EQ(out_length, cleartext[i].size());
+ DCHECK_LE(out_length, ciphertext[i].size());
+ }
+ return Status::OK();
+}
+
+// Decrypts 'data'. Uses 'offset' in the file to set the initialization vector.
+Status DoDecryptV(const uint8_t* key, uint64_t offset, ArrayView<Slice> data) {
+ // Set the initialization vector based on the offset.
+ uint8_t iv[16];
+ InlineBigEndianEncodeFixed64(&iv[0], 0);
+ InlineBigEndianEncodeFixed64(&iv[8], offset / kEncryptionBlockSize);
+
+ evp_ctx_unique_ptr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
+ OPENSSL_RET_NOT_OK(EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr,
key, iv),
+ "Failed to initialize decryption");
+ size_t offset_mod = offset % kEncryptionBlockSize;
+ if (offset_mod) {
+ unsigned char scratch_clear[kEncryptionBlockSize];
+ unsigned char scratch_cipher[kEncryptionBlockSize];
+ int out_length;
+ OPENSSL_RET_NOT_OK(EVP_DecryptUpdate(ctx.get(),
+ scratch_clear,
+ &out_length,
+ scratch_cipher,
+ offset_mod),
+ "Failed to decrypt scratch data");
+ }
+
+ for (auto i = 0; i < data.size(); ++i) {
+ const Slice& ciphertext_slice = data[i];
+ int in_length = ciphertext_slice.size();
+ if (!in_length || IsAllZeros(ciphertext_slice)) continue;
+ int out_length;
+ // We don't call EVP_DecryptFinal_ex() after EVP_DecryptUpdate() for the
+ // same reason we don't call EVP_EncryptFinal_ex().
+ OPENSSL_RET_NOT_OK(EVP_DecryptUpdate(ctx.get(),
+ data[i].mutable_data(),
+ &out_length,
+ ciphertext_slice.data(),
+ in_length),
+ "Failed to decrypt data");
+ DCHECK_EQ(out_length, in_length);
+ }
+ return Status::OK();
+}
+
Status DoOpen(const string& filename, Env::OpenMode mode, int* fd) {
MAYBE_RETURN_EIO(filename, IOError(Env::kInjectedFailureStatusMsg, EIO));
ThreadRestrictions::AssertIOAllowed();
@@ -392,8 +489,8 @@ Status DoOpen(const string& filename, Env::OpenMode mode,
int* fd) {
return Status::OK();
}
-Status DoReadV(int fd, const string& filename, uint64_t offset,
- ArrayView<Slice> results) {
+Status DoReadV(
+ int fd, const string& filename, uint64_t offset, ArrayView<Slice> results,
bool decrypt) {
MAYBE_RETURN_EIO(filename, IOError(Env::kInjectedFailureStatusMsg, EIO));
ThreadRestrictions::AssertIOAllowed();
@@ -405,7 +502,7 @@ Status DoReadV(int fd, const string& filename, uint64_t
offset,
for (size_t i = 0; i < iov_size; i++) {
Slice& result = results[i];
bytes_req += result.size();
- iov[i] = { result.mutable_data(), result.size() };
+ iov[i] = {result.mutable_data(), result.size()};
}
uint64_t cur_offset = offset;
@@ -432,11 +529,15 @@ Status DoReadV(int fd, const string& filename, uint64_t
offset,
}
if (PREDICT_FALSE(r == 0)) {
// EOF.
+ RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset, results));
return Status::EndOfFile(
Substitute("EOF trying to read $0 bytes at offset $1", bytes_req,
offset));
}
if (PREDICT_TRUE(r == rem)) {
// All requested bytes were read. This is almost always the case.
+ if (decrypt) {
+ RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset, results));
+ }
return Status::OK();
}
DCHECK_LE(r, rem);
@@ -458,11 +559,15 @@ Status DoReadV(int fd, const string& filename, uint64_t
offset,
cur_offset += r;
rem -= r;
}
+ if (decrypt) {
+ RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset, results));
+ }
DCHECK_EQ(0, rem);
return Status::OK();
}
-Status DoWriteV(int fd, const string& filename, uint64_t offset,
ArrayView<const Slice> data) {
+Status DoWriteV(
+ int fd, const string& filename, uint64_t offset, ArrayView<const Slice>
data, bool encrypt) {
MAYBE_RETURN_EIO(filename, IOError(Env::kInjectedFailureStatusMsg, EIO));
ThreadRestrictions::AssertIOAllowed();
@@ -471,10 +576,32 @@ Status DoWriteV(int fd, const string& filename, uint64_t
offset, ArrayView<const
size_t bytes_req = 0;
size_t iov_size = data.size();
struct iovec iov[iov_size];
- for (size_t i = 0; i < iov_size; i++) {
- const Slice& result = data[i];
- bytes_req += result.size();
- iov[i] = { const_cast<uint8_t*>(result.data()), result.size() };
+ std::vector<Slice> encrypted_data(iov_size);
+ SCOPED_CLEANUP({
+ if (encrypt) {
+ delete[] encrypted_data[0].mutable_data();
+ }
+ });
+ if (encrypt) {
+ for (size_t i = 0; i < iov_size; i++) {
+ bytes_req += data[i].size();
+ }
+ unique_ptr<unsigned char[]> encrypted_buf(new unsigned char[bytes_req]);
+ size_t buffer_offset = 0;
+ for (size_t i = 0; i < iov_size; i++) {
+ size_t size = data[i].size();
+ encrypted_data[i] = Slice(&encrypted_buf[buffer_offset], size);
+ buffer_offset += size;
+ iov[i] = {const_cast<uint8_t*>(encrypted_data[i].data()), size};
+ }
+ RETURN_NOT_OK(DoEncryptV(kDummyEncryptionKey, offset, data,
encrypted_data));
+ encrypted_buf.release();
+ } else {
+ for (size_t i = 0; i < iov_size; i++) {
+ const Slice& result = data[i];
+ bytes_req += result.size();
+ iov[i] = {const_cast<uint8_t*>(result.data()), result.size()};
+ }
}
uint64_t cur_offset = offset;
@@ -625,10 +752,12 @@ class PosixSequentialFile: public SequentialFile {
private:
const string filename_;
FILE* const file_;
+ const bool encrypted_;
+ size_t offset_;
public:
- PosixSequentialFile(string fname, FILE* f)
- : filename_(std::move(fname)), file_(f) {}
+ PosixSequentialFile(string fname, bool encrypted, FILE* f)
+ : filename_(std::move(fname)), file_(f), encrypted_(encrypted),
offset_(0) {}
~PosixSequentialFile() {
int err;
RETRY_ON_EINTR(err, fclose(file_));
@@ -653,6 +782,10 @@ class PosixSequentialFile: public SequentialFile {
return IOError(filename_, errno);
}
}
+ if (encrypted_) {
+ RETURN_NOT_OK(DoDecryptV(kDummyEncryptionKey, offset_,
ArrayView<Slice>(result, 1)));
+ }
+ offset_ += r;
return Status::OK();
}
@@ -663,6 +796,7 @@ class PosixSequentialFile: public SequentialFile {
if (fseek(file_, n, SEEK_CUR)) {
return IOError(filename_, errno);
}
+ offset_ += n;
return Status::OK();
}
@@ -674,20 +808,21 @@ class PosixRandomAccessFile: public RandomAccessFile {
private:
const string filename_;
const int fd_;
+ const bool encrypted_;
public:
- PosixRandomAccessFile(string fname, int fd)
- : filename_(std::move(fname)), fd_(fd) {}
+ PosixRandomAccessFile(string fname, int fd, bool encrypted)
+ : filename_(std::move(fname)), fd_(fd), encrypted_(encrypted) {}
~PosixRandomAccessFile() {
DoClose(fd_);
}
virtual Status Read(uint64_t offset, Slice result) const OVERRIDE {
- return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1));
+ return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1),
encrypted_);
}
virtual Status ReadV(uint64_t offset, ArrayView<Slice> results) const
OVERRIDE {
- return DoReadV(fd_, filename_, offset, results);
+ return DoReadV(fd_, filename_, offset, results, encrypted_);
}
virtual Status Size(uint64_t *size) const OVERRIDE {
@@ -715,15 +850,15 @@ class PosixRandomAccessFile: public RandomAccessFile {
// order to further improve Sync() performance.
class PosixWritableFile : public WritableFile {
public:
- PosixWritableFile(string fname, int fd, uint64_t file_size,
- bool sync_on_close)
+ PosixWritableFile(string fname, int fd, uint64_t file_size, bool
sync_on_close, bool encrypted)
: filename_(std::move(fname)),
fd_(fd),
sync_on_close_(sync_on_close),
filesize_(file_size),
pre_allocated_size_(0),
pending_sync_(false),
- closed_(false) {}
+ closed_(false),
+ encrypted_(encrypted) {}
~PosixWritableFile() {
WARN_NOT_OK(Close(), "Failed to close " + filename_);
@@ -735,7 +870,7 @@ class PosixWritableFile : public WritableFile {
virtual Status AppendV(ArrayView<const Slice> data) OVERRIDE {
ThreadRestrictions::AssertIOAllowed();
- RETURN_NOT_OK(DoWriteV(fd_, filename_, filesize_, data));
+ RETURN_NOT_OK(DoWriteV(fd_, filename_, filesize_, data, encrypted_));
// Calculate the amount of data written
size_t bytes_written = accumulate(data.begin(), data.end(),
static_cast<size_t>(0),
[&](int sum, const Slice& curr) {
@@ -857,27 +992,29 @@ class PosixWritableFile : public WritableFile {
uint64_t pre_allocated_size_;
bool pending_sync_;
bool closed_;
+ const bool encrypted_;
};
class PosixRWFile : public RWFile {
public:
- PosixRWFile(string fname, int fd, bool sync_on_close)
+ PosixRWFile(string fname, int fd, bool sync_on_close, bool encrypted)
: filename_(std::move(fname)),
fd_(fd),
sync_on_close_(sync_on_close),
is_on_xfs_(false),
- closed_(false) {}
+ closed_(false),
+ encrypted_(encrypted) {}
~PosixRWFile() {
WARN_NOT_OK(Close(), "Failed to close " + filename_);
}
virtual Status Read(uint64_t offset, Slice result) const OVERRIDE {
- return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1));
+ return DoReadV(fd_, filename_, offset, ArrayView<Slice>(&result, 1),
encrypted_);
}
virtual Status ReadV(uint64_t offset, ArrayView<Slice> results) const
OVERRIDE {
- return DoReadV(fd_, filename_, offset, results);
+ return DoReadV(fd_, filename_, offset, results, encrypted_);
}
virtual Status Write(uint64_t offset, const Slice& data) OVERRIDE {
@@ -885,7 +1022,7 @@ class PosixRWFile : public RWFile {
}
virtual Status WriteV(uint64_t offset, ArrayView<const Slice> data) OVERRIDE
{
- return DoWriteV(fd_, filename_, offset, data);
+ return DoWriteV(fd_, filename_, offset, data, encrypted_);
}
virtual Status PreAllocate(uint64_t offset,
@@ -1118,6 +1255,7 @@ class PosixRWFile : public RWFile {
GoogleOnceDynamic once_;
bool is_on_xfs_;
bool closed_;
+ const bool encrypted_;
};
int LockOrUnlock(int fd, bool lock) {
@@ -1147,6 +1285,12 @@ class PosixEnv : public Env {
}
virtual Status NewSequentialFile(const string& fname,
+ unique_ptr<SequentialFile>* result)
override {
+ return NewSequentialFile(SequentialFileOptions(), fname, result);
+ }
+
+ virtual Status NewSequentialFile(const SequentialFileOptions& opts,
+ const string& fname,
unique_ptr<SequentialFile>* result)
OVERRIDE {
TRACE_EVENT1("io", "PosixEnv::NewSequentialFile", "path", fname);
MAYBE_RETURN_EIO(fname, IOError(Env::kInjectedFailureStatusMsg, EIO));
@@ -1156,7 +1300,7 @@ class PosixEnv : public Env {
if (f == nullptr) {
return IOError(fname, errno);
}
- result->reset(new PosixSequentialFile(fname, f));
+ result->reset(new PosixSequentialFile(fname, opts.encrypted, f));
return Status::OK();
}
@@ -1177,7 +1321,7 @@ class PosixEnv : public Env {
return IOError(fname, errno);
}
- result->reset(new PosixRandomAccessFile(fname, fd));
+ result->reset(new PosixRandomAccessFile(fname, fd, opts.encrypted));
return Status::OK();
}
@@ -1219,7 +1363,7 @@ class PosixEnv : public Env {
TRACE_EVENT1("io", "PosixEnv::NewRWFile", "path", fname);
int fd;
RETURN_NOT_OK(DoOpen(fname, opts.mode, &fd));
- result->reset(new PosixRWFile(fname, fd, opts.sync_on_close));
+ result->reset(new PosixRWFile(fname, fd, opts.sync_on_close,
opts.encrypted));
return Status::OK();
}
@@ -1228,7 +1372,7 @@ class PosixEnv : public Env {
TRACE_EVENT1("io", "PosixEnv::NewTempRWFile", "template", name_template);
int fd = 0;
RETURN_NOT_OK(MkTmpFile(name_template, &fd, created_filename));
- res->reset(new PosixRWFile(*created_filename, fd, opts.sync_on_close));
+ res->reset(new PosixRWFile(*created_filename, fd, opts.sync_on_close,
opts.encrypted));
return Status::OK();
}
@@ -1888,7 +2032,7 @@ class PosixEnv : public Env {
if (opts.mode == MUST_EXIST) {
RETURN_NOT_OK(GetFileSize(fname, &file_size));
}
- result->reset(new PosixWritableFile(fname, fd, file_size,
opts.sync_on_close));
+ result->reset(new PosixWritableFile(fname, fd, file_size,
opts.sync_on_close, opts.encrypted));
return Status::OK();
}
diff --git a/src/kudu/util/openssl_util.h b/src/kudu/util/openssl_util.h
index 03769bd..d1e4b16 100644
--- a/src/kudu/util/openssl_util.h
+++ b/src/kudu/util/openssl_util.h
@@ -53,12 +53,12 @@ typedef struct x509_st X509;
#define OPENSSL_RET_NOT_OK(call, msg) \
if ((call) <= 0) { \
- return Status::RuntimeError((msg), GetOpenSSLErrors()); \
+ return Status::RuntimeError((msg), security::GetOpenSSLErrors()); \
}
#define OPENSSL_RET_IF_NULL(call, msg) \
if ((call) == nullptr) { \
- return Status::RuntimeError((msg), GetOpenSSLErrors()); \
+ return Status::RuntimeError((msg), security::GetOpenSSLErrors()); \
}
// Scoped helper which DCHECKs that on both scope entry and exit, there are no