amiibo.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * (c) 2015-2017 Marcos Del Sol Vives
  3. * (c) 2016 javiMaD
  4. *
  5. * SPDX-License-Identifier: MIT
  6. */
  7. #include "amiibo.h"
  8. #include "util.h"
  9. #include "mbedtls/md.h"
  10. #include "mbedtls/aes.h"
  11. #include <errno.h>
  12. #include "portable_endian.h"
  13. #define htobe16(x) __builtin_bswap16(x)
  14. #define be16toh(x) __builtin_bswap16(x)
  15. #define HMAC_POS_DATA 0x008
  16. #define HMAC_POS_TAG 0x1B4
  17. void nfc3d_amiibo_calc_seed(const uint8_t * dump, uint8_t * key) {
  18. memcpy(key + 0x00, dump + 0x029, 0x02);
  19. memset(key + 0x02, 0x00, 0x0E);
  20. memcpy(key + 0x10, dump + 0x1D4, 0x08);
  21. memcpy(key + 0x18, dump + 0x1D4, 0x08);
  22. memcpy(key + 0x20, dump + 0x1E8, 0x20);
  23. }
  24. void nfc3d_amiibo_keygen(const nfc3d_keygen_masterkeys * masterKeys, const uint8_t * dump, nfc3d_keygen_derivedkeys * derivedKeys) {
  25. uint8_t seed[NFC3D_KEYGEN_SEED_SIZE];
  26. nfc3d_amiibo_calc_seed(dump, seed);
  27. nfc3d_keygen(masterKeys, seed, derivedKeys);
  28. }
  29. void nfc3d_amiibo_cipher(const nfc3d_keygen_derivedkeys * keys, const uint8_t * in, uint8_t * out) {
  30. mbedtls_aes_context aes;
  31. size_t nc_off = 0;
  32. unsigned char nonce_counter[16];
  33. unsigned char stream_block[16];
  34. mbedtls_aes_setkey_enc( &aes, keys->aesKey, 128 );
  35. memset(nonce_counter, 0, sizeof(nonce_counter));
  36. memset(stream_block, 0, sizeof(stream_block));
  37. memcpy(nonce_counter, keys->aesIV, sizeof(nonce_counter));
  38. mbedtls_aes_crypt_ctr( &aes, 0x188, &nc_off, nonce_counter, stream_block, in + 0x02C, out + 0x02C );
  39. memcpy(out + 0x000, in + 0x000, 0x008);
  40. // Data signature NOT copied
  41. memcpy(out + 0x028, in + 0x028, 0x004);
  42. // Tag signature NOT copied
  43. memcpy(out + 0x1D4, in + 0x1D4, 0x034);
  44. }
  45. void nfc3d_amiibo_tag_to_internal(const uint8_t * tag, uint8_t * intl) {
  46. memcpy(intl + 0x000, tag + 0x008, 0x008);
  47. memcpy(intl + 0x008, tag + 0x080, 0x020);
  48. memcpy(intl + 0x028, tag + 0x010, 0x024);
  49. memcpy(intl + 0x04C, tag + 0x0A0, 0x168);
  50. memcpy(intl + 0x1B4, tag + 0x034, 0x020);
  51. memcpy(intl + 0x1D4, tag + 0x000, 0x008);
  52. memcpy(intl + 0x1DC, tag + 0x054, 0x02C);
  53. }
  54. void nfc3d_amiibo_internal_to_tag(const uint8_t * intl, uint8_t * tag) {
  55. memcpy(tag + 0x008, intl + 0x000, 0x008);
  56. memcpy(tag + 0x080, intl + 0x008, 0x020);
  57. memcpy(tag + 0x010, intl + 0x028, 0x024);
  58. memcpy(tag + 0x0A0, intl + 0x04C, 0x168);
  59. memcpy(tag + 0x034, intl + 0x1B4, 0x020);
  60. memcpy(tag + 0x000, intl + 0x1D4, 0x008);
  61. memcpy(tag + 0x054, intl + 0x1DC, 0x02C);
  62. }
  63. bool nfc3d_amiibo_unpack(const nfc3d_amiibo_keys * amiiboKeys, const uint8_t * tag, uint8_t * plain) {
  64. uint8_t internal[NFC3D_AMIIBO_SIZE];
  65. nfc3d_keygen_derivedkeys dataKeys;
  66. nfc3d_keygen_derivedkeys tagKeys;
  67. // Convert format
  68. nfc3d_amiibo_tag_to_internal(tag, internal);
  69. // Generate keys
  70. nfc3d_amiibo_keygen(&amiiboKeys->data, internal, &dataKeys);
  71. nfc3d_amiibo_keygen(&amiiboKeys->tag, internal, &tagKeys);
  72. // Decrypt
  73. nfc3d_amiibo_cipher(&dataKeys, internal, plain);
  74. // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC!
  75. mbedtls_md_hmac( mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tagKeys.hmacKey, sizeof(tagKeys.hmacKey),
  76. plain + 0x1D4, 0x34, plain + HMAC_POS_TAG );
  77. // Regenerate data HMAC
  78. mbedtls_md_hmac( mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), dataKeys.hmacKey, sizeof(dataKeys.hmacKey),
  79. plain + 0x029, 0x1DF, plain + HMAC_POS_DATA );
  80. return
  81. memcmp(plain + HMAC_POS_DATA, internal + HMAC_POS_DATA, 32) == 0 &&
  82. memcmp(plain + HMAC_POS_TAG, internal + HMAC_POS_TAG, 32) == 0;
  83. }
  84. void nfc3d_amiibo_pack(const nfc3d_amiibo_keys * amiiboKeys, const uint8_t * plain, uint8_t * tag) {
  85. uint8_t cipher[NFC3D_AMIIBO_SIZE];
  86. nfc3d_keygen_derivedkeys tagKeys;
  87. nfc3d_keygen_derivedkeys dataKeys;
  88. // Generate keys
  89. nfc3d_amiibo_keygen(&amiiboKeys->tag, plain, &tagKeys);
  90. nfc3d_amiibo_keygen(&amiiboKeys->data, plain, &dataKeys);
  91. // Generate tag HMAC
  92. mbedtls_md_hmac( mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tagKeys.hmacKey, sizeof(tagKeys.hmacKey),
  93. plain + 0x1D4, 0x34, cipher + HMAC_POS_TAG );
  94. // Init mbedtls HMAC context
  95. mbedtls_md_context_t ctx;
  96. mbedtls_md_init( &ctx );
  97. mbedtls_md_setup( &ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1 );
  98. // Generate data HMAC
  99. mbedtls_md_hmac_starts( &ctx, dataKeys.hmacKey, sizeof(dataKeys.hmacKey) );
  100. mbedtls_md_hmac_update( &ctx, plain + 0x029, 0x18B ); // Data
  101. mbedtls_md_hmac_update( &ctx, cipher + HMAC_POS_TAG, 0x20 ); // Tag HMAC
  102. mbedtls_md_hmac_update( &ctx, plain + 0x1D4, 0x34 ); // Here be dragons
  103. mbedtls_md_hmac_finish( &ctx, cipher + HMAC_POS_DATA );
  104. // HMAC cleanup
  105. mbedtls_md_free( &ctx );
  106. // Encrypt
  107. nfc3d_amiibo_cipher(&dataKeys, plain, cipher);
  108. // Convert back to hardware
  109. nfc3d_amiibo_internal_to_tag(cipher, tag);
  110. }
  111. bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys * amiiboKeys, const char * path) {
  112. FILE * f = fopen(path, "rb");
  113. if (!f) {
  114. return false;
  115. }
  116. if (!fread(amiiboKeys, sizeof(*amiiboKeys), 1, f)) {
  117. fclose(f);
  118. return false;
  119. }
  120. fclose(f);
  121. if (
  122. (amiiboKeys->data.magicBytesSize > 16) ||
  123. (amiiboKeys->tag.magicBytesSize > 16)
  124. ) {
  125. errno = EILSEQ;
  126. return false;
  127. }
  128. return true;
  129. }
  130. void nfc3d_amiibo_copy_app_data(const uint8_t * src, uint8_t * dst) {
  131. uint16_t *ami_nb_wr = (uint16_t*)(dst + 0x29);
  132. uint16_t *cfg_nb_wr = (uint16_t*)(dst + 0xB4);
  133. /* increment write counters */
  134. *ami_nb_wr = htobe16(be16toh(*ami_nb_wr) + 1);
  135. *cfg_nb_wr = htobe16(be16toh(*cfg_nb_wr) + 1);
  136. /* copy flags */
  137. dst[0x2C] = src[0x2C];
  138. /* copy programID */
  139. memcpy(dst + 0xAC, src + 0xAC, 8);
  140. /* copy AppID */
  141. memcpy(dst + 0xB6, src + 0xB6, 4);
  142. /* copy AppData */
  143. memcpy(dst + 0xDC, src + 0xDC, 216);
  144. }