/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 | 67 | void EncryptionParams::ToEncryptionParamsPB(EncryptionParamsPB* encryption_header) const { |
68 | 67 | encryption_header->set_data_key(key, key_size); |
69 | 67 | encryption_header->set_nonce(nonce, kBlockSize - 4); |
70 | 67 | encryption_header->set_counter(counter); |
71 | 67 | encryption_header->set_openssl_compatible_counter_overflow(openssl_compatible_counter_overflow); |
72 | 67 | } |
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 | 106 | Result<EncryptionParamsPtr> EncryptionParams::FromSlice(const Slice& s) { |
90 | 106 | auto params = std::make_unique<EncryptionParams>(); |
91 | 106 | Slice mutable_s(s); |
92 | 106 | memcpy(params->nonce, s.data(), sizeof(params->nonce)); |
93 | 106 | memcpy(¶ms->counter, s.data() + sizeof(params->nonce), sizeof(params->counter)); |
94 | 106 | mutable_s.remove_prefix(sizeof(params->nonce) + sizeof(params->counter)); |
95 | 106 | RETURN_NOT_OK(IsValidKeySize(mutable_s.size())); |
96 | 106 | memcpy(params->key, mutable_s.data(), mutable_s.size()); |
97 | 106 | params->key_size = narrow_cast<uint32_t>(mutable_s.size()); |
98 | 106 | return params; |
99 | 106 | } |
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 | 400k | if (0 <= ctr_min399k && ctr_min <= ctr_max400k && ctr_max <= std::numeric_limits<uint32_t>::max()) { |
110 | 400k | encryption_params->counter = narrow_cast<uint32_t>( |
111 | 400k | 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 | 226 | Status EncryptionParams::IsValidKeySize(size_t size) { |
125 | 226 | if (size != 16 && size != 240 && size != 320 ) { |
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 | 226 | return Status::OK(); |
131 | 226 | } |
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 | 205k | void* EncryptionBuffer::GetBuffer(size_t size_needed) { |
142 | 205k | if (size_needed > size) { |
143 | 789 | size = size_needed; |
144 | 789 | if (buffer) { |
145 | 68 | free(buffer); |
146 | 68 | } |
147 | 789 | buffer = malloc(size_needed); |
148 | 789 | } |
149 | 205k | return buffer; |
150 | 205k | } |
151 | | |
152 | 176 | EncryptionBuffer::~EncryptionBuffer() { |
153 | 176 | if (buffer) { |
154 | 176 | free(buffer); |
155 | 176 | } |
156 | 176 | } |
157 | | |
158 | 205k | EncryptionBuffer* EncryptionBuffer::Get() { |
159 | 205k | static thread_local EncryptionBuffer encryption_buffer; |
160 | 205k | return &encryption_buffer; |
161 | 205k | } |
162 | | |
163 | 5.31k | Result<uint32_t> GetHeaderSize(SequentialFile* file, HeaderManager* header_manager) { |
164 | 5.31k | if (!header_manager) { |
165 | 0 | return STATUS(InvalidArgument, "header_manager argument must be non null."); |
166 | 0 | } |
167 | 5.31k | Slice encryption_info; |
168 | 5.31k | auto metadata_start = header_manager->GetEncryptionMetadataStartIndex(); |
169 | 5.31k | auto buf = static_cast<uint8_t*>(EncryptionBuffer::Get()->GetBuffer(metadata_start)); |
170 | | |
171 | 5.31k | RETURN_NOT_OK(file->Read(metadata_start, &encryption_info, buf)); |
172 | 5.31k | auto status = VERIFY_RESULT(header_manager->GetFileEncryptionStatusFromPrefix(encryption_info)); |
173 | 5.31k | return status.is_encrypted ? (status.header_size + metadata_start)4 : 05.30k ; |
174 | 5.31k | } |
175 | | |
176 | | class OpenSSLInitializer { |
177 | | public: |
178 | 15.8k | OpenSSLInitializer() { |
179 | 15.8k | SSL_library_init(); |
180 | 15.8k | SSL_load_error_strings(); |
181 | 15.8k | OpenSSL_add_all_algorithms(); |
182 | 15.8k | OpenSSL_add_all_ciphers(); |
183 | 15.8k | } |
184 | | |
185 | 145 | ~OpenSSLInitializer() { |
186 | 145 | ERR_free_strings(); |
187 | 145 | EVP_cleanup(); |
188 | 145 | CRYPTO_cleanup_all_ex_data(); |
189 | 145 | ERR_remove_thread_state(nullptr); |
190 | 145 | SSL_COMP_free_compression_methods(); |
191 | 145 | } |
192 | | }; |
193 | | |
194 | 26.6k | OpenSSLInitializer& InitOpenSSL() { |
195 | 26.6k | static OpenSSLInitializer initializer; |
196 | 26.6k | return initializer; |
197 | 26.6k | } |
198 | | |
199 | | Status CompleteCreateEncryptionInfoForWrite(const std::string& header, |
200 | | std::unique_ptr<EncryptionParams> encryption_params, |
201 | | std::unique_ptr<BlockAccessCipherStream>* stream, |
202 | 40 | uint32_t* header_size) { |
203 | | // Since file doesn't exist or this overwrites, append key to the name and create. |
204 | 40 | *stream = std::make_unique<BlockAccessCipherStream>(std::move(encryption_params)); |
205 | 40 | RETURN_NOT_OK((*stream)->Init()); |
206 | 40 | 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 | 40 | *header_size = static_cast<uint32_t>(header.size()); |
210 | 40 | return Status::OK(); |
211 | 40 | } |
212 | | |
213 | | } // namespace encryption |
214 | | } // namespace yb |