-
-
Save ledudu/f5492c97a8ff0e83b855442d75fe89df to your computer and use it in GitHub Desktop.
Revisions
-
SciresM revised this gist
Oct 8, 2020 . 1 changed file with 49 additions and 11 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -25,14 +25,50 @@ def tea_decrypt(v, k): cur_sum = u32(cur_sum - delta) return [v0, v1] def tea_encrypt(v, k): # Taken with love from Wikipedia v0, v1 = v[0], v[1] cur_sum = 0 delta = 0x9E3779B9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] for i in xrange(0, 32): cur_sum = u32(cur_sum + delta) v0 = u32(v0 + (u32((v1 << 4) + k0) ^ u32(v1 + cur_sum) ^ u32((v1 >> 5) + k1))) v1 = u32(v1 + (u32((v0 << 4) + k2) ^ u32(v0 + cur_sum) ^ u32((v0 >> 5) + k3))) return [v0, v1] def get_key(offset): return [u32(0x73707048 + offset), u32(0xE8AD34FB + offset), u32(0xA4A8ACE6 + offset), u32(0x7B648B68 + offset)] def encrypt_firmware(data, do_print = True): # Parse header. # Checks from validate_firmware_header (sub_08000CA8) # Note that several of these checks are redundant, and header + 0xC is not used but is set.... assert len(data) >= 0x10 offset, size, version, _C = up('<IIII', data[:0x10]) assert size < 0x20000 assert (offset & 0x3FF) == 0 assert (size & 0x3FF) == 0 assert offset == 0 assert size < 0x1CC00 if do_print: print 'Encrypting Update version %d.%d, size = 0x%X' % (version >> 8, version & 0xFF, size) # Encrypt data. assert len(data) == 0x10 + size calc_mac = [0, 0, 0, 0] dec = data[0x10:] enc = '' for i in xrange(0, size, 8): cur_key = get_key(i) cur_dec = up('<II', dec[i:i+8]) cur_enc = tea_encrypt(cur_dec, cur_key) tea_update_custom_mac(calc_mac, cur_dec, cur_key) enc += pk('<II', *cur_enc) calc_mac = pk('<IIII', *calc_mac) return data[:0x10] + calc_mac + enc def decrypt_firmware(data, do_print = True): # Parse header. # Checks from validate_firmware_header (sub_08000CA8) # Note that several of these checks are redundant, and header + 0xC is not used but is set.... @@ -44,25 +80,25 @@ def decrypt_firmware(data, f): assert (size & 0x3FF) == 0 assert offset == 0 assert size < 0x1CC00 if do_print: print 'Decrypting Update version %d.%d, size = 0x%X' % (version >> 8, version & 0xFF, size) # Decrypt data. assert len(data) == 0x20 + size calc_mac = [0, 0, 0, 0] enc = data[0x20:] dec = '' for i in xrange(0, size, 8): cur_key = get_key(i) cur_enc = up('<II', enc[i:i+8]) cur_dec = tea_decrypt(cur_enc, cur_key) tea_update_custom_mac(calc_mac, cur_dec, cur_key) dec += pk('<II', *cur_dec) calc_mac = pk('<IIII', *calc_mac) if calc_mac != mac and do_print: print '[WARN] Calculated MAC (%s) != Expected MAC (%s)' % (calc_mac.encode('hex'), mac.encode('hex')) return data[:0x10] + dec def main(argc, argv): if argc != 4 or argv[1] not in ('-d', '-e'): @@ -72,10 +108,12 @@ def main(argc, argv): data = f.read() with open(argv[3], 'wb') as f: if argv[1] == '-d': f.write(decrypt_firmware(data)) else: assert argv[1] == '-e' enc = encrypt_firmware(data) assert data == decrypt_firmware(enc, False) f.write(enc) return 0 if __name__ == '__main__': -
SciresM revised this gist
Oct 8, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -44,7 +44,7 @@ def decrypt_firmware(data, f): assert (size & 0x3FF) == 0 assert offset == 0 assert size < 0x1CC00 print 'Decrypting Update version %d.%d, size = 0x%X' % (version >> 8, version & 0xFF, size) # Decrypt data. assert len(data) == 0x20 + size -
SciresM created this gist
Oct 8, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,82 @@ import sys from struct import pack as pk, unpack as up def u32(x): return x & 0xFFFFFFFF def tea_update_custom_mac(mac, v, k): v0, v1 = v[0], v[1] cur_sum = 0xC6EF3720 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] mac[3] = u32(mac[3] - (u32((v0 << 4) + k1) ^ u32(mac[2] + cur_sum) ^ u32((v1 >> 5) + k2))) mac[2] = u32(mac[2] - (u32((v1 << 4) + k3) ^ u32(mac[3] + cur_sum) ^ u32((v0 >> 5) + k0))) mac[1] = u32(mac[1] - (u32((v0 << 4) + k2) ^ u32(mac[0] + cur_sum) ^ u32((v0 >> 5) + k3))) mac[0] = u32(mac[0] - (u32((v1 << 4) + k0) ^ u32(mac[1] + cur_sum) ^ u32((v1 >> 5) + k1))) def tea_decrypt(v, k): # Taken with love from Wikipedia v0, v1 = v[0], v[1] cur_sum = 0xC6EF3720 delta = 0x9E3779B9 k0, k1, k2, k3 = k[0], k[1], k[2], k[3] for i in xrange(0, 32): v1 = u32(v1 - (u32((v0 << 4) + k2) ^ u32(v0 + cur_sum) ^ u32((v0 >> 5) + k3))) v0 = u32(v0 - (u32((v1 << 4) + k0) ^ u32(v1 + cur_sum) ^ u32((v1 >> 5) + k1))) cur_sum = u32(cur_sum - delta) return [v0, v1] def get_key(offset): return [u32(0x73707048 + offset), u32(0xE8AD34FB + offset), u32(0xA4A8ACE6 + offset), u32(0x7B648B68 + offset)] def encrypt_firmware(data, f): print 'TODO: Encryption' pass def decrypt_firmware(data, f): # Parse header. # Checks from validate_firmware_header (sub_08000CA8) # Note that several of these checks are redundant, and header + 0xC is not used but is set.... assert len(data) >= 0x20 offset, size, version, _C = up('<IIII', data[:0x10]) mac = data[0x10:0x20] assert size < 0x20000 assert (offset & 0x3FF) == 0 assert (size & 0x3FF) == 0 assert offset == 0 assert size < 0x1CC00 print 'Decrypting Update version %d.%d.%d, size = 0x%X' % (version >> 8, (version >> 4) & 0xF, (version >> 0) & 0xF, size) # Decrypt data. assert len(data) == 0x20 + size calc_mac = [0, 0, 0, 0] enc = data[0x20:] dec = '' for i in xrange(0, size, 8): cur_enc = up('<II', enc[i:i+8]) cur_key = get_key(i) cur_dec = tea_decrypt(cur_enc, cur_key) tea_update_custom_mac(calc_mac, cur_dec, cur_key) dec += pk('<II', *cur_dec) calc_mac = pk('<IIII', *calc_mac) if calc_mac != mac: print '[WARN] Calculated MAC (%s) != Expected MAC (%s)' % (calc_mac.encode('hex'), mac.encode('hex')) f.write(data[:0x10]) f.write(dec) def main(argc, argv): if argc != 4 or argv[1] not in ('-d', '-e'): print 'Usage: %s {-d|-e} in out' % argv[0] return 1 with open(argv[2], 'rb') as f: data = f.read() with open(argv[3], 'wb') as f: if argv[1] == '-d': decrypt_firmware(data, f) else: assert argv[1] == '-e' encrypt_firmware(data, f) return 0 if __name__ == '__main__': sys.exit(main(len(sys.argv), sys.argv))