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