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