Beispiel #1
0
        /// <summary>
        /// Form loaded event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ShowSteamSecretForm_Load(object sender, EventArgs e)
        {
            this.revocationcodeField.SecretMode = true;

            SteamAuthenticator authenticator = CurrentAuthenticator.AuthenticatorData as SteamAuthenticator;

            this.revocationcodeField.Text = authenticator.RevocationCode;
        }
Beispiel #2
0
        /// <summary>
        ///     Import the selected SDA account
        /// </summary>
        /// <returns>true if successful</returns>
        private bool ImportSDA()
        {
            var entry = importSDAList.SelectedItem as ImportedSDAEntry;

            if (entry == null)
            {
                WinAuthForm.ErrorDialog(this, "Please load and select a Steam account");
                return(false);
            }

            var auth  = new SteamAuthenticator();
            var token = JObject.Parse(entry.json);

            foreach (var prop in token.Root.Children().ToList())
            {
                var child = token.SelectToken(prop.Path);

                var lkey = prop.Path.ToLower();
                if (lkey == "fully_enrolled" || lkey == "session")
                {
                    prop.Remove();
                }
                else if (lkey == "device_id")
                {
                    auth.DeviceId = child.Value <string>();
                    prop.Remove();
                }
                else if (lkey == "serial_number")
                {
                    auth.Serial = child.Value <string>();
                }
                else if (lkey == "account_name")
                {
                    if (nameField.Text.Length == 0)
                    {
                        nameField.Text = "Steam (" + child.Value <string>() + ")";
                    }
                }
                else if (lkey == "shared_secret")
                {
                    auth.SecretKey = Convert.FromBase64String(child.Value <string>());
                }
            }

            auth.SteamData = token.ToString(Formatting.None);

            Authenticator.AuthenticatorData = auth;

            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Form loaded event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ShowSteamSecretForm_Load(object sender, EventArgs e)
        {
            this.revocationcodeField.SecretMode = true;
            this.deviceidField.SecretMode       = true;
            this.steamdataField.SecretMode      = false;

            SteamAuthenticator authenticator = CurrentAuthenticator.AuthenticatorData as SteamAuthenticator;

            this.deviceidField.Text = authenticator.DeviceId;
            if (string.IsNullOrEmpty(authenticator.SteamData) == false && authenticator.SteamData[0] == '{')
            {
                this.revocationcodeField.Text = JObject.Parse(authenticator.SteamData).SelectToken("revocation_code").Value <string>();
                if (authenticator.SteamData.IndexOf("shared_secret") != -1)
                {
                    this.steamdataField.SecretMode = true;
                    this.steamdataField.Text       = authenticator.SteamData;
                    this.steamdataField.ForeColor  = SystemColors.ControlText;
                }
            }
            else
            {
                this.revocationcodeField.Text = authenticator.SteamData;
            }
        }
Beispiel #4
0
		/// <summary>
		/// Create a new SteamClient
		/// </summary>
		public SteamClient(SteamAuthenticator auth, string session = null)
		{
			this.Authenticator = auth;
			this.Session = new SteamSession(session);

			if (this.Session.Confirmations != null)
			{
				if (this.IsLoggedIn() == false)
				{
					this.Session.Confirmations = null;
				}
				else
				{
					Task.Factory.StartNew(() =>
					{
						Refresh();
						PollConfirmations(this.Session.Confirmations);
					});
				}
			}
		}
Beispiel #5
0
        /// <summary>
        /// Verify and create the authenticator if needed
        /// </summary>
        /// <returns>true is successful</returns>
        private bool verifyAuthenticator(string privatekey)
        {
            if (string.IsNullOrEmpty(privatekey) == true)
            {
                return(false);
            }

            this.Authenticator.Name = nameField.Text;

            int digits = (this.Authenticator.AuthenticatorData != null ? this.Authenticator.AuthenticatorData.CodeDigits : GoogleAuthenticator.DEFAULT_CODE_DIGITS);

            if (string.IsNullOrEmpty(digitsField.Text) == true || int.TryParse(digitsField.Text, out digits) == false || digits <= 0)
            {
                return(false);
            }

            WinAuth.Authenticator.HMACTypes hmac = WinAuth.Authenticator.HMACTypes.SHA1;
#if NETFX_3
            try
            {
                hmac = (WinAuth.Authenticator.HMACTypes)Enum.Parse(typeof(WinAuth.Authenticator.HMACTypes), (string)hashField.SelectedItem, true);
            }
            catch (Exception) { }
#else
            Enum.TryParse <WinAuth.Authenticator.HMACTypes>((string)hashField.SelectedItem, out hmac);
#endif

            string authtype = timeBasedRadio.Checked == true ? TOTP : HOTP;

            int period = 0;
            if (string.IsNullOrEmpty(intervalField.Text) == true || int.TryParse(intervalField.Text, out period) == false || period <= 0)
            {
                return(false);
            }

            long counter = 0;

            // if this is a URL, pull it down
            Uri   uri;
            Match match;
            if (Regex.IsMatch(privatekey, "https?://.*") == true && Uri.TryCreate(privatekey, UriKind.Absolute, out uri) == true)
            {
                try
                {
                    var request = (HttpWebRequest)WebRequest.Create(uri);
                    request.AllowAutoRedirect = true;
                    request.Timeout           = 20000;
                    request.UserAgent         = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)";
                    using (var response = (HttpWebResponse)request.GetResponse())
                    {
                        if (response.StatusCode == HttpStatusCode.OK && response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) == true)
                        {
                            using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(response.GetResponseStream()))
                            {
                                IBarcodeReader reader = new BarcodeReader();
                                var            result = reader.Decode(bitmap);
                                if (result != null)
                                {
                                    privatekey = HttpUtility.UrlDecode(result.Text);
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    WinAuthForm.ErrorDialog(this.Owner, "Cannot load QR code image from " + privatekey, ex);
                    return(false);
                }
            }
            else if ((match = Regex.Match(privatekey, @"data:image/([^;]+);base64,(.*)", RegexOptions.IgnoreCase)).Success == true)
            {
                byte[] imagedata = Convert.FromBase64String(match.Groups[2].Value);
                using (MemoryStream ms = new MemoryStream(imagedata))
                {
                    using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(ms))
                    {
                        IBarcodeReader reader = new BarcodeReader();
                        var            result = reader.Decode(bitmap);
                        if (result != null)
                        {
                            privatekey = HttpUtility.UrlDecode(result.Text);
                        }
                    }
                }
            }
            else if (IsValidFile(privatekey) == true)
            {
                // assume this is the image file
                using (Bitmap bitmap = (Bitmap)Bitmap.FromFile(privatekey))
                {
                    IBarcodeReader reader = new BarcodeReader();
                    var            result = reader.Decode(bitmap);
                    if (result != null)
                    {
                        privatekey = result.Text;
                    }
                }
            }

            string issuer = null;
            string serial = null;

            // check for otpauth://, e.g. "otpauth://totp/[email protected]?secret=IHZJDKAEEC774BMUK3GX6SA"
            match = Regex.Match(privatekey, @"otpauth://([^/]+)/([^?]+)\?(.*)", RegexOptions.IgnoreCase);
            if (match.Success == true)
            {
                authtype = match.Groups[1].Value.ToLower();
                string label = match.Groups[2].Value;
                int    p     = label.IndexOf(":");
                if (p != -1)
                {
                    issuer = label.Substring(0, p);
                    label  = label.Substring(p + 1);
                }

                NameValueCollection qs = WinAuthHelper.ParseQueryString(match.Groups[3].Value);
                privatekey = qs["secret"] ?? privatekey;
                int querydigits;
                if (int.TryParse(qs["digits"], out querydigits) && querydigits != 0)
                {
                    digits = querydigits;
                }
                if (qs["counter"] != null)
                {
                    long.TryParse(qs["counter"], out counter);
                }
                issuer = qs["issuer"];
                if (string.IsNullOrEmpty(issuer) == false)
                {
                    label = issuer + (string.IsNullOrEmpty(label) == false ? " (" + label + ")" : string.Empty);
                }
                serial = qs["serial"];
                if (string.IsNullOrEmpty(label) == false)
                {
                    this.Authenticator.Name = this.nameField.Text = label;
                }
                string periods = qs["period"];
                if (string.IsNullOrEmpty(periods) == false)
                {
                    int.TryParse(periods, out period);
                }
                if (qs["algorithm"] != null)
                {
#if NETFX_3
                    try
                    {
                        hmac = (WinAuth.Authenticator.HMACTypes)Enum.Parse(typeof(WinAuth.Authenticator.HMACTypes), qs["algorithm"], true);
                        hashField.SelectedItem = hmac.ToString();
                    }
                    catch (Exception) { }
#else
                    if (Enum.TryParse <WinAuth.Authenticator.HMACTypes>(qs["algorithm"], true, out hmac) == true)
                    {
                        hashField.SelectedItem = hmac.ToString();
                    }
#endif
                }
            }

            // just get the hex chars
            privatekey = Regex.Replace(privatekey, @"[^0-9a-z]", "", RegexOptions.IgnoreCase);
            if (privatekey.Length == 0)
            {
                WinAuthForm.ErrorDialog(this.Owner, "The secret code is not valid");
                return(false);
            }

            try
            {
                Authenticator auth;
                if (authtype == TOTP)
                {
                    if (string.Compare(issuer, "BattleNet", true) == 0)
                    {
                        if (string.IsNullOrEmpty(serial) == true)
                        {
                            throw new ApplicationException("Battle.net Authenticator does not have a serial");
                        }
                        serial = serial.ToUpper();
                        if (Regex.IsMatch(serial, @"^[A-Z]{2}-?[\d]{4}-?[\d]{4}-?[\d]{4}$") == false)
                        {
                            throw new ApplicationException("Invalid serial for Battle.net Authenticator");
                        }
                        auth = new BattleNetAuthenticator();
                        ((BattleNetAuthenticator)auth).SecretKey = Base32.getInstance().Decode(privatekey);
                        ((BattleNetAuthenticator)auth).Serial    = serial;

                        issuer = string.Empty;
                    }
                    else if (issuer == "Steam")
                    {
                        auth = new SteamAuthenticator();
                        ((SteamAuthenticator)auth).SecretKey = Base32.getInstance().Decode(privatekey);
                        ((SteamAuthenticator)auth).Serial    = string.Empty;
                        ((SteamAuthenticator)auth).DeviceId  = string.Empty;
                        //((SteamAuthenticator)auth).RevocationCode = string.Empty;
                        ((SteamAuthenticator)auth).SteamData = string.Empty;

                        this.Authenticator.Skin = null;

                        issuer = string.Empty;
                    }
                    else
                    {
                        auth = new GoogleAuthenticator();
                        ((GoogleAuthenticator)auth).Enroll(privatekey);
                    }
                    timer.Enabled          = true;
                    codeProgress.Visible   = true;
                    timeBasedRadio.Checked = true;
                }
                else if (authtype == HOTP)
                {
                    auth = new HOTPAuthenticator();
                    if (counterField.Text.Trim().Length != 0)
                    {
                        long.TryParse(counterField.Text.Trim(), out counter);
                    }
                    ((HOTPAuthenticator)auth).Enroll(privatekey, counter); // start with the next code
                    timer.Enabled             = false;
                    codeProgress.Visible      = false;
                    counterBasedRadio.Checked = true;
                }
                else
                {
                    WinAuthForm.ErrorDialog(this.Owner, "Only TOTP or HOTP authenticators are supported");
                    return(false);
                }

                auth.HMACType   = hmac;
                auth.CodeDigits = digits;
                auth.Period     = period;
                this.Authenticator.AuthenticatorData = auth;

                if (digits > 5)
                {
                    codeField.SpaceOut = digits / 2;
                }
                else
                {
                    codeField.SpaceOut = 0;
                }

                //string key = Base32.getInstance().Encode(this.Authenticator.AuthenticatorData.SecretKey);
                this.codeField.Text = auth.CurrentCode;

                codeProgress.Maximum = period;

                if (!(auth is HOTPAuthenticator) && auth.ServerTimeDiff == 0L && SyncErrorWarned == false)
                {
                    SyncErrorWarned = true;
                    MessageBox.Show(this, string.Format(strings.AuthenticatorSyncError, "Google"), WinAuthMain.APPLICATION_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
            catch (Exception irre)
            {
                WinAuthForm.ErrorDialog(this.Owner, "Unable to create the authenticator. The secret code is probably invalid.", irre);
                return(false);
            }

            return(true);
        }
Beispiel #6
0
		/// <summary>
		/// Import a file containing authenticators in the KeyUriFormat. The file might be plain text, encrypted zip or encrypted pgp.
		/// </summary>
		/// <param name="parent">parent Form</param>
		/// <param name="file">file name to import</param>
		/// <returns>list of imported authenticators</returns>
		public static List<WinAuthAuthenticator> ImportAuthenticators(Form parent, string file)
		{
			List<WinAuthAuthenticator> authenticators = new List<WinAuthAuthenticator>();

			string password = null;
			string pgpKey = null;

			StringBuilder lines = new StringBuilder();
			bool retry;
			do
			{
				retry = false;
				lines.Length = 0;

				// open the zip file
				if (string.Compare(Path.GetExtension(file), ".zip", true) == 0)
				{
					using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read))
					{
						ZipFile zip = null;
						try
						{
							zip = new ZipFile(fs);
							if (string.IsNullOrEmpty(password) == false)
							{
								zip.Password = password;
							}

							byte[] buffer = new byte[4096];
							foreach (ZipEntry entry in zip)
							{
								if (entry.IsFile == false || string.Compare(Path.GetExtension(entry.Name), ".txt", true) != 0)
								{
									continue;
								}

								// read file out
								Stream zs = zip.GetInputStream(entry);
								using (var ms = new MemoryStream())
								{
									StreamUtils.Copy(zs, ms, buffer);

									// get as string and append
									ms.Seek(0, SeekOrigin.Begin);
									using (var sr = new StreamReader(ms))
									{
										lines.Append(sr.ReadToEnd()).Append(Environment.NewLine);
									}
								}
							}
						}
						catch (ZipException ex)
						{
							if (ex.Message.IndexOf("password") != -1)
							{
								// already have a password
								if (string.IsNullOrEmpty(password) == false)
								{
									WinAuthForm.ErrorDialog(parent, strings.InvalidPassword, ex.InnerException, MessageBoxButtons.OK);
								}

								// need password
								GetPasswordForm form = new GetPasswordForm();
								if (form.ShowDialog(parent) == DialogResult.Cancel)
								{
									return null;
								}
								password = form.Password;
								retry = true;
								continue;
							}

							throw;
						}
						finally
						{
							if (zip != null)
							{
								zip.IsStreamOwner = true;
								zip.Close();
							}
						}
					}
				}
				else if (string.Compare(Path.GetExtension(file), ".pgp", true) == 0)
				{
					string encoded = File.ReadAllText(file);
					if (string.IsNullOrEmpty(pgpKey) == true)
					{
						// need password
						GetPGPKeyForm form = new GetPGPKeyForm();
						if (form.ShowDialog(parent) == DialogResult.Cancel)
						{
							return null;
						}
						pgpKey = form.PGPKey;
						password = form.Password;
						retry = true;
						continue;
					}
					try
					{
						string line = PGPDecrypt(encoded, pgpKey, password);
						lines.Append(line);
					}
					catch (Exception ex)
					{
						WinAuthForm.ErrorDialog(parent, strings.InvalidPassword, ex.InnerException, MessageBoxButtons.OK);

						pgpKey = null;
						password = null;
						retry = true;
						continue;
					}
				}
				else // read a plain text file
				{
					lines.Append(File.ReadAllText(file));
				}
			} while (retry);

			int linenumber = 0;
			try
			{
				using (var sr = new StringReader(lines.ToString()))
				{
					string line;
					while ((line = sr.ReadLine()) != null)
					{
						linenumber++;

						// ignore blank lines or comments
						line = line.Trim();
						if (line.Length == 0 || line.IndexOf("#") == 0)
						{
							continue;
						}

						// parse and validate URI
						var uri = new Uri(line);

						// we only support "otpauth"
						if (uri.Scheme != "otpauth")
						{
							throw new ApplicationException("Import only supports otpauth://");
						}
						// we only support totp (not hotp)
						if (uri.Host != "totp" && uri.Host != "hotp")
						{
							throw new ApplicationException("Import only supports otpauth://totp/ or otpauth://hotp/");
						}

						// get the label and optional issuer
						string issuer = string.Empty;
						string label = (string.IsNullOrEmpty(uri.LocalPath) == false ? uri.LocalPath.Substring(1) : string.Empty); // skip past initial /
						int p = label.IndexOf(":");
						if (p != -1)
						{
							issuer = label.Substring(0, p);
							label = label.Substring(p + 1);
						}
						// + aren't decoded
						label = label.Replace("+", " ");

						var query = HttpUtility.ParseQueryString(uri.Query);
						string secret = query["secret"];
						if (string.IsNullOrEmpty(secret) == true)
						{
							throw new ApplicationException("Authenticator does not contain secret");
						}

						string counter = query["counter"];
						if (uri.Host == "hotp" && string.IsNullOrEmpty(counter) == true)
						{
							throw new ApplicationException("HOTP authenticator should have a counter");
						}

						WinAuthAuthenticator importedAuthenticator = new WinAuthAuthenticator();
						importedAuthenticator.AutoRefresh = false;
						//
						Authenticator auth;
						if (string.Compare(issuer, "BattleNet", true) == 0)
						{
							string serial = query["serial"];
							if (string.IsNullOrEmpty(serial) == true)
							{
								throw new ApplicationException("Battle.net Authenticator does not have a serial");
							}
							serial = serial.ToUpper();
							if (Regex.IsMatch(serial, @"^[A-Z]{2}-?[\d]{4}-?[\d]{4}-?[\d]{4}$") == false)
							{
								throw new ApplicationException("Invalid serial for Battle.net Authenticator");
							}
							auth = new BattleNetAuthenticator();
							//char[] decoded = Base32.getInstance().Decode(secret).Select(c => Convert.ToChar(c)).ToArray(); // this is hex string values
							//string hex = new string(decoded);
							//((BattleNetAuthenticator)auth).SecretKey = Authenticator.StringToByteArray(hex);

							((BattleNetAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);

							((BattleNetAuthenticator)auth).Serial = serial;

							issuer = string.Empty;
						}
						else if (string.Compare(issuer, "Steam", true) == 0)
						{
							auth = new SteamAuthenticator();
							((SteamAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
							((SteamAuthenticator)auth).Serial = string.Empty;
							((SteamAuthenticator)auth).DeviceId = string.Empty;
							((SteamAuthenticator)auth).RevocationCode = string.Empty;
							issuer = string.Empty;
						}
						else if (uri.Host == "hotp")
						{
							auth = new HOTPAuthenticator();
							((HOTPAuthenticator)auth).SecretKey = Base32.getInstance().Decode(secret);
							((HOTPAuthenticator)auth).Counter = int.Parse(counter);
							
							if (string.IsNullOrEmpty(issuer) == false)
							{
								auth.Issuer = issuer;
							}
						}
						else // if (string.Compare(issuer, "Google", true) == 0)
						{
							auth = new GoogleAuthenticator();
							((GoogleAuthenticator)auth).Enroll(secret);

							if (string.Compare(issuer, "Google", true) == 0)
							{
								issuer = string.Empty;
							}
							else if (string.IsNullOrEmpty(issuer) == false)
							{
								auth.Issuer = issuer;
							}
						}
						//
						int digits = 0;
						int.TryParse(query["digits"], out digits);
						if (digits != 0)
						{
							auth.CodeDigits = digits;
						}
						//
						if (label.Length != 0)
						{
							importedAuthenticator.Name = (issuer.Length != 0 ? issuer + " (" + label + ")" : label);
						}
						else if (issuer.Length != 0)
						{
							importedAuthenticator.Name = issuer;
						}
						else
						{
							importedAuthenticator.Name = "Imported";
						}
						//
						importedAuthenticator.AuthenticatorData = auth;

						// set the icon
						string icon = query["icon"];
						if (string.IsNullOrEmpty(icon) == false)
						{
							if (icon.StartsWith("base64:") == true)
							{
								string b64 = Convert.ToBase64String(Base32.getInstance().Decode(icon.Substring(7)));
								importedAuthenticator.Skin = "base64:" + b64;
							}
							else
							{
								importedAuthenticator.Skin = icon + "Icon.png";
							}
						}

						// sync
						importedAuthenticator.Sync();

						authenticators.Add(importedAuthenticator);
					}
				}

				return authenticators;
			}
			catch (UriFormatException ex)
			{
				throw new ImportException(string.Format(strings.ImportInvalidUri, linenumber), ex);
			}
			catch (Exception ex)
			{
				throw new ImportException(string.Format(strings.ImportError, linenumber, ex.Message), ex);
			}
		}
Beispiel #7
0
        /// <summary>
        ///     Import an authenticator from the uuid and steamguard files
        /// </summary>
        /// <returns>true if successful</returns>
        private bool ImportSteamGuard()
        {
            var uuid = importUuid.Text.Trim();

            if (uuid.Length == 0)
            {
                WinAuthForm.ErrorDialog(this, "Please enter the contents of the steam.uuid.xml file or your DeviceId");
                return(false);
            }

            var steamguard = importSteamguard.Text.Trim();

            if (steamguard.Length == 0)
            {
                WinAuthForm.ErrorDialog(this, "Please enter the contents of your SteamGuard file");
                return(false);
            }

            // check the deviceid
            string deviceId;

            if (uuid.IndexOf("?xml") != -1)
            {
                try
                {
                    var doc = new XmlDocument();
                    doc.LoadXml(uuid);
                    var node = doc.SelectSingleNode("//string[@name='uuidKey']");
                    if (node == null)
                    {
                        WinAuthForm.ErrorDialog(this, "Cannot find uuidKey in xml");
                        return(false);
                    }

                    deviceId = node.InnerText;
                }
                catch (Exception ex)
                {
                    WinAuthForm.ErrorDialog(this, "Invalid uuid xml: " + ex.Message);
                    return(false);
                }
            }
            else
            {
                deviceId = uuid;
            }

            if (string.IsNullOrEmpty(deviceId) || Regex.IsMatch(deviceId, @"android:[0-9abcdef-]+",
                                                                RegexOptions.Singleline | RegexOptions.IgnoreCase) == false)
            {
                WinAuthForm.ErrorDialog(this, "Invalid deviceid, expecting \"android:NNNN...\"");
                return(false);
            }

            // check the steamguard
            byte[] secret;
            string serial;

            try
            {
                var json = JObject.Parse(steamguard);

                var node = json.SelectToken("shared_secret");
                if (node == null)
                {
                    throw new ApplicationException("no shared_secret");
                }
                secret = Convert.FromBase64String(node.Value <string>());

                node = json.SelectToken("serial_number");
                if (node == null)
                {
                    throw new ApplicationException("no serial_number");
                }
                serial = node.Value <string>();
            }
            catch (Exception ex)
            {
                WinAuthForm.ErrorDialog(this, "Invalid SteamGuard JSON contents: " + ex.Message);
                return(false);
            }

            var auth = new SteamAuthenticator();

            auth.SecretKey = secret;
            auth.Serial    = serial;
            auth.SteamData = steamguard;
            auth.DeviceId  = deviceId;

            Authenticator.AuthenticatorData = auth;

            return(true);
        }
		/// <summary>
		/// Import the selected SDA account
		/// </summary>
		/// <returns>true if successful</returns>
		private bool ImportSDA()
		{
			var entry = this.importSDAList.SelectedItem as ImportedSDAEntry;
			if (entry == null)
			{
				WinAuthForm.ErrorDialog(this, "Please load and select a Steam account");
				return false;
			}

			SteamAuthenticator auth = new SteamAuthenticator();
			var token = JObject.Parse(entry.json);
			foreach (var prop in token.Root.Children().ToList())
			{
				var child = token.SelectToken(prop.Path);

				string lkey = prop.Path.ToLower();
				if (lkey == "fully_enrolled" || lkey == "session")
				{
					prop.Remove();
				}
				else if (lkey == "device_id")
				{
					auth.DeviceId = child.Value<string>();
					prop.Remove();
				}
				else if (lkey == "serial_number")
				{
					auth.Serial = child.Value<string>();
				}
				else if (lkey == "account_name")
				{
					if (this.nameField.Text.Length == 0)
					{
						this.nameField.Text = "Steam (" + child.Value<string>() + ")";
					}
				}
				else if (lkey == "shared_secret")
				{
					auth.SecretKey = Convert.FromBase64String(child.Value<string>());
				}
			}
			auth.SteamData = token.ToString(Newtonsoft.Json.Formatting.None);

			this.Authenticator.AuthenticatorData = auth;

			return true;
		}
		/// <summary>
		/// Import an authenticator from the uuid and steamguard files
		/// </summary>
		/// <returns>true if successful</returns>
		private bool ImportSteamGuard()
		{
			string uuid = importUuid.Text.Trim();
			if (uuid.Length == 0)
			{
				WinAuthForm.ErrorDialog(this, "Please enter the contents of the steam.uuid.xml file or your DeviceId");
				return false;
			}
			string steamguard = this.importSteamguard.Text.Trim();
			if (steamguard.Length == 0)
			{
				WinAuthForm.ErrorDialog(this, "Please enter the contents of your SteamGuard file");
				return false;
			}

			// check the deviceid
			string deviceId;
			if (uuid.IndexOf("?xml") != -1)
			{
				try
				{
					XmlDocument doc = new XmlDocument();
					doc.LoadXml(uuid);
					var node = doc.SelectSingleNode("//string[@name='uuidKey']");
					if (node == null)
					{
						WinAuthForm.ErrorDialog(this, "Cannot find uuidKey in xml");
						return false;
					}

					deviceId = node.InnerText;
				}
				catch (Exception ex)
				{
					WinAuthForm.ErrorDialog(this, "Invalid uuid xml: " + ex.Message);
					return false;
				}
			}
			else
			{
				deviceId = uuid;
			}
			if (string.IsNullOrEmpty(deviceId) || Regex.IsMatch(deviceId, @"android:[0-9abcdef-]+", RegexOptions.Singleline | RegexOptions.IgnoreCase) == false)
			{
				WinAuthForm.ErrorDialog(this, "Invalid deviceid, expecting \"android:NNNN...\"");
				return false;
			}

			// check the steamguard
			byte[] secret;
			string serial;
			try
			{
				var json = JObject.Parse(steamguard);

				var node = json.SelectToken("shared_secret");
				if (node == null)
				{
					throw new ApplicationException("no shared_secret");
				}			
				secret = Convert.FromBase64String(node.Value<string>());

				node = json.SelectToken("serial_number");
				if (node == null)
				{
					throw new ApplicationException("no serial_number");
				}
				serial = node.Value<string>();
			}
			catch (Exception ex)
			{
				WinAuthForm.ErrorDialog(this, "Invalid SteamGuard JSON contents: " + ex.Message);
				return false;
			}

			SteamAuthenticator auth = new SteamAuthenticator();
			auth.SecretKey = secret;
			auth.Serial = serial;
			auth.SteamData = steamguard;
			auth.DeviceId = deviceId;

			this.Authenticator.AuthenticatorData = auth;

			return true;
		}
Beispiel #10
0
		/// <summary>
		/// Verify and create the authenticator if needed
		/// </summary>
		/// <returns>true is successful</returns>
		private bool verifyAuthenticator(string privatekey)
		{
			if (string.IsNullOrEmpty(privatekey) == true)
			{
				return false;
			}

			this.Authenticator.Name = nameField.Text;

			int digits = (this.Authenticator.AuthenticatorData != null ? this.Authenticator.AuthenticatorData.CodeDigits : GoogleAuthenticator.DEFAULT_CODE_DIGITS);

			string authtype = timeBasedRadio.Checked == true ? TOTP : HOTP;

			long counter = 0;

			// if this is a URL, pull it down
			Uri uri;
			Match match;
			if (Regex.IsMatch(privatekey, "https?://.*") == true && Uri.TryCreate(privatekey, UriKind.Absolute, out uri) == true)
			{
				try
				{
					var request = (HttpWebRequest)WebRequest.Create(uri);
					request.AllowAutoRedirect = true;
					request.Timeout = 20000;
					request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)";
					using (var response = (HttpWebResponse)request.GetResponse())
					{
						if (response.StatusCode == HttpStatusCode.OK && response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) == true)
						{
							using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(response.GetResponseStream()))
							{
								IBarcodeReader reader = new BarcodeReader();
								var result = reader.Decode(bitmap);
								if (result != null)
								{
									privatekey = HttpUtility.UrlDecode(result.Text);
								}
							}
						}
					}
				}
				catch (Exception ex)
				{
					WinAuthForm.ErrorDialog(this.Owner, "Cannot load QR code image from " + privatekey, ex);
					return false;
				}
			}
			else if ((match = Regex.Match(privatekey, @"data:image/([^;]+);base64,(.*)", RegexOptions.IgnoreCase)).Success == true)
			{
				byte[] imagedata = Convert.FromBase64String(match.Groups[2].Value);
				using (MemoryStream ms = new MemoryStream(imagedata))
				{
					using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(ms))
					{
						IBarcodeReader reader = new BarcodeReader();
						var result = reader.Decode(bitmap);
						if (result != null)
						{
							privatekey = HttpUtility.UrlDecode(result.Text);
						}
					}
				}
			}
			else if (IsValidFile(privatekey) == true)
			{
				// assume this is the image file
				using (Bitmap bitmap = (Bitmap)Bitmap.FromFile(privatekey))
				{
					IBarcodeReader reader = new BarcodeReader();
					var result = reader.Decode(bitmap);
					if (result != null)
					{
						privatekey = result.Text;
					}
				}
			}

			string issuer = null;
			string serial = null;

			// check for otpauth://, e.g. "otpauth://totp/[email protected]?secret=IHZJDKAEEC774BMUK3GX6SA"
			match = Regex.Match(privatekey, @"otpauth://([^/]+)/([^?]+)\?(.*)", RegexOptions.IgnoreCase);
			if (match.Success == true)
			{
				authtype = match.Groups[1].Value.ToLower();
				string label = match.Groups[2].Value;
				int p = label.IndexOf(":");
				if (p != -1)
				{
					issuer = label.Substring(0, p);
					label = label.Substring(p + 1);
				}

				NameValueCollection qs = WinAuthHelper.ParseQueryString(match.Groups[3].Value);
				privatekey = qs["secret"] ?? privatekey;
				int querydigits;
				if (int.TryParse(qs["digits"], out querydigits) && querydigits != 0)
				{
					digits = querydigits;
				}
				if (qs["counter"] != null)
				{
					long.TryParse(qs["counter"], out counter);
				}
				issuer = qs["issuer"];
				if (string.IsNullOrEmpty(issuer) == false)
				{
					label = issuer + (string.IsNullOrEmpty(label) == false ? " (" + label + ")" : string.Empty);
				}
				serial = qs["serial"];

				if (string.IsNullOrEmpty(label) == false)
				{
					this.Authenticator.Name = this.nameField.Text = label;
				}
			}

			// just get the hex chars
			privatekey = Regex.Replace(privatekey, @"[^0-9a-z]", "", RegexOptions.IgnoreCase);
			if (privatekey.Length == 0)
			{
				WinAuthForm.ErrorDialog(this.Owner, "The secret code is not valid");
				return false;
			}

			try
			{
				Authenticator auth;
				if (authtype == TOTP)
				{
					if (string.Compare(issuer, "BattleNet", true) == 0)
					{
						if (string.IsNullOrEmpty(serial) == true)
						{
							throw new ApplicationException("Battle.net Authenticator does not have a serial");
						}
						serial = serial.ToUpper();
						if (Regex.IsMatch(serial, @"^[A-Z]{2}-?[\d]{4}-?[\d]{4}-?[\d]{4}$") == false)
						{
							throw new ApplicationException("Invalid serial for Battle.net Authenticator");
						}
						auth = new BattleNetAuthenticator();
						((BattleNetAuthenticator)auth).SecretKey = Base32.getInstance().Decode(privatekey);
						((BattleNetAuthenticator)auth).Serial = serial;

						issuer = string.Empty;
					}
					else if (issuer == "Steam")
					{
						auth = new SteamAuthenticator();
						((SteamAuthenticator)auth).SecretKey = Base32.getInstance().Decode(privatekey);
						((SteamAuthenticator)auth).Serial = string.Empty;
						((SteamAuthenticator)auth).DeviceId = string.Empty;
						//((SteamAuthenticator)auth).RevocationCode = string.Empty;
						((SteamAuthenticator)auth).SteamData = string.Empty;

						this.Authenticator.Skin = null;

						issuer = string.Empty;
					}
					else
					{
						auth = new GoogleAuthenticator();
						((GoogleAuthenticator)auth).Enroll(privatekey);
					}
					timer.Enabled = true;
					codeProgress.Visible = true;
					timeBasedRadio.Checked = true;
				}
				else if (authtype == HOTP)
				{
					auth = new HOTPAuthenticator();
					if (counterField.Text.Trim().Length != 0)
					{
						long.TryParse(counterField.Text.Trim(), out counter);
					}
					((HOTPAuthenticator)auth).Enroll(privatekey, counter); // start with the next code
					timer.Enabled = false;
					codeProgress.Visible = false;
					counterBasedRadio.Checked = true;
				}
				else
				{
					WinAuthForm.ErrorDialog(this.Owner, "Only TOTP or HOTP authenticators are supported");
					return false;
				}

				auth.CodeDigits = digits;
				this.Authenticator.AuthenticatorData = auth;

				if (digits > 5)
				{
					codeField.SpaceOut = digits / 2;
				}
				else
				{
					codeField.SpaceOut = 0;
				}

				//string key = Base32.getInstance().Encode(this.Authenticator.AuthenticatorData.SecretKey);
				this.codeField.Text = auth.CurrentCode;

				if (!(auth is HOTPAuthenticator) && auth.ServerTimeDiff == 0L && SyncErrorWarned == false)
				{
					SyncErrorWarned = true;
					MessageBox.Show(this, string.Format(strings.AuthenticatorSyncError, "Google"), WinAuthMain.APPLICATION_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Warning);
				}
			}
			catch (Exception irre)
			{
				WinAuthForm.ErrorDialog(this.Owner, "Unable to create the authenticator. The secret code is probably invalid.", irre);
				return false;
			}

			return true;
		}