Пример #1
0
        /// <summary>
        /// Create start HTTP request
        /// </summary>
        private XmlQuery StartOrResumeApp(NvHttp nv, LimelightStreamConfiguration streamConfig)
        {
            XmlQuery serverInfo = new XmlQuery(nv.baseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId());
            string currentGameString = serverInfo.XmlAttribute("currentgame");

            byte[] aesIv = streamConfig.GetRiAesIv();
            int riKeyId =
                (int)(((aesIv[0] << 24) & 0xFF000000) |
                ((aesIv[1] << 16) & 0xFF0000) |
                ((aesIv[2] << 8) & 0xFF00) |
                (aesIv[3] & 0xFF));
            string riConfigString =
                "&rikey=" + Pairing.bytesToHex(streamConfig.GetRiAesKey()) +
                "&rikeyid=" + riKeyId;

            // Launch a new game if nothing is running
            if (currentGameString == null || currentGameString.Equals("0"))
            {
                return new XmlQuery(nv.baseUrl + "/launch?uniqueid=" + nv.GetUniqueId() + "&appid=" + selected.steamID +
                    "&mode=" + streamConfig.GetWidth() + "x" + streamConfig.GetHeight() + "x" + streamConfig.GetFps() +
                    "&additionalStates=1&sops=1" + // FIXME: make sops configurable
                    riConfigString);
            }
            else
            {
                // A game was already running, so resume it
                // FIXME: Quit and relaunch if it's not the game we came to start
                return new XmlQuery(nv.baseUrl + "/resume?uniqueid=" + nv.GetUniqueId() + riConfigString);
            }
        }
Пример #2
0
        /// <summary>
        /// Query the server to get the device pair state
        /// </summary>
        /// <returns>True if device is already paired, false if not, null if failure</returns>
        public async Task <bool?> QueryPairState()
        {
            XmlQuery pairState;

            try
            {
                pairState = new XmlQuery(nv.BaseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId());
            }
            catch (Exception e)
            {
                Debug.WriteLine("Failed to get pair state: " + e.Message);

                return(null);
            }
            nv.ServerInfo = pairState;

            // Check if the device is paired by checking the XML attribute within the <paired> tag
            if (String.Compare(pairState.XmlAttribute("PairStatus"), "1") != 0)
            {
                Debug.WriteLine("Not paired");
                return(false);
            }
            // We're already paired if we get here!
            return(true);
        }
Пример #3
0
        /// <summary>
        /// Create start HTTP request
        /// </summary>
        private XmlQuery StartOrResumeApp(NvHttp nv, LimelightStreamConfiguration streamConfig)
        {
            XmlQuery serverInfo        = new XmlQuery(nv.BaseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId());
            string   currentGameString = serverInfo.XmlAttribute("currentgame");

            byte[] aesIv   = streamConfig.GetRiAesIv();
            int    riKeyId =
                (int)(((aesIv[0] << 24) & 0xFF000000) |
                      ((aesIv[1] << 16) & 0xFF0000) |
                      ((aesIv[2] << 8) & 0xFF00) |
                      (aesIv[3] & 0xFF));
            string riConfigString =
                "&rikey=" + Pairing.bytesToHex(streamConfig.GetRiAesKey()) +
                "&rikeyid=" + riKeyId;

            // Launch a new game if nothing is running
            if (currentGameString == null || currentGameString.Equals("0"))
            {
                return(new XmlQuery(nv.BaseUrl + "/launch?uniqueid=" + nv.GetUniqueId() + "&appid=" + selected.steamID +
                                    "&mode=" + streamConfig.GetWidth() + "x" + streamConfig.GetHeight() + "x" + streamConfig.GetFps() +
                                    "&additionalStates=1&sops=1" + // FIXME: make sops configurable
                                    riConfigString));
            }
            else
            {
                // A game was already running, so resume it
                // FIXME: Quit and relaunch if it's not the game we came to start
                return(new XmlQuery(nv.BaseUrl + "/resume?uniqueid=" + nv.GetUniqueId() + riConfigString));
            }
        }
Пример #4
0
        private async void Quit_Game(object sender, RoutedEventArgs e)
        {
            // TODO need to make a UI element to display this text
            Task.Run(() => SpinnerBegin("Quitting...")).Wait();
            // If we haven't used nv before, create it.
            if (nv == null)
            {
                try
                {
                    await SpinnerBegin("Quitting");

                    Computer selected = (Computer)computerPicker.SelectedItem;
                    nv = new NvHttp(selected.IpAddress);
                    await nv.ServerIPAddress();

                    XmlQuery quit = new XmlQuery(nv.BaseUrl + "/cancel?uniqueid=" + nv.GetUniqueId());
                }
                catch (Exception)
                {
                    SpinnerEnd();
                    StreamSetupFailed("Unable to quit");
                    return;
                }
                finally
                {
                    // Turn off the spinner
                    SpinnerEnd();
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Query the app list on the server to get the Steam App ID
        /// </summary>
        /// <returns>True if the operation succeeded, false otherwise</returns>
        private async Task <bool> QueryAppList()
        {
            XmlQuery appList;
            string   steamIdStr;

            try
            {
                appList = new XmlQuery(nv.baseUrl + "/applist?uniqueid=" + nv.GetDeviceName());
            }
            catch (Exception e)
            {
                var dialog = new MessageDialog("Device not paired: " + e.Message, "App List Query Failed");
                dialog.ShowAsync();
                return(false);
            }
            // App list query went well - try to get the steam ID
            try
            {
                steamIdStr = await Task.Run(() => appList.XmlAttribute("ID", appList.XmlAttributeElement("App")));
            }
            catch (Exception e)
            {
                // Steam ID lookup failed
                var dialog = new MessageDialog("Failed to get Steam ID: " + e.Message, "Steam ID Lookup Failed");
                dialog.ShowAsync();
                return(false);
            }

            // We're in the clear - save the Steam app ID
            steamId = Convert.ToInt32(steamIdStr);
            return(true);
        }
Пример #6
0
        /// <summary>
        /// Starts the connection by calling into Limelight Common
        /// </summary>
        private async Task StartConnection()
        {
            NvHttp nv = null;

            await SetStateText("Resolving hostname...");

            try
            {
                nv = new NvHttp(selected.IpAddress);
            }
            catch (ArgumentNullException)
            {
                stageFailureText = "Error resolving hostname";
                ConnectionFailed();
            }

            XmlQuery launchApp;

            // Launch Steam
            await SetStateText("Launching Steam");

            try
            {
                launchApp = new XmlQuery(nv.baseUrl + "/launch?uniqueid=" + nv.GetDeviceName() + "&appid=" + selected.steamID);
            }
            catch (Exception)
            {
                Debug.WriteLine("Can't find steam");
                stageFailureText = "Error launching Steam";
                ConnectionFailed();
                return;
            }

            // Set up callbacks
            LimelightStreamConfiguration streamConfig = new LimelightStreamConfiguration(frameWidth, frameHeight, 30, 10000, 1024); // TODO a magic number. Get FPS from the settings
            LimelightDecoderRenderer     drCallbacks  = new LimelightDecoderRenderer(DrSetup, DrStart, DrStop, DrRelease, DrSubmitDecodeUnit);
            LimelightAudioRenderer       arCallbacks  = new LimelightAudioRenderer(ArInit, ArStart, ArStop, ArRelease, ArPlaySample);
            LimelightConnectionListener  clCallbacks  = new LimelightConnectionListener(ClStageStarting, ClStageComplete, ClStageFailed,
                                                                                        ClConnectionStarted, ClConnectionTerminated, ClDisplayMessage, ClDisplayTransientMessage);

            // Call into Common to start the connection
            Debug.WriteLine("Starting connection");
            uint addr = 0;

            //uint addr = (uint)nv.resolvedHost.ToString(); // TODO how to get the addr as a uint
            LimelightCommonRuntimeComponent.StartConnection(addr, streamConfig, clCallbacks, drCallbacks, arCallbacks);

            if (stageFailureText != null)
            {
                Debug.WriteLine("Stage failed");
                ConnectionFailed();
                return;
            }
            else
            {
                ConnectionSuccess();
            }
        }
Пример #7
0
        private X509Certificate extractPlainCert(XmlQuery q, String tag)
        {
            String certHexString = q.XmlAttribute(tag);

            byte[] certBytes = HexToBytes(certHexString);
            String certText  = Encoding.UTF8.GetString(certBytes, 0, certBytes.Length);

            PemReader certReader = new PemReader(new StringReader(certText));

            return((X509Certificate)certReader.ReadObject());
        }
Пример #8
0
        /// <summary>
        /// Unpair from the device
        /// </summary>
        private void Unpair()
        {
            XmlQuery unpair;

            try
            {
                unpair = new XmlQuery(nv.BaseUrl + "/unpair?uniqueid=" + nv.GetUniqueId());
            }
            catch (Exception e)
            {
                Debug.WriteLine("Error hitting unpair URL " + e.Message);
            }
        }
Пример #9
0
        /// <summary>
        /// Query the app list on the server to get the Steam App ID
        /// </summary>
        /// <returns>True if the operation succeeded, false otherwise</returns>
        private int QueryAppList()
        {
            XmlQuery appList;
            string   steamIdStr;

            try
            {
                appList = new XmlQuery(nv.BaseUrl + "/applist?uniqueid=" + nv.GetUniqueId());
            }
            catch (Exception e)
            {
                var dialog = new MessageDialog(e.Message, "App List Query Failed");
                dialog.ShowAsync();
                return(0);
            }
            Debug.WriteLine(appList.rawXmlString);
            // App list query went well - try to get the steam ID
            try
            {
                steamIdStr = appList.SearchAttribute("App", "AppTitle", "Steam", "ID");
                Debug.WriteLine(steamIdStr);
                if (steamIdStr == null)
                {
                    // Not found
                    var dialog = new MessageDialog("Steam Not Found", "Steam ID Lookup Failed");
                    dialog.ShowAsync();
                    return(0);
                }
            }
            // Exception connecting to the resource
            catch (Exception e)
            {
                // Steam ID lookup failed
                var dialog = new MessageDialog("Failed to get Steam ID: " + e.Message, "Steam ID Lookup Failed");
                dialog.ShowAsync();
                return(0);
            }

            // We're in the clear - save the Steam app ID
            return(Convert.ToInt32(steamIdStr));
        }
Пример #10
0
        /// <summary>
        /// Query the server to get the device pair state
        /// </summary>
        /// <returns>True if the operation succeeded, false otherwise</returns>
        private async Task <bool> QueryPairState()
        {
            XmlQuery pairState;

            try
            {
                pairState = new XmlQuery(nv.baseUrl + "/serverinfo?uniqueid=" + nv.GetDeviceName());
            }
            catch (Exception e)
            {
                var dialog = new MessageDialog("Failed to get pair state: " + e.Message);
                dialog.ShowAsync();
                return(false);
            }

            // Check if the device is paired by checking the XML attribute within the <paired> tag
            if (String.Compare(pairState.XmlAttribute("PairStatus"), "0") == 0)
            {
                Debug.WriteLine("Not paired");
                return(false);
            }
            return(true);
        }
Пример #11
0
        private async Task <bool> Challenges(string uniqueId)
        {
            // Generate a salt for hashing the PIN
            byte[] salt = GenerateRandomBytes(16);

            string pin = new Random().Next(9999).ToString("D4");

            // Combine the salt and pin, then create an AES key from them
            byte[] saltAndPin = SaltPin(salt, pin);
            aesKey = GenerateAesKey(saltAndPin);

            if (!nv.ServerInfo.XmlAttribute("currentgame").Equals("0"))
            {
                // The server is busy - we can't stream to it
                var busyDialog = new MessageDialog("Server is busy", "Pairing Failed");
                await busyDialog.ShowAsync();

                return(false);
            }

            // Send the salt and get the server cert
            var dialog = new MessageDialog("Enter the following PIN on the host PC: " + pin, "Enter PIN");

            dialog.Commands.Add(new UICommand("Close"));
            await dialog.ShowAsync();

            // User will need to close dialog themselves
            XmlQuery getServerCert = new XmlQuery(nv.BaseUrl + "/pair?uniqueid=" + uniqueId +
                                                  "&devicename=roth&updateState=1&phrase=getservercert&salt=" + bytesToHex(salt) + "&clientcert=" + bytesToHex(pemCertBytes));

            if (!getServerCert.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            X509Certificate serverCert = extractPlainCert(getServerCert, "plaincert");

            // Generate a random challenge and encrypt it with our AES key
            byte[] randomChallenge = GenerateRandomBytes(16);
            Debug.WriteLine("Client challenge: " + bytesToHex(randomChallenge));
            byte[] encryptedChallenge = EncryptAes(randomChallenge, aesKey);

            // Send the encrypted challenge to the server
            XmlQuery challengeResp = new XmlQuery(nv.BaseUrl +
                                                  "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&clientchallenge=" + bytesToHex(encryptedChallenge));

            // If we're not paired, there's a problem.
            if (!challengeResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            // Decode the server's response and subsequent challenge
            byte[] encServerChallengeResponse = HexToBytes(challengeResp.XmlAttribute("challengeresponse"));
            byte[] decServerChallengeResponse = DecryptAes(encServerChallengeResponse, aesKey);

            byte[] serverResponse = new byte[20], serverChallenge = new byte[16];
            Array.Copy(decServerChallengeResponse, serverResponse, serverResponse.Length);
            Array.Copy(decServerChallengeResponse, 20, serverChallenge, 0, serverChallenge.Length);
            Debug.WriteLine("serverResponse: " + bytesToHex(serverResponse));
            Debug.WriteLine("server challenge: " + bytesToHex(serverChallenge));

            // Using another 16 bytes secret, compute a challenge response hash using the secret, our cert sig, and the challenge
            byte[] clientSecret = GenerateRandomBytes(16);
            Debug.WriteLine("Client secret: " + bytesToHex(clientSecret));
            Debug.WriteLine("Client sig: " + bytesToHex(cert.GetSignature()));

            byte[] challengeRespHash = ToSHA1Bytes(concatBytes(concatBytes(serverChallenge, cert.GetSignature()), clientSecret));
            Debug.WriteLine("Challenge SHA 1: " + bytesToHex(challengeRespHash));
            byte[]   challengeRespEncrypted = EncryptAes(challengeRespHash, aesKey);
            XmlQuery secretResp             = new XmlQuery(nv.BaseUrl +
                                                           "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&serverchallengeresp=" + bytesToHex(challengeRespEncrypted));

            if (!secretResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            // Get the server's signed secret
            byte[] serverSecretResp = HexToBytes(secretResp.XmlAttribute("pairingsecret"));
            byte[] serverSecret = new byte[16]; byte[] serverSignature = new byte[256];
            Array.Copy(serverSecretResp, 0, serverSecret, 0, 16);
            Array.Copy(serverSecretResp, 16, serverSignature, 0, 256);

            // Ensure the authenticity of the data
            if (!VerifySignature(serverSecret, serverSignature, serverCert))
            {
                // Cancel the pairing process
                Unpair();
                // Looks like a MITM
                return(false);
            }

            // Ensure the server challenge matched what we expected (aka the PIN was correct)
            byte[] serverChallengeRespHash = ToSHA1Bytes(concatBytes(concatBytes(randomChallenge, serverCert.GetSignature()), serverSecret));
            if (!serverChallengeRespHash.SequenceEqual(serverResponse))
            {
                // Cancel the pairing process
                Unpair();
                // Probably got the wrong PIN
                return(false);
            }

            // Send the server our signed secret
            byte[]   clientPairingSecret = concatBytes(clientSecret, SignData(clientSecret));
            XmlQuery clientSecretResp    = new XmlQuery(nv.BaseUrl +
                                                        "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&clientpairingsecret=" + bytesToHex(clientPairingSecret));

            if (!clientSecretResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            // Do the initial challenge (seems neccessary for us to show as paired)
            XmlQuery pairChallenge = new XmlQuery(nv.BaseUrl + "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&phrase=pairchallenge");

            if (!pairChallenge.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }
            return(true);
        }
Пример #12
0
        private async Task<bool> Challenges(string uniqueId)
        {
            // Generate a salt for hashing the PIN
            byte[] salt = GenerateRandomBytes(16);

            string pin = new Random().Next(9999).ToString("D4");
            
            // Combine the salt and pin, then create an AES key from them
            byte[] saltAndPin = SaltPin(salt, pin);
            aesKey = GenerateAesKey(saltAndPin);

            // Send the salt and get the server cert
            var dialog = new MessageDialog("Enter the following PIN on the host PC: " + pin, "Enter PIN");
            dialog.Commands.Add(new UICommand("Close"));
            dialog.ShowAsync();

            // User will need to close dialog themselves
            XmlQuery getServerCert = new XmlQuery(nv.baseUrl + "/pair?uniqueid=" + uniqueId +
                "&devicename=roth&updateState=1&phrase=getservercert&salt=" + bytesToHex(salt) + "&clientcert=" + bytesToHex(pemCertBytes));
            
            if (!getServerCert.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return false; 
            }

            X509Certificate serverCert = extractPlainCert(getServerCert, "plaincert");

            // Generate a random challenge and encrypt it with our AES key
		    byte[] randomChallenge = GenerateRandomBytes(16);
            Debug.WriteLine("Client challenge: " + bytesToHex(randomChallenge));
		    byte[] encryptedChallenge = EncryptAes(randomChallenge, aesKey);

		    // Send the encrypted challenge to the server
		    XmlQuery challengeResp = new XmlQuery(nv.baseUrl + 
				    "/pair?uniqueid="+uniqueId+"&devicename=roth&updateState=1&clientchallenge="+bytesToHex(encryptedChallenge));
            // If we're not paired, there's a problem. 
		    if (!challengeResp.XmlAttribute("paired").Equals("1")) {
                Unpair(); 
			    return false;
		    }

            // Decode the server's response and subsequent challenge
            byte[] encServerChallengeResponse = HexToBytes(challengeResp.XmlAttribute("challengeresponse"));
            byte[] decServerChallengeResponse = DecryptAes(encServerChallengeResponse, aesKey);

            byte[] serverResponse = new byte[20], serverChallenge = new byte[16];
            Array.Copy(decServerChallengeResponse, serverResponse, serverResponse.Length);
            Array.Copy(decServerChallengeResponse, 20, serverChallenge, 0, serverChallenge.Length);
            Debug.WriteLine("serverResponse: " + bytesToHex(serverResponse));
            Debug.WriteLine("server challenge: " + bytesToHex(serverChallenge));

            // Using another 16 bytes secret, compute a challenge response hash using the secret, our cert sig, and the challenge
            byte[] clientSecret = GenerateRandomBytes(16);
            Debug.WriteLine("Client secret: " + bytesToHex(clientSecret));
            Debug.WriteLine("Client sig: " + bytesToHex(cert.GetSignature()));

            byte[] challengeRespHash = ToSHA1Bytes(concatBytes(concatBytes(serverChallenge, cert.GetSignature()), clientSecret));
            Debug.WriteLine("Challenge SHA 1: " + bytesToHex(challengeRespHash));
            byte[] challengeRespEncrypted = EncryptAes(challengeRespHash, aesKey);
            XmlQuery secretResp = new XmlQuery(nv.baseUrl +
                    "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&serverchallengeresp=" + bytesToHex(challengeRespEncrypted));
            if (!secretResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair(); 
                return false;
            }

            // Get the server's signed secret
            byte[] serverSecretResp = HexToBytes(secretResp.XmlAttribute("pairingsecret"));
            byte[] serverSecret = new byte[16]; byte[] serverSignature = new byte[256]; 
            Array.Copy(serverSecretResp, 0, serverSecret, 0, 16);
            Array.Copy(serverSecretResp, 16, serverSignature, 0, 256);

            // Ensure the authenticity of the data
            if (!VerifySignature(serverSecret, serverSignature, serverCert))
            {
                // Cancel the pairing process
                Unpair(); 
                // Looks like a MITM
                return false;
            }

            // Ensure the server challenge matched what we expected (aka the PIN was correct)
            byte[] serverChallengeRespHash = ToSHA1Bytes(concatBytes(concatBytes(randomChallenge, serverCert.GetSignature()), serverSecret));
            if (!serverChallengeRespHash.SequenceEqual(serverResponse))
            {
                // Cancel the pairing process
                Unpair(); 
                // Probably got the wrong PIN
                return false;
            }

            // Send the server our signed secret
            byte[] clientPairingSecret = concatBytes(clientSecret, SignData(clientSecret));
            XmlQuery clientSecretResp = new XmlQuery(nv.baseUrl +
                    "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&clientpairingsecret=" + bytesToHex(clientPairingSecret));
            if (!clientSecretResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return false; 
            }

            // Do the initial challenge (seems neccessary for us to show as paired)
            XmlQuery pairChallenge = new XmlQuery(nv.baseUrl + "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&phrase=pairchallenge");

            if (!pairChallenge.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return false; 
            }
            return true; 
        } 
Пример #13
0
 /// <summary>
 /// Unpair from the device
 /// </summary>
 private void Unpair()
 {
     XmlQuery unpair;
     try
     {
         unpair = new XmlQuery(nv.baseUrl + "/unpair?uniqueid=" + nv.GetUniqueId());
     }
     catch (Exception e)
     {
         Debug.WriteLine("Error hitting unpair URL " + e.Message);
     }
 }
Пример #14
0
        /// <summary>
        /// Query the server to get the device pair state
        /// </summary>
        /// <returns>True if device is already paired, false if not, null if failure</returns>
        public async Task<bool?> QueryPairState()
        {
            XmlQuery pairState;
            try
            {
                pairState = new XmlQuery(nv.baseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId());
            }
            catch (Exception e)
            {
                Debug.WriteLine("Failed to get pair state: " + e.Message);
                
                return null;
            }

            // Check if the device is paired by checking the XML attribute within the <paired> tag
            if (String.Compare(pairState.XmlAttribute("PairStatus"), "1") != 0)
            {
                Debug.WriteLine("Not paired");
                return false;
            }
            // We're already paired if we get here!
            return true;
        }
Пример #15
0
        private X509Certificate extractPlainCert(XmlQuery q, String tag)
        {
            String certHexString = q.XmlAttribute(tag);
            byte[] certBytes = HexToBytes(certHexString);
            String certText = Encoding.UTF8.GetString(certBytes, 0, certBytes.Length);

            PemReader certReader = new PemReader(new StringReader(certText));
            return (X509Certificate)certReader.ReadObject();
        }
Пример #16
0
        private bool Challenges(string uniqueId)
        {
            // "Please don't do this ever, but it's only okay because Cameron said so" -Cameron Gutman
            getClientCertificate();
            // Generate a salt for hashing the PIN
            byte[] salt = GenerateRandomBytes(16);

            string pin = "0000";

            // Combine the salt and pin, then create an AES key from them
            byte[] saltAndPin = SaltPin(salt, pin);
            aesKey = GenerateAesKey(saltAndPin);

            // Send the salt and get the server cert

            XmlQuery getServerCert = new XmlQuery(nv.baseUrl + "/pair?uniqueid=" + uniqueId +
                                                  "&devicename=roth&updateState=1&phrase=getservercert&salt=" + bytesToHex(salt) + "&clientcert=" + bytesToHex(pemCertBytes));

            if (!getServerCert.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            X509Certificate serverCert = extractPlainCert(getServerCert, "plaincert");

            // Generate a random challenge and encrypt it with our AES key
            byte[] randomChallenge = GenerateRandomBytes(16);
            Debug.WriteLine("Client challenge: " + bytesToHex(randomChallenge));
            byte[] encryptedChallenge = EncryptAes(randomChallenge, aesKey);

            // Send the encrypted challenge to the server
            XmlQuery challengeResp = new XmlQuery(nv.baseUrl +
                                                  "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&clientchallenge=" + bytesToHex(encryptedChallenge));

            // If we're not paired, there's a problem.
            if (!challengeResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            // Decode the server's response and subsequent challenge
            byte[] encServerChallengeResponse = HexToBytes(challengeResp.XmlAttribute("challengeresponse"));
            byte[] decServerChallengeResponse = DecryptAes(encServerChallengeResponse, aesKey);


            byte[] serverResponse = new byte[20], serverChallenge = new byte[16];
            Array.Copy(decServerChallengeResponse, serverResponse, serverResponse.Length);
            Array.Copy(decServerChallengeResponse, 20, serverChallenge, 0, serverChallenge.Length);
            Debug.WriteLine("serverResponse: " + bytesToHex(serverResponse));
            Debug.WriteLine("server challenge: " + bytesToHex(serverChallenge));



            // Using another 16 bytes secret, compute a challenge response hash using the secret, our cert sig, and the challenge
            byte[] clientSecret = GenerateRandomBytes(16);
            Debug.WriteLine("Client secret: " + bytesToHex(clientSecret));
            Debug.WriteLine("Client sig: " + bytesToHex(cert.GetSignature()));

            byte[] challengeRespHash = ToSHA1Bytes(concatBytes(concatBytes(serverChallenge, cert.GetSignature()), clientSecret));
            Debug.WriteLine("Challenge SHA 1: " + bytesToHex(challengeRespHash));
            byte[]   challengeRespEncrypted = EncryptAes(challengeRespHash, aesKey);
            XmlQuery secretResp             = new XmlQuery(nv.baseUrl +
                                                           "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&serverchallengeresp=" + bytesToHex(challengeRespEncrypted));

            if (!secretResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            // Get the server's signed secret
            byte[] serverSecretResp = HexToBytes(secretResp.XmlAttribute("pairingsecret"));
            byte[] serverSecret = new byte[16]; byte[] serverSignature = new byte[256];
            Array.Copy(serverSecretResp, 0, serverSecret, 0, 16);
            Array.Copy(serverSecretResp, 16, serverSignature, 0, 256);

            // Ensure the authenticity of the data
            if (!VerifySignature(serverSecret, serverSignature, serverCert))
            {
                // Cancel the pairing process
                Unpair();
                // Looks like a MITM
                return(false);
            }

            // Ensure the server challenge matched what we expected (aka the PIN was correct)
            byte[] serverChallengeRespHash = ToSHA1Bytes(concatBytes(concatBytes(randomChallenge, serverCert.GetSignature()), serverSecret));
            if (!serverChallengeRespHash.SequenceEqual(serverResponse))
            {
                // Cancel the pairing process
                Unpair();
                // Probably got the wrong PIN
                return(false);
            }

            // Send the server our signed secret
            byte[]   clientPairingSecret = concatBytes(clientSecret, SignData(clientSecret));
            XmlQuery clientSecretResp    = new XmlQuery(nv.baseUrl +
                                                        "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&clientpairingsecret=" + bytesToHex(clientPairingSecret));

            if (!clientSecretResp.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }

            // Do the initial challenge (seems neccessary for us to show as paired)
            XmlQuery pairChallenge = new XmlQuery(nv.baseUrl + "/pair?uniqueid=" + uniqueId + "&devicename=roth&updateState=1&phrase=pairchallenge");

            if (!pairChallenge.XmlAttribute("paired").Equals("1"))
            {
                Unpair();
                return(false);
            }
            return(true);
        }
Пример #17
0
        /// <summary>
        /// Query the app list on the server to get the Steam App ID
        /// </summary>
        /// <returns>True if the operation succeeded, false otherwise</returns>
        private async Task<int> QueryAppList()
        {
            XmlQuery appList;
            string steamIdStr;
            try
            {
                appList = new XmlQuery(nv.baseUrl + "/applist?uniqueid=" + nv.GetUniqueId());
            }
            catch (Exception e)
            {
                var dialog = new MessageDialog(e.Message, "App List Query Failed");
                dialog.ShowAsync();
                return 0;
            }
            Debug.WriteLine(appList.rawXmlString); 
            // App list query went well - try to get the steam ID
            try
            {
                // FIXME Due to a bug in Steam, we need to launch by app right now to test
                steamIdStr = appList.SearchAttribute("App", "AppTitle", "Borderlands 2", "ID");
                Debug.WriteLine(steamIdStr);
                if (steamIdStr == null)
                {
                    // Not found
                    var dialog = new MessageDialog("Steam ID Not Found", "Steam ID Lookup Failed");
                    dialog.ShowAsync();
                    return 0;
                }
            }
                // Exception connecting to the resource
            catch (Exception e)
            {
                // Steam ID lookup failed
                var dialog = new MessageDialog("Failed to get Steam ID: " + e.Message, "Steam ID Lookup Failed");
                dialog.ShowAsync();
                return 0;
            }

            // We're in the clear - save the Steam app ID
            return Convert.ToInt32(steamIdStr);
        }