forked from speedb-io/speedb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
env_encryption.h
363 lines (286 loc) · 14 KB
/
env_encryption.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#pragma once
#include <string>
#include "rocksdb/customizable.h"
#include "rocksdb/env.h"
#include "rocksdb/file_system.h"
#include "rocksdb/rocksdb_namespace.h"
namespace ROCKSDB_NAMESPACE {
class EncryptionProvider;
struct ConfigOptions;
// Returns an Env that encrypts data when stored on disk and decrypts data when
// read from disk.
Env* NewEncryptedEnv(Env* base_env,
const std::shared_ptr<EncryptionProvider>& provider);
std::shared_ptr<FileSystem> NewEncryptedFS(
const std::shared_ptr<FileSystem>& base_fs,
const std::shared_ptr<EncryptionProvider>& provider);
// BlockAccessCipherStream is the base class for any cipher stream that
// supports random access at block level (without requiring data from other
// blocks). E.g. CTR (Counter operation mode) supports this requirement.
class BlockAccessCipherStream {
public:
virtual ~BlockAccessCipherStream(){};
// BlockSize returns the size of each block supported by this cipher stream.
virtual size_t BlockSize() = 0;
// Encrypt one or more (partial) blocks of data at the file offset.
// Length of data is given in dataSize.
virtual Status Encrypt(uint64_t fileOffset, char* data, size_t dataSize);
// Decrypt one or more (partial) blocks of data at the file offset.
// Length of data is given in dataSize.
virtual Status Decrypt(uint64_t fileOffset, char* data, size_t dataSize);
protected:
// Allocate scratch space which is passed to EncryptBlock/DecryptBlock.
virtual void AllocateScratch(std::string&) = 0;
// Encrypt a block of data at the given block index.
// Length of data is equal to BlockSize();
virtual Status EncryptBlock(uint64_t blockIndex, char* data,
char* scratch) = 0;
// Decrypt a block of data at the given block index.
// Length of data is equal to BlockSize();
virtual Status DecryptBlock(uint64_t blockIndex, char* data,
char* scratch) = 0;
};
// BlockCipher
//
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
// because RocksDB is not exception-safe. This could cause undefined behavior
// including data loss, unreported corruption, deadlocks, and more.
class BlockCipher : public Customizable {
public:
virtual ~BlockCipher() {}
// Creates a new BlockCipher from the input config_options and value
// The value describes the type of provider (and potentially optional
// configuration parameters) used to create this provider.
// For example, if the value is "ROT13", a ROT13BlockCipher is created.
//
// @param config_options Options to control how this cipher is created
// and initialized.
// @param value The value might be:
// - ROT13 Create a ROT13 Cipher
// - ROT13:nn Create a ROT13 Cipher with block size of nn
// @param result The new cipher object
// @return OK if the cipher was successfully created
// @return NotFound if an invalid name was specified in the value
// @return InvalidArgument if either the options were not valid
static Status CreateFromString(const ConfigOptions& config_options,
const std::string& value,
std::shared_ptr<BlockCipher>* result);
static const char* Type() { return "BlockCipher"; }
// Short-cut method to create a ROT13 BlockCipher.
// This cipher is only suitable for test purposes and should not be used in
// production!!!
static std::shared_ptr<BlockCipher> NewROT13Cipher(size_t block_size);
// BlockSize returns the size of each block supported by this cipher stream.
virtual size_t BlockSize() = 0;
// Encrypt a block of data.
// Length of data is equal to BlockSize().
virtual Status Encrypt(char* data) = 0;
// Decrypt a block of data.
// Length of data is equal to BlockSize().
virtual Status Decrypt(char* data) = 0;
};
// The encryption provider is used to create a cipher stream for a specific
// file. The returned cipher stream will be used for actual
// encryption/decryption actions.
//
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
// because RocksDB is not exception-safe. This could cause undefined behavior
// including data loss, unreported corruption, deadlocks, and more.
class EncryptionProvider : public Customizable {
public:
virtual ~EncryptionProvider() {}
// Creates a new EncryptionProvider from the input config_options and value.
// The value describes the type of provider (and potentially optional
// configuration parameters) used to create this provider.
// For example, if the value is "CTR", a CTREncryptionProvider will be
// created. If the value is end with "://test" (e.g CTR://test"), the
// provider will be initialized in "TEST" mode prior to being returned.
//
// @param config_options Options to control how this provider is created
// and initialized.
// @param value The value might be:
// - CTR Create a CTR provider
// - CTR://test Create a CTR provider and initialize it for tests.
// @param result The new provider object
// @return OK if the provider was successfully created
// @return NotFound if an invalid name was specified in the value
// @return InvalidArgument if either the options were not valid
static Status CreateFromString(const ConfigOptions& config_options,
const std::string& value,
std::shared_ptr<EncryptionProvider>* result);
static const char* Type() { return "EncryptionProvider"; }
// Short-cut method to create a CTR-provider
static std::shared_ptr<EncryptionProvider> NewCTRProvider(
const std::shared_ptr<BlockCipher>& cipher);
// GetPrefixLength returns the length of the prefix that is added to every
// file and used for storing encryption options. For optimal performance, the
// prefix length should be a multiple of the page size.
virtual size_t GetPrefixLength() const = 0;
// CreateNewPrefix initialized an allocated block of prefix memory
// for a new file.
virtual Status CreateNewPrefix(const std::string& fname, char* prefix,
size_t prefixLength) const = 0;
// Method to add a new cipher key for use by the EncryptionProvider.
// @param descriptor Descriptor for this key
// @param cipher The cryptographic key to use
// @param len The length of the cipher key
// @param for_write If true, this cipher should be used for writing files.
// If false, this cipher should only be used for reading
// files
// @return OK if the cipher was successfully added to the provider, non-OK
// otherwise
virtual Status AddCipher(const std::string& descriptor, const char* cipher,
size_t len, bool for_write) = 0;
// CreateCipherStream creates a block access cipher stream for a file given
// name and options.
virtual Status CreateCipherStream(
const std::string& fname, const EnvOptions& options, Slice& prefix,
std::unique_ptr<BlockAccessCipherStream>* result) = 0;
// Returns a string representing an encryption marker prefix for this
// provider. If a marker is provided, this marker can be used to tell whether
// a file is encrypted by this provider. The marker will also be part of any
// encryption prefix for this provider.
virtual std::string GetMarker() const { return ""; }
};
class EncryptedSequentialFile : public FSSequentialFile {
protected:
std::unique_ptr<FSSequentialFile> file_;
std::unique_ptr<BlockAccessCipherStream> stream_;
uint64_t offset_;
const size_t prefixLength_;
public:
// Default ctor. Given underlying sequential file is supposed to be at
// offset == prefixLength.
EncryptedSequentialFile(std::unique_ptr<FSSequentialFile>&& f,
std::unique_ptr<BlockAccessCipherStream>&& s,
size_t prefixLength)
: file_(std::move(f)),
stream_(std::move(s)),
offset_(prefixLength),
prefixLength_(prefixLength) {}
IOStatus Read(size_t n, const IOOptions& options, Slice* result,
char* scratch, IODebugContext* dbg) override;
IOStatus Skip(uint64_t n) override;
bool use_direct_io() const override;
size_t GetRequiredBufferAlignment() const override;
IOStatus InvalidateCache(size_t offset, size_t length) override;
IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options,
Slice* result, char* scratch,
IODebugContext* dbg) override;
};
class EncryptedRandomAccessFile : public FSRandomAccessFile {
protected:
std::unique_ptr<FSRandomAccessFile> file_;
std::unique_ptr<BlockAccessCipherStream> stream_;
size_t prefixLength_;
public:
EncryptedRandomAccessFile(std::unique_ptr<FSRandomAccessFile>&& f,
std::unique_ptr<BlockAccessCipherStream>&& s,
size_t prefixLength)
: file_(std::move(f)),
stream_(std::move(s)),
prefixLength_(prefixLength) {}
IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
Slice* result, char* scratch,
IODebugContext* dbg) const override;
IOStatus Prefetch(uint64_t offset, size_t n, const IOOptions& options,
IODebugContext* dbg) override;
size_t GetUniqueId(char* id, size_t max_size) const override;
void Hint(AccessPattern pattern) override;
bool use_direct_io() const override;
size_t GetRequiredBufferAlignment() const override;
IOStatus InvalidateCache(size_t offset, size_t length) override;
};
class EncryptedWritableFile : public FSWritableFile {
protected:
std::unique_ptr<FSWritableFile> file_;
std::unique_ptr<BlockAccessCipherStream> stream_;
size_t prefixLength_;
public:
// Default ctor. Prefix is assumed to be written already.
EncryptedWritableFile(std::unique_ptr<FSWritableFile>&& f,
std::unique_ptr<BlockAccessCipherStream>&& s,
size_t prefixLength)
: file_(std::move(f)),
stream_(std::move(s)),
prefixLength_(prefixLength) {}
using FSWritableFile::Append;
IOStatus Append(const Slice& data, const IOOptions& options,
IODebugContext* dbg) override;
using FSWritableFile::PositionedAppend;
IOStatus PositionedAppend(const Slice& data, uint64_t offset,
const IOOptions& options,
IODebugContext* dbg) override;
bool IsSyncThreadSafe() const override;
bool use_direct_io() const override;
size_t GetRequiredBufferAlignment() const override;
uint64_t GetFileSize(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Truncate(uint64_t size, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus InvalidateCache(size_t offset, size_t length) override;
IOStatus RangeSync(uint64_t offset, uint64_t nbytes, const IOOptions& options,
IODebugContext* dbg) override;
void PrepareWrite(size_t offset, size_t len, const IOOptions& options,
IODebugContext* dbg) override;
void SetPreallocationBlockSize(size_t size) override;
void GetPreallocationStatus(size_t* block_size,
size_t* last_allocated_block) override;
IOStatus Allocate(uint64_t offset, uint64_t len, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Close(const IOOptions& options, IODebugContext* dbg) override;
};
class EncryptedRandomRWFile : public FSRandomRWFile {
protected:
std::unique_ptr<FSRandomRWFile> file_;
std::unique_ptr<BlockAccessCipherStream> stream_;
size_t prefixLength_;
public:
EncryptedRandomRWFile(std::unique_ptr<FSRandomRWFile>&& f,
std::unique_ptr<BlockAccessCipherStream>&& s,
size_t prefixLength)
: file_(std::move(f)),
stream_(std::move(s)),
prefixLength_(prefixLength) {}
bool use_direct_io() const override;
size_t GetRequiredBufferAlignment() const override;
IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
Slice* result, char* scratch,
IODebugContext* dbg) const override;
IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Close(const IOOptions& options, IODebugContext* dbg) override;
};
class EncryptedFileSystem : public FileSystemWrapper {
public:
explicit EncryptedFileSystem(const std::shared_ptr<FileSystem>& base)
: FileSystemWrapper(base) {}
// Method to add a new cipher key for use by the EncryptionProvider.
// @param description Descriptor for this key.
// @param cipher The cryptographic key to use
// @param len The length of the cipher key
// @param for_write If true, this cipher should be used for writing files.
// If false, this cipher should only be used for reading
// files
// @return OK if the cipher was successfully added to the provider, non-OK
// otherwise
virtual Status AddCipher(const std::string& descriptor, const char* cipher,
size_t len, bool for_write) = 0;
static const char* kClassName() { return "EncryptedFileSystem"; }
bool IsInstanceOf(const std::string& name) const override {
if (name == kClassName()) {
return true;
} else {
return FileSystemWrapper::IsInstanceOf(name);
}
}
};
} // namespace ROCKSDB_NAMESPACE