Skip to content

Commit

Permalink
verify dec and sig
Browse files Browse the repository at this point in the history
  • Loading branch information
seiya-git committed Oct 22, 2023
1 parent a4a6b19 commit 0c18c31
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 16 deletions.
47 changes: 47 additions & 0 deletions py-test/lib/NcaKeys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
def getNcaModulusKey(keytype = None):
keylist = {
'nca_header_fixed_key_modulus_00': int((
'BFBE406CF4A780E9F07D0C99611D772F96BC4B9E58381B03ABB175499F2B4D58'
'34B005A37522BE1A3F0373AC7068D116B904465EB707912F078B26DEF60007B2'
'B451F80D0A5E58ADEBBC9AD649B964EFA782B5CF6D7013B00F85F6A908AA4D67'
'6687FA89FF7590181E6B3DE98A68C92604D980CE3F5E92CE01FF063BF2C1A90C'
'CE026F16BC92420A4164CD52B6344DAEC02EDEA4DF27683CC1A060AD43F3FC86'
'C13E6C46F77C299FFAFDF0E3CE64E735F2F656566F6DF1E242B08340A5C3202B'
'CC9AAECAED4D7030A8701C70FD1363290279EAD2A7AF3528321C7BE62F1AAA40'
'7E328C2742FE8278EC0DEBE6834B6D8104401A9E9A67F67229FA04F09DE4F403'
), 16),
'nca_header_fixed_key_modulus_01': int((
'ADE3E1FA0435E5B6DD49EA8929B1FFB643DFCA96A04A13DF43D9949796436548'
'705833A27D357B96745E0B5C32181424C258B36C227AA1B7CB90A7A3F97D4516'
'A5C8ED8FAD395E9E4B51687DF80C35C63F91AE44A592300D46F840FFD0FF06D2'
'1C7F9618DCB71D663ED173BC158A2F94F300C183F1CDD78188ABDF8CEF97DD1B'
'175F58F69AE9E8C22F3815F52107F837905D2E024024150D25B7265D09CC4CF4'
'F21B94705A9EEEED7777D45199F5DC761EE36C8CD112D457D1B683E4E4FEDAE9'
'B43B33E5378ADFB57F89F19B9EB015B23AFEEA61845B7D4B23120B8312F2226B'
'B922964B260B635E965752A3676422CAD0563E74B5981F0DF8B334E698685AAD'
), 16),
'acid_fixed_key_modulus_00': int((
'DDC8DDF24E6DF0CA9EC75DC77BADFE7D238969B6F206A20288E15591ABCB4D50'
'2EFC9D9476D64CD8FF10FA5E930AB457AC51C71666F41A54C2C5043D1BFE3020'
'8AAC6F6FF5C7B668B8C9406B42AD1121E78BE9750186E4489B0A0AF87FE887F2'
'8201E6A30FE466AE833F4E9F5E0130A400B99AAE5F03CC1860E5EF3B5E1516FE'
'1C8278B52F477C0666885D35A2672010E76C4368D3E45A682A5AE26D73B03153'
'1C200944F51A9D22BE12A17711E2A1CD409AA28B609BEFA0D34863A2F8A32C08'
'56522E6019675AA79FDC3F3F692B316AB7884A148480333C9D44B73F4CE175EA'
'37EAE81E7C77B7C61AA2F09F1061CD7B5B324C37EFB17168530AED517D3522FD'
), 16),
'acid_fixed_key_modulus_01': int((
'E7AA25C801A5146B01603ED9965ABF90ACA7FD9B5BBD8A26B0CB20289A7212F5'
'2065B3B984581F27BC7CA2C99E1895CFC2732E748C66E59E792BB8070CB04E8E'
'AB852142C4C56D889CDB15953F80DB7A9A7D4156251718424D8CACA57BDB425D'
'5935455D8A02B570C0723546D01D60014ACC1C46D3D63552D6E1F83B5DEADDB8'
'FE7D50CB3523678BB6E474D260FCFD43BF910881C54F5D169AC49AC6F6F3E1F6'
'5C07AA716C13A4B1B366BF904C3DA2C40BB83D7A8C19FAFF6BB91F02CCB6D30C'
'7D191F47F9C74001FA46EA0BD402E03D309A1A0FEAA76655F7CB28E2BB99E483'
'C34303EEDC1F0223DDD12D39A4657503EF379C06D6FAA115F0DB1747264F4903'
), 16),
}

if keytype not in keylist:
return keylist
return keylist[keytype]
121 changes: 107 additions & 14 deletions py-test/lib/Verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,28 +67,39 @@ def verify(file):
log_info += f" {str(int(res['title_ext'], 16)).zfill(4)}"
print(f'[:INFO:] Verifying... {log_info}\n')

check, log = decrypt_verify(f)
vmsg = list()
check = True

check_decrypt, vmsg = verify_decrypt(f, vmsg)
if check_decrypt == False:
check = False

check_sig, vmsg = verify_sig(f, vmsg)
if check_sig == False:
check = False

f.flush()
f.close()

return check, log + '\n'
outlog = os.path.basename(file) + '\n'
outlog += '\n'.join(vmsg) + '\n'

return check, outlog

except BaseException as e:
raise e

def decrypt_verify(nspx):
def verify_decrypt(nspx, vmsg = list()):
listed_files = list()
valid_files = list()
listed_certs = list()

verdict = True
vmsg = list()

if type(nspx) != Fs.Xci.Xci and type(nspx) != Fs.Nsp.Nsp:
return False, msg

tvmsg = '[:INFO:] DECRYPTION TEST'
tvmsg = '\n[:INFO:] DECRYPTION TEST'
print(tvmsg)
vmsg.append(tvmsg)

Expand Down Expand Up @@ -375,20 +386,102 @@ def decrypt_verify(nspx):
vmsg.append(tvmsg)
verdict = False

file_ext = nspx._path[-3:].upper()

bad_format = False
if len(titlerights) < 1 and isCard == False:
verdict = False
bad_format = True
# Note: Ignore it for now, Tinfoil doesn't support install separate xci dlc
# if len(titlerights) < 1 and isCard == False:
# bad_format = True
# verdict = False

if bad_format != True:
if verdict == True:
tvmsg = f'\nVERDICT: {file_ext} FILE IS CORRECT'
else:
tvmsg = f'\nVERDICT: {file_ext} FILE IS CORRUPT OR MISSES FILES'
else:
tvmsg = f'\nVERDICT: {file_ext} FILE IS IN WRONG FORMAT (XCI IN NSP)'
print(tvmsg)
vmsg.append(tvmsg)

return verdict, vmsg

def verify_sig(nspx, vmsg = list(), cnmt = 'check'):
verdict = True
keygenerationlist = list()

tvmsg = '\n[:INFO:] SIGNATURE 1 TEST'
print(tvmsg)
vmsg.append(tvmsg)

temp_hfs = nspx
isCard = False

if(type(nspx) == Fs.Xci.Xci):
for nspf in nspx.hfs0:
if nspf._path == 'secure':
temp_hfs = nspf
isCard = True
else:
for file in nspf:
tvmsg = ''
tvmsg += f'\n:0000000000000000 - Content.UNKNOWN'
tvmsg += f'\n> {file._path}\t -> SKIPPED'
tvmsg += f'\n* Partition: {nspf._path}'
print(tvmsg)
vmsg.append(tvmsg)

for f in temp_hfs:
if type(f) == Fs.Nca.Nca:
tvmsg = f'\n:{f.header.titleId} - Content.{f.header.contentType._name_}'
print(tvmsg)
vmsg.append(tvmsg)
verify = VerifyTools.verify_nca_sig_simple(f)

tabs = '\t'
if f.header.contentType != Fs.Type.Content.META:
tabs += '\t'

if verify == True:
tvmsg = f'> {f._path}{tabs} -> is PROPER'
print(tvmsg)
vmsg.append(tvmsg)
else:
tvmsg = f'> {f._path}{tabs} -> was MODIFIED'
print(tvmsg)
vmsg.append(tvmsg)

if verdict == True:
verdict = verify
if f._path.endswith('.ncz'):
ncz = Fs.Nca.Nca(f)
ncz._path = f._path

tvmsg = f'\n:{ncz.header.titleId} - Content.{ncz.header.contentType._name_}'
print(tvmsg)
vmsg.append(tvmsg)

verify = VerifyTools.verify_nca_sig_simple(ncz)

if verify == True:
tvmsg = f'> {ncz._path}\t\t -> is PROPER'
print(tvmsg)
vmsg.append(tvmsg)
else:
tvmsg = f'> {ncz._path}\t\t -> was MODIFIED'
print(tvmsg)
vmsg.append(tvmsg)

if verdict == True:
verdict = verify

file_ext = nspx._path[-3:].upper()

if bad_format == True:
tvmsg = f'\nVERDICT: {file_ext} FILE IS IN WRONG FORMAT (XCI IN NSP)'
elif verdict == True:
tvmsg = f'\nVERDICT: {file_ext} FILE IS CORRECT'
if verdict == True:
tvmsg = f'\nVERDICT: {file_ext} FILE IS SAFE'
else:
tvmsg = f'\nVERDICT: {file_ext} FILE IS CORRUPT OR MISSES FILES'
tvmsg = f'\nVERDICT: {file_ext} FILE COULD\'VE BEEN TAMPERED WITH'
print(tvmsg)
vmsg.append(tvmsg)

return verdict, '\n'.join(vmsg)
return verdict, vmsg
36 changes: 36 additions & 0 deletions py-test/lib/VerifyTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@

from lib import Hex
from nut import Keys
from nut import aes128

import zstandard
from lib import FsTools
from lib import Header, BlockDecompressorReader
from lib.NcaKeys import getNcaModulusKey

from Crypto.Hash import SHA256
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5, PKCS1_PSS

RSA_PUBLIC_EXPONENT = 0x10001
FS_HEADER_LENGTH = 0x200

def readInt64(f, byteorder='little', signed = False):
return int.from_bytes(f.read(8), byteorder=byteorder, signed=signed)
Expand Down Expand Up @@ -299,3 +310,28 @@ def pr_noenc_check_dlc(self):
return False
else:
return True

def verify_nca_sig_simple(self):
self.rewind()
sign1 = self.header.signature1
hcrypto = aes128.AESXTS(uhx(Keys.get('header_key')))

self.header.rewind()
orig_header = self.header.read(0xC00)
self.header.seek(0x200)
headdata = self.header.read(0x200)

self.header.seek(0x221)
sigKeyGen = self.header.readInt8()

if sigKeyGen == 0:
pubkey = RSA.RsaKey(n = getNcaModulusKey('nca_header_fixed_key_modulus_00'), e = RSA_PUBLIC_EXPONENT)
else:
pubkey = RSA.RsaKey(n = getNcaModulusKey('nca_header_fixed_key_modulus_01'), e = RSA_PUBLIC_EXPONENT)

rsapss = PKCS1_PSS.new(pubkey)
digest = SHA256.new(headdata)

verification = rsapss.verify(digest, sign1)
return verification

9 changes: 7 additions & 2 deletions py-test/verify_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,20 @@ def scan_folder():
with open(lpath_badfolder, 'a') as f:
f.write(f'{item}\n')

rootpath = os.path.dirname(item_path)
basename = os.path.basename(item_path)
basename = f'{basename[:-4]}-{basename[-3:]}-verify'
log_name = os.path.join(rootpath, basename)

try:
nspTest, nspLog = Verify.verify(item_path)
if nspTest != True:
with open(lpath_badfile, 'a') as f:
f.write(f'{item_path}\n')
with open(f'{item_path}.verify-bad.txt', 'w') as f:
with open(f'{log_name}-bad.txt', 'w') as f:
f.write(f'{nspLog}')
else:
with open(f'{item_path}.verify.txt', 'w') as f:
with open(f'{log_name}.txt', 'w') as f:
f.write(f'{nspLog}')
except Exception as e:
send_hook(f'[:WARN:] An error occurred:\n{item}: {str(e)}')
Expand Down

0 comments on commit 0c18c31

Please sign in to comment.