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