mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-25 12:51:01 -04:00
Add support for extracting/packing/otherwise handling dev WADs
This commit is contained in:
parent
c604c195d2
commit
9ae059b797
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "libWiiPy"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
authors = [
|
||||
{ name="NinjaCheetah", email="ninjacheetah@ncxprogramming.com" },
|
||||
{ name="Lillian Skinner", email="lillian@randommeaninglesscharacters.com" }
|
||||
|
@ -7,11 +7,14 @@ common_key = 'ebe42a225e8593e448d9c5457381aaf7'
|
||||
korean_key = '63b82bb4f4614e2e13f2fefbba4c9b7e'
|
||||
vwii_key = '30bfc76e7c19afbb23163330ced7c28d'
|
||||
|
||||
development_key = 'a1604a6a7123b529ae8bec32c816fcaa'
|
||||
|
||||
def get_common_key(common_key_index) -> bytes:
|
||||
|
||||
def get_common_key(common_key_index, dev=False) -> bytes:
|
||||
"""
|
||||
Gets the specified Wii Common Key based on the index provided. If an invalid common key index is provided, this
|
||||
function falls back on always returning key 0 (the Common Key).
|
||||
function falls back on always returning key 0 (the Common Key). If the kwarg "dev" is specified, then key 0 will
|
||||
point to the development common key rather than the retail one. Keys 1 and 2 are unaffected by this argument.
|
||||
|
||||
Possible values for common_key_index: 0: Common Key, 1: Korean Key, 2: vWii Key
|
||||
|
||||
@ -19,6 +22,8 @@ def get_common_key(common_key_index) -> bytes:
|
||||
----------
|
||||
common_key_index : int
|
||||
The index of the common key to be returned.
|
||||
dev : bool
|
||||
If the dev keys should be used in place of the retail keys. Only affects key 0.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@ -27,7 +32,10 @@ def get_common_key(common_key_index) -> bytes:
|
||||
"""
|
||||
match common_key_index:
|
||||
case 0:
|
||||
common_key_bin = binascii.unhexlify(common_key)
|
||||
if dev:
|
||||
common_key_bin = binascii.unhexlify(development_key)
|
||||
else:
|
||||
common_key_bin = binascii.unhexlify(common_key)
|
||||
case 1:
|
||||
common_key_bin = binascii.unhexlify(korean_key)
|
||||
case 2:
|
||||
|
@ -30,7 +30,7 @@ def _convert_tid_to_iv(title_id: str | bytes) -> bytes:
|
||||
return title_key_iv
|
||||
|
||||
|
||||
def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: bytes | str) -> bytes:
|
||||
def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: bytes | str, dev=False) -> bytes:
|
||||
"""
|
||||
Gets the decrypted version of the encrypted Title Key provided.
|
||||
|
||||
@ -44,6 +44,8 @@ def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: byt
|
||||
The index of the common key used to encrypt the Title Key.
|
||||
title_id : bytes, str
|
||||
The Title ID of the title that the key is for.
|
||||
dev : bool
|
||||
Whether the Title Key is encrypted with the development key or not.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@ -51,7 +53,7 @@ def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: byt
|
||||
The decrypted Title Key.
|
||||
"""
|
||||
# Load the correct common key for the title.
|
||||
common_key = get_common_key(common_key_index)
|
||||
common_key = get_common_key(common_key_index, dev)
|
||||
# Convert the IV into the correct format based on the type provided.
|
||||
title_key_iv = _convert_tid_to_iv(title_id)
|
||||
# The IV will always be in the same format by this point, so add the last 8 bytes.
|
||||
@ -63,7 +65,7 @@ def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: byt
|
||||
return title_key
|
||||
|
||||
|
||||
def encrypt_title_key(title_key_dec: bytes, common_key_index: int, title_id: bytes | str) -> bytes:
|
||||
def encrypt_title_key(title_key_dec: bytes, common_key_index: int, title_id: bytes | str, dev=False) -> bytes:
|
||||
"""
|
||||
Encrypts the provided Title Key with the selected common key.
|
||||
|
||||
@ -77,6 +79,8 @@ def encrypt_title_key(title_key_dec: bytes, common_key_index: int, title_id: byt
|
||||
The index of the common key used to encrypt the Title Key.
|
||||
title_id : bytes, str
|
||||
The Title ID of the title that the key is for.
|
||||
dev : bool
|
||||
Whether the Title Key is encrypted with the development key or not.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@ -84,7 +88,7 @@ def encrypt_title_key(title_key_dec: bytes, common_key_index: int, title_id: byt
|
||||
An encrypted Title Key.
|
||||
"""
|
||||
# Load the correct common key for the title.
|
||||
common_key = get_common_key(common_key_index)
|
||||
common_key = get_common_key(common_key_index, dev)
|
||||
# Convert the IV into the correct format based on the type provided.
|
||||
title_key_iv = _convert_tid_to_iv(title_id)
|
||||
# The IV will always be in the same format by this point, so add the last 8 bytes.
|
||||
|
@ -40,6 +40,9 @@ class Ticket:
|
||||
|
||||
Attributes
|
||||
----------
|
||||
is_dev : bool
|
||||
Whether this Ticket is signed for development or not, and whether the Title Key is encrypted for development
|
||||
or not.
|
||||
signature : bytes
|
||||
The signature applied to the ticket.
|
||||
ticket_version : int
|
||||
@ -56,6 +59,8 @@ class Ticket:
|
||||
The index of the common key required to decrypt this ticket's Title Key.
|
||||
"""
|
||||
def __init__(self):
|
||||
# If this is a dev ticket
|
||||
self.is_dev: bool = False # Defaults to false, set to true during load if this ticket is using dev certs.
|
||||
# Signature blob header
|
||||
self.signature_type: bytes = b'' # Type of signature, always 0x10001 for RSA-2048
|
||||
self.signature: bytes = b'' # Actual signature data
|
||||
@ -155,6 +160,11 @@ class Ticket:
|
||||
limit_type = int.from_bytes(ticket_data.read(4))
|
||||
limit_value = int.from_bytes(ticket_data.read(4))
|
||||
self.title_limits_list.append(_TitleLimit(limit_type, limit_value))
|
||||
# Check certs to see if this is a retail or dev ticket. Treats unknown certs as being retail for now.
|
||||
if self.signature_issuer.find("Root-CA00000002-XS00000006") != -1:
|
||||
self.is_dev = True
|
||||
else:
|
||||
self.is_dev = False
|
||||
|
||||
def dump(self) -> bytes:
|
||||
"""
|
||||
@ -315,7 +325,7 @@ class Ticket:
|
||||
bytes
|
||||
The decrypted title key.
|
||||
"""
|
||||
title_key = decrypt_title_key(self.title_key_enc, self.common_key_index, self.title_id)
|
||||
title_key = decrypt_title_key(self.title_key_enc, self.common_key_index, self.title_id, self.is_dev)
|
||||
return title_key
|
||||
|
||||
def set_title_id(self, title_id) -> None:
|
||||
|
@ -137,7 +137,8 @@ class Title:
|
||||
self.tmd.set_title_id(title_id)
|
||||
title_key_decrypted = self.ticket.get_title_key()
|
||||
self.ticket.set_title_id(title_id)
|
||||
title_key_encrypted = encrypt_title_key(title_key_decrypted, self.ticket.common_key_index, title_id)
|
||||
title_key_encrypted = encrypt_title_key(title_key_decrypted, self.ticket.common_key_index, title_id,
|
||||
self.ticket.is_dev)
|
||||
self.ticket.title_key_enc = title_key_encrypted
|
||||
|
||||
def set_title_version(self, title_version: str | int) -> None:
|
||||
|
Loading…
x
Reference in New Issue
Block a user