Editing Talk:Keys

Jump to navigation Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
= Script to Decrypt CP Box EMC blob and preserve header =
= Python Script to decrypt CP Box EMC blob and preserve header =


* (trim 0x80 bytes, entrypoint at 0x100C00)
* (trim 0x80 bytes, entrypoint at 0x100C00)


<source lang="python3">
<pre>
import struct
import struct
from binascii import unhexlify as uhx
from binascii import unhexlify as uhx
Line 14: Line 14:


CIPHERKEYSEMC = ['F0332357C8CFAE7E7E26E52BE9E3AED4']
CIPHERKEYSEMC = ['F0332357C8CFAE7E7E26E52BE9E3AED4']
CIPHERKEYSEAP = ['262555E3CF062B070B5AA2CDDF3A5D0E']
CIPHERKEYSEAP = ['00000000000000000000000000000000']
HASHERKEYEMC  = ['00000000000000000000000000000000']
HASHERKEYEMC  = ['00000000000000000000000000000000']
HASHERKEYEAP  = ['1EE22F6A189E7D99A28B9A96D3C4DBA2']
HASHERKEYEAP  = ['00000000000000000000000000000000']
ZEROS128 =      ['00000000000000000000000000000000']
ZEROS128 =      ['00000000000000000000000000000000']


Line 90: Line 90:
if __name__ == '__main__':
if __name__ == '__main__':
     main(len(sys.argv), sys.argv)
     main(len(sys.argv), sys.argv)
</source>
</pre>


= Script to Encrypt CP Box EMC blob (Requires Header from Decrypt Script) =
= Portability =


<source lang="python3">
== hid_auth ==
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)
</source>
 
= Script to Decrypt or Encrypt EAP Kernel =
 
<source lang="python3">
#!/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):
<pre>
    if len(seed) != 16:
ED E7 41 CC 7F D6 0E 1F 2D B0 89 16 1F C0 EB 66
        return False
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
</pre>


    personality = ''
== ipmi ==
    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)
<pre>
        idx |= (c1 & 0b10)
53 49 45 49 50 4D 49 00 00 00 00 00 00 00 00 00
        idx |= (c1 & 0b1)
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
</pre>


        idx |= (c2 & 0b1000)
== kdf_ncdt_psk ==
        idx |= (c2 & 0b100)


        personality += uid_alphabet[idx]
<pre>
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
</pre>


    return personality
== livedump ==


seed = os.urandom(16)
<pre>
if len(sys.argv) > 4:
96 1E 5E 85 B5 3E 77 64 43 E5 F4 45 85 E8 90 0A
    seed = personalize(seed, sys.argv[4])
52 5E 06 2A 4C 79 64 69 0F 75 2F 28 71 9C 6B A1
    if seed == False:
A8 C2 A0 0D 84 31 E7 17 DD EF 6D 80 F6 5C AE 32
        sys.exit()
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
</pre>


MAGIC = 0x12EBC95C
== logger ==
EXPECTED_VERSION = 0x10000
PARTITION_SIZE = 16 * 1024 * 1024
BLOB_MAGIC = 0x4B726E00
SECTOR_SIZE = 0x200
HEADER_FMT = '<II16s20s'
BLOB_INFO_FMT = '<III456x'


# CP key
<pre>
ENC_KEY = uhx('CBCC1E53F42C1CB44D965E233CD792A8')
15 A0 CB 65 D6 A4 05 27 E6 1C CD DA 2A EF 53 3B
MAC_KEY = uhx('683D6E2E496687CB5B831DA12BCB001B')
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
</pre>


if mode == 'dec':
== pfs_sd_auth ==
    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
<pre>
        magic, size, offset = struct.unpack(BLOB_INFO_FMT, data[:struct.calcsize(BLOB_INFO_FMT)])
2B CF 69 8E 79 CF DD FA C2 4D 4C 25 BF 35 1E 62
        if magic != BLOB_MAGIC:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
            print('error: invalid blob info magic: 0x{0:08X}'.format(magic))
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
            #sys.exit()
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
</pre>


        # read blob data
== playready2 ==
        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
<pre>
    magic, version, iv, blob_hash = struct.unpack(HEADER_FMT, data[:struct.calcsize(HEADER_FMT)])
B6 34 65 57 9E 73 D4 C0 A1 A9 0F F0 51 34 57 50
    if magic != MAGIC:
7A 4A FB 4A 3B 94 B2 19 3A B7 9A 79 C5 66 02 BF
        print('error: invalid header magic: 0x{0:08X}'.format(magic))
76 51 C1 B9 90 23 37 FF 9A 32 31 6A E6 22 55 47
        sys.exit()
6F 73 5B 03 C4 6C 89 0B C4 22 A1 68 4D B2 8A 7F
    if version != EXPECTED_VERSION:
1B AE 90 5E C6 CA 53 38 E7 79 E5 B7 63 DB 84 FB
        print('error: invalid version: 0x{0:08X}'.format(version))
15 E8 06 B2 9D C7 58 5B BB AF 11 91 6E 66 6E F0
        sys.exit()
F6 74 CC 4B B7 36 B9 EF 93 AD A9 CB D4 FA 5D 65
    data = aes_decrypt_cbc_cts(ENC_KEY, iv, data[struct.calcsize(HEADER_FMT):])
C4 F5 5A 98 65 13 4A AB 7D 87 F5 88 5C E2 B3 93
    blob_calc_hash = hmac_sha1(MAC_KEY, data)
</pre>
    if blob_calc_hash != blob_hash:
        print('warning: invalid blob hash')


    # write blob
== rootparam ==  
    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:
<pre>
        # read and encrypt blob data
91 0B 7C A6 6B 4B F9 DA 00 72 F1 67 6C 51 99 70
        data = f.read()
C1 4D B2 26 6A 59 29 C2 5E 1A 72 5D D8 19 05 BF
        blob_hash = hmac_sha1(MAC_KEY, data)
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        data = aes_encrypt_cbc_cts(ENC_KEY, iv, data)
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        data = struct.pack(HEADER_FMT, MAGIC, EXPECTED_VERSION, iv, blob_hash) + data
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
</pre>


        # generate and encrypt blob info
== sys_tlm_seck ==
        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
<pre>
    total_size = len(tmp_data) + len(data)
53 43 45 5F 53 59 53 5F 54 4C 4D 5F 53 45 43 4B
    with open(output_file_path, 'wb') as f:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        f.write(tmp_data)
99 E9 AC B7 36 53 5E 4B 25 4D 25 B9 E2 AB 3E 09
        f.write(data)
CB CB C7 A7 C0 E8 1A EF 93 CF AE E1 57 4C 1A 7C
        padding_size = align_up(total_size, SECTOR_SIZE) - total_size
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        if padding_size > 0:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
            f.write(b'\0' * padding_size)
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        f.seek(PARTITION_SIZE)
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        f.truncate()
</pre>
</source>
 
= Script to Decrypt env.img =
 
<source lang="python3">
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)
</source>


= Fake Keys =
= Fake Keys =
This section should explain in what the following keys are fake.


<pre>
<pre>
Please note that all contributions to PS5 Developer wiki are considered to be released under the GNU Free Documentation License 1.2 (see PS5 Developer wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)