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 "rocksdb/env_encryption.h"
11 
12 namespace ROCKSDB_NAMESPACE {
13 
14 // Implements a BlockCipher using ROT13.
15 //
16 // Note: This is a sample implementation of BlockCipher,
17 // it is NOT considered safe and should NOT be used in production.
18 class ROT13BlockCipher : public BlockCipher {
19  private:
20   size_t blockSize_;
21 
22  public:
ROT13BlockCipher(size_t blockSize)23   ROT13BlockCipher(size_t blockSize) : blockSize_(blockSize) {}
~ROT13BlockCipher()24   virtual ~ROT13BlockCipher(){};
25   const char* Name() const override;
26   // BlockSize returns the size of each block supported by this cipher stream.
BlockSize()27   size_t BlockSize() override { return blockSize_; }
28 
29   // Encrypt a block of data.
30   // Length of data is equal to BlockSize().
31   Status Encrypt(char* data) override;
32 
33   // Decrypt a block of data.
34   // Length of data is equal to BlockSize().
35   Status Decrypt(char* data) override;
36 };
37 
38 // CTRCipherStream implements BlockAccessCipherStream using an
39 // Counter operations mode.
40 // See https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
41 //
42 // Note: This is a possible implementation of BlockAccessCipherStream,
43 // it is considered suitable for use.
44 class CTRCipherStream final : public BlockAccessCipherStream {
45  private:
46   std::shared_ptr<BlockCipher> cipher_;
47   std::string iv_;
48   uint64_t initialCounter_;
49 
50  public:
CTRCipherStream(const std::shared_ptr<BlockCipher> & c,const char * iv,uint64_t initialCounter)51   CTRCipherStream(const std::shared_ptr<BlockCipher>& c, const char* iv,
52                   uint64_t initialCounter)
53       : cipher_(c), iv_(iv, c->BlockSize()), initialCounter_(initialCounter){};
~CTRCipherStream()54   virtual ~CTRCipherStream(){};
55 
56   // BlockSize returns the size of each block supported by this cipher stream.
BlockSize()57   size_t BlockSize() override { return cipher_->BlockSize(); }
58 
59  protected:
60   // Allocate scratch space which is passed to EncryptBlock/DecryptBlock.
61   void AllocateScratch(std::string&) override;
62 
63   // Encrypt a block of data at the given block index.
64   // Length of data is equal to BlockSize();
65   Status EncryptBlock(uint64_t blockIndex, char* data, char* scratch) override;
66 
67   // Decrypt a block of data at the given block index.
68   // Length of data is equal to BlockSize();
69   Status DecryptBlock(uint64_t blockIndex, char* data, char* scratch) override;
70 };
71 
72 // This encryption provider uses a CTR cipher stream, with a given block cipher
73 // and IV.
74 //
75 // Note: This is a possible implementation of EncryptionProvider,
76 // it is considered suitable for use, provided a safe BlockCipher is used.
77 class CTREncryptionProvider : public EncryptionProvider {
78  private:
79   std::shared_ptr<BlockCipher> cipher_;
80 
81  protected:
82   // For optimal performance when using direct IO, the prefix length should be a
83   // multiple of the page size. This size is to ensure the first real data byte
84   // is placed at largest known alignment point for direct io.
85   const static size_t defaultPrefixLength = 4096;
86 
87  public:
88   explicit CTREncryptionProvider(
89       const std::shared_ptr<BlockCipher>& c = nullptr)
cipher_(c)90       : cipher_(c){};
~CTREncryptionProvider()91   virtual ~CTREncryptionProvider() {}
92 
93   const char* Name() const override;
94 
95   // GetPrefixLength returns the length of the prefix that is added to every
96   // file
97   // and used for storing encryption options.
98   // For optimal performance when using direct IO, the prefix length should be a
99   // multiple of the page size.
100   size_t GetPrefixLength() const override;
101 
102   // CreateNewPrefix initialized an allocated block of prefix memory
103   // for a new file.
104   Status CreateNewPrefix(const std::string& fname, char* prefix,
105                          size_t prefixLength) const override;
106 
107   // CreateCipherStream creates a block access cipher stream for a file given
108   // given name and options.
109   Status CreateCipherStream(
110       const std::string& fname, const EnvOptions& options, Slice& prefix,
111       std::unique_ptr<BlockAccessCipherStream>* result) override;
112 
113   Status AddCipher(const std::string& descriptor, const char* /*cipher*/,
114                    size_t /*len*/, bool /*for_write*/) override;
115 
116  protected:
117   Status TEST_Initialize() override;
118 
119   // PopulateSecretPrefixPart initializes the data into a new prefix block
120   // that will be encrypted. This function will store the data in plain text.
121   // It will be encrypted later (before written to disk).
122   // Returns the amount of space (starting from the start of the prefix)
123   // that has been initialized.
124   virtual size_t PopulateSecretPrefixPart(char* prefix, size_t prefixLength,
125                                           size_t blockSize) const;
126 
127   // CreateCipherStreamFromPrefix creates a block access cipher stream for a
128   // file given
129   // given name and options. The given prefix is already decrypted.
130   virtual Status CreateCipherStreamFromPrefix(
131       const std::string& fname, const EnvOptions& options,
132       uint64_t initialCounter, const Slice& iv, const Slice& prefix,
133       std::unique_ptr<BlockAccessCipherStream>* result);
134 };
135 }  // namespace ROCKSDB_NAMESPACE
136 
137 #endif  // !defined(ROCKSDB_LITE)
138