/* Searches for a block in the hash table */ block_node *check_hash(uint32_t block) { block_node *b; //pthread_mutex_lock(&hash_mutex); if (ht[hash_block(block)].active == 0){ /* This will be the common case...let's optimize here with likely() */ return NULL; } b = check_list(ht[hash_block(block)].list, block); //pthread_mutex_unlock(&hash_mutex); return b; }
static void setup_macaddr(void) { #if CONFIG_IS_ENABLED(CMD_NET) int ret; const char *cpuid = env_get("cpuid#"); u8 hash[SHA256_SUM_LEN]; int size = sizeof(hash); u8 mac_addr[6]; /* Only generate a MAC address, if none is set in the environment */ if (env_get("ethaddr")) return; if (!cpuid) { debug("%s: could not retrieve 'cpuid#'\n", __func__); return; } ret = hash_block("sha256", (void *)cpuid, strlen(cpuid), hash, &size); if (ret) { debug("%s: failed to calculate SHA256\n", __func__); return; } /* Copy 6 bytes of the hash to base the MAC address on */ memcpy(mac_addr, hash, 6); /* Make this a valid MAC address and set it */ mac_addr[0] &= 0xfe; /* clear multicast bit */ mac_addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ eth_env_set_enetaddr("ethaddr", mac_addr); #endif }
static ssize_t verify_signature_read_cb(struct archive *archive, void *cookie, const void **buf) { struct signature_archive *state = cookie; char hash[SHA512_DIGEST_STRING_LENGTH]; ssize_t len, expected; if (state->sign_cur_block >= state->sign_block_number) return 0; /* The following works for sign_block_len > 1 */ if (state->sign_cur_block + 1 == state->sign_block_number) expected = state->pkg_size % state->sign_block_len; else expected = state->sign_block_len; len = archive_read_data(state->archive, state->sign_buf, expected); if (len != expected) { warnx("Short read from package"); return -1; } hash_block(state->sign_buf, len, hash); if (strcmp(hash, state->sign_blocks[state->sign_cur_block]) != 0) { warnx("Invalid signature of block %llu", (unsigned long long)state->sign_cur_block); return -1; } ++state->sign_cur_block; *buf = state->sign_buf; return len; }
/* * Computes 256 bit Key exchange key as specified in RFC 4357 */ static int make_cp_exchange_key(BIGNUM *priv_key, EVP_PKEY *pubk, unsigned char *shared_key) { unsigned char dh_key[128]; int ret; gost_hash_ctx hash_ctx; DH *dh = DH_new(); if (!dh) return 0; memset(dh_key, 0, 128); dh->g = BN_dup(pubk->pkey.dsa->g); dh->p = BN_dup(pubk->pkey.dsa->p); dh->priv_key = BN_dup(priv_key); ret = compute_pair_key_le(dh_key, ((DSA *)(EVP_PKEY_get0(pubk)))->pub_key, dh); DH_free(dh); if (!ret) return 0; init_gost_hash_ctx(&hash_ctx, &GostR3411_94_CryptoProParamSet); start_hash(&hash_ctx); hash_block(&hash_ctx, dh_key, 128); finish_hash(&hash_ctx, shared_key); done_gost_hash_ctx(&hash_ctx); return 1; }
/* Inserts a block in the hash table */ void insert_hash(block_node *b) { int i; i = hash_block(b->block); //pthread_mutex_lock(&hash_mutex); ht[i].active = ht[i].active | (unsigned char)0xFF; /* Uuuu....deep magic...I wonder what this does... */ insert_list(&(ht[i].list), b); //pthread_mutex_unlock(&hash_mutex); }
void remove_hash(uint32_t block) { int i; i = hash_block(block); //pthread_mutex_lock(&hash_mutex); remove_list(&(ht[i].list), block); if(ht[i].list == NULL) ht[i].active = ht[i].active & (unsigned char)0x00; /* Uuuu....deep magic...I wonder what this does... */ //pthread_mutex_unlock(&hash_mutex); }
/* Implementation of CryptoPro VKO 34.10-2001 algorithm */ static int VKO_compute_key (unsigned char *shared_key, size_t shared_key_size, const EC_POINT * pub_key, EC_KEY * priv_key, const unsigned char *ukm) { unsigned char ukm_be[8], databuf[64], hashbuf[64]; BIGNUM *UKM = NULL, *p = NULL, *order = NULL, *X = NULL, *Y = NULL; const BIGNUM *key = EC_KEY_get0_private_key (priv_key); EC_POINT *pnt = EC_POINT_new (EC_KEY_get0_group (priv_key)); int i; gost_hash_ctx hash_ctx; BN_CTX *ctx = BN_CTX_new (); for (i = 0; i < 8; i++) { ukm_be[7 - i] = ukm[i]; } BN_CTX_start (ctx); UKM = getbnfrombuf (ukm_be, 8); p = BN_CTX_get (ctx); order = BN_CTX_get (ctx); X = BN_CTX_get (ctx); Y = BN_CTX_get (ctx); EC_GROUP_get_order (EC_KEY_get0_group (priv_key), order, ctx); BN_mod_mul (p, key, UKM, order, ctx); EC_POINT_mul (EC_KEY_get0_group (priv_key), pnt, NULL, pub_key, p, ctx); EC_POINT_get_affine_coordinates_GFp (EC_KEY_get0_group (priv_key), pnt, X, Y, ctx); /*Serialize elliptic curve point same way as we do it when saving * key */ store_bignum (Y, databuf, 32); store_bignum (X, databuf + 32, 32); /* And reverse byte order of whole buffer */ for (i = 0; i < 64; i++) { hashbuf[63 - i] = databuf[i]; } init_gost_hash_ctx (&hash_ctx, &GostR3411_94_CryptoProParamSet); start_hash (&hash_ctx); hash_block (&hash_ctx, hashbuf, 64); finish_hash (&hash_ctx, shared_key); done_gost_hash_ctx (&hash_ctx); BN_free (UKM); BN_CTX_end (ctx); BN_CTX_free (ctx); EC_POINT_free (pnt); return 32; }
static int passwd_abort(uint64_t etime) { const char *sha_env_str = getenv("bootstopkeysha256"); u8 sha_env[SHA256_SUM_LEN]; u8 sha[SHA256_SUM_LEN]; char presskey[MAX_DELAY_STOP_STR]; const char *algo_name = "sha256"; u_int presskey_len = 0; int abort = 0; int size; int ret; if (sha_env_str == NULL) sha_env_str = CONFIG_AUTOBOOT_STOP_STR_SHA256; /* * Generate the binary value from the environment hash value * so that we can compare this value with the computed hash * from the user input */ ret = hash_parse_string(algo_name, sha_env_str, sha_env); if (ret) { printf("Hash %s not supported!\n", algo_name); return 0; } /* * We don't know how long the stop-string is, so we need to * generate the sha256 hash upon each input character and * compare the value with the one saved in the environment */ do { if (tstc()) { /* Check for input string overflow */ if (presskey_len >= MAX_DELAY_STOP_STR) return 0; presskey[presskey_len++] = getc(); /* Calculate sha256 upon each new char */ hash_block(algo_name, (const void *)presskey, presskey_len, sha, &size); /* And check if sha matches saved value in env */ if (slow_equals(sha, sha_env, SHA256_SUM_LEN)) abort = 1; } } while (!abort && get_ticks() <= etime); return abort; }
std::string hash_rom(HashFunc * hf, boost::filesystem::path path) { std::streampos size; boost::filesystem::path ext; std::ifstream file (path.string(), std::ios::binary | std::ios::ate); if (file.is_open()) { size = file.tellg(); ext = path.extension(); switch (decoders[ext.string()]) { case DEC_BINARY: return hash_file(hf, file, 0); case DEC_SNES: if (size % 1024 == 512) return hash_file(hf, file, 512); else return hash_file(hf, file, 0); break; case DEC_MGD: return hash_block(hf, file, (size_t)size, deinterleave); case DEC_SMD: return hash_block(hf, file, 16384, deinterleave); case DEC_LNX: return hash_file(hf, file, 64); case DEC_N64: return hash_n64(hf, file); case DEC_NES: return hash_nes(hf, file); case DEC_NOT_DEF: return ""; } file.close(); } return ""; }
int hash_blocks(const EVP_MD *md, const unsigned char *in, size_t in_size, unsigned char *out, size_t *out_size, const unsigned char *salt, size_t salt_size, size_t block_size) { size_t s; *out_size = 0; for (size_t i = 0; i < in_size; i += block_size) { hash_block(md, in + i, block_size, salt, salt_size, out, &s); out += s; *out_size += s; } return 0; }
int hash_stream(gost_hash_ctx * ctx, int fd, char *sum) { unsigned char buffer[BUF_SIZE]; ssize_t bytes; int i; start_hash(ctx); while ((bytes = read(fd, buffer, BUF_SIZE)) > 0) { hash_block(ctx, buffer, bytes); } if (bytes < 0) { return 0; } finish_hash(ctx, buffer); for (i = 0; i < 32; i++) { sprintf(sum + 2 * i, "%02x", buffer[31 - i]); } return 1; }
std::string hash_n64(HashFunc * hf, std::ifstream& file) { char * b = new char [4]; void (*swap)(char*, unsigned int); file.seekg (0, std::ios::beg); file.read (b, 4); unsigned char* header = reinterpret_cast<unsigned char*>(b); if (header[0] == 0x80) { swap = &z_swap; } else if (header[3] == 0x80) { swap = &n_swap; } else { swap = NULL; } delete[] b; return hash_block(hf, file, 16384, swap); }
void pkg_sign_gpg(const char *name, const char *output) { struct archive *pkg; struct archive_entry *entry, *hash_entry, *sign_entry; int fd; struct stat sb; char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH]; unsigned char block[65536]; off_t i, size; size_t block_len, signature_len; if ((fd = open(name, O_RDONLY)) == -1) err(EXIT_FAILURE, "Cannot open binary package %s", name); if (fstat(fd, &sb) == -1) err(EXIT_FAILURE, "Cannot stat %s", name); entry = archive_entry_new(); archive_entry_copy_stat(entry, &sb); pkgname = extract_pkgname(fd); hash_file = xasprintf(hash_template, pkgname, (long long)archive_entry_size(entry)); free(pkgname); for (i = 0; i < archive_entry_size(entry); i += block_len) { if (i + (off_t)sizeof(block) < archive_entry_size(entry)) block_len = sizeof(block); else block_len = archive_entry_size(entry) % sizeof(block); if (read(fd, block, block_len) != (ssize_t)block_len) err(2, "short read"); hash_block(block, block_len, hash); tmp = xasprintf("%s%s\n", hash_file, hash); free(hash_file); hash_file = tmp; } tmp = xasprintf("%s%s", hash_file, hash_trailer); free(hash_file); hash_file = tmp; if (detached_gpg_sign(hash_file, strlen(hash_file), &signature_file, &signature_len, gpg_keyring_sign, gpg_sign_as)) err(EXIT_FAILURE, "Cannot sign hash file"); lseek(fd, 0, SEEK_SET); sign_entry = archive_entry_clone(entry); hash_entry = archive_entry_clone(entry); pkgname = strrchr(name, '/'); archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name); archive_entry_set_pathname(hash_entry, HASH_FNAME); archive_entry_set_pathname(sign_entry, GPG_SIGNATURE_FNAME); archive_entry_set_size(hash_entry, strlen(hash_file)); archive_entry_set_size(sign_entry, signature_len); pkg = archive_write_new(); archive_write_set_compression_none(pkg); archive_write_set_format_ar_bsd(pkg); archive_write_open_filename(pkg, output); archive_write_header(pkg, hash_entry); archive_write_data(pkg, hash_file, strlen(hash_file)); archive_write_finish_entry(pkg); archive_entry_free(hash_entry); archive_write_header(pkg, sign_entry); archive_write_data(pkg, signature_file, signature_len); archive_write_finish_entry(pkg); archive_entry_free(sign_entry); size = archive_entry_size(entry); archive_write_header(pkg, entry); for (i = 0; i < size; i += block_len) { if (i + (off_t)sizeof(block) < size) block_len = sizeof(block); else block_len = size % sizeof(block); if (read(fd, block, block_len) != (ssize_t)block_len) err(2, "short read"); archive_write_data(pkg, block, block_len); } archive_write_finish_entry(pkg); archive_entry_free(entry); archive_write_finish(pkg); close(fd); exit(0); }
int main(int argc, char* argv[]) { Options* args = arg_parse(argc, argv); int matches = 0; float time = 0; if(args == NULL) { fprintf(stderr, "usage: %s [-d] buffers outer_r inner_r\n", argv[0]); exit(EXIT_FAILURE); } /* we need two buffers for IO and at least one for blocks */ if(args->buffers < 3) { fprintf(stderr, "error: need at least 3 buffers\n"); exit(EXIT_FAILURE); } int block_size = args->buffers - 2; FILE *fp_inner, *fp_outer; /* get a file pointer to inner relation, exit if unable */ if(!e_fopen(args->outer_file, &fp_outer, "r")) { fprintf(stderr, "failed to open %s\n", args->outer_file); exit(EXIT_FAILURE); } if(!e_fopen(args->inner_file, &fp_inner, "r")) { fprintf(stderr, "failed to open %s\n", args->inner_file); exit(EXIT_FAILURE); } /* determine which relation is the outer and setup variables accordingly */ int is_outer_char = is_char_relation(fp_outer); int o_records_pp, i_records_pp; if(is_outer_char) { o_records_pp = CHAR_RECORDS_PP; i_records_pp = GUILD_RECORDS_PP; } else { o_records_pp = GUILD_RECORDS_PP; i_records_pp = CHAR_RECORDS_PP; } #ifdef DO_TIME hrtime_t start, end; start = gethrtime(); #endif Hashtable* htable = hash_init(HASH_SIZE); /* for each block of outer relation, scan inner relation */ while(!feof(fp_outer)) { /* read in a block from outer file, where a block is the number * of available buffers, each page is a buffer and each page can * hold 2 records. */ Page** block = read_block(block_size, fp_outer, is_outer_char); /* hash block for faster comparisions */ hash_block(htable, block, block_size, o_records_pp, is_outer_char); /* scan inner relation */ while(!feof(fp_inner)) { /* read one page into the input buffer */ Page* p = read_page(i_records_pp, fp_inner, !is_outer_char); for(int i = 0; i < i_records_pp; i++) { Character* c = NULL; Guild* g = NULL; Entry* e = NULL; /* we have either a character or guild from outer, so get the one we don't from the hashtable */ if(is_outer_char) { if(!p->g[i]) continue; g = p->g[i]; e = hash_lookup(htable, g->guild_id); } else { if(!p->c[i]) continue; c = p->c[i]; e = hash_lookup(htable, c->guild_id); } /* check all possible matches */ while(e != NULL) { if(is_outer_char) c = (Character*)e->value; else g = (Guild*)e->value; /* compare guild id's for match */ if(g->guild_id == c->guild_id) { matches++; /* output the tuple if -d flag set */ if(args->dflag) { if(is_outer_char) { printf("%d,%s,%d,%d,%d,%s\n", c->guild_id, c->name, c->race, c->class, c->id, g->g_name); } else { printf("%d,%s,%s,%d,%d,%d\n", g->guild_id, g->g_name, c->name, c->race, c->class, c->id); } } } /* using chaining, so get next possible match */ e = e->next; } } /* deallocate page */ free_page(p, i_records_pp, !is_outer_char); }
int main(int argc, char **argv) { byte *strings[] = { "", "a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa", "aaaaaaa", "aaaaaaaa", "aaaaaaaaa", "aaaaaaaaaa", "AHOJ", "\200aaaa", "\200", "\200\200", "\200\200\200", "\200\200\200\200", "\200\200\200\200\200", "kelapS treboR", "Robert Spalek", "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu", "********************************", "****************************************************************", NULL }; int lengths[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 4000, 8000, 16000, 32000, 64000, -1 }; int i; if (argc > 1) alignment = atoi(argv[1]); printf("Alignment set to %d\n", alignment); for (i=0; strings[i]; i++) if (strlen(strings[i]) != str_len(strings[i])) die("Internal str_len() error on string %d", i); printf("%d strings tested OK\n", i); for (i=0; strings[i]; i++) { uns h1, h2; h1 = hash_string(strings[i]); h2 = hash_string_nocase(strings[i]); if (h1 != hash_block(strings[i], str_len(strings[i]))) die("Internal hash_string() error on string %d", i); printf("hash %2d = %08x %08x", i, h1, h2); if (h1 == h2) printf(" upper case?"); printf("\n"); } for (i=0; lengths[i] >= 0; i++) { byte str[lengths[i] + 1 + alignment]; uns count = TEST_TIME / (lengths[i] + 10); uns el1 = 0, el2 = 0, elh = 0, elhn = 0; uns tot1 = 0, tot2 = 0, hash = 0, hashn = 0; uns j; for (j=0; j<count; j++) { random_string(str + alignment, lengths[i]); elapsed_time(); /* Avoid "optimizing" by gcc, since the functions are * attributed PURE. */ tot1 += strlen(str + alignment); el1 += elapsed_time(); tot2 += str_len(str + alignment); el2 += elapsed_time(); hash ^= hash_string(str + alignment); elh += elapsed_time(); hashn ^= hash_string_nocase(str + alignment); elhn += elapsed_time(); } if (tot1 != tot2) die("Internal error during test %d", i); printf("Test %d: strlen = %d, passes = %d, classical = %d usec, speedup = %.4f\n", i, lengths[i], count, el1, (el1 + 0.) / el2); printf("\t\t total hash = %08x/%08x, hash time = %d/%d usec\n", hash, hashn, elh, elhn); } /* printf("test1: %d\n", hash_modify(10000000, 10000000, 99777555)); printf("test1: %d, %d\n", i, hash_modify(i, lengths[i-2], 99777333)); printf("test1: %d, %d\n", i, hash_modify(lengths[i-2], i, 99777333)); printf("test1: %d,%d,%d->%d\n", i, i*3-2, i*i, hash_modify(4587, i*3-2, i*i)); printf("test1: %d\n", hash_modify(lengths[5], 345, i)); */ return 0; }
static unsigned int dataset_hash_hash(const void*h) { return hash_block(h, HASH_SIZE); }
/** * Process an emulated EC command * * @param ec Current emulated EC state * @param req_hdr Pointer to request header * @param req_data Pointer to body of request * @param resp_hdr Pointer to place to put response header * @param resp_data Pointer to place to put response data, if any * @return length of response data, or 0 for no response data, or -1 on error */ static int process_cmd(struct ec_state *ec, struct ec_host_request *req_hdr, const void *req_data, struct ec_host_response *resp_hdr, void *resp_data) { int len; /* TODO([email protected]): Check checksums */ debug("EC command %#0x\n", req_hdr->command); switch (req_hdr->command) { case EC_CMD_HELLO: { const struct ec_params_hello *req = req_data; struct ec_response_hello *resp = resp_data; resp->out_data = req->in_data + 0x01020304; len = sizeof(*resp); break; } case EC_CMD_GET_VERSION: { struct ec_response_get_version *resp = resp_data; strcpy(resp->version_string_ro, "sandbox_ro"); strcpy(resp->version_string_rw, "sandbox_rw"); resp->current_image = ec->current_image; debug("Current image %d\n", resp->current_image); len = sizeof(*resp); break; } case EC_CMD_VBNV_CONTEXT: { const struct ec_params_vbnvcontext *req = req_data; struct ec_response_vbnvcontext *resp = resp_data; switch (req->op) { case EC_VBNV_CONTEXT_OP_READ: memcpy(resp->block, ec->vbnv_context, sizeof(resp->block)); len = sizeof(*resp); break; case EC_VBNV_CONTEXT_OP_WRITE: memcpy(ec->vbnv_context, resp->block, sizeof(resp->block)); len = 0; break; default: printf(" ** Unknown vbnv_context command %#02x\n", req->op); return -1; } break; } case EC_CMD_REBOOT_EC: { const struct ec_params_reboot_ec *req = req_data; printf("Request reboot type %d\n", req->cmd); switch (req->cmd) { case EC_REBOOT_DISABLE_JUMP: len = 0; break; case EC_REBOOT_JUMP_RW: ec->current_image = EC_IMAGE_RW; len = 0; break; default: puts(" ** Unknown type"); return -1; } break; } case EC_CMD_HOST_EVENT_GET_B: { struct ec_response_host_event_mask *resp = resp_data; resp->mask = 0; if (ec->recovery_req) { resp->mask |= EC_HOST_EVENT_MASK( EC_HOST_EVENT_KEYBOARD_RECOVERY); } len = sizeof(*resp); break; } case EC_CMD_VBOOT_HASH: { const struct ec_params_vboot_hash *req = req_data; struct ec_response_vboot_hash *resp = resp_data; struct fmap_entry *entry; int ret, size; entry = &ec->ec_config.region[EC_FLASH_REGION_RW]; switch (req->cmd) { case EC_VBOOT_HASH_RECALC: case EC_VBOOT_HASH_GET: size = SHA256_SUM_LEN; len = get_image_used(ec, entry); ret = hash_block("sha256", ec->flash_data + entry->offset, len, resp->hash_digest, &size); if (ret) { printf(" ** hash_block() failed\n"); return -1; } resp->status = EC_VBOOT_HASH_STATUS_DONE; resp->hash_type = EC_VBOOT_HASH_TYPE_SHA256; resp->digest_size = size; resp->reserved0 = 0; resp->offset = entry->offset; resp->size = len; len = sizeof(*resp); break; default: printf(" ** EC_CMD_VBOOT_HASH: Unknown command %d\n", req->cmd); return -1; } break; } case EC_CMD_FLASH_PROTECT: { const struct ec_params_flash_protect *req = req_data; struct ec_response_flash_protect *resp = resp_data; uint32_t expect = EC_FLASH_PROTECT_ALL_NOW | EC_FLASH_PROTECT_ALL_AT_BOOT; printf("mask=%#x, flags=%#x\n", req->mask, req->flags); if (req->flags == expect || req->flags == 0) { resp->flags = req->flags ? EC_FLASH_PROTECT_ALL_NOW : 0; resp->valid_flags = EC_FLASH_PROTECT_ALL_NOW; resp->writable_flags = 0; len = sizeof(*resp); } else { puts(" ** unexpected flash protect request\n"); return -1; } break; } case EC_CMD_FLASH_REGION_INFO: { const struct ec_params_flash_region_info *req = req_data; struct ec_response_flash_region_info *resp = resp_data; struct fmap_entry *entry; switch (req->region) { case EC_FLASH_REGION_RO: case EC_FLASH_REGION_RW: case EC_FLASH_REGION_WP_RO: entry = &ec->ec_config.region[req->region]; resp->offset = entry->offset; resp->size = entry->length; len = sizeof(*resp); printf("EC flash region %d: offset=%#x, size=%#x\n", req->region, resp->offset, resp->size); break; default: printf("** Unknown flash region %d\n", req->region); return -1; } break; } case EC_CMD_FLASH_ERASE: { const struct ec_params_flash_erase *req = req_data; memset(ec->flash_data + req->offset, ec->ec_config.flash_erase_value, req->size); len = 0; break; } case EC_CMD_FLASH_WRITE: { const struct ec_params_flash_write *req = req_data; memcpy(ec->flash_data + req->offset, req + 1, req->size); len = 0; break; } case EC_CMD_MKBP_STATE: len = cros_ec_keyscan(ec, resp_data); break; case EC_CMD_ENTERING_MODE: len = 0; break; default: printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; } return len; }
int gost_digest_update(EVP_MD_CTX *ctx,const void *data,size_t count) { return hash_block((gost_hash_ctx *)ctx->md_data,data,count); }
int main(int argc, char **argv) { char *data_filename; char *verity_filename; unsigned char *salt = NULL; size_t salt_size = 0; bool sparse = false; size_t block_size = 4096; uint64_t calculate_size = 0; bool verbose = false; while (1) { const static struct option long_options[] = { {"salt-str", required_argument, 0, 'a'}, {"salt-hex", required_argument, 0, 'A'}, {"help", no_argument, 0, 'h'}, {"sparse", no_argument, 0, 'S'}, {"verity-size", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {NULL, 0, 0, 0} }; int c = getopt_long(argc, argv, "a:A:hSs:v", long_options, NULL); if (c < 0) { break; } switch (c) { case 'a': salt_size = strlen(optarg); salt = new unsigned char[salt_size](); if (salt == NULL) { FATAL("failed to allocate memory for salt\n"); } memcpy(salt, optarg, salt_size); break; case 'A': { BIGNUM *bn = NULL; if(!BN_hex2bn(&bn, optarg)) { FATAL("failed to convert salt from hex\n"); } salt_size = BN_num_bytes(bn); salt = new unsigned char[salt_size](); if (salt == NULL) { FATAL("failed to allocate memory for salt\n"); } if((size_t)BN_bn2bin(bn, salt) != salt_size) { FATAL("failed to convert salt to bytes\n"); } } break; case 'h': usage(); return 1; case 'S': sparse = true; break; case 's': { char* endptr; errno = 0; unsigned long long int inSize = strtoull(optarg, &endptr, 0); if (optarg[0] == '\0' || *endptr != '\0' || (errno == ERANGE && inSize == ULLONG_MAX)) { FATAL("invalid value of verity-size\n"); } if (inSize > UINT64_MAX) { FATAL("invalid value of verity-size\n"); } calculate_size = (uint64_t)inSize; } break; case 'v': verbose = true; break; case '?': usage(); return 1; default: abort(); } } argc -= optind; argv += optind; const EVP_MD *md = EVP_sha256(); if (!md) { FATAL("failed to get digest\n"); } size_t hash_size = EVP_MD_size(md); assert(hash_size * 2 < block_size); if (!salt || !salt_size) { salt_size = hash_size; salt = new unsigned char[salt_size]; if (salt == NULL) { FATAL("failed to allocate memory for salt\n"); } int random_fd = open("/dev/urandom", O_RDONLY); if (random_fd < 0) { FATAL("failed to open /dev/urandom\n"); } ssize_t ret = read(random_fd, salt, salt_size); if (ret != (ssize_t)salt_size) { FATAL("failed to read %zu bytes from /dev/urandom: %zd %d\n", salt_size, ret, errno); } close(random_fd); } if (calculate_size) { if (argc != 0) { usage(); return 1; } size_t verity_blocks = 0; size_t level_blocks; int levels = 0; do { level_blocks = verity_tree_blocks(calculate_size, block_size, hash_size, levels); levels++; verity_blocks += level_blocks; } while (level_blocks > 1); printf("%" PRIu64 "\n", (uint64_t)verity_blocks * block_size); return 0; } if (argc != 2) { usage(); return 1; } data_filename = argv[0]; verity_filename = argv[1]; int fd = open(data_filename, O_RDONLY); if (fd < 0) { FATAL("failed to open %s\n", data_filename); } struct sparse_file *file; if (sparse) { file = sparse_file_import(fd, false, false); } else { file = sparse_file_import_auto(fd, false, verbose); } if (!file) { FATAL("failed to read file %s\n", data_filename); } int64_t len = sparse_file_len(file, false, false); if (len % block_size != 0) { FATAL("file size %" PRIu64 " is not a multiple of %zu bytes\n", len, block_size); } int levels = 0; size_t verity_blocks = 0; size_t level_blocks; do { level_blocks = verity_tree_blocks(len, block_size, hash_size, levels); levels++; verity_blocks += level_blocks; } while (level_blocks > 1); unsigned char *verity_tree = new unsigned char[verity_blocks * block_size](); unsigned char **verity_tree_levels = new unsigned char *[levels + 1](); size_t *verity_tree_level_blocks = new size_t[levels](); if (verity_tree == NULL || verity_tree_levels == NULL || verity_tree_level_blocks == NULL) { FATAL("failed to allocate memory for verity tree\n"); } unsigned char *ptr = verity_tree; for (int i = levels - 1; i >= 0; i--) { verity_tree_levels[i] = ptr; verity_tree_level_blocks[i] = verity_tree_blocks(len, block_size, hash_size, i); ptr += verity_tree_level_blocks[i] * block_size; } assert(ptr == verity_tree + verity_blocks * block_size); assert(verity_tree_level_blocks[levels - 1] == 1); unsigned char zero_block_hash[hash_size]; unsigned char zero_block[block_size]; memset(zero_block, 0, block_size); hash_block(md, zero_block, block_size, salt, salt_size, zero_block_hash, NULL); unsigned char root_hash[hash_size]; verity_tree_levels[levels] = root_hash; struct sparse_hash_ctx ctx; ctx.hashes = verity_tree_levels[0]; ctx.salt = salt; ctx.salt_size = salt_size; ctx.hash_size = hash_size; ctx.block_size = block_size; ctx.zero_block_hash = zero_block_hash; ctx.md = md; sparse_file_callback(file, false, false, hash_chunk, &ctx); sparse_file_destroy(file); close(fd); for (int i = 0; i < levels; i++) { size_t out_size; hash_blocks(md, verity_tree_levels[i], verity_tree_level_blocks[i] * block_size, verity_tree_levels[i + 1], &out_size, salt, salt_size, block_size); if (i < levels - 1) { assert(div_round_up(out_size, block_size) == verity_tree_level_blocks[i + 1]); } else { assert(out_size == hash_size); } } for (size_t i = 0; i < hash_size; i++) { printf("%02x", root_hash[i]); } printf(" "); for (size_t i = 0; i < salt_size; i++) { printf("%02x", salt[i]); } printf("\n"); fd = open(verity_filename, O_WRONLY|O_CREAT, 0666); if (fd < 0) { FATAL("failed to open output file '%s'\n", verity_filename); } write(fd, verity_tree, verity_blocks * block_size); close(fd); delete[] verity_tree_levels; delete[] verity_tree_level_blocks; delete[] verity_tree; delete[] salt; }