#!/usr/bin/env python3 """ Created by: Wonder Gumise & Ahmad MK Nasser Date created: 20/03/2019 Version: 1.0.1 Date last modified 15/04/2019 Python Version: 3.3 py-crypto Version: 2.6.1 """ from pprint import pprint from Crypto.Cipher import AES import drbg import CMAC import os import sys import hexfile import binascii def GetBlockListOfSampleAddresses(size, sample_size, seed, start_addr): #Block sampling for each address '''Generate of `size` randomly sampled address blocks using the given `seed` :param size: The size of the data image in bytes :param sample_size: The percentage of the data image being sampled :param seed: A 32 byte seed of type bytes for use by the AES CTR DRBG generator :param start_addr: The start address of the hex image ''' cipher = drbg.CTRDRBG('aes128' , seed) #AES CTR DRBG object for use in generating the addresses rnd_addr_list = [] mask = (size >> 16) - 1 #create a mask to later limit the address range sample_size = int(size*(sample_size/100)) #convert sample size as a percentage to bytes block_size = int(sample_size/16) #convert sample size to blocks for _ in range(block_size): buffer = cipher._generate(3) #create a range limited hex address from the generated bytes corresponding to the size of the hex image address = ((int(buffer[2]) & mask)<<16 | int(buffer[1])<<8 | (int(buffer[0]) & 0xF0)) address = address + start_addr for j in range(16): rnd_addr_list.append(address+j) #print(rnd_addr_list) return rnd_addr_list #sorted(rnd_addr_list) def GetOnePerBlockListOfSampleAddresses(size, seed, start_addr): #Byte sampling for each address '''Generate of one randomly sampled address for every block in the hex image using the given `seed` :param size: The size of the data image in bytes :param seed: A 32 byte seed of type bytes for use by the AES CTR DRBG generator :param start_addr: The start address of the hex file ''' cipher = drbg.CTRDRBG('aes128' , seed) #AES CTR DRBG object for use in generating the addresses rnd_addr_list = [] size = (int(size/16)) #convert size to blocks for _ in range(int(size/2)): offset_b = cipher._generate(1) ##offset = int.from_bytes(offset_b, byteorder='big') #debug only #print(offset) #debug only address = start_addr + int(offset_b[0] & 0x0F) rnd_addr_list.append(address) start_addr += 16 address = start_addr + ((int(offset_b[0]) & 0xF0) >> 4) rnd_addr_list.append(address) start_addr += 16 return rnd_addr_list def GetTwoPerBlockListOfSampleAddresses(size, seed, start_addr): #Byte sampling for each address '''Generate of two randomly sampled addresses for every block in the hex image using the given `seed` :param size: The size of the data image in bytes :param seed: A 32 byte seed of type bytes for use by the AES CTR DRBG generator :param start_addr: The start address of the hex file ''' cipher = drbg.CTRDRBG('aes128' , seed) #AES CTR DRBG object for use in generating the addresses rnd_addr_list = [] size = (int(size/16)) #fetch size from hexfile for _ in range(size): offset_b = cipher._generate(1) ##offset = int.from_bytes(offset_b, byteorder='big') #debug only #print(offset) #debug only address = start_addr + int(offset_b[0] & 0x0F) rnd_addr_list.append(address) address = start_addr + ((int(offset_b[0]) & 0xF0) >> 4) rnd_addr_list.append(address) start_addr += 16 return rnd_addr_list if __name__ == "__main__": print(' Setup phase:\n') seed = os.urandom(32) seed_str = binascii.hexlify(seed) seed_str = seed_str.decode('utf-8') f_seed = open("Saved_Parameters\seed.txt", 'w') f_seed.write(seed_str) #save seed in file f_seed.close() key = input('Enter key as 16byte hexstring: ') # print(hex(key)) f_key = open("Saved_Parameters\key.txt", 'w') f_key.write(key) #save key in file f_key.close() key = str.encode(key) #convert hex string to hex bytes key = binascii.unhexlify(key) #convert hex bytes to bytes filename = input('Enter filename/relative path of original hexfile: ') #get original hexfile name from user f_hex = hexfile.load(filename) if f_hex.size > 16777216: #max hex file size which can be handled is 16MB since 24bit hex addresses are used print('Error: File size too large') print(' Max compatible hex file size is 16MB') sys.exit(0) info = f_hex.segments info = str(info) #convert hex segments info list to a string info = info[:-2] #remove '>]' from the end of segments info string info = [x for x in info.split() if x.startswith('0x')] #extract hex number from the info string start_addr = int(info[0], 16) #convert the hex number to type int # print(start_addr) #debug only scheme = input('Enter sample boot method: ') #choose sample boot method f_scheme = open("Saved_Parameters\scheme.txt", 'w') f_scheme.write(scheme) #save scheme in file f_scheme.close() if scheme == 'rbs': sample_size = input('Enter sample size as a percentage (1 - 100): ') #choose sample boot method f_sample_size = open("Saved_Parameters\sample_size.txt", 'w') f_sample_size.write(sample_size) #save scheme in file f_sample_size.close() sample_size = int(sample_size) s_addr = GetBlockListOfSampleAddresses(f_hex.size, sample_size, seed, start_addr) elif scheme == 'pbs1': s_addr = GetOnePerBlockListOfSampleAddresses(f_hex.size, seed, start_addr) elif scheme == 'pbs2': s_addr = GetTwoPerBlockListOfSampleAddresses(f_hex.size, seed, start_addr) else: print('Error: Invalid sample boot method') print(' Valid options are: rbs, pbs1 and pbs2') sys.exit(0) s_data = [] for addr in s_addr: data = f_hex[addr] #get data from sampled addresses s_data.append(data) # print(s_data) s_data = bytes(s_data) #convert sampled data to bytes cmac = CMAC.new(key,ciphermod=AES) #create new CMAC object cmac.update(s_data) #calculate cmac tag of sampled data # print(cmac.hexdigest()) f_cmac = open("Saved_Parameters\cmac.txt", 'w') f_cmac.write(cmac.hexdigest()) #save calculated tag in file f_cmac.close() sys.exit(0)