Add consolidated GodMode9 key dumping script. (#6396)

This commit is contained in:
Steveice10 2023-04-09 12:16:31 -07:00 committed by GitHub
parent 8d19483b7e
commit b6e73f0d49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 396 additions and 8 deletions

291
dist/dumpkeys/DumpKeys.gm9 vendored Normal file
View file

@ -0,0 +1,291 @@
set PREVIEW_MODE "Key Dumper\n \nWorking..."
# Boot9
set BOOT9_BIN "M:/boot9.bin"
fget $[BOOT9_BIN]@D9D0:10 KEYX_2C
set KEYX_2D $[KEYX_2C]
set KEYX_2E $[KEYX_2C]
set KEYX_2F $[KEYX_2C]
fget $[BOOT9_BIN]@D9E0:10 KEYX_30
set KEYX_31 $[KEYX_30]
set KEYX_32 $[KEYX_30]
set KEYX_33 $[KEYX_30]
fget $[BOOT9_BIN]@D9F0:10 KEYX_34
set KEYX_35 $[KEYX_34]
set KEYX_36 $[KEYX_34]
set KEYX_37 $[KEYX_34]
fget $[BOOT9_BIN]@DA00:10 KEYX_38
set KEYX_39 $[KEYX_38]
set KEYX_3A $[KEYX_38]
set KEYX_3B $[KEYX_38]
fget $[BOOT9_BIN]@DA10:10 KEYX_3C
fget $[BOOT9_BIN]@DA20:10 KEYX_3D
fget $[BOOT9_BIN]@DA30:10 KEYX_3E
fget $[BOOT9_BIN]@DA40:10 KEYX_3F
fget $[BOOT9_BIN]@DA50:10 KEYY_04
fget $[BOOT9_BIN]@DA60:10 KEYY_05
fget $[BOOT9_BIN]@DA70:10 KEYY_06
fget $[BOOT9_BIN]@DA80:10 KEYY_07
fget $[BOOT9_BIN]@DA90:10 KEYY_08
fget $[BOOT9_BIN]@DAA0:10 KEYY_09
fget $[BOOT9_BIN]@DAB0:10 KEYY_0A
fget $[BOOT9_BIN]@DAC0:10 KEYY_0B
fget $[BOOT9_BIN]@DAD0:10 KEYN_0D
fget $[BOOT9_BIN]@DBA0:10 KEYN_2D
fget $[BOOT9_BIN]@DBB0:10 KEYN_32
fget $[BOOT9_BIN]@DBC0:10 KEYN_36
fget $[BOOT9_BIN]@DBD0:10 KEYN_38
# NATIVE_FIRM
if chk $[ONTYPE] "N3DS"
if not find 1:/title/00040138/20000002/content/????????.app NATIVE_FIRM_APP
echo "New 3DS NATIVE_FIRM not found."
goto Exit
end
set EXPECTED_NATIVE_FIRM_VER "1F00"
set KEYY_2E_OFFSET "66504"
set KEYY_39_NFC_OFFSET "66524"
set COMMON_0_OFFSET "6CE51"
set COMMON_1_OFFSET "6CE65"
set COMMON_2_OFFSET "6CE79"
set COMMON_3_OFFSET "6CE8D"
set COMMON_4_OFFSET "6CEA1"
set COMMON_5_OFFSET "6CEB5"
else
if not find 1:/title/00040138/00000002/content/????????.app NATIVE_FIRM_APP
echo "Old 3DS NATIVE_FIRM not found."
goto Exit
end
set EXPECTED_NATIVE_FIRM_VER "1F00"
set KEYY_2E_OFFSET "66488"
set KEYY_39_NFC_OFFSET "664A8"
set COMMON_0_OFFSET "6CDC1"
set COMMON_1_OFFSET "6CDD5"
set COMMON_2_OFFSET "6CDE9"
set COMMON_3_OFFSET "6CDFD"
set COMMON_4_OFFSET "6CE11"
set COMMON_5_OFFSET "6CE25"
end
set NATIVE_FIRM_EXTHEADER "G:/extheader.bin"
set NATIVE_FIRM_ENCRYPTED "G:/exefs/.firm"
set NATIVE_FIRM_DECRYPTED "$[GM9OUT]/native.firm"
set PROCESS9_CODE "G:/0004013000003000.Process9/exefs/.code"
imgmount $[NATIVE_FIRM_APP]
fget $[NATIVE_FIRM_EXTHEADER]@E:2 NATIVE_FIRM_VER
if not chk $[NATIVE_FIRM_VER] $[EXPECTED_NATIVE_FIRM_VER]
echo "Unsupported NATIVE_FIRM version.\nThis script requires the latest 3DS firmware.\n\nExpected $[EXPECTED_NATIVE_FIRM_VER], got $[NATIVE_FIRM_VER]"
goto Exit
end
cp -w $[NATIVE_FIRM_ENCRYPTED] $[NATIVE_FIRM_DECRYPTED]
decrypt $[NATIVE_FIRM_DECRYPTED]
imgumount
imgmount $[NATIVE_FIRM_DECRYPTED]
fget $[PROCESS9_CODE]@$[KEYY_2E_OFFSET]:10 KEYY_2E
set KEYY_31 $[KEYY_2E]
set KEYY_39_DLP $[KEYY_2E]
fget $[PROCESS9_CODE]@$[KEYY_39_NFC_OFFSET]:10 KEYY_39_NFC
fget $[PROCESS9_CODE]@$[COMMON_0_OFFSET]:10 COMMON_0
fget $[PROCESS9_CODE]@$[COMMON_1_OFFSET]:10 COMMON_1
fget $[PROCESS9_CODE]@$[COMMON_2_OFFSET]:10 COMMON_2
fget $[PROCESS9_CODE]@$[COMMON_3_OFFSET]:10 COMMON_3
fget $[PROCESS9_CODE]@$[COMMON_4_OFFSET]:10 COMMON_4
fget $[PROCESS9_CODE]@$[COMMON_5_OFFSET]:10 COMMON_5
imgumount
rm -o -s $[NATIVE_FIRM_DECRYPTED]
# NFC
if chk $[ONTYPE] "N3DS"
if not find 1:/title/00040130/20004002/content/????????.app NFC_APP
echo "New 3DS NFC not found."
goto Exit
end
set EXPECTED_NFC_VER "0700"
set NFC_PHRASE_0_OFFSET "355EE"
set NFC_SEED_0_OFFSET "355FC"
set NFC_HMAC_KEY_0_OFFSET "3560A"
set NFC_PHRASE_1_OFFSET "3561A"
set NFC_SEED_1_OFFSET "35628"
set NFC_HMAC_KEY_1_OFFSET "35638"
set NFC_IV_OFFSET "35648"
else
if not find 1:/title/00040130/00004002/content/????????.app NFC_APP
echo "Old 3DS NFC not found."
goto Exit
end
set EXPECTED_NFC_VER "0800"
set NFC_PHRASE_0_OFFSET "17382"
set NFC_SEED_0_OFFSET "17390"
set NFC_HMAC_KEY_0_OFFSET "1739E"
set NFC_PHRASE_1_OFFSET "173AE"
set NFC_SEED_1_OFFSET "173BC"
set NFC_HMAC_KEY_1_OFFSET "173CC"
set NFC_IV_OFFSET "173DC"
end
set NFC_EXTHEADER "G:/extheader.bin"
set NFC_CODE "$[GM9OUT]/nfc_code.bin"
imgmount $[NFC_APP]
fget $[NFC_EXTHEADER]@E:2 NFC_VER
if not chk $[NFC_VER] $[EXPECTED_NFC_VER]
echo "Unsupported NFC module version.\nThis script requires the latest 3DS firmware.\n\nExpected $[EXPECTED_NFC_VER], got $[NFC_VER]"
goto Exit
end
imgumount
extrcode $[NFC_APP] $[NFC_CODE]
fget $[NFC_CODE]@$[NFC_PHRASE_0_OFFSET]:E NFC_PHRASE_0
fget $[NFC_CODE]@$[NFC_SEED_0_OFFSET]:E NFC_SEED_0
fget $[NFC_CODE]@$[NFC_HMAC_KEY_0_OFFSET]:10 NFC_HMAC_KEY_0
fget $[NFC_CODE]@$[NFC_PHRASE_1_OFFSET]:E NFC_PHRASE_1
fget $[NFC_CODE]@$[NFC_SEED_1_OFFSET]:10 NFC_SEED_1
fget $[NFC_CODE]@$[NFC_HMAC_KEY_1_OFFSET]:10 NFC_HMAC_KEY_1
fget $[NFC_CODE]@$[NFC_IV_OFFSET]:10 NFC_IV
rm -o -s $[NFC_CODE]
# GodMode9 Key Database
set KEY_DB "V:/aeskeydb.bin"
set KEY_DB_18X "K:/slot0x18KeyX.ret.bin"
set KEY_DB_19X "K:/slot0x19KeyX.ret.bin"
set KEY_DB_1AX "K:/slot0x1AKeyX.ret.bin"
set KEY_DB_1BX "K:/slot0x1BKeyX.ret.bin"
set KEY_DB_1CX "K:/slot0x1CKeyX.ret.bin"
set KEY_DB_1DX "K:/slot0x1DKeyX.ret.bin"
set KEY_DB_1EX "K:/slot0x1EKeyX.ret.bin"
set KEY_DB_1FX "K:/slot0x1FKeyX.ret.bin"
set KEY_DB_25X "K:/slot0x25KeyX.ret.bin"
set KEY_DB_24Y "K:/slot0x24KeyY.bin"
set KEY_DB_2FY "K:/slot0x2FKeyY.ret.bin"
imgmount $[KEY_DB]
fget $[KEY_DB_18X]@0:10 KEYX_18
fget $[KEY_DB_19X]@0:10 KEYX_19
fget $[KEY_DB_1AX]@0:10 KEYX_1A
fget $[KEY_DB_1BX]@0:10 KEYX_1B
fget $[KEY_DB_1CX]@0:10 KEYX_1C
fget $[KEY_DB_1DX]@0:10 KEYX_1D
fget $[KEY_DB_1EX]@0:10 KEYX_1E
fget $[KEY_DB_1FX]@0:10 KEYX_1F
fget $[KEY_DB_25X]@0:10 KEYX_25
fget $[KEY_DB_24Y]@0:10 KEYY_24
fget $[KEY_DB_2FY]@0:10 KEYY_2F
imgumount
# Write Keys To File
set OUT "0:/gm9/aes_keys.txt"
dumptxt $[OUT] "# KeyX"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "slot0x18KeyX=$[KEYX_18]"
dumptxt -p $[OUT] "slot0x19KeyX=$[KEYX_19]"
dumptxt -p $[OUT] "slot0x1AKeyX=$[KEYX_1A]"
dumptxt -p $[OUT] "slot0x1BKeyX=$[KEYX_1B]"
dumptxt -p $[OUT] "slot0x1CKeyX=$[KEYX_1C]"
dumptxt -p $[OUT] "slot0x1DKeyX=$[KEYX_1D]"
dumptxt -p $[OUT] "slot0x1EKeyX=$[KEYX_1E]"
dumptxt -p $[OUT] "slot0x1FKeyX=$[KEYX_1F]"
dumptxt -p $[OUT] "slot0x25KeyX=$[KEYX_25]"
dumptxt -p $[OUT] "slot0x2CKeyX=$[KEYX_2C]"
dumptxt -p $[OUT] "slot0x2DKeyX=$[KEYX_2D]"
dumptxt -p $[OUT] "slot0x2EKeyX=$[KEYX_2E]"
dumptxt -p $[OUT] "slot0x2FKeyX=$[KEYX_2F]"
dumptxt -p $[OUT] "slot0x30KeyX=$[KEYX_30]"
dumptxt -p $[OUT] "slot0x31KeyX=$[KEYX_31]"
dumptxt -p $[OUT] "slot0x32KeyX=$[KEYX_32]"
dumptxt -p $[OUT] "slot0x33KeyX=$[KEYX_33]"
dumptxt -p $[OUT] "slot0x34KeyX=$[KEYX_34]"
dumptxt -p $[OUT] "slot0x35KeyX=$[KEYX_35]"
dumptxt -p $[OUT] "slot0x36KeyX=$[KEYX_36]"
dumptxt -p $[OUT] "slot0x37KeyX=$[KEYX_37]"
dumptxt -p $[OUT] "slot0x38KeyX=$[KEYX_38]"
dumptxt -p $[OUT] "slot0x39KeyX=$[KEYX_39]"
dumptxt -p $[OUT] "slot0x3AKeyX=$[KEYX_3A]"
dumptxt -p $[OUT] "slot0x3BKeyX=$[KEYX_3B]"
dumptxt -p $[OUT] "slot0x3CKeyX=$[KEYX_3C]"
dumptxt -p $[OUT] "slot0x3DKeyX=$[KEYX_3D]"
dumptxt -p $[OUT] "slot0x3EKeyX=$[KEYX_3E]"
dumptxt -p $[OUT] "slot0x3FKeyX=$[KEYX_3F]"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "# KeyY"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "slot0x04KeyY=$[KEYY_04]"
dumptxt -p $[OUT] "slot0x05KeyY=$[KEYY_05]"
dumptxt -p $[OUT] "slot0x06KeyY=$[KEYY_06]"
dumptxt -p $[OUT] "slot0x07KeyY=$[KEYY_07]"
dumptxt -p $[OUT] "slot0x08KeyY=$[KEYY_08]"
dumptxt -p $[OUT] "slot0x09KeyY=$[KEYY_09]"
dumptxt -p $[OUT] "slot0x0AKeyY=$[KEYY_0A]"
dumptxt -p $[OUT] "slot0x0BKeyY=$[KEYY_0B]"
dumptxt -p $[OUT] "slot0x24KeyY=$[KEYY_24]"
dumptxt -p $[OUT] "slot0x2EKeyY=$[KEYY_2E]"
dumptxt -p $[OUT] "slot0x2FKeyY=$[KEYY_2F]"
dumptxt -p $[OUT] "slot0x31KeyY=$[KEYY_31]"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "# DLP/NFC KeyY (slot 0x39)"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "dlpKeyY=$[KEYY_39_DLP]"
dumptxt -p $[OUT] "nfcKeyY=$[KEYY_39_NFC]"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "# Ticket Common KeyY (slot 0x3D)"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "common0=$[COMMON_0]"
dumptxt -p $[OUT] "common1=$[COMMON_1]"
dumptxt -p $[OUT] "common2=$[COMMON_2]"
dumptxt -p $[OUT] "common3=$[COMMON_3]"
dumptxt -p $[OUT] "common4=$[COMMON_4]"
dumptxt -p $[OUT] "common5=$[COMMON_5]"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "# KeyN"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "slot0x0DKeyN=$[KEYN_0D]"
dumptxt -p $[OUT] "slot0x2DKeyN=$[KEYN_2D]"
dumptxt -p $[OUT] "slot0x32KeyN=$[KEYN_32]"
dumptxt -p $[OUT] "slot0x36KeyN=$[KEYN_36]"
dumptxt -p $[OUT] "slot0x38KeyN=$[KEYN_38]"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "# NFC Secrets"
dumptxt -p $[OUT] ""
dumptxt -p $[OUT] "nfcSecret0Phrase=$[NFC_PHRASE_0]"
dumptxt -p $[OUT] "nfcSecret0Seed=$[NFC_SEED_0]"
dumptxt -p $[OUT] "nfcSecret0HmacKey=$[NFC_HMAC_KEY_0]"
dumptxt -p $[OUT] "nfcSecret1Phrase=$[NFC_PHRASE_1]"
dumptxt -p $[OUT] "nfcSecret1Seed=$[NFC_SEED_1]"
dumptxt -p $[OUT] "nfcSecret1HmacKey=$[NFC_HMAC_KEY_1]"
dumptxt -p $[OUT] "nfcIv=$[NFC_IV]"
@Exit

10
dist/dumpkeys/README.md vendored Normal file
View file

@ -0,0 +1,10 @@
# DumpKeys
This is a GodMode9 script that dumps all the keys and other related secrets that Citra needs from a real 3DS.
Usage:
1. Copy "DumpKeys.gm9" into the "gm9/scripts/" directory on your SD card.
2. Launch GodMode9, press the HOME button, select Scripts, and select "DumpKeys" from the list of scripts that appears.
3. Wait for the script to complete and return you to the GodMode9 main menu.
4. Power off your system and copy the "gm9/aes_keys.txt" file off of your SD card into "(Citra directory)/sysdata/".

View file

@ -31,13 +31,12 @@ constexpr std::array<u8, 10> KeyTypes{{
HW::AES::APTWrap,
HW::AES::BOSSDataKey,
0x32, // unknown
HW::AES::DLPDataKey,
HW::AES::DLPNFCDataKey,
HW::AES::CECDDataKey,
0, // invalid
HW::AES::FRDKey,
// Note: According to 3dbrew the KeyY is overridden by Process9 when using this key type.
// TODO: implement this behaviour?
HW::AES::NFCKey,
HW::AES::DLPNFCDataKey,
}};
void PS_PS::EncryptDecryptAes(Kernel::HLERequestContext& ctx) {
@ -60,6 +59,12 @@ void PS_PS::EncryptDecryptAes(Kernel::HLERequestContext& ctx) {
// and encrypted data is actually returned, but the key used is unknown.
ASSERT_MSG(key_type != 7 && key_type < 10, "Key type is invalid");
if (key_type == 0x5) {
HW::AES::SelectDlpNfcKeyYIndex(HW::AES::DlpNfcKeyY::Dlp);
} else if (key_type == 0x9) {
HW::AES::SelectDlpNfcKeyYIndex(HW::AES::DlpNfcKeyY::Nfc);
}
if (!HW::AES::IsNormalKeyAvailable(KeyTypes[key_type])) {
LOG_ERROR(Service_PS,
"Key 0x{:2X} is not available, encryption/decryption will not be correct",

View file

@ -55,6 +55,15 @@ AESKey HexToKey(const std::string& hex) {
return key;
}
std::vector<u8> HexToVector(const std::string& hex) {
std::vector<u8> vector(hex.size() / 2);
for (std::size_t i = 0; i < vector.size(); ++i) {
vector[i] = static_cast<u8>(std::stoi(hex.substr(i * 2, 2), nullptr, 16));
}
return vector;
}
struct KeySlot {
std::optional<AESKey> x;
std::optional<AESKey> y;
@ -91,6 +100,9 @@ struct KeySlot {
std::array<KeySlot, KeySlotID::MaxKeySlotID> key_slots;
std::array<std::optional<AESKey>, MaxCommonKeySlot> common_key_y_slots;
std::array<std::optional<AESKey>, NumDlpNfcKeyYs> dlp_nfc_key_y_slots;
std::array<NfcSecret, NumNfcSecrets> nfc_secrets;
AESIV nfc_iv;
enum class FirmwareType : u32 {
ARM9 = 0, // uses NDMA
@ -440,6 +452,12 @@ void LoadPresetKeys() {
while (!file.eof()) {
std::string line;
std::getline(file, line);
// Ignore empty or commented lines.
if (line.empty() || line.starts_with("#")) {
continue;
}
std::vector<std::string> parts;
Common::SplitString(line, '=', parts);
if (parts.size() != 2) {
@ -448,6 +466,24 @@ void LoadPresetKeys() {
}
const std::string& name = parts[0];
std::size_t nfc_secret_index;
if (std::sscanf(name.c_str(), "nfcSecret%zd", &nfc_secret_index) == 1) {
auto value = HexToVector(parts[1]);
if (nfc_secret_index >= nfc_secrets.size()) {
LOG_ERROR(HW_AES, "Invalid NFC secret index {}", nfc_secret_index);
} else if (name.ends_with("Phrase")) {
nfc_secrets[nfc_secret_index].phrase = value;
} else if (name.ends_with("Seed")) {
nfc_secrets[nfc_secret_index].seed = value;
} else if (name.ends_with("HmacKey")) {
nfc_secrets[nfc_secret_index].hmac_key = value;
} else {
LOG_ERROR(HW_AES, "Invalid NFC secret {}", name);
}
continue;
}
AESKey key;
try {
key = HexToKey(parts[1]);
@ -466,6 +502,21 @@ void LoadPresetKeys() {
continue;
}
if (name == "dlpKeyY") {
dlp_nfc_key_y_slots[DlpNfcKeyY::Dlp] = key;
continue;
}
if (name == "nfcKeyY") {
dlp_nfc_key_y_slots[DlpNfcKeyY::Nfc] = key;
continue;
}
if (name == "nfcIv") {
nfc_iv = key;
continue;
}
std::size_t slot_id;
char key_type;
if (std::sscanf(name.c_str(), "slot0x%zXKey%c", &slot_id, &key_type) != 2) {
@ -534,4 +585,16 @@ void SelectCommonKeyIndex(u8 index) {
key_slots[KeySlotID::TicketCommonKey].SetKeyY(common_key_y_slots.at(index));
}
void SelectDlpNfcKeyYIndex(u8 index) {
key_slots[KeySlotID::DLPNFCDataKey].SetKeyY(dlp_nfc_key_y_slots.at(index));
}
const NfcSecret& GetNfcSecret(u8 index) {
return nfc_secrets[index];
}
const AESIV& GetNfcIv() {
return nfc_iv;
}
} // namespace HW::AES

View file

@ -6,6 +6,7 @@
#include <array>
#include <cstddef>
#include <vector>
#include "common/common_types.h"
namespace HW::AES {
@ -27,8 +28,8 @@ enum KeySlotID : std::size_t {
// AES Keyslot used to encrypt the BOSS container data.
BOSSDataKey = 0x38,
// AES Keyslot used to calculate DLP data frame checksum.
DLPDataKey = 0x39,
// AES Keyslot used to calculate DLP data frame checksum and encrypt Amiibo key data.
DLPNFCDataKey = 0x39,
// AES Keyslot used to generate the StreetPass CCMP key.
CECDDataKey = 0x2E,
@ -36,9 +37,6 @@ enum KeySlotID : std::size_t {
// AES Keyslot used by the friends module.
FRDKey = 0x36,
// AES Keyslot used by the NFC module.
NFCKey = 0x39,
// AES keyslot used for APT:Wrap/Unwrap functions
APTWrap = 0x31,
@ -48,11 +46,28 @@ enum KeySlotID : std::size_t {
MaxKeySlotID = 0x40,
};
enum DlpNfcKeyY : std::size_t {
// Download Play KeyY
Dlp = 0,
// NFC (Amiibo) KeyY
Nfc = 1
};
struct NfcSecret {
std::vector<u8> phrase;
std::vector<u8> seed;
std::vector<u8> hmac_key;
};
constexpr std::size_t MaxCommonKeySlot = 6;
constexpr std::size_t NumDlpNfcKeyYs = 2;
constexpr std::size_t NumNfcSecrets = 2;
constexpr std::size_t AES_BLOCK_SIZE = 16;
using AESKey = std::array<u8, AES_BLOCK_SIZE>;
using AESIV = std::array<u8, AES_BLOCK_SIZE>;
void InitKeys(bool force = false);
@ -65,5 +80,9 @@ bool IsNormalKeyAvailable(std::size_t slot_id);
AESKey GetNormalKey(std::size_t slot_id);
void SelectCommonKeyIndex(u8 index);
void SelectDlpNfcKeyYIndex(u8 index);
const NfcSecret& GetNfcSecret(u8 index);
const AESIV& GetNfcIv();
} // namespace HW::AES