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