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/build_verity_tree.h"
18 
19 #include <android-base/logging.h>
20 #include <android-base/unique_fd.h>
21 #include <sparse/sparse.h>
22 
23 #undef NDEBUG
24 
generate_verity_tree(const std::string & data_filename,const std::string & verity_filename,HashTreeBuilder * builder,const std::vector<unsigned char> & salt_content,size_t block_size,bool sparse,bool verbose)25 bool generate_verity_tree(const std::string& data_filename,
26                           const std::string& verity_filename,
27                           HashTreeBuilder* builder,
28                           const std::vector<unsigned char>& salt_content,
29                           size_t block_size, bool sparse, bool verbose) {
30   android::base::unique_fd data_fd(open(data_filename.c_str(), O_RDONLY));
31   if (data_fd == -1) {
32     PLOG(ERROR) << "failed to open " << data_filename;
33     return false;
34   }
35 
36   struct sparse_file* file;
37   if (sparse) {
38     file = sparse_file_import(data_fd, false, false);
39   } else {
40     file = sparse_file_import_auto(data_fd, false, verbose);
41   }
42 
43   if (!file) {
44     LOG(ERROR) << "failed to read file " << data_filename;
45     return false;
46   }
47 
48   int64_t len = sparse_file_len(file, false, false);
49   if (len % block_size != 0) {
50     LOG(ERROR) << "file size " << len << " is not a multiple of " << block_size
51                << " byte";
52     return false;
53   }
54 
55   // Initialize the builder to compute the hash tree.
56   if (!builder->Initialize(len, salt_content)) {
57     LOG(ERROR) << "Failed to initialize HashTreeBuilder";
58     return false;
59   }
60 
61   auto hash_callback = [](void* priv, const void* data, size_t len) {
62     auto sparse_hasher = static_cast<HashTreeBuilder*>(priv);
63     return sparse_hasher->Update(static_cast<const unsigned char*>(data), len)
64                ? 0
65                : 1;
66   };
67   sparse_file_callback(file, false, false, hash_callback, builder);
68   sparse_file_destroy(file);
69 
70   if (!builder->BuildHashTree()) {
71     return false;
72   }
73 
74   return builder->WriteHashTreeToFile(verity_filename);
75 }
76