Nike+iPod reverse engineering (protocol too)

UPDATE: code posted below

Nike+iPod is a very interesting piece of hardware for all kinds of reasons, not the least of which is that it as actually useful. It works by wirelessly transmitting data from a sensor (that is stored in your shoe) to a receiver that is either externally connected to your iPod or to the receiver that is integrated into the bluetooth chip in the iPhone (3GS and 4 only). Some work has been done by others to try and figure out what data is sent by the sensor. This previous work can be seen here: 1, 2, and 3. As you can see, none of them really got far. They all failed to decode packet payload (which happens to be encrypted), they all failed to receive said data without using the stock receiver, and they all fail to understand the data. They only got as far as figuring out that there are 4 bits in there that are unique per sensor. Needless to say that this left me quite unsatisfied. I took a few days to figure out how it all works, and I am happy to say that I've decoded the entire packet payload successfully. Curiously those 4 bytes that everyone used for identifying the sensor uniquely are in fact NOT unique. If a tag's serial number is "4A123456VSX", then from those 4 bytes you can only define SOME of the digits of this serial number, not all. In fact for that particular tag, with just those 4 bytes you'd only get "_A123456___".

Hardware of the Nike+iPod sensor is quite interesting. I knew it used a nRF2402[Product page] to transmit the data. It's a 2.4 GHz transmitter using GFSK modulation supporting 250Kbps or 1Mbps operation. It features a FIFO, and automatic packet assembly. That includes appending a "TO" address to the packet, sending a preamble byte, sending packet data, and sending a CRC as neeed. It is quite configurable. Channel is set in 1MHz increments, CRC choices are 0,8, or 16 bits. "TO" address can be anywhere from 0 to 5 bytes in 1 byte increments. This is a lot of options, and I had no time to guess what they chose. I opened to foot sensor and sniffed the configuration bytes sent to the nRF chip using a logic analizer. nRF2402 takes 2 configuration bytes on startup. Those bytes were: 0xE7 0x99. This tells us quite a lot. It tells us that the channel used is channel number 25, transmit power is set to maximum (1mW), data rate is 250 kbps, and 16-bit CRC is used. It also tells us some non-surprising things: ShockBurst is used, preamble is used. I also sniffed a lot of data frames here, and noticed that they all begin with the byte 0x0D. This may seem irrelevant now, but that will pass quickly. The packets are also 28 bytes long. Add in the 2 bytes of address and 2 bytes of CRC for the total RF payload of 32 bytes. One extra byte is sent for preamble. The TO address used in each message is "0xC2 0xBD".

Recieving the data without the Nike+ receiver is difficult, which is why all other projects used said receiver. I had no desire to buy this receiver, and I am stubburn, so I looked for other ways. Nordic Semiconductor makes many other chips, and I happened to have one (nRF24L01+[Product Page]) around, on a breakout board from Sparkfun. This chip uses the same band, same modulation, same packet assembler/disassembler, and is by the same manufacturer - by all rules of logic it should be as good a receiver as anything. We hit the first snag as we read the datasheet and see that we need to use at least 3 address bytes to receive data. Well, this dashes our hopes, doesn't it? Nah. If you read carefully through all Nordic datasheets, you'll see that the data length is never sent for these chips while using ShockBurst - both sides simply know it. Furthermore, the CRC is calculated over ADDR + DATA together, so realistically 2 bytes of address + 28 bytes of data is the same as 3 bytes of address + 27 bytes of data. This is where knowing that each packet begins with 0x0D helps. We tell our nRF24L01+ to receive on channel 25, expect 250 kbps, look for data length 27, 16-bit crc, and TO field of "0xC2 0xBD 0x0D". Let's turn it on and see what happens.... It works. We start getting packets: one a second. AWESOME! The sensor sends one packet every second as long as you walk or run, and for 10 seconds after you stop walking or running.

Data dumping is the next step for data analysis. I used a PIC16F688 I had lying around to drive the nRF chip and a Saleae Logic device to capture the data that I had the PIC pump out a bit-bannged SPI bus. Here's some data I've dumped. These are all, of course, missing the leading 0x0D byte since it's used as address by the packet handler in my nRF24L01+. So where do we go from here? First off we can, as everyone else had, notice that bytes 0,1,2,3,4,5 are the same for all packets. In fact for all sensors first two bytes are "0x0D 0x01". this means that bytes 2,3,4,5 are the four "uniquie bytes" that everyone figured were the device serial number. Byte 6 seems to almost always be 0xAx where x keeps incrementing. The rest of the packet looks like random garbage.

Packet 1:
 ->packet is from device '4H12797KVSX'
 ->payload: 06 06 D0 01 C6 00 00 19 00 00 D8 00 00 5F 00 00 A7 EC 02 0F 56
 ->on hours: 6
 ->Tc: 464
 ->walking steps: 198
 ->running steps: 216
 -> lifetime walking miles: 25
 -> lifetime running miles: 95

After some hard work with an ARM disassembler (and copies of iPhone and iPodNano OS images) to figure out how the packets are to be decoded, we can now process each frame to get something like what you see on the right. Here's the rest of the data file of processed results from the above-mentioned dump file. There is a lot of intersting things to be learned from the disassembly, but since Apple owns that assembly code, I cannot post it (which is not to say I will not post my own code to descramble the packets soon). I can, however, say that the protocol is pretty well designed, allowing different packet lengths, diferent address lengths, etc. The "Nike+iPod" remote product seems to use the same protocol. I plan to try and make a device that acts as it next. A few other cool tidbits from the disassembly:

  • If any Nike+ sensor reports that it's been on for more than 1000 hours, Apple code says its battery is "dead" even if it really isn't
  • The sensor counts steps and discriminates walking from running by itself, so it does a fair bit of data processing internally (this was a surprise for me)
  • The sensor keeps a fair bit of data stored internally
  • Nike+ sensor itself does not keep time, except to wait a second between trasmissions. iPhone and iPodNano both use their own local time at time of packet RX to keep track of steps/second.

sample payload and how the bytes are used:
offset:	00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14
data:	06 08 5A E2 2E 01 00 26 00 00 4A 01 00 8D 00 00 A7 EC 02 4B 64
use:	?C B  K  JK D  D  D  G  G  G  E  E  E  H  H  H  A  A  AB !! !!
	? - [partially] unknown
	A - serial number component
	B - on hours
	C - packet type
	D - walking step count
	E - running step count
	G - lifetime walking miles
	H - lifetime running miles
	J - some flags (4 known to be used, one not used anywhere)
	K - "Tc"
	! - unused apparently

The packet payload is used as follows (box on left). I did my best to figure out what each byte is used for. I am not quite sure what some of the flags are, and I saw no references to the last few bytes of the payload. Perhaps during development they decided they didn't need them. I'll try and see what they mean later on. The "miles run" and "miles walked" values are adjusted by Nike software in iPhone to be real values. There are two ways to do it: calibrated and uncalibrated. Calibrated is more precise, but Apple claims uncalibrated works for most people. Since it's been shown that numbers cannot be copyrighted, I will reveal that to convert between sensor's reported "miles walked" to real miles walked you need to multiply sensor's data by 64, and then divide by 15319.1484510898590087890625. For "miles run" the divider is 18947.3681151866912841796875.

Update #1: I finished making a receiver and am quite surprised by just how accurate the "uncalibrated" data is. I think this is a nice cheap alternative to those who want to use the product but lack an iPodNano/iPhone. This receiver costs $8 to make, and all you need besides it is the foot sensor, which is cheap. Top line shows: Tc, steps taken walking/running. Bottom lime is lifetime miles walked/run.

Further work includes all kinds of cool things legitimate as well as not. As you can see the sensor broadcasts all kinds of potentially identifiable and useful (read: creepy) data about you and every step you take (literally). Some potential uses (bold items are ones I plan to undertake):

  • Creating your own sensors and feeding data to Nike+iPod
  • Creating a remote-control like Nike+iPod watch
  • Modifying the sensor to send other data (the piezo speaker can be a microphone)
  • And some crazy stalkerish things like:
    • Sniffing this data in gyms to see who is exercizing and who isn't, and how much they generally do (given the "lifetime" values)
    • Following someone in a crowd (using a few directional antennas)
    • Jamming the devices/faking data to mess with people
    • Targeted advertisements in the gym, eg: fast runners need new shoes, slow runners need a personal trainer.
  • Anything else you can think of.

As you can see in the posted data dumps - it all works well. Feedback/questions/comments/grievances/complaints/suggestions/etc... are always welcome in [EMAIL] form. Code for the decode used for this can be seen [here].

© 2012-2023