def gen_xci_parts_spec1(filepath=None, remote=None, target_cnmt=None, cachefolder=None, keypatch=False, files_list=None): if filepath == "": filepath = None if remote == "": remote = None if remote == None: test = filepath.split('|') TD = None if len(test) < 2: filepath = test[0] lib, TD, libpath = get_library_from_path(remote_lib_file, filepath) else: filepath = test[0] TD = test[1] if str(TD).upper() == "NONE": TD = None ID, name, type, size, md5, remote = DrivePrivate.get_Data(filepath, TD=TD, Print=False) if keypatch != False: try: keypatch = int(keypatch) except: keypatch = False if cachefolder == None: cachefolder = os.path.join(ztools_dir, '_mtp_cache_') if not os.path.exists(cachefolder): os.makedirs(cachefolder) else: for f in os.listdir(cachefolder): fp = os.path.join(cachefolder, f) try: shutil.rmtree(fp) except OSError: os.remove(fp) if files_list == None: files_list = DriveTools.get_files_from_head(remote, remote.name) files = list() filesizes = list() fplist = list() for k in range(len(files_list)): entry = files_list[k] fplist.append(entry[0]) if target_cnmt == None: for i in range(len(files_list)): entry = files_list[i] cnmtfile = entry[0] if cnmtfile.endswith('.cnmt.nca'): target_cnmt = cnmtfile break for i in range(len(files_list)): entry = files_list[i] cnmtfile = entry[0] if cnmtfile.endswith('.cnmt.nca') and target_cnmt == cnmtfile: metadict, d1, d2 = DriveTools.get_cnmt_data(target=cnmtfile, file=remote) ncadata = metadict['ncadata'] for j in range(len(ncadata)): row = ncadata[j] if row['NCAtype'] != 'Meta' and row['NCAtype'] != 'Program': test1 = str(row['NcaId']) + '.nca' test2 = str(row['NcaId']) + '.ncz' if test1 in fplist: files.append(str(row['NcaId']) + '.nca') filesizes.append(int(row['Size'])) elif test2 in fplist: files.append(str(row['NcaId']) + '.ncz') for k in range(len(files_list)): entry = files_list[k] if entry[0] == test2: filesizes.append(int(entry[3])) break for j in range(len(ncadata)): row = ncadata[j] if row['NCAtype'] == 'Meta': # print(str(row['NcaId'])+'.cnmt.nca') files.append(str(row['NcaId']) + '.cnmt.nca') filesizes.append(int(row['Size'])) for j in range(len(ncadata)): row = ncadata[j] # print(row) if row['NCAtype'] == 'Program': test1 = str(row['NcaId']) + '.nca' test2 = str(row['NcaId']) + '.ncz' if test1 in fplist: files.append(str(row['NcaId']) + '.nca') filesizes.append(int(row['Size'])) elif test2 in fplist: files.append(str(row['NcaId']) + '.ncz') for k in range(len(files_list)): entry = files_list[k] if entry[0] == test2: filesizes.append(int(entry[3])) break break remote.rewind() outheader = sq_tools.gen_nsp_header(files, filesizes) properheadsize = len(outheader) # print(properheadsize) # print(bucketsize) i = 0 sum = properheadsize outfile = os.path.join(cachefolder, "0") outf = open(outfile, 'w+b') outf.write(outheader) written = 0 for fi in files: if fi.endswith('nca') or fi.endswith('ncz'): for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(fi).lower(): nca_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] nca_size = files_list[i][3] break data = remote.read_at(off1, nca_size) ncaHeader = NcaHeader() ncaHeader.open( MemoryFile(remote.read_at(off1, 0x400), FsType.Crypto.XTS, uhx(Keys.get('header_key')))) crypto1 = ncaHeader.getCryptoType() crypto2 = ncaHeader.getCryptoType2() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 crypto = aes128.AESECB( Keys.keyAreaKey(Keys.getMasterKeyIndex(masterKeyRev), ncaHeader.keyIndex)) hcrypto = aes128.AESXTS(uhx(Keys.get('header_key'))) gc_flag = '00' * 0x01 crypto1 = ncaHeader.getCryptoType() crypto2 = ncaHeader.getCryptoType2() if ncaHeader.getRightsId() != 0: ncaHeader.rewind() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 titleKeyDec = Keys.decryptTitleKey( titleKey, Keys.getMasterKeyIndex(int(masterKeyRev))) encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < ncaHeader.getCryptoType2(): encKeyBlock, crypto1, crypto2 = get_new_cryptoblock( ncaHeader, keypatch, encKeyBlock, t) t.close() if ncaHeader.getRightsId() == 0: ncaHeader.rewind() encKeyBlock = ncaHeader.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < ncaHeader.getCryptoType2(): encKeyBlock, crypto1, crypto2 = get_new_cryptoblock( ncaHeader, keypatch, encKeyBlock, t) t.close() ncaHeader.rewind() i = 0 newheader = get_newheader(MemoryFile(remote.read_at(off1, 0xC00)), encKeyBlock, crypto1, crypto2, hcrypto, gc_flag) outf.write(newheader) written += len(newheader) break else: pass outf.flush() outf.close() tfile = os.path.join(cachefolder, "remote_files.csv") with open(tfile, 'w') as csvfile: csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format("step", "filepath", "size", "targetsize", "off1", "off2", "token")) csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format(0, outfile, properheadsize + written, properheadsize, 0, properheadsize, "False")) k = 0 l = 0 for fi in files: for j in files_list: if j[0] == fi: csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format( k + 1, outfile, properheadsize + written, 0xC00, (properheadsize + l * 0xC00), (properheadsize + (l * 0xC00) + 0xC00), "False")) off1 = j[1] + 0xC00 off2 = j[2] targetsize = j[3] - 0xC00 URL = 'https://www.googleapis.com/drive/v3/files/' + remote.ID + '?alt=media' token = remote.access_token csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format( k + 2, URL, remote.size, targetsize, off1, off2, token)) break k += 2 l += 1 nspname = "test.nsp" try: g = remote.name g0 = [pos for pos, char in enumerate(g) if char == '['] g0 = (g[0:g0[0]]).strip() titleid = metadict['titleid'] titleversion = metadict['version'] ctype = metadict['ctype'] nspname = f"{g0} [{titleid}] [v{titleversion}] [{ctype}].nsp" except: pass return nspname
def gen_mxci_parts(input_files, cachefolder=None, keypatch=False): from listmanager import calculate_name if keypatch != False: try: keypatch = int(keypatch) except: keypatch = False if cachefolder == None: cachefolder = os.path.join(ztools_dir, '_mtp_cache_') if not os.path.exists(cachefolder): os.makedirs(cachefolder) else: for f in os.listdir(cachefolder): fp = os.path.join(cachefolder, f) try: shutil.rmtree(fp) except OSError: os.remove(fp) end_name, prlist = calculate_name(input_files, romanize=True, ext='.xci') print(f"Calculated name {end_name}") outheader, properheadsize, sz, files = gen_multi_file_header( prlist, input_files) properheadsize = len(outheader) outfile = os.path.join(cachefolder, "0") outf = open(outfile, 'w+b') outf.write(outheader) # print(properheadsize) # print(bucketsize) i = 0 sum = properheadsize for fi in files: for filepath in input_files: if filepath.endswith('xci'): xci = squirrelXCI(filepath) written = 0 for nspF in xci.hfs0: if str(nspF._path) == "secure": for nca in nspF: if nca._path == fi: nca = Nca(nca) crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 crypto = aes128.AESECB( Keys.keyAreaKey( Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex)) hcrypto = aes128.AESXTS( uhx(Keys.get('header_key'))) gc_flag = '00' * 0x01 crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if nca.header.getRightsId() != 0: nca.rewind() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 from mtp_tools import get_nca_ticket check, titleKey = get_nca_ticket( filepath, fi) if check == False: sys.exit("Can't verify titleckey") titleKeyDec = Keys.decryptTitleKey( titleKey, Keys.getMasterKeyIndex( int(masterKeyRev))) encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2( ): encKeyBlock, crypto1, crypto2 = squirrelXCI.get_new_cryptoblock( squirrelXCI, nca, keypatch, encKeyBlock, t) t.close() if nca.header.getRightsId() == 0: nca.rewind() encKeyBlock = nca.header.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2( ): encKeyBlock, crypto1, crypto2 = squirrelXCI.get_new_cryptoblock( squirrelXCI, nca, keypatch, encKeyBlock, t) t.close() nca.rewind() i = 0 newheader = xci.get_newheader( nca, encKeyBlock, crypto1, crypto2, hcrypto, gc_flag) outf.write(newheader) written += len(newheader) nca.seek(0xC00) break else: pass xci.flush() xci.close() elif filepath.endswith('nsp'): nsp = squirrelNSP(filepath) written = 0 for nca in nsp: if nca._path == fi: nca = Nca(nca) crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 crypto = aes128.AESECB( Keys.keyAreaKey( Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex)) hcrypto = aes128.AESXTS(uhx(Keys.get('header_key'))) gc_flag = '00' * 0x01 crypto1 = nca.header.getCryptoType() crypto2 = nca.header.getCryptoType2() if nca.header.getRightsId() != 0: nca.rewind() if crypto2 > crypto1: masterKeyRev = crypto2 if crypto2 <= crypto1: masterKeyRev = crypto1 from mtp_tools import get_nca_ticket check, titleKey = get_nca_ticket(filepath, fi) if check == False: sys.exit("Can't verify titleckey") titleKeyDec = Keys.decryptTitleKey( titleKey, Keys.getMasterKeyIndex(int(masterKeyRev))) encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2(): encKeyBlock, crypto1, crypto2 = squirrelNSP.get_new_cryptoblock( squirrelNSP, nca, keypatch, encKeyBlock, t) t.close() if nca.header.getRightsId() == 0: nca.rewind() encKeyBlock = nca.header.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < nca.header.getCryptoType2(): encKeyBlock, crypto1, crypto2 = squirrelNSP.get_new_cryptoblock( squirrelNSP, nca, keypatch, encKeyBlock, t) t.close() nca.rewind() i = 0 newheader = nsp.get_newheader(nca, encKeyBlock, crypto1, crypto2, hcrypto, gc_flag) outf.write(newheader) written += len(newheader) nca.seek(0xC00) break else: pass nsp.flush() nsp.close() outf.flush() outf.close() tfile = os.path.join(cachefolder, "files.csv") with open(tfile, 'w') as csvfile: csvfile.write("{}|{}|{}|{}|{}|{}\n".format("step", "filepath", "size", "targetsize", "off1", "off2")) csvfile.write("{}|{}|{}|{}|{}|{}\n".format(0, outfile, properheadsize + written, properheadsize, 0, properheadsize)) k = 0 l = 0 for fi in files: for filepath in input_files: if filepath.endswith('xci'): files_list = sq_tools.ret_xci_offsets(filepath) elif filepath.endswith('nsp'): files_list = sq_tools.ret_nsp_offsets(filepath) for j in files_list: if j[0] == fi: csvfile.write("{}|{}|{}|{}|{}|{}\n".format( k + 1, outfile, properheadsize + written, 0xC00, (properheadsize + l * 0xC00), (properheadsize + (l * 0xC00) + 0xC00))) off1 = j[1] + 0xC00 off2 = j[2] targetsize = j[3] - 0xC00 csvfile.write("{}|{}|{}|{}|{}|{}\n".format( k + 2, filepath, (os.path.getsize(filepath)), targetsize, off1, off2)) break k += 2 l += 1 return end_name
def encryptTitleKey(key, i): kek = getTitleKek(i) crypto = aes128.AESECB(uhx(kek)) return crypto.encrypt(key)
def open(self, file=None, mode='rb', cryptoType=-1, cryptoKey=-1, cryptoCounter=-1): super(NcaHeader, self).open(file, mode, cryptoType, cryptoKey, cryptoCounter) self.rewind() self.signature1 = self.read(0x100) self.signature2 = self.read(0x100) self.magic = self.read(0x4) self.isGameCard = self.readInt8() self.contentType = self.readInt8() try: self.contentType = Fs.Type.Content(self.contentType) except: pass self.cryptoType = self.readInt8() self.keyIndex = self.readInt8() self.size = self.readInt64() self.titleId = hx(self.read(8)[::-1]).decode('utf-8').upper() self.readInt32() # padding self.sdkVersion = self.readInt32() self.cryptoType2 = self.readInt8() self.read(0xF) # padding self.rightsId = hx(self.read(0x10)) if self.magic not in [b'NCA3', b'NCA2']: raise Exception('Failed to decrypt NCA header: ' + str(self.magic)) self.sectionHashes = [] for i in range(4): self.sectionTables.append(SectionTableEntry(self.read(0x10))) for i in range(4): self.sectionHashes.append(self.sectionTables[i]) self.masterKey = (self.cryptoType if self.cryptoType > self.cryptoType2 else self.cryptoType2) - 1 if self.masterKey < 0: self.masterKey = 0 self.encKeyBlock = self.getKeyBlock() #for i in range(4): # offset = i * 0x10 # key = encKeyBlock[offset:offset+0x10] # Print.info('enc %d: %s' % (i, hx(key))) if Keys.keyAreaKey(self.masterKey, self.keyIndex): crypto = aes128.AESECB( Keys.keyAreaKey(self.masterKey, self.keyIndex)) self.keyBlock = crypto.decrypt(self.encKeyBlock) self.keys = [] for i in range(4): offset = i * 0x10 key = self.keyBlock[offset:offset + 0x10] #Print.info('dec %d: %s' % (i, hx(key))) self.keys.append(key) else: self.keys = [None, None, None, None, None, None, None] if self.hasTitleRights(): if self.titleId.upper() in Titles.keys() and Titles.get( self.titleId.upper()).key: self.titleKeyDec = Keys.decryptTitleKey( uhx(Titles.get(self.titleId.upper()).key), self.masterKey) else: pass #Print.info('could not find title key!') else: self.titleKeyDec = self.key()
def cr_tr_nca_nd(self, ofolder, buffer, metapatch): indent = 1 tabs = '\t' * indent for nspF in self.hfs0: if str(nspF._path) == "secure": for ticket in nspF: if type(ticket) == Ticket: masterKeyRev = ticket.getMasterKeyRevision() titleKeyDec = Keys.decryptTitleKey( ticket.getTitleKeyBlock().to_bytes( 16, byteorder='big'), Keys.getMasterKeyIndex(masterKeyRev)) rightsId = ticket.getRightsId() Print.info('rightsId =\t' + hex(rightsId)) Print.info('titleKeyDec =\t' + str(hx(titleKeyDec))) Print.info('masterKeyRev =\t' + hex(masterKeyRev)) for nca in nspF: if type(nca) == Nca: if nca.header.getRightsId() != 0: if nca.header.getCryptoType2() != masterKeyRev: pass raise IOError('Mismatched masterKeyRevs!') for nca in nspF: vfragment = "false" if type(nca) == Nca: vfragment = "false" if str(nca.header.contentType) == 'Content.DATA': for f in nca: for file in f: filename = str(file._path) if filename == "fragment": vfragment = "true" if str(vfragment) == "true": Print.info('Skipping delta fragment: ' + str(nca._path)) continue else: Print.info('Copying files: ') if nca.header.getRightsId() != 0: nca.rewind() filename = str(nca._path) outfolder = str(ofolder) + '/' filepath = os.path.join(outfolder, filename) if not os.path.exists(outfolder): os.makedirs(outfolder) fp = open(filepath, 'w+b') nca.rewind() Print.info(tabs + 'Copying: ' + str(filename)) for data in iter(lambda: nca.read(int(buffer)), ""): fp.write(data) fp.flush() if not data: break fp.close() target = Nca(filepath, 'r+b') target.rewind() Print.info(tabs + 'Removing titlerights for ' + str(filename)) Print.info(tabs + 'Writing masterKeyRev for %s, %d' % (str(nca._path), masterKeyRev)) crypto = aes128.AESECB( Keys.keyAreaKey( Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex)) encKeyBlock = crypto.encrypt(titleKeyDec * 4) target.header.setRightsId(0) target.header.setKeyBlock(encKeyBlock) Hex.dump(encKeyBlock) target.close() if nca.header.getRightsId() == 0: nca.rewind() filename = str(nca._path) outfolder = str(ofolder) + '/' filepath = os.path.join(outfolder, filename) if not os.path.exists(outfolder): os.makedirs(outfolder) fp = open(filepath, 'w+b') nca.rewind() Print.info(tabs + 'Copying: ' + str(filename)) for data in iter(lambda: nca.read(int(buffer)), ""): fp.write(data) fp.flush() if not data: break fp.close() if metapatch == 'true': if str(nca.header.contentType ) == 'Content.META': Print.info( tabs + '-------------------------------------' ) Print.info(tabs + 'Checking meta: ') meta_nca = Fs.Nca(filepath, 'r+b') if meta_nca.get_req_system( ) > 336592896: meta_nca.write_req_system( 336592896) meta_nca.flush() meta_nca.close() Print.info( tabs + 'Updating cnmt hashes: ') ############################ meta_nca = Fs.Nca(filepath, 'r+b') sha = meta_nca.calc_pfs0_hash() meta_nca.flush() meta_nca.close() meta_nca = Fs.Nca(filepath, 'r+b') meta_nca.set_pfs0_hash(sha) meta_nca.flush() meta_nca.close() ############################ meta_nca = Fs.Nca(filepath, 'r+b') sha2 = meta_nca.calc_htable_hash() meta_nca.flush() meta_nca.close() meta_nca = Fs.Nca(filepath, 'r+b') meta_nca.header.set_htable_hash( sha2) meta_nca.flush() meta_nca.close() ######################## meta_nca = Fs.Nca(filepath, 'r+b') sha3 = meta_nca.header.calculate_hblock_hash( ) meta_nca.flush() meta_nca.close() meta_nca = Fs.Nca(filepath, 'r+b') meta_nca.header.set_hblock_hash( sha3) meta_nca.flush() meta_nca.close() ######################## with open(filepath, 'r+b') as file: nsha = sha256( file.read()).hexdigest() newname = nsha[:32] + '.cnmt.nca' Print.info(tabs + 'New name: ' + newname) dir = os.path.dirname( os.path.abspath(filepath)) newpath = dir + '/' + newname os.rename(filepath, newpath) Print.info( tabs + '-------------------------------------' ) else: Print.info( tabs + '-> No need to patch the meta') Print.info( tabs + '-------------------------------------' )
def load(fileName): global keyAreaKeys global titleKeks with open(fileName, encoding="utf8") as f: for line in f.readlines(): r = re.match('\s*([a-z0-9_]+)\s*=\s*([A-F0-9]+)\s*', line, re.I) if r: keyname = r.group(1) if keyname.startswith('master_key_'): if keyname[-2] != '0': num = keyname[-2:] else: num = keyname[-1] try: num = int(int(num, 16)) except: num = int(num, 10) if len(str(num)) < 2: num = '0' + str(num) keyname = 'master_key_' + str(num) keys[keyname] = r.group(2) if 'master_key_16' in keys.keys() and not 'master_key_10' in keys.keys( ) and not 'master_key_11' in keys.keys( ) and not 'master_key_12' in keys.keys( ) and not 'master_key_13' in keys.keys( ) and not 'master_key_14' in keys.keys( ) and not 'master_key_15' in keys.keys(): keys['master_key_10'] = keys['master_key_16'] del keys['master_key_16'] # for k in keys.keys(): # print(k) #crypto = aes128.AESCTR(uhx(key), uhx('00000000000000000000000000000010')) aes_kek_generation_source = uhx(keys['aes_kek_generation_source']) aes_key_generation_source = uhx(keys['aes_key_generation_source']) keyAreaKeys = [] for i in range(20): keyAreaKeys.append([None, None, None]) for i in range(20): if i < 10: masterKeyName = 'master_key_0' + str(i) else: masterKeyName = 'master_key_' + str(i) if masterKeyName in keys.keys(): # aes_decrypt(master_ctx, &keyset->titlekeks[i], keyset->titlekek_source, 0x10); masterKey = uhx(keys[masterKeyName]) crypto = aes128.AESECB(masterKey) titleKeks.append( crypto.decrypt(uhx(keys['titlekek_source'])).hex()) keyAreaKeys[i][0] = generateKek( uhx(keys['key_area_key_application_source']), masterKey, aes_kek_generation_source, aes_key_generation_source) keyAreaKeys[i][1] = generateKek( uhx(keys['key_area_key_ocean_source']), masterKey, aes_kek_generation_source, aes_key_generation_source) keyAreaKeys[i][2] = generateKek( uhx(keys['key_area_key_system_source']), masterKey, aes_kek_generation_source, aes_key_generation_source) else: titleKeks.append('0' * 32)