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 <fcntl.h>
18 #include <getopt.h>
19 #include <inttypes.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include <limits>
25 #include <string>
26 #include <vector>
27
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
30 #include <android-base/parseint.h>
31 #include <android-base/unique_fd.h>
32
33 #include "verity/build_verity_tree.h"
34
usage(void)35 static void usage(void) {
36 printf(
37 "usage: build_verity_tree [ <options> ] -s <size> | <data> <verity>\n"
38 "options:\n"
39 " -a,--salt-str=<string> set salt to <string>\n"
40 " -A,--salt-hex=<hex digits> set salt to <hex digits>\n"
41 " -h show this help\n"
42 " -s,--verity-size=<data size> print the size of the verity tree\n"
43 " -v, enable verbose logging\n"
44 " -S treat <data image> as a sparse file\n");
45 }
46
main(int argc,char ** argv)47 int main(int argc, char** argv) {
48 constexpr size_t kBlockSize = 4096;
49
50 std::vector<unsigned char> salt;
51 bool sparse = false;
52 uint64_t calculate_size = 0;
53 bool verbose = false;
54 std::string hash_algorithm;
55
56 while (1) {
57 constexpr struct option long_options[] = {
58 {"salt-str", required_argument, nullptr, 'a'},
59 {"salt-hex", required_argument, nullptr, 'A'},
60 {"help", no_argument, nullptr, 'h'},
61 {"sparse", no_argument, nullptr, 'S'},
62 {"verity-size", required_argument, nullptr, 's'},
63 {"verbose", no_argument, nullptr, 'v'},
64 {"hash-algorithm", required_argument, nullptr, 0},
65 {nullptr, 0, nullptr, 0}};
66 int option_index;
67 int c = getopt_long(argc, argv, "a:A:hSs:v", long_options, &option_index);
68 if (c < 0) {
69 break;
70 }
71
72 switch (c) {
73 case 'a':
74 salt.clear();
75 salt.insert(salt.end(), optarg, &optarg[strlen(optarg)]);
76 break;
77 case 'A':
78 if (!HashTreeBuilder::ParseBytesArrayFromString(optarg, &salt)) {
79 return 1;
80 }
81 break;
82 case 'h':
83 usage();
84 return 1;
85 case 'S':
86 sparse = true;
87 break;
88 case 's': {
89 if (!android::base::ParseUint(optarg, &calculate_size,
90 std::numeric_limits<uint64_t>::max())) {
91 LOG(ERROR) << "Invalid input size: " << optarg;
92 return 1;
93 }
94
95 } break;
96 case 'v':
97 verbose = true;
98 break;
99 case 0: {
100 std::string option = long_options[option_index].name;
101 if (option == "hash-algorithm") {
102 hash_algorithm = optarg;
103 }
104 } break;
105 case '?':
106 usage();
107 return 1;
108 default:
109 abort();
110 }
111 }
112
113 argc -= optind;
114 argv += optind;
115
116 auto hash_function = hash_algorithm.empty()
117 ? EVP_sha256()
118 : HashTreeBuilder::HashFunction(hash_algorithm);
119 if (hash_function == nullptr) {
120 return 1;
121 }
122 HashTreeBuilder builder(kBlockSize, hash_function);
123
124 if (calculate_size) {
125 if (argc != 0) {
126 usage();
127 return 1;
128 }
129
130 uint64_t tree_size = builder.CalculateSize(calculate_size);
131 printf("%" PRIu64 "\n", tree_size);
132 return 0;
133 }
134
135 if (argc != 2) {
136 usage();
137 return 1;
138 }
139
140 if (salt.empty()) {
141 salt.resize(builder.hash_size());
142
143 android::base::unique_fd random_fd(open("/dev/urandom", O_RDONLY));
144 if (random_fd < 0) {
145 PLOG(ERROR) << "failed to open /dev/urandom";
146 return 1;
147 }
148
149 ssize_t ret = read(random_fd, salt.data(), salt.size());
150 if (ret != static_cast<ssize_t>(salt.size())) {
151 PLOG(ERROR) << "failed to read " << salt.size()
152 << " bytes from /dev/urandom: " << ret;
153 return 1;
154 }
155 }
156
157 if (!generate_verity_tree(argv[0], argv[1], &builder, salt, kBlockSize,
158 sparse, verbose)) {
159 return 1;
160 }
161
162 // Output the root hash and the salt.
163 std::string root_hash_string =
164 HashTreeBuilder::BytesArrayToString(builder.root_hash());
165 std::string salt_string = HashTreeBuilder::BytesArrayToString(salt);
166 printf("%s %s\n", root_hash_string.c_str(), salt_string.c_str());
167
168 return 0;
169 }
170