diff --git a/docs/connection.md b/docs/connection.md new file mode 100644 index 00000000..b66a56b4 --- /dev/null +++ b/docs/connection.md @@ -0,0 +1,64 @@ +# Connection Setup +## Access point Connection +The first step to connecting to Spotify's servers is finding an Access Point (AP) to do so. +Clients make an HTTP GET request to `http://apresolve.spotify.com` to retrieve a list of hostname an port combination in JSON format. +An AP is randomly picked from that list to connect to. + +The connection is done using a bare TCP socket. Despite many APs using ports 80 and 443, neither HTTP nor TLS are used to connect. + +## Connection Hello +The first 3 packets exchanged are unencrypted, and have the following format : + +header | length | payload +---------|--------|--------- +variable | 32 | variable + +Length is a 32 bit, big endian encoded, integer. +It is the length of the entire packet, ie `len(header) + 4 + len(payload)`. + +The header is only present in the very first packet sent by the client, and is two bytes long, `[0, 4]`. +It probably corresponds to the protocol version used. + +The payload is a protobuf encoded message. + +The client starts by sending a `ClientHello` message, describing the client info, a random nonce and client's Diffie Hellman public key. + +The AP replies by a `APResponseMessage` message, containing a random nonce and the server's DH key. + +The client solves a challenge based on these two packets, and sends it back using a `ClientResponsePlaintext`. +It also computes the shared keys used to encrypt the rest of the communication. + +## Login challenge and cipher key computation. +The client starts by computing the DH shared secret using it's private key and the server's public key. +HMAC-SHA1 is then used to compute the send and receive keys, as well as the login challenge. + +``` +data = [] +for i in 1..6 { + data += HMAC(client_hello || ap_response || [ i ], shared) +} + +challenge = HMAC(client_hello || ap_response, data[:20]) +send_key = data[20:52] +recv_key = data[52:84] +``` + +`client_hello` and `ap_response` are the first packets sent respectively by the client and the AP. +These include the header and length fields. + +## Encrypted packets +Every packet after ClientResponsePlaintext is encrypted using a Shannon cipher. + +The cipher is setup with 4 bytes big endian nonce, incremented after each packet, starting at zero. +Two independent ciphers and accompanying nonces are used, one for transmission and one for reception, +using respectively `send_key` and `recv_key` as keys. + +The packet format is as followed : + +cmd | length | payload | mac +----|--------|----------|---- + 8 | 16 | variable | 32 + +Each packet has a type identified by the 8 bit `cmd` field. +The 16 bit big endian length only inculdes the length of the payload. +