Example #1
0
        /// <summary>
        ///     Read the saved Xml to load the hotkey
        /// </summary>
        /// <param name="reader">XmlReader</param>
        public void ReadXml(XmlReader reader)
        {
            reader.MoveToContent();

            if (reader.IsEmptyElement)
            {
                reader.Read();
                return;
            }

            reader.Read();
            while (reader.EOF == false)
            {
                if (reader.IsStartElement())
                {
                    switch (reader.Name)
                    {
                    case "modifiers":
                        Modifiers = (WinAPI.KeyModifiers)BitConverter.ToInt32(
                            Authenticator.StringToByteArray(reader.ReadElementContentAsString()), 0);
                        break;

                    case "key":
                        Key = (WinAPI.VirtualKeyCode)BitConverter.ToUInt16(
                            Authenticator.StringToByteArray(reader.ReadElementContentAsString()), 0);
                        break;

                    case "action":
                        Action = (HotKeyActions)Enum.Parse(typeof(HotKeyActions),
                                                           reader.ReadElementContentAsString(), true);
                        break;

                    case "window":
                        Window = reader.ReadElementContentAsString();
                        break;

                    case "advanced":
                        Advanced = reader.ReadElementContentAsString();
                        break;

                    default:
                        reader.Skip();
                        break;
                    }
                }
                else
                {
                    reader.Read();
                    break;
                }
            }
        }
Example #2
0
 /// <summary>
 /// Create a new HotKeySequence from a loaded string
 /// </summary>
 /// <param name="data"></param>
 public HoyKeySequence(string data)
 {
     if (string.IsNullOrEmpty(data) == false)
     {
         Match match = Regex.Match(data, @"([0-9a-fA-F]{8})([0-9a-fA-F]{4})\t([^\t]*)\t(Y|N)(.*)", RegexOptions.Multiline);
         if (match.Success == true)
         {
             Modifiers   = (WinAPI.KeyModifiers)BitConverter.ToInt32(Authenticator.StringToByteArray(match.Groups[1].Value), 0);
             HotKey      = (WinAPI.VirtualKeyCode)BitConverter.ToUInt16(Authenticator.StringToByteArray(match.Groups[2].Value), 0);
             WindowTitle = match.Groups[3].Value;
             Advanced    = (match.Groups[4].Value == "Y");
             if (Advanced == true)
             {
                 AdvancedScript = match.Groups[5].Value;
             }
         }
     }
 }
Example #3
0
        protected bool ReadXmlInternal(XmlReader reader, string password = null)
        {
            bool changed = false;

            decimal version;

            if (decimal.TryParse(reader.GetAttribute("version"), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out version) == true)
            {
                Version = version;

                if (version > WinAuthConfig.CURRENTVERSION)
                {
                    // ensure we don't overwrite a newer config
                    throw new WinAuthInvalidNewerConfigException(string.Format(strings.ConfigIsNewer, version));
                }
            }

            string encrypted = reader.GetAttribute("encrypted");

            this.PasswordType = Authenticator.DecodePasswordTypes(encrypted);
            if (this.PasswordType != Authenticator.PasswordTypes.None)
            {
                // read the encrypted text from the node
                string data = reader.ReadElementContentAsString();
                // decrypt
                YubiKey yubi = null;
                if ((this.PasswordType & (Authenticator.PasswordTypes.YubiKeySlot1 | Authenticator.PasswordTypes.YubiKeySlot2)) != 0 /* && this.Yubi == null */)
                {
                    yubi = YubiKey.CreateInstance();
                }
                data = Authenticator.DecryptSequence(data, this.PasswordType, password, yubi);

                using (MemoryStream ms = new MemoryStream(Authenticator.StringToByteArray(data)))
                {
                    reader  = XmlReader.Create(ms);
                    changed = ReadXml(reader, password);
                }

                this.PasswordType = Authenticator.DecodePasswordTypes(encrypted);
                this.Password     = password;
                this.Yubi         = yubi;

                return(changed);
            }

            reader.MoveToContent();
            if (reader.IsEmptyElement)
            {
                reader.Read();
                return(changed);
            }

            bool   defaultAutoRefresh = true;
            bool   defaultAllowCopy   = false;
            bool   defaultCopyOnCode  = false;
            bool   defaultHideSerial  = true;
            string defaultSkin        = null;

            reader.Read();
            while (reader.EOF == false)
            {
                if (reader.IsStartElement())
                {
                    switch (reader.Name)
                    {
                    case "config":
                        changed = ReadXmlInternal(reader, password) || changed;
                        break;

                    // 3.2 has new layout
                    case "data":
                    {
                        encrypted         = reader.GetAttribute("encrypted");
                        this.PasswordType = Authenticator.DecodePasswordTypes(encrypted);
                        if (this.PasswordType != Authenticator.PasswordTypes.None)
                        {
                            string md5 = reader.GetAttribute("md5");
                            // read the encrypted text from the node
                            string data = reader.ReadElementContentAsString();

                            using (var hasher = new MD5CryptoServiceProvider())
                            {
                                hasher.ComputeHash(Authenticator.StringToByteArray(data));
                            }

                            // decrypt
                            YubiKey yubi = null;
                            if ((this.PasswordType & (Authenticator.PasswordTypes.YubiKeySlot1 | Authenticator.PasswordTypes.YubiKeySlot2)) != 0 /* && this.Yubi == null */)
                            {
                                yubi = YubiKey.CreateInstance();
                            }
                            data = Authenticator.DecryptSequence(data, this.PasswordType, password, yubi);
                            byte[] plain = Authenticator.StringToByteArray(data);

                            using (MemoryStream ms = new MemoryStream(plain))
                            {
                                var datareader = XmlReader.Create(ms);
                                changed = ReadXmlInternal(datareader, password) || changed;
                            }

                            this.PasswordType = Authenticator.DecodePasswordTypes(encrypted);
                            this.Password     = password;
                            this.Yubi         = yubi;
                        }
                    }
                    break;

                    case "alwaysontop":
                        _alwaysOnTop = reader.ReadElementContentAsBoolean();
                        break;

                    case "usetrayicon":
                        _useTrayIcon = reader.ReadElementContentAsBoolean();
                        break;

                    case "notifyaction":
                        string s = reader.ReadElementContentAsString();
                        if (string.IsNullOrEmpty(s) == false)
                        {
                            try {
                                _notifyAction = (NotifyActions)Enum.Parse(typeof(NotifyActions), s, true);
                            }
                            catch (Exception) { }
                        }
                        break;

                    case "startwithwindows":
                        _startWithWindows = reader.ReadElementContentAsBoolean();
                        break;

                    case "autosize":
                        _autoSize = reader.ReadElementContentAsBoolean();
                        break;

                    case "left":
                        _position.X = reader.ReadElementContentAsInt();
                        break;

                    case "top":
                        _position.Y = reader.ReadElementContentAsInt();
                        break;

                    case "width":
                        _width = reader.ReadElementContentAsInt();
                        break;

                    case "height":
                        _height = reader.ReadElementContentAsInt();
                        break;

                    case "shadowtype":
                        _shadowType = reader.ReadElementContentAsString();
                        break;

                    case "pgpkey":
                        _pgpKey = reader.ReadElementContentAsString();
                        break;

                    case "settings":
                        XmlSerializer serializer = new XmlSerializer(typeof(setting[]), new XmlRootAttribute()
                        {
                            ElementName = "settings"
                        });
                        _settings = ((setting[])serializer.Deserialize(reader)).ToDictionary(e => e.Key, e => e.Value);
                        break;

                    // previous setting used as defaults for new
                    case "autorefresh":
                        defaultAutoRefresh = reader.ReadElementContentAsBoolean();
                        break;

                    case "allowcopy":
                        defaultAllowCopy = reader.ReadElementContentAsBoolean();
                        break;

                    case "copyoncode":
                        defaultCopyOnCode = reader.ReadElementContentAsBoolean();
                        break;

                    case "hideserial":
                        defaultHideSerial = reader.ReadElementContentAsBoolean();
                        break;

                    case "skin":
                        defaultSkin = reader.ReadElementContentAsString();
                        break;

                    case "WinAuthAuthenticator":
                        var wa = new WinAuthAuthenticator();
                        changed = wa.ReadXml(reader, password) || changed;
                        this.Add(wa);
                        if (this.CurrentAuthenticator == null)
                        {
                            this.CurrentAuthenticator = wa;
                        }
                        break;

                    // for old 2.x configs
                    case "authenticator":
                        var waold = new WinAuthAuthenticator();
                        waold.AuthenticatorData = Authenticator.ReadXmlv2(reader, password);
                        if (waold.AuthenticatorData is BattleNetAuthenticator)
                        {
                            waold.Name = "Battle.net";
                        }
                        else if (waold.AuthenticatorData is GuildWarsAuthenticator)
                        {
                            waold.Name = "GuildWars 2";
                        }
                        else if (waold.AuthenticatorData is GuildWarsAuthenticator)
                        {
                            waold.Name = "Authenticator";
                        }
                        this.Add(waold);
                        this.CurrentAuthenticator = waold;
                        waold.AutoRefresh         = defaultAutoRefresh;
                        waold.AllowCopy           = defaultAllowCopy;
                        waold.CopyOnCode          = defaultCopyOnCode;
                        waold.HideSerial          = defaultHideSerial;
                        break;

                    // old 2.x auto login script
                    case "autologin":
                        var hks = new HoyKeySequence();
                        hks.ReadXml(reader, password);
                        if (hks.HotKey != 0)
                        {
                            if (this.CurrentAuthenticator.HotKey == null)
                            {
                                this.CurrentAuthenticator.HotKey = new HotKey();
                            }
                            HotKey hotkey = this.CurrentAuthenticator.HotKey;
                            hotkey.Action    = HotKey.HotKeyActions.Inject;
                            hotkey.Key       = hks.HotKey;
                            hotkey.Modifiers = hks.Modifiers;
                            if (hks.WindowTitleRegex == true && string.IsNullOrEmpty(hks.WindowTitle) == false)
                            {
                                hotkey.Window = "/" + Regex.Escape(hks.WindowTitle);
                            }
                            else if (string.IsNullOrEmpty(hks.WindowTitle) == false)
                            {
                                hotkey.Window = hks.WindowTitle;
                            }
                            else if (string.IsNullOrEmpty(hks.ProcessName) == false)
                            {
                                hotkey.Window = hks.ProcessName;
                            }
                            if (hks.Advanced == true)
                            {
                                hotkey.Action   = HotKey.HotKeyActions.Advanced;
                                hotkey.Advanced = hks.AdvancedScript;
                            }
                        }
                        break;

                    default:
                        reader.Skip();
                        break;
                    }
                }
                else
                {
                    reader.Read();
                    break;
                }
            }

            return(changed);
        }
Example #4
0
        /// <summary>
        /// Write the data as xml into an XmlWriter
        /// </summary>
        /// <param name="writer">XmlWriter to write config</param>
        public void WriteXmlString(XmlWriter writer, bool includeFilename = false, bool includeSettings = true)
        {
            writer.WriteStartDocument(true);
            //
            if (includeFilename == true && string.IsNullOrEmpty(this.Filename) == false)
            {
                writer.WriteComment(this.Filename);
            }
            //
            writer.WriteStartElement("WinAuth");
            writer.WriteAttributeString("version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(2));
            //
            writer.WriteStartElement("alwaysontop");
            writer.WriteValue(this.AlwaysOnTop);
            writer.WriteEndElement();
            //
            writer.WriteStartElement("usetrayicon");
            writer.WriteValue(this.UseTrayIcon);
            writer.WriteEndElement();
            //
            writer.WriteStartElement("notifyaction");
            writer.WriteValue(Enum.GetName(typeof(NotifyActions), this.NotifyAction));
            writer.WriteEndElement();
            //
            writer.WriteStartElement("startwithwindows");
            writer.WriteValue(this.StartWithWindows);
            writer.WriteEndElement();
            //
            writer.WriteStartElement("autosize");
            writer.WriteValue(this.AutoSize);
            writer.WriteEndElement();
            //
            if (this.Position.IsEmpty == false)
            {
                writer.WriteStartElement("left");
                writer.WriteValue(this.Position.X);
                writer.WriteEndElement();
                writer.WriteStartElement("top");
                writer.WriteValue(this.Position.Y);
                writer.WriteEndElement();
            }
            //
            writer.WriteStartElement("width");
            writer.WriteValue(this.Width);
            writer.WriteEndElement();
            //
            writer.WriteStartElement("height");
            writer.WriteValue(this.Height);
            writer.WriteEndElement();
            //
            if (string.IsNullOrEmpty(this.ShadowType) == false)
            {
                writer.WriteStartElement("shadowtype");
                writer.WriteValue(this.ShadowType);
                writer.WriteEndElement();
            }
            //
            if (string.IsNullOrEmpty(this.PGPKey) == false)
            {
                writer.WriteStartElement("pgpkey");
                writer.WriteCData(this.PGPKey);
                writer.WriteEndElement();
            }

            if (PasswordType != Authenticator.PasswordTypes.None)
            {
                writer.WriteStartElement("data");

                StringBuilder encryptedTypes = new StringBuilder();
                if ((PasswordType & Authenticator.PasswordTypes.Explicit) != 0)
                {
                    encryptedTypes.Append("y");
                }
                if ((PasswordType & Authenticator.PasswordTypes.User) != 0)
                {
                    encryptedTypes.Append("u");
                }
                if ((PasswordType & Authenticator.PasswordTypes.Machine) != 0)
                {
                    encryptedTypes.Append("m");
                }
                if ((PasswordType & Authenticator.PasswordTypes.YubiKeySlot1) != 0)
                {
                    encryptedTypes.Append("a");
                }
                if ((PasswordType & Authenticator.PasswordTypes.YubiKeySlot2) != 0)
                {
                    encryptedTypes.Append("b");
                }
                writer.WriteAttributeString("encrypted", encryptedTypes.ToString());

                byte[] data;
                using (MemoryStream ms = new MemoryStream())
                {
                    XmlWriterSettings settings = new XmlWriterSettings();
                    settings.Indent   = true;
                    settings.Encoding = Encoding.UTF8;
                    using (XmlWriter encryptedwriter = XmlWriter.Create(ms, settings))
                    {
                        encryptedwriter.WriteStartElement("config");
                        foreach (WinAuthAuthenticator wa in this)
                        {
                            wa.WriteXmlString(encryptedwriter);
                        }
                        encryptedwriter.WriteEndElement();
                    }

                    data = ms.ToArray();
                }

                using (var hasher = new MD5CryptoServiceProvider())
                {
                    string encdata = Authenticator.EncryptSequence(Authenticator.ByteArrayToString(data), PasswordType, Password, this.Yubi);
                    string enchash = Authenticator.ByteArrayToString(hasher.ComputeHash(Authenticator.StringToByteArray(encdata)));
                    writer.WriteAttributeString("md5", enchash);
                    writer.WriteString(encdata);
                }

                writer.WriteEndElement();
            }
            else
            {
                foreach (WinAuthAuthenticator wa in this)
                {
                    wa.WriteXmlString(writer);
                }
            }

            if (includeSettings == true && _settings.Count != 0)
            {
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add(string.Empty, string.Empty);
                XmlSerializer serializer = new XmlSerializer(typeof(setting[]), new XmlRootAttribute()
                {
                    ElementName = "settings"
                });
                serializer.Serialize(writer, _settings.Select(e => new setting {
                    Key = e.Key, Value = e.Value
                }).ToArray(), ns);
            }

            // close WinAuth
            writer.WriteEndElement();

            // end document
            writer.WriteEndDocument();
        }
Example #5
0
        /// <summary>
        /// Enroll the authenticator with the server
        /// </summary>
        public bool Enroll(EnrollState state)
        {
            // clear error
            state.Error = null;

            try
            {
                var    data    = new NameValueCollection();
                var    cookies = state.Cookies = state.Cookies ?? new CookieContainer();
                string response;

                if (string.IsNullOrEmpty(state.OAuthToken) == true)
                {
                    // get session
                    if (cookies.Count == 0)
                    {
                        cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("mobileClientVersion", "3067969+%282.1.3%29"));
                        cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("mobileClient", "android"));
                        cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("steamid", ""));
                        cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("steamLogin", ""));
                        cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("Steam_Language", "english"));
                        cookies.Add(new Uri(COMMUNITY_BASE + "/"), new Cookie("dob", ""));

                        NameValueCollection headers = new NameValueCollection();
                        headers.Add("X-Requested-With", "com.valvesoftware.android.steam.community");

                        response = Request("https://steamcommunity.com/mobilelogin?oauth_client_id=DE45CD61&oauth_scope=read_profile%20write_profile%20read_client%20write_client", "GET", null, cookies, headers);
                    }

                    // get the user's RSA key
                    data.Add("username", state.Username);
                    response = Request(COMMUNITY_BASE + "/mobilelogin/getrsakey", "POST", data, cookies);
                    var rsaresponse = JObject.Parse(response);
                    if (rsaresponse.SelectToken("success").Value <bool>() != true)
                    {
                        throw new InvalidEnrollResponseException("Cannot get steam information for user: "******"publickey_exp").Value <string>());
                        p.Modulus  = Authenticator.StringToByteArray(rsaresponse.SelectToken("publickey_mod").Value <string>());
                        rsa.ImportParameters(p);
                        encryptedPassword = rsa.Encrypt(passwordBytes, false);
                    }

                    // login request
                    data = new NameValueCollection();
                    data.Add("password", Convert.ToBase64String(encryptedPassword));
                    data.Add("username", state.Username);
                    data.Add("twofactorcode", "");
                    data.Add("emailauth", (state.EmailAuthText != null ? state.EmailAuthText : string.Empty));
                    data.Add("loginfriendlyname", "#login_emailauth_friendlyname_mobile");
                    data.Add("captchagid", (state.CaptchaId != null ? state.CaptchaId : "-1"));
                    data.Add("captcha_text", (state.CaptchaText != null ? state.CaptchaText : "enter above characters"));
                    data.Add("emailsteamid", (state.EmailAuthText != null ? state.SteamId ?? string.Empty : string.Empty));
                    data.Add("rsatimestamp", rsaresponse.SelectToken("timestamp").Value <string>());
                    data.Add("remember_login", "false");
                    data.Add("oauth_client_id", "DE45CD61");
                    data.Add("oauth_scope", "read_profile write_profile read_client write_client");
                    data.Add("donotache", new DateTime().ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds.ToString());
                    response = Request(COMMUNITY_BASE + "/mobilelogin/dologin/", "POST", data, cookies);
                    Dictionary <string, object> loginresponse = JsonConvert.DeserializeObject <Dictionary <string, object> >(response);

                    if (loginresponse.ContainsKey("emailsteamid") == true)
                    {
                        state.SteamId = loginresponse["emailsteamid"] as string;
                    }

                    // require captcha
                    if (loginresponse.ContainsKey("captcha_needed") == true && (bool)loginresponse["captcha_needed"] == true)
                    {
                        state.RequiresCaptcha = true;
                        state.CaptchaId       = (string)loginresponse["captcha_gid"];
                        state.CaptchaUrl      = COMMUNITY_BASE + "/public/captcha.php?gid=" + state.CaptchaId;
                    }
                    else
                    {
                        state.RequiresCaptcha = false;
                        state.CaptchaId       = null;
                        state.CaptchaUrl      = null;
                        state.CaptchaText     = null;
                    }

                    // require email auth
                    if (loginresponse.ContainsKey("emailauth_needed") == true && (bool)loginresponse["emailauth_needed"] == true)
                    {
                        if (loginresponse.ContainsKey("emaildomain") == true)
                        {
                            var emaildomain = (string)loginresponse["emaildomain"];
                            if (string.IsNullOrEmpty(emaildomain) == false)
                            {
                                state.EmailDomain = emaildomain;
                            }
                        }
                        state.RequiresEmailAuth = true;
                    }
                    else
                    {
                        state.EmailDomain       = null;
                        state.RequiresEmailAuth = false;
                    }

                    // require email auth
                    if (loginresponse.ContainsKey("requires_twofactor") == true && (bool)loginresponse["requires_twofactor"] == true)
                    {
                        state.Requires2FA = true;
                    }
                    else
                    {
                        state.Requires2FA = false;
                    }

                    // if we didn't login, return the result
                    if (loginresponse.ContainsKey("login_complete") == false || (bool)loginresponse["login_complete"] == false || loginresponse.ContainsKey("oauth") == false)
                    {
                        if (loginresponse.ContainsKey("oauth") == false)
                        {
                            state.Error = "Invalid response from Steam (No OAuth token)";
                        }
                        if (loginresponse.ContainsKey("message") == true)
                        {
                            state.Error = (string)loginresponse["message"];
                        }
                        return(false);
                    }

                    // get the OAuth token - is stringified json
                    string oauth     = (string)loginresponse["oauth"];
                    var    oauthjson = JObject.Parse(oauth);
                    state.OAuthToken = oauthjson.SelectToken("oauth_token").Value <string>();
                    if (oauthjson.SelectToken("steamid") != null)
                    {
                        state.SteamId = oauthjson.SelectToken("steamid").Value <string>();
                    }
                }

                // login to webapi
                data.Clear();
                data.Add("access_token", state.OAuthToken);
                response = Request(WEBAPI_BASE + "/ISteamWebUserPresenceOAuth/Logon/v0001", "POST", data);

                var sessionid = cookies.GetCookies(new Uri(COMMUNITY_BASE + "/"))["sessionid"].Value;

                if (state.RequiresActivation == false)
                {
                    data.Clear();
                    data.Add("op", "has_phone");
                    data.Add("arg", "null");
                    data.Add("sessionid", sessionid);

                    response = Request(COMMUNITY_BASE + "/steamguard/phoneajax", "POST", data, cookies);
                    var  jsonresponse = JObject.Parse(response);
                    bool hasPhone     = jsonresponse.SelectToken("has_phone").Value <Boolean>();
                    if (hasPhone == false)
                    {
                        state.OAuthToken    = null;                      // force new login
                        state.RequiresLogin = true;
                        state.Cookies       = null;
                        state.Error         = "Your Steam account must have a SMS-capable phone number attached. Go into Account Details of the Steam client or Steam website and click Add a Phone Number.";
                        return(false);
                    }

                    //response = Request(COMMUNITY_BASE + "/steamguard/phone_checksms?bForTwoFactor=1&bRevoke2fOnCancel=", "GET", null, cookies);

                    // add a new authenticator
                    data.Clear();
                    string deviceId = BuildRandomId();
                    data.Add("access_token", state.OAuthToken);
                    data.Add("steamid", state.SteamId);
                    data.Add("authenticator_type", "1");
                    data.Add("device_identifier", deviceId);
                    data.Add("sms_phone_id", "1");
                    response = Request(WEBAPI_BASE + "/ITwoFactorService/AddAuthenticator/v0001", "POST", data);
                    var tfaresponse = JObject.Parse(response);
                    if (response.IndexOf("status") == -1 && tfaresponse.SelectToken("response.status").Value <int>() == 84)
                    {
                        // invalid response
                        state.OAuthToken    = null;                      // force new login
                        state.RequiresLogin = true;
                        state.Cookies       = null;
                        state.Error         = "Unable to send SMS. Check your phone is registered on your Steam account.";
                        return(false);
                    }
                    if (response.IndexOf("shared_secret") == -1)
                    {
                        // invalid response
                        state.OAuthToken    = null;                      // force new login
                        state.RequiresLogin = true;
                        state.Cookies       = null;
                        state.Error         = "Invalid response from Steam: " + response;
                        return(false);
                    }

                    // save data into this authenticator
                    var secret = tfaresponse.SelectToken("response.shared_secret").Value <string>();
                    this.SecretKey       = Convert.FromBase64String(secret);
                    this.Serial          = tfaresponse.SelectToken("response.serial_number").Value <string>();
                    this.DeviceId        = deviceId;
                    state.RevocationCode = tfaresponse.SelectToken("response.revocation_code").Value <string>();

                    // add the steamid into the data
                    var steamdata = JObject.Parse(tfaresponse.SelectToken("response").ToString());
                    if (steamdata.SelectToken("steamid") == null)
                    {
                        steamdata.Add("steamid", state.SteamId);
                    }
                    if (steamdata.SelectToken("steamguard_scheme") == null)
                    {
                        steamdata.Add("steamguard_scheme", "2");
                    }
                    this.SteamData = steamdata.ToString(Newtonsoft.Json.Formatting.None);

                    // calculate server drift
                    long servertime = tfaresponse.SelectToken("response.server_time").Value <long>() * 1000;
                    ServerTimeDiff = servertime - CurrentTime;
                    LastServerTime = DateTime.Now.Ticks;

                    state.RequiresActivation = true;

                    return(false);
                }

                // finalize adding the authenticator
                data.Clear();
                data.Add("access_token", state.OAuthToken);
                data.Add("steamid", state.SteamId);
                data.Add("activation_code", state.ActivationCode);

                // try and authorise
                var retries = 0;
                while (state.RequiresActivation == true && retries < ENROLL_ACTIVATE_RETRIES)
                {
                    data.Add("authenticator_code", this.CalculateCode(false));
                    data.Add("authenticator_time", this.ServerTime.ToString());
                    response = Request(WEBAPI_BASE + "/ITwoFactorService/FinalizeAddAuthenticator/v0001", "POST", data);
                    var finalizeresponse = JObject.Parse(response);
                    if (response.IndexOf("status") != -1 && finalizeresponse.SelectToken("response.status").Value <int>() == INVALID_ACTIVATION_CODE)
                    {
                        state.Error = "Invalid activation code";
                        return(false);
                    }

                    // reset our time
                    if (response.IndexOf("server_time") != -1)
                    {
                        long servertime = finalizeresponse.SelectToken("response.server_time").Value <long>() * 1000;
                        ServerTimeDiff = servertime - CurrentTime;
                        LastServerTime = DateTime.Now.Ticks;
                    }

                    // check success
                    if (finalizeresponse.SelectToken("response.success").Value <bool>() == true)
                    {
                        if (response.IndexOf("want_more") != -1 && finalizeresponse.SelectToken("response.want_more").Value <bool>() == true)
                        {
                            ServerTimeDiff += 30000L;
                            retries++;
                            continue;
                        }
                        state.RequiresActivation = false;
                        break;
                    }

                    ServerTimeDiff += 30000L;
                    retries++;
                }
                if (state.RequiresActivation == true)
                {
                    state.Error = "There was a problem activating. There might be an issue with the Steam servers. Please try again later.";
                    return(false);
                }

                // mark and successful and return key
                state.Success   = true;
                state.SecretKey = Authenticator.ByteArrayToString(this.SecretKey);

                // send confirmation email
                data.Clear();
                data.Add("access_token", state.OAuthToken);
                data.Add("steamid", state.SteamId);
                data.Add("email_type", "2");
                response = Request(WEBAPI_BASE + "/ITwoFactorService/SendEmail/v0001", "POST", data);

                return(true);
            }
            catch (UnauthorisedRequestException ex)
            {
                throw new InvalidEnrollResponseException("You are not allowed to add an authenticator. Have you enabled 'community-generated content' in Family View?", ex);
            }
            catch (InvalidRequestException ex)
            {
                throw new InvalidEnrollResponseException("Error enrolling new authenticator", ex);
            }
        }
Example #6
0
        /// <summary>
        /// Configure the Yubikey
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void yubiSecretUpdateButton_Click(object sender, EventArgs e)
        {
            if (yubiSecretField.Text.Trim().Length == 0)
            {
                WinAuthForm.ErrorDialog(this, "Please enter a secret phase or password");
                return;
            }

            if (WinAuthForm.ConfirmDialog(this,
                                          "This will overwrite any existing data on your YubiKey.\n\nAre you sure you want to continue?",
                                          MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2) != System.Windows.Forms.DialogResult.Yes)
            {
                return;
            }

            int  slot  = (yubiSlotToggle.Checked == true ? 2 : 1);
            bool press = yubiPressToggle.Checked;

            // bug in YubiKey 3.2.x (and below?) where using keypress doesn't always work
            // see http://forum.yubico.com/viewtopic.php?f=26&t=1571
            if (press == true &&
                (this.Yubikey.Info.Status.VersionMajor < 3 ||
                 (this.Yubikey.Info.Status.VersionMajor == 3 && this.Yubikey.Info.Status.VersionMinor <= 3)))
            {
                if (WinAuthForm.ConfirmDialog(this,
                                              "This is a known issue using \"Require button press\" with YubiKeys that have firmware version 3.3 and below. It can cause intermittent problems when reading the Challenge-Response. You can contact Yubico and may be able to get a free replacement.\n\nDo you want to continue anyway?",
                                              MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2) != System.Windows.Forms.DialogResult.Yes)
                {
                    return;
                }
            }

            // calculate the actual key. This is a byte version of the string, salt="mnemonic"(+user password TBD), PBKDF 2048 times, return 20byte/160bit key
            byte[] bytes = Encoding.UTF8.GetBytes(yubiSecretField.Text.Trim());
            string salt  = "mnemonic";

            byte[]             saltbytes = Encoding.UTF8.GetBytes(salt);
            Rfc2898DeriveBytes kg        = new Rfc2898DeriveBytes(bytes, saltbytes, YUBIKEY_PBKDF2_ITERATIONS);

            byte[] key = kg.GetBytes(YUBIKEY_PBKDF2_KEYSIZE);

            try
            {
                this.Yubikey.SetChallengeResponse(slot, key, key.Length, press);
            }
            catch (YubKeyException ex)
            {
                WinAuthForm.ErrorDialog(this, ex.Message, ex);
                return;
            }

            if (press == true)
            {
                if (WinAuthForm.ConfirmDialog(this,
                                              "Your YubiKey slot will now be verified. Please click its button when it flashes." + Environment.NewLine + Environment.NewLine + "Continue?",
                                              MessageBoxButtons.YesNo,
                                              MessageBoxIcon.Warning) != System.Windows.Forms.DialogResult.Yes)
                {
                    WinAuthForm.ErrorDialog(this, "Your YubiKey has been updated. Please verify it before continuing.");
                    return;
                }
            }

            // perform the test encryption/decryption using the yubi
            try
            {
                string challenge = "WinAuth";
                string plain     = Authenticator.ByteArrayToString(Encoding.ASCII.GetBytes(challenge));
                Authenticator.PasswordTypes passwordType = (slot == 1 ? Authenticator.PasswordTypes.YubiKeySlot1 : Authenticator.PasswordTypes.YubiKeySlot2);
                string encrypted = Authenticator.EncryptSequence(plain, passwordType, null, this.Yubikey);
                plain = Authenticator.DecryptSequence(encrypted, passwordType, null, this.Yubikey);
                string response = Encoding.ASCII.GetString(Authenticator.StringToByteArray(plain));
                if (challenge != response)
                {
                    throw new ApplicationException("verification failed");
                }
            }
            catch (ApplicationException ex)
            {
                WinAuthForm.ErrorDialog(this, "The YubiKey test failed. Please try configuring it again or doing it manually. (" + ex.Message + ")");
                return;
            }

            YubikeySlot = slot;

            WinAuthForm.ErrorDialog(this, "Your YubiKey has been successfully updated.");
        }
Example #7
0
        public void ReadXml(XmlReader reader, string password = null)
        {
            reader.MoveToContent();

            if (reader.IsEmptyElement)
            {
                reader.Read();
                return;
            }

            reader.Read();
            while (reader.EOF == false)
            {
                if (reader.IsStartElement())
                {
                    switch (reader.Name)
                    {
                    case "modifiers":
                        Modifiers = (WinAPI.KeyModifiers)BitConverter.ToInt32(Authenticator.StringToByteArray(reader.ReadElementContentAsString()), 0);
                        break;

                    case "hotkey":
                        HotKey = (WinAPI.VirtualKeyCode)BitConverter.ToUInt16(Authenticator.StringToByteArray(reader.ReadElementContentAsString()), 0);
                        break;

                    case "windowtitle":
                        WindowTitle = reader.ReadElementContentAsString();
                        break;

                    case "windowtitleregex":
                        WindowTitleRegex = reader.ReadElementContentAsBoolean();
                        break;

                    case "processname":
                        ProcessName = reader.ReadElementContentAsString();
                        break;

                    case "advanced":
                        Advanced = reader.ReadElementContentAsBoolean();
                        break;

                    case "script":
                        string encrypted = reader.GetAttribute("encrypted");
                        string data      = reader.ReadElementContentAsString();

                        if (string.IsNullOrEmpty(encrypted) == false)
                        {
                            Authenticator.PasswordTypes passwordType = Authenticator.DecodePasswordTypes(encrypted);
                            data = Authenticator.DecryptSequence(data, passwordType, password, true);
                            //byte[] plain = Authenticator.StringToByteArray(data);
                            //data = Encoding.UTF8.GetString(plain, 0, plain.Length);

/*
 *              char[] encTypes = encrypted.ToCharArray();
 *              // we read the string in reverse order (the order they were encrypted)
 *              for (int i = encTypes.Length - 1; i >= 0; i--)
 *              {
 *                char encryptedType = encTypes[i];
 *                switch (encryptedType)
 *                {
 *                  case 'u':
 *                    {
 *                      // we are going to decrypt with the Windows User account key
 *                      byte[] cipher = Authenticator.StringToByteArray(data);
 *                      byte[] plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.CurrentUser);
 *                      data = Encoding.UTF8.GetString(plain, 0, plain.Length);
 *                      break;
 *                    }
 *                  case 'm':
 *                    {
 *                      // we are going to decrypt with the Windows local machine key
 *                      byte[] cipher = Authenticator.StringToByteArray(data);
 *                      byte[] plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.LocalMachine);
 *                      data = Encoding.UTF8.GetString(plain, 0, plain.Length);
 *                      break;
 *                    }
 *                  case 'y':
 *                    {
 *                      // we use an explicit password to encrypt data
 *                      if (string.IsNullOrEmpty(password) == true)
 *                      {
 *                        throw new EncryptedSecretDataException();
 *                      }
 *                      data = Authenticator.Decrypt(data, password, true);
 *                      byte[] plain = Authenticator.StringToByteArray(data);
 *                      data = Encoding.UTF8.GetString(plain, 0, plain.Length);
 *                      break;
 *                    }
 *                  default:
 *                    break;
 *                }
 *              }
 */
                        }

                        AdvancedScript = data;

                        break;

                    default:
                        reader.Skip();
                        break;
                    }
                }
                else
                {
                    reader.Read();
                    break;
                }
            }
        }
Example #8
0
        /// <summary>
        /// Create a new HotKeySequence from a loaded string
        /// </summary>
        /// <param name="data">XmlNode from config</param>
        public HoyKeySequence(XmlNode autoLoginNode, string password, decimal version)
        {
            bool    boolVal = false;
            XmlNode node    = autoLoginNode.SelectSingleNode("modifiers");

            if (node != null && node.InnerText.Length != 0)
            {
                Modifiers = (WinAPI.KeyModifiers)BitConverter.ToInt32(Authenticator.StringToByteArray(node.InnerText), 0);
            }
            node = autoLoginNode.SelectSingleNode("hotkey");
            if (node != null && node.InnerText.Length != 0)
            {
                HotKey = (WinAPI.VirtualKeyCode)BitConverter.ToUInt16(Authenticator.StringToByteArray(node.InnerText), 0);
            }
            node = autoLoginNode.SelectSingleNode("windowtitle");
            if (node != null && node.InnerText.Length != 0)
            {
                WindowTitle = node.InnerText;
            }
            node = autoLoginNode.SelectSingleNode("windowtitleregex");
            if (node != null && bool.TryParse(node.InnerText, out boolVal) == true)
            {
                WindowTitleRegex = boolVal;
            }
            node = autoLoginNode.SelectSingleNode("processname");
            if (node != null && node.InnerText.Length != 0)
            {
                ProcessName = node.InnerText;
            }
            node = autoLoginNode.SelectSingleNode("advanced");
            if (node != null && bool.TryParse(node.InnerText, out boolVal) == true)
            {
                Advanced = boolVal;
            }
            node = autoLoginNode.SelectSingleNode("script");
            if (node != null && node.InnerText.Length != 0)
            {
                string data = node.InnerText;

                XmlAttribute attr = node.Attributes["encrypted"];
                if (attr != null && attr.InnerText.Length != 0)
                {
                    char[] encTypes = attr.InnerText.ToCharArray();
                    // we read the string in reverse order (the order they were encrypted)
                    for (int i = encTypes.Length - 1; i >= 0; i--)
                    {
                        char encryptedType = encTypes[i];
                        switch (encryptedType)
                        {
                        case 'u':
                        {
                            // we are going to decrypt with the Windows User account key
                            byte[] cipher = Authenticator.StringToByteArray(data);
                            byte[] plain  = ProtectedData.Unprotect(cipher, null, DataProtectionScope.CurrentUser);
                            data = Encoding.UTF8.GetString(plain, 0, plain.Length);
                            break;
                        }

                        case 'm':
                        {
                            // we are going to decrypt with the Windows local machine key
                            byte[] cipher = Authenticator.StringToByteArray(data);
                            byte[] plain  = ProtectedData.Unprotect(cipher, null, DataProtectionScope.LocalMachine);
                            data = Encoding.UTF8.GetString(plain, 0, plain.Length);
                            break;
                        }

                        case 'y':
                        {
                            // we use an explicit password to encrypt data
                            if (string.IsNullOrEmpty(password) == true)
                            {
                                throw new EncryptedSecretDataException();
                            }
                            data = Authenticator.Decrypt(data, password, (version >= (decimal)1.7));                                             // changed encrypted in 1.7
                            byte[] plain = Authenticator.StringToByteArray(data);
                            data = Encoding.UTF8.GetString(plain, 0, plain.Length);
                            break;
                        }

                        default:
                            break;
                        }
                    }
                }
                AdvancedScript = data;
            }
        }
Example #9
0
        /// <summary>
        /// Enroll the authenticator with the server
        /// </summary>
        public bool Enroll(EnrollState state)
        {
            // clear error
            state.Error = null;

            try
            {
                var    data    = new NameValueCollection();
                var    cookies = state.Cookies = state.Cookies ?? new CookieContainer();
                string response;

                if (string.IsNullOrEmpty(state.OAuthToken) == true)
                {
                    // get session
                    response = Request(COMMUNITY_BASE + "/login/home?goto=0", "GET", null, cookies);

                    // get the user's RSA key
                    data.Add("username", state.Username);
                    response = Request(COMMUNITY_BASE + "/login/getrsakey", "POST", data, cookies);
                    var rsaresponse = JObject.Parse(response);
                    if (rsaresponse.SelectToken("success").Value <bool>() != true)
                    {
                        throw new InvalidEnrollResponseException("Cannot get steam information for user: "******"steamid").Value <string>();

                    // encrypt password with RSA key
                    RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
                    byte[] encryptedPassword;
                    using (var rsa = new RSACryptoServiceProvider())
                    {
                        var passwordBytes = Encoding.ASCII.GetBytes(state.Password);
                        var p             = rsa.ExportParameters(false);
                        p.Exponent = Authenticator.StringToByteArray(rsaresponse.SelectToken("publickey_exp").Value <string>());
                        p.Modulus  = Authenticator.StringToByteArray(rsaresponse.SelectToken("publickey_mod").Value <string>());
                        rsa.ImportParameters(p);
                        encryptedPassword = rsa.Encrypt(passwordBytes, false);
                    }

                    // login request
                    data = new NameValueCollection();
                    data.Add("password", Convert.ToBase64String(encryptedPassword));
                    data.Add("username", state.Username);
                    data.Add("twofactorcode", "");
                    data.Add("emailauth", (state.EmailAuthText != null ? state.EmailAuthText : string.Empty));
                    data.Add("loginfriendlyname", "#login_emailauth_friendlyname_mobile");
                    data.Add("captchagid", (state.CaptchaId != null ? state.CaptchaId : "-1"));
                    data.Add("captcha_text", (state.CaptchaText != null ? state.CaptchaText : "enter above characters"));
                    data.Add("emailsteamid", (state.EmailAuthText != null ? state.SteamId : string.Empty));
                    data.Add("rsatimestamp", rsaresponse.SelectToken("timestamp").Value <string>());
                    data.Add("remember_login", "false");
                    data.Add("oauth_client_id", "DE45CD61");
                    data.Add("oauth_scope", "read_profile write_profile read_client write_client");
                    data.Add("donotache", new DateTime().ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds.ToString());
                    response = Request(COMMUNITY_BASE + "/mobilelogin/dologin/", "POST", data, cookies);
                    Dictionary <string, object> loginresponse = JsonConvert.DeserializeObject <Dictionary <string, object> >(response);

                    // require captcha
                    if (loginresponse.ContainsKey("captcha_needed") == true && (bool)loginresponse["captcha_needed"] == true)
                    {
                        state.RequiresCaptcha = true;
                        state.CaptchaId       = (string)loginresponse["captcha_gid"];
                        state.CaptchaUrl      = COMMUNITY_BASE + "/public/captcha.php?gid=" + state.CaptchaId;
                    }
                    else
                    {
                        state.RequiresCaptcha = false;
                        state.CaptchaId       = null;
                        state.CaptchaUrl      = null;
                        state.CaptchaText     = null;
                    }

                    // require email auth
                    if (loginresponse.ContainsKey("emailauth_needed") == true && (bool)loginresponse["emailauth_needed"] == true)
                    {
                        if (loginresponse.ContainsKey("emaildomain") == true)
                        {
                            var emaildomain = (string)loginresponse["emaildomain"];
                            if (string.IsNullOrEmpty(emaildomain) == false)
                            {
                                state.EmailDomain = emaildomain;
                            }
                        }
                        state.RequiresEmailAuth = true;
                    }
                    else
                    {
                        state.EmailDomain       = null;
                        state.RequiresEmailAuth = false;
                    }

                    // require email auth
                    if (loginresponse.ContainsKey("requires_twofactor") == true && (bool)loginresponse["requires_twofactor"] == true)
                    {
                        state.Requires2FA = true;
                    }
                    else
                    {
                        state.Requires2FA = false;
                    }

                    // if we didn't login, return the result
                    if (loginresponse.ContainsKey("login_complete") == false || (bool)loginresponse["login_complete"] == false || loginresponse.ContainsKey("oauth") == false)
                    {
                        if (loginresponse.ContainsKey("oauth") == false)
                        {
                            state.Error = "No OAuth token in response";
                        }
                        if (loginresponse.ContainsKey("message") == true)
                        {
                            state.Error = (string)loginresponse["message"];
                        }
                        return(false);
                    }

                    // get the OAuth token - is stringified json
                    string oauth     = (string)loginresponse["oauth"];
                    var    oauthjson = JObject.Parse(oauth);
                    state.OAuthToken = oauthjson.SelectToken("oauth_token").Value <string>();
                }

                // login to webapi
                data.Clear();
                data.Add("access_token", state.OAuthToken);
                response = Request(WEBAPI_BASE + "/ISteamWebUserPresenceOAuth/Logon/v0001", "POST", data);

                if (state.RequiresActivation == false)
                {
                    // add a new authenticator
                    data.Clear();
                    string deviceId = BuildRandomId();
                    data.Add("access_token", state.OAuthToken);
                    data.Add("steamid", state.SteamId);
                    data.Add("authenticator_type", "1");
                    data.Add("device_identifier", deviceId);
                    response = Request(WEBAPI_BASE + "/ITwoFactorService/AddAuthenticator/v0001", "POST", data);
                    var tfaresponse = JObject.Parse(response);
                    if (response.IndexOf("revocation_code") == -1)
                    {
                        // invalid response
                        state.OAuthToken    = null;                      // force new login
                        state.RequiresLogin = true;
                        state.Cookies       = null;
                        state.Error         = "Invalid response from Steam: " + response;
                        return(false);
                    }

                    // save data into this authenticator
                    var secret = tfaresponse.SelectToken("response.shared_secret").Value <string>();
                    this.SecretKey      = Convert.FromBase64String(secret);
                    this.Serial         = tfaresponse.SelectToken("response.serial_number").Value <string>();
                    this.DeviceId       = deviceId;
                    this.RevocationCode = state.RevocationCode = tfaresponse.SelectToken("response.revocation_code").Value <string>();

                    // calculate server drift
                    long servertime = tfaresponse.SelectToken("response.server_time").Value <long>() * 1000;
                    ServerTimeDiff = servertime - CurrentTime;
                    LastServerTime = DateTime.Now.Ticks;

                    // send authorisation email
                    data.Clear();
                    data.Add("access_token", state.OAuthToken);
                    data.Add("steamid", state.SteamId);
                    data.Add("email_type", "1");
                    data.Add("include_activation", "1");
                    response = Request(WEBAPI_BASE + "/ITwoFactorService/SendEmail/v0001", "POST", data);

                    state.RequiresActivation = true;

                    return(false);
                }

                // finalize adding the authenticator
                data.Clear();
                data.Add("access_token", state.OAuthToken);
                data.Add("steamid", state.SteamId);
                data.Add("activation_code", state.ActivationCode);

                // try and authorise
                ServerTimeDiff -= 40000;                 // start at previous interval
                var retries = 0;
                while (state.RequiresActivation == true && retries < ENROLL_ACTIVATE_RETRIES)
                {
                    data.Add("authenticator_code", this.CalculateCode(false));
                    data.Add("authenticator_time", this.ServerTime.ToString());
                    response = Request(WEBAPI_BASE + "/ITwoFactorService/FinalizeAddAuthenticator/v0001", "POST", data);
                    var finalizeresponse = JObject.Parse(response);
                    if (response.IndexOf("status") != -1 && finalizeresponse.SelectToken("response.status").Value <int>() == INVALID_ACTIVATION_CODE)
                    {
                        state.Error = "Invalid activation code";
                        return(false);
                    }

                    // reset our time
                    if (response.IndexOf("server_time") != -1)
                    {
                        long servertime = finalizeresponse.SelectToken("response.server_time").Value <long>() * 1000;
                        ServerTimeDiff = servertime - CurrentTime;
                        LastServerTime = DateTime.Now.Ticks;
                    }

                    // check success
                    if (finalizeresponse.SelectToken("response.success").Value <bool>() == true)
                    {
                        if (response.IndexOf("want_more") != -1 && finalizeresponse.SelectToken("response.want_more").Value <bool>() == true)
                        {
                            ServerTimeDiff += 30000L;
                            retries++;
                            continue;
                        }
                        state.RequiresActivation = false;
                        break;
                    }

                    ServerTimeDiff += 30000L;
                    retries++;
                }
                if (state.RequiresActivation == true)
                {
                    state.Error = "There was a problem activating. There might be an issue with the Steam servers. Please try again later.";
                    return(false);
                }

                // mark and successful and return key
                state.Success   = true;
                state.SecretKey = Authenticator.ByteArrayToString(this.SecretKey);

                // send confirmation email
                data.Clear();
                data.Add("access_token", state.OAuthToken);
                data.Add("steamid", state.SteamId);
                data.Add("email_type", "2");
                response = Request(WEBAPI_BASE + "/ITwoFactorService/SendEmail/v0001", "POST", data);

                return(true);
            }
            catch (InvalidRequestException ex)
            {
                throw new InvalidEnrollResponseException("Error enrolling new authenticator", ex);
            }
        }