blob: c38d979181debd4c4cdd745480c047dc59f6d3fb [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001#!/usr/bin/python
2# -*- coding: utf8 -*-
3
4import json
5import struct
6import sys
7import binascii
8import cryptoSB
9import copy
10
11from jsoncomment import JsonComment
12
13__Align = 16
14__Align_16_en = 0
15
16__TEST = 0
17
18g_magic_size = 8
19g_total_len_size = 4
20g_bl_version_size = 4
21g_img_number_size = 4
22g_ls_cmd_number_size = 4
23g_mi_header_info_size = (g_magic_size + g_total_len_size + g_bl_version_size + g_img_number_size + g_ls_cmd_number_size)
24
25g_img_header_size = 96
26g_ls_cmd_size = 8
27
28g_img_oneoffset_table_size = 4
29g_img_onehash_table_size = 64
30
31g_public_key_size = 96
32g_sbc_auth_alg_size = 4
33g_sbc_auth_inf_size = 4
34g_sbc_size = (g_public_key_size + g_sbc_auth_alg_size + g_sbc_auth_inf_size)
35
36g_boot_hash_size = 64
37g_signature_size = 96
38g_auth_size = (g_boot_hash_size + g_signature_size)
39
40def to_int(s):
41 if isinstance(s, (str, unicode)):
42 return int(s, 0)
43 else:
44 return s
45
46def byte_to_int(bytes):
47 result = 0
48
49 for b in bytes:
50 result = result*256 + ord(b)
51
52 return result
53
54def read_desc(mi_desc_fn):
55 #desc = json.load(open(mi_desc_fn))
56
57 parser = JsonComment(json)
58 desc = parser.loads(open(mi_desc_fn).read())
59
60 for img in desc['images']:
61 img['img_enc_alg'] = to_int(img['img_enc_alg'])
62 img['img_enc_inf'] = to_int(img['img_enc_inf'])
63
64 '''0627 remove int assign avoid key start is (0x00..)'''
65 #img['img_iv'] = to_int(img['img_iv'])
66
67 return desc
68
69
70def gen_ver_magic(major, minor, revision):
71 major = to_int(major)
72 minor = to_int(minor)
73 revision = to_int(revision)
74
75 x = major ^ 0xaa
76 y = minor ^ 0x55
77 z = revision ^ 0x99
78 checksum = (x + y + z) & 0xff
79
80 return (major << 0) | (minor << 8) | (revision << 16) | (checksum << 24)
81
82def my_gen_ver_magic(major, minor, revision):
83 major = to_int(major)
84 minor = to_int(minor)
85 revision = to_int(revision)
86
87 x = major ^ 0xaa
88 y = minor ^ 0x55
89 z = revision ^ 0x99
90 checksum = (x + y + z) & 0xff
91
92 highmagic = byte_to_int(b'\x27\x21\xca\xfe')
93 #print(hex(highmagic))
94
95 return (major << 0) | (minor << 8) | (revision << 16) | (checksum << 24), highmagic
96
97def my_gen_mtk_magic(magic):
98 magic_str = my_to_bytes(magic, g_magic_size, endianess='little')
99
100 lowmagic = byte_to_int(magic_str[4:8])
101 highmagic = byte_to_int(magic_str[0:4])
102
103 return lowmagic, highmagic
104
105def pad_to_align(align, current_size):
106 if not align:
107 return ''
108
109 pad_size = (align - current_size % align) % align
110 pad = '\0' * pad_size
111
112 return pad
113
114
115def dump(data):
116 for i in range(0, len(data)):
117 if(i%16 == 0):
118 print("[%04X]" % i),
119
120 print("%02x" % ord(data[i])),
121 if(((i+1)%16) == 0):
122 print
123
124def pack_load_script(mi_desc):
125 ls_script = []
126 reserved = 0
127 images = mi_desc['images']
128 img_num = len(images)
129
130 ls_cmds = mi_desc['load_srcipt_cmd']
131 ls_cmds_num = len(ls_cmds)
132 #print("ls_cmds_num: %d" %ls_cmds_num)
133
134 for i in range(ls_cmds_num):
135 ls_cmd = ls_cmds[i]
136 cmd = ls_cmd['cmd']
137
138 if cmd == "LOAD":
139 cmd_id = 0
140 img_file = ls_cmd['img_file']
141 addr = to_int(ls_cmd['addr'])
142
143 img_id = -1
144 for j in range(img_num):
145 img = images[j]
146 img_binary_name = img['img_file']
147 if img_file == img_binary_name:
148 img_id = j
149 break
150
151 if img_id == -1:
152 print("Please check img file name")
153 return
154
155 packed_cmd = struct.pack('<BBHI', cmd_id, img_id, reserved, addr)
156 #dump(packed_cmd)
157 #print
158 elif cmd == "MCU-ENTRY":
159 cmd_id = 2
160 mcu_id = ls_cmd['mcu_id']
161 addr = to_int(ls_cmd['addr'])
162 packed_cmd = struct.pack('<BBHI', cmd_id, mcu_id, reserved, addr)
163 #dump(packed_cmd)
164 #print
165 elif cmd == "MCU_RESET-ENTRY":
166 cmd_id = 1
167 mcu_id = ls_cmd['mcu_id']
168 addr = to_int(ls_cmd['addr'])
169 packed_cmd = struct.pack('<BBHI', cmd_id, mcu_id, reserved, addr)
170 #dump(packed_cmd)
171 #print
172 else:
173 print("unknown command: %s" %cmd)
174 return
175
176 ls_script += packed_cmd
177
178 #print("load script:")
179 #dump(ls_script)
180
181 return ls_script
182
183
184def my_pack_images(mi_desc, privk, enckey, align=None, img_dir=''):
185 '''
186 mipack_file
187 mi_header_info
188 u32 magic
189 u32 total_len
190 u32 bl_version
191 u32 img_number (N)
192 u32 load_script_cmd_number (M)
193
194 img_info[1]~img_info[N]
195 u32 img_length
196 u32 img_offset
197 64Byes img_hash
198 u32 img_enc_inf
199 u32 img_enc_alg
200 16Bytes img_iv
201
202 load_script_cmd[1]~load_script_cmd[M]
203 u64 cmd
204
205 sbc data
206 96Bytes public_key
207 u32 sbc_auth_inf
208 u32 sbc_auth_alg
209
210 auth data
211 64Bytes boothash
212 96Bytes signature
213
214 [img binary 1]
215 ...
216 [img binary 1]
217 '''
218
219 key_mode = 0
220
221 mi_header_struct = struct.Struct('<IIIIII')
222 sbc_struct = struct.Struct('<II')
223
224 #run hash
225 hash = cryptoSB.HASH()
226
227 # ver_magic
228 #version = mi_desc['version']
229 #major, minor, revision = version.split('.')
230 #ver_magic_l, ver_magic_h = my_gen_ver_magic(major, minor, revision)
231
232 ver_magic_l, ver_magic_h = my_gen_mtk_magic(to_int(mi_desc['magic_num']))
233
234 # bl region
235 bl_version = mi_desc['bl_version']
236 images = mi_desc['images']
237 img_num = len(images)
238 ls_cmds = mi_desc['load_srcipt_cmd']
239 ls_cmds_num = len(ls_cmds)
240
241 '''size of bl + imgl + sbc + auth'''
242 # Fixed size section: mi_header, sbc data, auth data
243 # Non-fixed size section: img_info, load script
244 bl_total_len = g_mi_header_info_size + g_sbc_size + g_auth_size
245 bl_total_len += img_num * g_img_header_size
246 bl_total_len += ls_cmds_num * g_ls_cmd_size
247
248
249 #print("==== multi-image header size ====")
250 #print("g_mi_header_info_size=%d, g_sbc_size=%d, g_auth_size=%d, bl_total_len = %d" %(g_mi_header_info_size, g_sbc_size, g_auth_size, bl_total_len))
251
252 #img_header_table = []
253 img_headers = []
254 bins = []
255 sbc_region = []
256 hashtable = []
257 imagetmp = [[], [], [], [], [], [], [], [], [], []]
258 packtmp = []
259 blh_hash = []
260 signaturelist = []
261
262 imagesize = []
263
264
265 # sbc region
266 ##pub_key = to_int(mi_desc['public_key'])
267 ##public_key = my_binify(pub_key)
268 '''20180627 remove int assign avoid key start is (0x00..)'''
269 pub_key = (mi_desc['public_key'])
270 public_key = cryptoSB.strip_key(pub_key)
271 public_key_append = my_pad_to_align(public_key, 96)
272 sbc_region.append(public_key_append)
273 pubk = b'\x04' + public_key
274
275 #print("======= sbc region =========")
276 sbc_auth_alg = mi_desc['sbc_auth_alg']
277 #print("sbc_auth_alg = 0x%x" %sbc_auth_alg)
278 sbc_auth_inf = mi_desc['sbc_auth_inf']
279 #print("sbc_auth_inf = 0x%x" %sbc_auth_inf)
280 sbc = sbc_struct.pack(sbc_auth_inf, sbc_auth_alg)
281 sbc_region.append(sbc)
282
283
284 # pad before 1st image
285
286 #pad = pad_to_align(64, expected_size)
287 #bins.append(pad)
288 #expected_size += len(pad)
289
290
291 # images
292 # 16 bytes aligned
293 img_offset = (bl_total_len + 15) & (~15)
294 img_offset_table = []
295
296 for i in range(img_num):
297 #print("\n\n======== Start image step: =========")
298
299
300 img = images[i]
301 img_file = img['img_file']
302 img_enc_inf = img['img_enc_inf']
303 img_enc_alg = img['img_enc_alg']
304 #print("img_enc_inf=0x%x" %img_enc_inf)
305
306 bin = open(img_dir + '/' + img_file, 'rb').read()
307
308 iv_int = img['img_iv']
309 #iv = my_binify(iv_int)
310 '''0627 remove int assign avoid key start is (0x00..)'''
311 iv = cryptoSB.strip_key(iv_int)
312 iv0= int(iv[0:4].encode('hex'), 16)
313 iv1= int(iv[4:8].encode('hex'), 16)
314 iv2= int(iv[8:12].encode('hex'), 16)
315 iv3= int(iv[12:16].encode('hex'), 16)
316 #print type(iv)
317 #print("IV:")
318 #cryptoSB.dump(iv)
319
320
321 if(img_enc_inf == 1):
322 '''image encrypt'''
323 out = cryptoSB.my_img_enc(bin, enckey, iv, img_enc_alg, __Align)
324 bins.append(out)
325 #bins = out
326 elif(img_enc_inf == 2):
327 '''image encrypt'''
328 out = cryptoSB.my_img_enc(bin, enckey, iv, img_enc_alg, __Align)
329 bins.append(out)
330 #bins = out
331 else:
332 '''plaintext image'''
333 out = my_pad_to_align(bin, __Align)
334 bins.append(out)
335 #bins = out
336
337 # binary length should be 16 bytes aligned
338 length = len(out)
339
340 imagesize.append(length)
341 #print("")
342 #print("image[%d] offset : 0x%x" %(i, img_offset))
343 #print("image[%d] size : 0x%x" %(i, imagesize[i]))
344
345 imagetmp[i] = copy.copy(bins)
346
347 img_str = ''.join(bins)
348 #print type(img_str)
349 #print("========= image[%d] binary ==========" %i)
350 #cryptoSB.dump(img_str)
351
352
353 # hash each (image header + image binary)
354 #print('')
355 #print("========= image[%d] binary hash ==========" %i)
356 hashvalue = cryptoSB.sb_hash(img_str, sbc_auth_alg)
357 imghash = my_pad_to_align(hashvalue, 64)
358 #cryptoSB.dump(imghash)
359
360 # img_header
361 img_hdr = struct.pack('<II',
362 length,
363 img_offset)
364 img_hdr += "".join(imghash)
365 '''20180719 fix IV order fail'''
366 img_hdr += struct.pack('<II16s',
367 img_enc_inf,
368 img_enc_alg,
369 iv)
370
371
372 img_offset_table.append(str(img_offset))
373 img_offset += length
374 #img_offset_table.append(my_to_bytes(img_offset, 4, endianess='little'))
375
376 #print("\n=====>")
377 #print("image[%d] header info :" %i)
378 #cryptoSB.dump(img_hdr)
379 img_headers.append(img_hdr)
380
381 #img_headers.remove(img_hdr)
382 while len(bins) > 0:
383 bins.pop()
384
385
386 #print("\n\nSTART to pack all sections ...")
387 pack = []
388
389 #print("======== append mi_header info ==========")
390 total_len = int(img_offset_table[img_num-1]) + int(imagesize[img_num-1])
391
392 mi_header = mi_header_struct.pack(
393 ver_magic_l,
394 ver_magic_h,
395 total_len,
396 bl_version,
397 img_num,
398 ls_cmds_num)
399
400
401 pack.append(mi_header)
402
403 # append image info
404 for i in range(img_num):
405 pack += img_headers[i]
406
407
408 ls_script = pack_load_script(mi_desc)
409 if ls_script == None:
410 print("pack_load_script fail")
411 return
412
413 # append load script
414 pack += ls_script
415
416 # append sbc data
417 pack += sbc_region
418
419 # for easy view. please remove it while release final
420 '''align for (bl + imgl + sbc)'''
421 if(__Align_16_en == 1):
422 padnum = pad_to_align(16, len(''.join(pack)))
423 pack.append(padnum)
424
425 #print("======== append mi_header hash: ==========")
426 bl_header = ''.join(pack)
427 #cryptoSB.dump(bl_header)
428 blh = copy.copy(bl_header)
429 boothash = cryptoSB.sb_hash(blh, sbc_auth_alg)
430 boothash_append = my_pad_to_align(boothash, g_boot_hash_size)
431 #cryptoSB.dump(boothash_append)
432 blh_hash.append(boothash_append)
433
434 # append hash
435 pack += blh_hash
436
437 #print("======== append mi_header signature: =========")
438 #privk = "\xc1\xbe\xe4\xfa\x86\xaf\x86\x84\x67\x7c\xae\xee\xa8\x8a\xb0\x72\x3e\x55\x4a\xef\x01\x60\xb8\xfc\x65\x3c\x0e\x00\x08\x0f\x4f\x78"
439 #pubk = "\x04\x14\xc1\xcf\x10\x99\x9d\x3a\x98\xf3\x71\xb8\xd8\x9b\x3b\x26\xb2\x9e\xe1\xbd\x99\xf3\xe0\x39\x3d\x34\x21\x6a\x6f\x49\x58\x7a\xb1\xdd\x8a\xba\x7a\x9d\x02\x99\x5f\xda\xa0\xb8\x62\x82\xae\xc2\xd0\xc6\x88\xc2\x26\x03\x97\x86\x65\x46\xbb\x20\xc9\xd1\x44\xb9\x84"
440
441 if sbc_auth_inf == 0:
442 padbytes = '\0' * g_signature_size
443 signaturelist.append(padbytes)
444 else:
445 pem_key_format = mi_desc['pem_key_format']
446 if(pem_key_format == 1):
447 '''PEM format'''
448 key_mode = 1
449 elif(pem_key_format == 2):
450 '''DER format'''
451 key_mode = 2
452 else:
453 '''String format'''
454 key_mode = 0
455
456 #ecdsa = cryptoSB.ECDSA()
457 #signature = ecdsa.sign(privk, pubk, boothash, sbc_auth_alg)
458 ''' 20180616 fix the sb_sign msg error : not boothash -> blh is right'''
459 signature = cryptoSB.sb_sign(privk, pubk, blh, sbc_auth_alg, key_mode)
460 #print("signature size = %d" %len(signature))
461 signature_append = my_pad_to_align(signature, g_signature_size)
462 #cryptoSB.dump(signature_append)
463 signaturelist.append(signature_append)
464
465 #check verify
466 #ret = ecdsa.verify(pubk, boothash, signature, sbc_auth_alg)
467 #print("ecdsa verify: %s" %ret)
468
469
470 #dump("".join(signaturelist))
471 # append signature
472 pack += signaturelist
473
474 # for easy view, please remove it while release final
475 '''align for (bl + imgl + sbc + auth)'''
476 if(__Align_16_en == 1):
477 padnum = pad_to_align(16, len(''.join(pack)))
478 pack.append(padnum)
479
480 # append image binary
481 for i in range(img_num):
482 offset = int(img_offset_table[i])
483 pad_num = offset - len(''.join(pack))
484 #print("offset = %d" %offset)
485 #print("pad_num = %d" %pad_num)
486
487 padbytes = '\0' * pad_num
488 pack.append(padbytes)
489 pack += imagetmp[i]
490
491 #print(len(''.join(pack)))
492
493 # clear list
494 while len(signaturelist) > 0:
495 signaturelist.pop()
496
497
498 return ''.join(pack)
499
500'''support to_bytes to python 2.7'''
501def my_to_bytes(n, length, endianess='big'):
502 h = '%x' % n
503 s = ('0'*(len(h) % 2) + h).zfill(length*2).decode('hex')
504 return s if endianess == 'big' else s[::-1]
505
506'''long to byte string'''
507def my_binify(x):
508 h = hex(x)[2:].rstrip('L')
509 return binascii.unhexlify(h)
510
511def my_binify2(x):
512 if(hex(x)[0:2] == '0x'):
513 h = hex(x)[2:].rstrip('L')
514 else:
515 h = hex(x).rstrip('L')
516
517 return binascii.unhexlify(h)
518
519def my_pad_to_align(x, align):
520 if(align == 0):
521 return x
522 else:
523 size = len(x)
524 #print("size 0x%x" %size)
525 pad_size = (align - size % align) % align
526 for i in range(0, pad_size, 1):
527 x += b'\x00'
528
529 #cryptoSB.dump(x)
530 return x
531
532
533def img_enc(mi_desc, key, align=None):
534
535 images = mi_desc['images']
536 img_num = len(images)
537
538 img = images[0]
539 #load_addr = img['load_addr']
540 #entrypoint = img['entrypoint']
541 img_file = img['img_file']
542 img_enc_alg = img['img_enc_alg']
543 #print(img_enc_alg)
544 img_enc_inf = img['img_enc_inf']
545 #print(img_enc_inf)
546 iv = img['img_iv']
547 iv = my_binify(iv)
548 #print type(iv)
549 #print("img_enc dump:")
550 #cryptoSB.dump(iv)
551
552 bin = open(img_file, 'rb').read()
553 #cryptoSB.dump(bin)
554
555 #align
556 bin = my_pad_to_align(bin, 64)
557
558 aes = cryptoSB.AESCipher(key, 16)
559 encmsg = aes.aes_encrypt(bin)
560 #print("result image enc:")
561 #cryptoSB.dump(encmsg)
562
563 return encmsg
564
565
566
567
568if __name__ == '__main__':
569 import os, sys, getopt
570
571
572 def print_usage():
573 print ('usage:', os.path.basename(sys.argv[0]), "[options] <image config>.json\n", \
574 'options:\n', \
575 '\t[-o | --output out.img]\n', \
576 '\t[-h | --help]\n', \
577 '\t[-i | --input]\n', \
578 '\t[-k | --prikey hexkey e.g. 0x0102..]\n', \
579 '\t[-s | --enckey hexkey e.g. 0x0102..]\n', \
580 '\t[-p | --pemdir <pem path>\n', \
581 '\t[-d | --imgdir <image path>\n')
582
583
584 def main():
585 opts, args = getopt.getopt(sys.argv[1:],
586 'ho:a:i:k:s:p:d:',
587 ['help', 'output=', 'align=', 'input=',
588 'prikey=', 'enckey=', 'pemdir=', 'imgdir=']
589 )
590
591 out_name = None
592 align = 0
593 infile_name = None
594 aeskey = None
595 pubkey = None
596 privk = None
597 pem_dir = "binfile"
598 img_dir = ''
599
600 for o, a in opts:
601 if o in ('-h', '--help'):
602 print_usage()
603 sys.exit()
604 elif o in ('-o', '--output'):
605 out_name = a
606 elif o in ('-a', '--align'):
607 align = int(a)
608 elif o in ('-i', '--input'):
609 ## doesn't need currently
610 infile_name = a
611 elif o in ('-k', '--prikey'):
612 privkey = a
613 elif o in ('-s', '--enckey'):
614 aeskey = a
615 elif o in ('-p', '--pemdir'):
616 pem_dir = a
617 elif o in ('-d', '--imgdir'):
618 img_dir = a
619 else:
620 print_usage()
621 sys.exit(1)
622
623 if len(args) >= 1:
624 mi_desc_fn = args[0]
625 else:
626 print_usage()
627 sys.exit(1)
628
629 if not out_name:
630 fn, ext = os.path.splitext(mi_desc_fn)
631 out_name = fn + '.img'
632
633 """ read json script """
634 mi_desc = read_desc(mi_desc_fn)
635
636 #mipack = pack_images(mi_desc, align)
637
638 #print 'output: %s (%d bytes)' % (out_name, len(mipack))
639 #open(out_name, 'wb').write(mipack)
640
641 cmd_line_key = mi_desc['cmd_line_key']
642 sign_priv_key = mi_desc['sign_priv_key']
643 aes_enc_sym_key = mi_desc['aes_enc_sym_key']
644
645 """ Where is the key input from """
646
647 pem_key_format = mi_desc['pem_key_format']
648 if(pem_key_format == 1):
649 sbc_auth_alg = mi_desc['sbc_auth_alg']
650 if(sbc_auth_alg == 0):
651 key_path = pem_dir + "/ecdsa_p256_private.pem"
652 #print(key_path)
653 privk = open(key_path,"rb").read()
654 #privk = open("binfile/ecdsa_p256_private.pem","rb").read()
655 #pubk_pem = open("binfile/ecdsa_p256_public.pem","rb").read()
656 elif(sbc_auth_alg == 1):
657 privk = open("binfile/ecdsa_p384_private.pem","rb").read()
658
659 key = cryptoSB.strip_key(aes_enc_sym_key)
660
661 else:
662 if(cmd_line_key == 1):
663 key = cryptoSB.strip_key(aeskey)
664 privk = cryptoSB.strip_key(privkey)
665 #print("dump privkey:")
666 #cryptoSB.dump(privk)
667 elif(cmd_line_key == 0):
668 key = cryptoSB.strip_key(aes_enc_sym_key)
669 privk = cryptoSB.strip_key(sign_priv_key)
670 #print("dump privkey:")
671 #cryptoSB.dump(privk)
672 else:
673 prnit("ERROR: please check cmd_line_key json")
674
675
676
677 #run hash
678 #hash = cryptoSB.HASH()
679 #imghash = hash.hash_sha256(enc_data)
680 #cryptoSB.dump(imghash)
681
682 mipack = my_pack_images(mi_desc, privk, key, align, img_dir)
683 if mipack == None:
684 print("my_pack_images fail")
685 return
686
687 #out_name = 'my_' + fn + '.img'
688 #out_name = fn + '.img'
689 print('output: %s (%d bytes)' % (out_name, len(mipack)))
690 open(out_name, 'wb').write(mipack)
691
692 main()
693