/// <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); } }
/// <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); }
/// <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)); } }
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(); } } }
/// <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); }
/// <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(); } }
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()); }
/// <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); } }
/// <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)); }
/// <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); }
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); }
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; }
/// <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); } }
/// <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; }
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(); }
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); }
/// <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); }