/Users/deen/code/yugabyte-db/src/yb/encryption/header_manager_impl.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/header_manager_impl.h" |
15 | | |
16 | | #include <string> |
17 | | |
18 | | #include "yb/encryption/cipher_stream_fwd.h" |
19 | | #include "yb/encryption/encryption.pb.h" |
20 | | #include "yb/encryption/header_manager.h" |
21 | | #include "yb/encryption/universe_key_manager.h" |
22 | | |
23 | | #include "yb/gutil/casts.h" |
24 | | |
25 | | #include "yb/util/status_fwd.h" |
26 | | #include "yb/util/errno.h" |
27 | | #include "yb/util/pb_util.h" |
28 | | #include "yb/util/status_format.h" |
29 | | |
30 | | static const string kEncryptionMagic = "encrypt!"; |
31 | | |
32 | | namespace yb { |
33 | | namespace encryption { |
34 | | |
35 | | class HeaderManagerImpl : public HeaderManager { |
36 | | public: |
37 | | explicit HeaderManagerImpl(UniverseKeyManager* universe_key_manager) |
38 | 12.2k | : universe_key_manager_(universe_key_manager) {} |
39 | | |
40 | 39 | Result<string> SerializeEncryptionParams(const EncryptionParams& encryption_info) override { |
41 | | // 1. Generate the EncrytionParamsPB string to be encrypted. |
42 | 39 | EncryptionParamsPB encryption_params_pb; |
43 | 39 | encryption_info.ToEncryptionParamsPB(&encryption_params_pb); |
44 | 39 | string encryption_params_pb_str; |
45 | 39 | encryption_params_pb.SerializeToString(&encryption_params_pb_str); |
46 | | |
47 | | // 2. Encrypt the encryption params with the latest universe key. |
48 | 39 | auto universe_params = VERIFY_RESULT(universe_key_manager_->GetLatestUniverseParams()); |
49 | 39 | auto stream = VERIFY_RESULT(BlockAccessCipherStream::FromEncryptionParams( |
50 | 39 | std::move(universe_params.params))); |
51 | 39 | auto encrypted_data_key = static_cast<char*>( |
52 | 39 | EncryptionBuffer::Get()->GetBuffer(encryption_params_pb_str.size())); |
53 | 39 | RETURN_NOT_OK(stream->Encrypt(0, encryption_params_pb_str, encrypted_data_key)); |
54 | | |
55 | | // 3. Serialize the universe key id. |
56 | 39 | auto universe_key_id_str = universe_params.version_id; |
57 | 39 | char universe_key_size[sizeof(uint32_t)]; |
58 | 39 | BigEndian::Store32(universe_key_size, narrow_cast<uint32_t>(universe_key_id_str.size())); |
59 | | |
60 | | // 4. Serialize the encrypted encryption params. |
61 | 39 | char encrypted_data_key_size[sizeof(uint32_t)]; |
62 | 39 | BigEndian::Store32( |
63 | 39 | encrypted_data_key_size, narrow_cast<uint32_t>(encryption_params_pb_str.size())); |
64 | | |
65 | | // 5. Generate the encryption metadata string. |
66 | 39 | auto metadata_str = string(universe_key_size, sizeof(universe_key_size)) + universe_key_id_str + |
67 | 39 | string(encrypted_data_key_size, sizeof(encrypted_data_key_size)) + |
68 | 39 | string(encrypted_data_key, encryption_params_pb_str.size()); |
69 | | |
70 | | // 6. Serialize the header size. |
71 | 39 | char header_size[sizeof(uint32_t)]; |
72 | 39 | BigEndian::Store32(header_size, narrow_cast<uint32_t>(metadata_str.size())); |
73 | | |
74 | 39 | return kEncryptionMagic + string(header_size, sizeof(header_size)) + metadata_str; |
75 | 39 | } |
76 | | |
77 | | Result<EncryptionParamsPtr> |
78 | 35 | DecodeEncryptionParamsFromEncryptionMetadata(const Slice& s) override { |
79 | 35 | Slice s_mutable(s); |
80 | | // 1. Get the size of the universe key id. |
81 | 35 | RETURN_NOT_OK(CheckSliceCanBeDecoded(s_mutable, sizeof(uint32_t), "universe key id size")); |
82 | 35 | auto universe_key_size = BigEndian::Load32(s_mutable.data()); |
83 | 35 | s_mutable.remove_prefix(sizeof(uint32_t)); |
84 | | |
85 | | // 2. Get the universe key id. |
86 | 35 | RETURN_NOT_OK(CheckSliceCanBeDecoded(s_mutable, universe_key_size, "universe key id")); |
87 | 35 | std::string universe_key_id(s_mutable.cdata(), universe_key_size); |
88 | 35 | s_mutable.remove_prefix(universe_key_size); |
89 | | |
90 | | // 3. Create an encryption stream from the universe key. |
91 | 35 | auto universe_params = VERIFY_RESULT( |
92 | 35 | universe_key_manager_->GetUniverseParamsWithVersion(universe_key_id)); |
93 | 35 | auto stream = VERIFY_RESULT(BlockAccessCipherStream::FromEncryptionParams( |
94 | 35 | std::move(universe_params))); |
95 | | |
96 | | // 4. Get the size of the encryption params pb. |
97 | 35 | RETURN_NOT_OK(CheckSliceCanBeDecoded(s_mutable, sizeof(uint32_t), "encryption params size")); |
98 | 35 | auto encryption_params_pb_size = BigEndian::Load32(s_mutable.data()); |
99 | 35 | s_mutable.remove_prefix(sizeof(uint32_t)); |
100 | | |
101 | | // 5. Decrypt the resulting data key. |
102 | 35 | auto decrypted_data_key = static_cast<uint8_t*>( |
103 | 35 | EncryptionBuffer::Get()->GetBuffer(s_mutable.size())); |
104 | 35 | RETURN_NOT_OK(stream->Decrypt(0, s_mutable, decrypted_data_key)); |
105 | | |
106 | | // 6. Convert the resulting decrypted data key into encryption params. |
107 | 35 | RETURN_NOT_OK(CheckSliceCanBeDecoded( |
108 | 35 | s_mutable, encryption_params_pb_size, "encryption params")); |
109 | 35 | auto encryption_params_pb = VERIFY_RESULT(pb_util::ParseFromSlice<EncryptionParamsPB>( |
110 | 35 | Slice(decrypted_data_key, encryption_params_pb_size))); |
111 | 35 | return EncryptionParams::FromEncryptionParamsPB(encryption_params_pb); |
112 | 35 | } |
113 | | |
114 | 1.90M | uint32_t GetEncryptionMetadataStartIndex() override { |
115 | 1.90M | return narrow_cast<uint32_t>(kEncryptionMagic.size() + sizeof(uint32_t)); |
116 | 1.90M | } |
117 | | |
118 | | Result<FileEncryptionStatus> GetFileEncryptionStatusFromPrefix( |
119 | 1.90M | const Slice& s) override { |
120 | 1.90M | FileEncryptionStatus status; |
121 | 1.90M | status.is_encrypted = s.compare_prefix(Slice(kEncryptionMagic)) == 0; |
122 | 1.90M | if (status.is_encrypted) { |
123 | 39 | status.header_size = BigEndian::Load32(s.data() + kEncryptionMagic.size()); |
124 | 39 | } |
125 | 1.90M | return status; |
126 | 1.90M | } |
127 | | |
128 | 3.39M | bool IsEncryptionEnabled() override { |
129 | 3.39M | return universe_key_manager_->IsEncryptionEnabled(); |
130 | 3.39M | } |
131 | | |
132 | | private: |
133 | 140 | Status CheckSliceCanBeDecoded(const Slice& s, uint32_t expected_length, const string& field) { |
134 | 140 | if (s.size() < expected_length) { |
135 | 0 | return STATUS_SUBSTITUTE(InvalidArgument, |
136 | 0 | "Error parsing field $0: expect $1 bytes found $2", |
137 | 0 | field, expected_length, s.size()); |
138 | 0 | } |
139 | 140 | return Status::OK(); |
140 | 140 | } |
141 | | |
142 | | UniverseKeyManager* universe_key_manager_; |
143 | | |
144 | | }; |
145 | | |
146 | 12.2k | std::unique_ptr<HeaderManager> DefaultHeaderManager(UniverseKeyManager* universe_key_manager) { |
147 | 12.2k | return std::make_unique<HeaderManagerImpl>(universe_key_manager); |
148 | 12.2k | } |
149 | | |
150 | | } // namespace encryption |
151 | | } // namespace yb |