kormax / apple-enhanced-contactless-polling

Reverse-engineering Apple Enhanced Contactless Polling
134 stars 12 forks source link

Implementing ECP with PN532 #1

Closed Nauman3S closed 10 months ago

Nauman3S commented 10 months ago

The investigation on reverse engineering of apple enhanced contactless polling that you put together in this repo is very intresting.

I am trying to implement ECP using PN532. I already had a look at CHIPS section and could understand most of it. I am currently using libnfc on Linux board with PN532 connected as a SPI device. I also have arduino-based board at hand for testing.

It would be helpful if you can share the sample firmware you used for PN532 for testing. I'm also willing to contribute to this repo by adding the hardware integration details of my test cases.

kormax commented 10 months ago

Hello.

In regards to libnfc, I am not familiar with the codebase, but from what I see, a "nice" ECP implementation would require modifying the source code of the library itself, or bringing up the polling code to the upper layer.
Cannot give any pointers as I didn't work with it. I only added it to references as something people may look into. Sorry if it created any confusion implying that there is support. None of the libraries have, and I assume none will add one as it might bring unneeded attention.

As for code example, that PN532 snippet of code from CHIPS is the only example I have, with only that particular piece containing needed commands to implement ECP. I don't have any C/C++ code, only that, and in Python. As for a "working demo", that is something that I'll do, possibly on the weekend. It will use nfcpy and PN532. The only modification needed for NFCPY ContactlessFrontend class is to create a subclass with overridden sense method, with part right after self.target = sense_tta(target) updated to send ECP with pn532-specific commands.

kormax commented 10 months ago

Hello.

Commit ca71deb contains working example that can be modified further to suit your needs. It can be viewed in examples/nfcpy directory.

Please let me know if you are able to use the example. I'll mark the issue as resolved afterwards.

robinryf commented 10 months ago

Hello,

thank you for the in-depth analysis! I'm following the bread crumbs but I am kind of stuck on this topic. I modified the given example to broadcast an ECP frame that should auto-select the HomeKey in my Wallet. But it does not do it :/ It just opens the default start screen of my wallet app. I calculated the "Reader Identifier" as mentioned here: https://github.com/kupa22/apple-homekey#characteristic-nfc-access-control-point but it seems something is off. Do I need a valid reader identifier for ECP to work? I'm using a PN532 from Elechouse.

Can you maybe please give me some pointers?

This is what I am broadcasting as ECP Frame: broadcast = "6a02cb02060211009e8f6ea77a6c2bff" I tried with or without the CRC16

kormax commented 10 months ago

Your frame looks good. Yes, if used with my example app, should be without CRC.

You can verify that your calculated reader identifier is correct by making an encrypted ios backup and looking at the homekey pass json file.

As for other possible issues, assuming you're using my example code:

  1. Express mode could be turned off for your home key, I've found that it sometimes doesn't turn on when initially created. Check if it is turned on for you.

By the way, if you add keys for two homes onto a single device, it breaks the way ECP is processed, and phone will answer to any home key frame regardless of reader identifier.

robinryf commented 10 months ago

Thank you for your response!

I'm creating a backup at the moment. That takes some time...

But now that you said the reader identifier is inside the .keypass it got me thinking... I was following this algorithm:

SHA256( concatenate( 6B65792D6964656E746966696572, readerPrivateKey ) ) --> first 8 Bytes is the Reader Identifier

I used the constant 6B65792D6964656E746966696572 in my calculation. Do I have to replace this value "6B65792D6964656E746966696572" with something from the HomeKey pairing process? Does the documentation indicate I should replace 6B65792D6964656E746966696572 with the issuer Key Identifier shared in the "Device Credential Request" ?

kormax commented 10 months ago

6B65792D6964656E746966696572 is hex representation of a string "key-identifier", it is stated just near that part of text you've found the calculation formula.

Regarding the calculation itself, here's a piece of Python code doing just that:

reader_group_id = hashlib.sha256("key-identifier".encode() + reader_private_key).digest()[:8]

where

reader_private_key should be a 32 byte long value written inside on of the HAP commands (the one related to reader key config)

robinryf commented 10 months ago

Thank you. And sorry for the noob questions. Getting into RE projects.

I have the reader private key from HAP in string format. Do I also have to call .encode() on it? Should it be upper case HEX ?

kormax commented 10 months ago

Unless told otherwise, everything should be treated as bytes. Especially HEX-like strings, which are bytes printed as hex in examples solely for easier readability.

If you're planning on continuing the conversation, i think you should move it to the home key repository so that other interested people would be able to find answers to similar questions easier.