Ejemplo n.º 1
0
 /// <summary>
 /// Synchronously marks the producer/consumer queue as complete for adding.
 /// </summary>
 public void CompleteAdding()
 {
     using (_mutex.Lock())
     {
         if (_completed.IsCancellationRequested)
         {
             return;
         }
         _completed.Cancel();
         _completedOrNotEmpty.NotifyAll();
     }
 }
Ejemplo n.º 2
0
        internal MercuryPacket Receive(NetworkStream a, CancellationToken cts)
        {
            using (recvLock.Lock(cts))
            {
                recvCipher.nonce(Utils.toByteArray(recvNonce));
                Interlocked.Increment(ref recvNonce);

                var headerBytes = new byte[3];
                a.ReadComplete(headerBytes, 0, headerBytes.Length);
                recvCipher.decrypt(headerBytes);

                var cmd           = headerBytes[0];
                var payloadLength = (short)((headerBytes[1] << 8) | (headerBytes[2] & 0xFF));

                var payloadBytes = new byte[payloadLength];
                a.ReadComplete(payloadBytes, 0, payloadBytes.Length);
                recvCipher.decrypt(payloadBytes);

                var mac = new byte[4];
                a.ReadComplete(mac, 0, mac.Length);

                var expectedMac = new byte[4];
                recvCipher.finish(expectedMac);
                return(new MercuryPacket((MercuryPacket.Type)cmd, payloadBytes));
            }
        }
Ejemplo n.º 3
0
        private void SendUnchecked(MercuryPacket.Type cmd, byte[] payload, CancellationToken cts)
        {
            using (sendLock.Lock(cts))
            {
                var a = conn.Result.NetworkStream;
                var payloadLengthAsByte = BitConverter.GetBytes((short)payload.Length).Reverse().ToArray();
                using var yetAnotherBuffer = new MemoryStream(3 + payload.Length);
                yetAnotherBuffer.WriteByte((byte)cmd);
                yetAnotherBuffer.Write(payloadLengthAsByte, 0, payloadLengthAsByte.Length);
                yetAnotherBuffer.Write(payload, 0, payload.Length);

                sendCipher.nonce(Utils.toByteArray(sendNonce));
                Interlocked.Increment(ref sendNonce);

                var bufferBytes = yetAnotherBuffer.ToArray();
                sendCipher.encrypt(bufferBytes);

                var fourBytesBuffer = new byte[4];
                sendCipher.finish(fourBytesBuffer);
                a.Write(bufferBytes, 0, bufferBytes.Length);
                a.Write(fourBytesBuffer, 0, fourBytesBuffer.Length);
                a.Flush();
            }
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Synchronously enters the monitor. Returns a disposable that leaves the monitor when disposed. This method may block the calling thread.
 /// </summary>
 /// <param name="cancellationToken">The cancellation token used to cancel the enter. If this is already set, then this method will attempt to enter the monitor immediately (succeeding if the monitor is currently available).</param>
 public IDisposable Enter(CancellationToken cancellationToken)
 {
     return(_asyncLock.Lock(cancellationToken));
 }
Ejemplo n.º 5
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");
        }