def decrypt(keyName, isKek, isDsk, sourceKey1, sourceKey2): for key in range(len(master_keys)): # Create the MasterKey Cipher masterKey_cipher = AES.new(uhx(master_keys[key]), AES.MODE_ECB) # Use the MasterKey Cipher to Decrypt the Source Key dec_sourceKey = masterKey_cipher.decrypt(uhx(sourceKey1)) if isKek: # Decrypt the Kek Gen Source dec_kekGenSource = masterKey_cipher.decrypt( uhx(aes_kek_generation_source)) # Create the Kek Cipher kek_cipher = AES.new(uhx(hx(dec_kekGenSource).upper()), AES.MODE_ECB) # Use the Kek Cipher to Decrypt the Source Key dec_keyAreaKey = kek_cipher.decrypt(uhx(sourceKey1)) # Create the Key Cipher key_cipher = AES.new(uhx(hx(dec_keyAreaKey).upper()), AES.MODE_ECB) # Use the Key Cipher to Decrypt the Key Gen Source dec_sourceKey = key_cipher.decrypt(uhx(aes_key_generation_source)) if isDsk: # Create the Dual-Source Key Cipher MSK_cipher = AES.new(uhx(hx(dec_sourceKey).upper()), AES.MODE_ECB) # Use the Dual-Source Key Cipher to Decrypt the Source Key dec_sourceKey2 = MSK_cipher.decrypt(uhx(sourceKey2)) # Print out the Generated Source Key print('%s = %s' % (keyName, hx(dec_sourceKey2).upper())) # Since this only uses Master_Key_00... Stop Processing break # Print out the Generated Source Key [MasterKey Enumerated] print('%s%d = %s' % (keyName, key, hx(dec_sourceKey).upper()))
def parse(self, ncaType=''): f = open(self.path, 'rb') data = {} if self.type == 'SystemUpdate': EntriesNB = read_u16(f, 0x12) for n in range(0x20, 0x10 * EntriesNB, 0x10): titleId = hex(read_u64(f, n))[2:] if len(titleId) != 16: titleId = '%s%s' % ((16 - len(titleId)) * '0', titleId) ver = str(read_u32(f, n + 0x8)) packType = self.packTypes[read_u8(f, n + 0xC)] data[titleId] = ver, packType else: tableOffset = read_u16(f, 0xE) contentEntriesNB = read_u16(f, 0x10) cmetadata = {} for n in range(contentEntriesNB): offset = 0x20 + tableOffset + 0x38 * n hash = hx(read_at(f, offset, 0x20)).decode() titleId = hx(read_at(f, offset + 0x20, 0x10)).decode() size = str(read_u48(f, offset + 0x30)) type = self.ncaTypes[read_u16(f, offset + 0x36)] if type == ncaType or ncaType == '': data[titleId] = type, size, hash f.close() return data
def read_cnmt(self, path = None, mode = 'rb'): cryptoType = self.get_cryptoType() cryptoKey = self.get_cryptoKey() cryptoCounter = self.get_cryptoCounter() r = super(Pfs0, self).open(path, mode, cryptoType, cryptoKey, cryptoCounter) self.rewind() for cnmt in self: f = Fs.factory(cnmt) cnmt.rewind() titleid=f.readInt64() titleversion = cnmt.read(0x4) cnmt.rewind() cnmt.seek(0xE) offset=cnmt.readInt16() content_entries=cnmt.readInt16() meta_entries=cnmt.readInt16() cnmt.rewind() cnmt.seek(0x20) original_ID=cnmt.readInt64() min_sversion=cnmt.readInt64() Print.info('') Print.info('...........................................') Print.info('Reading: ' + str(cnmt._path)) Print.info('...........................................') Print.info('titleid = ' + str(hx(titleid.to_bytes(8, byteorder='big')))) Print.info('version = ' + str(int.from_bytes(titleversion, byteorder='little'))) Print.info('Table offset = '+ str(hx((offset+0x20).to_bytes(2, byteorder='big')))) Print.info('number of content = '+ str(content_entries)) Print.info('number of meta entries = '+ str(meta_entries)) Print.info('Application id\Patch id = ' + str(hx(original_ID.to_bytes(8, byteorder='big')))) Print.info('RequiredSystemVersion = ' + str(min_sversion)) cnmt.rewind() cnmt.seek(0x20+offset)
def extract_nso(path_in, path_out): with open(path_in, 'rb') as f: text_off = read_u32(f, 0x10) text_loc = read_u32(f, 0x14) text_size = read_u32(f, 0x18) text_compressed_size = read_u32(f, 0x60) test_data = b'hello' lz4.block.decompress(lz4.block.compress(test_data)) print('Text offset: {}'.format(text_off)) print('Text compressed size: {}'.format(text_compressed_size)) print('Text uncompressed size: {}'.format(text_size)) compressed_patched_text = read_at(f, text_off, text_compressed_size) print(hx(compressed_patched_text)[0:10]) text = lz4.block.decompress(compressed_patched_text, uncompressed_size=text_size) decompressed_hash = read_at(f, 0xA0, 0x20) calculated_hash = sha256(text) print('Compressed size: {}'.format(text_compressed_size)) print('Decompressed hash: {}'.format(hx(decompressed_hash))) print('Calculated hash: {}'.format(hx(calculated_hash))) if decompressed_hash == calculated_hash: print('Validated decompressed hash') else: print('Failed to validate decompressed hash') return with open(path_out, 'wb') as o: o.write(text)
def read_pfs0_header(self, file=None, mode='rb'): for f in self: cryptoType = f.get_cryptoType() cryptoKey = f.get_cryptoKey() cryptoCounter = f.get_cryptoCounter() pfs0_offset = 0xC00 + self.header.get_htable_offset( ) + self.header.get_pfs0_offset() super(Nca, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter) self.seek(pfs0_offset) pfs0_magic = self.read(4) pfs0_nfiles = self.readInt32() pfs0_table_size = self.readInt32() pfs0_reserved = self.read(0x4) Print.info('PFS0 Magic = ' + str(pfs0_magic)) Print.info('PFS0 number of files = ' + str(pfs0_nfiles)) Print.info('PFS0 string table size = ' + str(hx(pfs0_table_size.to_bytes(4, byteorder='big')))) for i in range(pfs0_nfiles): Print.info('........................') Print.info('PFS0 Content number ' + str(i + 1)) Print.info('........................') f_offset = self.readInt64() Print.info('offset = ' + str(hx(f_offset.to_bytes(8, byteorder='big')))) f_size = self.readInt32() Print.info('Size =\t' + str(hx(pfs0_table_size.to_bytes(4, byteorder='big')))) filename_offset = self.readInt32() Print.info('offset of filename = ' + str(hx(f_offset.to_bytes(8, byteorder='big')))) f_reserved = self.read(0x4)
def get_public_key(key): if key not in public_keys: return None der = public_keys[key] N = int(hx(der[0x18:0x79]), 0x10) E = int(hx(der[0x7B:0x7E]), 0x10) return (N, E, der)
def readhfs0(self): self.seek(0x4) nfiles = self.readInt32() stringTableSize = self.readInt32() self.readInt32() # junk data Print.info("Magic: " + str(self.magic)) Print.info("Number of files: " + str(nfiles)) Print.info("Legth of string table: " + str(hx(stringTableSize.to_bytes(4, byteorder='big')))) for i in range(nfiles): Print.info('........................') Print.info('Content number ' + str(i + 1)) Print.info('........................') file_offset = self.readInt64() file_size = self.readInt64() file_offset_stable = self.readInt32() hashregion = self.readInt32() hashregion = self.read(0x4) self.read(0x8) sha = self.read(0x20) Print.info('File offset: ' + str(hx(file_offset.to_bytes(8, byteorder='big')))) Print.info('Size of file: ' + str(file_size)) Print.info( 'Offset in stringtable: ' + str(hx(file_offset_stable.to_bytes(4, byteorder='big')))) Print.info('Hash Region: ' + str(hx(hashregion.to_bytes(4, byteorder='big')))) Print.info('Sha 256: ' + str(hx(sha)))
def get_titlekeys(tik, tik_size, kp): if tik_size & 0x3FF: print 'Invalid ticket binary!' sys.exit(1) num_tiks = tik_size >> 10 for i in xrange(num_tiks): ofs = i << 10 CA = read_at(tik, ofs + 0x140, 4) if CA == '\x00' * 4: continue if CA != 'Root': print 'Unknown Ticket verifier: %s' % read_str( tik, ofs + 0x140, 0x40) tkey_block = read_at(tik, ofs + 0x180, 0x100) if tkey_block[0x10:] == '\x00' * 0xF0: # Common Ticket titlekey = tkey_block[:0x10] else: # Personalized Ticket titlekey = extract_titlekey(int(hx(tkey_block), 16), kp) if titlekey is not None: print 'Ticket %d:' % i print ' Rights ID: %s' % hx(read_at(tik, ofs + 0x2A0, 0x10)) print ' Title ID: %s' % hx(read_at(tik, ofs + 0x2A0, 8)) print ' Titlekey: %s' % hx(titlekey) return
def printInfo(self, maxDepth=3, indent=0): tabs = '\t' * indent Print.info(tabs + 'magic = ' + str(self.magic)) Print.info(tabs + 'fsType = ' + str(self.fsType)) Print.info(tabs + 'cryptoType = ' + str(self.cryptoType)) Print.info(tabs + 'size = ' + str(self.size)) Print.info(tabs + 'offset = %s - (%s)' % (str(self.offset), str(self.sectionStart))) if self.cryptoCounter: Print.info(tabs + 'cryptoCounter = ' + str(hx(self.cryptoCounter))) if self.cryptoKey: Print.info(tabs + 'cryptoKey = ' + str(hx(self.cryptoKey))) if self.cryptoKey: Print.info(tabs + 'cryptoKey = ' + str(hx(self.cryptoKey))) Print.info('\n%s\t%s\n' % (tabs, '*' * 64)) Print.info('\n%s\tFiles:\n' % (tabs)) if (indent + 1 < maxDepth): for f in self: f.printInfo(maxDepth, indent + 1) Print.info('\n%s\t%s\n' % (tabs, '*' * 64)) if self.bktrRelocation: self.bktrRelocation.printInfo(maxDepth, indent + 1) if self.bktrSubsection: self.bktrSubsection.printInfo(maxDepth, indent + 1)
def restore(self): header = self.getVerifiedHeader() if not header: raise IOError('could not restore nca header for %s - %s' % (self.titleId, str(self.f._path))) if not self.hasTitleRights(): if header[0x30:0x40] != b'\x00' * 0x10: self.rightsId = hx(header[0x30:0x40]) key = hx( Keys.encryptTitleKey( self.key(), max(max(header[0x6], header[0x20]) - 1, 0))).decode().upper() #key = hx(self.key()).decode().upper() title = Titles.get(self.titleId) if title.key and title.key != key: raise IOError( 'nca title key does not match database: %s vs %s' % (title.key, key)) elif not title.key: title.key = key else: self.rightsId = b'0' * 32 self.seek(0x200) self.write(header) return True
def open(self, file=None, mode='rb', cryptoType=-1, cryptoKey=-1, cryptoCounter=-1): super(Ticket, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter) self.rewind() self.signatureType = self.readInt32() try: self.signatureType = Type.TicketSignature(self.signatureType) except: raise IOError('Invalid ticket format') self.signaturePadding = 0x40 - ( (self.signatureSizes[self.signatureType] + 4) % 0x40) self.seek(0x4 + self.signatureSizes[self.signatureType] + self.signaturePadding) self.issuer = self.read(0x40) self.titleKeyBlock = self.read(0x100) self.readInt8() # unknown self.keyType = self.readInt8() self.read(0x4) # unknown self.masterKeyRevision = self.readInt8() self.read(0x9) # unknown self.ticketId = hx(self.read(0x8)).decode('utf-8') self.deviceId = hx(self.read(0x8)).decode('utf-8') self.rightsId = hx(self.read(0x10)).decode('utf-8') self.accountId = hx(self.read(0x4)).decode('utf-8') self.seek(0x286) self.masterKeyRevision = self.readInt8()
def main(argc, argv): with open(sys.argv[1], 'rb') as f: data = f.read() data1 = data[0x4E0:0x500] data2 = data[0x500:0x520] data3 = data[0x520:0x540] data4 = data[0x540:0x560] eid1 = data[0x10:0x290] hash = data[0x290:0x2A0] cmac1= CMAC.new(uhx(EID1KEYS[0]), ciphermod=AES) cmac1.update(eid1) print(hx(hash)) print(cmac1.hexdigest()) sexy = aes_decrypt_cbc(uhx(EID1KEYS[0]), uhx(ZEROS128[0]), eid1) keyseed = sexy[0x150:0x160] pck1 = aes_encrypt_cbc(uhx(TIMEKEYS[0]), uhx(ZEROS128[0]), keyseed) pck2 = aes_encrypt_cbc(uhx(TIMEKEYS[1]), uhx(ZEROS128[0]), keyseed) pck3 = aes_encrypt_cbc(uhx(TIMEKEYS[2]), uhx(ZEROS128[0]), keyseed) pck4 = aes_encrypt_cbc(uhx(TIMEKEYS[3]), uhx(ZEROS128[0]), keyseed) data1_stage1 = aes_decrypt_ecb(pck1,data1) data1_body = data1_stage1[:0x10] data1_stage2 = aes_decrypt_ecb(uhx(TIMEFINALS[0]),data1_stage1)[:0x10] data1_omac = data1_stage1[0x10:] cmac2= CMAC.new(uhx(TIMEFINALS[0]), ciphermod=AES) cmac2.update(data1_body) print(hx(data1_omac)) print(cmac2.hexdigest()) with open(sys.argv[1] + '.eid1.dec.bin', 'wb') as g: g.write(sexy) with open(sys.argv[1] + '.time1.dec.bin', 'wb') as g: g.write(data1_stage2)
def get_new_cryptoblock(ncaHeader, newMasterKeyRev,encKeyBlock,t): indent = 1 tabs = '\t' * indent indent2 = 2 tabs2 = '\t' * indent2 masterKeyRev = ncaHeader.getCryptoType2() if type(ncaHeader) == NcaHeader(): if ncaHeader.getCryptoType2() != newMasterKeyRev: t.write(tabs + '-----------------------------------') t.write(tabs + 'Changing keygeneration from %d to %s' % ( ncaHeader.getCryptoType2(), str(newMasterKeyRev))) t.write(tabs + '-----------------------------------') if sum(encKeyBlock) != 0: key = Keys.keyAreaKey(Keys.getMasterKeyIndex(masterKeyRev),ncaHeader.keyIndex) t.write(tabs2 + '+ decrypting with %s (%d, %d)' % (str(hx(key)), Keys.getMasterKeyIndex(masterKeyRev), ncaHeader.keyIndex)) crypto = aes128.AESECB(key) decKeyBlock = crypto.decrypt(encKeyBlock) key = Keys.keyAreaKey(Keys.getMasterKeyIndex(newMasterKeyRev),ncaHeader.keyIndex) t.write(tabs2 + '+ encrypting with %s (%d, %d)' % (str(hx(key)), Keys.getMasterKeyIndex(newMasterKeyRev), ncaHeader.keyIndex)) crypto = aes128.AESECB(key) reEncKeyBlock = crypto.encrypt(decKeyBlock) encKeyBlock = reEncKeyBlock if newMasterKeyRev >= 3: crypto1=2 crypto2=newMasterKeyRev if newMasterKeyRev == 2: crypto1=2 crypto2=0 if newMasterKeyRev < 2: crypto1=newMasterKeyRev crypto2=0 return encKeyBlock,crypto1,crypto2 return encKeyBlock,ncaHeader.getCryptoType(),ncaHeader.getCryptoType2()
def read_cnmt(self, file=None, mode='rb'): for f in self: cryptoType = f.get_cryptoType() cryptoKey = f.get_cryptoKey() cryptoCounter = f.get_cryptoCounter() pfs0_offset = 0xC00 + self.header.get_htable_offset( ) + self.header.get_pfs0_offset() super(Nca, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter) self.seek(pfs0_offset + 0x8) pfs0_table_size = self.readInt32() cmt_offset = pfs0_offset + 0x28 + pfs0_table_size self.seek(cmt_offset) titleid = self.readInt64() titleversion = self.read(0x4) self.seek(cmt_offset + 0xE) offset = self.readInt16() content_entries = self.readInt16() meta_entries = self.readInt16() self.seek(cmt_offset + 0x20) original_ID = self.readInt64() self.seek(cmt_offset + 0x28) min_sversion = self.readInt32() end_of_emeta = self.readInt32() Print.info('') Print.info('...........................................') Print.info('Reading: ' + str(self._path)) Print.info('...........................................') Print.info('titleid = ' + str(hx(titleid.to_bytes(8, byteorder='big')))) Print.info('version = ' + str(int.from_bytes(titleversion, byteorder='little'))) Print.info('Table offset = ' + str(hx((offset + 0x20).to_bytes(2, byteorder='big')))) Print.info('number of content = ' + str(content_entries)) Print.info('number of meta entries = ' + str(meta_entries)) Print.info('Application id\Patch id = ' + str(hx(original_ID.to_bytes(8, byteorder='big')))) Print.info('RequiredVersion = ' + str(min_sversion)) self.seek(cmt_offset + offset + 0x20) for i in range(content_entries): Print.info('........................') Print.info('Content number ' + str(i + 1)) Print.info('........................') vhash = self.read(0x20) Print.info('hash =\t' + str(hx(vhash))) NcaId = self.read(0x10) Print.info('NcaId =\t' + str(hx(NcaId))) size = self.read(0x6) Print.info( 'Size =\t' + str(int.from_bytes(size, byteorder='little', signed=True))) ncatype = self.read(0x1) Print.info( 'ncatype = ' + str(int.from_bytes(ncatype, byteorder='little', signed=True))) unknown = self.read(0x1)
def serialize(self): obj = {} obj['titleId'] = self.titleId obj['titleKey'] = self.titleKey obj['ncaHeader'] = hx(self.ncaHeader).decode() obj['sectionHeaderBlock'] = hx(self.sectionHeaderBlock).decode() obj['pfs0Header'] = hx(self.pfs0Header).decode() obj['pfs0Offset'] = self.pfs0Offset return obj
def open(self, file=None, mode='rb', cryptoType=-1, cryptoKey=-1, cryptoCounter=-1): super(Cnmt, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter) self.rewind() self.titleId = hx(self.read(8)[::-1]).decode() self.version = self.readInt32() self.titleType = self.readInt8() self.readInt8() # junk self.headerOffset = self.readInt16() self.contentEntryCount = self.readInt16() self.metaEntryCount = self.readInt16() self.metaAttributes = self.readInt8() self.contentEntries = [] self.metaEntries = [] self.seek(0x18) self.requiredDownloadSystemVersion = self.readInt32() self.seek(0x20) self.requiredSystemVersion = None self.requiredApplicationVersion = None self.otherApplicationId = None if self.titleType == 0x80: #base self.otherApplicationId = hx(self.read(8)[::-1]).decode() self.requiredSystemVersion = self.readInt32() self.requiredApplicationVersion = self.readInt32() if self.titleType == 0x81: #patch self.otherApplicationId = hx(self.read(8)[::-1]).decode() self.requiredSystemVersion = self.readInt32() if self.titleType == 0x82: #DLC self.otherApplicationId = hx(self.read(8)[::-1]).decode() self.requiredApplicationVersion = self.readInt32() self.seek(0x20 + self.headerOffset) for i in range(self.contentEntryCount): self.contentEntries.append(ContentEntry(self)) for i in range(self.metaEntryCount): self.metaEntries.append(MetaEntry(self))
def print_nsp_info(path): nsp = PFS0(path) tik_entry = nsp.get_file_entry_by_extension('tik') if tik_entry is None: print('NSP is missing a tik file!') sys.exit() tik_data = tik_entry.read_data() title_key = hx(tik_data[0x180:0x190]).decode('utf-8') rights_id = hx(tik_data[0x2A0:0x2B0]).decode('utf-8') print('{}|{}|{}'.format(rights_id, title_key, path.stem)) time.sleep(5)
def get_ssl_privk(cal0): ssl_kek = uhx('B011............................') cal0.seek(0x0AE0) sec_block = cal0.read(0x800) with open('clcert.der', 'wb') as cert: cert.write(sec_block) cal0.seek(0x3AE0) ctr = Counter.new(128, initial_value=int(hx(cal0.read(0x10)), 16)) dec = AES.new(ssl_kek, AES.MODE_CTR, counter=ctr).decrypt(cal0.read(0x120)) privk = hx(dec[:0x100]) with open('privk.bin', 'wb') as out: out.write(uhx(privk)) return None
def open(self, file=None, mode='rb', cryptoType=-1, cryptoKey=-1, cryptoCounter=-1): super(Cnmt, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter) self.rewind() self.titleId = hx(self.read(8)[::-1]).decode() self.version = self.readInt32() self.titleType = self.readInt8() self.IdOffset = self.readInt8() self.headerOffset = self.readInt16() self.contentEntryCount = self.readInt16() self.metaEntryCount = self.readInt16() self.contentEntries = [] self.metaEntries = [] self.seek(0x20 + self.headerOffset) for i in range(self.contentEntryCount): self.contentEntries.append(ContentEntry(self)) for i in range(self.metaEntryCount): self.metaEntries.append(MetaEntry(self))
def __init__(self, f): self.hash = f.read(32) self.ncaId = hx(f.read(16)).decode() self.size = f.readInt48() self.type = f.readInt8() f.readInt8() # junk
def printInfo(self, maxDepth=3, indent=0): tabs = '\t' * indent rightsId = format(self.getRightsId(), 'X').zfill(32) titleId = rightsId[0:16] titleKey = format(self.getTitleKeyBlock(), 'X').zfill(32) Print.info('\n%sTicket\n' % (tabs)) super(Ticket, self).printInfo(maxDepth, indent) Print.info(tabs + 'signatureType = ' + str(self.signatureType)) Print.info(tabs + 'keyType = ' + str(self.keyType)) Print.info(tabs + 'masterKeyRev = ' + str(self.masterKeyRevision)) Print.info(tabs + 'ticketId = ' + str(self.ticketId)) Print.info(tabs + 'deviceId = ' + str(self.deviceId)) Print.info(tabs + 'rightsId = ' + rightsId) Print.info(tabs + 'accountId = ' + str(self.accountId)) Print.info(tabs + 'titleId = ' + titleId) Print.info(tabs + 'titleKey = ' + titleKey) Print.info(tabs + 'titleKeyDec = ' + str( hx( Keys.decryptTitleKey( (self.getTitleKey()), self.masterKeyRevision)))) try: if blockchain.verifyKey(titleId, titleKey): tkeyStatus = 'VERIFIED' else: tkeyStatus = 'BAD KEY' except BaseException as e: tkeyStatus = 'UNKNOWN - ' + str(e) raise Print.info(tabs + 'titleKeyStatus = ' + tkeyStatus)
def get_key(url): file=location(url) res=file.response;readable=file.readable;output=file.name if not readable: return False else: clean_name=untag(output) files_list=get_files_from_head(file,output) for i in range(len(files_list)): if (files_list[i][0]).endswith('.tik'): #print(files_list[i][0]) #print(files_list[i][1]) #print(files_list[i][2]) off1=files_list[i][1] off2=files_list[i][2] sz=files_list[i][3] trights=((files_list[i][0])[:-4]).upper() #print(trights) file.rewind() file.seek(off1,sz) buf=int(sz) try: data=file.read(buf) tk=str(hx(data[0x180:0x190])) tk=tk.upper();tk=tk[2:-1] #print(tk) print('TRIGHTS STRING: ') print(trights+'|'+tk+'|'+clean_name) except IOError as e: print(e, file=sys.stderr)
def printInfo(self, indent=0): tabs = '\t' * indent Print.info('\n%sNCA Archive\n' % (tabs)) super(Nca, self).printInfo(indent) #Print.info(tabs + 'Header Block Hash: ' + str(hx(self.header.get_hblock_hash()))) #self.header.calculate_hblock_hash() #self.get_hblock() #self.calc_htable_hash() #Print.info('hash from pfs0: ' + str(hx(self.get_pfs0_hash()))) #self.calc_pfs0_hash() #self.get_req_system() #self.write_req_system() #Print.info(tabs + 'RSA-2048 signature 1 = ' + str(hx(self.header.signature1))) #Print.info(tabs + 'RSA-2048 signature 2 = ' + str(hx(self.header.signature2))) Print.info(tabs + 'magic = ' + str(self.header.magic)) Print.info(tabs + 'titleId = ' + str(self.header.titleId)) Print.info(tabs + 'rightsId = ' + str(self.header.rightsId)) Print.info(tabs + 'isGameCard = ' + hex(self.header.isGameCard)) Print.info(tabs + 'contentType = ' + str(self.header.contentType)) #Print.info(tabs + 'cryptoType = ' + str(self.header.getCryptoType())) Print.info(tabs + 'SDK version = ' + str(self.header.sdkVersion)) Print.info(tabs + 'Size: ' + str(self.header.size)) Print.info(tabs + 'Crypto-Type1: ' + str(self.header.cryptoType)) Print.info(tabs + 'Crypto-Type2: ' + str(self.header.cryptoType2)) Print.info(tabs + 'key Index: ' + str(self.header.keyIndex)) #Print.info(tabs + 'key Block: ' + str(self.header.getKeyBlock())) for key in self.header.keys: Print.info(tabs + 'key Block: ' + str(hx(key))) Print.info('\n%sPartitions:' % (tabs)) for s in self: s.printInfo(indent + 1)
def __init__(self, f): self.titleId = hx(f.read(8)[::-1]).decode() self.version = f.readInt32() self.type = f.readInt8() self.install = f.readInt8() f.readInt16() # junk
def fix_baseid(dbfile): Datashelve = Dict(dbfile) for k in Datashelve.keys(): try: entry = Datashelve[k] if entry['id'] != '-': if str(entry['id'])[-3:] == '000': entry['baseid'] = entry['id'] elif str(entry['id'])[-3:] == '800': entry['baseid'] = str(entry['id'])[:-3] + '000' #print(entry['id']) #print(entry['baseid']) else: fileid = str(entry['id']) DLCnumb = fileid token = int(hx(bytes.fromhex('0' + DLCnumb[-4:-3])), 16) - int('1', 16) token = str(hex(token))[-1] token = token.upper() fileid = fileid[:-4] + token + '000' entry['baseid'] = fileid Datashelve[k] = entry print('- Added baseid: ' + entry['baseid']) except: pass Datashelve.close()
def __init__(self, fPath): self.packTypes = { 0x1: 'SystemProgram', 0x2: 'SystemData', 0x3: 'SystemUpdate', 0x4: 'BootImagePackage', 0x5: 'BootImagePackageSafe', 0x80: 'Application', 0x81: 'Patch', 0x82: 'AddOnContent', 0x83: 'Delta' } self.ncaTypes = { 0: 'Meta', 1: 'Program', 2: 'Data', 3: 'Control', 4: 'HtmlDocument', 5: 'LegalInformation', 6: 'DeltaFragment' } f = open(fPath, 'rb') self.path = fPath self.type = self.packTypes[read_u8(f, 0xC)] self.id = '0%s' % format(read_u64(f, 0x0), 'x') self.ver = str(read_u32(f, 0x8)) self.sysver = str(read_u64(f, 0x28)) self.dlsysver = str(read_u64(f, 0x18)) self.digest = hx(read_at(f, f.seek(0, 2) - 0x20, f.seek(0, 2))).decode() f.close()
def self_header(file): # MAGIC = 4F 15 3D 1D # MAGIC, VERSION, MODE, ENDIAN, ATTRIBUTES FMT = '<4s4B' MAGIC, VERSION, MODE, ENDIAN, ATTRIBUTES = struct.unpack( FMT, file.read(struct.calcsize(FMT))) print('\n[SELF Header]') print('Magic: 0x%s' % hx(MAGIC).upper()) print('Version: %d' % VERSION) print('Mode: 0x%X' % MODE) print('Endian: %d (%s)' % (ENDIAN, 'Little Endian' if ENDIAN == 1 else 'Unknown')) print('Attributes: 0x%X' % ATTRIBUTES) # KEY TYPE, HEADER SIZE, META SIZE, FILE SIZE, ENTRY COUNT, FLAG, 4x PADDING EXTENDED_FMT = '<I2HQ2H4x' KEY_TYPE, HEADER_SIZE, META_SIZE, FILE_SIZE, ENTRY_COUNT, FLAG = struct.unpack( EXTENDED_FMT, file.read(struct.calcsize(EXTENDED_FMT))) print('\n[SELF Extended Header]') print('Key Type: 0x%X' % KEY_TYPE) print('Header Size: 0x%X' % HEADER_SIZE) print('Meta Size: %d Bytes' % META_SIZE) print('File Size: %d Bytes' % FILE_SIZE) print('Entry Count: %d' % ENTRY_COUNT) print('Flag: 0x%X' % FLAG) return ENTRY_COUNT
def printInfo(self, maxDepth=3, indent=0): tabs = '\t' * indent Print.info('\n%sNCA Archive\n' % (tabs)) super(Nca, self).printInfo(maxDepth, indent) Print.info(tabs + 'magic = ' + str(self.header.magic)) Print.info(tabs + 'titleId = ' + str(self.header.titleId)) Print.info(tabs + 'rightsId = ' + str(self.header.rightsId)) Print.info(tabs + 'isGameCard = ' + hex(self.header.isGameCard)) Print.info(tabs + 'contentType = ' + str(self.header.contentType)) Print.info(tabs + 'cryptoType = ' + str(self.cryptoType)) Print.info(tabs + 'Size: ' + str(self.header.size)) Print.info(tabs + 'crypto master key: ' + str(self.header.cryptoType)) Print.info(tabs + 'crypto master key2: ' + str(self.header.cryptoType2)) Print.info(tabs + 'key Index: ' + str(self.header.keyIndex)) #Print.info(tabs + 'key Block: ' + str(self.header.getKeyBlock())) for key in self.header.keys: if key: Print.info(tabs + 'key Block: ' + str(hx(key))) if (indent + 1 < maxDepth): Print.info('\n%sPartitions:' % (tabs)) for s in self: s.printInfo(maxDepth, indent + 1) if self.header.contentType == Fs.Type.Content.PROGRAM: Print.info(tabs + 'build Id: ' + str(self.buildId()))
def self_extended_information(file): # AUTHENTICATION ID, PROGRAM TYPE, APPLICATION VERSION, FIRMWARE VERSION, DIGEST FMT = '<4Q32s' AUTHENTICATION_ID, TYPE, APPLICATION_VERSION, FIRMWARE_VERSION, DIGEST = struct.unpack( FMT, file.read(struct.calcsize(FMT))) TYPES = { 0x1: 'PT_FAKE', 0x4: 'PT_NPDRM_EXEC', 0x5: 'PT_NPDRM_DYNLIB', 0x8: 'PT_SYSTEM_EXEC', 0x9: 'PT_SYSTEM_DYNLIB', 0xC: 'PT_HOST_KERNEL', 0xE: 'PT_SECURE_MODULE', 0xF: 'PT_SECURE_KERNEL' } print('\n[SELF Extended Information]') print('Authentication ID: 0x%X' % AUTHENTICATION_ID) print('Type: 0x%X (%s)' % (TYPE, TYPES.get(TYPE, 'Unknown'))) print('Application Version: 0x%X' % APPLICATION_VERSION) print('Firmware Version: 0x%X' % FIRMWARE_VERSION) print('Digest: %s' % hx(DIGEST).upper()) if TYPE in {0x4, 0x5}: return True return False
def get_dlc_baseid(titleid): baseid = str(titleid) token = int(hx(bytes.fromhex('0' + baseid[-4:-3])), 16) - int('1', 16) token = str(hex(token))[-1] token = token.upper() baseid = baseid[:-4] + token + '000' return baseid
def gen_kat1(password, name): kats = [] length = 4 for name, H in zip(*HH): expected = s2k(password, H=H, outlen=length) kats.append(SIMPLE_TEMPLATE.format(expected=hx(expected), hash_name=name, length=length)) expected = s2k(password, TEST_SALT, H=H, outlen=length) kats.append(SALTED_TEMPLATE.format(expected=hx(expected), hash_name=name, length=length)) for c in range(3): expected = s2k(password, TEST_SALT, c=c, H=H, outlen=length) kats.append(ITERATED_TEMPLATE.format(expected=hx(expected), hash_name=name, count=c, length=length)) short_output = '\n'.join(kats) kats = [] length = 32 for name, H in zip(*HH): expected = s2k(password, H=H, outlen=length) kats.append(SIMPLE_TEMPLATE.format(expected=hx(expected), hash_name=name, length=length)) expected = s2k(password, TEST_SALT, H=H, outlen=length) kats.append(SALTED_TEMPLATE.format(expected=hx(expected), hash_name=name, length=length)) for c in range(3): expected = s2k(password, TEST_SALT, c=c, H=H, outlen=length) kats.append(ITERATED_TEMPLATE.format(expected=hx(expected), hash_name=name, count=c, length=length)) long_output = '\n'.join(kats) return KAT_TEMPLATE_1.format(password=password, name=name, short_output=short_output, long_output=long_output)
def test_kats(): for expected, test in TESTS: if hx(s2k(*test)) != expected: raise Exception()