You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
4.7 KiB
170 lines
4.7 KiB
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <getopt.h>
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <limits>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <android-base/file.h>
|
|
#include <android-base/logging.h>
|
|
#include <android-base/parseint.h>
|
|
#include <android-base/unique_fd.h>
|
|
|
|
#include "verity/build_verity_tree.h"
|
|
|
|
static void usage(void) {
|
|
printf(
|
|
"usage: build_verity_tree [ <options> ] -s <size> | <data> <verity>\n"
|
|
"options:\n"
|
|
" -a,--salt-str=<string> set salt to <string>\n"
|
|
" -A,--salt-hex=<hex digits> set salt to <hex digits>\n"
|
|
" -h show this help\n"
|
|
" -s,--verity-size=<data size> print the size of the verity tree\n"
|
|
" -v, enable verbose logging\n"
|
|
" -S treat <data image> as a sparse file\n");
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
constexpr size_t kBlockSize = 4096;
|
|
|
|
std::vector<unsigned char> salt;
|
|
bool sparse = false;
|
|
uint64_t calculate_size = 0;
|
|
bool verbose = false;
|
|
std::string hash_algorithm;
|
|
|
|
while (1) {
|
|
constexpr struct option long_options[] = {
|
|
{"salt-str", required_argument, nullptr, 'a'},
|
|
{"salt-hex", required_argument, nullptr, 'A'},
|
|
{"help", no_argument, nullptr, 'h'},
|
|
{"sparse", no_argument, nullptr, 'S'},
|
|
{"verity-size", required_argument, nullptr, 's'},
|
|
{"verbose", no_argument, nullptr, 'v'},
|
|
{"hash-algorithm", required_argument, nullptr, 0},
|
|
{nullptr, 0, nullptr, 0}};
|
|
int option_index;
|
|
int c = getopt_long(argc, argv, "a:A:hSs:v", long_options, &option_index);
|
|
if (c < 0) {
|
|
break;
|
|
}
|
|
|
|
switch (c) {
|
|
case 'a':
|
|
salt.clear();
|
|
salt.insert(salt.end(), optarg, &optarg[strlen(optarg)]);
|
|
break;
|
|
case 'A':
|
|
if (!HashTreeBuilder::ParseBytesArrayFromString(optarg, &salt)) {
|
|
return 1;
|
|
}
|
|
break;
|
|
case 'h':
|
|
usage();
|
|
return 1;
|
|
case 'S':
|
|
sparse = true;
|
|
break;
|
|
case 's': {
|
|
if (!android::base::ParseUint(optarg, &calculate_size,
|
|
std::numeric_limits<uint64_t>::max())) {
|
|
LOG(ERROR) << "Invalid input size: " << optarg;
|
|
return 1;
|
|
}
|
|
|
|
} break;
|
|
case 'v':
|
|
verbose = true;
|
|
break;
|
|
case 0: {
|
|
std::string option = long_options[option_index].name;
|
|
if (option == "hash-algorithm") {
|
|
hash_algorithm = optarg;
|
|
}
|
|
} break;
|
|
case '?':
|
|
usage();
|
|
return 1;
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
auto hash_function = hash_algorithm.empty()
|
|
? EVP_sha256()
|
|
: HashTreeBuilder::HashFunction(hash_algorithm);
|
|
if (hash_function == nullptr) {
|
|
return 1;
|
|
}
|
|
HashTreeBuilder builder(kBlockSize, hash_function);
|
|
|
|
if (calculate_size) {
|
|
if (argc != 0) {
|
|
usage();
|
|
return 1;
|
|
}
|
|
|
|
uint64_t tree_size = builder.CalculateSize(calculate_size);
|
|
printf("%" PRIu64 "\n", tree_size);
|
|
return 0;
|
|
}
|
|
|
|
if (argc != 2) {
|
|
usage();
|
|
return 1;
|
|
}
|
|
|
|
if (salt.empty()) {
|
|
salt.resize(builder.hash_size());
|
|
|
|
android::base::unique_fd random_fd(open("/dev/urandom", O_RDONLY));
|
|
if (random_fd < 0) {
|
|
PLOG(ERROR) << "failed to open /dev/urandom";
|
|
return 1;
|
|
}
|
|
|
|
ssize_t ret = read(random_fd, salt.data(), salt.size());
|
|
if (ret != static_cast<ssize_t>(salt.size())) {
|
|
PLOG(ERROR) << "failed to read " << salt.size()
|
|
<< " bytes from /dev/urandom: " << ret;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (!generate_verity_tree(argv[0], argv[1], &builder, salt, kBlockSize,
|
|
sparse, verbose)) {
|
|
return 1;
|
|
}
|
|
|
|
// Output the root hash and the salt.
|
|
std::string root_hash_string =
|
|
HashTreeBuilder::BytesArrayToString(builder.root_hash());
|
|
std::string salt_string = HashTreeBuilder::BytesArrayToString(salt);
|
|
printf("%s %s\n", root_hash_string.c_str(), salt_string.c_str());
|
|
|
|
return 0;
|
|
}
|