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

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