Exemple #1
0
        /// <summary>
        /// <exception cref="IOException"/>
        /// <exception cref="SpotifyAuthenticatedException"/>
        /// <exception cref="AccessViolationException"/>
        /// </summary>
        private void Connect()
        {
            #region ClientHello Setup

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            var clientHello = new ClientHello
            {
                BuildInfo = new BuildInfo
                {
                    Platform     = Platform.Win32X86,
                    Product      = Product.Client,
                    ProductFlags = { ProductFlags.ProductFlagNone },
                    Version      = 112800721
                }
            };
            clientHello.CryptosuitesSupported.Add(Cryptosuite.Shannon);
            clientHello.LoginCryptoHello = new LoginCryptoHelloUnion
            {
                DiffieHellman = new LoginCryptoDiffieHellmanHello
                {
                    Gc = ByteString.CopyFrom(keys.PublicKeyArray()),
                    ServerKeysKnown = 1
                }
            };

            var nonce = new byte[16];
            (new Random()).NextBytes(nonce);
            clientHello.ClientNonce = ByteString.CopyFrom(nonce);
            clientHello.Padding     = ByteString.CopyFrom(new byte[1]
            {
                (byte)30
            });

            var clientHelloBytes = clientHello.ToByteArray();

            var a = conn.Result.NetworkStream;
            a.WriteByte(0x00);
            a.WriteByte(0x04);
            a.WriteByte(0x00);
            a.WriteByte(0x00);
            a.WriteByte(0x00);
            a.Flush();

            var length = 2 + 4 + clientHelloBytes.Length;
            var bytes  = BitConverter.GetBytes(length);
            a.WriteByte(bytes[0]);
            a.Write(clientHelloBytes, 0, clientHelloBytes.Length);
            a.Flush();
            var buffer = new byte[1000];
            var len    = int.Parse(a.Read(buffer, 0, buffer.Length).ToString());
            var tmp    = new byte[len];
            Array.Copy(buffer, tmp, len);

            tmp = tmp.Skip(4).ToArray();
            var accumulator = new MemoryStream();
            accumulator.WriteByte(0x00);
            accumulator.WriteByte(0x04);

            var lnarr = Utils.toByteArray(length);
            accumulator.Write(lnarr, 0, lnarr.Length);
            accumulator.Write((byte[])clientHelloBytes, 0, clientHelloBytes.Length);

            var lenArr = Utils.toByteArray(len);
            accumulator.Write(lenArr, 0, lenArr.Length);
            accumulator.Write((byte[])tmp, 0, tmp.Length);

            #endregion ClientHello Setup

            //Read APResponseMessage

            #region APResponse

            var binaryData        = accumulator.ToArray();
            var apResponseMessage = APResponseMessage.Parser.ParseFrom(tmp);
            var sharedKey         = Utils.toByteArray(keys.ComputeSharedKey(apResponseMessage
                                                                            .Challenge.LoginCryptoChallenge.DiffieHellman.Gs.ToByteArray()));

            // Check gs_signature
            var rsa        = new RSACryptoServiceProvider();
            var rsaKeyInfo = new RSAParameters
            {
                Modulus  = new BigInteger(1, serverKey).ToByteArrayUnsigned(),
                Exponent = BigInteger.ValueOf(65537).ToByteArrayUnsigned()
            };

            //Set  to the public key values.

            //Import key parameters into RSA.
            rsa.ImportParameters(rsaKeyInfo);
            var gs   = apResponseMessage.Challenge.LoginCryptoChallenge.DiffieHellman.Gs.ToByteArray();
            var sign = apResponseMessage.Challenge.LoginCryptoChallenge.DiffieHellman.GsSignature.ToByteArray();

            if (!rsa.VerifyData(gs,
                                sign,
                                HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1))
            {
                throw new AccessViolationException("Failed to verify APResponse");
            }

            // Solve challenge
            binaryData     = accumulator.ToArray();
            using var data = new MemoryStream();
            var mac = new HMACSHA1(sharedKey);
            mac.Initialize();
            for (var i = 1; i < 6; i++)
            {
                mac.TransformBlock(binaryData, 0, binaryData.Length, null, 0);
                var temp = new[] { (byte)i };
                mac.TransformBlock(temp, 0, temp.Length, null, 0);
                mac.TransformFinalBlock(new byte[0], 0, 0);
                var final = mac.Hash;
                data.Write(final, 0, final.Length);
                mac = new HMACSHA1(sharedKey);
            }

            var dataArray = data.ToArray();
            mac = new HMACSHA1(Arrays.CopyOfRange(dataArray, 0, 0x14));
            mac.TransformBlock(binaryData, 0, binaryData.Length, null, 0);
            mac.TransformFinalBlock(new byte[0], 0, 0);
            var challenge = mac.Hash;
            var clientResponsePlaintext = new ClientResponsePlaintext
            {
                LoginCryptoResponse = new LoginCryptoResponseUnion
                {
                    DiffieHellman = new LoginCryptoDiffieHellmanResponse
                    {
                        Hmac = ByteString.CopyFrom(challenge)
                    }
                },
                PowResponse    = new PoWResponseUnion(),
                CryptoResponse = new CryptoResponseUnion()
            };
            var clientResponsePlaintextBytes = clientResponsePlaintext.ToByteArray();
            len = 4 + clientResponsePlaintextBytes.Length;
            a.WriteByte(0x00);
            a.WriteByte(0x00);
            a.WriteByte(0x00);
            var bytesb = BitConverter.GetBytes(len);
            a.WriteByte(bytesb[0]);
            a.Write(clientResponsePlaintextBytes, 0, clientResponsePlaintextBytes.Length);
            a.Flush();
            try
            {
                var scrap = new byte[4];
                conn.Result.NetworkStream.ReadTimeout = 300;
                var read = conn.Result.NetworkStream.Read(scrap, 0, scrap.Length);
                if (read == scrap.Length)
                {
                    length = (scrap[0] << 24) | (scrap[1] << 16) | (scrap[2] << 8) | (scrap[3] & 0xFF);
                    var payload = new byte[length - 4];
                    conn.Result.NetworkStream.ReadComplete(payload, 0, payload.Length);
                    var failed = APResponseMessage.Parser.ParseFrom(payload)?.LoginFailed;
                    throw new SpotifyAuthenticatedException(failed);
                }
                else if (read > 0)
                {
                    throw new Exception("Read unknown data!");
                }
            }
            catch (Exception x)
            {
                // ignored
            }
            finally
            {
                conn.Result.NetworkStream.ReadTimeout = Timeout.Infinite;
            }

            using (authLock.Lock())
            {
                sendCipher = new Shannon();
                sendCipher.key(Arrays.CopyOfRange(data.ToArray(), 0x14, 0x34));

                recvCipher = new Shannon();
                recvCipher.key(Arrays.CopyOfRange(data.ToArray(), 0x34, 0x54));
                authLockEventWaitHandle.Set();
            }

            #endregion APResponse

            Debug.WriteLine("Connected successfully");
        }