Reverse Engineering Nintendo Amiibo (NFC Toy)
Intro
This is an attempt to summarize the (circa 2015) reverse-engineering efforts of the Nintendo Amiibo NFC toys. I personally had no involvement - I only recently became aware of the efforts when I made a simple iOS app called TagWallet (github link). This is merely a compilation of what I've learned.
Amiibo Overview
- ~4" (10cm) tall collectible figurines (or cards) made by Nintendo that have an integrated NTAG215 chip at their base
- Recent game consoles (e.g. 3DS, Switch) and controllers have NFC readers to detect Amiibo "taps"
- Amiibo's can unlock extra character/levels in games or give bonuses/special items (via reading from NTAG215)
- Amiibo's can track player customizations and/or level-ups (via writing to NTAG215)
- There's often artificial scarcity of certain models. Some are especially rare or "special" and re-sold on ebay for highly marked up prices.
NTAG215 Overview
- 30mm diameter NFC "sticker" or wallet-sized plastic card that can be had for $0.20 to $0.50 each.
- "Contactless" read/write data transmission (in practice you physically tap tag to reader or hold within 1cm)
- Tag has 540 bytes total EEPROM. (504 bytes available for user data)
- Data transfer of 106 kbit/s (all 540 bytes in 40ms)
- Memory is read/written to in 4-byte chunks called "pages", for a total of 135 pages.
- 7-byte UID (aka serial number) hardcoded at factory that can't be changed (plus 2 check bytes for 9 bytes total)
- The "lock bytes" specify which pages can no longer be written to. Each bit corresponds to a range of pages. Once a bit has been set, it's can't be unset and the corresponding page(s) are read-only henceforth.
NTAG215 Byte Layout
Page | Byte Offset in Page | |||
---|---|---|---|---|
0 | 1 | 2 | 3 | |
0 | UID | |||
1 | ||||
2 | Internal | Lock Bytes | ||
3 | Capability Container | |||
4 | User Data 504 bytes read/write |
|||
5 | ||||
6 | ||||
... | ||||
127 | ||||
128 | ||||
129 | ||||
130 | Dynamic Lock Bytes | - | ||
131 | MIRROR | - | MIRROR_PAGE | AUTH0 |
132 | ACCESS | - | ||
133 | PWD | |||
134 | PACK | - |
NTAG215 Authentication
The NTAG215 provides a rudimentary authentication mechanism. To enable password authentication:
- Write to the AUTH0 byte to specify the page from which password verification is required
- Write to the ACCESS byte to specify "write access protection" or "read and write access protection". Also you can configure the max allowed invalid attempts (default = 11) to prevent brute force attacks.
- Write a 32-bit password to the PWD bytes. Mifare recommends that the password be derived from the UID to improve security.
- Write a 16-bit password acknowledgement to the PACK bytes
Once enabled, you must use the PWD_AUTH command to authenticate, which returns the PACK value as acknowledgement.
NTAG215 Commands
In iOS, you use the CoreNFC framework to create a connection between your app and a tag. Once connected, you issue MiFare commands (as specified in the data sheet) to read or write, or otherwise interact with the tag). Despite what the CoreNFC documentation says, Apple computes the 2-byte CRC for you, which simplifies things! I believe it's a similar situation with Android.
Below are the four most common commands. Here are some examples of these commands in use (Swift).
GET_VERSION
Request:Byte Offset | Description | Value |
---|---|---|
0 | Command | 0x60 |
Byte Offset | Description | Value |
---|---|---|
0 | Fixed Header | 0x00 |
1 | Vendor ID | 0x04 |
2 | Product Type | 0x04 |
3 | Product Subtype | 0x02 |
4 | Maj. Product Ver. | 0x01 |
5 | Min. Product Ver. | 0x00 |
6 | Storage Size | 0x11 |
7 | Protocol Type | 0x03 |
READ
Reads 4 pages (16 bytes) starting at the specified page number
Byte Offset | Description | Value |
---|---|---|
0 | Command | 0x30 |
1 | Start Page # | [0..<135] |
Byte Offset | Description | Value |
---|---|---|
0..<4 | Page[start + 0] | 4 bytes |
4..<8 | Page[start + 1] | 4 bytes |
8..<12 | Page[start + 2] | 4 bytes |
12..<16 | Page[start + 3] | 4 bytes |
FAST_READ
Reads a range of pages, inclusive of the start/end pages. Note: I experienced timeout errors when I tried to read an entire tag's memory in a single FAST_READ. I ended up doing a few batches of ~40 pages each, which seems to be a common approach.
Byte Offset | Description | Value |
---|---|---|
0 | Command | 0x3A |
1 | Start Page # | [0..<135] |
2 | End Page # | [0..<135] |
Byte Offset | Description | Value |
---|---|---|
0..<4 | Page[start] | 4 bytes |
4..<8 | Page[start + 1] | 4 bytes |
... | ... | 4 bytes |
... | Page[end] | 4 bytes |
WRITE
Write a single page (4 bytes) at a time.
Byte Offset | Description | Value |
---|---|---|
0 | Command | 0xA2 |
1 | Page # | [0..<135] |
2..<6 | Data | 4 bytes |
Byte Offset | Description | Value |
---|---|---|
0 | ACK/NAK | 4 bit value |
PWD_AUTH
Authenticate with tag if read and/or write password protection was previously enabled.
Byte Offset | Description | Value |
---|---|---|
0 | Command | 0x1B |
1..<5 | Password | 4 bytes |
Byte Offset | Description | Value |
---|---|---|
0..<2 | PACK | 2 bytes |
Amiibo Encryption Reverse Engineering
- All 504 bytes of "user memory" can be freely read.
- Password required for write acces
- The NTAG215 "lock bytes" are set to disable write-access to the "Amiibo Model Info" (so you can't change an existing amiibo into a different model)
- To increase security, Nintendo added their own layer of encryption and digital signing. The digital signing prevents you from blindly altering the game data bytes because then the signature will no longer match. Additionally, the signature is also based on the UID of the tag, so you can't simply copy the bytes from an Amiibo to a blank NTAG215 to clone it (because the blank tag has a different, hard-coded UID).
- See Amiibo Byte Layout below
In April of 2015, Marcos Del Sol Vives (aka socram8888) announced on reddit that he had determined the Amiibo encryption and signing scheme by reverse-engineered the NFC binary employed by the Nintendo 3DS operating system. He discovered that the game console has the following data hard-coded into the hardware:
- "Data" Key Info: (used for decrypting and signing user memory)
- 16-byte HMAC key
- 14-byte "magic bytes"
- 14-byte "type string" (literally: "unfixed infos")
- "Tag" Key Info: (used for signing tag UID and tag settings)
- 16-byte HMAC key
- 16-byte "magic bytes"
- 14-byte "type string" (literally: "locked secret")
- 32-byte xorpad
The hard-coded "Data" and "Tag" keys above are not used directly for encryption/signing. Rather, the key info is used (along with data unique to each tag) as input to a DRBG (Deterministic Random Bit Generator) to derive the actual keys. This process is outlined below:
"DRBG Seed" Parts | Size |
---|---|
"Type String" | 14 bytes |
Magic Bytes (Prepended with 2-byte "Amiibo Write Counter" if "Data" Key Info) | 16 bytes |
Tag UID | 8 bytes |
Tag UID | 8 bytes |
xorpad ^ amiibo salt (amiibo salt found on page[24..<32]) | 32 bytes |
Each "DRBG Seed" is then used as input for HMAC-SHA256, signed with its respective "16-byte HMAC key", to get the actual keys, like so:
HMAC-SHA256 Input | HMAC-SHA256 Output | |
---|---|---|
0x0000 + "DRBG Seed" | 16 bytes | AES Key |
16 bytes | AES IV | |
0x0001 + "DRBG Seed" | 16 bytes | HMAC Key |
16 bytes | - |
So, ultimately we end up with two sets of keys:
"Tag" Key | Usage |
---|---|
AES Key | Not used? |
AES IV | Not used? |
HMAC Key | Sign tag data with HMAC-256 |
"Data" Key | Usage |
---|---|
AES Key | Encrypt/Decrypt Main Amiibo Data with AES-128-CTR |
AES IV | |
HMAC Key | Sign Amiibo data + tag data with HMAC-256 |
» See this process in code (Swift)
With everything figured out, socram8888 subsequently released amiitool, a program to encrypt/decrypt/copy amiibo data
Amiibo Byte Layout Overview
Page | Byte Offset in Page | |||
---|---|---|---|---|
0 | 1 | 2 | 3 | |
... | ... | |||
4 | Tag Settings Write Counter, Init Date, Tag Nickname? |
|||
5 | ||||
... | ||||
11 | ||||
12 | ||||
13 | Tag HMAC Hash UID + Amiibo Model Info + Keygen Salt |
|||
14 | ||||
... | ||||
19 | ||||
20 | ||||
21 | Amiibo Model Info Amiibo series, game series, character, variation |
|||
22 | ||||
23 | ||||
24 | Keygen Salt Hardcoded from factory |
|||
25 | ||||
... | ||||
30 | ||||
31 | ||||
32 | Data HMAC Hash Tag Settings + Decrypted Amiibo Data + Tag HMAC Hash + UID + Keygen Salt |
|||
33 | ||||
... | ||||
38 | ||||
39 | ||||
40 | Encrypted Amiibo Data Character customizations, level-ups, etc 360 Bytes |
|||
41 | ||||
42 | ||||
43 | ||||
... | ||||
126 | ||||
127 | ||||
128 | ||||
129 | ||||
... | ... |
NTAG215 Password Reverse Engineering
Around 2015, it was discovered that the 32-bit password used for locking down write access is derived from the 7-byte tag UID using the following algorithm:
password[0] = 0xAA ^ (uid[1] ^ uid[3]) password[1] = 0x55 ^ (uid[2] ^ uid[4]) password[2] = 0xAA ^ (uid[3] ^ uid[5]) password[3] = 0x55 ^ (uid[4] ^ uid[6])
Reading Data from iPhone
Step-by-Step Overview
- Create an NFCTagReaderSession and connect to the tag as an NFCMiFareTag
- Use `sendMiFareCommand()` to send READ or FAST_READ command to tag and read all 130 pages of data.
- To determine amiibo model type, use data from page #21 and #22. Page #21 (bytes[84..<88]) is the "head" and page #22 (bytes[88..<92]) is the "tail" - you can use these values at amiiboapi.com.
- To read encrpyted data (pages #40 to #130), you need the private Nintendo "Data Key" (aka "unfixed-info" key).
Cloning an Amiibo to blank NTAG215 with iPhone
If you have the "master" keys, you can easily clone an amiibo to a blank tag like so:
Step-by-Step Overview
- Read all data from source amiibo
- Read UID from blank target tag
- Decrypt source "Amiibo Data" (pages #40 to #130)
- Re-compute the HMAC hashes with new keys derived from decrypted data and target UID
- Re-encrypt the "Ammibo Data" with new key derived from target UID
- Re-construct patched data using the new HMAC hashes and newly re-encrypted "Amiibo Data"
- Write pages #3 to #130 of the patched data to blank target tag using miFare WRITE command
- Write to page #134 to configure authentication
- Generate password from target UID and write to page #133
- Write to page #2 to enable the "Lock Bytes"
- Write to page #130 to enable the "Dynamic Lock Bytes"
- Write to pages #131 and #132 for CFG
Code Example for Cloning (Swift)
Nintendo 3DS Read Procedure
- GET_VERSION
- READ (startpage=3 ??)
- PWD_AUTH (Key is based on UID)
- FAST_READ (pages #0 through #59)
- FAST_READ (pages #60 through #119)
- FAST_READ (pages #120 through #134)
Nintendo 3DS Write Procedure
- GET_VERSION
- READ (startpage=3 ??)
- PWD_AUTH (Key is based on UID)
- WRITE (for each page from #0 through #12) (Note: The first byte for page[4] is zero here)
- WRITE (for each page from #20 through #129)
- FAST_READ (pages #0 through #59)
- FAST_READ (pages #60 through #119)
- FAST_READ (pages #120 through #134)
- WRITE page #4 (same data as before except first byte is 0xA5 this time.)
- FAST_READ page #4