3ds_decrypt_v2

3ds cart image decryptor (lusi1990 fork)
git clone git://bsandro.tech/3ds_decrypt_v2
Log | Files | Refs | README

commit cd521fed547e6059a27cf4bbefa9dbec5ff714b3
parent e9b5a4308a3778ffc6135a47290847488f7b058d
Author: bsandro <brian.drosan@gmail.com>
Date:   Sun, 15 May 2022 22:26:28 +0300

python3 support

Diffstat:
M3ds_decrypt_v2.py | 436++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
1 file changed, 288 insertions(+), 148 deletions(-)

diff --git a/3ds_decrypt_v2.py b/3ds_decrypt_v2.py @@ -1,37 +1,44 @@ -# /usr/bin/env python2 +# /usr/bin/env python3 from Crypto.Cipher import AES from Crypto.Util import Counter from sys import argv import struct -rol = lambda val, r_bits, max_bits: \ - (val << r_bits % max_bits) & (2 ** max_bits - 1) | \ - ((val & (2 ** max_bits - 1)) >> (max_bits - (r_bits % max_bits))) +rol = lambda val, r_bits, max_bits: (val << r_bits % max_bits) & (2**max_bits - 1) | ( + (val & (2**max_bits - 1)) >> (max_bits - (r_bits % max_bits)) +) def to_bytes(num): - numstr = '' + numstr = bytearray(b"") tmp = num while len(numstr) < 16: - numstr += chr(tmp & 0xFF) + numstr.append(tmp & 0xFF) tmp >>= 8 - return numstr[::-1] + return bytes(numstr[::-1]) # Setup Keys and IVs -plain_counter = struct.unpack('>Q', '\x01\x00\x00\x00\x00\x00\x00\x00') -exefs_counter = struct.unpack('>Q', '\x02\x00\x00\x00\x00\x00\x00\x00') -romfs_counter = struct.unpack('>Q', '\x03\x00\x00\x00\x00\x00\x00\x00') -Constant = struct.unpack('>QQ', - '\x1F\xF9\xE9\xAA\xC5\xFE\x04\x08\x02\x45\x91\xDC\x5D\x52\x76\x8A') # 3DS AES Hardware Constant +plain_counter = struct.unpack(">Q", b"\x01\x00\x00\x00\x00\x00\x00\x00") +exefs_counter = struct.unpack(">Q", b"\x02\x00\x00\x00\x00\x00\x00\x00") +romfs_counter = struct.unpack(">Q", b"\x03\x00\x00\x00\x00\x00\x00\x00") +Constant = struct.unpack( + ">QQ", b"\x1F\xF9\xE9\xAA\xC5\xFE\x04\x08\x02\x45\x91\xDC\x5D\x52\x76\x8A" +) # 3DS AES Hardware Constant # Retail keys -KeyX0x18 = struct.unpack('>QQ', - '\x82\xE9\xC9\xBE\xBF\xB8\xBD\xB8\x75\xEC\xC0\xA0\x7D\x47\x43\x74') # KeyX 0x18 (New 3DS 9.3) -KeyX0x1B = struct.unpack('>QQ', - '\x45\xAD\x04\x95\x39\x92\xC7\xC8\x93\x72\x4A\x9A\x7B\xCE\x61\x82') # KeyX 0x1B (New 3DS 9.6) -KeyX0x25 = struct.unpack('>QQ', '\xCE\xE7\xD8\xAB\x30\xC0\x0D\xAE\x85\x0E\xF5\xE3\x82\xAC\x5A\xF3') # KeyX 0x25 (> 7.x) -KeyX0x2C = struct.unpack('>QQ', '\xB9\x8E\x95\xCE\xCA\x3E\x4D\x17\x1F\x76\xA9\x4D\xE9\x34\xC0\x53') # KeyX 0x2C (< 6.x) +KeyX0x18 = struct.unpack( + ">QQ", b"\x82\xE9\xC9\xBE\xBF\xB8\xBD\xB8\x75\xEC\xC0\xA0\x7D\x47\x43\x74" +) # KeyX 0x18 (New 3DS 9.3) +KeyX0x1B = struct.unpack( + ">QQ", b"\x45\xAD\x04\x95\x39\x92\xC7\xC8\x93\x72\x4A\x9A\x7B\xCE\x61\x82" +) # KeyX 0x1B (New 3DS 9.6) +KeyX0x25 = struct.unpack( + ">QQ", b"\xCE\xE7\xD8\xAB\x30\xC0\x0D\xAE\x85\x0E\xF5\xE3\x82\xAC\x5A\xF3" +) # KeyX 0x25 (> 7.x) +KeyX0x2C = struct.unpack( + ">QQ", b"\xB9\x8E\x95\xCE\xCA\x3E\x4D\x17\x1F\x76\xA9\x4D\xE9\x34\xC0\x53" +) # KeyX 0x2C (< 6.x) # Dev Keys: (Uncomment these lines if your 3ds rom is encrypted with Dev Keys) # KeyX0x18 = struct.unpack('>QQ', '\x30\x4B\xF1\x46\x83\x72\xEE\x64\x11\x5E\xBD\x40\x93\xD8\x42\x76') # Dev KeyX 0x18 (New 3DS 9.3) @@ -39,210 +46,343 @@ KeyX0x2C = struct.unpack('>QQ', '\xB9\x8E\x95\xCE\xCA\x3E\x4D\x17\x1F\x76\xA9\x4 # KeyX0x25 = struct.unpack('>QQ', '\x81\x90\x7A\x4B\x6F\x1B\x47\x32\x3A\x67\x79\x74\xCE\x4A\xD7\x1B') # Dev KeyX 0x25 (> 7.x) # KeyX0x2C = struct.unpack('>QQ', '\x51\x02\x07\x51\x55\x07\xCB\xB1\x8E\x24\x3D\xCB\x85\xE2\x3A\x1D') # Dev KeyX 0x2C (< 6.x) -with open(argv[1], 'rb') as f: - with open(argv[1], 'rb+') as g: - print argv[1] # Print the filename of the file being decrypted +with open(argv[1], "rb") as f: + with open(argv[1], "rb+") as g: + print(argv[1]) # Print the filename of the file being decrypted f.seek(0x100) # Seek to start of NCSD header magic = f.read(0x04) - if magic == "NCSD": + if magic == b"NCSD": f.seek(0x188) - ncsd_flags = struct.unpack('<BBBBBBBB', f.read(0x8)) + ncsd_flags = struct.unpack("<BBBBBBBB", f.read(0x8)) sectorsize = 0x200 * (2 ** ncsd_flags[6]) - for p in xrange(8): - f.seek((0x120) + (p * 0x08)) # Seek to start of partition information, read offsets and lengths - part_off = struct.unpack('<L', f.read(0x04)) - part_len = struct.unpack('<L', f.read(0x04)) - - f.seek(((part_off[0]) * sectorsize) + 0x188) # Get the partition flags to determine encryption type. - partition_flags = struct.unpack('<BBBBBBBB', f.read(0x8)) - - if (partition_flags[7] & 0x04): # check if the 'NoCrypto' bit (bit 3) is set - print ("Partition %1d: Already Decrypted?...") % (p) + for p in range(8): + f.seek( + (0x120) + (p * 0x08) + ) # Seek to start of partition information, read offsets and lengths + part_off = struct.unpack("<L", f.read(0x04)) + part_len = struct.unpack("<L", f.read(0x04)) + + f.seek( + ((part_off[0]) * sectorsize) + 0x188 + ) # Get the partition flags to determine encryption type. + partition_flags = struct.unpack("<BBBBBBBB", f.read(0x8)) + + if ( + partition_flags[7] & 0x04 + ): # check if the 'NoCrypto' bit (bit 3) is set + print(f"Partition {p}: Already Decrypted?...") else: if (part_off[0] * sectorsize) > 0: # check if partition exists f.seek( - ((part_off[0]) * sectorsize) + 0x100) # Find partition start (+ 0x100 to skip NCCH header) + ((part_off[0]) * sectorsize) + 0x100 + ) # Find partition start (+ 0x100 to skip NCCH header) magic = f.read(0x04) - if magic == "NCCH": # check if partition is valid + if magic == b"NCCH": # check if partition is valid f.seek(((part_off[0]) * sectorsize) + 0x0) - part_keyy = struct.unpack('>QQ', f.read( - 0x10)) # KeyY is the first 16 bytes of partition RSA-2048 SHA-256 signature + part_keyy = struct.unpack( + ">QQ", f.read(0x10) + ) # KeyY is the first 16 bytes of partition RSA-2048 SHA-256 signature f.seek(((part_off[0]) * sectorsize) + 0x108) - tid = struct.unpack('<Q', - f.read(0x8)) # TitleID is used as IV joined with the content type. - plain_iv = (tid[::] + plain_counter[ - ::]) # Get the IV for plain sector (TitleID + Plain Counter) - exefs_iv = (tid[::] + exefs_counter[::]) # Get the IV for ExeFS (TitleID + ExeFS Counter) - romfs_iv = (tid[::] + romfs_counter[::]) # Get the IV for RomFS (TitleID + RomFS Counter) - - f.seek((part_off[0] * sectorsize) + 0x160) # get exheader hash - exhdr_sbhash = str("%016X%016X%016X%016X") % (struct.unpack('>QQQQ', f.read(0x20))) + tid = struct.unpack( + "<Q", f.read(0x8) + ) # TitleID is used as IV joined with the content type. + plain_iv = ( + tid[::] + plain_counter[::] + ) # Get the IV for plain sector (TitleID + Plain Counter) + exefs_iv = ( + tid[::] + exefs_counter[::] + ) # Get the IV for ExeFS (TitleID + ExeFS Counter) + romfs_iv = ( + tid[::] + romfs_counter[::] + ) # Get the IV for RomFS (TitleID + RomFS Counter) + + f.seek( + (part_off[0] * sectorsize) + 0x160 + ) # get exheader hash + exhdr_sbhash = str("%016X%016X%016X%016X") % ( + struct.unpack(">QQQQ", f.read(0x20)) + ) f.seek((part_off[0] * sectorsize) + 0x180) - exhdr_len = struct.unpack('<L', f.read(0x04)) # get extended header length + exhdr_len = struct.unpack( + "<L", f.read(0x04) + ) # get extended header length f.seek((part_off[0] * sectorsize) + 0x190) - plain_off = struct.unpack('<L', f.read(0x04)) # get plain sector offset - plain_len = struct.unpack('<L', f.read(0x04)) # get plain sector length + plain_off = struct.unpack( + "<L", f.read(0x04) + ) # get plain sector offset + plain_len = struct.unpack( + "<L", f.read(0x04) + ) # get plain sector length f.seek((part_off[0] * sectorsize) + 0x198) - logo_off = struct.unpack('<L', f.read(0x04)) # get logo offset - logo_len = struct.unpack('<L', f.read(0x04)) # get logo length + logo_off = struct.unpack( + "<L", f.read(0x04) + ) # get logo offset + logo_len = struct.unpack( + "<L", f.read(0x04) + ) # get logo length f.seek((part_off[0] * sectorsize) + 0x1A0) - exefs_off = struct.unpack('<L', f.read(0x04)) # get exefs offset - exefs_len = struct.unpack('<L', f.read(0x04)) # get exefs length + exefs_off = struct.unpack( + "<L", f.read(0x04) + ) # get exefs offset + exefs_len = struct.unpack( + "<L", f.read(0x04) + ) # get exefs length f.seek((part_off[0] * sectorsize) + 0x1B0) - romfs_off = struct.unpack('<L', f.read(0x04)) # get romfs offset - romfs_len = struct.unpack('<L', f.read(0x04)) # get romfs length + romfs_off = struct.unpack( + "<L", f.read(0x04) + ) # get romfs offset + romfs_len = struct.unpack( + "<L", f.read(0x04) + ) # get romfs length f.seek((part_off[0] * sectorsize) + 0x1C0) # get exefs hash - exefs_sbhash = str("%016X%016X%016X%016X") % (struct.unpack('>QQQQ', f.read(0x20))) + exefs_sbhash = str("%016X%016X%016X%016X") % ( + struct.unpack(">QQQQ", f.read(0x20)) + ) f.seek((part_off[0] * sectorsize) + 0x1E0) # get romfs hash - romfs_sbhash = str("%016X%016X%016X%016X") % (struct.unpack('>QQQQ', f.read(0x20))) - - plainIV = long(str("%016X%016X") % (plain_iv[::]), 16) - exefsIV = long(str("%016X%016X") % (exefs_iv[::]), 16) - romfsIV = long(str("%016X%016X") % (romfs_iv[::]), 16) - KeyY = long(str("%016X%016X") % (part_keyy[::]), 16) - Const = long(str("%016X%016X") % (Constant[::]), 16) - - KeyX2C = long(str("%016X%016X") % (KeyX0x2C[::]), 16) - NormalKey2C = rol((rol(KeyX2C, 2, 128) ^ KeyY) + Const, 87, 128) - - if (partition_flags[3] == 0x00): # Uses Original Key - KeyX = long(str("%016X%016X") % (KeyX0x2C[::]), 16) - elif (partition_flags[3] == 0x01): # Uses 7.x Key - KeyX = long(str("%016X%016X") % (KeyX0x25[::]), 16) - elif (partition_flags[3] == 0x0A): # Uses New3DS 9.3 Key - KeyX = long(str("%016X%016X") % (KeyX0x18[::]), 16) - elif (partition_flags[3] == 0x0B): # Uses New3DS 9.6 Key - KeyX = long(str("%016X%016X") % (KeyX0x1B[::]), 16) + romfs_sbhash = str("%016X%016X%016X%016X") % ( + struct.unpack(">QQQQ", f.read(0x20)) + ) + + plainIV = int(str("%016X%016X") % (plain_iv[::]), 16) + exefsIV = int(str("%016X%016X") % (exefs_iv[::]), 16) + romfsIV = int(str("%016X%016X") % (romfs_iv[::]), 16) + KeyY = int(str("%016X%016X") % (part_keyy[::]), 16) + Const = int(str("%016X%016X") % (Constant[::]), 16) + + KeyX2C = int(str("%016X%016X") % (KeyX0x2C[::]), 16) + NormalKey2C = rol( + (rol(KeyX2C, 2, 128) ^ KeyY) + Const, 87, 128 + ) + + if partition_flags[3] == 0x00: # Uses Original Key + KeyX = int(str("%016X%016X") % (KeyX0x2C[::]), 16) + elif partition_flags[3] == 0x01: # Uses 7.x Key + KeyX = int(str("%016X%016X") % (KeyX0x25[::]), 16) + elif partition_flags[3] == 0x0A: # Uses New3DS 9.3 Key + KeyX = int(str("%016X%016X") % (KeyX0x18[::]), 16) + elif partition_flags[3] == 0x0B: # Uses New3DS 9.6 Key + KeyX = int(str("%016X%016X") % (KeyX0x1B[::]), 16) NormalKey = rol((rol(KeyX, 2, 128) ^ KeyY) + Const, 87, 128) - if (partition_flags[7] & 0x01): # fixed crypto key (aka 0-key) + if ( + partition_flags[7] & 0x01 + ): # fixed crypto key (aka 0-key) NormalKey = 0x00 NormalKey2C = 0x00 + print("0-key detected") - if (exhdr_len[0] > 0): + if exhdr_len[0] > 0: # decrypt exheader f.seek((part_off[0] + 1) * sectorsize) g.seek((part_off[0] + 1) * sectorsize) exhdr_filelen = 0x800 exefsctr2C = Counter.new(128, initial_value=(plainIV)) - exefsctrmode2C = AES.new(to_bytes(NormalKey2C), AES.MODE_CTR, counter=exefsctr2C) - print ("Partition %1d ExeFS: Decrypting: ExHeader") % (p) + blen_s = to_bytes(NormalKey2C) + print( + f"NormalKey2C: {NormalKey2C} of len {len(blen_s)}" + ) + exefsctrmode2C = AES.new( + blen_s, AES.MODE_CTR, counter=exefsctr2C + ) + print(f"Partition {p} ExeFS: Decrypting: ExHeader") g.write(exefsctrmode2C.decrypt(f.read(exhdr_filelen))) - if (exefs_len[0] > 0): + if exefs_len[0] > 0: # decrypt exefs filename table f.seek((part_off[0] + exefs_off[0]) * sectorsize) g.seek((part_off[0] + exefs_off[0]) * sectorsize) exefsctr2C = Counter.new(128, initial_value=(exefsIV)) - exefsctrmode2C = AES.new(to_bytes(NormalKey2C), AES.MODE_CTR, counter=exefsctr2C) + exefsctrmode2C = AES.new( + to_bytes(NormalKey2C), + AES.MODE_CTR, + counter=exefsctr2C, + ) g.write(exefsctrmode2C.decrypt(f.read(sectorsize))) - print ("Partition %1d ExeFS: Decrypting: ExeFS Filename Table") % (p) - - if (partition_flags[3] == 0x01 or partition_flags[3] == 0x0A or partition_flags[ - 3] == 0x0B): + print( + f"Partition {p} ExeFS: Decrypting: ExeFS Filename Table" + ) + + if ( + partition_flags[3] == 0x01 + or partition_flags[3] == 0x0A + or partition_flags[3] == 0x0B + ): code_filelen = 0 - for j in xrange(10): # 10 exefs filename slots + for j in range(10): # 10 exefs filename slots # get filename, offset and length - f.seek(((part_off[0] + exefs_off[0]) * sectorsize) + j * 0x10) - g.seek(((part_off[0] + exefs_off[0]) * sectorsize) + j * 0x10) - exefs_filename = struct.unpack('<8s', g.read(0x08)) - if str(exefs_filename[0]) == str(".code\x00\x00\x00"): - code_fileoff = struct.unpack('<L', g.read(0x04)) - code_filelen = struct.unpack('<L', g.read(0x04)) - datalenM = ((code_filelen[0]) / (1024 * 1024)) - datalenB = ((code_filelen[0]) % (1024 * 1024)) - ctroffset = ((code_fileoff[0] + sectorsize) / 0x10) - exefsctr = Counter.new(128, initial_value=(exefsIV + ctroffset)) - exefsctr2C = Counter.new(128, initial_value=(exefsIV + ctroffset)) - exefsctrmode = AES.new(to_bytes(NormalKey), AES.MODE_CTR, counter=exefsctr) - exefsctrmode2C = AES.new(to_bytes(NormalKey2C), AES.MODE_CTR, - counter=exefsctr2C) - f.seek((((part_off[0] + exefs_off[0]) + 1) * sectorsize) + code_fileoff[0]) - g.seek((((part_off[0] + exefs_off[0]) + 1) * sectorsize) + code_fileoff[0]) - if (datalenM > 0): - for i in xrange(datalenM): - g.write(exefsctrmode2C.encrypt( - exefsctrmode.decrypt(f.read(1024 * 1024)))) - print ( - "\rPartition %1d ExeFS: Decrypting: %8s... %4d / %4d mb...") % ( - p, str(exefs_filename[0]), i, datalenM + 1), - if (datalenB > 0): - g.write(exefsctrmode2C.encrypt(exefsctrmode.decrypt(f.read(datalenB)))) - print ( - "\rPartition %1d ExeFS: Decrypting: %8s... %4d / %4d mb... Done!") % ( - p, str(exefs_filename[0]), datalenM + 1, datalenM + 1) + f.seek( + ((part_off[0] + exefs_off[0]) * sectorsize) + + j * 0x10 + ) + g.seek( + ((part_off[0] + exefs_off[0]) * sectorsize) + + j * 0x10 + ) + exefs_filename = struct.unpack( + "<8s", g.read(0x08) + ) + if str(exefs_filename[0]) == str( + ".code\x00\x00\x00" + ): + code_fileoff = struct.unpack( + "<L", g.read(0x04) + ) + code_filelen = struct.unpack( + "<L", g.read(0x04) + ) + datalenM = (code_filelen[0]) / (1024 * 1024) + datalenB = (code_filelen[0]) % (1024 * 1024) + ctroffset = ( + code_fileoff[0] + sectorsize + ) / 0x10 + exefsctr = Counter.new( + 128, initial_value=(exefsIV + ctroffset) + ) + exefsctr2C = Counter.new( + 128, initial_value=(exefsIV + ctroffset) + ) + exefsctrmode = AES.new( + to_bytes(NormalKey), + AES.MODE_CTR, + counter=exefsctr, + ) + exefsctrmode2C = AES.new( + to_bytes(NormalKey2C), + AES.MODE_CTR, + counter=exefsctr2C, + ) + f.seek( + ( + ((part_off[0] + exefs_off[0]) + 1) + * sectorsize + ) + + code_fileoff[0] + ) + g.seek( + ( + ((part_off[0] + exefs_off[0]) + 1) + * sectorsize + ) + + code_fileoff[0] + ) + if datalenM > 0: + for i in range(int(datalenM)): + g.write( + exefsctrmode2C.encrypt( + exefsctrmode.decrypt( + f.read(1024 * 1024) + ) + ) + ) + print( + f"\rPartition {p} ExeFS: Decrypting: {str(exefs_filename[0])}... {i} / {datalenM+1} mb..." + ) + if datalenB > 0: + g.write( + exefsctrmode2C.encrypt( + exefsctrmode.decrypt( + f.read(datalenB) + ) + ) + ) + print( + f"\rPartition {p} ExeFS: Decrypting: {str(exefs_filename[0])}... {datalenM + 1} / {datalenM + 1} mb... Done!" + ) # decrypt exefs - exefsSizeM = ((exefs_len[0] - 1) * sectorsize) / (1024 * 1024) - exefsSizeB = ((exefs_len[0] - 1) * sectorsize) % (1024 * 1024) - ctroffset = (sectorsize / 0x10) - exefsctr2C = Counter.new(128, initial_value=(exefsIV + ctroffset)) - exefsctrmode2C = AES.new(to_bytes(NormalKey2C), AES.MODE_CTR, counter=exefsctr2C) + exefsSizeM = ((exefs_len[0] - 1) * sectorsize) / ( + 1024 * 1024 + ) + exefsSizeB = ((exefs_len[0] - 1) * sectorsize) % ( + 1024 * 1024 + ) + ctroffset = sectorsize / 0x10 + exefsctr2C = Counter.new( + 128, initial_value=(exefsIV + ctroffset) + ) + exefsctrmode2C = AES.new( + to_bytes(NormalKey2C), + AES.MODE_CTR, + counter=exefsctr2C, + ) f.seek((part_off[0] + exefs_off[0] + 1) * sectorsize) g.seek((part_off[0] + exefs_off[0] + 1) * sectorsize) - if (exefsSizeM > 0): - for i in xrange(exefsSizeM): - g.write(exefsctrmode2C.decrypt(f.read(1024 * 1024))) - print ("\rPartition %1d ExeFS: Decrypting: %4d / %4d mb") % ( - p, i, exefsSizeM + 1), - if (exefsSizeB > 0): + if exefsSizeM > 0: + for i in range(int(exefsSizeM)): + g.write( + exefsctrmode2C.decrypt(f.read(1024 * 1024)) + ) + print( + f"\rPartition {p} ExeFS: Decrypting: {i} / {exefsSizeM + 1} mb" + ) + if exefsSizeB > 0: g.write(exefsctrmode2C.decrypt(f.read(exefsSizeB))) - print ("\rPartition %1d ExeFS: Decrypting: %4d / %4d mb... Done") % ( - p, exefsSizeM + 1, exefsSizeM + 1) + print( + f"\rPartition {p} ExeFS: Decrypting: {exefsSizeM + 1} / {exefsSizeM + 1} mb... Done" + ) else: - print ("Partition %1d ExeFS: No Data... Skipping...") % (p) + print(f"Partition {p} ExeFS: No Data... Skipping...") - if (romfs_off[0] != 0): + if romfs_off[0] != 0: romfsSizeM = (romfs_len[0] * sectorsize) / (1024 * 1024) romfsSizeB = (romfs_len[0] * sectorsize) % (1024 * 1024) romfsctr = Counter.new(128, initial_value=romfsIV) - romfsctrmode = AES.new(to_bytes(NormalKey), AES.MODE_CTR, counter=romfsctr) + romfsctrmode = AES.new( + to_bytes(NormalKey), AES.MODE_CTR, counter=romfsctr + ) f.seek((part_off[0] + romfs_off[0]) * sectorsize) g.seek((part_off[0] + romfs_off[0]) * sectorsize) - if (romfsSizeM > 0): - for i in xrange(romfsSizeM): - g.write(romfsctrmode.decrypt(f.read(1024 * 1024))) - print ("\rPartition %1d RomFS: Decrypting: %4d / %4d mb") % ( - p, i, romfsSizeM + 1), - if (romfsSizeB > 0): + if romfsSizeM > 0: + for i in range(int(romfsSizeM)): + g.write( + romfsctrmode.decrypt(f.read(1024 * 1024)) + ) + print( + f"\rPartition {p} RomFS: Decrypting: {i} / {romfsSizeM + 1} mb" + ) + if romfsSizeB > 0: g.write(romfsctrmode.decrypt(f.read(romfsSizeB))) - print ("\rPartition %1d RomFS: Decrypting: %4d / %4d mb... Done") % ( - p, romfsSizeM + 1, romfsSizeM + 1) + print( + f"\rPartition {p} RomFS: Decrypting: {romfsSizeM + 1} / {romfsSizeM + 1} mb... Done" + ) else: - print ("Partition %1d RomFS: No Data... Skipping...") % (p) + print(f"Partition {p} RomFS: No Data... Skipping...") g.seek((part_off[0] * sectorsize) + 0x18B) - g.write(struct.pack('<B', int(0x00))) # set crypto-method to 0x00 + g.write( + struct.pack("<B", int(0x00)) + ) # set crypto-method to 0x00 g.seek((part_off[0] * sectorsize) + 0x18F) flag = int(partition_flags[7]) # read partition flag - flag = (flag & (( - 0x01 | 0x20) ^ 0xFF)) # turn off 0x01 = FixedCryptoKey and 0x20 = CryptoUsingNewKeyY - flag = (flag | 0x04) # turn on 0x04 = NoCrypto - g.write(struct.pack('<B', int(flag))) # write flag + flag = flag & ( + (0x01 | 0x20) ^ 0xFF + ) # turn off 0x01 = FixedCryptoKey and 0x20 = CryptoUsingNewKeyY + flag = flag | 0x04 # turn on 0x04 = NoCrypto + g.write(struct.pack("<B", int(flag))) # write flag else: - print ("Partition %1d Unable to read NCCH header") % (p) + print(f"Partition {p} Unable to read NCCH header") else: - print ("Partition %1d Not found... Skipping...") % (p) - print ("Done...") + print(f"Partition {p} Not found... Skipping...") + print("Done...") else: - print ("Error: Not a 3DS Rom?") + print("Error: Not a 3DS Rom?") # raw_input('Press Enter to Exit...')