postlund / pyatv

A client library for Apple TV and AirPlay devices
https://pyatv.dev
MIT License
866 stars 95 forks source link

AirPlay broken for tvOS 10.2+ #79

Closed postlund closed 7 years ago

postlund commented 7 years ago

From tvOS 10.2 and onwards, device verification is now mandatory. This breaks AirPlay streaming for this version (and later). I will look into this as soon as I have some time.

https://www.google.se/amp/appleinsider.com/articles/17/03/29/tvos-102-update-requires-airplay-hardware-verification-breaks-third-party-streaming-apps/amp/

philippe44 commented 7 years ago

Thanks @postlund and @funtax. I still receive an error when I'm sending the proof, so I'm not sure what's missing. Just a silly question. The plist items (pk, salt, proof) ... shall they be encoded in a special way? By default the Perl Crypt::SRP package use everything in raw format (I've tried hex, b64 but did not help and it seems that all is raw anyway). Crypt::SRP by default handles everything in raw. I was wondering why you do hex convert of pk and salt before calculating the proof

postlund commented 7 years ago

Everything in the plist-responses shall be in binary (raw) format and not converted to hex. I would highly recommend to log the various variables for a successful pairing either with @funtax library or mine, just so you have reference values. Then you input the same parameters in your code (e.g private key, PIN code) and pin-point when they differ. That's how I did and just trying to "get it right" the first time would never have worked.

philippe44 commented 7 years ago

Thanks @funtax and @postlund. I'm good now. Authentication & Verification works in Perl. I've been pretty unlucky with 2 packages from Perl (SRP and Plist) that each head a nasty bug which derailed me for a long while. I know need to do a C version as well, at least for the verification steps

I'm also documenting the different steps needed for exchange the and I'll make this available later. This is a pretty big list of crypto functions needed!

philippe44 commented 7 years ago

Just a quick follow-up: it's all working now. I've created a small doc that describes the protocol, in a format similar to http://nto.github.io/AirPlay.html. You can find it here https://htmlpreview.github.io/?https://github.com/philippe44/RAOP-Player/blob/master/doc/auth_protocol.html Thank you both

LionisIAm commented 6 years ago

@philippe44 , @postlund Does anybody know how works second part of this protocol? I Mean an AppleTV part. What should I answer on AirPlay clients requests? Thanks if any help.

philippe44 commented 6 years ago

Can't you get that from the doc I've made?

LionisIAm commented 6 years ago

@philippe44 yes, sure. Even I am trying to make my server without pw (so we are starting from 10.2. RTSP session authentication) IPad didnt accept my answer. As I can see, I should respond "with a body containing 96 bytes of data." as I did, but dont know what is " remaining bytes (usually 64) are some data " so random bytes are not accessible.

LionisIAm commented 6 years ago

And also Iam receiving messageInfoDefaultHttpRequest(chunked: false) POST /pair-setup RTSP/1.0 Content-Length: 32 Content-Type: application/octet-stream CSeq: 0 DACP-ID: C30201934BF1D1F2 Active-Remote: 514593877 User-Agent: AirPlay/280.33BigEndianHeapChannelBuffer(ridx=0, widx=32, cap=32) This kind of request, which is not discribed at your document @philippe44

philippe44 commented 6 years ago

understood - at this point, unfortunately I don't know. It might be that is a signature of something and iPad verifies it, but when writing a client, I did not have to verify it. Only thing I can recommend is to verify that all your other steps are correct using the test vector I've included. There is such an amount of crypto which include many options that any small mistep makes it wrong.

Another thing: I'm not sure how you can start at 10.2 as what is done here requires that all other steps are done before. They must be done only once, but they must because the client will send you a request that relies on the fact that its pairing was accepted before

postlund commented 6 years ago

@philippe44 @LionisIAm I had a look at the code I wrote for MRP, which also uses SRP but with a proecdure more or less looking like the one used by HomeKit. The parts seems to be a bit weird to me and my guess is that it's encrypted data with a signature of some sort (as you said, @philippe44). In the MRP code, the data corresponding to is decrypted with CHACHA20Poly1305 using the previously derived shared key. Basically like this:

 def verify1(self, credentials, session_pub_key, encrypted):
      """First verification step."""
      public = curve25519.Public(session_pub_key)
      self._shared = self._verify_private.get_shared_key(
          public, hashfunc=lambda x: x)  # No additional hashing used

      session_key = hkdf_expand('Pair-Verify-Encrypt-Salt',
                                'Pair-Verify-Encrypt-Info',
                                self._shared)

      chacha = chacha20.Chacha20Cipher(session_key, session_key)
      decrypted = chacha.decrypt(encrypted, nounce='PV-Msg02'.encode())

      decrypted_tlv = tlv8.read_tlv(decrypted)
      ...

The variable encrypted here corresponds to . Since AirPlay uses AES in CTR mode instead of CHACHA20Poly1305, I assume AES is used here instead. So maybe it is possible to decrypt using the shared secret to derive some sort of identifier that normal iOS devices verifies, but our implementations still don't (because we don't know how it works yet).

You can find the SRP code for MRP here (still WIP): https://github.com/postlund/pyatv/pull/114/files#diff-0db40656ea4dba91f392656886afa836R100

MikkelSnitker commented 6 years ago

Has anyone figured out what contains?