Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NFC #49

Open
bettse opened this issue Feb 20, 2018 · 21 comments
Open

NFC #49

bettse opened this issue Feb 20, 2018 · 21 comments

Comments

@bettse
Copy link

bettse commented Feb 20, 2018

I'm interested in how the joycon does NFC. I've written my own code[1] to do the basics (set player LED, vibrate, change input remote mode), but I've been struggling to get NFC data. When setting the input report mode to 0x31, it still get all 0’s for the data after the standard HID data. There is a note on the docs about this, "31 input report has all zeroes for IR/NFC data if a 11 ouput report with subcmd 03 00 or 03 01 or 03 02 was not sent before.”, but I’ve tried variations of a 0x11 command with a 0x03 subcommand and still seen any progress (both trying it before changing the input mode, and after). It is also unclear from the notes of the 0x11 command has the same format as the 0x01 command, so its possible I’m putting the subcommand byte in the wrong location.

Do I have the format of the 0x11 command wrong, or does anyone happen to know a minimal sequence of commands to get NFC data to start flowing? I've worked with NFC before[2], so I'm confident that I can work with the data once it starts flowing.

[1] https://github.com/bettse/expecimal (https://gitlab.com/bettse/expecimal)
[2] https://github.com/bettse/FS13_nfc_tag_reader/blob/master/device.nut#L226-L253

@CTCaer
Copy link
Contributor

CTCaer commented Feb 20, 2018

Hey,
The x11 is not exactly the same as x01. It has the timming byte, the subcmd and arg (and a crc byte in the end of the packet? I don't remember).
It only works with specific subcmd.

The problem here is that IR and NFC are a bit unexplored waters.
You need to speak to MCU first and configure it before starting asking packets.
It works like IR configuration. You have to send some specific cmd x01 subcmd x21 packets first and then can get data from IR or NFC.

Now that we have better homebrew, experimenting with IR and NFC natively will be a thing.
And then, by using a BT mitm or UART mitm we can start exploring/decoding the official configuration packets.

But for now, that's most of the info we have.
Check #47 for more insight

@bettse
Copy link
Author

bettse commented Mar 2, 2018

In the process of trying to reproduce what the joycon normally receives when using NFC, I've been working through some of the commands sent. I found something odd: the acknowledgement packet for the 0x04 and 0x21 subcommands doesn't use the byte 12 (byte 12 based on this table} of subcommand + 0x80, but is one less (0xa0 to ack 0x21, 0x83 to ack 0x04)?

@CTCaer
Copy link
Contributor

CTCaer commented Mar 3, 2018

Well I should had clarified that..
Here how it works:
The switch does not except that the next packet it will receive is the correct.
It just parses every packet.
So to identify what is what, checks the received packets for the input report id and then parses them accordingly.

So lets say switch sent a x01 output report with a cmd.
So it when it receives a x21 input report, it does not say: "ah, that's for the command I sent before."
For x21 input report it checks the ACK byte as follows:

// As you understood:
// with input report id byte *excluded*, the ack byte is byte12
// with input report id byte *included*, the ack byte is byte13

int parse_iput_report_x21_subcmd( &byte[1] ){ //To trim the input report byte
	if (byte[12] >> 7){
		// byte[12] is an ACK
		// check if it has DATA after the subcmd byte
		// byte[12] & 7f value says what data it has. Not from what subcmd comes from!
		switch (byte[12] & 7f){
			// All cases also check byte[13] to know which subcmd aplies to.
			//This is because multiple subcmds can have the same TYPE of data

			// Default reply that aknowledges that a subcmd was received and
			// has NO DATA in its reply, except if it failed or not	
			case 0x00:
				simpleACK_check_which_subcmd_applies_to();
				// This also checks the byte[14] to see if the subcmd failed. 0x00 success or 0x01 failed
				// E.g. subcmd x11: if you write to a locked SPI area it has this set to 0x01, which means it failed to write there.
				break;

			case 0x1:
				manual_bt_pairing();
				break;
			case 0x2:
				parse_controller_info();
				break;
			case 0x3:
				parse_trigger_buttons_press_time();
				break;
			case 0x5:
				parse_page_info();
				break;
			case 0x10:
				check_which_spi_address_and_size_and_then_parse_data();
				// Switch knows what data it has there by matching the address and size returned.
				// Not by the order of received packets that we are used to do for simplicity.
				// This is also happening to other types of data received (e.g. IMU data), but I wont write it here.
				break;
			case 0x20:
				parse_mcu_configuration_data();
				break;
			case 0x28:
				parse_unknown_mcu_data();
				break;
			case 0x29:
				parse_unknown_mcu_data_2();
				break;
			case 0x30:
				parse_which_player_leds_are_on();
				break;
			case 0x40:
				parse_imu_data();
				break;
			case 0x50:
				parse_batt_voltage_data();
				break;
			case 0x51:
				parse_unknown_data();
				break;
			default:
				return 1;
		}
		return 0;
	}
	else{
		// byte[12] is 0x00, a NACK
		// nothing to parse. Subcmd output report had wrong arguments
		check_byte13_to_which_subcmd_failed();
		return 1;
	}
}

So as you understand from the above, because most of the times, the AC_ has_data portion of byte[12] is the same with the subcmd, we misunderstood it at first. But this portion says what type of data the reply has

@CTCaer
Copy link
Contributor

CTCaer commented Mar 3, 2018

Created a PR to explain the ACK byte.

@bettse
Copy link
Author

bettse commented Mar 4, 2018

That is awesome, thanks!

@bettse
Copy link
Author

bettse commented Mar 9, 2018

I've made progress with NFC. I have swift code in the aforementioned expecimal project, but the series of commands is something like

  • set the input mode to 0x31
  • start sending subcommand 1 to report 0x11
  • watch for the 0x31 input to have 01 00 00 00 04 00 12 01 at the start of the nfc data section (about byte 49 or 50, depending on how you count)
  • send the MCU config subcommand with parameters 21 00 04
    • Note that the MCU config subcommand is 0x21, so it'll look like 21 21 00 04
    • The MCU config subcommands have a crc (crc-8-ccitt / polynomial 0x07) as the last byte, it covers all but the first byte of the params. So in this case it would be 00 04 00 .. (crap ton of 00's). The value for this command would be 0xa2
  • continue sending subcommand 1 to report 0x11
  • watch for the input to have 01 00 00 00 04 00 12 04 (note the final 0x04) at the start of the nfc data
  • start sending subcommand 0x02 to report 0x11 with parameters: 04 00 00 08 and a final crc8 that covers the parameters (including all the 0's afterwards). In this case the value should be 0x87.
  • watch for the input to have 2a 00 05 00 00 09 31 00 at the start of the nfc data
  • start sending subcommand 0x02 to report 0x11 with parameters 01 00 00 08 05 00 00 00 2c 01 (crc is 0x9a for this one)
  • watch for the input to have 2a 00 05 00 00 09 31 01 (note the 0x01 at the end) at the start of the nfc data
  • Scan your NFC token! you'll see the input contain its UID. there are some other bytes that change as well, but I'm not sure what they mean (I don't see the SAK, for example).
  • Interestingly, the UID remains in the output even after you remove the token from the reader, and scanning another token doesn't change it.

Next up: token auth, reading, and writing.

@bettse
Copy link
Author

bettse commented Mar 10, 2018

Probably worth also noting that the amiibo use 7 byte UIDs, and the UID in the input data has a 0x07 prefix to indicate that, and MIFARE classic tokens with 4 byte UIDs are also supported (prefixed 0x04). This is not surprising since Skylanders Imaginators for Nintendo Switch uses the joycon to read the figures, and these figures are effectively MIFARE classic 1k tokens (their SAK is non-standard, so most readers won't read them). This also means that both NTAG PWD (4 bytes) based authentication as well as MIFARE classic keyA (6 bytes) must be supported within these commands somehow.

@CTCaer
Copy link
Contributor

CTCaer commented Mar 10, 2018

Great job! we now know way more. I'll comment your bullets with the info I learned from poking in IR config:

  1. Same as IR
  2. This gets the MCU state. But you normally send it after you send subcmd x22 01 to resume MCU.
  3. With 2 in mind, it reports FF 00 00 00 00 00 00 00. This means not ready. Then switches to 01 00 00 00 04 00 12 06 which means changing state. And finally changes to 01 00 00 00 04 00 12 01 which means it's ready to receive MCU config.
  4. This sets the MCU mode. So 21 21 00 04 is for NFC and 21 21 00 05 for IR. Hmm, what about 0, 1, 2, 3? Nice find about crc-8-ccitt. It took me a lot to understand it. Didn't know it was common knowledge :/
  5. same
  6. In IR you get a x21 input report and a x31 report that have 01 00 00 00 04 00 12 01. I means not ready or changing mode I think. Then changes to 01 00 00 00 04 00 12 05, mode set to IR (5)
  7. Now here things change a little bit. 1st of all x11 cmd x02 subcmd gets the MCU NFC mode state. x11cmd x03 subcmd is for MCU IR mode.
    It's when you write configuration. For example, exposure, leds, gain, etc for IR sensor. And also to get data from it.
  • Here for IR you send a MCU write subcmd with sth like 2301070f00030009. The x21 changed to x23 at start of data. I assume, x21 is for changing MCU mode and x23 is to change mode configuration.
  • After you get a x21 subcmd reply that has x0b in args, then you start sending x11cmd with x03 subcmd and x02 arg, to get state of configuration. For IR 13000700030009 is ready to receive.
  1. You send IR config for sensor now with x01cmd and x21 subcmd and arg cmd x23.
  2. Wait to get 13000700030009 from x21 input report this time and 230000000000 from x31 report.
  3. You send the next IR config and wait for the same things. But this time because it's the final config, you send x11cmd x03subcmd and x00 for args to get the final OK.
  4. Continue sending x11cmd x03subcmd and x00 for args, which I assume is the get data from selected MCU mode. Now the IR camera data is starting flowing.

The header for IR data is simple. And it's similar with NFC in a certain point.
10 bytes: 03 00 07 XX YY YY YY YY ZZ ZZ
03: is probably like the ack byte. 3 has IR data or IR data for image transfer.
07: is probably the image transfer id.
XX: This is the packet fragment number
YY YY YY YY: id of the packet. That's how you know what fragmented packets to merge
ZZ ZZ: always x0000?

Now in IR, you request the packets specifically. You want the first 1st? you just send x11 id x3 subcmd.
You get the first 1. You continue sending the x11 id x3 subcmd, because it also serves as packet received.
So now the controller sends you the 2nd packet. XX is 1. Now if you send x11 id x3 like this you will never receive the 3rd packet from the data fragment.

x11 output report, subcmd x03:
Argument: 00 00 00 XX.
XX: fragment id ACK.

So, you need to send 00 00 00 01, for the controller to know that you received the 2nd fragment with id x01. And now it will send fragment packet id x02.

When the controller stards sending the same packet again again you send the simple x11cmd x03 subcmd to start a new series of fragments request.

@CTCaer
Copy link
Contributor

CTCaer commented Mar 12, 2018

Some info on the mcu registers:
x21 arg:
2304 09002e 640130 900131 240132 000010 00012e 80012f 00000e 030143 c8 00000000000000c5
From the above we can see the following:
register is uint16_t (LE probably) and takes a uint8_t arg.
E.g. 0x3001 is resolution and 0x64 is 80x60

Another theory is that the 0x01 at the register is the size of the register.

These probably correlate to NFC registers write also.
As you can understand, MCU here refers to IR Sensor MCU or the NFC MCU.
Fun fact: they can both be firmware updated.


EDIT:
More info discovered:
0x2304 is to write registers. x09: no of registers. Then it's uint16_t address and uint8_t value.
Maximum 9 registers as seen from all packets examined.
So the correct delimiting is like this:
2304 09 002e64 013090 013124 013200 001000 012e80 012f00 000e03 0143c8 00000000000000 c5

@CTCaer
Copy link
Contributor

CTCaer commented Mar 20, 2018

@bettse
So I played a little with your command stream.
First, I saw that for params: 04 00 00 08 and 01 00 00 08 05 00 00 00 2c 01, removing 0x8 and 0x2c had the same effect. It was still working. Seems that the x05 is the length of the 0000002c01 command.

Additionally, I didn't saw anything else changing. Maybe because I tried an empty tag?
The only I had were 01 01 04 00, the data length and the data (here the uid lentgh and uid).
0x04 is status and the other 2 0x01, I don't know.
I tried playing with the commands a little but the only thing I've managed was to get a ...x31 x07 empty report.
So no additional progress from my side.

Did you figure out anything else?

@bettse
Copy link
Author

bettse commented Mar 20, 2018

I got distracted by another project, so I haven't done anything new with this, but interesting finds.

@bettse
Copy link
Author

bettse commented Mar 24, 2018

I played with it a bit more this evening and found that the command that starts 02 06 00 00 08 ... requests the token's data, which comes back in a message starting 0x3a (instead of 0x2a). The response contained roughly half the token data, and something about the state machine of my test program resulted in it getting a second 0x3a that contained the rest of the data. I can't say for certain yet what command requested the second half.

I think the 02 06 00 00 08 command contains the PWD for the token (PWD is the abbreviation used in the ntag documentation, unsurprisingly it means 'password'. 4 bytes).

In my case, the token(amiibo) has UID 04d4b142544980, so the command to the controller was
02 06 00 00 08 13 d0 07 00 00 00 00 00 00 00 01 03 00 3b 3c 77 78 86 00 00 .... I think based on what you found before, that the 0x13 after the 0x08 represents the length. I'm still trying to work out what the 3b 3c 77 ... represents, since the PWD for that UID should be 3c b0 a1 81

In the response to this (the 0x3a that contains the token data), it does repeat the same 03 00 3b 3c 77 78 86 00 00 just before the start of the token data. Its also got some other interesting stuff before that, but I'm hesitant to post it just yet since I truncate some of the printouts (because they can get very long) and I wouldn't want to put up bad data.

@bettse
Copy link
Author

bettse commented Mar 24, 2018

I tried with a second amiibo and got its data back, and then remembered that the amiibo PWD, as I recall, is only necessary for /writing/, no auth is required for reading.

@bettse
Copy link
Author

bettse commented Mar 24, 2018

I played with skylanders imaginators a bit in case it might provide another perspective. the skylanders tokens use a 4 byte uid. the game sent 4 commands that provide the controller with the "Key A"s (like the PWD, but for Mifare Classic) for some of the sectors. the ordering was a little weird to me.

02 0f 0100001f d00736 9b7eb5b2 60 4b0b20107ccb 0060 4b0b20107ccb 0160 fe8ad3c7d698 07
02 0f 0200001f 60 4b0b20107ccb 0260 4b0b20107ccb 0360 fe8ad3c7d698 0460 b9d2c086cef1
02 0f 0300001f 2260 f50868216076 3e60 fe8ad3c7d698 0660 d8e70794015b 0860 070b459a44-
02 0f 04000812 3d 1160 2ae42a2f2510 2460 9fbf14d51932 2d00000000000000000000000000

I added the spacing to make a few pieces clear. the hypen is because the last byte (3d) appears in the next message.

so the command is 02 0f, and clearly the next byte is a counter to order the data. I think the 1f is the length of the data (note: I removed the checksum byte from these). Perhaps the controller looks for data until one that is less than 0x1f arrives? the UID of the token is 9b7eb5b2

0x60 is the command for mifare authentication with the "A" key [1], and 4b0b20107ccb is the Key A for sector 0 of the token. A little background on Mifare classic 1K memory: its 1024 bytes broken into 16 sectors, each with 4 blocks of 16 bytes. the last block of the sector (ex block 3, block 7, etc) is the 'trailer' and contains access configuration as well as the keys (A and B) for that sector (but generally they cannot be read out).

So my theory is that the data is [0x60] [Key] [block #]. For example, sector 1's key a is fe8ad3c7d698, and its followed in the data by 0x07/0x04/0x06, which are all blocks in that sector.

The ordering is mixed up, going for blocks 0, 1, 7, 2, 3, etc, but I think that's based on what initial data the game wants out of the token (for example, to determine what generation of token it is since skylanders has published something like 6 editions of the game).

Dunno what d00736 means.

[1] https://github.com/adafruit/Adafruit-PN532/blob/master/Adafruit_PN532.h#L100

@CTCaer
Copy link
Contributor

CTCaer commented Mar 24, 2018

Great findings.
I'm trying to gulp down your info for now.
Here are some bits from Switch service xcd:sys:

  • CMD x02 XX (bold are the ones you saw):
    x01: Start polling
    x02: Stop polling
    x06: Ntag read
    x08: Ntag write
    x09: Send raw data
    x0f: Mifare read/write (write depends on a subcmd byte flipped to x01)
    x11: Register/Clear mifare key (depends on subcmd, don't know yet which one)

Also about the reply (here's an x2a example, I don't know if it is the same with 3a):
2a 00 05 0000 09 31 09 000000 01 01 02 00 07 04c8117a442f84
x2a: MCU input report id
x00: Error type? This shows up when x31 XX becomes x31 07.
x05: MCU Mode - NFC
x000: Unknown
x09: Size of header?
--NFC header--
x31: Always the same. Maybe it shows the type of reply?
x09: State of MCU. x01 when you start discovery, x07 is error, x09 after it found a tag. I'll try to find where these are.
x0000: dunno..
x01 x01: dunno..
x02: Type of tag. For now I know x02 for ntag, x04 for mifare
x00: dunno..
x07: Size of data
--NFC data--
..

More about cmds:
02 01 00 00 0805 0100002c01
02 0f 04 00 0812 3d 1160 2ae42a2f2510 2460 9fbf14d51932 2d00000000000000000000000000:
x01/x0f: Polling/mifare read
x00/x04: count of packet. If we send multiple commands.
x00: Unkown (it's not for write/read in mifare)
x00/x08: x00 if the mcu should expect more command packets or x08 if this is the end packet. That's what the MCU looks for (not the less than x1f bytes).
x05/x12: Correct, it's the length of command data. Max 31 bytes it seems.
--nfc cmd data--

Also about your findings for mifare:
I checked some online docs and presentantions and it says that the trailer has the conditions as you said.
These say which key will be used for each operation read/write.
Gerlvaos has a write up and a tool to calculate the Dkeys and Mifare password.
http://gelvaos.blogspot.gr/2010/12/how-to-access-to-mifare-memory.html
http://gelvaos.blogspot.gr/2011/01/how-to-calculate-mifare-password.html
https://github.com/gelvaos/MifarePass
See if anything matches your replies/cmds

About the d00736:
So it sends d00736 UID 60 KEYA:
xd0 maybe is for the UID. But shouldn't x07 be a x04 to make sense?
My question here is why it sends the key without any block before x60?
I'll check deeper inside the xcd service.

@CTCaer
Copy link
Contributor

CTCaer commented Mar 24, 2018

So d0 07 36:
(36 & 7c) / 4 = 13 [cmd count] 12 xYY60 cmds here + 1
I don't know if the 1 cmd left is the raw key x60 cmd at start
(36 & 2) / 2 = 1 [use raw key]. Sof if this is 0, the x60 4b0b20107ccb does not get sent.
(36 & 1) = 0 [mifare read]. If 1: mifare write

I'm still trying to find the xd007. I'll update this comment if I have more info
EDIT1: left cmd is probably the raw key at start: x60 4b0b20107ccb

@CTCaer
Copy link
Contributor

CTCaer commented Apr 25, 2018

@bettse
When the switch sends the 02 0f 0100001f d00736 ... commands,
how the controller replies?
Again with a x2a mcu report id?

Can you sent some samples? (remove uid with UIDU if you want).

@bettse
Copy link
Author

bettse commented Apr 26, 2018

I dumped a scan of an amiibo before I realized it was the wrong one to answer your question: https://gist.github.com/bettse/dbbe62ec853a2a5111a61a4869d17753

I haven't messed with this stuff for a few weeks, but I don't think I ever got to the point where my application would make the mifare classic read requests to the controller.

@CTCaer
Copy link
Contributor

CTCaer commented Apr 26, 2018

@bettse
Well actually it was exactly what I really needed.
This helps a lot! thanks

(it also includes an answer to my question, but for ntags.)

@CTCaer
Copy link
Contributor

CTCaer commented Apr 26, 2018

@bettse
So your log was very helpful. I parsed it a little bit here:
https://gist.github.com/CTCaer/69ce224521d1ee4b153b250d9cbbb6a9

Many bytes are already known.

So the communication was probably interrupted.

If you ever find some time, please send me a full log of:

  • Ntag (amiibo)
  • Mifare (skylanders)

Thank you a lot!

@YouTubePlays
Copy link

Hello People,

I am piggy bagging on to this discussion I was checking the NFC communication and
got x3A message also in x2a message from procontroller there is a section starting after uid byte 72 do you have any idea what this section is?
here is my log for x3a

Thanks for the ideas / help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants