mirror of
https://git.h3cjp.net/H3cJP/citra.git
synced 2024-11-26 05:22:49 +00:00
nfc: Use existing secrets infrastructure for amiibo encryption. (#6652)
This commit is contained in:
parent
4383f6d80a
commit
c00768d6d0
|
@ -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…
Reference in a new issue