YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/encryption/encryption_util.cc
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
#include "yb/encryption/encryption_util.h"
15
16
#include <openssl/err.h>
17
#include <openssl/rand.h>
18
#include <openssl/ssl.h>
19
20
#include <memory>
21
22
#include <boost/pointer_cast.hpp>
23
24
#include "yb/gutil/casts.h"
25
#include "yb/gutil/endian.h"
26
27
#include "yb/encryption/cipher_stream.h"
28
#include "yb/encryption/encryption.pb.h"
29
#include "yb/encryption/header_manager.h"
30
31
#include "yb/util/atomic.h"
32
#include "yb/util/flag_tags.h"
33
#include "yb/util/logging.h"
34
#include "yb/util/random_util.h"
35
#include "yb/util/status_format.h"
36
37
DEFINE_int64(encryption_counter_min, 0,
38
             "Minimum value (inclusive) for the randomly generated 32-bit encryption counter at "
39
             "the beginning of a file");
40
TAG_FLAG(encryption_counter_min, advanced);
41
TAG_FLAG(encryption_counter_min, hidden);
42
43
DEFINE_int64(encryption_counter_max, 0x7fffffffLL,
44
             "Maximum value (inclusive) for the randomly generated 32-bit encryption counter at "
45
             "the beginning of a file. Setting to 2147483647 by default to reduce the probability "
46
             "of #3707 until it is fixed. This only reduces the key size by 1 bit but eliminates "
47
             "the encryption overflow issue for files up to 32 GiB in size.");
48
49
TAG_FLAG(encryption_counter_max, advanced);
50
TAG_FLAG(encryption_counter_max, hidden);
51
52
DEFINE_test_flag(bool, encryption_use_openssl_compatible_counter_overflow, true,
53
                 "Overflow into the rest of the initialization vector when computing counter"
54
                 "increment for newly created keys.")
55
56
namespace yb {
57
namespace encryption {
58
59
namespace {
60
61
std::vector<std::unique_ptr<std::mutex>> crypto_mutexes;
62
63
}  // anonymous namespace
64
65
constexpr uint32_t kDefaultKeySize = 16;
66
67
56
void EncryptionParams::ToEncryptionParamsPB(EncryptionParamsPB* encryption_header) const {
68
56
  encryption_header->set_data_key(key, key_size);
69
56
  encryption_header->set_nonce(nonce, kBlockSize - 4);
70
56
  encryption_header->set_counter(counter);
71
56
  encryption_header->set_openssl_compatible_counter_overflow(openssl_compatible_counter_overflow);
72
56
}
73
74
Result<EncryptionParamsPtr> EncryptionParams::FromEncryptionParamsPB(
75
109
    const EncryptionParamsPB& encryption_header) {
76
109
  auto encryption_params = std::make_unique<EncryptionParams>();
77
109
  memcpy(encryption_params->key, encryption_header.data_key().c_str(),
78
109
         encryption_header.data_key().size());
79
109
  memcpy(encryption_params->nonce, encryption_header.nonce().c_str(), kBlockSize - 4);
80
109
  encryption_params->counter = encryption_header.counter();
81
109
  auto size = encryption_header.data_key().size();
82
109
  RETURN_NOT_OK(IsValidKeySize(size));
83
109
  encryption_params->key_size = narrow_cast<uint32_t>(size);
84
109
  encryption_params->openssl_compatible_counter_overflow =
85
109
      encryption_header.openssl_compatible_counter_overflow();
86
109
  return encryption_params;
87
109
}
88
89
30
Result<EncryptionParamsPtr> EncryptionParams::FromSlice(const Slice& s) {
90
30
  auto params = std::make_unique<EncryptionParams>();
91
30
  Slice mutable_s(s);
92
30
  memcpy(params->nonce, s.data(), sizeof(params->nonce));
93
30
  memcpy(&params->counter, s.data() + sizeof(params->nonce), sizeof(params->counter));
94
30
  mutable_s.remove_prefix(sizeof(params->nonce) + sizeof(params->counter));
95
30
  RETURN_NOT_OK(IsValidKeySize(mutable_s.size()));
96
30
  memcpy(params->key, mutable_s.data(), mutable_s.size());
97
30
  params->key_size = narrow_cast<uint32_t>(mutable_s.size());
98
30
  return params;
99
30
}
100
101
399k
EncryptionParamsPtr EncryptionParams::NewEncryptionParams() {
102
399k
  auto encryption_params = std::make_unique<EncryptionParams>();
103
399k
  RAND_bytes(encryption_params->key, kDefaultKeySize);
104
399k
  RAND_bytes(encryption_params->nonce, kBlockSize - 4);
105
399k
  RAND_bytes(boost::reinterpret_pointer_cast<uint8_t>(&encryption_params->counter), 4);
106
107
399k
  const int64_t ctr_min = GetAtomicFlag(&FLAGS_encryption_counter_min);
108
399k
  const int64_t ctr_max = GetAtomicFlag(&FLAGS_encryption_counter_max);
109
399k
  if (0 <= ctr_min && ctr_min <= ctr_max && ctr_max <= std::numeric_limits<uint32_t>::max()) {
110
399k
    encryption_params->counter = narrow_cast<uint32_t>(
111
399k
        ctr_min + encryption_params->counter % (ctr_max - ctr_min + 1));
112
18.4E
  } else {
113
18.4E
    YB_LOG_EVERY_N_SECS(WARNING, 10)
114
0
        << "Invalid encrypted counter range: "
115
0
        << "[" << ctr_min << ", " << ctr_max << "] specified by --encryption_counter_{min,max}, "
116
0
        << "falling back to using the full unsigned 32-bit integer range.";
117
18.4E
  }
118
399k
  encryption_params->key_size = kDefaultKeySize;
119
399k
  encryption_params->openssl_compatible_counter_overflow =
120
399k
      FLAGS_TEST_encryption_use_openssl_compatible_counter_overflow;
121
399k
  return encryption_params;
122
399k
}
123
124
139
Status EncryptionParams::IsValidKeySize(size_t size) {
125
139
  if (size != 16 && size != 24 && size != 32) {
126
0
    return STATUS_SUBSTITUTE(
127
0
        InvalidArgument,
128
0
        "After parsing nonce and counter, expect 16, 24, or 32 bytes, found $0", size);
129
0
  }
130
139
  return Status::OK();
131
139
}
132
133
1
bool EncryptionParams::Equals(const EncryptionParams& other) {
134
1
  return memcmp(key, other.key, other.key_size) == 0 &&
135
1
         memcmp(nonce, other.nonce, sizeof(nonce)) == 0 &&
136
1
         counter == other.counter &&
137
1
         key_size == other.key_size &&
138
1
         openssl_compatible_counter_overflow == other.openssl_compatible_counter_overflow;
139
1
}
140
141
203k
void* EncryptionBuffer::GetBuffer(size_t size_needed) {
142
203k
  if (size_needed > size) {
143
478
    size = size_needed;
144
478
    if (buffer) {
145
68
      free(buffer);
146
68
    }
147
478
    buffer = malloc(size_needed);
148
478
  }
149
203k
  return buffer;
150
203k
}
151
152
122
EncryptionBuffer::~EncryptionBuffer() {
153
122
  if (buffer) {
154
122
    free(buffer);
155
122
  }
156
122
}
157
158
203k
EncryptionBuffer* EncryptionBuffer::Get() {
159
203k
  static thread_local EncryptionBuffer encryption_buffer;
160
203k
  return &encryption_buffer;
161
203k
}
162
163
3.08k
Result<uint32_t> GetHeaderSize(SequentialFile* file, HeaderManager* header_manager) {
164
3.08k
  if (!header_manager) {
165
0
    return STATUS(InvalidArgument, "header_manager argument must be non null.");
166
0
  }
167
3.08k
  Slice encryption_info;
168
3.08k
  auto metadata_start = header_manager->GetEncryptionMetadataStartIndex();
169
3.08k
  auto buf = static_cast<uint8_t*>(EncryptionBuffer::Get()->GetBuffer(metadata_start));
170
171
3.08k
  RETURN_NOT_OK(file->Read(metadata_start, &encryption_info, buf));
172
3.08k
  auto status = VERIFY_RESULT(header_manager->GetFileEncryptionStatusFromPrefix(encryption_info));
173
3.08k
  return status.is_encrypted ? (status.header_size + metadata_start) : 0;
174
3.08k
}
175
176
class OpenSSLInitializer {
177
 public:
178
10.8k
  OpenSSLInitializer() {
179
10.8k
    SSL_library_init();
180
10.8k
    SSL_load_error_strings();
181
10.8k
    OpenSSL_add_all_algorithms();
182
10.8k
    OpenSSL_add_all_ciphers();
183
10.8k
  }
184
185
121
  ~OpenSSLInitializer() {
186
121
    ERR_free_strings();
187
121
    EVP_cleanup();
188
121
    CRYPTO_cleanup_all_ex_data();
189
121
    ERR_remove_thread_state(nullptr);
190
121
    SSL_COMP_free_compression_methods();
191
121
  }
192
};
193
194
17.5k
OpenSSLInitializer& InitOpenSSL() {
195
17.5k
  static OpenSSLInitializer initializer;
196
17.5k
  return initializer;
197
17.5k
}
198
199
Status CompleteCreateEncryptionInfoForWrite(const std::string& header,
200
                                            std::unique_ptr<EncryptionParams> encryption_params,
201
                                            std::unique_ptr<BlockAccessCipherStream>* stream,
202
39
                                            uint32_t* header_size) {
203
  // Since file doesn't exist or this overwrites, append key to the name and create.
204
39
  *stream = std::make_unique<BlockAccessCipherStream>(std::move(encryption_params));
205
39
  RETURN_NOT_OK((*stream)->Init());
206
39
  if (header.size() > std::numeric_limits<uint32_t>::max()) {
207
0
    return STATUS_FORMAT(Corruption, "Invalid encryption header size: $0", header.size());
208
0
  }
209
39
  *header_size = static_cast<uint32_t>(header.size());
210
39
  return Status::OK();
211
39
}
212
213
} // namespace encryption
214
} // namespace yb