def setMasterKeyRev(self, newMasterKeyRev): if not Titles.contains(self.titleId): raise IOError('No title key found in database! ' + self.titleId) ticket = self.ticket() masterKeyRev = ticket.getMasterKeyRevision() titleKey = ticket.getTitleKeyBlock() newTitleKey = Keys.changeTitleKeyMasterKey( titleKey.to_bytes(16, byteorder='big'), Keys.getMasterKeyIndex(masterKeyRev), Keys.getMasterKeyIndex(newMasterKeyRev)) rightsId = ticket.getRightsId() if rightsId != 0: raise IOError('please remove titlerights first') if (newMasterKeyRev == None and rightsId == 0) or masterKeyRev == newMasterKeyRev: Print.info('Nothing to do') return Print.info('rightsId =\t' + hex(rightsId)) Print.info('titleKey =\t' + str(hx(titleKey.to_bytes(16, byteorder='big')))) Print.info('newTitleKey =\t' + str(hx(newTitleKey))) Print.info('masterKeyRev =\t' + hex(masterKeyRev)) for nca in self: if type(nca) == Nca: if nca.header.getCryptoType2() != masterKeyRev: pass raise IOError('Mismatched masterKeyRevs!') ticket.setMasterKeyRevision(newMasterKeyRev) ticket.setRightsId((ticket.getRightsId() & 0xFFFFFFFFFFFFFFFF0000000000000000) + newMasterKeyRev) ticket.setTitleKeyBlock(int.from_bytes(newTitleKey, 'big')) for nca in self: if type(nca) == Nca: if nca.header.getCryptoType2() != newMasterKeyRev: Print.info('writing masterKeyRev for %s, %d -> %s' % (str(nca._path), nca.header.getCryptoType2(), str(newMasterKeyRev))) encKeyBlock = nca.header.getKeyBlock() if sum(encKeyBlock) != 0: key = Keys.keyAreaKey( Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex) Print.info('decrypting with %s (%d, %d)' % (str(hx(key)), Keys.getMasterKeyIndex(masterKeyRev), nca.header.keyIndex)) crypto = aes128.AESECB(key) decKeyBlock = crypto.decrypt(encKeyBlock) key = Keys.keyAreaKey( Keys.getMasterKeyIndex(newMasterKeyRev), nca.header.keyIndex) Print.info('encrypting with %s (%d, %d)' % (str(hx(key)), Keys.getMasterKeyIndex(newMasterKeyRev), nca.header.keyIndex)) crypto = aes128.AESECB(key) reEncKeyBlock = crypto.encrypt(decKeyBlock) nca.header.setKeyBlock(reEncKeyBlock) if newMasterKeyRev >= 3: nca.header.setCryptoType(2) nca.header.setCryptoType2(newMasterKeyRev) else: nca.header.setCryptoType(newMasterKeyRev) nca.header.setCryptoType2(0)
def verifyKey(self, userkey): if not self.header.hasTitleRights(): titleKeyDec = Keys.decryptTitleKey( file.getTitleKeyBlock().to_bytes(16, byteorder='big'), Keys.getMasterKeyIndex(self.masterKey())) else: encKey = userkey titleKeyDec = Keys.decryptTitleKey( encKey, Keys.getMasterKeyIndex(self.masterKey())) ''' print('\nTesting {} with:'.format(self)) print('- Keygeneration {}'.format(self.masterKey())) print('- Encrypted key {}'.format(str(hx(encKey))[2:-1])) print('- Decrypted key {}'.format(str(hx(titleKeyDec))[2:-1])) ''' decKey = titleKeyDec f = self if self.header.getRightsId() != 0: for fs in self: #print(fs.fsType) #print(fs.cryptoType) if fs.fsType == Type.Fs.PFS0 and fs.cryptoType == Type.Crypto.CTR: f.seek(0) ncaHeader = NcaHeader() ncaHeader.open( MemoryFile(f.read(0x400), Type.Crypto.XTS, uhx(Keys.get('header_key')))) pfs0 = fs sectionHeaderBlock = fs.buffer #fs.f.setKey(b'\x00' * 16) #print('- Current key {}'.format(str(hx(fs.f.cryptoKey))[2:-1])) fs.seek(0) pfs0Offset = 0 #int.from_bytes(sectionHeaderBlock[0x38:0x40], byteorder='little', signed=False) pfs0Header = fs.read(0x10) #Hex.dump(sectionHeaderBlock) #mem = MemoryFile(pfs0Header, Type.Crypto.CTR, decKey, pfs0.cryptoCounter, offset = pfs0Offset) data = pfs0Header #mem.read(); #Hex.dump(pfs0Header) magic = data[0:4] #print(magic) if magic != b'PFS0': return False else: return True if fs.fsType == Type.Fs.ROMFS and fs.cryptoType == Type.Crypto.CTR: f.seek(0) ncaHeader = NcaHeader() ncaHeader.open( MemoryFile(f.read(0x400), Type.Crypto.XTS, uhx(Keys.get('header_key')))) ncaHeader = f.read(0x400) pfs0 = fs sectionHeaderBlock = fs.buffer levelOffset = int.from_bytes(sectionHeaderBlock[0x18:0x20], byteorder='little', signed=False) levelSize = int.from_bytes(sectionHeaderBlock[0x20:0x28], byteorder='little', signed=False) pfs0Offset = levelOffset f.seek(pfs0Offset + fs.f.offset) pfs0Header = f.read(levelSize) #fs.seek(pfs0Offset) #pfs0Header = fs.read(levelSize) #print(sectionHeaderBlock[8:12] == b'IVFC') if sectionHeaderBlock[8:12] == b'IVFC': #Hex.dump(sectionHeaderBlock) #Print.info(hx(sectionHeaderBlock[0xc8:0xc8+0x20]).decode('utf-8')) mem = MemoryFile(pfs0Header, Type.Crypto.CTR, decKey, pfs0.cryptoCounter, offset=fs.f.offset) data = mem.read() #Hex.dump(data, 48) #print('hash = %s' % str(sha256(data).hexdigest())) if hx(sectionHeaderBlock[0xc8:0xc8 + 0x20]).decode('utf-8') == str( sha256(data).hexdigest()): return True else: return False else: mem = MemoryFile(pfs0Header, Type.Crypto.CTR, decKey, pfs0.cryptoCounter, offset=pfs0Offset) data = mem.read() #Hex.dump(data) magic = mem.read()[0:4] #print(magic) if magic != b'PFS0': pass else: return True if fs.fsType == Type.Fs.ROMFS and fs.cryptoType == Type.Crypto.BKTR and str( f.header.contentType) == 'Content.PROGRAM': f.seek(0) ncaHeader = NcaHeader() ncaHeader.open( MemoryFile(f.read(0x400), Type.Crypto.XTS, uhx(Keys.get('header_key')))) ncaHeader = f.read(0x400) pfs0 = fs sectionHeaderBlock = fs.buffer levelOffset = int.from_bytes(sectionHeaderBlock[0x18:0x20], byteorder='little', signed=False) levelSize = int.from_bytes(sectionHeaderBlock[0x20:0x28], byteorder='little', signed=False) pfs0Offset = fs.offset + levelOffset f.seek(pfs0Offset) pfs0Header = f.read(levelSize) if sectionHeaderBlock[8:12] == b'IVFC': for i in range(10): ini = 0x100 + (i * 0x10) fin = 0x110 + (i * 4) test = sectionHeaderBlock[ini:fin] if test == b'BKTR': return True return False