mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	nfc: Use existing secrets infrastructure for amiibo encryption. (#6652)
This commit is contained in:
		
							parent
							
								
									4383f6d80a
								
							
						
					
					
						commit
						c00768d6d0
					
				
					 5 changed files with 68 additions and 80 deletions
				
			
		|  | @ -12,9 +12,9 @@ | ||||||
| #include <cryptopp/modes.h> | #include <cryptopp/modes.h> | ||||||
| #include <cryptopp/sha.h> | #include <cryptopp/sha.h> | ||||||
| 
 | 
 | ||||||
| #include "common/file_util.h" |  | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "core/hle/service/nfc/amiibo_crypto.h" | #include "core/hle/service/nfc/amiibo_crypto.h" | ||||||
|  | #include "core/hw/aes/key.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::NFC::AmiiboCrypto { | namespace Service::NFC::AmiiboCrypto { | ||||||
| 
 | 
 | ||||||
|  | @ -159,35 +159,44 @@ HashSeed GetSeed(const NTAG215File& data) { | ||||||
|     return seed; |     return seed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed) { | std::vector<u8> GenerateInternalKey(const HW::AES::NfcSecret& secret, const HashSeed& seed) { | ||||||
|     const std::size_t seed_part1_len = sizeof(key.magic_bytes) - key.magic_length; |     static constexpr std::size_t FULL_SEED_LENGTH = 0x10; | ||||||
|     const std::size_t string_size = key.type_string.size(); |     const std::size_t seed_part1_len = FULL_SEED_LENGTH - secret.seed.size(); | ||||||
|  |     const std::size_t string_size = secret.phrase.size(); | ||||||
|     std::vector<u8> output(string_size + seed_part1_len); |     std::vector<u8> output(string_size + seed_part1_len); | ||||||
| 
 | 
 | ||||||
|     // Copy whole type string
 |     // Copy whole type string
 | ||||||
|     memccpy(output.data(), key.type_string.data(), '\0', string_size); |     memccpy(output.data(), secret.phrase.data(), '\0', string_size); | ||||||
| 
 | 
 | ||||||
|     // Append (16 - magic_length) from the input seed
 |     // Append (FULL_SEED_LENGTH - secret.seed.size()) from the input seed
 | ||||||
|     memcpy(output.data() + string_size, &seed, seed_part1_len); |     memcpy(output.data() + string_size, &seed, seed_part1_len); | ||||||
| 
 | 
 | ||||||
|     // Append all bytes from magicBytes
 |     // Append all bytes from secret.seed
 | ||||||
|     output.insert(output.end(), key.magic_bytes.begin(), |     output.insert(output.end(), secret.seed.begin(), secret.seed.end()); | ||||||
|                   key.magic_bytes.begin() + key.magic_length); |  | ||||||
| 
 | 
 | ||||||
|     output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end()); |     output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end()); | ||||||
|     output.emplace_back(seed.nintendo_id_1); |     output.emplace_back(seed.nintendo_id_1); | ||||||
|     output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end()); |     output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end()); | ||||||
|     output.emplace_back(seed.nintendo_id_2); |     output.emplace_back(seed.nintendo_id_2); | ||||||
| 
 | 
 | ||||||
|     for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) { |     HW::AES::SelectDlpNfcKeyYIndex(HW::AES::DlpNfcKeyY::Nfc); | ||||||
|         output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i])); |     auto nfc_key = HW::AES::GetNormalKey(HW::AES::KeySlotID::DLPNFCDataKey); | ||||||
|     } |     auto nfc_iv = HW::AES::GetNfcIv(); | ||||||
|  | 
 | ||||||
|  |     // Decrypt the keygen salt using the NFC key and IV.
 | ||||||
|  |     CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption d; | ||||||
|  |     d.SetKeyWithIV(nfc_key.data(), nfc_key.size(), nfc_iv.data(), nfc_iv.size()); | ||||||
|  |     std::array<u8, sizeof(seed.keygen_salt)> decrypted_salt{}; | ||||||
|  |     d.ProcessData(reinterpret_cast<unsigned char*>(decrypted_salt.data()), | ||||||
|  |                   reinterpret_cast<const unsigned char*>(seed.keygen_salt.data()), | ||||||
|  |                   seed.keygen_salt.size()); | ||||||
|  |     output.insert(output.end(), decrypted_salt.begin(), decrypted_salt.end()); | ||||||
| 
 | 
 | ||||||
|     return output; |     return output; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CryptoInit(CryptoCtx& ctx, CryptoPP::HMAC<CryptoPP::SHA256>& hmac_ctx, const HmacKey& hmac_key, | void CryptoInit(CryptoCtx& ctx, CryptoPP::HMAC<CryptoPP::SHA256>& hmac_ctx, | ||||||
|                 const std::vector<u8>& seed) { |                 std::span<const u8> hmac_key, std::span<const u8> seed) { | ||||||
|     // Initialize context
 |     // Initialize context
 | ||||||
|     ctx.used = false; |     ctx.used = false; | ||||||
|     ctx.counter = 0; |     ctx.counter = 0; | ||||||
|  | @ -216,16 +225,16 @@ void CryptoStep(CryptoCtx& ctx, CryptoPP::HMAC<CryptoPP::SHA256>& hmac_ctx, Drgb | ||||||
|         output.data(), reinterpret_cast<const unsigned char*>(ctx.buffer.data()), ctx.buffer_size); |         output.data(), reinterpret_cast<const unsigned char*>(ctx.buffer.data()), ctx.buffer_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) { | DerivedKeys GenerateKey(const HW::AES::NfcSecret& secret, const NTAG215File& data) { | ||||||
|     const auto seed = GetSeed(data); |     const auto seed = GetSeed(data); | ||||||
| 
 | 
 | ||||||
|     // Generate internal seed
 |     // Generate internal seed
 | ||||||
|     const std::vector<u8> internal_key = GenerateInternalKey(key, seed); |     const std::vector<u8> internal_key = GenerateInternalKey(secret, seed); | ||||||
| 
 | 
 | ||||||
|     // Initialize context
 |     // Initialize context
 | ||||||
|     CryptoCtx ctx{}; |     CryptoCtx ctx{}; | ||||||
|     CryptoPP::HMAC<CryptoPP::SHA256> hmac_ctx; |     CryptoPP::HMAC<CryptoPP::SHA256> hmac_ctx; | ||||||
|     CryptoInit(ctx, hmac_ctx, key.hmac_key, internal_key); |     CryptoInit(ctx, hmac_ctx, secret.hmac_key, internal_key); | ||||||
| 
 | 
 | ||||||
|     // Generate derived keys
 |     // Generate derived keys
 | ||||||
|     DerivedKeys derived_keys{}; |     DerivedKeys derived_keys{}; | ||||||
|  | @ -264,40 +273,16 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou | ||||||
|     out_data.password = in_data.password; |     out_data.password = in_data.password; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) { | static constexpr std::size_t HMAC_KEY_SIZE = 0x10; | ||||||
|     const auto citra_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); |  | ||||||
|     auto keys_file = FileUtil::IOFile(citra_keys_dir + "key_retail.bin", "rb"); |  | ||||||
| 
 |  | ||||||
|     if (!keys_file.IsOpen()) { |  | ||||||
|         LOG_ERROR(Service_NFC, "No keys detected"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (keys_file.ReadBytes(&unfixed_info, sizeof(InternalKey)) != sizeof(InternalKey)) { |  | ||||||
|         LOG_ERROR(Service_NFC, "Failed to read unfixed_info"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     if (keys_file.ReadBytes(&locked_secret, sizeof(InternalKey)) != sizeof(InternalKey)) { |  | ||||||
|         LOG_ERROR(Service_NFC, "Failed to read locked-secret"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool IsKeyAvailable() { |  | ||||||
|     const auto citra_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir); |  | ||||||
|     return FileUtil::Exists(citra_keys_dir + "key_retail.bin"); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data) { | bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data) { | ||||||
|     InternalKey locked_secret{}; |     if (!HW::AES::NfcSecretsAvailable()) { | ||||||
|     InternalKey unfixed_info{}; |  | ||||||
| 
 |  | ||||||
|     if (!LoadKeys(locked_secret, unfixed_info)) { |  | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     auto unfixed_info = HW::AES::GetNfcSecret(HW::AES::NfcSecretId::UnfixedInfo); | ||||||
|  |     auto locked_secret = HW::AES::GetNfcSecret(HW::AES::NfcSecretId::LockedSecret); | ||||||
|  | 
 | ||||||
|     // Generate keys
 |     // Generate keys
 | ||||||
|     NTAG215File encoded_data = NfcDataToEncodedData(encrypted_tag_data); |     NTAG215File encoded_data = NfcDataToEncodedData(encrypted_tag_data); | ||||||
|     const auto data_keys = GenerateKey(unfixed_info, encoded_data); |     const auto data_keys = GenerateKey(unfixed_info, encoded_data); | ||||||
|  | @ -308,13 +293,13 @@ bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& t | ||||||
| 
 | 
 | ||||||
|     // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC!
 |     // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC!
 | ||||||
|     constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; |     constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; | ||||||
|     CryptoPP::HMAC<CryptoPP::SHA256> tag_hmac(tag_keys.hmac_key.data(), sizeof(HmacKey)); |     CryptoPP::HMAC<CryptoPP::SHA256> tag_hmac(tag_keys.hmac_key.data(), HMAC_KEY_SIZE); | ||||||
|     tag_hmac.CalculateDigest(reinterpret_cast<unsigned char*>(&tag_data.hmac_tag), |     tag_hmac.CalculateDigest(reinterpret_cast<unsigned char*>(&tag_data.hmac_tag), | ||||||
|                              reinterpret_cast<const unsigned char*>(&tag_data.uid), input_length); |                              reinterpret_cast<const unsigned char*>(&tag_data.uid), input_length); | ||||||
| 
 | 
 | ||||||
|     // Regenerate data HMAC
 |     // Regenerate data HMAC
 | ||||||
|     constexpr std::size_t input_length2 = DYNAMIC_LOCK_START - WRITE_COUNTER_START; |     constexpr std::size_t input_length2 = DYNAMIC_LOCK_START - WRITE_COUNTER_START; | ||||||
|     CryptoPP::HMAC<CryptoPP::SHA256> data_hmac(data_keys.hmac_key.data(), sizeof(HmacKey)); |     CryptoPP::HMAC<CryptoPP::SHA256> data_hmac(data_keys.hmac_key.data(), HMAC_KEY_SIZE); | ||||||
|     data_hmac.CalculateDigest(reinterpret_cast<unsigned char*>(&tag_data.hmac_data), |     data_hmac.CalculateDigest(reinterpret_cast<unsigned char*>(&tag_data.hmac_data), | ||||||
|                               reinterpret_cast<const unsigned char*>(&tag_data.write_counter), |                               reinterpret_cast<const unsigned char*>(&tag_data.write_counter), | ||||||
|                               input_length2); |                               input_length2); | ||||||
|  | @ -333,13 +318,13 @@ bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& t | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_tag_data) { | bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_tag_data) { | ||||||
|     InternalKey locked_secret{}; |     if (!HW::AES::NfcSecretsAvailable()) { | ||||||
|     InternalKey unfixed_info{}; |  | ||||||
| 
 |  | ||||||
|     if (!LoadKeys(locked_secret, unfixed_info)) { |  | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     auto unfixed_info = HW::AES::GetNfcSecret(HW::AES::NfcSecretId::UnfixedInfo); | ||||||
|  |     auto locked_secret = HW::AES::GetNfcSecret(HW::AES::NfcSecretId::LockedSecret); | ||||||
|  | 
 | ||||||
|     // Generate keys
 |     // Generate keys
 | ||||||
|     const auto data_keys = GenerateKey(unfixed_info, tag_data); |     const auto data_keys = GenerateKey(unfixed_info, tag_data); | ||||||
|     const auto tag_keys = GenerateKey(locked_secret, tag_data); |     const auto tag_keys = GenerateKey(locked_secret, tag_data); | ||||||
|  | @ -349,12 +334,12 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t | ||||||
|     // Generate tag HMAC
 |     // Generate tag HMAC
 | ||||||
|     constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; |     constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; | ||||||
|     constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START; |     constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START; | ||||||
|     CryptoPP::HMAC<CryptoPP::SHA256> tag_hmac(tag_keys.hmac_key.data(), sizeof(HmacKey)); |     CryptoPP::HMAC<CryptoPP::SHA256> tag_hmac(tag_keys.hmac_key.data(), HMAC_KEY_SIZE); | ||||||
|     tag_hmac.CalculateDigest(reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), |     tag_hmac.CalculateDigest(reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), | ||||||
|                              reinterpret_cast<const unsigned char*>(&tag_data.uid), input_length); |                              reinterpret_cast<const unsigned char*>(&tag_data.uid), input_length); | ||||||
| 
 | 
 | ||||||
|     // Generate data HMAC
 |     // Generate data HMAC
 | ||||||
|     CryptoPP::HMAC<CryptoPP::SHA256> data_hmac(data_keys.hmac_key.data(), sizeof(HmacKey)); |     CryptoPP::HMAC<CryptoPP::SHA256> data_hmac(data_keys.hmac_key.data(), HMAC_KEY_SIZE); | ||||||
|     data_hmac.Update(reinterpret_cast<const unsigned char*>(&tag_data.write_counter), |     data_hmac.Update(reinterpret_cast<const unsigned char*>(&tag_data.write_counter), | ||||||
|                      input_length2); |                      input_length2); | ||||||
|     data_hmac.Update(reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), |     data_hmac.Update(reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), | ||||||
|  |  | ||||||
|  | @ -15,6 +15,10 @@ template <class T> | ||||||
| class HMAC; | class HMAC; | ||||||
| } // namespace CryptoPP
 | } // namespace CryptoPP
 | ||||||
| 
 | 
 | ||||||
|  | namespace HW::AES { | ||||||
|  | struct NfcSecret; | ||||||
|  | } // namespace HW::AES
 | ||||||
|  | 
 | ||||||
| namespace Service::NFC::AmiiboCrypto { | namespace Service::NFC::AmiiboCrypto { | ||||||
| // Byte locations in Service::NFC::NTAG215File
 | // Byte locations in Service::NFC::NTAG215File
 | ||||||
| constexpr std::size_t HMAC_DATA_START = 0x8; | constexpr std::size_t HMAC_DATA_START = 0x8; | ||||||
|  | @ -24,7 +28,6 @@ constexpr std::size_t HMAC_TAG_START = 0x1B4; | ||||||
| constexpr std::size_t UUID_START = 0x1D4; | constexpr std::size_t UUID_START = 0x1D4; | ||||||
| constexpr std::size_t DYNAMIC_LOCK_START = 0x208; | constexpr std::size_t DYNAMIC_LOCK_START = 0x208; | ||||||
| 
 | 
 | ||||||
| using HmacKey = std::array<u8, 0x10>; |  | ||||||
| using DrgbOutput = std::array<u8, 0x20>; | using DrgbOutput = std::array<u8, 0x20>; | ||||||
| 
 | 
 | ||||||
| struct HashSeed { | struct HashSeed { | ||||||
|  | @ -38,17 +41,6 @@ struct HashSeed { | ||||||
| }; | }; | ||||||
| static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size"); | static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size"); | ||||||
| 
 | 
 | ||||||
| struct InternalKey { |  | ||||||
|     HmacKey hmac_key; |  | ||||||
|     std::array<char, 0xE> type_string; |  | ||||||
|     u8 reserved; |  | ||||||
|     u8 magic_length; |  | ||||||
|     std::array<u8, 0x10> magic_bytes; |  | ||||||
|     std::array<u8, 0x20> xor_pad; |  | ||||||
| }; |  | ||||||
| static_assert(sizeof(InternalKey) == 0x50, "InternalKey is an invalid size"); |  | ||||||
| static_assert(std::is_trivially_copyable_v<InternalKey>, "InternalKey must be trivially copyable."); |  | ||||||
| 
 |  | ||||||
| struct CryptoCtx { | struct CryptoCtx { | ||||||
|     std::array<char, 480> buffer; |     std::array<char, 480> buffer; | ||||||
|     bool used; |     bool used; | ||||||
|  | @ -79,27 +71,21 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data); | ||||||
| HashSeed GetSeed(const NTAG215File& data); | HashSeed GetSeed(const NTAG215File& data); | ||||||
| 
 | 
 | ||||||
| // Middle step on the generation of derived keys
 | // Middle step on the generation of derived keys
 | ||||||
| std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed); | std::vector<u8> GenerateInternalKey(const HW::AES::NfcSecret& secret, const HashSeed& seed); | ||||||
| 
 | 
 | ||||||
| // Initializes mbedtls context
 | // Initializes mbedtls context
 | ||||||
| void CryptoInit(CryptoCtx& ctx, CryptoPP::HMAC<CryptoPP::SHA256>& hmac_ctx, const HmacKey& hmac_key, | void CryptoInit(CryptoCtx& ctx, CryptoPP::HMAC<CryptoPP::SHA256>& hmac_ctx, | ||||||
|                 const std::vector<u8>& seed); |                 std::span<const u8> hmac_key, std::span<const u8> seed); | ||||||
| 
 | 
 | ||||||
| // Feeds data to mbedtls context to generate the derived key
 | // Feeds data to mbedtls context to generate the derived key
 | ||||||
| void CryptoStep(CryptoCtx& ctx, CryptoPP::HMAC<CryptoPP::SHA256>& hmac_ctx, DrgbOutput& output); | void CryptoStep(CryptoCtx& ctx, CryptoPP::HMAC<CryptoPP::SHA256>& hmac_ctx, DrgbOutput& output); | ||||||
| 
 | 
 | ||||||
| // Generates the derived key from amiibo data
 | // Generates the derived key from amiibo data
 | ||||||
| DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data); | DerivedKeys GenerateKey(const HW::AES::NfcSecret& secret, const NTAG215File& data); | ||||||
| 
 | 
 | ||||||
| // Encodes or decodes amiibo data
 | // Encodes or decodes amiibo data
 | ||||||
| void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& out_data); | void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& out_data); | ||||||
| 
 | 
 | ||||||
| /// Loads both amiibo keys from key_retail.bin
 |  | ||||||
| bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info); |  | ||||||
| 
 |  | ||||||
| /// Returns true if key_retail.bin exist
 |  | ||||||
| bool IsKeyAvailable(); |  | ||||||
| 
 |  | ||||||
| /// Decodes encripted amiibo data returns true if output is valid
 | /// Decodes encripted amiibo data returns true if output is valid
 | ||||||
| bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data); | bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| #include "core/hle/kernel/shared_page.h" | #include "core/hle/kernel/shared_page.h" | ||||||
| #include "core/hle/service/nfc/amiibo_crypto.h" | #include "core/hle/service/nfc/amiibo_crypto.h" | ||||||
| #include "core/hle/service/nfc/nfc_device.h" | #include "core/hle/service/nfc/nfc_device.h" | ||||||
|  | #include "core/hw/aes/key.h" | ||||||
| 
 | 
 | ||||||
| SERVICE_CONSTRUCT_IMPL(Service::NFC::NfcDevice) | SERVICE_CONSTRUCT_IMPL(Service::NFC::NfcDevice) | ||||||
| 
 | 
 | ||||||
|  | @ -98,7 +99,7 @@ bool NfcDevice::LoadAmiibo(std::string filename) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Fallback for encrypted amiibos without keys
 |     // Fallback for encrypted amiibos without keys
 | ||||||
|     if (!AmiiboCrypto::IsKeyAvailable()) { |     if (!HW::AES::NfcSecretsAvailable()) { | ||||||
|         LOG_INFO(Service_NFC, "Loading amiibo without keys"); |         LOG_INFO(Service_NFC, "Loading amiibo without keys"); | ||||||
|         memcpy(&encrypted_tag.raw, &tag.raw, sizeof(EncryptedNTAG215File)); |         memcpy(&encrypted_tag.raw, &tag.raw, sizeof(EncryptedNTAG215File)); | ||||||
|         tag.file = {}; |         tag.file = {}; | ||||||
|  |  | ||||||
|  | @ -593,8 +593,18 @@ void SelectDlpNfcKeyYIndex(u8 index) { | ||||||
|     key_slots[KeySlotID::DLPNFCDataKey].SetKeyY(dlp_nfc_key_y_slots.at(index)); |     key_slots[KeySlotID::DLPNFCDataKey].SetKeyY(dlp_nfc_key_y_slots.at(index)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const NfcSecret& GetNfcSecret(u8 index) { | bool NfcSecretsAvailable() { | ||||||
|     return nfc_secrets[index]; |     auto missing_secret = | ||||||
|  |         std::find_if(nfc_secrets.begin(), nfc_secrets.end(), [](auto& nfc_secret) { | ||||||
|  |             return nfc_secret.phrase.empty() || nfc_secret.seed.empty() || | ||||||
|  |                    nfc_secret.hmac_key.empty(); | ||||||
|  |         }); | ||||||
|  |     SelectDlpNfcKeyYIndex(DlpNfcKeyY::Nfc); | ||||||
|  |     return IsNormalKeyAvailable(KeySlotID::DLPNFCDataKey) && missing_secret == nfc_secrets.end(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const NfcSecret& GetNfcSecret(NfcSecretId secret_id) { | ||||||
|  |     return nfc_secrets[secret_id]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const AESIV& GetNfcIv() { | const AESIV& GetNfcIv() { | ||||||
|  |  | ||||||
|  | @ -60,6 +60,11 @@ struct NfcSecret { | ||||||
|     std::vector<u8> hmac_key; |     std::vector<u8> hmac_key; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum NfcSecretId : std::size_t { | ||||||
|  |     UnfixedInfo = 0, | ||||||
|  |     LockedSecret = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| constexpr std::size_t MaxCommonKeySlot = 6; | constexpr std::size_t MaxCommonKeySlot = 6; | ||||||
| constexpr std::size_t NumDlpNfcKeyYs = 2; | constexpr std::size_t NumDlpNfcKeyYs = 2; | ||||||
| constexpr std::size_t NumNfcSecrets = 2; | constexpr std::size_t NumNfcSecrets = 2; | ||||||
|  | @ -83,7 +88,8 @@ AESKey GetNormalKey(std::size_t slot_id); | ||||||
| void SelectCommonKeyIndex(u8 index); | void SelectCommonKeyIndex(u8 index); | ||||||
| void SelectDlpNfcKeyYIndex(u8 index); | void SelectDlpNfcKeyYIndex(u8 index); | ||||||
| 
 | 
 | ||||||
| const NfcSecret& GetNfcSecret(u8 index); | bool NfcSecretsAvailable(); | ||||||
|  | const NfcSecret& GetNfcSecret(NfcSecretId secret_id); | ||||||
| const AESIV& GetNfcIv(); | const AESIV& GetNfcIv(); | ||||||
| 
 | 
 | ||||||
| } // namespace HW::AES
 | } // namespace HW::AES
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue