Re-encrypt Title Key when setting the Title ID (title module only)

This commit is contained in:
Campbell 2024-07-28 03:28:44 -04:00
parent d6e6352d0a
commit 2d67f982dc
Signed by: NinjaCheetah
GPG Key ID: B547958AF96ED344

View File

@ -3,10 +3,12 @@
# #
# See https://wiibrew.org/wiki/Title for details about how titles are formatted # See https://wiibrew.org/wiki/Title for details about how titles are formatted
import math
from .content import ContentRegion from .content import ContentRegion
from .ticket import Ticket from .ticket import Ticket
from .tmd import TMD from .tmd import TMD
from .wad import WAD from .wad import WAD
from .crypto import encrypt_title_key
class Title: class Title:
@ -120,7 +122,8 @@ class Title:
def set_title_id(self, title_id: str) -> None: def set_title_id(self, title_id: str) -> None:
""" """
Sets the Title ID of the title in both the TMD and Ticket. Sets the Title ID of the title in both the TMD and Ticket. This also re-encrypts the Title Key as the Title Key
is used as the IV for decrypting it.
Parameters Parameters
---------- ----------
@ -130,7 +133,10 @@ class Title:
if len(title_id) != 16: if len(title_id) != 16:
raise ValueError("Invalid Title ID! Title IDs must be 8 bytes long.") raise ValueError("Invalid Title ID! Title IDs must be 8 bytes long.")
self.tmd.set_title_id(title_id) self.tmd.set_title_id(title_id)
title_key_decrypted = self.ticket.get_title_key()
self.ticket.set_title_id(title_id) self.ticket.set_title_id(title_id)
title_key_encrypted = encrypt_title_key(title_key_decrypted, self.ticket.common_key_index, title_id)
self.ticket.title_key_enc = title_key_encrypted
def set_title_version(self, title_version: str | int) -> None: def set_title_version(self, title_version: str | int) -> None:
""" """
@ -184,6 +190,41 @@ class Title:
dec_content = self.content.get_content_by_cid(cid, self.ticket.get_title_key(), skip_hash) dec_content = self.content.get_content_by_cid(cid, self.ticket.get_title_key(), skip_hash)
return dec_content return dec_content
def get_title_size(self) -> int:
"""
Gets the installed size of the title, including the TMD and Ticket, in bytes.
Returns
-------
int
The installed size of the title, in bytes.
"""
title_size = 0
# Dumping and measuring the TMD and Ticket this way to ensure that any changes to them are measured properly.
# Yes, the Ticket size should be a constant, but it's still good to check just in case.
title_size += len(self.tmd.dump())
title_size += len(self.ticket.dump())
# For contents, get their sizes from the content records, because they store the intended sizes of the decrypted
# contents, which are usually different from the encrypted sizes.
for record in self.content.content_records:
title_size += record.content_size
return title_size
def get_title_size_blocks(self) -> int:
"""
Gets the installed size of the title, including the TMD and Ticket, in the Wii's displayed "blocks" format.
1 Wii block is equal to 128KiB, and if any amount of a block is used, the entire block is considered used.
Returns
-------
int
The installed size of the title, in blocks.
"""
title_size_bytes = self.get_title_size()
blocks = math.ceil(title_size_bytes / 131072)
return blocks
def set_enc_content(self, enc_content: bytes, index: int, content_size: int, content_hash: bytes, cid: int = None, def set_enc_content(self, enc_content: bytes, index: int, content_size: int, content_hash: bytes, cid: int = None,
content_type: int = None) -> None: content_type: int = None) -> None:
""" """