Skip to content

Instantly share code, notes, and snippets.

@SadPaladin
Created May 2, 2018 13:21
Show Gist options
  • Save SadPaladin/3ec7971468ec2c4532633131bfaf1bc2 to your computer and use it in GitHub Desktop.
Save SadPaladin/3ec7971468ec2c4532633131bfaf1bc2 to your computer and use it in GitHub Desktop.
A script to decrypt uboot/kernel/mcu update images used by Allwinner T8-based car radio headunits
#!/usr/bin/env python3
import hashlib
import sys
import tqdm # Used to report progress during decryption
if len(sys.argv) not in (2,3):
print("Usage: dcupdate.py enciphered_file [deciphered_file]")
print("Deciphers images used by Allwinner T8-based car radio headunits")
sys.exit(0)
print("Deciphering update '{}'".format(sys.argv[1]))
# Extracted from UBoot Firmware
unkA = bytes([0xC1, 0x81, 0x56, 0xC2, 0x44, 0xBD, 0x11, 0xE1, 0x94, 0x38, 0x00, 0x0C, 0x29, 0xBA, 0x27, 0xC0])
unkB = bytes([0x81, 0x6B, 0xAE, 0x89, 0x3F, 0x95, 0xE6, 0xDB, 0x96, 0xA3, 0xB9, 0x90, 0x57, 0x17, 0x29, 0xAF])
unk_xored = bytes([a ^ b for a,b in zip(unkA, unkB)])
print("Magic bytes:")
print(" A = {}".format(unkA.hex()))
print(" B = {}".format(unkB.hex()))
print(" A ^ B = {}".format(unk_xored.hex()))
def obfuscate_block(key_block, in_block):
inner_digest = hashlib.md5(key_block + in_block + unk_xored).digest()
outer_digest = hashlib.md5(inner_digest + unkB).digest()
return outer_digest
fn = sys.argv[1]
try:
with open(fn, 'rb') as f:
buffer = f.read()
key_block = buffer[-0x20:-0x10]
print("Key Block: {}".format(key_block.hex()))
# Verify checksum
file_md5 = hashlib.md5(buffer[:-0x10]).digest()
obfuscated_md5 = obfuscate_block(key_block, file_md5)
exp_obfuscated_md5 = buffer[-0x10:]
print("Obfuscated Checksum: {}".format(obfuscated_md5.hex()))
print("Expected Checksum: {}".format(exp_obfuscated_md5.hex()))
assert obfuscated_md5 == exp_obfuscated_md5, "Checksums do not match"
if len(sys.argv) == 2:
print("Checksums match! No output file specified, exiting...")
sys.exit(0)
# Dump deciphered file
print("Deciphering file...")
out_fn = sys.argv[2]
xor_block = bytes([0] * 16)
with open(out_fn, 'wb') as fout:
for i in tqdm.trange(0, len(buffer) - 0x20, 0x10):
xor_block = obfuscate_block(key_block, xor_block)
block = buffer[i:i+min(0x10, len(buffer) - 0x20)]
dec_block = bytes([a ^ b for a,b in zip(block, xor_block)])
fout.write(dec_block)
except IOError as e:
print("I/O Error ({0}): {1}".format(e.errno, e.strerror))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment