mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-27 22:01: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]
|
[project]
|
||||||
name = "libWiiPy"
|
name = "libWiiPy"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
authors = [
|
authors = [
|
||||||
{ name="NinjaCheetah", email="ninjacheetah@ncxprogramming.com" },
|
{ name="NinjaCheetah", email="ninjacheetah@ncxprogramming.com" },
|
||||||
{ name="Lillian Skinner", email="lillian@randommeaninglesscharacters.com" }
|
{ name="Lillian Skinner", email="lillian@randommeaninglesscharacters.com" }
|
||||||
|
@ -7,11 +7,14 @@ common_key = 'ebe42a225e8593e448d9c5457381aaf7'
|
|||||||
korean_key = '63b82bb4f4614e2e13f2fefbba4c9b7e'
|
korean_key = '63b82bb4f4614e2e13f2fefbba4c9b7e'
|
||||||
vwii_key = '30bfc76e7c19afbb23163330ced7c28d'
|
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
|
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
|
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
|
common_key_index : int
|
||||||
The index of the common key to be returned.
|
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
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -27,7 +32,10 @@ def get_common_key(common_key_index) -> bytes:
|
|||||||
"""
|
"""
|
||||||
match common_key_index:
|
match common_key_index:
|
||||||
case 0:
|
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:
|
case 1:
|
||||||
common_key_bin = binascii.unhexlify(korean_key)
|
common_key_bin = binascii.unhexlify(korean_key)
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -30,7 +30,7 @@ def _convert_tid_to_iv(title_id: str | bytes) -> bytes:
|
|||||||
return title_key_iv
|
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.
|
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.
|
The index of the common key used to encrypt the Title Key.
|
||||||
title_id : bytes, str
|
title_id : bytes, str
|
||||||
The Title ID of the title that the key is for.
|
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
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -51,7 +53,7 @@ def decrypt_title_key(title_key_enc: bytes, common_key_index: int, title_id: byt
|
|||||||
The decrypted Title Key.
|
The decrypted Title Key.
|
||||||
"""
|
"""
|
||||||
# Load the correct common key for the title.
|
# 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.
|
# Convert the IV into the correct format based on the type provided.
|
||||||
title_key_iv = _convert_tid_to_iv(title_id)
|
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.
|
# 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
|
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.
|
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.
|
The index of the common key used to encrypt the Title Key.
|
||||||
title_id : bytes, str
|
title_id : bytes, str
|
||||||
The Title ID of the title that the key is for.
|
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
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -84,7 +88,7 @@ def encrypt_title_key(title_key_dec: bytes, common_key_index: int, title_id: byt
|
|||||||
An encrypted Title Key.
|
An encrypted Title Key.
|
||||||
"""
|
"""
|
||||||
# Load the correct common key for the title.
|
# 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.
|
# Convert the IV into the correct format based on the type provided.
|
||||||
title_key_iv = _convert_tid_to_iv(title_id)
|
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.
|
# 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
|
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
|
signature : bytes
|
||||||
The signature applied to the ticket.
|
The signature applied to the ticket.
|
||||||
ticket_version : int
|
ticket_version : int
|
||||||
@ -56,6 +59,8 @@ class Ticket:
|
|||||||
The index of the common key required to decrypt this ticket's Title Key.
|
The index of the common key required to decrypt this ticket's Title Key.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
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
|
# Signature blob header
|
||||||
self.signature_type: bytes = b'' # Type of signature, always 0x10001 for RSA-2048
|
self.signature_type: bytes = b'' # Type of signature, always 0x10001 for RSA-2048
|
||||||
self.signature: bytes = b'' # Actual signature data
|
self.signature: bytes = b'' # Actual signature data
|
||||||
@ -155,6 +160,11 @@ class Ticket:
|
|||||||
limit_type = int.from_bytes(ticket_data.read(4))
|
limit_type = int.from_bytes(ticket_data.read(4))
|
||||||
limit_value = 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))
|
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:
|
def dump(self) -> bytes:
|
||||||
"""
|
"""
|
||||||
@ -315,7 +325,7 @@ class Ticket:
|
|||||||
bytes
|
bytes
|
||||||
The decrypted title key.
|
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
|
return title_key
|
||||||
|
|
||||||
def set_title_id(self, title_id) -> None:
|
def set_title_id(self, title_id) -> None:
|
||||||
|
@ -137,7 +137,8 @@ class Title:
|
|||||||
self.tmd.set_title_id(title_id)
|
self.tmd.set_title_id(title_id)
|
||||||
title_key_decrypted = self.ticket.get_title_key()
|
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)
|
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
|
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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user