New interoperability for Activision Skylanders NFC toys
Demonstration: writing on a Mac, reading on a Raspberry Pi
This demo shows new interoperability of Activision Skylanders NFC toys. Previously, only Activision hardware and games had the ability to write data to Skylanders NFC toys.
Any NFC reader can read the ATQA, SAK and UID of an NFC toy. These let you tell it's a Skylander, and its unique ID.
By knowing the algorithm used to set the read/write passwords (keys A), we can interoperably read/write our own data to a Skylanders NFC toy.
This video first shows a program which computes the sixteen (16) keys A and uses them to write new, custom text to a Skylanders NFC toy. The program is running on a standard Apple laptop, using a commercial, off-the-shelf, USB NFC reader (the Identiv SCL3711).
Then, a standard Raspberry Pi computer is shown, using a commercial, off-the-shelf, NFC add-on (the ITEAD PN532 NFC module). A program running on the Raspberry Pi computes the same sixteen (16) keys A, and uses them to read the custom text from the toy.
The video has artificial delays inserted so the on-screen explanations can be read; computing the keys A and reading and writing to the NFC toy are nearly instantaneous otherwise.
Read Writing your own data to an Activision Skylanders NFC toy to see a step-by-step workflow similar to the demo video, using standard software available on any Mac or Linux computer.
Computing the keys A
Since 2014, researchers have developed at least a couple of ways to generate the keys A for Activision Skylanders toys. The simplest version is a standard 64-bit CRC, reduced to operate on only 48 bits.
A clean room description of the algorithm is as follows:
The key A for sector 0 is always the 6-byte (12-character) hexadecimal representation of the integer computed by the multiplication of the three prime numbers 73 and 2017 and 560,381,651
For all other sectors, let a big-endian, most-significant-bit first, 48-bit CRC computation use the ECMA-182 polynomial of
0x42f0e1eba9ea3693
, and not be reflected or reversed or have a final register XOR value; this is equivalent to a CRC64-ECMA-182 with left shift, MSB check and remainder trim reduced from 64 to 48 bitsLet the initial value of the CRC48 register be the value of the integer computed by the multiplication of the five prime numbers 2 and 2 and 3 and 1103 and 12,868,356,821
Compute the CRC48 of the 5 bytes encoded by the 10-character hexadecimal concatenation of the UID and the sector number in hexadecimal
The key A for that sector is 6 bytes, represented in hexadecimal as 12 characters: the result of the CRC48 with the hexadecimal bytes' order reversed
UID | Sector | Key A |
---|---|---|
ff81bab9 |
1 | 83018b0e7d13 |
c47260f8 |
3 | ab04476c4c95 |
96506199 |
15 | f8905a892508 |
BF2EE007 |
6 | 8d30722433ca |
An example of this implemented in Python 2 is as follows:
#!/usr/bin/python
## tnp3xxx.py - Compute a key A
##
## Written in 2016 and 2017 and 2018 by Vitorio Miliano
##
## To the extent possible under law, the author has dedicated all
## copyright and related and neighboring rights to this software to
## the public domain worldwide. This software is distributed without
## any warranty.
##
## You should have received a copy of the CC0 Public Domain
## Dedication along with this software. If not, see
## <http://creativecommons.org/publicdomain/zero/1.0/>.
import binascii, re, struct, sys
uidre = re.compile('^[0-9a-f]{8}$', re.IGNORECASE)
magic_nums = [2, 3, 73, 1103, 2017, 560381651, 12868356821]
# Standard MSB CRC pseudocode e.g. https://en.wikipedia.org/w/index.php?title=Computation_of_cyclic_redundancy_checks&oldid=771577830#Bit_ordering_.28endianness.29
# CRC64 ECMA-182 e.g. http://stackoverflow.com/a/29241216
def pseudo_crc48(crc, data):
POLY = 0x42f0e1eba9ea3693
MSB = 0x800000000000
TRIM = 0xffffffffffff
for x in data:
crc = crc ^ (x << 40)
for k in range(0, 8):
if crc & MSB:
crc = (crc << 1) ^ POLY
else:
crc = crc << 1
crc = crc & TRIM
return crc
def calc_keya(uid, sector):
if sector == 0:
return format(magic_nums[2] * magic_nums[4] * magic_nums[5], '012x')
if uidre.match(uid) is None:
raise ValueError('invalid UID (four hex bytes)')
if sector < 0 or sector > 15:
raise ValueError('invalid sector (0-15)')
PRE = magic_nums[0] * magic_nums[0] * magic_nums[1] * magic_nums[3] * magic_nums[6]
ints = [ord(a) for a in uid.decode('hex')] + [sector]
key = pseudo_crc48(PRE, ints)
return binascii.hexlify(struct.pack('<Q', key))[0:12]
if __name__ == '__main__':
if len(sys.argv) > 1:
keysa = []
for sector in range(0, 16):
keysa.append(calc_keya(sys.argv[1], sector))
if len(sys.argv) > 2 and sys.argv[2] == '-eml':
print ('0'*20+'\n'+('0'*32+'\n')*3).join(keysa).join([(sys.argv[1]+'0'*24+'\n')+(('0'*32+'\n')*2), '0'*20])
else:
print '\n'.join(keysa)
Use at your own risk
This has only been tested with figures from previous Skylanders games: Spyro's Adventure, Giants, Swap Force, Trap Team, and SuperChargers.
Writing custom data to an Activision Skylanders NFC toy will result in the game (Spyro's Adventure, Giants, Swap Force, Trap Team, or SuperChargers) not recognizing the figure. Completely erasing the NFC toy will allow the game to recognize it again (as a new toy).
This has not been tested with Imaginators figures or the Imaginators game. Other researchers have found additional security data stored on Imaginators figures, matching the recommendations in Kevin Valk's masters thesis, Comprehensive security analyses of a toys-to-life game and possible countermeasures. Erasing or overwriting this data will render an Imaginators toy unable to be used with the Imaginators game in the future.