Ticket
Tickets sind in vielen verschlüsselten Dateien, die von der Wii genutzt werden, vorhanden (wie WADs oder Wii-Discs). Sie enthalten unter Anderem den verschlüsselten AES "Title-Key" und die Title ID der Daten und sind mit einem Zertifikat einer Zertifikatskette (welche für alle Titel gleich und im NAND gespeichert ist) signiert. Es gibt nur Tickets mit einer RSA-2048-Signatur. Tickets können bei freien, nicht konsolengebundenen Titeln vom Nintendo-Update-Server heruntergeladen werden (bspw. http://nus.cdn.shop.wii.com/ccs/download/000000010000003A/cetk für das Ticket vom IOS58).
Im Dateisystem liegen Tickets in /ticket/<TitleID-high>/<TitleID-low>.tik. Hierbei werden mehrere Tickets für den gleichen Titel angehängt, d.h. eine TIK-Datei kann mehrere Tickets enthalten (676 Bytes pro Ticket).
Datenstruktur
| Start | Ende | Länge in Byte | Beschreibung |
|---|---|---|---|
| 0x0000 | 0x0003 | 4 | Signatur-Typ (immer 0x10001 für RSA-2048) |
| 0x0004 | 0x0103 | 256 | Signatur |
| 0x0104 | 0x013F | 60 | Padding (immer 0; alles nach diesem Feld wird von der obigen Signatur abgedeckt) |
| 0x0140 | 0x017F | 64 | Aussteller, z.B. Root-CA00000001-XS00000003. Der hintere Teil ist der Name des Zertifikats, mit dem geprüft wird, und muss bei einem Ticket mit XS beginnen
|
| 0x0180 | 0x01BB | 60 | ECDH-Daten; öffentlicher ECC-B233-Schlüssel des Ticket-Servers. Ist die Konsolen-ID != 0, rechnet ES daraus mit dem eigenen Gerätesschlüssel einen gemeinsamen Schlüssel und entschlüsselt den Title-Key damit. IV = Ticket-ID + 8 Nullbytes. Erst danach folgt die Common-Key-Verschlüsselung. |
| 0x01BC | 0x01BC | 1 | Version der Datenstruktur (immer 0) |
| 0x01BD | 0x01BD | 1 | CA-CRL-Version. Wird von ES nicht ausgewertet |
| 0x01BE | 0x01BE | 1 | Signer-CRL-Version. Wird von ES nicht ausgewertet |
| 0x01BF | 0x01CE | 16 | Verschlüsselter Title-Key |
| 0x01CF | 0x01CF | 1 | Padding |
| 0x01D0 | 0x01D7 | 8 | Ticket-ID (genutzt als Initialisierungsvektor für die Entschlüsselung des Title-Keys von konsolenspezifischen Titeln) |
| 0x01D8 | 0x01DB | 4 | Konsolen-ID |
| 0x01DC | 0x01E3 | 8 | Title ID / Initialisierungsvektor für die AES-CBC-Verschlüsselung |
| 0x01E4 | 0x01E5 | 2 | System Access Mask - Bitmaske, die angibt, auf welche der ersten 16 Inhalte das Wii-Systemmenü zugreifen darf. U.a. benutzt beim Fotokanal |
| 0x01E6 | 0x01E7 | 2 | Ticket-Version |
| 0x01E8 | 0x01EB | 4 | Erlaubte Title-ID - untere 32 Bit der Title-ID, die dieses Ticket öffnen/benutzen darf |
| 0x01EC | 0x01EF | 4 | Maske zu oberem Feld. Die untere Hälfte der Title-ID des laufenden Titels wird mit der Umkehrung dieser Maske UND-verknüpft; das Ergebnis muss der erlaubten Title-ID entsprechen |
| 0x01F0 | 0x01F0 | 1 | Lizenztyp. Untere 4 Bits: 0 = Permanent, 1 = Demo, 2 = Trial, 3 = Ausleihe, 4 = Subscription, 5 = Service. Bit 0x80 = Geschenk |
| 0x01F1 | 0x01F1 | 1 | Common-Key-Index (0 = "Normaler" Common-Key, 1 = Koreanischer Common-Key, 2 = vWii) |
| 0x01F2 | 0x0220 | 47 | Reserviert |
| 0x0221 | 0x0221 | 1 | Audit-Feld |
| 0x0222 | 0x0261 | 64 | Inhaltszugriffsberechtigungen: ein Bit je Inhalt |
| 0x0262 | 0x0263 | 2 | Padding |
| 0x0264 | 0x02A3 | 64 | 8 Limits, je 8 Byte. Von Nintendo nie genutzt[1], aber als Aprilscherz vom Homebrewkanal[2] |
Um an den entschlüsselten Title-Key zu kommen, müssen die 16 Byte beim Offset 0x1BF mit dem Common-Key entschlüsselt werden, wobei die Title ID (Offset 0x1DC) als Initialisierungsvektor genutzt wird (die letzten 8 Byte des IV sind 0).
Inhaltszugriffsberechtigungen
Das Ticket gibt nicht automatisch alle Inhalte eines Titels frei. Dafür sind die 64 Byte ab 0x0222 da: jedes Bit steht für einen Inhalt, also das erste Byte für die Inhalte 0 bis 7, das zweite für 8 bis 15 usw. Steht dort FF, sind alle acht Inhalte des Bytes freigegeben, bei 01 nur der erste davon, etc. Fehlt das Bit, verweigert ES das Öffnen des Inhalts.
Die System Access Mask bei 0x01E4 funktioniert genauso, nur eben für das Systemmenü und beschränkt auf die ersten 16 Inhalte.
Signatur
Signiert wird der SHA1-Hash über den Bereich vom Aussteller (0x0140) bis zum Ende des Tickets, also 356 Byte. Geprüft wird er mit dem XS-Zertifikat. Beim Download vom NUS hängt die Kette hinter dem Ticket, im NAND nimmt ES sie aus /sys/cert.sys.
Fakesigned heißt: die Signatur ist genullt und die reservierten Bytes ab 0x01F2 sind so lange verändert worden, bis der SHA1-Hash des Tickets mit 00 beginnt. Frühe IOS-Versionen verglichen den Hash mit strncmp, das beim ersten Nullbyte aufhört zu vergleichen, und nahmen so ein Ticket als gültig an (siehe Trucha Bug).
ES prüft Ticket und TMD getrennt, für einen selbst installierten Titel muss also beides fakesigned sein. Moderne WAD-Manager erledigen dies direkt auf der Konsole.
Limit
Ein Ticket kann acht Limits (wie z.B. Zeitbeschränkungen für Demoversionen) beinhalten. Nicht benutzte Einträge haben den Typ 0. D.h. Limits lassen sich auch kombinieren.
| Start | Ende | Länge in Byte | Beschreibung |
|---|---|---|---|
| 0x0000 | 0x0003 | 4 | Typ (siehe unten) |
| 0x0004 | 0x0007 | 4 | Wert: Sekunden oder Anzahl, je nach Typ |
Der Verbrauch wird je Ticket-ID in /sys/cc.sys mitgezählt (außer für Typ = 3). Erreicht er den Wert, verweigert ES den Start des Titels.
Typ
| Typ | Bedeutung | Wert |
|---|---|---|
| 0 | Unbenutzt | |
| 1 | Spielzeit | Sekunden |
| 2 | Absoluter Zeitpunkt | Unix-Zeit; auf der Wii nicht vorhanden |
| 3 | Anzahl Titel | Anzahl; von der Wii nicht ausgewertet |
| 4 | Anzahl Starts | Anzahl |
Anwendungsbeispiel
Dieses Code-Beispiel in Python 3 entschlüsselt den Title-Key mithilfe des Common-Keys.
from pathlib import Path
from Crypto.Cipher import AES # pip install pycryptodome
COMMON_KEYS = (
bytes.fromhex("ebe42a225e8593e448d9c5457381aaf7"), # Wii
bytes.fromhex("63b82bb4f4614e2e13f2fefbba4c9b7e"), # Korea
bytes.fromhex("30bfc76e7c19afbb23163330ced7c28d"), # vWii
)
def decrypt_title_key(ticket: bytes) -> bytes:
"""Entschlüsselt den Title-Key eines Tickets (nicht konsolengebunden)."""
encrypted_key = ticket[0x1BF:0x1CF]
title_id = ticket[0x1DC:0x1E4]
common_key = COMMON_KEYS[ticket[0x1F1]]
iv = title_id + bytes(8)
return AES.new(common_key, AES.MODE_CBC, iv).decrypt(encrypted_key)
title_key = decrypt_title_key(Path("cetk").read_bytes())
print(title_key.hex())
Gibt für das IOS58 aus:
d565f8922be6605b3024095fe38b0e25
Trivia
- Wenn der verschlüsselte Title-Key auf
476f747461476574536f6d6542656572bzw.GottaGetSomeBeer(in ASCII) gesetzt ist, spricht man von einem "Beer Ticket". Dies wird bspw. von ShowMiiWads gesetzt. - Der verschlüsselte Title-Key des Homebrewkanals lautet
TheMostAwesomest.
Einzelnachweise
- ↑ Wii#Time Limits and Usage Periods for Channels auf The Cutting Room Floor, abgerufen am 25. August 2026
- ↑ Homebrew Channel released ironically von Engadget am 02. April 2008, abgerufen am 25. August 2026