YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/encryption/encryption_util.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#ifndef YB_ENCRYPTION_ENCRYPTION_UTIL_H
15
#define YB_ENCRYPTION_ENCRYPTION_UTIL_H
16
17
#include <stdint.h>
18
19
#include <cstdarg>
20
#include <string>
21
22
#include "yb/encryption/cipher_stream.h"
23
#include "yb/encryption/header_manager.h"
24
25
#include "yb/util/status_fwd.h"
26
#include "yb/util/file_system.h"
27
#include "yb/util/result.h"
28
#include "yb/util/status_format.h"
29
30
namespace yb {
31
namespace encryption {
32
33
class EncryptionParamsPB;
34
class RandomAccessFile;
35
class HeaderManager;
36
class BlockAccessCipherStream;
37
class OpenSSLInitializer;
38
39
// Struct generated for encryption status of existing files.
40
struct FileEncryptionStatus {
41
  bool is_encrypted;
42
  uint32_t header_size;
43
};
44
45
// Encryption params consisting of key size 16, 24, or 32, nonce size 12, and counter size 4.
46
struct EncryptionParams {
47
  static constexpr uint32_t kBlockSize = 16;
48
  static constexpr uint32_t kMaxKeySize = 32;
49
50
  uint8_t key[kMaxKeySize];
51
  // Nonce of 12 bytes for encryption.
52
  uint8_t nonce[kBlockSize - sizeof(uint32_t)];
53
  // Counter of 4 bytes incremented for each block.
54
  uint32_t counter;
55
  uint32_t key_size;
56
57
  // When computing counter increment, do we want to overflow the counter into the rest of the
58
  // initialization vector as part of the new format.
59
  bool openssl_compatible_counter_overflow;
60
61
  void ToEncryptionParamsPB(EncryptionParamsPB* encryption_header) const;
62
63
  static Result<std::unique_ptr<EncryptionParams>> FromEncryptionParamsPB(
64
      const EncryptionParamsPB& encryption_header);
65
66
  // Given a slice, convert contents to encryption params. Used to read latest universe key.
67
  static Result<std::unique_ptr<EncryptionParams>> FromSlice(const Slice& s);
68
69
  static std::unique_ptr<EncryptionParams> NewEncryptionParams();
70
71
  static CHECKED_STATUS IsValidKeySize(size_t size);
72
73
  bool Equals(const EncryptionParams& other);
74
};
75
76
typedef std::unique_ptr<EncryptionParams> EncryptionParamsPtr;
77
78
// Since this will typically be passed in by an external user (YW or yb-admin), UniverseKeyId
79
// will be a generic string for ease of use.
80
using UniverseKeyId = std::string;
81
82
struct UniverseKeyParams {
83
  UniverseKeyId version_id;
84
  EncryptionParamsPtr params;
85
};
86
87
// Thread local buffer for any encryption operations.
88
class EncryptionBuffer {
89
 public:
90
  void* GetBuffer(size_t size_needed);
91
  ~EncryptionBuffer();
92
  static EncryptionBuffer* Get();
93
 private:
94
  size_t size = 0;
95
  void* buffer = nullptr;
96
};
97
98
99
// Given a readable file, generate a cipher stream and header size for that file.
100
template <typename BufType, typename Readable>
101
Result<bool> GetEncryptionInfoFromFile(HeaderManager* header_manager,
102
                                       Readable* underlying_r,
103
                                       std::unique_ptr<BlockAccessCipherStream>* stream,
104
2.55M
                                       uint32_t* header_size) {
105
2.55M
  if (!header_manager) {
106
0
    return STATUS(InvalidArgument, "header_manager must be non-null.");
107
0
  }
108
109
2.55M
  Slice encryption_info;
110
2.55M
  auto metadata_start = header_manager->GetEncryptionMetadataStartIndex();
111
2.55M
  auto buf = std::unique_ptr<BufType[]>(new BufType[metadata_start]);
112
2.55M
  RETURN_NOT_OK(underlying_r->Read(0, metadata_start, &encryption_info, buf.get()));
113
2.55M
  auto encryption_status = VERIFY_RESULT(
114
2.55M
      header_manager->GetFileEncryptionStatusFromPrefix(encryption_info));
115
2.55M
  if (!encryption_status.is_encrypted) {
116
2.54M
    return false;
117
2.54M
  }
118
119
1.69k
  *header_size = metadata_start + encryption_status.header_size;
120
1.69k
  buf = std::unique_ptr<BufType[]>(new BufType[*header_size]);
121
1.69k
  RETURN_NOT_OK(underlying_r->Read(
122
1.69k
      metadata_start, encryption_status.header_size, &encryption_info, buf.get()));
123
1.69k
  auto encryption_params = VERIFY_RESULT(
124
1.69k
      header_manager->DecodeEncryptionParamsFromEncryptionMetadata(encryption_info));
125
126
0
  *stream = std::make_unique<BlockAccessCipherStream>(std::move(encryption_params));
127
1.69k
  RETURN_NOT_OK((*stream)->Init());
128
1.69k
  return true;
129
1.69k
}
130
131
CHECKED_STATUS CompleteCreateEncryptionInfoForWrite(
132
    const std::string& header, std::unique_ptr<EncryptionParams> encryption_params,
133
    std::unique_ptr<BlockAccessCipherStream>* stream, uint32_t* header_size);
134
135
// Given a writable file, generate a new stream and header for that file.
136
template <typename Writable>
137
Status CreateEncryptionInfoForWrite(HeaderManager* header_manager,
138
                                    Writable* underlying_w,
139
                                    std::unique_ptr<BlockAccessCipherStream>* stream,
140
40
                                    uint32_t* header_size) {
141
40
  auto encryption_params = EncryptionParams::NewEncryptionParams();
142
40
  string header = VERIFY_RESULT(
143
40
      header_manager->SerializeEncryptionParams(*encryption_params.get()));
144
40
  RETURN_NOT_OK(underlying_w->Append(header));
145
40
  return CompleteCreateEncryptionInfoForWrite(
146
40
      header, std::move(encryption_params), stream, header_size);
147
40
}
yb::Status yb::encryption::CreateEncryptionInfoForWrite<rocksdb::WritableFile>(yb::encryption::HeaderManager*, rocksdb::WritableFile*, std::__1::unique_ptr<yb::encryption::BlockAccessCipherStream, std::__1::default_delete<yb::encryption::BlockAccessCipherStream> >*, unsigned int*)
Line
Count
Source
140
39
                                    uint32_t* header_size) {
141
39
  auto encryption_params = EncryptionParams::NewEncryptionParams();
142
39
  string header = VERIFY_RESULT(
143
39
      header_manager->SerializeEncryptionParams(*encryption_params.get()));
144
39
  RETURN_NOT_OK(underlying_w->Append(header));
145
39
  return CompleteCreateEncryptionInfoForWrite(
146
39
      header, std::move(encryption_params), stream, header_size);
147
39
}
yb::Status yb::encryption::CreateEncryptionInfoForWrite<yb::WritableFile>(yb::encryption::HeaderManager*, yb::WritableFile*, std::__1::unique_ptr<yb::encryption::BlockAccessCipherStream, std::__1::default_delete<yb::encryption::BlockAccessCipherStream> >*, unsigned int*)
Line
Count
Source
140
1
                                    uint32_t* header_size) {
141
1
  auto encryption_params = EncryptionParams::NewEncryptionParams();
142
1
  string header = VERIFY_RESULT(
143
1
      header_manager->SerializeEncryptionParams(*encryption_params.get()));
144
1
  RETURN_NOT_OK(underlying_w->Append(header));
145
1
  return CompleteCreateEncryptionInfoForWrite(
146
1
      header, std::move(encryption_params), stream, header_size);
147
1
}
148
149
template <typename EncryptedFile, typename BufType, typename ReadablePtr>
150
Status CreateRandomAccessFile(ReadablePtr* result,
151
                              HeaderManager* header_manager,
152
538k
                              ReadablePtr underlying) {
153
538k
  result->reset();
154
538k
  std::unique_ptr<BlockAccessCipherStream> stream;
155
538k
  uint32_t header_size;
156
157
538k
  const auto file_encrypted = VERIFY_RESULT(GetEncryptionInfoFromFile<BufType>(
158
538k
      header_manager, underlying.get(), &stream, &header_size));
159
160
538k
  if (!file_encrypted) {
161
537k
    *result = std::move(underlying);
162
537k
    return Status::OK();
163
537k
  }
164
165
872
  result->reset(new EncryptedFile(std::move(underlying), std::move(stream), header_size));
166
872
  return Status::OK();
167
538k
}
168
169
template <typename EncryptedFile, typename WritablePtr>
170
Status CreateWritableFile(WritablePtr* result,
171
                          HeaderManager* header_manager,
172
4.53M
                          WritablePtr underlying) {
173
4.53M
  result->reset();
174
4.53M
  if (
!header_manager->IsEncryptionEnabled()4.53M
) {
175
4.53M
    *result = std::move(underlying);
176
4.53M
    return Status::OK();
177
4.53M
  }
178
179
18.4E
  std::unique_ptr<BlockAccessCipherStream> stream;
180
18.4E
  uint32_t header_size = 0;
181
18.4E
  RETURN_NOT_OK(CreateEncryptionInfoForWrite(
182
18.4E
      header_manager, underlying.get(), &stream, &header_size));
183
18.4E
  result->reset(new EncryptedFile(std::move(underlying), std::move(stream), header_size));
184
18.4E
  return Status::OK();
185
18.4E
}
yb::Status yb::encryption::CreateWritableFile<yb::RocksDBEncryptedWritableFile, std::__1::unique_ptr<rocksdb::WritableFile, std::__1::default_delete<rocksdb::WritableFile> > >(std::__1::unique_ptr<rocksdb::WritableFile, std::__1::default_delete<rocksdb::WritableFile> >*, yb::encryption::HeaderManager*, std::__1::unique_ptr<rocksdb::WritableFile, std::__1::default_delete<rocksdb::WritableFile> >)
Line
Count
Source
172
3.33M
                          WritablePtr underlying) {
173
3.33M
  result->reset();
174
3.33M
  if (
!header_manager->IsEncryptionEnabled()3.33M
) {
175
3.33M
    *result = std::move(underlying);
176
3.33M
    return Status::OK();
177
3.33M
  }
178
179
18.4E
  std::unique_ptr<BlockAccessCipherStream> stream;
180
18.4E
  uint32_t header_size = 0;
181
18.4E
  RETURN_NOT_OK(CreateEncryptionInfoForWrite(
182
18.4E
      header_manager, underlying.get(), &stream, &header_size));
183
18.4E
  result->reset(new EncryptedFile(std::move(underlying), std::move(stream), header_size));
184
18.4E
  return Status::OK();
185
18.4E
}
yb::Status yb::encryption::CreateWritableFile<yb::encryption::EncryptedWritableFile, std::__1::unique_ptr<yb::WritableFile, std::__1::default_delete<yb::WritableFile> > >(std::__1::unique_ptr<yb::WritableFile, std::__1::default_delete<yb::WritableFile> >*, yb::encryption::HeaderManager*, std::__1::unique_ptr<yb::WritableFile, std::__1::default_delete<yb::WritableFile> >)
Line
Count
Source
172
1.19M
                          WritablePtr underlying) {
173
1.19M
  result->reset();
174
1.19M
  if (
!header_manager->IsEncryptionEnabled()1.19M
) {
175
1.19M
    *result = std::move(underlying);
176
1.19M
    return Status::OK();
177
1.19M
  }
178
179
18.4E
  std::unique_ptr<BlockAccessCipherStream> stream;
180
18.4E
  uint32_t header_size = 0;
181
18.4E
  RETURN_NOT_OK(CreateEncryptionInfoForWrite(
182
18.4E
      header_manager, underlying.get(), &stream, &header_size));
183
18.4E
  result->reset(new EncryptedFile(std::move(underlying), std::move(stream), header_size));
184
18.4E
  return Status::OK();
185
18.4E
}
186
187
Result<uint32_t> GetHeaderSize(SequentialFile* file, HeaderManager* header_manager);
188
189
OpenSSLInitializer& InitOpenSSL();
190
191
} // namespace encryption
192
} // namespace yb
193
194
#endif // YB_ENCRYPTION_ENCRYPTION_UTIL_H