1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "verity/hash_tree_builder.h"
18
19 #include <algorithm>
20 #include <functional>
21 #include <memory>
22
23 #include <android-base/file.h>
24 #include <android-base/logging.h>
25 #include <android-base/stringprintf.h>
26 #include <android-base/strings.h>
27 #include <android-base/unique_fd.h>
28 #include <openssl/bn.h>
29
30 #include "build_verity_tree_utils.h"
31
HashFunction(const std::string & hash_name)32 const EVP_MD* HashTreeBuilder::HashFunction(const std::string& hash_name) {
33 if (android::base::EqualsIgnoreCase(hash_name, "sha1")) {
34 return EVP_sha1();
35 }
36 if (android::base::EqualsIgnoreCase(hash_name, "sha256")) {
37 return EVP_sha256();
38 }
39 if (android::base::EqualsIgnoreCase(hash_name, "sha384")) {
40 return EVP_sha384();
41 }
42 if (android::base::EqualsIgnoreCase(hash_name, "sha512")) {
43 return EVP_sha512();
44 }
45 if (android::base::EqualsIgnoreCase(hash_name, "blake2b-256")) {
46 return EVP_blake2b256();
47 }
48
49 LOG(ERROR) << "Unsupported hash algorithm " << hash_name;
50 return nullptr;
51 }
52
HashTreeBuilder(size_t block_size,const EVP_MD * md)53 HashTreeBuilder::HashTreeBuilder(size_t block_size, const EVP_MD* md)
54 : block_size_(block_size), data_size_(0), md_(md) {
55 CHECK(md_ != nullptr) << "Failed to initialize md";
56
57 hash_size_raw_ = EVP_MD_size(md_);
58
59 // Round up the hash size to the next power of 2.
60 hash_size_ = 1;
61 while (hash_size_ < hash_size_raw_) {
62 hash_size_ = hash_size_ << 1;
63 }
64 CHECK_LT(hash_size_ * 2, block_size_);
65 }
66
BytesArrayToString(const std::vector<unsigned char> & bytes)67 std::string HashTreeBuilder::BytesArrayToString(
68 const std::vector<unsigned char>& bytes) {
69 std::string result;
70 for (const auto& c : bytes) {
71 result += android::base::StringPrintf("%02x", c);
72 }
73 return result;
74 }
75
ParseBytesArrayFromString(const std::string & hex_string,std::vector<unsigned char> * bytes)76 bool HashTreeBuilder::ParseBytesArrayFromString(
77 const std::string& hex_string, std::vector<unsigned char>* bytes) {
78 if (hex_string.size() % 2 != 0) {
79 LOG(ERROR) << "Hex string size must be even number " << hex_string;
80 return false;
81 }
82
83 BIGNUM* bn = nullptr;
84 if (!BN_hex2bn(&bn, hex_string.c_str())) {
85 LOG(ERROR) << "Failed to parse hex in " << hex_string;
86 return false;
87 }
88 std::unique_ptr<BIGNUM, decltype(&BN_free)> guard(bn, BN_free);
89
90 size_t bytes_size = BN_num_bytes(bn);
91 bytes->resize(bytes_size);
92 if (BN_bn2bin(bn, bytes->data()) != bytes_size) {
93 LOG(ERROR) << "Failed to convert hex to bytes " << hex_string;
94 return false;
95 }
96 return true;
97 }
98
CalculateSize(uint64_t input_size,size_t block_size,size_t hash_size)99 uint64_t HashTreeBuilder::CalculateSize(
100 uint64_t input_size, size_t block_size, size_t hash_size) {
101 uint64_t verity_blocks = 0;
102 size_t level_blocks;
103 size_t levels = 0;
104 do {
105 level_blocks =
106 verity_tree_blocks(input_size, block_size, hash_size, levels);
107 levels++;
108 verity_blocks += level_blocks;
109 } while (level_blocks > 1);
110
111 return verity_blocks * block_size;
112 }
113
Initialize(int64_t expected_data_size,const std::vector<unsigned char> & salt)114 bool HashTreeBuilder::Initialize(int64_t expected_data_size,
115 const std::vector<unsigned char>& salt) {
116 data_size_ = expected_data_size;
117 salt_ = salt;
118
119 if (data_size_ % block_size_ != 0) {
120 LOG(ERROR) << "file size " << data_size_
121 << " is not a multiple of block size " << block_size_;
122 return false;
123 }
124
125 // Reserve enough space for the hash of the input data.
126 size_t base_level_blocks =
127 verity_tree_blocks(data_size_, block_size_, hash_size_, 0);
128 std::vector<unsigned char> base_level;
129 base_level.reserve(base_level_blocks * block_size_);
130 verity_tree_.emplace_back(std::move(base_level));
131
132 // Save the hash of the zero block to avoid future recalculation.
133 std::vector<unsigned char> zero_block(block_size_, 0);
134 zero_block_hash_.resize(hash_size_);
135 HashBlock(zero_block.data(), zero_block_hash_.data());
136
137 return true;
138 }
139
HashBlock(const unsigned char * block,unsigned char * out)140 bool HashTreeBuilder::HashBlock(const unsigned char* block,
141 unsigned char* out) {
142 unsigned int s;
143 int ret = 1;
144
145 EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
146 CHECK(mdctx != nullptr);
147 ret &= EVP_DigestInit_ex(mdctx, md_, nullptr);
148 ret &= EVP_DigestUpdate(mdctx, salt_.data(), salt_.size());
149 ret &= EVP_DigestUpdate(mdctx, block, block_size_);
150 ret &= EVP_DigestFinal_ex(mdctx, out, &s);
151 EVP_MD_CTX_destroy(mdctx);
152
153 CHECK_EQ(1, ret);
154 CHECK_EQ(hash_size_raw_, s);
155 std::fill(out + s, out + hash_size_, 0);
156
157 return true;
158 }
159
HashBlocks(const unsigned char * data,size_t len,std::vector<unsigned char> * output_vector)160 bool HashTreeBuilder::HashBlocks(const unsigned char* data, size_t len,
161 std::vector<unsigned char>* output_vector) {
162 if (len == 0) {
163 return true;
164 }
165 CHECK_EQ(0, len % block_size_);
166
167 if (data == nullptr) {
168 for (size_t i = 0; i < len; i += block_size_) {
169 output_vector->insert(output_vector->end(), zero_block_hash_.begin(),
170 zero_block_hash_.end());
171 }
172 return true;
173 }
174
175 for (size_t i = 0; i < len; i += block_size_) {
176 unsigned char hash_buffer[hash_size_];
177 if (!HashBlock(data + i, hash_buffer)) {
178 return false;
179 }
180 output_vector->insert(output_vector->end(), hash_buffer,
181 hash_buffer + hash_size_);
182 }
183
184 return true;
185 }
186
Update(const unsigned char * data,size_t len)187 bool HashTreeBuilder::Update(const unsigned char* data, size_t len) {
188 CHECK_GT(data_size_, 0);
189
190 if (!leftover_.empty()) {
191 CHECK_LT(leftover_.size(), block_size_);
192 size_t append_len = std::min(len, block_size_ - leftover_.size());
193 if (data == nullptr) {
194 leftover_.insert(leftover_.end(), append_len, 0);
195 } else {
196 leftover_.insert(leftover_.end(), data, data + append_len);
197 }
198 if (leftover_.size() < block_size_) {
199 return true;
200 }
201 if (!HashBlocks(leftover_.data(), leftover_.size(), &verity_tree_[0])) {
202 return false;
203 }
204 leftover_.clear();
205 if (data != nullptr) {
206 data += append_len;
207 }
208 len -= append_len;
209 }
210 if (len % block_size_ != 0) {
211 if (data == nullptr) {
212 leftover_.assign(len % block_size_, 0);
213 } else {
214 leftover_.assign(data + len - len % block_size_, data + len);
215 }
216 len -= len % block_size_;
217 }
218 return HashBlocks(data, len, &verity_tree_[0]);
219 }
220
CalculateRootDigest(const std::vector<unsigned char> & root_verity,std::vector<unsigned char> * root_digest)221 bool HashTreeBuilder::CalculateRootDigest(const std::vector<unsigned char>& root_verity,
222 std::vector<unsigned char>* root_digest) {
223 if (root_verity.size() != block_size_) {
224 return false;
225 }
226 return HashBlocks(root_verity.data(), block_size_, root_digest);
227 }
228
BuildHashTree()229 bool HashTreeBuilder::BuildHashTree() {
230 // Expects only the base level in the verity_tree_.
231 CHECK_EQ(1, verity_tree_.size());
232
233 if (!leftover_.empty()) {
234 LOG(ERROR) << leftover_.size() << " bytes data left from last Update().";
235 return false;
236 }
237
238 // Expects the base level to have the same size as the total hash size of
239 // input data.
240 AppendPaddings(&verity_tree_.back());
241 size_t base_level_blocks =
242 verity_tree_blocks(data_size_, block_size_, hash_size_, 0);
243 CHECK_EQ(base_level_blocks * block_size_, verity_tree_[0].size());
244
245 while (verity_tree_.back().size() > block_size_) {
246 const auto& current_level = verity_tree_.back();
247 // Computes the next level of the verity tree based on the hash of the
248 // current level.
249 size_t next_level_blocks =
250 verity_tree_blocks(current_level.size(), block_size_, hash_size_, 0);
251 std::vector<unsigned char> next_level;
252 next_level.reserve(next_level_blocks * block_size_);
253
254 HashBlocks(current_level.data(), current_level.size(), &next_level);
255 AppendPaddings(&next_level);
256
257 // Checks the size of the next level.
258 CHECK_EQ(next_level_blocks * block_size_, next_level.size());
259 verity_tree_.emplace_back(std::move(next_level));
260 }
261
262 CHECK_EQ(block_size_, verity_tree_.back().size());
263 return CalculateRootDigest(verity_tree_.back(), &root_hash_);
264 }
265
CheckHashTree(const std::vector<unsigned char> & hash_tree) const266 bool HashTreeBuilder::CheckHashTree(
267 const std::vector<unsigned char>& hash_tree) const {
268 size_t offset = 0;
269 // Reads reversely to output the verity tree top-down.
270 for (size_t i = verity_tree_.size(); i > 0; i--) {
271 const auto& level_blocks = verity_tree_[i - 1];
272 if (offset + level_blocks.size() > hash_tree.size()) {
273 LOG(ERROR) << "Hash tree too small: " << hash_tree.size();
274 return false;
275 }
276 auto iter = std::mismatch(level_blocks.begin(), level_blocks.end(),
277 hash_tree.begin() + offset)
278 .first;
279 if (iter != level_blocks.end()) {
280 LOG(ERROR) << "Mismatch found at the hash tree level " << i << " offset "
281 << std::distance(level_blocks.begin(), iter);
282 return false;
283 }
284 offset += level_blocks.size();
285 }
286 if (offset != hash_tree.size()) {
287 LOG(ERROR) << "Hash tree size mismatch: " << hash_tree.size()
288 << " != " << offset;
289 return false;
290 }
291 return true;
292 }
293
WriteHashTreeToFile(const std::string & output) const294 bool HashTreeBuilder::WriteHashTreeToFile(const std::string& output) const {
295 android::base::unique_fd output_fd(
296 open(output.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666));
297 if (output_fd == -1) {
298 PLOG(ERROR) << "Failed to open output file " << output;
299 return false;
300 }
301
302 return WriteHashTreeToFd(output_fd, 0);
303 }
304
WriteHashTree(std::function<bool (const void *,size_t)> callback) const305 bool HashTreeBuilder::WriteHashTree(
306 std::function<bool(const void*, size_t)> callback) const {
307 CHECK(!verity_tree_.empty());
308
309 // Reads reversely to output the verity tree top-down.
310 for (size_t i = verity_tree_.size(); i > 0; i--) {
311 const auto& level_blocks = verity_tree_[i - 1];
312 if (!callback(level_blocks.data(), level_blocks.size())) {
313 PLOG(ERROR) << "Failed to write the hash tree level " << i;
314 return false;
315 }
316 }
317
318 return true;
319 }
320
WriteHashTreeToFd(int fd,uint64_t offset) const321 bool HashTreeBuilder::WriteHashTreeToFd(int fd, uint64_t offset) const {
322 CHECK(!verity_tree_.empty());
323
324 if (lseek(fd, offset, SEEK_SET) != offset) {
325 PLOG(ERROR) << "Failed to seek the output fd, offset: " << offset;
326 return false;
327 }
328
329 return WriteHashTree([fd](auto data, auto size) {
330 return android::base::WriteFully(fd, data, size);
331 });
332 }
333
AppendPaddings(std::vector<unsigned char> * data)334 void HashTreeBuilder::AppendPaddings(std::vector<unsigned char>* data) {
335 size_t remainder = data->size() % block_size_;
336 if (remainder != 0) {
337 data->resize(data->size() + block_size_ - remainder, 0);
338 }
339 }
340