mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-26 05:11:02 -04:00
Added function to ticket.py to return the decrypted Title Key
Also added crypto.py which will manage all crypto-related functionality in the library. Currently only offers a function to decrypt a given Title Key. ticket.py now creates a list of play limits placed on a title.
This commit is contained in:
parent
d86c754ebf
commit
3c5f8b6763
@ -1 +1,2 @@
|
||||
build
|
||||
pycryptodome
|
||||
|
@ -1,21 +1,25 @@
|
||||
# "commonkeys.py" from libWiiPy by NinjaCheetah & Contributors
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
|
||||
default_key = 'ebe42a225e8593e448d9c5457381aaf7'
|
||||
import binascii
|
||||
|
||||
common_key = 'ebe42a225e8593e448d9c5457381aaf7'
|
||||
korean_key = '63b82bb4f4614e2e13f2fefbba4c9b7e'
|
||||
vwii_key = '30bfc76e7c19afbb23163330ced7c28d'
|
||||
|
||||
|
||||
def get_default_key():
|
||||
"""Returns the regular Wii Common Key used to encrypt most content."""
|
||||
return default_key
|
||||
|
||||
|
||||
def get_korean_key():
|
||||
"""Returns the Korean Wii Common Key used to encrypt Korean content."""
|
||||
return korean_key
|
||||
|
||||
|
||||
def get_vwii_key():
|
||||
"""Returns the vWii Common Key used to encrypt vWii-specific content."""
|
||||
return vwii_key
|
||||
def get_common_key(common_key_index):
|
||||
"""
|
||||
Returns the specified Wii Common Key based on the index provided.
|
||||
Possible values for common_key_index: 0: Common Key, 1: Korean Key, 2: vWii Key
|
||||
"""
|
||||
match common_key_index:
|
||||
case 0:
|
||||
common_key_bin = binascii.unhexlify(common_key)
|
||||
case 1:
|
||||
common_key_bin = binascii.unhexlify(korean_key)
|
||||
case 2:
|
||||
common_key_bin = binascii.unhexlify(vwii_key)
|
||||
case _:
|
||||
raise ValueError("The common key index provided, " + str(common_key_index + ", does not exist."))
|
||||
return common_key_bin
|
||||
|
@ -2,3 +2,22 @@
|
||||
# https://github.com/NinjaCheetah/libWiiPy
|
||||
#
|
||||
# See https://wiibrew.org/wiki/Ticket for details about the TMD format
|
||||
|
||||
from .commonkeys import get_common_key
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
|
||||
def decrypt_title_key(title_key_enc, common_key_index, title_id):
|
||||
"""
|
||||
Returns the decrypted version of the encrypted Title Key provided.
|
||||
Requires the index of the common key to use, and the Title ID of the title that the Title Key is for.
|
||||
"""
|
||||
# Load the correct common key for the title.
|
||||
common_key = get_common_key(common_key_index)
|
||||
# Calculate the IV by adding 8 bytes to the end of the Title ID.
|
||||
title_key_iv = title_id + (b'\x00' * 8)
|
||||
# Create a new AES object with the values provided.
|
||||
aes = AES.new(common_key, AES.MODE_CBC, title_key_iv)
|
||||
# Decrypt the Title Key using the AES object.
|
||||
title_key = aes.decrypt(title_key_enc)
|
||||
return title_key
|
||||
|
@ -4,6 +4,20 @@
|
||||
# See https://wiibrew.org/wiki/Ticket for details about the TMD format
|
||||
|
||||
import io
|
||||
from .crypto import decrypt_title_key
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
|
||||
@dataclass
|
||||
class TitleLimit:
|
||||
"""Creates a TitleLimit object that contains the type of restriction and the limit."""
|
||||
# The type of play limit applied. The following types exist:
|
||||
# 0 = None, 1 = Time Limit, 3 = None, 4 = Launch Count
|
||||
limit_type: int
|
||||
# The maximum value of the limit applied.
|
||||
# This is either the number of minutes for a time limit, or the number of launches for a launch limit.
|
||||
maximum_usage: int
|
||||
|
||||
|
||||
class Ticket:
|
||||
@ -28,9 +42,7 @@ class Ticket:
|
||||
self.title_export_allowed: int # Whether title export is allowed with a PRNG key or not.
|
||||
self.common_key_index: int # Which common key should be used. 0 = Common Key, 1 = Korean Key, 2 = vWii Key
|
||||
self.content_access_permissions: bytes # "Content access permissions (one bit for each content)"
|
||||
#self.limit_type: int # Type of play limit applied to the title.
|
||||
# 0 = None, 1 = Time Limit, 3 = None, 4 = Launch Count
|
||||
#self.maximum_launches: int # Maximum for the selected limit type, being either minutes or launches.
|
||||
self.title_limits_list: List[TitleLimit] = [] # List of play limits applied to the title.
|
||||
# v1 ticket data
|
||||
# TODO: Figure out v1 ticket stuff
|
||||
with io.BytesIO(self.ticket) as ticketdata:
|
||||
@ -85,6 +97,12 @@ class Ticket:
|
||||
# Content access permissions
|
||||
ticketdata.seek(0x222)
|
||||
self.content_access_permissions = ticketdata.read(64)
|
||||
# Content limits
|
||||
ticketdata.seek(0x264)
|
||||
for limit in range(0, 8):
|
||||
limit_type = int.from_bytes(ticketdata.read(4))
|
||||
limit_value = int.from_bytes(ticketdata.read(4))
|
||||
self.title_limits_list.append(TitleLimit(limit_type, limit_value))
|
||||
|
||||
def get_signature(self):
|
||||
"""Returns the signature of the ticket."""
|
||||
@ -131,6 +149,6 @@ class Ticket:
|
||||
|
||||
def get_title_key(self):
|
||||
"""Returns the decrypted title key contained in the ticket."""
|
||||
# TODO
|
||||
return b'\x00'
|
||||
title_key = decrypt_title_key(self.title_key_enc, self.common_key_index, self.title_id)
|
||||
return title_key
|
||||
|
||||
|
@ -29,17 +29,17 @@ class TMD:
|
||||
self.version: int # This seems to always be 0 no matter what?
|
||||
self.ca_crl_version: int
|
||||
self.signer_crl_version: int
|
||||
self.vwii: int
|
||||
self.ios_tid: str
|
||||
self.ios_version: int
|
||||
self.title_id: str
|
||||
self.content_type: str
|
||||
self.group_id: int # Publisher of the title
|
||||
self.region: int
|
||||
self.vwii: int # Whether the title is for the vWii. 0 = No, 1 = Yes
|
||||
self.ios_tid: str # The Title ID of the IOS version the associated title runs on.
|
||||
self.ios_version: int # The IOS version the associated title runs on.
|
||||
self.title_id: str # The Title ID of the associated title.
|
||||
self.content_type: str # The type of content contained within the associated title.
|
||||
self.group_id: int # The ID of the publisher of the associated title.
|
||||
self.region: int # The ID of the region of the associated title.
|
||||
self.ratings: int
|
||||
self.access_rights: int
|
||||
self.title_version: int
|
||||
self.num_contents: int
|
||||
self.title_version: int # The version of the associated title.
|
||||
self.num_contents: int # The number of contents contained in the associated title.
|
||||
self.boot_index: int
|
||||
self.content_record: List[ContentRecord]
|
||||
# Load data from TMD file
|
||||
|
Loading…
x
Reference in New Issue
Block a user