Skip to content

Instantly share code, notes, and snippets.

@danny8376
Last active February 22, 2024 08:09
Show Gist options
  • Save danny8376/fd7104396827adeabb8c13780a6f65c6 to your computer and use it in GitHub Desktop.
Save danny8376/fd7104396827adeabb8c13780a6f65c6 to your computer and use it in GitHub Desktop.
from pyctr.crypto import CryptoEngine
from Cryptodome.Cipher import AES
from hashlib import sha256
a = CryptoEngine()
def print_diff(ori, enc, dec, postxt, *suffix):
if postxt == None:
return
if type(postxt) is tuple:
s = len(enc) // len(postxt)
for x in range(len(enc) // s):
b, e = x * s, (x + 1) * s
xori, xenc, xdec = ori[b:e], enc[b:e], dec[b:e]
if xori != xenc:
print(f"{postxt[x]} ori:", xori.hex(), *suffix)
print(f"{postxt[x]} fix:", xenc.hex(), xdec.hex(), *suffix)
elif ori != enc:
print(f"{postxt} ori:", ori.hex(), *suffix)
print(f"{postxt} fix:", enc.hex(), dec.hex(), *suffix)
def decrypt_otp_block(data, iv):
cipher = AES.new(a.otp_key, AES.MODE_CBC, iv)
return cipher.decrypt(data)
def crack_singlebit(indata, iv, check, postxt):
#if check(decrypt_otp_block(indata, iv)):
# return indata
ret = None
ints = bytearray(indata)
for x in range(len(indata)):
orig = ints[x]
for bit in range(8):
new = orig ^ (1 << bit)
ints[x] = new
data = decrypt_otp_block(ints, iv)
if check(data):
print_diff(indata, ints, data, postxt, "(single bit)")
ret = ints
return ret
ints[x] = orig
return ret
def crack_dataline(indata, iv, bit, check, postxt):
#if check(decrypt_otp_block(indata, iv)):
# return indata
set_size = len(indata) // 4
ret = None
for combi in range(pow(2, set_size)):
ints = bytearray(indata)
for addr in range(set_size):
if (combi >> addr) & 1:
byte = 4 * addr + bit // 8
orig = ints[byte]
ints[byte] = orig ^ (1 << (bit % 8))
cipher = AES.new(a.otp_key, AES.MODE_CBC, iv)
data = cipher.decrypt(ints)
if check(data):
print_diff(indata, ints, data, postxt, "(data line)")
ret = ints
return ret
return ret
def crack_singlebit_dataline(indata, extract, check, postxt, bit = -1):
indata, iv = extract(indata)
ret = (-1, b"\x00" * len(indata))
if check(decrypt_otp_block(indata, iv)):
if bit == -1:
bit = -2
return (bit, indata)
if bit == -1 or bit == 32:
res = crack_singlebit(indata, iv, check, postxt)
if res != None:
ret = (32, res)
return ret
#if bit == 32: # force sigle bit -> fail
# return ret
if bit < 0: # -1: default, -2: no need to fix previously
for bit in range(32):
res = crack_dataline(indata, iv, bit, check, postxt)
if res != None:
ret = (bit, res)
return ret
else:
res = crack_dataline(indata, iv, bit, check, postxt)
if res != None:
ret = (bit, res)
return ret
return ret
def crack0x00(otp2fix):
def extract(data):
return data[0:0x10], a.otp_iv
def check(data):
return data[0:4] == b"\x0f\xb0\xad\xde" and data[0xD:0x10] == b"\x00\x00\x00" and data[0xC] in (0, 2)
ret = crack_singlebit_dataline(otp2fix, extract, check, "0x00")
if ret[0] == -1:
print("Can't fix 0x00")
exit(1)
return ret
def crack0x10(otp2fix, bit):
def extract(data):
return data[0x10:0x20], data[0:0x10]
def check(data):
return data[0x8:0xA] == b"\x05\x00"
ret = crack_singlebit_dataline(otp2fix, extract, check, "0x10", bit)
if ret[0] == -1:
print("Can't fix 0x10")
exit(1)
return ret
def crack0x70x80(otp2fix, bit):
def extract(data):
return data[0x70:0x90], data[0x60:0x70]
def check(data):
return data[0x10:0x20] == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
ret = crack_singlebit_dataline(otp2fix, extract, check, ("0x70", "0x80"), bit)
if ret[0] == -1:
print("can't fix 0x70, 0x80")
#exit(1)
return ret
def showbits(bit):
for addr in range(0x100 // 4):
byte = 4 * addr + bit // 8
orig = otp[byte]
print((orig >> (bit % 8)) & 1, end="\t")
if addr % 4 == 3:
print()
with open('otp.mem', 'rb') as f:
content = f.read(0x100)
otp = bytearray(content)
bit, otp[0:0x10] = crack0x00(otp)
#showbits(bit)
bit, otp[0x10:0x20] = crack0x10(otp, bit)
bit, otp[0x70:0x90] = crack0x70x80(otp, bit)
#showbits(bit)
print(f"Bit: {bit}")
for x in range(0x10):
print("--------------------------------")
start = 0x10 * x
end = start + 0x10
print(content[start:end].hex())
print(otp[start:end].hex())
with open('otp_fixed.mem', 'wb') as f:
f.write(otp)
#for bit in range(32):
# ints = bytearray(content[0:0x10])
# for combi in range(pow(2, 0x10 // 4)):
# for addr in range(0, 0x10, 4):
# if (combi >> addr) & 1:
# byte = addr + bit // 8
# orig = ints[byte]
# ints[byte] = orig ^ (1 << (bit % 8))
# cipher = AES.new(a.otp_key, AES.MODE_CBC, a.otp_iv)
# data = cipher.decrypt(ints)
# ohash = data[0xE0:]
# before_hash = data[0:0xE0]
# hash_before_hash = sha256(before_hash).hexdigest()
# if data[0:4].hex() == "0fb0adde":
# print(data[0:4].hex(), bit, combi)
# #print(bit, hash_before_hash, ohash.hex(), hash_before_hash == ohash.hex())
# if hash_before_hash == ohash.hex():
# print(beginning + before_hash + ohash)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment