diff options
| author | 2022-09-07 01:03:02 -0500 | |
|---|---|---|
| committer | 2022-09-07 09:49:43 -0500 | |
| commit | 063b23cc58b1e7367f9e530e752ab56fe1f56532 (patch) | |
| tree | 6d227dca418bb26529762f2ce038c0776a569892 /src | |
| parent | core: nfp: Workaround for lack of multiple nfp interfaces (diff) | |
| download | yuzu-063b23cc58b1e7367f9e530e752ab56fe1f56532.tar.gz yuzu-063b23cc58b1e7367f9e530e752ab56fe1f56532.tar.xz yuzu-063b23cc58b1e7367f9e530e752ab56fe1f56532.zip | |
core: nfp: Remove magic numbers
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_crypto.cpp | 171 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_crypto.h | 29 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_types.h | 8 |
3 files changed, 103 insertions, 105 deletions
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index d9d0c8f62..31dd3a307 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp | |||
| @@ -70,10 +70,10 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { | |||
| 70 | NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | 70 | NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { |
| 71 | NTAG215File encoded_data{}; | 71 | NTAG215File encoded_data{}; |
| 72 | 72 | ||
| 73 | memcpy(encoded_data.uuid2.data(), nfc_data.uuid.data() + 0x8, 2); | 73 | memcpy(encoded_data.uuid2.data(), nfc_data.uuid.data() + 0x8, sizeof(encoded_data.uuid2)); |
| 74 | encoded_data.static_lock = nfc_data.static_lock; | 74 | encoded_data.static_lock = nfc_data.static_lock; |
| 75 | encoded_data.compability_container = nfc_data.compability_container; | 75 | encoded_data.compability_container = nfc_data.compability_container; |
| 76 | encoded_data.unfixed_hash = nfc_data.user_memory.unfixed_hash; | 76 | encoded_data.hmac_data = nfc_data.user_memory.hmac_data; |
| 77 | encoded_data.constant_value = nfc_data.user_memory.constant_value; | 77 | encoded_data.constant_value = nfc_data.user_memory.constant_value; |
| 78 | encoded_data.write_counter = nfc_data.user_memory.write_counter; | 78 | encoded_data.write_counter = nfc_data.user_memory.write_counter; |
| 79 | encoded_data.settings = nfc_data.user_memory.settings; | 79 | encoded_data.settings = nfc_data.user_memory.settings; |
| @@ -84,8 +84,8 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | |||
| 84 | encoded_data.unknown = nfc_data.user_memory.unknown; | 84 | encoded_data.unknown = nfc_data.user_memory.unknown; |
| 85 | encoded_data.hash = nfc_data.user_memory.hash; | 85 | encoded_data.hash = nfc_data.user_memory.hash; |
| 86 | encoded_data.application_area = nfc_data.user_memory.application_area; | 86 | encoded_data.application_area = nfc_data.user_memory.application_area; |
| 87 | encoded_data.locked_hash = nfc_data.user_memory.locked_hash; | 87 | encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag; |
| 88 | memcpy(encoded_data.uuid.data(), nfc_data.uuid.data(), 8); | 88 | memcpy(encoded_data.uuid.data(), nfc_data.uuid.data(), sizeof(encoded_data.uuid)); |
| 89 | encoded_data.model_info = nfc_data.user_memory.model_info; | 89 | encoded_data.model_info = nfc_data.user_memory.model_info; |
| 90 | encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt; | 90 | encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt; |
| 91 | encoded_data.dynamic_lock = nfc_data.dynamic_lock; | 91 | encoded_data.dynamic_lock = nfc_data.dynamic_lock; |
| @@ -99,11 +99,11 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { | |||
| 99 | EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { | 99 | EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { |
| 100 | EncryptedNTAG215File nfc_data{}; | 100 | EncryptedNTAG215File nfc_data{}; |
| 101 | 101 | ||
| 102 | memcpy(nfc_data.uuid.data() + 0x8, encoded_data.uuid2.data(), 2); | 102 | memcpy(nfc_data.uuid.data() + 0x8, encoded_data.uuid2.data(), sizeof(encoded_data.uuid2)); |
| 103 | memcpy(nfc_data.uuid.data(), encoded_data.uuid.data(), 8); | 103 | memcpy(nfc_data.uuid.data(), encoded_data.uuid.data(), sizeof(encoded_data.uuid)); |
| 104 | nfc_data.static_lock = encoded_data.static_lock; | 104 | nfc_data.static_lock = encoded_data.static_lock; |
| 105 | nfc_data.compability_container = encoded_data.compability_container; | 105 | nfc_data.compability_container = encoded_data.compability_container; |
| 106 | nfc_data.user_memory.unfixed_hash = encoded_data.unfixed_hash; | 106 | nfc_data.user_memory.hmac_data = encoded_data.hmac_data; |
| 107 | nfc_data.user_memory.constant_value = encoded_data.constant_value; | 107 | nfc_data.user_memory.constant_value = encoded_data.constant_value; |
| 108 | nfc_data.user_memory.write_counter = encoded_data.write_counter; | 108 | nfc_data.user_memory.write_counter = encoded_data.write_counter; |
| 109 | nfc_data.user_memory.settings = encoded_data.settings; | 109 | nfc_data.user_memory.settings = encoded_data.settings; |
| @@ -114,7 +114,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { | |||
| 114 | nfc_data.user_memory.unknown = encoded_data.unknown; | 114 | nfc_data.user_memory.unknown = encoded_data.unknown; |
| 115 | nfc_data.user_memory.hash = encoded_data.hash; | 115 | nfc_data.user_memory.hash = encoded_data.hash; |
| 116 | nfc_data.user_memory.application_area = encoded_data.application_area; | 116 | nfc_data.user_memory.application_area = encoded_data.application_area; |
| 117 | nfc_data.user_memory.locked_hash = encoded_data.locked_hash; | 117 | nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag; |
| 118 | nfc_data.user_memory.model_info = encoded_data.model_info; | 118 | nfc_data.user_memory.model_info = encoded_data.model_info; |
| 119 | nfc_data.user_memory.keygen_salt = encoded_data.keygen_salt; | 119 | nfc_data.user_memory.keygen_salt = encoded_data.keygen_salt; |
| 120 | nfc_data.dynamic_lock = encoded_data.dynamic_lock; | 120 | nfc_data.dynamic_lock = encoded_data.dynamic_lock; |
| @@ -136,60 +136,53 @@ u32 GetTagPassword(const TagUuid& uuid) { | |||
| 136 | 136 | ||
| 137 | HashSeed GetSeed(const NTAG215File& data) { | 137 | HashSeed GetSeed(const NTAG215File& data) { |
| 138 | HashSeed seed{ | 138 | HashSeed seed{ |
| 139 | .data = | 139 | .magic = data.write_counter, |
| 140 | { | 140 | .padding = {}, |
| 141 | .magic = data.write_counter, | 141 | .uuid1 = {}, |
| 142 | .padding = {}, | 142 | .uuid2 = {}, |
| 143 | .uuid1 = {}, | 143 | .keygen_salt = data.keygen_salt, |
| 144 | .uuid2 = {}, | ||
| 145 | .keygen_salt = data.keygen_salt, | ||
| 146 | }, | ||
| 147 | }; | 144 | }; |
| 148 | 145 | ||
| 149 | // Copy the first 8 bytes of uuid | 146 | // Copy the first 8 bytes of uuid |
| 150 | memcpy(seed.data.uuid1.data(), data.uuid.data(), sizeof(seed.data.uuid1)); | 147 | memcpy(seed.uuid1.data(), data.uuid.data(), sizeof(seed.uuid1)); |
| 151 | memcpy(seed.data.uuid2.data(), data.uuid.data(), sizeof(seed.data.uuid2)); | 148 | memcpy(seed.uuid2.data(), data.uuid.data(), sizeof(seed.uuid2)); |
| 152 | 149 | ||
| 153 | return seed; | 150 | return seed; |
| 154 | } | 151 | } |
| 155 | 152 | ||
| 156 | void PreGenerateKey(const InternalKey& key, const HashSeed& seed, u8* output, | 153 | std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed) { |
| 157 | std::size_t& outputLen) { | 154 | const std::size_t seedPart1Len = sizeof(key.magic_bytes) - key.magic_length; |
| 158 | std::size_t index = 0; | 155 | const std::size_t string_size = key.type_string.size(); |
| 156 | std::vector<u8> output(string_size + seedPart1Len); | ||
| 159 | 157 | ||
| 160 | // Copy whole type string | 158 | // Copy whole type string |
| 161 | memccpy(output + index, key.type_string.data(), '\0', key.type_string.size()); | 159 | memccpy(output.data(), key.type_string.data(), '\0', string_size); |
| 162 | index += key.type_string.size(); | ||
| 163 | 160 | ||
| 164 | // Append (16 - magic_length) from the input seed | 161 | // Append (16 - magic_length) from the input seed |
| 165 | std::size_t seedPart1Len = 16 - key.magic_length; | 162 | memcpy(output.data() + string_size, &seed, seedPart1Len); |
| 166 | memcpy(output + index, &seed, seedPart1Len); | ||
| 167 | index += seedPart1Len; | ||
| 168 | 163 | ||
| 169 | // Append all bytes from magicBytes | 164 | // Append all bytes from magicBytes |
| 170 | memcpy(output + index, &key.magic_bytes, key.magic_length); | 165 | output.insert(output.end(), key.magic_bytes.begin(), |
| 171 | index += key.magic_length; | 166 | key.magic_bytes.begin() + key.magic_length); |
| 172 | 167 | ||
| 173 | // Seed 16 bytes at +0x10 | 168 | output.insert(output.end(), seed.uuid1.begin(), seed.uuid1.end()); |
| 174 | memcpy(output + index, &seed.raw[0x10], 16); | 169 | output.insert(output.end(), seed.uuid2.begin(), seed.uuid2.end()); |
| 175 | index += 16; | ||
| 176 | 170 | ||
| 177 | // 32 bytes at +0x20 from input seed xored with xor pad | 171 | for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) { |
| 178 | for (std::size_t i = 0; i < 32; i++) | 172 | output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i])); |
| 179 | output[index + i] = seed.raw[i + 32] ^ key.xor_pad[i]; | 173 | } |
| 180 | index += 32; | ||
| 181 | 174 | ||
| 182 | outputLen = index; | 175 | return output; |
| 183 | } | 176 | } |
| 184 | 177 | ||
| 185 | void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, | 178 | void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, |
| 186 | const u8* seed, std::size_t seed_size) { | 179 | const std::vector<u8>& seed) { |
| 187 | 180 | ||
| 188 | // Initialize context | 181 | // Initialize context |
| 189 | ctx.used = false; | 182 | ctx.used = false; |
| 190 | ctx.counter = 0; | 183 | ctx.counter = 0; |
| 191 | ctx.buffer_size = sizeof(ctx.counter) + seed_size; | 184 | ctx.buffer_size = sizeof(ctx.counter) + seed.size(); |
| 192 | memcpy(ctx.buffer.data() + sizeof(u16), seed, seed_size); | 185 | memcpy(ctx.buffer.data() + sizeof(u16), seed.data(), seed.size()); |
| 193 | 186 | ||
| 194 | // Initialize HMAC context | 187 | // Initialize HMAC context |
| 195 | mbedtls_md_init(&hmac_ctx); | 188 | mbedtls_md_init(&hmac_ctx); |
| @@ -217,18 +210,15 @@ void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& outp | |||
| 217 | } | 210 | } |
| 218 | 211 | ||
| 219 | DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) { | 212 | DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) { |
| 220 | constexpr std::size_t OUTPUT_SIZE = 512; | ||
| 221 | const auto seed = GetSeed(data); | 213 | const auto seed = GetSeed(data); |
| 222 | 214 | ||
| 223 | // Generate internal seed | 215 | // Generate internal seed |
| 224 | u8 internal_key[OUTPUT_SIZE]; | 216 | const std::vector<u8> internal_key = GenerateInternalKey(key, seed); |
| 225 | std::size_t internal_key_lenght = 0; | ||
| 226 | PreGenerateKey(key, seed, internal_key, internal_key_lenght); | ||
| 227 | 217 | ||
| 228 | // Initialize context | 218 | // Initialize context |
| 229 | CryptoCtx ctx{}; | 219 | CryptoCtx ctx{}; |
| 230 | mbedtls_md_context_t hmac_ctx; | 220 | mbedtls_md_context_t hmac_ctx; |
| 231 | CryptoInit(ctx, hmac_ctx, key.hmac_key, internal_key, internal_key_lenght); | 221 | CryptoInit(ctx, hmac_ctx, key.hmac_key, internal_key); |
| 232 | 222 | ||
| 233 | // Generate derived keys | 223 | // Generate derived keys |
| 234 | DerivedKeys derived_keys{}; | 224 | DerivedKeys derived_keys{}; |
| @@ -246,27 +236,34 @@ DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) { | |||
| 246 | void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& out_data) { | 236 | void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& out_data) { |
| 247 | mbedtls_aes_context aes; | 237 | mbedtls_aes_context aes; |
| 248 | std::size_t nc_off = 0; | 238 | std::size_t nc_off = 0; |
| 249 | std::array<u8, 0x10> nonce_counter{}; | 239 | std::array<u8, sizeof(keys.aes_iv)> nonce_counter{}; |
| 250 | std::array<u8, 0x10> stream_block{}; | 240 | std::array<u8, sizeof(keys.aes_iv)> stream_block{}; |
| 251 | 241 | ||
| 252 | mbedtls_aes_setkey_enc(&aes, keys.aes_key.data(), 128); | 242 | const auto aes_key_size = static_cast<u32>(keys.aes_key.size() * 8); |
| 253 | memcpy(nonce_counter.data(), keys.aes_iv.data(), sizeof(nonce_counter)); | 243 | mbedtls_aes_setkey_enc(&aes, keys.aes_key.data(), aes_key_size); |
| 254 | 244 | memcpy(nonce_counter.data(), keys.aes_iv.data(), sizeof(keys.aes_iv)); | |
| 255 | std::array<u8, sizeof(NTAG215File)> in_data_byes{}; | 245 | |
| 256 | std::array<u8, sizeof(NTAG215File)> out_data_bytes{}; | 246 | constexpr std::size_t encrypted_data_size = HMAC_TAG_START - SETTINGS_START; |
| 257 | memcpy(in_data_byes.data(), &in_data, sizeof(NTAG215File)); | 247 | mbedtls_aes_crypt_ctr(&aes, encrypted_data_size, &nc_off, nonce_counter.data(), |
| 258 | memcpy(out_data_bytes.data(), &out_data, sizeof(NTAG215File)); | 248 | stream_block.data(), |
| 259 | 249 | reinterpret_cast<const unsigned char*>(&in_data.settings), | |
| 260 | mbedtls_aes_crypt_ctr(&aes, 0x188, &nc_off, nonce_counter.data(), stream_block.data(), | 250 | reinterpret_cast<unsigned char*>(&out_data.settings)); |
| 261 | in_data_byes.data() + 0x2c, out_data_bytes.data() + 0x2c); | 251 | |
| 262 | 252 | // Copy the rest of the data directly | |
| 263 | memcpy(out_data_bytes.data(), in_data_byes.data(), 0x008); | 253 | out_data.uuid2 = in_data.uuid2; |
| 264 | // Data signature NOT copied | 254 | out_data.static_lock = in_data.static_lock; |
| 265 | memcpy(out_data_bytes.data() + 0x028, in_data_byes.data() + 0x028, 0x004); | 255 | out_data.compability_container = in_data.compability_container; |
| 266 | // Tag signature NOT copied | 256 | |
| 267 | memcpy(out_data_bytes.data() + 0x1D4, in_data_byes.data() + 0x1D4, 0x048); | 257 | out_data.constant_value = in_data.constant_value; |
| 268 | 258 | out_data.write_counter = in_data.write_counter; | |
| 269 | memcpy(&out_data, out_data_bytes.data(), sizeof(NTAG215File)); | 259 | |
| 260 | out_data.uuid = in_data.uuid; | ||
| 261 | out_data.model_info = in_data.model_info; | ||
| 262 | out_data.keygen_salt = in_data.keygen_salt; | ||
| 263 | out_data.dynamic_lock = in_data.dynamic_lock; | ||
| 264 | out_data.CFG0 = in_data.CFG0; | ||
| 265 | out_data.CFG1 = in_data.CFG1; | ||
| 266 | out_data.password = in_data.password; | ||
| 270 | } | 267 | } |
| 271 | 268 | ||
| 272 | bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) { | 269 | bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) { |
| @@ -309,26 +306,26 @@ bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& t | |||
| 309 | // Decrypt | 306 | // Decrypt |
| 310 | Cipher(data_keys, encoded_data, tag_data); | 307 | Cipher(data_keys, encoded_data, tag_data); |
| 311 | 308 | ||
| 312 | std::array<u8, sizeof(NTAG215File)> out{}; | ||
| 313 | memcpy(out.data(), &tag_data, sizeof(NTAG215File)); | ||
| 314 | |||
| 315 | // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC! | 309 | // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC! |
| 310 | constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; | ||
| 316 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), | 311 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), |
| 317 | sizeof(HmacKey), out.data() + 0x1D4, 0x34, out.data() + HMAC_POS_TAG); | 312 | sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uuid), |
| 313 | input_length, reinterpret_cast<unsigned char*>(&tag_data.hmac_tag)); | ||
| 318 | 314 | ||
| 319 | // Regenerate data HMAC | 315 | // Regenerate data HMAC |
| 316 | constexpr std::size_t input_length2 = DYNAMIC_LOCK_START - WRITE_COUNTER_START; | ||
| 320 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), data_keys.hmac_key.data(), | 317 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), data_keys.hmac_key.data(), |
| 321 | sizeof(HmacKey), out.data() + 0x29, 0x1DF, out.data() + HMAC_POS_DATA); | 318 | sizeof(HmacKey), |
| 322 | 319 | reinterpret_cast<const unsigned char*>(&tag_data.write_counter), input_length2, | |
| 323 | memcpy(&tag_data, out.data(), sizeof(NTAG215File)); | 320 | reinterpret_cast<unsigned char*>(&tag_data.hmac_data)); |
| 324 | 321 | ||
| 325 | if (memcmp(tag_data.unfixed_hash.data(), encrypted_tag_data.user_memory.unfixed_hash.data(), | 322 | if (tag_data.hmac_data != encrypted_tag_data.user_memory.hmac_data) { |
| 326 | 32) != 0) { | 323 | LOG_ERROR(Service_NFP, "hmac_data doesn't match"); |
| 327 | return false; | 324 | return false; |
| 328 | } | 325 | } |
| 329 | 326 | ||
| 330 | if (memcmp(tag_data.locked_hash.data(), encrypted_tag_data.user_memory.locked_hash.data(), | 327 | if (tag_data.hmac_tag != encrypted_tag_data.user_memory.hmac_tag) { |
| 331 | 32) != 0) { | 328 | LOG_ERROR(Service_NFP, "hmac_tag doesn't match"); |
| 332 | return false; | 329 | return false; |
| 333 | } | 330 | } |
| 334 | 331 | ||
| @@ -347,13 +344,14 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t | |||
| 347 | const auto data_keys = GenerateKey(unfixed_info, tag_data); | 344 | const auto data_keys = GenerateKey(unfixed_info, tag_data); |
| 348 | const auto tag_keys = GenerateKey(locked_secret, tag_data); | 345 | const auto tag_keys = GenerateKey(locked_secret, tag_data); |
| 349 | 346 | ||
| 350 | std::array<u8, sizeof(NTAG215File)> plain{}; | 347 | NTAG215File encoded_tag_data{}; |
| 351 | std::array<u8, sizeof(NTAG215File)> cipher{}; | ||
| 352 | memcpy(plain.data(), &tag_data, sizeof(NTAG215File)); | ||
| 353 | 348 | ||
| 354 | // Generate tag HMAC | 349 | // Generate tag HMAC |
| 350 | constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START; | ||
| 351 | constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START; | ||
| 355 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), | 352 | mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(), |
| 356 | sizeof(HmacKey), plain.data() + 0x1D4, 0x34, cipher.data() + HMAC_POS_TAG); | 353 | sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uuid), |
| 354 | input_length, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag)); | ||
| 357 | 355 | ||
| 358 | // Init mbedtls HMAC context | 356 | // Init mbedtls HMAC context |
| 359 | mbedtls_md_context_t ctx; | 357 | mbedtls_md_context_t ctx; |
| @@ -362,17 +360,18 @@ bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_t | |||
| 362 | 360 | ||
| 363 | // Generate data HMAC | 361 | // Generate data HMAC |
| 364 | mbedtls_md_hmac_starts(&ctx, data_keys.hmac_key.data(), sizeof(HmacKey)); | 362 | mbedtls_md_hmac_starts(&ctx, data_keys.hmac_key.data(), sizeof(HmacKey)); |
| 365 | mbedtls_md_hmac_update(&ctx, plain.data() + 0x029, 0x18B); // Data | 363 | mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.write_counter), |
| 366 | mbedtls_md_hmac_update(&ctx, cipher.data() + HMAC_POS_TAG, 0x20); // Tag HMAC | 364 | input_length2); // Data |
| 367 | mbedtls_md_hmac_update(&ctx, plain.data() + 0x1D4, 0x34); | 365 | mbedtls_md_hmac_update(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag), |
| 368 | mbedtls_md_hmac_finish(&ctx, cipher.data() + HMAC_POS_DATA); | 366 | sizeof(HashData)); // Tag HMAC |
| 367 | mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.uuid), | ||
| 368 | input_length); | ||
| 369 | mbedtls_md_hmac_finish(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_data)); | ||
| 369 | 370 | ||
| 370 | // HMAC cleanup | 371 | // HMAC cleanup |
| 371 | mbedtls_md_free(&ctx); | 372 | mbedtls_md_free(&ctx); |
| 372 | 373 | ||
| 373 | // Encrypt | 374 | // Encrypt |
| 374 | NTAG215File encoded_tag_data{}; | ||
| 375 | memcpy(&encoded_tag_data, cipher.data(), sizeof(NTAG215File)); | ||
| 376 | Cipher(data_keys, tag_data, encoded_tag_data); | 375 | Cipher(data_keys, tag_data, encoded_tag_data); |
| 377 | 376 | ||
| 378 | // Convert back to hardware | 377 | // Convert back to hardware |
diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfp/amiibo_crypto.h index 9b021a5eb..af7335912 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.h +++ b/src/core/hle/service/nfp/amiibo_crypto.h | |||
| @@ -10,23 +10,23 @@ | |||
| 10 | struct mbedtls_md_context_t; | 10 | struct mbedtls_md_context_t; |
| 11 | 11 | ||
| 12 | namespace Service::NFP::AmiiboCrypto { | 12 | namespace Service::NFP::AmiiboCrypto { |
| 13 | constexpr std::size_t HMAC_POS_DATA = 0x8; | 13 | // Byte locations in Service::NFP::NTAG215File |
| 14 | constexpr std::size_t HMAC_POS_TAG = 0x1B4; | 14 | constexpr std::size_t HMAC_DATA_START = 0x8; |
| 15 | constexpr std::size_t SETTINGS_START = 0x2c; | ||
| 16 | constexpr std::size_t WRITE_COUNTER_START = 0x29; | ||
| 17 | constexpr std::size_t HMAC_TAG_START = 0x1B4; | ||
| 18 | constexpr std::size_t UUID_START = 0x1D4; | ||
| 19 | constexpr std::size_t DYNAMIC_LOCK_START = 0x208; | ||
| 15 | 20 | ||
| 16 | using HmacKey = std::array<u8, 0x10>; | 21 | using HmacKey = std::array<u8, 0x10>; |
| 17 | using DrgbOutput = std::array<u8, 0x20>; | 22 | using DrgbOutput = std::array<u8, 0x20>; |
| 18 | 23 | ||
| 19 | struct HashSeed { | 24 | struct HashSeed { |
| 20 | union { | 25 | u16 magic; |
| 21 | std::array<u8, 0x40> raw; | 26 | std::array<u8, 0xE> padding; |
| 22 | struct { | 27 | std::array<u8, 0x8> uuid1; |
| 23 | u16 magic; | 28 | std::array<u8, 0x8> uuid2; |
| 24 | std::array<u8, 0xE> padding; | 29 | std::array<u8, 0x20> keygen_salt; |
| 25 | std::array<u8, 0x8> uuid1; | ||
| 26 | std::array<u8, 0x8> uuid2; | ||
| 27 | std::array<u8, 0x20> keygen_salt; | ||
| 28 | } data; | ||
| 29 | }; | ||
| 30 | }; | 30 | }; |
| 31 | static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size"); | 31 | static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size"); |
| 32 | 32 | ||
| @@ -71,12 +71,11 @@ u32 GetTagPassword(const TagUuid& uuid); | |||
| 71 | HashSeed GetSeed(const NTAG215File& data); | 71 | HashSeed GetSeed(const NTAG215File& data); |
| 72 | 72 | ||
| 73 | // Middle step on the generation of derived keys | 73 | // Middle step on the generation of derived keys |
| 74 | void PreGenerateKey(const InternalKey& key, const HashSeed& seed, u8* output, | 74 | std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed); |
| 75 | std::size_t& outputLen); | ||
| 76 | 75 | ||
| 77 | // Initializes mbedtls context | 76 | // Initializes mbedtls context |
| 78 | void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, | 77 | void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, |
| 79 | const u8* seed, std::size_t seed_size); | 78 | const std::vector<u8>& seed); |
| 80 | 79 | ||
| 81 | // Feeds data to mbedtls context to generate the derived key | 80 | // Feeds data to mbedtls context to generate the derived key |
| 82 | void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output); | 81 | void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output); |
diff --git a/src/core/hle/service/nfp/amiibo_types.h b/src/core/hle/service/nfp/amiibo_types.h index c9c0932d0..bf2de811a 100644 --- a/src/core/hle/service/nfp/amiibo_types.h +++ b/src/core/hle/service/nfp/amiibo_types.h | |||
| @@ -137,10 +137,10 @@ struct EncryptedAmiiboFile { | |||
| 137 | u16 write_counter; // Number of times the amiibo has been written? | 137 | u16 write_counter; // Number of times the amiibo has been written? |
| 138 | INSERT_PADDING_BYTES(0x1); // Unknown 1 | 138 | INSERT_PADDING_BYTES(0x1); // Unknown 1 |
| 139 | AmiiboSettings settings; // Encrypted amiibo settings | 139 | AmiiboSettings settings; // Encrypted amiibo settings |
| 140 | HashData locked_hash; // Hash | 140 | HashData hmac_tag; // Hash |
| 141 | AmiiboModelInfo model_info; // Encrypted amiibo model info | 141 | AmiiboModelInfo model_info; // Encrypted amiibo model info |
| 142 | HashData keygen_salt; // Salt | 142 | HashData keygen_salt; // Salt |
| 143 | HashData unfixed_hash; // Hash | 143 | HashData hmac_data; // Hash |
| 144 | Service::Mii::Ver3StoreData owner_mii; // Encrypted Mii data | 144 | Service::Mii::Ver3StoreData owner_mii; // Encrypted Mii data |
| 145 | u64_be title_id; // Encrypted Game id | 145 | u64_be title_id; // Encrypted Game id |
| 146 | u16_be applicaton_write_counter; // Encrypted Counter | 146 | u16_be applicaton_write_counter; // Encrypted Counter |
| @@ -155,7 +155,7 @@ struct NTAG215File { | |||
| 155 | std::array<u8, 0x2> uuid2; | 155 | std::array<u8, 0x2> uuid2; |
| 156 | u16 static_lock; // Set defined pages as read only | 156 | u16 static_lock; // Set defined pages as read only |
| 157 | u32 compability_container; // Defines available memory | 157 | u32 compability_container; // Defines available memory |
| 158 | HashData unfixed_hash; // Hash | 158 | HashData hmac_data; // Hash |
| 159 | u8 constant_value; // Must be A5 | 159 | u8 constant_value; // Must be A5 |
| 160 | u16 write_counter; // Number of times the amiibo has been written? | 160 | u16 write_counter; // Number of times the amiibo has been written? |
| 161 | INSERT_PADDING_BYTES(0x1); // Unknown 1 | 161 | INSERT_PADDING_BYTES(0x1); // Unknown 1 |
| @@ -167,7 +167,7 @@ struct NTAG215File { | |||
| 167 | std::array<u8, 0x2> unknown; | 167 | std::array<u8, 0x2> unknown; |
| 168 | HashData hash; // Probably a SHA256-HMAC hash? | 168 | HashData hash; // Probably a SHA256-HMAC hash? |
| 169 | ApplicationArea application_area; // Encrypted Game data | 169 | ApplicationArea application_area; // Encrypted Game data |
| 170 | HashData locked_hash; // Hash | 170 | HashData hmac_tag; // Hash |
| 171 | std::array<u8, 0x8> uuid; | 171 | std::array<u8, 0x8> uuid; |
| 172 | AmiiboModelInfo model_info; | 172 | AmiiboModelInfo model_info; |
| 173 | HashData keygen_salt; // Salt | 173 | HashData keygen_salt; // Salt |