mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Add consolidated GodMode9 key dumping script. (#6396)
This commit is contained in:
		
							parent
							
								
									8d19483b7e
								
							
						
					
					
						commit
						b6e73f0d49
					
				
					 5 changed files with 396 additions and 8 deletions
				
			
		|  | @ -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", | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue