Replaced unnecessary BytesIO usages with standard variables

This commit is contained in:
Campbell 2024-05-06 19:34:18 -04:00
parent 98666285db
commit 045613216a
No known key found for this signature in database
GPG Key ID: E543751376940756
7 changed files with 184 additions and 204 deletions

View File

@ -79,21 +79,18 @@ class ContentRegion:
bytes bytes
The full WAD file as bytes. The full WAD file as bytes.
""" """
# Open the stream and begin writing data to it. content_region_data = b''
with io.BytesIO() as content_region_data: for content in self.content_list:
for content in self.content_list: # Calculate padding after this content before the next one.
# Calculate padding after this content before the next one. padding_bytes = 0
padding_bytes = 0 if (len(content) % 64) != 0:
if (len(content) % 64) != 0: padding_bytes = 64 - (len(content) % 64)
padding_bytes = 64 - (len(content) % 64) # Write content data, then the padding afterward if necessary.
# Write content data, then the padding afterward if necessary. content_region_data += content
content_region_data.write(content) if padding_bytes > 0:
if padding_bytes > 0: content_region_data += b'\x00' * padding_bytes
content_region_data.write(b'\x00' * padding_bytes)
content_region_data.seek(0x0)
content_region_raw = content_region_data.read()
# Return the raw ContentRegion for the data contained in the object. # Return the raw ContentRegion for the data contained in the object.
return content_region_raw return content_region_data
def get_enc_content_by_index(self, index: int) -> bytes: def get_enc_content_by_index(self, index: int) -> bytes:
""" """

View File

@ -1,5 +1,6 @@
# "crypto.py" from libWiiPy by NinjaCheetah & Contributors # "crypto.py" from libWiiPy by NinjaCheetah & Contributors
# https://github.com/NinjaCheetah/libWiiPy # https://github.com/NinjaCheetah/libWiiPy
import struct import struct
from .commonkeys import get_common_key from .commonkeys import get_common_key
from .shared import convert_tid_to_iv from .shared import convert_tid_to_iv

View File

@ -3,7 +3,6 @@
# #
# See https://wiibrew.org/wiki/NUS for details about the NUS # See https://wiibrew.org/wiki/NUS for details about the NUS
import io
import requests import requests
import hashlib import hashlib
from typing import List from typing import List
@ -151,15 +150,13 @@ def download_cert(wiiu_endpoint: bool = False) -> bytes:
tmd = requests.get(url=tmd_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True).content tmd = requests.get(url=tmd_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True).content
cetk = requests.get(url=cetk_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True).content cetk = requests.get(url=cetk_url, headers={'User-Agent': 'wii libnup/1.0'}, stream=True).content
# Assemble the certificate. # Assemble the certificate.
with io.BytesIO() as cert_data: cert = b''
# Certificate Authority data. # Certificate Authority data.
cert_data.write(cetk[0x2A4 + 768:]) cert += cetk[0x2A4 + 768:]
# Certificate Policy data. # Certificate Policy data.
cert_data.write(tmd[0x328:0x328 + 768]) cert += tmd[0x328:0x328 + 768]
# XS data. # XS data.
cert_data.write(cetk[0x2A4:0x2A4 + 768]) cert += cetk[0x2A4:0x2A4 + 768]
cert_data.seek(0x0)
cert = cert_data.read()
# Since the cert is always the same, check the hash to make sure nothing went wildly wrong. # Since the cert is always the same, check the hash to make sure nothing went wildly wrong.
if hashlib.sha1(cert).hexdigest() != "ace0f15d2a851c383fe4657afc3840d6ffe30ad0": if hashlib.sha1(cert).hexdigest() != "ace0f15d2a851c383fe4657afc3840d6ffe30ad0":
raise Exception("An unknown error has occurred downloading and creating the certificate.") raise Exception("An unknown error has occurred downloading and creating the certificate.")

View File

@ -6,6 +6,7 @@
import binascii import binascii
def align_value(value, alignment=64) -> int: def align_value(value, alignment=64) -> int:
""" """
Aligns the provided value to the set alignment (defaults to 64). Aligns the provided value to the set alignment (defaults to 64).
@ -28,24 +29,24 @@ def align_value(value, alignment=64) -> int:
return value return value
def pad_bytes_stream(data, alignment=64) -> bytes: def pad_bytes(data, alignment=64) -> bytes:
""" """
Pads the provided bytes stream to the provided alignment (defaults to 64). Pads the provided bytes object to the provided alignment (defaults to 64).
Parameters Parameters
---------- ----------
data : BytesIO data : bytes
The data to align. The data to align.
alignment : int alignment : int
The number to align to. Defaults to 64. The number to align to. Defaults to 64.
Returns Returns
------- -------
BytesIO bytes
The aligned data. The aligned data.
""" """
while (data.getbuffer().nbytes % alignment) != 0: while (len(data) % alignment) != 0:
data.write(b'\x00') data += b'\x00'
return data return data

View File

@ -146,68 +146,62 @@ class Ticket:
bytes bytes
The full Ticket file as bytes. The full Ticket file as bytes.
""" """
# Open the stream and begin writing to it. ticket_data = b''
with io.BytesIO() as ticket_data: # Signature type.
# Signature type. ticket_data += self.signature_type
ticket_data.write(self.signature_type) # Signature data.
# Signature data. ticket_data += self.signature
ticket_data.write(self.signature) # Padding to 64 bytes.
# Padding to 64 bytes. ticket_data += b'\x00' * 60
ticket_data.write(b'\x00' * 60) # Signature issuer.
# Signature issuer. ticket_data += str.encode(self.signature_issuer)
ticket_data.write(str.encode(self.signature_issuer)) # ECDH data.
# ECDH data. ticket_data += self.ecdh_data
ticket_data.write(self.ecdh_data) # Ticket version.
# Ticket version. ticket_data += int.to_bytes(self.ticket_version, 1)
ticket_data.write(int.to_bytes(self.ticket_version, 1)) # Reserved (all \0x00).
# Reserved (all \0x00). ticket_data += b'\x00\x00'
ticket_data.write(b'\x00\x00') # Title Key.
# Title Key. ticket_data += self.title_key_enc
ticket_data.write(self.title_key_enc) # Unknown (write \0x00).
# Unknown (write \0x00). ticket_data += b'\x00'
ticket_data.write(b'\x00') # Ticket ID.
# Ticket ID. ticket_data += self.ticket_id
ticket_data.write(self.ticket_id) # Console ID.
# Console ID. ticket_data += int.to_bytes(self.console_id, 4)
ticket_data.write(int.to_bytes(self.console_id, 4)) # Title ID.
# Title ID. ticket_data += binascii.unhexlify(self.title_id)
ticket_data.write(binascii.unhexlify(self.title_id)) # Unknown data 1.
# Unknown data 1. ticket_data += self.unknown1
ticket_data.write(self.unknown1) # Title version.
# Title version. title_version_high = round(self.title_version / 256)
title_version_high = round(self.title_version / 256) ticket_data += int.to_bytes(title_version_high, 1)
ticket_data.write(int.to_bytes(title_version_high, 1)) title_version_low = self.title_version % 256
title_version_low = self.title_version % 256 ticket_data += int.to_bytes(title_version_low, 1)
ticket_data.write(int.to_bytes(title_version_low, 1)) # Permitted titles mask.
# Permitted titles mask. ticket_data += self.permitted_titles
ticket_data.write(self.permitted_titles) # Permit mask.
# Permit mask. ticket_data += self.permit_mask
ticket_data.write(self.permit_mask) # Title Export allowed.
# Title Export allowed. ticket_data += int.to_bytes(self.title_export_allowed, 1)
ticket_data.write(int.to_bytes(self.title_export_allowed, 1)) # Common Key index.
# Common Key index. ticket_data += int.to_bytes(self.common_key_index, 1)
ticket_data.write(int.to_bytes(self.common_key_index, 1)) # Unknown data 2.
# Unknown data 2. ticket_data += self.unknown2
ticket_data.write(self.unknown2) # Content access permissions.
# Content access permissions. ticket_data += self.content_access_permissions
ticket_data.write(self.content_access_permissions) # Padding (always \x00).
# Padding (always \x00). ticket_data += b'\x00\x00'
ticket_data.write(b'\x00\x00') # Iterate over Title Limit objects, write them back into raw data, then add them to the Ticket.
# Iterate over Title Limit objects, write them back into raw data, then add them to the Ticket. for title_limit in range(len(self.title_limits_list)):
for title_limit in range(len(self.title_limits_list)): title_limit_data = b''
title_limit_data = io.BytesIO() # Write all fields from the title limit entry.
# Write all fields from the title limit entry. title_limit_data += int.to_bytes(self.title_limits_list[title_limit].limit_type, 4)
title_limit_data.write(int.to_bytes(self.title_limits_list[title_limit].limit_type, 4)) title_limit_data += int.to_bytes(self.title_limits_list[title_limit].maximum_usage, 4)
title_limit_data.write(int.to_bytes(self.title_limits_list[title_limit].maximum_usage, 4)) # Write the entry to the ticket.
# Seek to the start and write the entry to the Ticket. ticket_data += title_limit_data
title_limit_data.seek(0x0)
ticket_data.write(title_limit_data.read())
title_limit_data.close()
# Set the Ticket attribute of the object to the new raw Ticket.
ticket_data.seek(0x0)
ticket_data_raw = ticket_data.read()
# Return the raw TMD for the data contained in the object. # Return the raw TMD for the data contained in the object.
return ticket_data_raw return ticket_data
def get_title_id(self) -> str: def get_title_id(self) -> str:
""" """

View File

@ -148,78 +148,72 @@ class TMD:
bytes bytes
The full TMD file as bytes. The full TMD file as bytes.
""" """
# Open the stream and begin writing to it. tmd_data = b''
with io.BytesIO() as tmd_data: # Signed blob header.
# Signed blob header. tmd_data += self.blob_header
tmd_data.write(self.blob_header) # Signing certificate issuer.
# Signing certificate issuer. tmd_data += self.issuer
tmd_data.write(self.issuer) # TMD version.
# TMD version. tmd_data += int.to_bytes(self.tmd_version, 1)
tmd_data.write(int.to_bytes(self.tmd_version, 1)) # Root certificate crl version.
# Root certificate crl version. tmd_data += int.to_bytes(self.ca_crl_version, 1)
tmd_data.write(int.to_bytes(self.ca_crl_version, 1)) # Signer crl version.
# Signer crl version. tmd_data += int.to_bytes(self.signer_crl_version, 1)
tmd_data.write(int.to_bytes(self.signer_crl_version, 1)) # If this is a vWii title or not.
# If this is a vWii title or not. tmd_data += int.to_bytes(self.vwii, 1)
tmd_data.write(int.to_bytes(self.vwii, 1)) # IOS Title ID.
# IOS Title ID. tmd_data += binascii.unhexlify(self.ios_tid)
tmd_data.write(binascii.unhexlify(self.ios_tid)) # Title's Title ID.
# Title's Title ID. tmd_data += binascii.unhexlify(self.title_id)
tmd_data.write(binascii.unhexlify(self.title_id)) # Content type.
# Content type. tmd_data += binascii.unhexlify(self.content_type)
tmd_data.write(binascii.unhexlify(self.content_type)) # Group ID.
# Group ID. tmd_data += int.to_bytes(self.group_id, 2)
tmd_data.write(int.to_bytes(self.group_id, 2)) # 2 bytes of zero for reasons.
# 2 bytes of zero for reasons. tmd_data += b'\x00\x00'
tmd_data.write(b'\x00\x00') # Region.
# Region. tmd_data += int.to_bytes(self.region, 2)
tmd_data.write(int.to_bytes(self.region, 2)) # Ratings.
# Ratings. tmd_data += self.ratings
tmd_data.write(self.ratings) # Reserved (all \x00).
# Reserved (all \x00). tmd_data += b'\x00' * 12
tmd_data.write(b'\x00' * 12) # IPC mask.
# IPC mask. tmd_data += self.ipc_mask
tmd_data.write(self.ipc_mask) # Reserved (all \x00).
# Reserved (all \x00). tmd_data += b'\x00' * 18
tmd_data.write(b'\x00' * 18) # Access rights.
# Access rights. tmd_data += self.access_rights
tmd_data.write(self.access_rights) # Title version.
# Title version. title_version_high = round(self.title_version / 256)
title_version_high = round(self.title_version / 256) tmd_data += int.to_bytes(title_version_high, 1)
tmd_data.write(int.to_bytes(title_version_high, 1)) title_version_low = self.title_version % 256
title_version_low = self.title_version % 256 tmd_data += int.to_bytes(title_version_low, 1)
tmd_data.write(int.to_bytes(title_version_low, 1)) # Number of contents.
# Number of contents. tmd_data += int.to_bytes(self.num_contents, 2)
tmd_data.write(int.to_bytes(self.num_contents, 2)) # Boot index.
# Boot index. tmd_data += int.to_bytes(self.boot_index, 2)
tmd_data.write(int.to_bytes(self.boot_index, 2)) # Minor version. Unused so write \x00.
# Minor version. Unused so write \x00. tmd_data += b'\x00\x00'
tmd_data.write(b'\x00\x00') # Iterate over content records, write them back into raw data, then add them to the TMD.
# Iterate over content records, write them back into raw data, then add them to the TMD. for content_record in range(self.num_contents):
for content_record in range(self.num_contents): content_data = b''
content_data = io.BytesIO() # Write all fields from the content record.
# Write all fields from the content record. content_data += int.to_bytes(self.content_records[content_record].content_id, 4)
content_data.write(int.to_bytes(self.content_records[content_record].content_id, 4)) content_data += int.to_bytes(self.content_records[content_record].index, 2)
content_data.write(int.to_bytes(self.content_records[content_record].index, 2)) content_data += int.to_bytes(self.content_records[content_record].content_type, 2)
content_data.write(int.to_bytes(self.content_records[content_record].content_type, 2)) content_data += int.to_bytes(self.content_records[content_record].content_size, 8)
content_data.write(int.to_bytes(self.content_records[content_record].content_size, 8)) content_data += binascii.unhexlify(self.content_records[content_record].content_hash)
content_data.write(binascii.unhexlify(self.content_records[content_record].content_hash)) # Write the record to the TMD.
# Seek to the start and write the record to the TMD. tmd_data += content_data
content_data.seek(0x0)
tmd_data.write(content_data.read())
content_data.close()
# Set the TMD attribute of the object to the new raw TMD.
tmd_data.seek(0x0)
tmd_data_raw = tmd_data.read()
# Return the raw TMD for the data contained in the object. # Return the raw TMD for the data contained in the object.
return tmd_data_raw return tmd_data
def get_title_region(self) -> str: def get_title_region(self) -> str:
""" """
Gets the region of the TMD's associated title. Gets the region of the TMD's associated title.
Can be one of several possible values: Can be one of several possible values:
'JAP', 'USA', 'EUR', 'NONE', or 'KOR'. 'JAP', 'USA', 'EUR', 'WORLD', or 'KOR'.
Returns Returns
------- -------
@ -234,7 +228,7 @@ class TMD:
case 2: case 2:
return "EUR" return "EUR"
case 3: case 3:
return "NONE" return "WORLD"
case 4: case 4:
return "KOR" return "KOR"

View File

@ -5,7 +5,7 @@
import io import io
import binascii import binascii
from .shared import align_value, pad_bytes_stream from .shared import align_value, pad_bytes
class WAD: class WAD:
@ -15,7 +15,7 @@ class WAD:
Attributes Attributes
---------- ----------
wad_type : str wad_type : str
The type of WAD, either ib for boot2 or Is for normal installable WADs. libWiiPy only supports Is currently. The type of WAD, either ib for boot2 or Is for normal installable WADs.
wad_cert_size : int wad_cert_size : int
The size of the WAD's certificate. The size of the WAD's certificate.
wad_crl_size : int wad_crl_size : int
@ -60,8 +60,8 @@ class WAD:
The data for the WAD you wish to load. The data for the WAD you wish to load.
""" """
with io.BytesIO(wad_data) as wad_data: with io.BytesIO(wad_data) as wad_data:
# Read the first 8 bytes of the file to ensure that it's a WAD. This will currently reject boot2 WADs, but # Read the first 8 bytes of the file to ensure that it's a WAD. Has two possible valid values for the two
# this tool cannot handle them correctly right now anyway. # different types of WADs that might be encountered.
wad_data.seek(0x0) wad_data.seek(0x0)
wad_magic_bin = wad_data.read(8) wad_magic_bin = wad_data.read(8)
wad_magic_hex = binascii.hexlify(wad_magic_bin) wad_magic_hex = binascii.hexlify(wad_magic_bin)
@ -140,50 +140,46 @@ class WAD:
bytes bytes
The full WAD file as bytes. The full WAD file as bytes.
""" """
# Open the stream and begin writing data to it. wad_data = b''
with io.BytesIO() as wad_data: # Lead-in data.
# Lead-in data. wad_data += b'\x00\x00\x00\x20'
wad_data.write(b'\x00\x00\x00\x20') # WAD type.
# WAD type. wad_data += str.encode(self.wad_type)
wad_data.write(str.encode(self.wad_type)) # WAD version.
# WAD version. wad_data += self.wad_version
wad_data.write(self.wad_version) # WAD cert size.
# WAD cert size. wad_data += int.to_bytes(self.wad_cert_size, 4)
wad_data.write(int.to_bytes(self.wad_cert_size, 4)) # WAD crl size.
# WAD crl size. wad_data += int.to_bytes(self.wad_crl_size, 4)
wad_data.write(int.to_bytes(self.wad_crl_size, 4)) # WAD ticket size.
# WAD ticket size. wad_data += int.to_bytes(self.wad_tik_size, 4)
wad_data.write(int.to_bytes(self.wad_tik_size, 4)) # WAD TMD size.
# WAD TMD size. wad_data += int.to_bytes(self.wad_tmd_size, 4)
wad_data.write(int.to_bytes(self.wad_tmd_size, 4)) # WAD content size.
# WAD content size. wad_data += int.to_bytes(self.wad_content_size, 4)
wad_data.write(int.to_bytes(self.wad_content_size, 4)) # WAD meta size.
# WAD meta size. wad_data += int.to_bytes(self.wad_meta_size, 4)
wad_data.write(int.to_bytes(self.wad_meta_size, 4)) wad_data = pad_bytes(wad_data)
wad_data = pad_bytes_stream(wad_data) # Retrieve the cert data and write it out.
# Retrieve the cert data and write it out. wad_data += self.get_cert_data()
wad_data.write(self.get_cert_data()) wad_data = pad_bytes(wad_data)
wad_data = pad_bytes_stream(wad_data) # Retrieve the crl data and write it out.
# Retrieve the crl data and write it out. wad_data += self.get_crl_data()
wad_data.write(self.get_crl_data()) wad_data = pad_bytes(wad_data)
wad_data = pad_bytes_stream(wad_data) # Retrieve the ticket data and write it out.
# Retrieve the ticket data and write it out. wad_data += self.get_ticket_data()
wad_data.write(self.get_ticket_data()) wad_data = pad_bytes(wad_data)
wad_data = pad_bytes_stream(wad_data) # Retrieve the TMD data and write it out.
# Retrieve the TMD data and write it out. wad_data += self.get_tmd_data()
wad_data.write(self.get_tmd_data()) wad_data = pad_bytes(wad_data)
wad_data = pad_bytes_stream(wad_data) # Retrieve the meta/footer data and write it out.
# Retrieve the meta/footer data and write it out. wad_data += self.get_meta_data()
wad_data.write(self.get_meta_data()) wad_data = pad_bytes(wad_data)
wad_data = pad_bytes_stream(wad_data) # Retrieve the content data and write it out.
# Retrieve the content data and write it out. wad_data += self.get_content_data()
wad_data.write(self.get_content_data()) wad_data = pad_bytes(wad_data)
wad_data = pad_bytes_stream(wad_data)
# Seek to the beginning and save this as the WAD data for the object.
wad_data.seek(0x0)
wad_data_raw = wad_data.read()
# Return the raw WAD file for the data contained in the object. # Return the raw WAD file for the data contained in the object.
return wad_data_raw return wad_data
def get_wad_type(self) -> str: def get_wad_type(self) -> str:
""" """