mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
179 lines
8.3 KiB
Python
Executable File
179 lines
8.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
#
|
||
# Copyright (c) 2001-2020, Arm Limited and Contributors. All rights reserved.
|
||
#
|
||
# SPDX-License-Identifier: BSD-3-Clause OR Arm’s non-OSI source license
|
||
#
|
||
|
||
####################################################################
|
||
# Filename - hbk_gen_util.py
|
||
# Description - This file is responsible for creation of public key
|
||
# HASH and its corresponding number of Zeroes
|
||
# as it should be saved in the OTP/NVM
|
||
####################################################################
|
||
|
||
import optparse
|
||
import sys
|
||
import os
|
||
from utils.common import util_logger
|
||
from utils.common import cryptolayer
|
||
|
||
# Prim key hash file name
|
||
PRIM_KEY_HASH_FILE_NAME = "prim_key_hash.txt"
|
||
ZEROS_NUM_FILES_NAME = "zero_bits_in_hash.txt"
|
||
# Util's log file
|
||
LOG_FILENAME = "gen_hbk_log.log"
|
||
|
||
OUTPUT_SIZE_SHA_256 = 32
|
||
OUTPUT_SIZE_SHA_256_TRUNC = int(OUTPUT_SIZE_SHA_256/2)
|
||
BITS_WITHIN_WORD = 32
|
||
BYTES_WITHIN_WORD = 4
|
||
|
||
|
||
def create_word_list(byte_array, byte_array_word_count, endianness):
|
||
"""
|
||
Creates a hexadecimal (32 bits) word list out of a byte array representation of an input number
|
||
:param byte_array: input number represented as a list of the bytes it consists of
|
||
:param byte_array_word_count: number of (32 bit) words in input array
|
||
:param endianness: output byte order -> little endian 'L' or big endian 'B'
|
||
:return: 32 bit word list
|
||
"""
|
||
word_list = []
|
||
if not isinstance(byte_array, list) or not isinstance(byte_array_word_count, int):
|
||
raise TypeError("input parameter byte_array or byte_array_word_count has wrong type")
|
||
if endianness != 'L' and endianness != 'B':
|
||
raise ValueError("input parameter endianness has wrong value")
|
||
else:
|
||
for i in range(byte_array_word_count):
|
||
if endianness == 'L':
|
||
current_word = byte_array[i * 4]
|
||
current_word = current_word + (byte_array[i * 4 + 1] << 8)
|
||
current_word = current_word + (byte_array[i * 4 + 2] << 16)
|
||
current_word = current_word + (byte_array[i * 4 + 3] << 24)
|
||
else:
|
||
current_word = byte_array[i * 4 + 3]
|
||
current_word = current_word + (byte_array[i * 4 + 2] << 8)
|
||
current_word = current_word + (byte_array[i * 4 + 1] << 16)
|
||
current_word = current_word + (byte_array[i * 4] << 24)
|
||
word_list.append(current_word)
|
||
return word_list
|
||
|
||
|
||
def count_zero_bits_in_bytes(bytes_input, bit_size):
|
||
"""
|
||
Calculate the number of zero bits in a number given in a bytes representation.
|
||
|
||
:param bytes_input: (bytes) input number
|
||
:param bit_size: size of bytes_input in bits
|
||
:return: (int) number of zero bits
|
||
|
||
Returns TypeError if parameter bytes_input is not "bytes"
|
||
Return TypeError if parameter bit_size is not int
|
||
"""
|
||
# converting to str in binary representation - byteorder/endianness is irrelevant for this function
|
||
binary_input = format(int.from_bytes(bytes_input, byteorder="big"), 'b').zfill(bit_size)
|
||
return binary_input.count("0")
|
||
|
||
|
||
class ArgumentParser:
|
||
def __init__(self):
|
||
self.key_filename = None
|
||
self.output_endianness = None
|
||
self.hash_format = None
|
||
self.result_hash_filename = None
|
||
self.result_zeros_filename = None
|
||
self.log_filename = None
|
||
self.parser = optparse.OptionParser()
|
||
self.parser.add_option("-k", "--key", dest="key_filename",
|
||
help="!Mandatory! The name of the PEM file holding the RSA public key")
|
||
self.parser.add_option("-e", "--endian", dest="output_endianness", default="L",
|
||
metavar="END",
|
||
help="Sets the output endianness: END=B for Big Endian or END=L for Little Endian ["
|
||
"default: %default]")
|
||
self.parser.add_option("-f", "--format", dest="hash_format", default="SHA256",
|
||
metavar="HASHMODE",
|
||
help="Sets the hash format: HASHMODE=SHA256 for full SHA-256 hash (Hbk) or "
|
||
"HASHMODE=SHA256_TRUNC for truncated SHA-256 hash (Hbk0 or Hbk1) [default: "
|
||
"%default]")
|
||
self.parser.add_option("-o", "--out-hash", dest="result_hash_filename", default=PRIM_KEY_HASH_FILE_NAME,
|
||
metavar="FILE",
|
||
help="Writes hash result to FILE [default: %default]")
|
||
self.parser.add_option("-z", "--out-zeros", dest="result_zeros_filename", default=ZEROS_NUM_FILES_NAME,
|
||
metavar="FILE",
|
||
help="Writes number of zero bits in the hash result to FILE [default: %default]")
|
||
self.parser.add_option("-l", "--log", dest="log_filename", default=LOG_FILENAME,
|
||
metavar="FILE",
|
||
help="Writes event log to FILE [default: %default]")
|
||
|
||
def parse_arguments(self, args):
|
||
(options, args) = self.parser.parse_args(args)
|
||
if len(args) > 0:
|
||
self.parser.error("incorrect number of positional arguments, use option -h for help")
|
||
|
||
self.key_filename = options.key_filename
|
||
if self.key_filename is None:
|
||
self.parser.error("Option -k must be given, use option -h for help")
|
||
|
||
self.output_endianness = options.output_endianness
|
||
if self.output_endianness is not None and self.output_endianness != "B" and self.output_endianness != "L":
|
||
self.parser.error("Illegal argument for output endianness (option -e)")
|
||
|
||
self.hash_format = options.hash_format
|
||
if self.hash_format is not None and self.hash_format != "SHA256" and self.hash_format != "SHA256_TRUNC":
|
||
self.parser.error("Illegal argument for hash format (option -f)")
|
||
|
||
self.result_hash_filename = options.result_hash_filename
|
||
self.result_zeros_filename = options.result_zeros_filename
|
||
self.log_filename = options.log_filename
|
||
|
||
|
||
class HbkGenerator:
|
||
def __init__(self, argument_parser, logger):
|
||
self.argument_parser = argument_parser
|
||
self.logger = logger
|
||
self.hash_digest = None
|
||
self.hash_word_list = None
|
||
self.zero_bits = None
|
||
|
||
# decide hash output size
|
||
if self.argument_parser.hash_format == "SHA256":
|
||
self.outputSize = OUTPUT_SIZE_SHA_256
|
||
else:
|
||
self.outputSize = OUTPUT_SIZE_SHA_256_TRUNC
|
||
self.output_word_count = self.outputSize // BYTES_WITHIN_WORD
|
||
self.output_bit_count = self.output_word_count * BITS_WITHIN_WORD
|
||
|
||
def generate_hbk(self):
|
||
self.logger.info("Step 1: Calculating hash")
|
||
self.hash_digest = cryptolayer.Common.get_hashed_n_and_np_from_public_key(self.argument_parser.key_filename,
|
||
self.logger)
|
||
self.hash_digest = self.hash_digest[:self.outputSize]
|
||
self.hash_word_list = create_word_list(list(self.hash_digest), self.output_word_count,
|
||
self.argument_parser.output_endianness)
|
||
self.logger.info("Step 2: Calculate num of zero bits over the hash")
|
||
self.zero_bits = count_zero_bits_in_bytes(self.hash_digest, self.output_bit_count)
|
||
|
||
def write_output_files(self):
|
||
hex_list = [format(item, "#08x") for item in self.hash_word_list]
|
||
hash_output_string = ", ".join(hex_list)
|
||
with open(self.argument_parser.result_hash_filename, 'w') as hash_output_file:
|
||
hash_output_file.write(hash_output_string)
|
||
#with open(self.argument_parser.result_zeros_filename, 'w') as zeros_output_file:
|
||
# zeros_output_file.write(hex(self.zero_bits))
|
||
|
||
|
||
def main(args):
|
||
if not (sys.version_info.major == 3 and sys.version_info.minor >= 5):
|
||
print("The script requires Python3.5 or later!")
|
||
sys.exit(-1)
|
||
# parse arguments
|
||
the_argument_parser = ArgumentParser()
|
||
the_argument_parser.parse_arguments(args)
|
||
# get logging up and running
|
||
the_logger = util_logger.UtilLogger(the_argument_parser.log_filename, "HBK Generator")
|
||
# perform main task
|
||
generator = HbkGenerator(the_argument_parser, the_logger)
|
||
generator.generate_hbk()
|
||
generator.write_output_files()
|
||
the_logger.info("Script completed successfully")
|