mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-26 13:21:01 -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
|
build
|
||||||
|
pycryptodome
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
# "commonkeys.py" from libWiiPy by NinjaCheetah & Contributors
|
# "commonkeys.py" from libWiiPy by NinjaCheetah & Contributors
|
||||||
# https://github.com/NinjaCheetah/libWiiPy
|
# https://github.com/NinjaCheetah/libWiiPy
|
||||||
|
|
||||||
default_key = 'ebe42a225e8593e448d9c5457381aaf7'
|
import binascii
|
||||||
|
|
||||||
|
common_key = 'ebe42a225e8593e448d9c5457381aaf7'
|
||||||
korean_key = '63b82bb4f4614e2e13f2fefbba4c9b7e'
|
korean_key = '63b82bb4f4614e2e13f2fefbba4c9b7e'
|
||||||
vwii_key = '30bfc76e7c19afbb23163330ced7c28d'
|
vwii_key = '30bfc76e7c19afbb23163330ced7c28d'
|
||||||
|
|
||||||
|
|
||||||
def get_default_key():
|
def get_common_key(common_key_index):
|
||||||
"""Returns the regular Wii Common Key used to encrypt most content."""
|
"""
|
||||||
return default_key
|
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
|
||||||
|
"""
|
||||||
def get_korean_key():
|
match common_key_index:
|
||||||
"""Returns the Korean Wii Common Key used to encrypt Korean content."""
|
case 0:
|
||||||
return korean_key
|
common_key_bin = binascii.unhexlify(common_key)
|
||||||
|
case 1:
|
||||||
|
common_key_bin = binascii.unhexlify(korean_key)
|
||||||
def get_vwii_key():
|
case 2:
|
||||||
"""Returns the vWii Common Key used to encrypt vWii-specific content."""
|
common_key_bin = binascii.unhexlify(vwii_key)
|
||||||
return 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
|
# https://github.com/NinjaCheetah/libWiiPy
|
||||||
#
|
#
|
||||||
# See https://wiibrew.org/wiki/Ticket for details about the TMD format
|
# 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
|
# See https://wiibrew.org/wiki/Ticket for details about the TMD format
|
||||||
|
|
||||||
import io
|
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:
|
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.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.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.content_access_permissions: bytes # "Content access permissions (one bit for each content)"
|
||||||
#self.limit_type: int # Type of play limit applied to the title.
|
self.title_limits_list: List[TitleLimit] = [] # List of play limits 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.
|
|
||||||
# v1 ticket data
|
# v1 ticket data
|
||||||
# TODO: Figure out v1 ticket stuff
|
# TODO: Figure out v1 ticket stuff
|
||||||
with io.BytesIO(self.ticket) as ticketdata:
|
with io.BytesIO(self.ticket) as ticketdata:
|
||||||
@ -85,6 +97,12 @@ class Ticket:
|
|||||||
# Content access permissions
|
# Content access permissions
|
||||||
ticketdata.seek(0x222)
|
ticketdata.seek(0x222)
|
||||||
self.content_access_permissions = ticketdata.read(64)
|
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):
|
def get_signature(self):
|
||||||
"""Returns the signature of the ticket."""
|
"""Returns the signature of the ticket."""
|
||||||
@ -131,6 +149,6 @@ class Ticket:
|
|||||||
|
|
||||||
def get_title_key(self):
|
def get_title_key(self):
|
||||||
"""Returns the decrypted title key contained in the ticket."""
|
"""Returns the decrypted title key contained in the ticket."""
|
||||||
# TODO
|
title_key = decrypt_title_key(self.title_key_enc, self.common_key_index, self.title_id)
|
||||||
return b'\x00'
|
return title_key
|
||||||
|
|
||||||
|
@ -29,17 +29,17 @@ class TMD:
|
|||||||
self.version: int # This seems to always be 0 no matter what?
|
self.version: int # This seems to always be 0 no matter what?
|
||||||
self.ca_crl_version: int
|
self.ca_crl_version: int
|
||||||
self.signer_crl_version: int
|
self.signer_crl_version: int
|
||||||
self.vwii: int
|
self.vwii: int # Whether the title is for the vWii. 0 = No, 1 = Yes
|
||||||
self.ios_tid: str
|
self.ios_tid: str # The Title ID of the IOS version the associated title runs on.
|
||||||
self.ios_version: int
|
self.ios_version: int # The IOS version the associated title runs on.
|
||||||
self.title_id: str
|
self.title_id: str # The Title ID of the associated title.
|
||||||
self.content_type: str
|
self.content_type: str # The type of content contained within the associated title.
|
||||||
self.group_id: int # Publisher of the title
|
self.group_id: int # The ID of the publisher of the associated title.
|
||||||
self.region: int
|
self.region: int # The ID of the region of the associated title.
|
||||||
self.ratings: int
|
self.ratings: int
|
||||||
self.access_rights: int
|
self.access_rights: int
|
||||||
self.title_version: int
|
self.title_version: int # The version of the associated title.
|
||||||
self.num_contents: int
|
self.num_contents: int # The number of contents contained in the associated title.
|
||||||
self.boot_index: int
|
self.boot_index: int
|
||||||
self.content_record: List[ContentRecord]
|
self.content_record: List[ContentRecord]
|
||||||
# Load data from TMD file
|
# Load data from TMD file
|
||||||
|
Loading…
x
Reference in New Issue
Block a user