Added ability to re-encrypt vWii WAD Title Keys with the common key

This allows the creation of WADs that can be installed from *within* vWii mode, instead of just from Wii U mode.
This commit is contained in:
Campbell 2024-05-03 22:39:37 -04:00
parent 95dd93b85f
commit ec16050d6f
4 changed files with 42 additions and 19 deletions

View File

@ -1,6 +1,5 @@
# NUSGet.py, licensed under the MIT license # NUSGet.py, licensed under the MIT license
# Copyright 2024 NinjaCheetah # Copyright 2024 NinjaCheetah
import sys import sys
import os import os
import json import json
@ -125,8 +124,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.log_text += new_text + "\n" self.log_text += new_text + "\n"
self.ui.log_text_browser.setText(self.log_text) self.ui.log_text_browser.setText(self.log_text)
# Always auto-scroll to the bottom of the log. # Always auto-scroll to the bottom of the log.
scrollBar = self.ui.log_text_browser.verticalScrollBar() scroll_bar = self.ui.log_text_browser.verticalScrollBar()
scrollBar.setValue(scrollBar.maximum()) scroll_bar.setValue(scroll_bar.maximum())
def load_title_data(self, selected_title, selected_version, selected_region=None): def load_title_data(self, selected_title, selected_version, selected_region=None):
# Use the information passed from the double click callback to prepare a title for downloading. # Use the information passed from the double click callback to prepare a title for downloading.
@ -168,15 +167,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# Throw an error and make a message box appear if you haven't selected any options to output the title. # Throw an error and make a message box appear if you haven't selected any options to output the title.
if (self.ui.pack_wad_chkbox.isChecked() is False and self.ui.keep_enc_chkbox.isChecked() is False and if (self.ui.pack_wad_chkbox.isChecked() is False and self.ui.keep_enc_chkbox.isChecked() is False and
self.ui.create_dec_chkbox.isChecked() is False): self.ui.create_dec_chkbox.isChecked() is False):
msgBox = QMessageBox() msg_box = QMessageBox()
msgBox.setIcon(QMessageBox.Icon.Critical) msg_box.setIcon(QMessageBox.Icon.Critical)
msgBox.setStandardButtons(QMessageBox.StandardButton.Ok) msg_box.setStandardButtons(QMessageBox.StandardButton.Ok)
msgBox.setDefaultButton(QMessageBox.StandardButton.Ok) msg_box.setDefaultButton(QMessageBox.StandardButton.Ok)
msgBox.setWindowTitle("No Output Selected") msg_box.setWindowTitle("No Output Selected")
msgBox.setText("You have not selected any format to output the data in!") msg_box.setText("You have not selected any format to output the data in!")
msgBox.setInformativeText("Please select at least one option for how you would like the download to be " msg_box.setInformativeText("Please select at least one option for how you would like the download to be "
"saved.") "saved.")
msgBox.exec() msg_box.exec()
return return
# Lock the UI prior to the download beginning to avoid spawning multiple threads or changing info part way in. # Lock the UI prior to the download beginning to avoid spawning multiple threads or changing info part way in.
self.ui.tid_entry.setEnabled(False) self.ui.tid_entry.setEnabled(False)
@ -187,6 +186,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.create_dec_chkbox.setEnabled(False) self.ui.create_dec_chkbox.setEnabled(False)
self.ui.use_local_chkbox.setEnabled(False) self.ui.use_local_chkbox.setEnabled(False)
self.ui.use_wiiu_nus_chkbox.setEnabled(False) self.ui.use_wiiu_nus_chkbox.setEnabled(False)
self.ui.pack_vwii_mode_chkbox.setEnabled(False)
self.ui.wad_file_entry.setEnabled(False) self.ui.wad_file_entry.setEnabled(False)
self.log_text = "" self.log_text = ""
self.ui.log_text_browser.setText(self.log_text) self.ui.log_text_browser.setText(self.log_text)
@ -241,6 +241,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.create_dec_chkbox.setEnabled(True) self.ui.create_dec_chkbox.setEnabled(True)
self.ui.use_local_chkbox.setEnabled(True) self.ui.use_local_chkbox.setEnabled(True)
self.ui.use_wiiu_nus_chkbox.setEnabled(True) self.ui.use_wiiu_nus_chkbox.setEnabled(True)
self.ui.pack_vwii_mode_chkbox.setEnabled(True)
if self.ui.pack_wad_chkbox.isChecked() is True: if self.ui.pack_wad_chkbox.isChecked() is True:
self.ui.wad_file_entry.setEnabled(True) self.ui.wad_file_entry.setEnabled(True)
@ -358,6 +359,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return -3 return -3
# If pack WAD is still true, pack the TMD, ticket, and contents all into a WAD. # If pack WAD is still true, pack the TMD, ticket, and contents all into a WAD.
if pack_wad_enabled is True: if pack_wad_enabled is True:
# If the option to pack for vWii mode instead of Wii U mode is enabled, then the Title Key needs to be
# re-encrypted with the common key instead of the vWii key, so that the title can be installed from within
# vWii mode. (vWii mode does not have access to the vWii key, only Wii U mode has that.)
if self.ui.pack_vwii_mode_chkbox.isChecked() is True and (tid[3] == "7" or tid[7] == "7"):
progress_callback.emit(" - Re-encrypting Title Key with the common key...")
title_key_dec = title.ticket.get_title_key()
title_key_common = libWiiPy.encrypt_title_key(title_key_dec, 0, title.tmd.title_id)
title.ticket.common_key_index = 0
title.ticket.title_key_enc = title_key_common
# Get the WAD certificate chain, courtesy of libWiiPy. # Get the WAD certificate chain, courtesy of libWiiPy.
progress_callback.emit(" - Building certificate...") progress_callback.emit(" - Building certificate...")
title.wad.set_cert_data(libWiiPy.download_cert(wiiu_endpoint=wiiu_nus_enabled)) title.wad.set_cert_data(libWiiPy.download_cert(wiiu_endpoint=wiiu_nus_enabled))

View File

@ -78,6 +78,11 @@ class Ui_MainWindow(object):
self.verticalLayout_4.addWidget(self.vwii_title_tree) self.verticalLayout_4.addWidget(self.vwii_title_tree)
self.pack_vwii_mode_chkbox = QCheckBox(self.vwii_tab)
self.pack_vwii_mode_chkbox.setObjectName(u"pack_vwii_mode_chkbox")
self.verticalLayout_4.addWidget(self.pack_vwii_mode_chkbox)
self.platform_tabs.addTab(self.vwii_tab, "") self.platform_tabs.addTab(self.vwii_tab, "")
self.verticalLayout.addWidget(self.platform_tabs) self.verticalLayout.addWidget(self.platform_tabs)
@ -163,7 +168,7 @@ class Ui_MainWindow(object):
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow) self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar") self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 610, 30)) self.menubar.setGeometry(QRect(0, 0, 610, 29))
MainWindow.setMenuBar(self.menubar) MainWindow.setMenuBar(self.menubar)
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
@ -178,6 +183,7 @@ class Ui_MainWindow(object):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None)) MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
self.label_2.setText(QCoreApplication.translate("MainWindow", u"Available Titles", None)) self.label_2.setText(QCoreApplication.translate("MainWindow", u"Available Titles", None))
self.platform_tabs.setTabText(self.platform_tabs.indexOf(self.wii_tab), QCoreApplication.translate("MainWindow", u"Wii", None)) self.platform_tabs.setTabText(self.platform_tabs.indexOf(self.wii_tab), QCoreApplication.translate("MainWindow", u"Wii", None))
self.pack_vwii_mode_chkbox.setText(QCoreApplication.translate("MainWindow", u"Pack for vWii mode instead of Wii U mode", None))
self.platform_tabs.setTabText(self.platform_tabs.indexOf(self.vwii_tab), QCoreApplication.translate("MainWindow", u"vWii", None)) self.platform_tabs.setTabText(self.platform_tabs.indexOf(self.vwii_tab), QCoreApplication.translate("MainWindow", u"vWii", None))
self.tid_entry.setText("") self.tid_entry.setText("")
self.tid_entry.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Title ID", None)) self.tid_entry.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Title ID", None))
@ -188,8 +194,8 @@ class Ui_MainWindow(object):
self.log_text_browser.setHtml(QCoreApplication.translate("MainWindow", u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" self.log_text_browser.setHtml(QCoreApplication.translate("MainWindow", u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n" "p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;\">\n" "</style></head><body style=\" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;\"><br /></p></body></html>", None)) "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>", None))
self.pack_wad_chkbox.setText(QCoreApplication.translate("MainWindow", u"Pack WAD", None)) self.pack_wad_chkbox.setText(QCoreApplication.translate("MainWindow", u"Pack WAD", None))
self.wad_file_entry.setPlaceholderText(QCoreApplication.translate("MainWindow", u"File Name", None)) self.wad_file_entry.setPlaceholderText(QCoreApplication.translate("MainWindow", u"File Name", None))
self.keep_enc_chkbox.setText(QCoreApplication.translate("MainWindow", u"Keep encrypted contents", None)) self.keep_enc_chkbox.setText(QCoreApplication.translate("MainWindow", u"Keep encrypted contents", None))

View File

@ -107,6 +107,13 @@
</column> </column>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="pack_vwii_mode_chkbox">
<property name="text">
<string>Pack for vWii mode instead of Wii U mode</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -165,8 +172,8 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -238,7 +245,7 @@ p, li { white-space: pre-wrap; }
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>610</width> <width>610</width>
<height>30</height> <height>29</height>
</rect> </rect>
</property> </property>
</widget> </widget>

View File

@ -1,4 +1,4 @@
pyside6 pyside6
nuitka nuitka
git+https://github.com/NinjaCheetah/libWiipy git+https://github.com/NinjaCheetah/libWiiPy
zstandard zstandard