617 lines
18 KiB
Python
Executable File
617 lines
18 KiB
Python
Executable File
#!/usr/bin/python3 -B
|
|
|
|
import argparse
|
|
import binascii
|
|
|
|
from Crypto.Cipher import AES
|
|
from Crypto.Hash import SHA256
|
|
from Crypto.PublicKey import RSA
|
|
from Crypto.Signature import PKCS1_v1_5
|
|
from Crypto.Random import new as Random
|
|
|
|
#
|
|
# Global variables
|
|
#
|
|
|
|
global_vars = {}
|
|
|
|
#
|
|
# Functions
|
|
#
|
|
|
|
def modinv(a, m):
|
|
from Crypto.Util.number import inverse
|
|
return inverse(a, m)
|
|
|
|
def load_vars_from_file(var_filename, varname, varsize):
|
|
global_vars[varname] = None
|
|
if vars(args)[var_filename] is not None:
|
|
with open(vars(args)[var_filename], 'rb') as f:
|
|
ba_var = f.read()
|
|
assert len(ba_var) == varsize
|
|
global_vars[varname] = ba_var
|
|
|
|
#
|
|
# Classes
|
|
#
|
|
|
|
class _Util:
|
|
def genDUID(usage):
|
|
duid_full = SHA256.new(usage).digest()
|
|
duid = duid_full[:16]
|
|
duid_ext = duid_full[16:]
|
|
return (duid, duid_ext)
|
|
|
|
class CommonHeader:
|
|
def __init__(self, ba_name):
|
|
magic = SHA256.new(ba_name).digest()
|
|
self.__magic64 = b'@ML ' + magic[:4]
|
|
#print(binascii.hexlify(self.__magic64))
|
|
|
|
self.setVersion(0, 0)
|
|
self.setFlags(0)
|
|
self.setLength(0)
|
|
|
|
def setVersion(self, major, minor):
|
|
assert major.bit_length() <= 8
|
|
assert minor.bit_length() <= 8
|
|
self.__version = major.to_bytes(1, byteorder='little')
|
|
self.__version += minor.to_bytes(1, byteorder='little')
|
|
|
|
def setFlags(self, flags):
|
|
assert flags.bit_length() <= 16
|
|
self.__flags = flags
|
|
|
|
def setLength(self, length):
|
|
assert length.bit_length() <= 32
|
|
self.__length = length
|
|
|
|
def packData(self):
|
|
data = b''
|
|
data += self.__magic64
|
|
data += self.__version
|
|
data += self.__flags.to_bytes(2, byteorder='little')
|
|
data += self.__length.to_bytes(4, byteorder='little')
|
|
return data
|
|
|
|
""" Data Structure: Public RSA Key """
|
|
class DSPubRSAKey:
|
|
def __init__(self, pem_file):
|
|
self.__rsakey = None
|
|
|
|
# Common Header
|
|
self.__cmn_hdr = CommonHeader(b'AML: PUBLIC RSA KEY')
|
|
self.__cmn_hdr.setVersion(0, 0)
|
|
self.__cmn_hdr.setFlags(0)
|
|
|
|
""" Load RSA key from PEM file """
|
|
if pem_file is not None:
|
|
f_rsakey = open(pem_file)
|
|
self.__rsakey = RSA.importKey(f_rsakey.read())
|
|
self.__nbits_rsakey = self.__rsakey.n.bit_length()
|
|
|
|
while True:
|
|
if self.__nbits_rsakey == 2048:
|
|
break
|
|
|
|
if self.__nbits_rsakey == 4096:
|
|
break
|
|
|
|
assert False, "RSA Key must be 2048-bit or 4096-bit"
|
|
|
|
f_rsakey.close();
|
|
|
|
self.__prepare_pubrsa_keydata()
|
|
|
|
return
|
|
|
|
def __prepare_pubrsa_keydata(self):
|
|
""" Preparation """
|
|
# Modulus: N
|
|
self.__nbytes_rsakey = self.__nbits_rsakey//8
|
|
self.__ba_rsakey_n = self.__rsakey.n.to_bytes(self.__nbytes_rsakey,
|
|
byteorder='little')
|
|
self.__ba_rsakey_n += b'\x00' * (512 - len(self.__ba_rsakey_n))
|
|
#print(binascii.hexlify(self.__ba_rsakey_n))
|
|
|
|
# Exponent: E
|
|
self.__ebits_rsakey = self.__rsakey.e.bit_length()
|
|
assert self.__ebits_rsakey <= 32
|
|
self.__ba_rsakey_e = self.__rsakey.e.to_bytes(4, byteorder='little')
|
|
#print(binascii.hexlify(self.__ba_rsakey_e))
|
|
|
|
# Reserved
|
|
self.__ba_reserved = b'\x00' *8
|
|
|
|
# RR: R*R mod N
|
|
rr = pow(2, self.__nbits_rsakey*2, self.__rsakey.n)
|
|
rinv = modinv(2**self.__nbits_rsakey, self.__rsakey.n)
|
|
assert rr*rinv*rinv % self.__rsakey.n == 1
|
|
self.__ba_rr = rr.to_bytes(self.__nbytes_rsakey, byteorder='little')
|
|
self.__ba_rr += b'\x00' * (512 - len(self.__ba_rr))
|
|
#print('0x{:x}'.format(rr))
|
|
#print(binascii.hexlify(self.__ba_rr))
|
|
|
|
# Ninv: -(N^-1) % 2^128
|
|
ninv = modinv(self.__rsakey.n, 2**self.__nbits_rsakey)
|
|
ninv = 2**self.__nbits_rsakey - ninv
|
|
assert ((ninv*self.__rsakey.n+1) % 2**self.__nbits_rsakey) == 0
|
|
|
|
ba_ninv = ninv.to_bytes(self.__nbytes_rsakey, byteorder='little')
|
|
self.__ba_ninv128 = ba_ninv[:(128//8)]
|
|
ninv128 = int.from_bytes(self.__ba_ninv128, byteorder='little')
|
|
assert (ninv128*(self.__rsakey.n % (2**128)) + 1) % (2**128) == 0
|
|
|
|
def getRSAKey(self):
|
|
return self.__rsakey
|
|
|
|
def __packData(self):
|
|
data = b''
|
|
|
|
data += self.__cmn_hdr.packData()
|
|
|
|
data += (self.__nbytes_rsakey//4).to_bytes(4, byteorder='little')
|
|
data += self.__ba_rsakey_e
|
|
data += self.__ba_reserved
|
|
data += self.__ba_rsakey_n
|
|
data += self.__ba_rr
|
|
data += self.__ba_ninv128
|
|
|
|
return data
|
|
|
|
def packData(self):
|
|
if self.__rsakey is None:
|
|
return b'\0' * 1072
|
|
|
|
length = len(self.__packData())
|
|
#print(length)
|
|
assert length == 1072
|
|
|
|
self.__cmn_hdr.setLength(length)
|
|
return self.__packData()
|
|
|
|
class DSRootCert:
|
|
def __init__(self):
|
|
self.__aeskey = None
|
|
|
|
# Common Header
|
|
self.__cmn_hdr = CommonHeader(b'AML: ROOT CERTIFICATE')
|
|
|
|
# DUID
|
|
usage = b'DUID/CERT: SECPU ROOT CERTIFICATE'
|
|
( self.__meta_duid, _ ) = _Util.genDUID(usage + b' - METADATA')
|
|
#print(self.__meta_duid)
|
|
#print(binascii.hexlify(self.__meta_duid))
|
|
|
|
# Tables of Hashes
|
|
self.__tbl_hashes = [ b'\x00' * 32, b'\x00' * 32,
|
|
b'\x00' * 32, b'\x00' * 32 ]
|
|
self.__vld_hashes = [ False, False, False, False ]
|
|
|
|
# EPKs: EPK1_Lo, EPK2_Lo, EPK2_Hi, EPK2_Hi
|
|
self.__epks = [ b'\x00' * 16, b'\x00' * 16,
|
|
b'\x00' * 16, b'\x00' * 16 ]
|
|
|
|
### Associated data of Public RSA Key ###
|
|
self.__idx_rsakey = -1
|
|
self.__ba_reserved = b'\x00' * 31
|
|
|
|
# Random nonce for protecting Public RSA Key
|
|
self.__ba_rnd_nonce = Random().read(16)
|
|
|
|
# Empty buffer for Public RSA Key
|
|
self.__ba_pubrsakey = b'\x00' * 1072
|
|
|
|
### DUID of Root Public RSA Key ###
|
|
( self.__rootrsa_duid, _ ) = _Util.genDUID(usage + b' - ROOT PUBLIC RSA KEY')
|
|
|
|
def setHash(self, idx, ba_key):
|
|
assert len(ba_key) == 1072
|
|
|
|
if ba_key == b'\0' * 1072:
|
|
self.__tbl_hashes[idx] = b'\0' * 32
|
|
self.__vld_hashes[idx] = True
|
|
return
|
|
|
|
""" Compose PubRSA key with associated data """
|
|
buf = idx.to_bytes(1, byteorder='little')
|
|
buf += self.__ba_reserved
|
|
buf += b'\0' * 16
|
|
buf += ba_key
|
|
buf += self.__rootrsa_duid
|
|
assert len(buf) == 1136
|
|
#print(binascii.hexlify(buf))
|
|
|
|
self.__tbl_hashes[idx] = SHA256.new(buf).digest()
|
|
self.__vld_hashes[idx] = True
|
|
|
|
def setPubRSAKey(self, idx, ba_key):
|
|
self.__idx_rsakey = idx
|
|
assert len(self.__ba_pubrsakey) == len(ba_key)
|
|
self.__ba_pubrsakey = ba_key
|
|
|
|
def setAESKey(self, key):
|
|
self.__aeskey = key
|
|
assert len(self.__aeskey) == 16
|
|
|
|
def setEk2PubRSA(self, ek):
|
|
if ek is None:
|
|
return
|
|
|
|
assert len(ek) == 16
|
|
self.__epks[0] = ek
|
|
|
|
def setEk2Loader(self, ek):
|
|
if ek is None:
|
|
return
|
|
|
|
assert len(ek) == 16
|
|
self.__epks[1] = ek
|
|
|
|
def setEk1PubRSA(self, ek):
|
|
if ek is None:
|
|
return
|
|
|
|
assert len(ek) == 16
|
|
self.__epks[2] = ek
|
|
|
|
def setEk1Loader(self, ek):
|
|
if ek is None:
|
|
return
|
|
|
|
assert len(ek) == 16
|
|
self.__epks[3] = ek
|
|
|
|
def setNoncePubRSA(self, nonce):
|
|
if nonce is None:
|
|
return
|
|
|
|
assert len(nonce) == 16
|
|
self.__ba_rnd_nonce = nonce
|
|
|
|
def __packData(self, metaonly=False):
|
|
data = b''
|
|
|
|
# Metadata
|
|
data += self.__cmn_hdr.packData()
|
|
|
|
data += self.__tbl_hashes[0]
|
|
data += self.__tbl_hashes[1]
|
|
data += self.__tbl_hashes[2]
|
|
data += self.__tbl_hashes[3]
|
|
|
|
data += self.__epks[0]
|
|
data += self.__epks[1]
|
|
data += self.__epks[2]
|
|
data += self.__epks[3]
|
|
|
|
# Reserved
|
|
data += b'\0' * 48
|
|
|
|
# DUID of Root Certificate Metadata
|
|
data += self.__meta_duid
|
|
|
|
# Return only Metadata
|
|
if metaonly:
|
|
return data
|
|
|
|
### Public RSA Key and Associated Information ###
|
|
buf = b''
|
|
|
|
buf += self.__idx_rsakey.to_bytes(1, byteorder='little')
|
|
buf += self.__ba_reserved
|
|
|
|
# Fill nonce with 0s for blank PubRSA Key
|
|
assert len(self.__ba_pubrsakey) == 1072
|
|
if self.__ba_pubrsakey == b'\0' * 1072:
|
|
self.__ba_rnd_nonce = b'\0' * 16
|
|
|
|
# Encrypt Public RSA Key with random nonce
|
|
tmpbuf = b''
|
|
tmpbuf += self.__ba_rnd_nonce
|
|
tmpbuf += self.__ba_pubrsakey
|
|
|
|
if self.__aeskey is not None:
|
|
cipher = AES.new(self.__aeskey, AES.MODE_CBC, b'\x00' * 16)
|
|
tmpbuf = cipher.encrypt(tmpbuf)
|
|
|
|
buf += tmpbuf
|
|
|
|
# DUID of Root Public RSA Key
|
|
buf += self.__rootrsa_duid
|
|
|
|
|
|
data += buf
|
|
|
|
return data
|
|
|
|
def packData(self):
|
|
assert self.__vld_hashes[0]
|
|
assert self.__vld_hashes[1]
|
|
assert self.__vld_hashes[2]
|
|
assert self.__vld_hashes[3]
|
|
|
|
assert self.__idx_rsakey >= 0
|
|
assert self.__idx_rsakey <= 3
|
|
|
|
length = len(self.__packData())
|
|
#print(length)
|
|
assert length == 1408
|
|
|
|
self.__cmn_hdr.setLength(length)
|
|
return self.__packData()
|
|
|
|
def getHashLock(self):
|
|
data = self.__packData(True)
|
|
#print(len(data))
|
|
#print(binascii.hexlify(data))
|
|
|
|
return SHA256.new(data).digest()
|
|
|
|
""" Data: SECPU Loader """
|
|
class DataSECPULoader:
|
|
def __init__(self, loader_file):
|
|
self.__aeskey = None
|
|
self.__sig_loader = None
|
|
|
|
### Controlling Data of SECPU Loader
|
|
self.__seg_id = None
|
|
self.__mask_segid = 0xFFFFFFFF;
|
|
self.__arb_vers = None
|
|
self.__mask_arbvers = 0xFFFFFFFF;
|
|
|
|
### DUID of SECPU Loader ###
|
|
( self.__loader_duid, _ ) = _Util.genDUID(b'DUID/BLOB: SECPU LOADER')
|
|
#print(binascii.hexlify(self.__loader_duid))
|
|
|
|
""" Read file and do sanity check"""
|
|
f_loader = open(loader_file, 'rb')
|
|
self.__ba_loader = f_loader.read()
|
|
len_loader = len(self.__ba_loader)
|
|
|
|
while True:
|
|
if len_loader == (28*1024):
|
|
break;
|
|
|
|
if len_loader == (60*1024):
|
|
break;
|
|
|
|
if len_loader == (76*1024):
|
|
break;
|
|
|
|
if len_loader == (92*1024):
|
|
break;
|
|
|
|
assert False, "Length of Loader file must be 28 KiB, 60 KiB, 76 KiB or 92 KiB"
|
|
f_loader.close()
|
|
|
|
def setAESKey(self, key):
|
|
self.__aeskey = key
|
|
assert len(self.__aeskey) == 16
|
|
|
|
def setSegID(self, seg_id):
|
|
if seg_id is None:
|
|
return
|
|
|
|
assert isinstance(seg_id, int)
|
|
assert seg_id.bit_length() <= 32
|
|
self.__seg_id = seg_id;
|
|
|
|
def setArbVers(self,arb_vers):
|
|
if arb_vers is None:
|
|
return
|
|
|
|
assert isinstance(arb_vers, int)
|
|
assert arb_vers.bit_length() <= 32
|
|
self.__arb_vers = arb_vers
|
|
|
|
def updateCtrlData(self):
|
|
# Not inject DUID and controlling data if bot SegID and ArbVers are None
|
|
if self.__seg_id is None and self.__arb_vers is None:
|
|
return
|
|
|
|
# Inject DUID and controlling data
|
|
buf = b''
|
|
buf += self.__loader_duid
|
|
buf += self.__seg_id.to_bytes(4, byteorder='little')
|
|
buf += self.__mask_segid.to_bytes(4, byteorder='little')
|
|
buf += self.__arb_vers.to_bytes(4, byteorder='little')
|
|
buf += self.__mask_arbvers.to_bytes(4, byteorder='little')
|
|
assert len(buf) == 32
|
|
|
|
sz_loader = len(self.__ba_loader)
|
|
self.__ba_loader = self.__ba_loader[:-32] + buf
|
|
assert sz_loader == len(self.__ba_loader)
|
|
|
|
def genSig(self, rsakey):
|
|
hash_loader = SHA256.new(self.__ba_loader)
|
|
#print(hash_loader.hexdigest())
|
|
|
|
self.__sig_loader = PKCS1_v1_5.new(rsakey).sign(hash_loader)
|
|
|
|
#self.__sig_loader = b'\x00' + self.__sig_loader[1:]
|
|
#self.__sig_loader = b'd' + self.__sig_loader[1:]
|
|
assert PKCS1_v1_5.new(rsakey).verify(hash_loader, self.__sig_loader)
|
|
|
|
def packLoader(self):
|
|
data = self.__ba_loader
|
|
|
|
if self.__aeskey is not None:
|
|
cipher = AES.new(self.__aeskey, AES.MODE_CBC, b'\x00' * 16)
|
|
data = cipher.encrypt(data)
|
|
|
|
return data
|
|
|
|
def packSig(self):
|
|
if self.__sig_loader is None:
|
|
return b'\0' * 512
|
|
|
|
data = self.__sig_loader
|
|
data += b'\x00' * (512 - len(data))
|
|
return data
|
|
|
|
#
|
|
# Main
|
|
#
|
|
|
|
""" Parse arguments """
|
|
parser = argparse.ArgumentParser(description='Generate SECPU Loader Image')
|
|
|
|
parser.add_argument('--aes128-keyfile-pubrsa', dest='aes128-keyfile-pubrsa')
|
|
parser.add_argument('--aes128-keyfile-loader', dest='aes128-keyfile-loader')
|
|
|
|
parser.add_argument('--ek2file-pubrsa', dest='ek2file-pubrsa')
|
|
parser.add_argument('--ek2file-loader', dest='ek2file-loader')
|
|
parser.add_argument('--ek1file-pubrsa', dest='ek1file-pubrsa')
|
|
parser.add_argument('--ek1file-loader', dest='ek1file-loader')
|
|
|
|
parser.add_argument('--noncefile-pubrsa', dest='noncefile-pubrsa')
|
|
|
|
parser.add_argument('--seg-id', dest='seg-id')
|
|
parser.add_argument('--arb-vers', dest='arb-vers')
|
|
|
|
parser.add_argument('--rootrsa-priv-key', dest='rootrsa-priv-key', required=False)
|
|
parser.add_argument('--rootrsa-idx', dest='rootrsa-idx', required=False, default=0)
|
|
parser.add_argument('--rootrsa-key-0', dest='rootrsa-key-0', required=False)
|
|
parser.add_argument('--rootrsa-key-1', dest='rootrsa-key-1', required=False)
|
|
parser.add_argument('--rootrsa-key-2', dest='rootrsa-key-2', required=False)
|
|
parser.add_argument('--rootrsa-key-3', dest='rootrsa-key-3', required=False)
|
|
parser.add_argument('--output', dest='output-file', required=True)
|
|
parser.add_argument('--out-hash', dest='output-hash-file')
|
|
parser.add_argument('LOADER_FILE', help='SECPU Loader')
|
|
|
|
args = parser.parse_args()
|
|
|
|
rootrsa_idx = int(vars(args)['rootrsa-idx'])
|
|
assert 0 <= rootrsa_idx and rootrsa_idx <= 3
|
|
|
|
""" AES Key for PubRSA """
|
|
if vars(args)['aes128-keyfile-pubrsa'] is not None:
|
|
f_key = open(vars(args)['aes128-keyfile-pubrsa'], 'rb')
|
|
ba_key_pubrsa = f_key.read()
|
|
assert len(ba_key_pubrsa) == 16
|
|
f_key.close()
|
|
else:
|
|
ba_key_pubrsa = None
|
|
|
|
""" AES Key for Loader """
|
|
if vars(args)['aes128-keyfile-loader'] is not None:
|
|
f_key = open(vars(args)['aes128-keyfile-loader'], 'rb')
|
|
ba_key_loader = f_key.read()
|
|
assert len(ba_key_loader) == 16
|
|
f_key.close()
|
|
else:
|
|
ba_key_loader = None
|
|
|
|
""" EKs """
|
|
load_vars_from_file('ek2file-pubrsa', 'ek2-pubrsa', 16)
|
|
load_vars_from_file('ek2file-loader', 'ek2-loader', 16)
|
|
load_vars_from_file('ek1file-pubrsa', 'ek1-pubrsa', 16)
|
|
load_vars_from_file('ek1file-loader', 'ek1-loader', 16)
|
|
|
|
""" Nonce for protecting PubRSA """
|
|
load_vars_from_file('noncefile-pubrsa', 'nonce-pubrsa', 16)
|
|
|
|
""" Controlling Data """
|
|
global_vars['seg-id'] = None
|
|
strval = vars(args)['seg-id']
|
|
if strval is not None:
|
|
val = int(strval, 0)
|
|
assert val.bit_length() <= 32
|
|
global_vars['seg-id'] = val
|
|
|
|
global_vars['arb-vers'] = None
|
|
strval = vars(args)['arb-vers']
|
|
if strval is not None:
|
|
val = int(strval, 0)
|
|
assert val.bit_length() <= 32
|
|
global_vars['arb-vers'] = val
|
|
|
|
""" Private RSA Key """
|
|
if vars(args)['rootrsa-priv-key'] is not None:
|
|
with open(vars(args)['rootrsa-priv-key'], 'r') as f_privkey:
|
|
obj_priv_rsakey = RSA.importKey(f_privkey.read())
|
|
assert obj_priv_rsakey.has_private() is True
|
|
else:
|
|
obj_priv_rsakey = None
|
|
|
|
""" Public RSA Key """
|
|
tbl_ds_pubrsakey = [ None, None, None, None]
|
|
tbl_ba_pubrsa = [ None, None, None, None]
|
|
|
|
for i in range(4):
|
|
tbl_ds_pubrsakey[i] = DSPubRSAKey(vars(args)['rootrsa-key-' + str(i)])
|
|
tbl_ba_pubrsa[i] = tbl_ds_pubrsakey[i].packData()
|
|
#print(binascii.hexlify(tbl_ba_pubrsa[0]))
|
|
|
|
""" Load SECPU Loader """
|
|
secpu_loader = DataSECPULoader(args.LOADER_FILE)
|
|
if ba_key_loader is not None:
|
|
secpu_loader.setAESKey(ba_key_loader)
|
|
|
|
secpu_loader.setSegID(global_vars['seg-id'])
|
|
secpu_loader.setArbVers(global_vars['arb-vers'])
|
|
secpu_loader.updateCtrlData()
|
|
|
|
""" Generate RSA Signature """
|
|
if obj_priv_rsakey is not None:
|
|
obj_pub_rsakey = tbl_ds_pubrsakey[rootrsa_idx].getRSAKey()
|
|
assert obj_pub_rsakey.n == obj_priv_rsakey.n
|
|
assert obj_pub_rsakey.e == obj_priv_rsakey.e
|
|
secpu_loader.genSig(obj_priv_rsakey)
|
|
|
|
""" Root Certificate """
|
|
ds_rootcert = DSRootCert()
|
|
if ba_key_pubrsa is not None:
|
|
ds_rootcert.setAESKey(ba_key_pubrsa)
|
|
|
|
for i in range(4):
|
|
ds_rootcert.setHash(i, tbl_ba_pubrsa[i])
|
|
|
|
ds_rootcert.setPubRSAKey(rootrsa_idx, tbl_ba_pubrsa[rootrsa_idx])
|
|
|
|
ds_rootcert.setEk2PubRSA(global_vars['ek2-pubrsa'])
|
|
ds_rootcert.setEk2Loader(global_vars['ek2-loader'])
|
|
ds_rootcert.setEk1PubRSA(global_vars['ek1-pubrsa'])
|
|
ds_rootcert.setEk1Loader(global_vars['ek1-loader'])
|
|
|
|
ds_rootcert.setNoncePubRSA(global_vars['nonce-pubrsa'])
|
|
|
|
ba_rootcert = ds_rootcert.packData()
|
|
ba_hashlock = ds_rootcert.getHashLock()
|
|
#print(binascii.hexlify(ba_rootcert))
|
|
|
|
print("SHA256 for OTP Hash-Lock:")
|
|
print(binascii.hexlify(ba_hashlock).decode('UTF-8'))
|
|
|
|
fname_hash = vars(args)['output-hash-file']
|
|
if fname_hash is not None:
|
|
f_hash = open(fname_hash, 'wb')
|
|
f_hash.write(ba_hashlock)
|
|
f_hash.close()
|
|
|
|
#
|
|
# Pack SECPU Loader Image
|
|
#
|
|
|
|
ba_sig = secpu_loader.packSig()
|
|
ba_loader = secpu_loader.packLoader()
|
|
|
|
buf = ba_rootcert
|
|
buf += (4096 - 32 - len(ba_sig) - len(buf)) * b'\x00'
|
|
buf += ba_sig
|
|
assert len(buf) == (4096 - 32)
|
|
|
|
buf += ba_loader
|
|
|
|
chksum = SHA256.new(buf).digest()
|
|
buf = chksum + buf
|
|
#print(len(buf))
|
|
#print(binascii.hexlify(buf))
|
|
|
|
f_img = open(vars(args)['output-file'], "wb")
|
|
f_img.write(buf)
|
|
f_img.close()
|
|
|
|
# vim: set expandtab ai tabstop=4 shiftwidth=4 softtabstop=-1:
|