]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // Copyright (c) 2016-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under both the GPLv2 (found in the | |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
5 | ||
6 | #pragma once | |
7 | ||
494da23a | 8 | #if !defined(ROCKSDB_LITE) |
11fdf7f2 TL |
9 | |
10 | #include <string> | |
11 | ||
20effc67 TL |
12 | #include "rocksdb/env.h" |
13 | #include "rocksdb/rocksdb_namespace.h" | |
11fdf7f2 | 14 | |
f67539c2 | 15 | namespace ROCKSDB_NAMESPACE { |
11fdf7f2 TL |
16 | |
17 | class EncryptionProvider; | |
18 | ||
20effc67 TL |
19 | struct ConfigOptions; |
20 | ||
494da23a | 21 | // Returns an Env that encrypts data when stored on disk and decrypts data when |
11fdf7f2 | 22 | // read from disk. |
20effc67 TL |
23 | Env* NewEncryptedEnv(Env* base_env, |
24 | const std::shared_ptr<EncryptionProvider>& provider); | |
11fdf7f2 | 25 | |
494da23a TL |
26 | // BlockAccessCipherStream is the base class for any cipher stream that |
27 | // supports random access at block level (without requiring data from other | |
28 | // blocks). E.g. CTR (Counter operation mode) supports this requirement. | |
11fdf7f2 | 29 | class BlockAccessCipherStream { |
494da23a TL |
30 | public: |
31 | virtual ~BlockAccessCipherStream(){}; | |
11fdf7f2 | 32 | |
494da23a TL |
33 | // BlockSize returns the size of each block supported by this cipher stream. |
34 | virtual size_t BlockSize() = 0; | |
11fdf7f2 | 35 | |
494da23a TL |
36 | // Encrypt one or more (partial) blocks of data at the file offset. |
37 | // Length of data is given in dataSize. | |
38 | virtual Status Encrypt(uint64_t fileOffset, char* data, size_t dataSize); | |
11fdf7f2 | 39 | |
494da23a TL |
40 | // Decrypt one or more (partial) blocks of data at the file offset. |
41 | // Length of data is given in dataSize. | |
42 | virtual Status Decrypt(uint64_t fileOffset, char* data, size_t dataSize); | |
11fdf7f2 | 43 | |
494da23a TL |
44 | protected: |
45 | // Allocate scratch space which is passed to EncryptBlock/DecryptBlock. | |
46 | virtual void AllocateScratch(std::string&) = 0; | |
11fdf7f2 | 47 | |
494da23a TL |
48 | // Encrypt a block of data at the given block index. |
49 | // Length of data is equal to BlockSize(); | |
50 | virtual Status EncryptBlock(uint64_t blockIndex, char* data, | |
51 | char* scratch) = 0; | |
11fdf7f2 | 52 | |
494da23a TL |
53 | // Decrypt a block of data at the given block index. |
54 | // Length of data is equal to BlockSize(); | |
55 | virtual Status DecryptBlock(uint64_t blockIndex, char* data, | |
56 | char* scratch) = 0; | |
11fdf7f2 TL |
57 | }; |
58 | ||
494da23a | 59 | // BlockCipher |
11fdf7f2 | 60 | class BlockCipher { |
494da23a TL |
61 | public: |
62 | virtual ~BlockCipher(){}; | |
11fdf7f2 | 63 | |
20effc67 TL |
64 | // Creates a new BlockCipher from the input config_options and value |
65 | // The value describes the type of provider (and potentially optional | |
66 | // configuration parameters) used to create this provider. | |
67 | // For example, if the value is "ROT13", a ROT13BlockCipher is created. | |
68 | // | |
69 | // @param config_options Options to control how this cipher is created | |
70 | // and initialized. | |
71 | // @param value The value might be: | |
72 | // - ROT13 Create a ROT13 Cipher | |
73 | // - ROT13:nn Create a ROT13 Cipher with block size of nn | |
74 | // @param result The new cipher object | |
75 | // @return OK if the cipher was sucessfully created | |
76 | // @return NotFound if an invalid name was specified in the value | |
77 | // @return InvalidArgument if either the options were not valid | |
78 | static Status CreateFromString(const ConfigOptions& config_options, | |
79 | const std::string& value, | |
80 | std::shared_ptr<BlockCipher>* result); | |
81 | ||
82 | // Short-cut method to create a ROT13 BlockCipher. | |
83 | // This cipher is only suitable for test purposes and should not be used in | |
84 | // production!!! | |
85 | static std::shared_ptr<BlockCipher> NewROT13Cipher(size_t block_size); | |
86 | ||
87 | virtual const char* Name() const = 0; | |
494da23a TL |
88 | // BlockSize returns the size of each block supported by this cipher stream. |
89 | virtual size_t BlockSize() = 0; | |
11fdf7f2 | 90 | |
494da23a TL |
91 | // Encrypt a block of data. |
92 | // Length of data is equal to BlockSize(). | |
93 | virtual Status Encrypt(char* data) = 0; | |
11fdf7f2 | 94 | |
494da23a TL |
95 | // Decrypt a block of data. |
96 | // Length of data is equal to BlockSize(). | |
97 | virtual Status Decrypt(char* data) = 0; | |
11fdf7f2 TL |
98 | }; |
99 | ||
494da23a TL |
100 | // The encryption provider is used to create a cipher stream for a specific |
101 | // file. The returned cipher stream will be used for actual | |
102 | // encryption/decryption actions. | |
11fdf7f2 TL |
103 | class EncryptionProvider { |
104 | public: | |
494da23a TL |
105 | virtual ~EncryptionProvider(){}; |
106 | ||
20effc67 TL |
107 | // Creates a new EncryptionProvider from the input config_options and value |
108 | // The value describes the type of provider (and potentially optional | |
109 | // configuration parameters) used to create this provider. | |
110 | // For example, if the value is "CTR", a CTREncryptionProvider will be | |
111 | // created. If the value is preceded by "test://" (e.g test://CTR"), the | |
112 | // TEST_Initialize method will be invoked prior to returning the provider. | |
113 | // | |
114 | // @param config_options Options to control how this provider is created | |
115 | // and initialized. | |
116 | // @param value The value might be: | |
117 | // - CTR Create a CTR provider | |
118 | // - test://CTR Create a CTR provider and initialize it for tests. | |
119 | // @param result The new provider object | |
120 | // @return OK if the provider was sucessfully created | |
121 | // @return NotFound if an invalid name was specified in the value | |
122 | // @return InvalidArgument if either the options were not valid | |
123 | static Status CreateFromString(const ConfigOptions& config_options, | |
124 | const std::string& value, | |
125 | std::shared_ptr<EncryptionProvider>* result); | |
126 | ||
127 | // Short-cut method to create a CTR-provider | |
128 | static std::shared_ptr<EncryptionProvider> NewCTRProvider( | |
129 | const std::shared_ptr<BlockCipher>& cipher); | |
130 | ||
131 | // Returns the name of this EncryptionProvider | |
132 | virtual const char* Name() const = 0; | |
133 | ||
494da23a TL |
134 | // GetPrefixLength returns the length of the prefix that is added to every |
135 | // file and used for storing encryption options. For optimal performance, the | |
136 | // prefix length should be a multiple of the page size. | |
20effc67 | 137 | virtual size_t GetPrefixLength() const = 0; |
494da23a TL |
138 | |
139 | // CreateNewPrefix initialized an allocated block of prefix memory | |
140 | // for a new file. | |
141 | virtual Status CreateNewPrefix(const std::string& fname, char* prefix, | |
20effc67 TL |
142 | size_t prefixLength) const = 0; |
143 | ||
144 | // Method to add a new cipher key for use by the EncryptionProvider. | |
145 | // @param description Descriptor for this key. | |
146 | // @param cipher The cryptographic key to use | |
147 | // @param len The length of the cipher key | |
148 | // @param for_write If true, this cipher should be used for writing files. | |
149 | // If false, this cipher should only be used for reading | |
150 | // files | |
151 | // @return OK if the cipher was successfully added to the provider, non-OK | |
152 | // otherwise | |
153 | virtual Status AddCipher(const std::string& descriptor, const char* cipher, | |
154 | size_t len, bool for_write) = 0; | |
494da23a TL |
155 | |
156 | // CreateCipherStream creates a block access cipher stream for a file given | |
157 | // given name and options. | |
158 | virtual Status CreateCipherStream( | |
159 | const std::string& fname, const EnvOptions& options, Slice& prefix, | |
160 | std::unique_ptr<BlockAccessCipherStream>* result) = 0; | |
11fdf7f2 | 161 | |
20effc67 TL |
162 | // Returns a string representing an encryption marker prefix for this |
163 | // provider. If a marker is provided, this marker can be used to tell whether | |
164 | // or not a file is encrypted by this provider. The maker will also be part | |
165 | // of any encryption prefix for this provider. | |
166 | virtual std::string GetMarker() const { return ""; } | |
494da23a TL |
167 | |
168 | protected: | |
20effc67 TL |
169 | // Optional method to initialize an EncryptionProvider in the TEST |
170 | // environment. | |
171 | virtual Status TEST_Initialize() { return Status::OK(); } | |
172 | }; | |
173 | ||
174 | class EncryptedSequentialFile : public SequentialFile { | |
175 | protected: | |
176 | std::unique_ptr<SequentialFile> file_; | |
177 | std::unique_ptr<BlockAccessCipherStream> stream_; | |
178 | uint64_t offset_; | |
179 | size_t prefixLength_; | |
11fdf7f2 TL |
180 | |
181 | public: | |
20effc67 TL |
182 | // Default ctor. Given underlying sequential file is supposed to be at |
183 | // offset == prefixLength. | |
184 | EncryptedSequentialFile(std::unique_ptr<SequentialFile>&& f, | |
185 | std::unique_ptr<BlockAccessCipherStream>&& s, | |
186 | size_t prefixLength) | |
187 | : file_(std::move(f)), | |
188 | stream_(std::move(s)), | |
189 | offset_(prefixLength), | |
190 | prefixLength_(prefixLength) {} | |
191 | ||
192 | // Read up to "n" bytes from the file. "scratch[0..n-1]" may be | |
193 | // written by this routine. Sets "*result" to the data that was | |
194 | // read (including if fewer than "n" bytes were successfully read). | |
195 | // May set "*result" to point at data in "scratch[0..n-1]", so | |
196 | // "scratch[0..n-1]" must be live when "*result" is used. | |
197 | // If an error was encountered, returns a non-OK status. | |
198 | // | |
199 | // REQUIRES: External synchronization | |
200 | virtual Status Read(size_t n, Slice* result, char* scratch) override; | |
201 | ||
202 | // Skip "n" bytes from the file. This is guaranteed to be no | |
203 | // slower that reading the same data, but may be faster. | |
204 | // | |
205 | // If end of file is reached, skipping will stop at the end of the | |
206 | // file, and Skip will return OK. | |
207 | // | |
208 | // REQUIRES: External synchronization | |
209 | virtual Status Skip(uint64_t n) override; | |
210 | ||
211 | // Indicates the upper layers if the current SequentialFile implementation | |
212 | // uses direct IO. | |
213 | virtual bool use_direct_io() const override; | |
214 | ||
215 | // Use the returned alignment value to allocate | |
216 | // aligned buffer for Direct I/O | |
217 | virtual size_t GetRequiredBufferAlignment() const override; | |
218 | ||
219 | // Remove any kind of caching of data from the offset to offset+length | |
220 | // of this file. If the length is 0, then it refers to the end of file. | |
221 | // If the system is not caching the file contents, then this is a noop. | |
222 | virtual Status InvalidateCache(size_t offset, size_t length) override; | |
223 | ||
224 | // Positioned Read for direct I/O | |
225 | // If Direct I/O enabled, offset, n, and scratch should be properly aligned | |
226 | virtual Status PositionedRead(uint64_t offset, size_t n, Slice* result, | |
227 | char* scratch) override; | |
228 | }; | |
494da23a | 229 | |
20effc67 TL |
230 | // A file abstraction for randomly reading the contents of a file. |
231 | class EncryptedRandomAccessFile : public RandomAccessFile { | |
232 | protected: | |
233 | std::unique_ptr<RandomAccessFile> file_; | |
234 | std::unique_ptr<BlockAccessCipherStream> stream_; | |
235 | size_t prefixLength_; | |
494da23a | 236 | |
20effc67 TL |
237 | public: |
238 | EncryptedRandomAccessFile(std::unique_ptr<RandomAccessFile>&& f, | |
239 | std::unique_ptr<BlockAccessCipherStream>&& s, | |
240 | size_t prefixLength) | |
241 | : file_(std::move(f)), | |
242 | stream_(std::move(s)), | |
243 | prefixLength_(prefixLength) {} | |
244 | ||
245 | // Read up to "n" bytes from the file starting at "offset". | |
246 | // "scratch[0..n-1]" may be written by this routine. Sets "*result" | |
247 | // to the data that was read (including if fewer than "n" bytes were | |
248 | // successfully read). May set "*result" to point at data in | |
249 | // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when | |
250 | // "*result" is used. If an error was encountered, returns a non-OK | |
251 | // status. | |
252 | // | |
253 | // Safe for concurrent use by multiple threads. | |
254 | // If Direct I/O enabled, offset, n, and scratch should be aligned properly. | |
255 | virtual Status Read(uint64_t offset, size_t n, Slice* result, | |
256 | char* scratch) const override; | |
257 | ||
258 | // Readahead the file starting from offset by n bytes for caching. | |
259 | virtual Status Prefetch(uint64_t offset, size_t n) override; | |
260 | ||
261 | // Tries to get an unique ID for this file that will be the same each time | |
262 | // the file is opened (and will stay the same while the file is open). | |
263 | // Furthermore, it tries to make this ID at most "max_size" bytes. If such an | |
264 | // ID can be created this function returns the length of the ID and places it | |
265 | // in "id"; otherwise, this function returns 0, in which case "id" | |
266 | // may not have been modified. | |
267 | // | |
268 | // This function guarantees, for IDs from a given environment, two unique ids | |
269 | // cannot be made equal to each other by adding arbitrary bytes to one of | |
270 | // them. That is, no unique ID is the prefix of another. | |
271 | // | |
272 | // This function guarantees that the returned ID will not be interpretable as | |
273 | // a single varint. | |
274 | // | |
275 | // Note: these IDs are only valid for the duration of the process. | |
276 | virtual size_t GetUniqueId(char* id, size_t max_size) const override; | |
277 | ||
278 | virtual void Hint(AccessPattern pattern) override; | |
279 | ||
280 | // Indicates the upper layers if the current RandomAccessFile implementation | |
281 | // uses direct IO. | |
282 | virtual bool use_direct_io() const override; | |
283 | ||
284 | // Use the returned alignment value to allocate | |
285 | // aligned buffer for Direct I/O | |
286 | virtual size_t GetRequiredBufferAlignment() const override; | |
287 | ||
288 | // Remove any kind of caching of data from the offset to offset+length | |
289 | // of this file. If the length is 0, then it refers to the end of file. | |
290 | // If the system is not caching the file contents, then this is a noop. | |
291 | virtual Status InvalidateCache(size_t offset, size_t length) override; | |
292 | }; | |
494da23a | 293 | |
20effc67 TL |
294 | // A file abstraction for sequential writing. The implementation |
295 | // must provide buffering since callers may append small fragments | |
296 | // at a time to the file. | |
297 | class EncryptedWritableFile : public WritableFileWrapper { | |
298 | protected: | |
299 | std::unique_ptr<WritableFile> file_; | |
300 | std::unique_ptr<BlockAccessCipherStream> stream_; | |
301 | size_t prefixLength_; | |
302 | ||
303 | public: | |
304 | // Default ctor. Prefix is assumed to be written already. | |
305 | EncryptedWritableFile(std::unique_ptr<WritableFile>&& f, | |
306 | std::unique_ptr<BlockAccessCipherStream>&& s, | |
307 | size_t prefixLength) | |
308 | : WritableFileWrapper(f.get()), | |
309 | file_(std::move(f)), | |
310 | stream_(std::move(s)), | |
311 | prefixLength_(prefixLength) {} | |
312 | ||
313 | Status Append(const Slice& data) override; | |
314 | ||
315 | Status PositionedAppend(const Slice& data, uint64_t offset) override; | |
316 | ||
317 | // Indicates the upper layers if the current WritableFile implementation | |
318 | // uses direct IO. | |
319 | virtual bool use_direct_io() const override; | |
320 | ||
321 | // Use the returned alignment value to allocate | |
322 | // aligned buffer for Direct I/O | |
323 | virtual size_t GetRequiredBufferAlignment() const override; | |
324 | ||
325 | /* | |
326 | * Get the size of valid data in the file. | |
327 | */ | |
328 | virtual uint64_t GetFileSize() override; | |
329 | ||
330 | // Truncate is necessary to trim the file to the correct size | |
331 | // before closing. It is not always possible to keep track of the file | |
332 | // size due to whole pages writes. The behavior is undefined if called | |
333 | // with other writes to follow. | |
334 | virtual Status Truncate(uint64_t size) override; | |
335 | ||
336 | // Remove any kind of caching of data from the offset to offset+length | |
337 | // of this file. If the length is 0, then it refers to the end of file. | |
338 | // If the system is not caching the file contents, then this is a noop. | |
339 | // This call has no effect on dirty pages in the cache. | |
340 | virtual Status InvalidateCache(size_t offset, size_t length) override; | |
341 | ||
342 | // Sync a file range with disk. | |
343 | // offset is the starting byte of the file range to be synchronized. | |
344 | // nbytes specifies the length of the range to be synchronized. | |
345 | // This asks the OS to initiate flushing the cached data to disk, | |
346 | // without waiting for completion. | |
347 | // Default implementation does nothing. | |
348 | virtual Status RangeSync(uint64_t offset, uint64_t nbytes) override; | |
349 | ||
350 | // PrepareWrite performs any necessary preparation for a write | |
351 | // before the write actually occurs. This allows for pre-allocation | |
352 | // of space on devices where it can result in less file | |
353 | // fragmentation and/or less waste from over-zealous filesystem | |
354 | // pre-allocation. | |
355 | virtual void PrepareWrite(size_t offset, size_t len) override; | |
356 | ||
357 | // Pre-allocates space for a file. | |
358 | virtual Status Allocate(uint64_t offset, uint64_t len) override; | |
359 | }; | |
494da23a | 360 | |
20effc67 TL |
361 | // A file abstraction for random reading and writing. |
362 | class EncryptedRandomRWFile : public RandomRWFile { | |
494da23a | 363 | protected: |
20effc67 TL |
364 | std::unique_ptr<RandomRWFile> file_; |
365 | std::unique_ptr<BlockAccessCipherStream> stream_; | |
366 | size_t prefixLength_; | |
367 | ||
368 | public: | |
369 | EncryptedRandomRWFile(std::unique_ptr<RandomRWFile>&& f, | |
370 | std::unique_ptr<BlockAccessCipherStream>&& s, | |
371 | size_t prefixLength) | |
372 | : file_(std::move(f)), | |
373 | stream_(std::move(s)), | |
374 | prefixLength_(prefixLength) {} | |
375 | ||
376 | // Indicates if the class makes use of direct I/O | |
377 | // If false you must pass aligned buffer to Write() | |
378 | virtual bool use_direct_io() const override; | |
379 | ||
380 | // Use the returned alignment value to allocate | |
381 | // aligned buffer for Direct I/O | |
382 | virtual size_t GetRequiredBufferAlignment() const override; | |
383 | ||
384 | // Write bytes in `data` at offset `offset`, Returns Status::OK() on success. | |
385 | // Pass aligned buffer when use_direct_io() returns true. | |
386 | virtual Status Write(uint64_t offset, const Slice& data) override; | |
387 | ||
388 | // Read up to `n` bytes starting from offset `offset` and store them in | |
389 | // result, provided `scratch` size should be at least `n`. | |
390 | // Returns Status::OK() on success. | |
391 | virtual Status Read(uint64_t offset, size_t n, Slice* result, | |
392 | char* scratch) const override; | |
393 | ||
394 | virtual Status Flush() override; | |
395 | ||
396 | virtual Status Sync() override; | |
397 | ||
398 | virtual Status Fsync() override; | |
399 | ||
400 | virtual Status Close() override; | |
11fdf7f2 TL |
401 | }; |
402 | ||
f67539c2 | 403 | } // namespace ROCKSDB_NAMESPACE |
11fdf7f2 TL |
404 | |
405 | #endif // !defined(ROCKSDB_LITE) |