Example #1
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);
        }
Example #2
0
 /// <summary>
 /// Enroll the authenticator with the server.
 public void Enroll(string b32key)
 {
     SecretKey = Base32.GetInstance().Decode(b32key);
     Sync();
 }
Example #3
0
        /// <summary>
        ///     Verify and create the authenticator if needed
        /// </summary>
        /// <returns>true is successful</returns>
        private bool verifyAuthenticator(string privatekey)
        {
            if (string.IsNullOrEmpty(privatekey))
            {
                return(false);
            }

            Authenticator.Name = nameField.Text;

            var authtype = "totp";

            // if this is a URL, pull it down
            Uri   uri;
            Match match;

            if (Regex.IsMatch(privatekey, "https?://.*") && Uri.TryCreate(privatekey, UriKind.Absolute, out uri))
            {
                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))
                        {
                            using (var bitmap = (Bitmap)Image.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(Owner, "Cannot load QR code image from " + privatekey, ex);
                    return(false);
                }
            }
            else if ((match = Regex.Match(privatekey, @"data:image/([^;]+);base64,(.*)", RegexOptions.IgnoreCase))
                     .Success)
            {
                var imagedata = Convert.FromBase64String(match.Groups[2].Value);
                using (var ms = new MemoryStream(imagedata))
                {
                    using (var bitmap = (Bitmap)Image.FromStream(ms))
                    {
                        IBarcodeReader reader = new BarcodeReader();
                        var            result = reader.Decode(bitmap);
                        if (result != null)
                        {
                            privatekey = HttpUtility.UrlDecode(result.Text);
                        }
                    }
                }
            }
            else if (IsValidFile(privatekey))
            {
                // assume this is the image file
                using (var bitmap = (Bitmap)Image.FromFile(privatekey))
                {
                    IBarcodeReader reader = new BarcodeReader();
                    var            result = reader.Decode(bitmap);
                    if (result != null)
                    {
                        privatekey = result.Text;
                    }
                }
            }

            // check for otpauth://, e.g. "otpauth://totp/[email protected]?secret=IHZJDKAEEC774BMUK3GX6SA"
            match = Regex.Match(privatekey, @"otpauth://([^/]+)/([^?]+)\?(.*)", RegexOptions.IgnoreCase);
            if (match.Success)
            {
                authtype = match.Groups[1].Value; // @todo we only handle totp (not hotp)
                if (string.Compare(authtype, "totp", true) != 0)
                {
                    WinAuthForm.ErrorDialog(Owner,
                                            "Only time-based (TOTP) authenticators are supported when adding a Google Authenticator. Use the general \"Add Authenticator\" for counter-based (HOTP) authenticators.");
                    return(false);
                }

                var label = match.Groups[2].Value;
                if (string.IsNullOrEmpty(label) == false)
                {
                    Authenticator.Name = nameField.Text = label;
                }

                var qs = WinAuthHelper.ParseQueryString(match.Groups[3].Value);
                privatekey = qs["secret"] ?? privatekey;
            }

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

            try
            {
                var auth = new GoogleAuthenticator();
                auth.Enroll(privatekey);
                Authenticator.AuthenticatorData = auth;

                codeProgress.Visible = true;

                var key = Base32.getInstance().Encode(Authenticator.AuthenticatorData.SecretKey);
                secretCodeField.Text = Regex.Replace(key, ".{3}", "$0 ").Trim();
                codeField.Text       = auth.CurrentCode;

                if (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(Owner,
                                        "Unable to create the authenticator. The secret code is probably invalid.", irre);
                return(false);
            }

            return(true);
        }
Example #4
0
        /// <summary>
        /// Create a KeyUriFormat compatible URL
        /// See https://code.google.com/p/google-authenticator/wiki/KeyUriFormat
        /// </summary>
        /// <returns>string</returns>
        public virtual string ToUrl(bool compat = false)
        {
            string type        = "totp";
            string extraparams = string.Empty;

            Match  match;
            string issuer = this.AuthenticatorData.Issuer;
            string label  = this.Name;

            if (string.IsNullOrEmpty(issuer) == true && (match = Regex.Match(label, @"^([^\(]+)\s+\((.*?)\)(.*)")).Success == true)
            {
                issuer = match.Groups[1].Value;
                label  = match.Groups[2].Value + match.Groups[3].Value;
            }
            if (string.IsNullOrEmpty(issuer) == false && (match = Regex.Match(label, @"^" + issuer + @"\s+\((.*?)\)(.*)")).Success == true)
            {
                label = match.Groups[1].Value + match.Groups[2].Value;
            }
            if (string.IsNullOrEmpty(issuer) == false)
            {
                extraparams += "&issuer=" + HttpUtility.UrlEncode(issuer);
            }

            if (this.AuthenticatorData is BattleNetAuthenticator)
            {
                extraparams += "&serial=" + HttpUtility.UrlEncode(((BattleNetAuthenticator)this.AuthenticatorData).Serial.Replace("-", ""));
            }
            else if (this.AuthenticatorData is SteamAuthenticator)
            {
                if (compat == false)
                {
                    extraparams += "&deviceid=" + HttpUtility.UrlEncode(((SteamAuthenticator)this.AuthenticatorData).DeviceId);
                    extraparams += "&data=" + HttpUtility.UrlEncode(((SteamAuthenticator)this.AuthenticatorData).SteamData);
                }
            }
            else if (this.AuthenticatorData is HOTPAuthenticator)
            {
                type         = "hotp";
                extraparams += "&counter=" + ((HOTPAuthenticator)this.AuthenticatorData).Counter;
            }

            string secret = HttpUtility.UrlEncode(Base32.getInstance().Encode(this.AuthenticatorData.SecretKey));

            // add the skin
            if (string.IsNullOrEmpty(this.Skin) == false && compat == false)
            {
                if (this.Skin.StartsWith("base64:") == true)
                {
                    byte[] bytes  = Convert.FromBase64String(this.Skin.Substring(7));
                    string icon32 = Base32.getInstance().Encode(bytes);
                    extraparams += "&icon=" + HttpUtility.UrlEncode("base64:" + icon32);
                }
                else
                {
                    extraparams += "&icon=" + HttpUtility.UrlEncode(this.Skin.Replace("Icon.png", ""));
                }
            }

            var url = string.Format("otpauth://" + type + "/{0}?secret={1}&digits={2}{3}",
                                    (string.IsNullOrEmpty(issuer) == false ? issuer + ":" + HttpUtility.UrlEncode(label) : HttpUtility.UrlEncode(label)),
                                    secret,
                                    this.AuthenticatorData.CodeDigits,
                                    extraparams);

            return(url);
        }
 /// <summary>
 /// Set the private key for the authenticator
 /// </summary>
 /// <param name="b32key">base32 encoded key</param>
 public void Enroll(string b32key, long counter = 0)
 {
     SecretKey = Base32.getInstance().Decode(b32key);
     Counter   = counter;
 }
Example #6
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;
                    }
                }
            }

            // 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;

                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);
                }
                string issuer = qs["issuer"];
                if (string.IsNullOrEmpty(issuer) == false)
                {
                    label = issuer + (string.IsNullOrEmpty(label) == false ? " (" + label + ")" : string.Empty);
                }

                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)
                {
                    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;

                codeField.SpaceOut = digits / 2;

                string key = Base32.getInstance().Encode(this.Authenticator.AuthenticatorData.SecretKey);
                //this.secretCodeField.Text = Regex.Replace(key, ".{3}", "$0 ").Trim();
                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);
        }