blob: 970d8c0113f9330f4a08e8dbc6d549b8a3b06f1c [file] [log] [blame]
#! /usr/bin/env python
import os
import sys
import math
import hashlib
import binascii
HASH_FUNCTION = "SHA256"
HASH_FUNCTION_SIZE = 32
BLOCK_SIZE = 4096
HASHES_PER_BLOCK = BLOCK_SIZE / HASH_FUNCTION_SIZE
def generate_salt():
return os.urandom(HASH_FUNCTION_SIZE)
def get_hash_image_blocks(data_image_size):
data_image_blocks = data_image_size / BLOCK_SIZE
return data_image_blocks / (HASH_FUNCTION_SIZE * 2)
def get_hash_image_size(data_image_size):
return get_hash_image_blocks(data_image_size) * BLOCK_SIZE
def blockify(data):
blocks = []
for i in range(0, len(data), BLOCK_SIZE):
chunk = data[i:i+BLOCK_SIZE]
blocks.append(chunk)
return blocks
def read_blocks(image_path):
image = open(image_path, "rb").read()
return blockify(image)
def hash_block(data, salt):
hasher = hashlib.new(HASH_FUNCTION)
hasher.update(salt)
hasher.update(data)
return hasher.digest()
def block_align(level):
pad_size = (BLOCK_SIZE - (len(level) % BLOCK_SIZE)) % BLOCK_SIZE
pad = '\x00' * pad_size
return level + pad
def generate_hashes(data_blocks, salt):
levels = []
root_hash = ''
while True:
hashes = [hash_block(b, salt) for b in data_blocks]
if len(hashes) == 1:
root_hash = hashes[0]
break
else:
level = ''.join(hashes)
level = block_align(level)
levels.insert(0, level)
data_blocks = blockify(level)
return root_hash, ''.join(levels)
def write_hashes(hashes, hash_image, hash_image_size):
hashes = hashes.ljust(hash_image_size, '\x00')
with open(hash_image, 'wb+') as hash_file:
hash_file.write(hashes)
def generate_hash_image(data_image, hash_image, hash_image_size, salt):
blocks = read_blocks(data_image)
root_hash, hashes = generate_hashes(blocks, salt)
write_hashes(hashes, hash_image, hash_image_size)
return root_hash
def build_verity_tree(data_image, hash_image, data_image_size):
salt = generate_salt()
hash_image_size = get_hash_image_size(data_image_size)
root_hash = generate_hash_image(data_image, hash_image, hash_image_size, salt)
print binascii.hexlify(root_hash), binascii.hexlify(salt)
if __name__ == "__main__":
if len(sys.argv) == 3 and sys.argv[1] == "-s":
print get_hash_image_size(int(sys.argv[2]))
elif len(sys.argv) == 4:
data_image = sys.argv[1]
hash_image = sys.argv[2]
data_image_size = int(sys.argv[3])
build_verity_tree(data_image, hash_image, data_image_size)
else:
exit(-1)