Talk:Keys: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
|||
(6 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
= Python Script to decrypt CP Box EMC blob and preserve header (trim 0x80 bytes, entrypoint at 0x100C00) | = Python Script to decrypt CP Box EMC blob and preserve header = | ||
* (trim 0x80 bytes, entrypoint at 0x100C00) | |||
<pre> | <pre> | ||
Line 12: | Line 14: | ||
CIPHERKEYSEMC = ['F0332357C8CFAE7E7E26E52BE9E3AED4'] | CIPHERKEYSEMC = ['F0332357C8CFAE7E7E26E52BE9E3AED4'] | ||
CIPHERKEYSEAP = [' | CIPHERKEYSEAP = ['262555E3CF062B070B5AA2CDDF3A5D0E'] | ||
HASHERKEYEMC = ['00000000000000000000000000000000'] | HASHERKEYEMC = ['00000000000000000000000000000000'] | ||
HASHERKEYEAP = [' | HASHERKEYEAP = ['1EE22F6A189E7D99A28B9A96D3C4DBA2'] | ||
ZEROS128 = ['00000000000000000000000000000000'] | ZEROS128 = ['00000000000000000000000000000000'] | ||
Line 88: | Line 90: | ||
if __name__ == '__main__': | if __name__ == '__main__': | ||
main(len(sys.argv), sys.argv) | main(len(sys.argv), sys.argv) | ||
</pre> | |||
= Python Script to Encrypt (Requires Header from Decryption Script) = | |||
<pre> | |||
import struct | |||
from binascii import unhexlify as uhx | |||
from binascii import hexlify as hx | |||
from Crypto.Cipher import AES | |||
from Crypto.Hash import SHA, HMAC | |||
import os | |||
import sys | |||
CIPHERKEYSEMC = ['F0332357C8CFAE7E7E26E52BE9E3AED4'] | |||
CIPHERKEYSEAP = ['262555E3CF062B070B5AA2CDDF3A5D0E'] | |||
HASHERKEYEMC = ['00000000000000000000000000000000'] | |||
HASHERKEYEAP = ['1EE22F6A189E7D99A28B9A96D3C4DBA2'] | |||
ZEROS128 = ['00000000000000000000000000000000'] | |||
def aes_decrypt_cbc(key, iv, input): | |||
return AES.new(key, AES.MODE_CBC, iv).decrypt(input) | |||
def aes_encrypt_cbc(key, iv, input): | |||
return AES.new(key, AES.MODE_CBC, iv).encrypt(input) | |||
def emc_decrypt_header(hdr): | |||
return hdr[:0x30] + aes_decrypt_cbc(uhx(CIPHERKEYSEMC[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) | |||
def emc_encrypt_header(hdr): | |||
return hdr[:0x30] + aes_encrypt_cbc(uhx(CIPHERKEYSEMC[0]), uhx(ZEROS128[0]), hdr[0x30:]) | |||
def eap_decrypt_header(hdr): | |||
return hdr[:0x30] + aes_decrypt_cbc(uhx(CIPHERKEYSEAP[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) | |||
def eap_encrypt_header(hdr): | |||
return hdr[:0x30] + aes_encrypt_cbc(uhx(CIPHERKEYSEAP[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) | |||
def main(argc, argv): | |||
with open(sys.argv[1], 'rb') as f: | |||
data = f.read() | |||
type = data[7:8] | |||
if type == uhx('48'): | |||
print 'EMC' | |||
body_len = struct.unpack('<L', data[0xc:0x10])[0] | |||
body = data[0x80:0x80+body_len] | |||
body_aes_key = data[0x30:0x40] | |||
ebody = aes_encrypt_cbc(body_aes_key, uhx(ZEROS128[0]), body) | |||
body_hmac_key = data[0x40:0x50] | |||
bhmac = HMAC.new(body_hmac_key, ebody, SHA) | |||
hdr = (data[0:0x50] + uhx(bhmac.hexdigest()) + data[0x64:0x6C]) | |||
hhmac = HMAC.new(uhx(HASHERKEYEMC[0]), hdr, SHA) | |||
hdr = (hdr + uhx(hhmac.hexdigest())) | |||
hdr = emc_encrypt_header(hdr) | |||
print bhmac.hexdigest() | |||
print hhmac.hexdigest() | |||
with open(sys.argv[1] + '.bin', 'wb') as g: | |||
g.write(hdr+ebody) | |||
if type == uhx('68'): | |||
print 'EAP' | |||
body_len = struct.unpack('<L', data[0xc:0x10])[0] | |||
body = data[0x80:0x80+body_len] | |||
body_aes_key = data[0x30:0x40] | |||
ebody = aes_encrypt_cbc(body_aes_key, uhx(ZEROS128[0]), body) | |||
body_hmac_key = data[0x40:0x50] | |||
bhmac = HMAC.new(body_hmac_key, ebody, SHA) | |||
hdr = (data[0:0x50] + uhx(bhmac.hexdigest()) + data[0x64:0x6C]) | |||
hhmac = HMAC.new(uhx(HASHERKEYEAP[0]), hdr, SHA) | |||
hdr = (hdr + uhx(hhmac.hexdigest())) | |||
hdr = eap_encrypt_header(hdr) | |||
print bhmac.hexdigest() | |||
print hhmac.hexdigest() | |||
with open(sys.argv[1] + '.bin', 'wb') as g: | |||
g.write(hdr+ebody) | |||
if __name__ == '__main__': | |||
main(len(sys.argv), sys.argv) | |||
</pre> | |||
= Python Script to Decrypt or Encrypt EAP Kernel = | |||
<pre> | |||
#!/usr/bin/env python | |||
import sys, os, struct | |||
import hashlib, hmac | |||
from binascii import unhexlify as uhx | |||
from Crypto.Cipher import AES | |||
from itertools import cycle | |||
try: | |||
# Python 2 | |||
from itertools import izip | |||
except: | |||
pass | |||
def as_uint32(x): | |||
return x & 0xFFFFFFFF | |||
def align_up(x, alignment): | |||
return (x + (alignment - 1)) & ~(alignment - 1) | |||
def align_down(x, alignment): | |||
return x & ~(alignment - 1) | |||
def sha1(data): | |||
return hashlib.sha1(data).digest() | |||
def hmac_sha1(key, data): | |||
return hmac.new(key=key, msg=data, digestmod=hashlib.sha1).digest() | |||
def xor_string(key, data): | |||
# Python 2 | |||
try: | |||
return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in izip(data, cycle(key))) | |||
# Python 3 | |||
except: | |||
return bytes(x ^ y for x, y in zip(data, cycle(key))) | |||
def aes_encrypt_ecb(key, input): | |||
aes = AES.new(key, AES.MODE_ECB) | |||
output = aes.encrypt(input) | |||
return output | |||
def aes_decrypt_ecb(key, input): | |||
aes = AES.new(key, AES.MODE_ECB) | |||
output = aes.decrypt(input) | |||
return output | |||
def aes_encrypt_cbc_cts(key, iv, data): | |||
result = b'' | |||
size = len(data) | |||
if size == 0: | |||
return result | |||
crypto = AES.new(key, AES.MODE_CBC, iv) | |||
size_aligned = align_down(size, crypto.block_size) | |||
result = crypto.encrypt(data[:size_aligned]) | |||
size_left = size - size_aligned | |||
if size_left > 0: | |||
assert size_left < crypto.block_size | |||
crypto = AES.new(key, AES.MODE_ECB) | |||
if size_aligned > AES.block_size: | |||
tmp = crypto.encrypt(result[size_aligned - AES.block_size:size_aligned]) | |||
else: | |||
tmp = crypto.encrypt(iv) | |||
result += xor_string(data[size_aligned:], tmp[:size_left]) | |||
#assert aes_decrypt_cbc_cts(key, iv, result) == data | |||
return result | |||
def aes_decrypt_cbc_cts(key, iv, data): | |||
result = b'' | |||
size = len(data) | |||
if size == 0: | |||
return result | |||
crypto = AES.new(key, AES.MODE_CBC, iv) | |||
size_aligned = align_down(size, crypto.block_size) | |||
result = crypto.decrypt(data[:size_aligned]) | |||
size_left = size - size_aligned | |||
if size_left > 0: | |||
assert size_left < crypto.block_size | |||
crypto = AES.new(key, AES.MODE_ECB) | |||
if size_aligned > AES.block_size: | |||
tmp = crypto.encrypt(data[size_aligned - AES.block_size:size_aligned]) | |||
else: | |||
tmp = crypto.encrypt(iv) | |||
result += xor_string(data[size_aligned:], tmp[:size_left]) | |||
#assert aes_encrypt_cbc_cts(key, iv, result) == data | |||
return result | |||
if len(sys.argv) < 4: | |||
script_file_name = os.path.split(sys.argv[0])[1] | |||
print('usage: {0} <input file> <output file> <enc/dec> [personality]'.format(script_file_name)) | |||
sys.exit() | |||
input_file_path = sys.argv[1] | |||
if not os.path.isfile(input_file_path): | |||
print('error: invalid input file specified') | |||
sys.exit() | |||
output_file_path = sys.argv[2] | |||
if os.path.exists(output_file_path) and not os.path.isfile(output_file_path): | |||
print('error: invalid output file specified') | |||
sys.exit() | |||
mode = sys.argv[3].lower() | |||
if mode != 'enc' and mode != 'dec': | |||
print('error: invalid mode') | |||
sys.exit() | |||
# total = 128 bits, symbol = 6 bits | |||
# uid max length = 8 symbols = 48 bits | |||
uid_alphabet = ' abcdefghijklmnopqrstuvwxyz' # 5 bits per symbol, 3 bits per byte | |||
uid_max_length = 8 | |||
def personalize(seed, personality): | |||
if len(seed) != 16: | |||
return False | |||
personality = personality.strip() | |||
if len(personality) == 0: | |||
print('error: empty personality') | |||
return False | |||
if len(personality) > uid_max_length: | |||
print('error: too large personality') | |||
return False | |||
personality = personality.lower().ljust(uid_max_length, ' ') | |||
seed = list(seed) | |||
pos = 0 | |||
for c in personality: | |||
idx = uid_alphabet.find(c) | |||
if idx < 0: | |||
print('error: invalid character at personality: {0}'.format(c)) | |||
return False | |||
c = ord(seed[pos + 0]) & ~0b00010011 | |||
c |= (idx & 0b10000) | |||
c |= (idx & 0b10) | |||
c |= (idx & 0b1) | |||
seed[pos + 0] = chr(c) | |||
c = ord(seed[pos + 1]) & ~0b00001100 | |||
c |= (idx & 0b1000) | |||
c |= (idx & 0b100) | |||
seed[pos + 1] = chr(c) | |||
pos += 2 | |||
return ''.join(seed) | |||
def unpersonalize(seed): | |||
if len(seed) != 16: | |||
return False | |||
personality = '' | |||
seed = list(seed) | |||
pos = 0 | |||
for i in range(uid_max_length): | |||
c1, c2, idx = ord(seed[i * 2 + 0]), ord(seed[i * 2 + 1]), 0 | |||
idx |= (c1 & 0b10000) | |||
idx |= (c1 & 0b10) | |||
idx |= (c1 & 0b1) | |||
idx |= (c2 & 0b1000) | |||
idx |= (c2 & 0b100) | |||
personality += uid_alphabet[idx] | |||
return personality | |||
seed = os.urandom(16) | |||
if len(sys.argv) > 4: | |||
seed = personalize(seed, sys.argv[4]) | |||
if seed == False: | |||
sys.exit() | |||
MAGIC = 0x12EBC95C | |||
EXPECTED_VERSION = 0x10000 | |||
PARTITION_SIZE = 16 * 1024 * 1024 | |||
BLOB_MAGIC = 0x4B726E00 | |||
SECTOR_SIZE = 0x200 | |||
HEADER_FMT = '<II16s20s' | |||
BLOB_INFO_FMT = '<III456x' | |||
# CP key | |||
ENC_KEY = uhx('CBCC1E53F42C1CB44D965E233CD792A8') | |||
MAC_KEY = uhx('683D6E2E496687CB5B831DA12BCB001B') | |||
if mode == 'dec': | |||
with open(input_file_path, 'rb') as f: | |||
# read and decrypt blob info | |||
magic, version, iv, blob_info_hash = struct.unpack(HEADER_FMT, f.read(struct.calcsize(HEADER_FMT))) | |||
if magic != MAGIC: | |||
print('error: invalid header magic: {0:08X}'.format(magic)) | |||
sys.exit() | |||
if version != EXPECTED_VERSION: | |||
print('error: invalid version: 0x{0:08X}'.format(version)) | |||
sys.exit() | |||
#print('iv: {0}'.format(iv.encode('hex').upper())) | |||
#personality = unpersonalize(iv) | |||
#print('personality: {0}'.format(personality)) | |||
data = f.read(SECTOR_SIZE - struct.calcsize(HEADER_FMT)) | |||
if data == '' or len(data) != (SECTOR_SIZE - struct.calcsize(HEADER_FMT)): | |||
print('error: insufficient blob info data') | |||
print(len(data)) | |||
print(SECTOR_SIZE - struct.calcsize(HEADER_FMT)) | |||
sys.exit() | |||
data = aes_decrypt_cbc_cts(ENC_KEY, iv, data) | |||
#print(data.encode('hex')) | |||
blob_info_calc_hash = hmac_sha1(MAC_KEY, data) | |||
if blob_info_calc_hash != blob_info_hash: | |||
print('warning: invalid blob info hash') | |||
# parse blob info | |||
magic, size, offset = struct.unpack(BLOB_INFO_FMT, data[:struct.calcsize(BLOB_INFO_FMT)]) | |||
if magic != BLOB_MAGIC: | |||
print('error: invalid blob info magic: 0x{0:08X}'.format(magic)) | |||
#sys.exit() | |||
# read blob data | |||
f.seek(offset) | |||
data = f.read(size) | |||
if data == '' or len(data) != size: | |||
print(len(data)) | |||
print(size) | |||
print('error: insufficient blob data') | |||
sys.exit() | |||
# decrypt blob | |||
magic, version, iv, blob_hash = struct.unpack(HEADER_FMT, data[:struct.calcsize(HEADER_FMT)]) | |||
if magic != MAGIC: | |||
print('error: invalid header magic: 0x{0:08X}'.format(magic)) | |||
sys.exit() | |||
if version != EXPECTED_VERSION: | |||
print('error: invalid version: 0x{0:08X}'.format(version)) | |||
sys.exit() | |||
data = aes_decrypt_cbc_cts(ENC_KEY, iv, data[struct.calcsize(HEADER_FMT):]) | |||
blob_calc_hash = hmac_sha1(MAC_KEY, data) | |||
if blob_calc_hash != blob_hash: | |||
print('warning: invalid blob hash') | |||
# write blob | |||
with open(output_file_path, 'wb') as f: | |||
f.write(data) | |||
elif mode == 'enc': | |||
# generate random iv | |||
iv = seed | |||
with open(input_file_path, 'rb') as f: | |||
# read and encrypt blob data | |||
data = f.read() | |||
blob_hash = hmac_sha1(MAC_KEY, data) | |||
data = aes_encrypt_cbc_cts(ENC_KEY, iv, data) | |||
data = struct.pack(HEADER_FMT, MAGIC, EXPECTED_VERSION, iv, blob_hash) + data | |||
# generate and encrypt blob info | |||
size = len(data) | |||
tmp_data = struct.pack(BLOB_INFO_FMT, BLOB_MAGIC, size, SECTOR_SIZE) | |||
blob_info_hash = hmac_sha1(MAC_KEY, tmp_data) | |||
tmp_data = aes_encrypt_cbc_cts(ENC_KEY, iv, tmp_data) | |||
tmp_data = struct.pack(HEADER_FMT, MAGIC, EXPECTED_VERSION, iv, blob_info_hash) + tmp_data | |||
# write everything | |||
total_size = len(tmp_data) + len(data) | |||
with open(output_file_path, 'wb') as f: | |||
f.write(tmp_data) | |||
f.write(data) | |||
padding_size = align_up(total_size, SECTOR_SIZE) - total_size | |||
if padding_size > 0: | |||
f.write(b'\0' * padding_size) | |||
f.seek(PARTITION_SIZE) | |||
f.truncate() | |||
</pre> | |||
= Python script to decrypt env.img = | |||
<pre> | |||
import sys | |||
import struct | |||
def unscramble(data): | |||
data_size = len(data) | |||
num_dwords = data_size // 4 | |||
magic = 0x012BB055 # TODO: constant from header @ 0xC | |||
new_data = bytearray() | |||
for i in range(num_dwords): | |||
value = struct.unpack_from('<I', data, i * 4)[0] | |||
value, magic = value ^ magic, value | |||
new_data += struct.pack('<I', value) | |||
return new_data | |||
with open(sys.argv[1],"rb") as file: | |||
file.seek(0x40) | |||
data=file.read(0xFF80) | |||
new_data = unscramble(data) | |||
with open(sys.argv[2],"wb") as file2: | |||
file2.write(new_data) | |||
</pre> | </pre> | ||
Latest revision as of 14:11, 4 September 2023
Python Script to decrypt CP Box EMC blob and preserve header[edit source]
- (trim 0x80 bytes, entrypoint at 0x100C00)
import struct from binascii import unhexlify as uhx from binascii import hexlify as hx from Crypto.Cipher import AES from Crypto.Hash import SHA, HMAC import os import sys CIPHERKEYSEMC = ['F0332357C8CFAE7E7E26E52BE9E3AED4'] CIPHERKEYSEAP = ['262555E3CF062B070B5AA2CDDF3A5D0E'] HASHERKEYEMC = ['00000000000000000000000000000000'] HASHERKEYEAP = ['1EE22F6A189E7D99A28B9A96D3C4DBA2'] ZEROS128 = ['00000000000000000000000000000000'] def aes_decrypt_cbc(key, iv, input): return AES.new(key, AES.MODE_CBC, iv).decrypt(input) def aes_encrypt_cbc(key, iv, input): return AES.new(key, AES.MODE_CBC, iv).encrypt(input) def emc_decrypt_header(hdr): return hdr[:0x30] + aes_decrypt_cbc(uhx(CIPHERKEYSEMC[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) def emc_encrypt_header(hdr): return hdr[:0x30] + aes_encrypt_cbc(uhx(CIPHERKEYSEMC[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) def eap_decrypt_header(hdr): return hdr[:0x30] + aes_decrypt_cbc(uhx(CIPHERKEYSEAP[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) def eap_encrypt_header(hdr): return hdr[:0x30] + aes_encrypt_cbc(uhx(CIPHERKEYSEAP[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) def main(argc, argv): with open(sys.argv[1], 'rb') as f: data = f.read(0x80) type = data[7:8] if type == uhx('48'): print 'EMC' hdr = emc_decrypt_header(data) body_aes_key = hdr[0x30:0x40] body_hmac_key = hdr[0x40:0x50] body_hmac = hdr[0x50:0x64] zeroes = hdr[0x64:0x6C] print(hx(zeroes)) header_hmac = hdr[0x6C:0x80] body_len = struct.unpack('<L', hdr[0xc:0x10])[0] print body_len ehdr = hdr[:0x6C] ebody = f.read(body_len) bhmac = HMAC.new(body_hmac_key, ebody, SHA) hhmac = HMAC.new(uhx(HASHERKEYEMC[0]), ehdr, SHA) body = aes_decrypt_cbc(body_aes_key, uhx(ZEROS128[0]), ebody) print bhmac.hexdigest() print hhmac.hexdigest() print hx(body_hmac) print hx(header_hmac) with open(sys.argv[1] + '.bin', 'wb') as g: g.write(hdr+body) if type == uhx('68'): print 'EAP' hdr = eap_decrypt_header(data) body_aes_key = hdr[0x30:0x40] body_hmac_key = hdr[0x40:0x50] body_hmac = hdr[0x50:0x64] zeroes = hdr[0x64:0x6C] print(hx(zeroes)) header_hmac = hdr[0x6C:0x80] body_len = struct.unpack('<L', hdr[0xc:0x10])[0] print body_len ehdr = hdr[:0x6C] ebody = f.read(body_len) bhmac = HMAC.new(body_hmac_key, ebody, SHA) hhmac = HMAC.new(uhx(HASHERKEYEAP[0]), ehdr, SHA) body = aes_decrypt_cbc(body_aes_key, uhx(ZEROS128[0]), ebody) print bhmac.hexdigest() print hhmac.hexdigest() print hx(body_hmac) print hx(header_hmac) with open(sys.argv[1] + '.bin', 'wb') as g: g.write(hdr+body) if __name__ == '__main__': main(len(sys.argv), sys.argv)
Python Script to Encrypt (Requires Header from Decryption Script)[edit source]
import struct from binascii import unhexlify as uhx from binascii import hexlify as hx from Crypto.Cipher import AES from Crypto.Hash import SHA, HMAC import os import sys CIPHERKEYSEMC = ['F0332357C8CFAE7E7E26E52BE9E3AED4'] CIPHERKEYSEAP = ['262555E3CF062B070B5AA2CDDF3A5D0E'] HASHERKEYEMC = ['00000000000000000000000000000000'] HASHERKEYEAP = ['1EE22F6A189E7D99A28B9A96D3C4DBA2'] ZEROS128 = ['00000000000000000000000000000000'] def aes_decrypt_cbc(key, iv, input): return AES.new(key, AES.MODE_CBC, iv).decrypt(input) def aes_encrypt_cbc(key, iv, input): return AES.new(key, AES.MODE_CBC, iv).encrypt(input) def emc_decrypt_header(hdr): return hdr[:0x30] + aes_decrypt_cbc(uhx(CIPHERKEYSEMC[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) def emc_encrypt_header(hdr): return hdr[:0x30] + aes_encrypt_cbc(uhx(CIPHERKEYSEMC[0]), uhx(ZEROS128[0]), hdr[0x30:]) def eap_decrypt_header(hdr): return hdr[:0x30] + aes_decrypt_cbc(uhx(CIPHERKEYSEAP[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) def eap_encrypt_header(hdr): return hdr[:0x30] + aes_encrypt_cbc(uhx(CIPHERKEYSEAP[0]), uhx(ZEROS128[0]), hdr[0x30:0x80]) def main(argc, argv): with open(sys.argv[1], 'rb') as f: data = f.read() type = data[7:8] if type == uhx('48'): print 'EMC' body_len = struct.unpack('<L', data[0xc:0x10])[0] body = data[0x80:0x80+body_len] body_aes_key = data[0x30:0x40] ebody = aes_encrypt_cbc(body_aes_key, uhx(ZEROS128[0]), body) body_hmac_key = data[0x40:0x50] bhmac = HMAC.new(body_hmac_key, ebody, SHA) hdr = (data[0:0x50] + uhx(bhmac.hexdigest()) + data[0x64:0x6C]) hhmac = HMAC.new(uhx(HASHERKEYEMC[0]), hdr, SHA) hdr = (hdr + uhx(hhmac.hexdigest())) hdr = emc_encrypt_header(hdr) print bhmac.hexdigest() print hhmac.hexdigest() with open(sys.argv[1] + '.bin', 'wb') as g: g.write(hdr+ebody) if type == uhx('68'): print 'EAP' body_len = struct.unpack('<L', data[0xc:0x10])[0] body = data[0x80:0x80+body_len] body_aes_key = data[0x30:0x40] ebody = aes_encrypt_cbc(body_aes_key, uhx(ZEROS128[0]), body) body_hmac_key = data[0x40:0x50] bhmac = HMAC.new(body_hmac_key, ebody, SHA) hdr = (data[0:0x50] + uhx(bhmac.hexdigest()) + data[0x64:0x6C]) hhmac = HMAC.new(uhx(HASHERKEYEAP[0]), hdr, SHA) hdr = (hdr + uhx(hhmac.hexdigest())) hdr = eap_encrypt_header(hdr) print bhmac.hexdigest() print hhmac.hexdigest() with open(sys.argv[1] + '.bin', 'wb') as g: g.write(hdr+ebody) if __name__ == '__main__': main(len(sys.argv), sys.argv)
Python Script to Decrypt or Encrypt EAP Kernel[edit source]
#!/usr/bin/env python import sys, os, struct import hashlib, hmac from binascii import unhexlify as uhx from Crypto.Cipher import AES from itertools import cycle try: # Python 2 from itertools import izip except: pass def as_uint32(x): return x & 0xFFFFFFFF def align_up(x, alignment): return (x + (alignment - 1)) & ~(alignment - 1) def align_down(x, alignment): return x & ~(alignment - 1) def sha1(data): return hashlib.sha1(data).digest() def hmac_sha1(key, data): return hmac.new(key=key, msg=data, digestmod=hashlib.sha1).digest() def xor_string(key, data): # Python 2 try: return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in izip(data, cycle(key))) # Python 3 except: return bytes(x ^ y for x, y in zip(data, cycle(key))) def aes_encrypt_ecb(key, input): aes = AES.new(key, AES.MODE_ECB) output = aes.encrypt(input) return output def aes_decrypt_ecb(key, input): aes = AES.new(key, AES.MODE_ECB) output = aes.decrypt(input) return output def aes_encrypt_cbc_cts(key, iv, data): result = b'' size = len(data) if size == 0: return result crypto = AES.new(key, AES.MODE_CBC, iv) size_aligned = align_down(size, crypto.block_size) result = crypto.encrypt(data[:size_aligned]) size_left = size - size_aligned if size_left > 0: assert size_left < crypto.block_size crypto = AES.new(key, AES.MODE_ECB) if size_aligned > AES.block_size: tmp = crypto.encrypt(result[size_aligned - AES.block_size:size_aligned]) else: tmp = crypto.encrypt(iv) result += xor_string(data[size_aligned:], tmp[:size_left]) #assert aes_decrypt_cbc_cts(key, iv, result) == data return result def aes_decrypt_cbc_cts(key, iv, data): result = b'' size = len(data) if size == 0: return result crypto = AES.new(key, AES.MODE_CBC, iv) size_aligned = align_down(size, crypto.block_size) result = crypto.decrypt(data[:size_aligned]) size_left = size - size_aligned if size_left > 0: assert size_left < crypto.block_size crypto = AES.new(key, AES.MODE_ECB) if size_aligned > AES.block_size: tmp = crypto.encrypt(data[size_aligned - AES.block_size:size_aligned]) else: tmp = crypto.encrypt(iv) result += xor_string(data[size_aligned:], tmp[:size_left]) #assert aes_encrypt_cbc_cts(key, iv, result) == data return result if len(sys.argv) < 4: script_file_name = os.path.split(sys.argv[0])[1] print('usage: {0} <input file> <output file> <enc/dec> [personality]'.format(script_file_name)) sys.exit() input_file_path = sys.argv[1] if not os.path.isfile(input_file_path): print('error: invalid input file specified') sys.exit() output_file_path = sys.argv[2] if os.path.exists(output_file_path) and not os.path.isfile(output_file_path): print('error: invalid output file specified') sys.exit() mode = sys.argv[3].lower() if mode != 'enc' and mode != 'dec': print('error: invalid mode') sys.exit() # total = 128 bits, symbol = 6 bits # uid max length = 8 symbols = 48 bits uid_alphabet = ' abcdefghijklmnopqrstuvwxyz' # 5 bits per symbol, 3 bits per byte uid_max_length = 8 def personalize(seed, personality): if len(seed) != 16: return False personality = personality.strip() if len(personality) == 0: print('error: empty personality') return False if len(personality) > uid_max_length: print('error: too large personality') return False personality = personality.lower().ljust(uid_max_length, ' ') seed = list(seed) pos = 0 for c in personality: idx = uid_alphabet.find(c) if idx < 0: print('error: invalid character at personality: {0}'.format(c)) return False c = ord(seed[pos + 0]) & ~0b00010011 c |= (idx & 0b10000) c |= (idx & 0b10) c |= (idx & 0b1) seed[pos + 0] = chr(c) c = ord(seed[pos + 1]) & ~0b00001100 c |= (idx & 0b1000) c |= (idx & 0b100) seed[pos + 1] = chr(c) pos += 2 return ''.join(seed) def unpersonalize(seed): if len(seed) != 16: return False personality = '' seed = list(seed) pos = 0 for i in range(uid_max_length): c1, c2, idx = ord(seed[i * 2 + 0]), ord(seed[i * 2 + 1]), 0 idx |= (c1 & 0b10000) idx |= (c1 & 0b10) idx |= (c1 & 0b1) idx |= (c2 & 0b1000) idx |= (c2 & 0b100) personality += uid_alphabet[idx] return personality seed = os.urandom(16) if len(sys.argv) > 4: seed = personalize(seed, sys.argv[4]) if seed == False: sys.exit() MAGIC = 0x12EBC95C EXPECTED_VERSION = 0x10000 PARTITION_SIZE = 16 * 1024 * 1024 BLOB_MAGIC = 0x4B726E00 SECTOR_SIZE = 0x200 HEADER_FMT = '<II16s20s' BLOB_INFO_FMT = '<III456x' # CP key ENC_KEY = uhx('CBCC1E53F42C1CB44D965E233CD792A8') MAC_KEY = uhx('683D6E2E496687CB5B831DA12BCB001B') if mode == 'dec': with open(input_file_path, 'rb') as f: # read and decrypt blob info magic, version, iv, blob_info_hash = struct.unpack(HEADER_FMT, f.read(struct.calcsize(HEADER_FMT))) if magic != MAGIC: print('error: invalid header magic: {0:08X}'.format(magic)) sys.exit() if version != EXPECTED_VERSION: print('error: invalid version: 0x{0:08X}'.format(version)) sys.exit() #print('iv: {0}'.format(iv.encode('hex').upper())) #personality = unpersonalize(iv) #print('personality: {0}'.format(personality)) data = f.read(SECTOR_SIZE - struct.calcsize(HEADER_FMT)) if data == '' or len(data) != (SECTOR_SIZE - struct.calcsize(HEADER_FMT)): print('error: insufficient blob info data') print(len(data)) print(SECTOR_SIZE - struct.calcsize(HEADER_FMT)) sys.exit() data = aes_decrypt_cbc_cts(ENC_KEY, iv, data) #print(data.encode('hex')) blob_info_calc_hash = hmac_sha1(MAC_KEY, data) if blob_info_calc_hash != blob_info_hash: print('warning: invalid blob info hash') # parse blob info magic, size, offset = struct.unpack(BLOB_INFO_FMT, data[:struct.calcsize(BLOB_INFO_FMT)]) if magic != BLOB_MAGIC: print('error: invalid blob info magic: 0x{0:08X}'.format(magic)) #sys.exit() # read blob data f.seek(offset) data = f.read(size) if data == '' or len(data) != size: print(len(data)) print(size) print('error: insufficient blob data') sys.exit() # decrypt blob magic, version, iv, blob_hash = struct.unpack(HEADER_FMT, data[:struct.calcsize(HEADER_FMT)]) if magic != MAGIC: print('error: invalid header magic: 0x{0:08X}'.format(magic)) sys.exit() if version != EXPECTED_VERSION: print('error: invalid version: 0x{0:08X}'.format(version)) sys.exit() data = aes_decrypt_cbc_cts(ENC_KEY, iv, data[struct.calcsize(HEADER_FMT):]) blob_calc_hash = hmac_sha1(MAC_KEY, data) if blob_calc_hash != blob_hash: print('warning: invalid blob hash') # write blob with open(output_file_path, 'wb') as f: f.write(data) elif mode == 'enc': # generate random iv iv = seed with open(input_file_path, 'rb') as f: # read and encrypt blob data data = f.read() blob_hash = hmac_sha1(MAC_KEY, data) data = aes_encrypt_cbc_cts(ENC_KEY, iv, data) data = struct.pack(HEADER_FMT, MAGIC, EXPECTED_VERSION, iv, blob_hash) + data # generate and encrypt blob info size = len(data) tmp_data = struct.pack(BLOB_INFO_FMT, BLOB_MAGIC, size, SECTOR_SIZE) blob_info_hash = hmac_sha1(MAC_KEY, tmp_data) tmp_data = aes_encrypt_cbc_cts(ENC_KEY, iv, tmp_data) tmp_data = struct.pack(HEADER_FMT, MAGIC, EXPECTED_VERSION, iv, blob_info_hash) + tmp_data # write everything total_size = len(tmp_data) + len(data) with open(output_file_path, 'wb') as f: f.write(tmp_data) f.write(data) padding_size = align_up(total_size, SECTOR_SIZE) - total_size if padding_size > 0: f.write(b'\0' * padding_size) f.seek(PARTITION_SIZE) f.truncate()
Python script to decrypt env.img[edit source]
import sys import struct def unscramble(data): data_size = len(data) num_dwords = data_size // 4 magic = 0x012BB055 # TODO: constant from header @ 0xC new_data = bytearray() for i in range(num_dwords): value = struct.unpack_from('<I', data, i * 4)[0] value, magic = value ^ magic, value new_data += struct.pack('<I', value) return new_data with open(sys.argv[1],"rb") as file: file.seek(0x40) data=file.read(0xFF80) new_data = unscramble(data) with open(sys.argv[2],"wb") as file2: file2.write(new_data)
Portability[edit source]
hid_auth[edit source]
ED E7 41 CC 7F D6 0E 1F 2D B0 89 16 1F C0 EB 66 7C A4 DA 59 40 CE 19 54 00 90 1D BF 59 25 EE 4F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ipmi[edit source]
53 49 45 49 50 4D 49 00 00 00 00 00 00 00 00 00 1A 88 B2 A3 64 E6 A2 8E 78 08 4E 3F 7F 40 FD 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
kdf_ncdt_psk[edit source]
53 43 45 5F 4B 44 46 5F 4E 43 44 54 5F 50 53 4B 59 E6 32 88 B0 4E 7F 68 F8 B8 DB 83 86 1E 07 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
livedump[edit source]
96 1E 5E 85 B5 3E 77 64 43 E5 F4 45 85 E8 90 0A 52 5E 06 2A 4C 79 64 69 0F 75 2F 28 71 9C 6B A1 A8 C2 A0 0D 84 31 E7 17 DD EF 6D 80 F6 5C AE 32 42 1F CB E5 E7 A4 F9 1F 79 2B 25 C7 A1 0C 9E 5A 7B 07 82 9F F3 7C 3F B4 66 2F CB F8 E4 0A 63 F2 99 EE B8 6F 06 D5 58 CD 6E 8E 6A F7 5E 48 3A 24 CC 73 EA E7 73 2F 44 2F 8B E5 28 FB 19 60 62 50 F4 A9 9C A5 9E FC 63 2C 2D CC 67 73 2B 8B 5A DE
logger[edit source]
15 A0 CB 65 D6 A4 05 27 E6 1C CD DA 2A EF 53 3B 13 FC 7C 35 24 14 B3 54 3D C7 83 24 6E FC C9 64 9D F8 40 9A C2 02 09 82 3C 08 61 2B E6 2A 51 79 CF 87 62 61 C0 85 46 C2 A5 DA A1 9B D0 E7 FF 79 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
pfs_sd_auth[edit source]
2B CF 69 8E 79 CF DD FA C2 4D 4C 25 BF 35 1E 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
playready2[edit source]
B6 34 65 57 9E 73 D4 C0 A1 A9 0F F0 51 34 57 50 7A 4A FB 4A 3B 94 B2 19 3A B7 9A 79 C5 66 02 BF 76 51 C1 B9 90 23 37 FF 9A 32 31 6A E6 22 55 47 6F 73 5B 03 C4 6C 89 0B C4 22 A1 68 4D B2 8A 7F 1B AE 90 5E C6 CA 53 38 E7 79 E5 B7 63 DB 84 FB 15 E8 06 B2 9D C7 58 5B BB AF 11 91 6E 66 6E F0 F6 74 CC 4B B7 36 B9 EF 93 AD A9 CB D4 FA 5D 65 C4 F5 5A 98 65 13 4A AB 7D 87 F5 88 5C E2 B3 93
rootparam[edit source]
91 0B 7C A6 6B 4B F9 DA 00 72 F1 67 6C 51 99 70 C1 4D B2 26 6A 59 29 C2 5E 1A 72 5D D8 19 05 BF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
sys_tlm_seck[edit source]
53 43 45 5F 53 59 53 5F 54 4C 4D 5F 53 45 43 4B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 99 E9 AC B7 36 53 5E 4B 25 4D 25 B9 E2 AB 3E 09 CB CB C7 A7 C0 E8 1A EF 93 CF AE E1 57 4C 1A 7C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Fake Keys[edit source]
PK0=C1E20574525331AE3E9ABFDFE3E64EB3AA1FD0CD30E3C286CEB84C0C280574E6 PK1=B8F64A4C3DC41A01C039BD1EBCDA3F9E25461024C8817CA8A0281126521884D0 PK2=5B031A912D8C2C8BACD4A919274827EBF4F855041C6B911DEABD26FCC38B2D86 PK3=53C9558316D34E6036A372BDA0238B4AB2D1B3E22074065BDD22DBC8584AD4C7 PK4=FBF4549BB1278E2336071887439BF819ACBB4292F7DA46729A76217419243C4B PK5=89132F5E01643367499C866DB7B1E7C0C8040EF7DE13516BC7776D97FAB9DB7B PK6=7FF33CBD9689177E5D8FD6BD2AA6BE0553893F63E525447DC5745BB9650CE69A PK7=E4767D540A9E9531BDD3FB2302806A953E6920B15B8AE41C4D471B91422510A8 PK9=A5F56F9B07BD524BE2BFFD2C9AA3D80D070A5A5010BEF863F6C64BFA282B76F9 PK10=0DC5A3E6CF63DD71744F1854A6CBF64C13CE4358AE3C2EBE959C8C3B3F6B79B2 PKA0=3F3B86299E4598147DD1A9A8D314081FE8EE67DDFBAE20 PKA1=2D85350A3BC10ED683101EBBCAC799A5D1B87F6C32A833 PKA2=45DE1F88B189E2D453FEAEA559F02157A21F3DB92C7826 PKA3=B7C26B663BDDE355D1B516B7CE9F0D41A82A61FDC7A6B6 PKA4=6CB6896E6D2C61B33817C2927B032EC7FBE01D0B8BC75E