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 
8 #if !defined(ROCKSDB_LITE)
9 
10 #include <string>
11 
12 #include "env.h"
13 
14 namespace ROCKSDB_NAMESPACE {
15 
16 class EncryptionProvider;
17 
18 // Returns an Env that encrypts data when stored on disk and decrypts data when
19 // read from disk.
20 Env* NewEncryptedEnv(Env* base_env, EncryptionProvider* provider);
21 
22 // BlockAccessCipherStream is the base class for any cipher stream that
23 // supports random access at block level (without requiring data from other
24 // blocks). E.g. CTR (Counter operation mode) supports this requirement.
25 class BlockAccessCipherStream {
26  public:
~BlockAccessCipherStream()27   virtual ~BlockAccessCipherStream(){};
28 
29   // BlockSize returns the size of each block supported by this cipher stream.
30   virtual size_t BlockSize() = 0;
31 
32   // Encrypt one or more (partial) blocks of data at the file offset.
33   // Length of data is given in dataSize.
34   virtual Status Encrypt(uint64_t fileOffset, char* data, size_t dataSize);
35 
36   // Decrypt one or more (partial) blocks of data at the file offset.
37   // Length of data is given in dataSize.
38   virtual Status Decrypt(uint64_t fileOffset, char* data, size_t dataSize);
39 
40  protected:
41   // Allocate scratch space which is passed to EncryptBlock/DecryptBlock.
42   virtual void AllocateScratch(std::string&) = 0;
43 
44   // Encrypt a block of data at the given block index.
45   // Length of data is equal to BlockSize();
46   virtual Status EncryptBlock(uint64_t blockIndex, char* data,
47                               char* scratch) = 0;
48 
49   // Decrypt a block of data at the given block index.
50   // Length of data is equal to BlockSize();
51   virtual Status DecryptBlock(uint64_t blockIndex, char* data,
52                               char* scratch) = 0;
53 };
54 
55 // BlockCipher
56 class BlockCipher {
57  public:
~BlockCipher()58   virtual ~BlockCipher(){};
59 
60   // BlockSize returns the size of each block supported by this cipher stream.
61   virtual size_t BlockSize() = 0;
62 
63   // Encrypt a block of data.
64   // Length of data is equal to BlockSize().
65   virtual Status Encrypt(char* data) = 0;
66 
67   // Decrypt a block of data.
68   // Length of data is equal to BlockSize().
69   virtual Status Decrypt(char* data) = 0;
70 };
71 
72 // Implements a BlockCipher using ROT13.
73 //
74 // Note: This is a sample implementation of BlockCipher,
75 // it is NOT considered safe and should NOT be used in production.
76 class ROT13BlockCipher : public BlockCipher {
77  private:
78   size_t blockSize_;
79 
80  public:
ROT13BlockCipher(size_t blockSize)81   ROT13BlockCipher(size_t blockSize) : blockSize_(blockSize) {}
~ROT13BlockCipher()82   virtual ~ROT13BlockCipher(){};
83 
84   // BlockSize returns the size of each block supported by this cipher stream.
BlockSize()85   virtual size_t BlockSize() override { return blockSize_; }
86 
87   // Encrypt a block of data.
88   // Length of data is equal to BlockSize().
89   virtual Status Encrypt(char* data) override;
90 
91   // Decrypt a block of data.
92   // Length of data is equal to BlockSize().
93   virtual Status Decrypt(char* data) override;
94 };
95 
96 // CTRCipherStream implements BlockAccessCipherStream using an
97 // Counter operations mode.
98 // See https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
99 //
100 // Note: This is a possible implementation of BlockAccessCipherStream,
101 // it is considered suitable for use.
102 class CTRCipherStream final : public BlockAccessCipherStream {
103  private:
104   BlockCipher& cipher_;
105   std::string iv_;
106   uint64_t initialCounter_;
107 
108  public:
CTRCipherStream(BlockCipher & c,const char * iv,uint64_t initialCounter)109   CTRCipherStream(BlockCipher& c, const char* iv, uint64_t initialCounter)
110       : cipher_(c), iv_(iv, c.BlockSize()), initialCounter_(initialCounter){};
~CTRCipherStream()111   virtual ~CTRCipherStream(){};
112 
113   // BlockSize returns the size of each block supported by this cipher stream.
BlockSize()114   virtual size_t BlockSize() override { return cipher_.BlockSize(); }
115 
116  protected:
117   // Allocate scratch space which is passed to EncryptBlock/DecryptBlock.
118   virtual void AllocateScratch(std::string&) override;
119 
120   // Encrypt a block of data at the given block index.
121   // Length of data is equal to BlockSize();
122   virtual Status EncryptBlock(uint64_t blockIndex, char* data,
123                               char* scratch) override;
124 
125   // Decrypt a block of data at the given block index.
126   // Length of data is equal to BlockSize();
127   virtual Status DecryptBlock(uint64_t blockIndex, char* data,
128                               char* scratch) override;
129 };
130 
131 // The encryption provider is used to create a cipher stream for a specific
132 // file. The returned cipher stream will be used for actual
133 // encryption/decryption actions.
134 class EncryptionProvider {
135  public:
~EncryptionProvider()136   virtual ~EncryptionProvider(){};
137 
138   // GetPrefixLength returns the length of the prefix that is added to every
139   // file and used for storing encryption options. For optimal performance, the
140   // prefix length should be a multiple of the page size.
141   virtual size_t GetPrefixLength() = 0;
142 
143   // CreateNewPrefix initialized an allocated block of prefix memory
144   // for a new file.
145   virtual Status CreateNewPrefix(const std::string& fname, char* prefix,
146                                  size_t prefixLength) = 0;
147 
148   // CreateCipherStream creates a block access cipher stream for a file given
149   // given name and options.
150   virtual Status CreateCipherStream(
151       const std::string& fname, const EnvOptions& options, Slice& prefix,
152       std::unique_ptr<BlockAccessCipherStream>* result) = 0;
153 };
154 
155 // This encryption provider uses a CTR cipher stream, with a given block cipher
156 // and IV.
157 //
158 // Note: This is a possible implementation of EncryptionProvider,
159 // it is considered suitable for use, provided a safe BlockCipher is used.
160 class CTREncryptionProvider : public EncryptionProvider {
161  private:
162   BlockCipher& cipher_;
163 
164  protected:
165   const static size_t defaultPrefixLength = 4096;
166 
167  public:
CTREncryptionProvider(BlockCipher & c)168   CTREncryptionProvider(BlockCipher& c) : cipher_(c){};
~CTREncryptionProvider()169   virtual ~CTREncryptionProvider() {}
170 
171   // GetPrefixLength returns the length of the prefix that is added to every
172   // file and used for storing encryption options. For optimal performance, the
173   // prefix length should be a multiple of the page size.
174   virtual size_t GetPrefixLength() override;
175 
176   // CreateNewPrefix initialized an allocated block of prefix memory
177   // for a new file.
178   virtual Status CreateNewPrefix(const std::string& fname, char* prefix,
179                                  size_t prefixLength) override;
180 
181   // CreateCipherStream creates a block access cipher stream for a file given
182   // given name and options.
183   virtual Status CreateCipherStream(
184       const std::string& fname, const EnvOptions& options, Slice& prefix,
185       std::unique_ptr<BlockAccessCipherStream>* result) override;
186 
187  protected:
188   // PopulateSecretPrefixPart initializes the data into a new prefix block
189   // that will be encrypted. This function will store the data in plain text.
190   // It will be encrypted later (before written to disk).
191   // Returns the amount of space (starting from the start of the prefix)
192   // that has been initialized.
193   virtual size_t PopulateSecretPrefixPart(char* prefix, size_t prefixLength,
194                                           size_t blockSize);
195 
196   // CreateCipherStreamFromPrefix creates a block access cipher stream for a
197   // file given given name and options. The given prefix is already decrypted.
198   virtual Status CreateCipherStreamFromPrefix(
199       const std::string& fname, const EnvOptions& options,
200       uint64_t initialCounter, const Slice& iv, const Slice& prefix,
201       std::unique_ptr<BlockAccessCipherStream>* result);
202 };
203 
204 }  // namespace ROCKSDB_NAMESPACE
205 
206 #endif  // !defined(ROCKSDB_LITE)
207