/// <summary> /// Click to create a enroll a new authenticator /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void enrollAuthenticatorButton_Click(object sender, EventArgs e) { do { try { newSerialNumberField.Text = "creating..."; BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); #if DEBUG authenticator.Enroll(System.Diagnostics.Debugger.IsAttached); #else authenticator.Enroll(); #endif this.Authenticator.AuthenticatorData = authenticator; newSerialNumberField.Text = authenticator.Serial; newLoginCodeField.Text = authenticator.CurrentCode; newRestoreCodeField.Text = authenticator.RestoreCode; newAuthenticatorProgress.Visible = true; newAuthenticatorTimer.Enabled = true; return; } catch (InvalidEnrollResponseException iere) { if (WinAuthForm.ErrorDialog(this.Owner, "注册新的验证器时发生错误", iere, MessageBoxButtons.RetryCancel) != System.Windows.Forms.DialogResult.Retry) { break; } } } while (true); clearAuthenticator(false); }
/// <summary> /// Perform a verification of the restore code in the background by checking it with the servers /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void VerifyRestoreCode(object sender, DoWorkEventArgs e) { var auth = e.Argument as BattleNetAuthenticator; // check if this authenticator is too old to be restored try { var testrestore = new BattleNetAuthenticator(); testrestore.Restore(auth.Serial, auth.RestoreCode); auth.RestoreCodeVerified = true; e.Result = null; } catch (InvalidRestoreCodeException) { e.Result = "This authenticator was created before the restore capability existed and so the restore code will not work.\n\n" + "You will need to remove this authenticator from your Battle.net account and create a new one."; } catch (InvalidRestoreResponseException) { // ignore the validation if servers are down } catch (Exception ex2) { e.Result = "Oops. An error (" + ex2.Message + ") occured whilst validating your restore code." + "Please log a ticket at https://github.com/winauth/winauth/issues so we can fix this."; } }
/// <summary> /// Form loaded event /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ShowRestoreCodeForm_Load(object sender, EventArgs e) { BattleNetAuthenticator authenticator = CurrentAuthenticator.AuthenticatorData as BattleNetAuthenticator; this.serialNumberField.SecretMode = true; this.restoreCodeField.SecretMode = true; this.serialNumberField.Text = authenticator.Serial; this.restoreCodeField.Text = authenticator.RestoreCode; // if needed start a background thread to verify the restore code if (authenticator.RestoreCodeVerified == false) { BackgroundWorker verify = new BackgroundWorker(); verify.DoWork += new DoWorkEventHandler(VerifyRestoreCode); verify.RunWorkerCompleted += new RunWorkerCompletedEventHandler(VerifyRestoreCodeCompleted); verify.RunWorkerAsync(CurrentAuthenticator.AuthenticatorData); } }
/// <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); }
/// <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); } }
/// <summary> /// Verify and create the authenticator if needed /// </summary> /// <returns>true is successful</returns> private bool verifyAuthenticator() { this.Authenticator.Name = nameField.Text; if (this.tabControl1.SelectedIndex == 0) { if (this.Authenticator.AuthenticatorData == null) { WinAuthForm.ErrorDialog(this.Owner, "您需要创建身份验证器并将其附加到您的帐户"); return(false); } } else if (this.tabControl1.SelectedIndex == 1) { string serial = this.restoreSerialNumberField.Text.Trim(); string restore = this.restoreRestoreCodeField.Text.Trim(); if (serial.Length == 0 || restore.Length == 0) { WinAuthForm.ErrorDialog(this.Owner, "请输入序列号和恢复代码"); return(false); } try { BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); authenticator.Restore(serial, restore); this.Authenticator.AuthenticatorData = authenticator; } catch (InvalidRestoreResponseException irre) { WinAuthForm.ErrorDialog(this.Owner, "无法恢复验证器: " + irre.Message, irre); return(false); } } else if (this.tabControl1.SelectedIndex == 2) { string privatekey = this.importPrivateKeyField.Text.Trim(); if (privatekey.Length == 0) { WinAuthForm.ErrorDialog(this.Owner, "请输入私钥"); return(false); } // just get the hex chars privatekey = Regex.Replace(privatekey, @"0x", "", RegexOptions.IgnoreCase); privatekey = Regex.Replace(privatekey, @"[^0-9abcdef]", "", RegexOptions.IgnoreCase); if (privatekey.Length == 0 || privatekey.Length < 40) { WinAuthForm.ErrorDialog(this.Owner, "私钥必须是至少40个十六进制字符的序列, e.g. 7B0BFA82... or 0x7B, 0x0B, 0xFA, 0x82, ..."); return(false); } try { BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); if (privatekey.Length == 40) // 20 bytes which is key only { authenticator.SecretKey = WinAuth.Authenticator.StringToByteArray(privatekey); authenticator.Serial = "US-Imported"; } else { authenticator.SecretData = privatekey; if (string.IsNullOrEmpty(authenticator.Serial) == true) { authenticator.Serial = "US-Imported"; } } authenticator.Sync(); this.Authenticator.AuthenticatorData = authenticator; } catch (Exception irre) { WinAuthForm.ErrorDialog(this.Owner, "无法导入身份验证器。私钥可能无效。", irre); return(false); } } return(true); }
public static Authenticator ReadXmlv2(XmlReader reader, string password = null) { Authenticator authenticator = null; string authenticatorType = reader.GetAttribute("type"); if (string.IsNullOrEmpty(authenticatorType) == false) { authenticatorType = authenticatorType.Replace("WindowsAuthenticator.", "WinAuth."); Type type = System.Reflection.Assembly.GetExecutingAssembly().GetType(authenticatorType, false, true); authenticator = Activator.CreateInstance(type) as Authenticator; } if (authenticator == null) { authenticator = new BattleNetAuthenticator(); } reader.MoveToContent(); if (reader.IsEmptyElement) { reader.Read(); return null; } reader.Read(); while (reader.EOF == false) { if (reader.IsStartElement()) { switch (reader.Name) { case "servertimediff": authenticator.ServerTimeDiff = reader.ReadElementContentAsLong(); break; //case "restorecodeverified": // authenticator.RestoreCodeVerified = reader.ReadElementContentAsBoolean(); // break; case "secretdata": string encrypted = reader.GetAttribute("encrypted"); string data = reader.ReadElementContentAsString(); PasswordTypes passwordType = DecodePasswordTypes(encrypted); if (passwordType != PasswordTypes.None) { // this is an old version so there is no hash data = DecryptSequence(data, passwordType, password, null); } authenticator.PasswordType = PasswordTypes.None; authenticator.SecretData = data; break; default: if (authenticator.ReadExtraXml(reader, reader.Name) == false) { reader.Skip(); } break; } } else { reader.Read(); break; } } return authenticator; }
private bool HandleBattleNetToken() { var serial = _wowManager.Settings.AuthenticatorSerial; var restoreCode = _wowManager.Settings.AuthenticatorRestoreCode; if (string.IsNullOrEmpty(serial) || string.IsNullOrEmpty(restoreCode)) return false; if (string.IsNullOrEmpty(_wowManager.Settings.AuthenticatorSerial)) return false; var frame = UIObject.GetUIObjectByName<Frame>(_wowManager, "TokenEnterDialogBackgroundEdit"); if (frame == null || !frame.IsVisible || !frame.IsShown) return false; var editBox = UIObject.GetUIObjectByName<EditBox>(_wowManager, "AccountLoginTokenEdit"); var auth = new BattleNetAuthenticator(); try { auth.Restore(serial, restoreCode); } catch (Exception ex) { _wowManager.Profile.Err("Could not get auth token: {0}", ex.Message); return false; } if (!string.IsNullOrEmpty(editBox.Text)) { Utility.SendBackgroundKey(_wowManager.GameProcess.MainWindowHandle, (char)Keys.End, false); Utility.SendBackgroundString(_wowManager.GameProcess.MainWindowHandle, new string('\b', "AccountLoginTokenEdit".Length * 2), false); _wowManager.Profile.Log("Pressing 'end' + delete keys to remove contents from {0}", "AccountLoginTokenEdit"); } Utility.SendBackgroundString(_wowManager.GameProcess.MainWindowHandle, auth.CurrentCode); Utility.SendBackgroundKey(_wowManager.GameProcess.MainWindowHandle, (char)Keys.Enter, false); _wowManager.Profile.Log("Accepting Battle net token."); return true; }
public static Authenticator ReadXmlv2(XmlReader reader, string password = null) { Authenticator authenticator = null; string authenticatorType = reader.GetAttribute("type"); if (string.IsNullOrEmpty(authenticatorType) == false) { authenticatorType = authenticatorType.Replace("WindowsAuthenticator.", "WinAuth."); Type type = Assembly.GetExecutingAssembly().GetType(authenticatorType, false, true); authenticator = Activator.CreateInstance(type) as Authenticator; } if (authenticator == null) { authenticator = new BattleNetAuthenticator(); } reader.MoveToContent(); if (reader.IsEmptyElement) { reader.Read(); return(null); } reader.Read(); while (reader.EOF == false) { if (reader.IsStartElement()) { switch (reader.Name) { case "servertimediff": authenticator.ServerTimeDiff = reader.ReadElementContentAsLong(); break; //case "restorecodeverified": // authenticator.RestoreCodeVerified = reader.ReadElementContentAsBoolean(); // break; case "secretdata": string encrypted = reader.GetAttribute("encrypted"); string data = reader.ReadElementContentAsString(); PasswordTypes passwordType = DecodePasswordTypes(encrypted); if (passwordType != PasswordTypes.None) { // this is an old version so there is no hash data = DecryptSequence(data, passwordType, password); } authenticator.PasswordType = PasswordTypes.None; authenticator.SecretData = data; break; default: if (authenticator.ReadExtraXml(reader, reader.Name) == false) { reader.Skip(); } break; } } else { reader.Read(); break; } } return(authenticator); }
/// <summary> /// Perform a verification of the restore code in the background by checking it with the servers /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void VerifyRestoreCode(object sender, DoWorkEventArgs e) { BattleNetAuthenticator auth = e.Argument as BattleNetAuthenticator; // check if this authenticator is too old to be restored try { BattleNetAuthenticator testrestore = new BattleNetAuthenticator(); testrestore.Restore(auth.Serial, auth.RestoreCode); auth.RestoreCodeVerified = true; e.Result = null; } catch (InvalidRestoreCodeException) { e.Result = "This authenticator was created before the restore capability existed and so the restore code will not work.\n\n" + "You will need to remove this authenticator from your Battle.net account and create a new one."; } catch (InvalidRestoreResponseException) { // ignore the validation if servers are down } catch (Exception ex2) { e.Result = "Oops. An error (" + ex2.Message + ") occured whilst validating your restore code." + "Please log a ticket at https://github.com/winauth/winauth/issues so we can fix this."; } }
/// <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; }
/// <summary> /// Click to create a enroll a new authenticator /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void enrollAuthenticatorButton_Click(object sender, EventArgs e) { do { try { newSerialNumberField.Text = "creating..."; BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); #if DEBUG authenticator.Enroll(System.Diagnostics.Debugger.IsAttached); #else authenticator.Enroll(); #endif this.Authenticator.AuthenticatorData = authenticator; newSerialNumberField.Text = authenticator.Serial; newLoginCodeField.Text = authenticator.CurrentCode; newRestoreCodeField.Text = authenticator.RestoreCode; newAuthenticatorProgress.Visible = true; newAuthenticatorTimer.Enabled = true; return; } catch (InvalidEnrollResponseException iere) { if (WinAuthForm.ErrorDialog(this.Owner, "An error occured while registering a new authenticator", iere, MessageBoxButtons.RetryCancel) != System.Windows.Forms.DialogResult.Retry) { break; } } } while (true); clearAuthenticator(false); }
/// <summary> /// Verify and create the authenticator if needed /// </summary> /// <returns>true is successful</returns> private bool verifyAuthenticator() { this.Authenticator.Name = nameField.Text; if (this.tabControl1.SelectedIndex == 0) { if (this.Authenticator.AuthenticatorData == null) { WinAuthForm.ErrorDialog(this.Owner, "You need to create an authenticator and attach it to your account"); return false; } } else if (this.tabControl1.SelectedIndex == 1) { string serial = this.restoreSerialNumberField.Text.Trim(); string restore = this.restoreRestoreCodeField.Text.Trim(); if (serial.Length == 0 || restore.Length == 0) { WinAuthForm.ErrorDialog(this.Owner, "Please enter the Serial number and Restore code"); return false; } try { BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); authenticator.Restore(serial, restore); this.Authenticator.AuthenticatorData = authenticator; } catch (InvalidRestoreResponseException irre) { WinAuthForm.ErrorDialog(this.Owner, "Unable to restore the authenticator: " + irre.Message, irre); return false; } } else if (this.tabControl1.SelectedIndex == 2) { string privatekey = this.importPrivateKeyField.Text.Trim(); if (privatekey.Length == 0) { WinAuthForm.ErrorDialog(this.Owner, "Please enter the Private key"); return false; } // just get the hex chars privatekey = Regex.Replace(privatekey, @"0x", "", RegexOptions.IgnoreCase); privatekey = Regex.Replace(privatekey, @"[^0-9abcdef]", "", RegexOptions.IgnoreCase); if (privatekey.Length == 0 || privatekey.Length < 40) { WinAuthForm.ErrorDialog(this.Owner, "The private key must be a sequence of at least 40 hexadecimal characters, e.g. 7B0BFA82... or 0x7B, 0x0B, 0xFA, 0x82, ..."); return false; } try { BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); if (privatekey.Length == 40) // 20 bytes which is key only { authenticator.SecretKey = WinAuth.Authenticator.StringToByteArray(privatekey); authenticator.Serial = "US-Imported"; } else { authenticator.SecretData = privatekey; if (string.IsNullOrEmpty(authenticator.Serial) == true) { authenticator.Serial = "US-Imported"; } } authenticator.Sync(); this.Authenticator.AuthenticatorData = authenticator; } catch (Exception irre) { WinAuthForm.ErrorDialog(this.Owner, "Unable to import the authenticator. The private key is probably invalid.", irre); return false; } } return true; }
/// <summary> /// Verify and create the authenticator if needed /// </summary> /// <returns>true is successful</returns> private bool verifyAuthenticator() { this.Authenticator.Name = nameField.Text; if (this.tabControl1.SelectedIndex == 0) { if (this.Authenticator.AuthenticatorData == null) { WinAuthForm.ErrorDialog(this.Owner, "You need to create an authenticator and attach it to your account"); return(false); } } else if (this.tabControl1.SelectedIndex == 1) { string serial = this.restoreSerialNumberField.Text.Trim(); string restore = this.restoreRestoreCodeField.Text.Trim(); if (serial.Length == 0 || restore.Length == 0) { WinAuthForm.ErrorDialog(this.Owner, "Please enter the Serial number and Restore code"); return(false); } try { BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); authenticator.Restore(serial, restore); this.Authenticator.AuthenticatorData = authenticator; } catch (InvalidRestoreResponseException irre) { WinAuthForm.ErrorDialog(this.Owner, "Unable to restore the authenticator: " + irre.Message, irre); return(false); } } else if (this.tabControl1.SelectedIndex == 2) { string privatekey = this.importPrivateKeyField.Text.Trim(); if (privatekey.Length == 0) { WinAuthForm.ErrorDialog(this.Owner, "Please enter the Private key"); return(false); } // just get the hex chars privatekey = Regex.Replace(privatekey, @"0x", "", RegexOptions.IgnoreCase); privatekey = Regex.Replace(privatekey, @"[^0-9abcdef]", "", RegexOptions.IgnoreCase); if (privatekey.Length == 0 || privatekey.Length < 40) { WinAuthForm.ErrorDialog(this.Owner, "The private key must be a sequence of at least 40 hexadecimal characters, e.g. 7B0BFA82... or 0x7B, 0x0B, 0xFA, 0x82, ..."); return(false); } try { BattleNetAuthenticator authenticator = new BattleNetAuthenticator(); if (privatekey.Length == 40) // 20 bytes which is key only { authenticator.SecretKey = WinAuth.Authenticator.StringToByteArray(privatekey); authenticator.Serial = "US-Imported"; } else { authenticator.SecretData = privatekey; if (string.IsNullOrEmpty(authenticator.Serial) == true) { authenticator.Serial = "US-Imported"; } } authenticator.Sync(); this.Authenticator.AuthenticatorData = authenticator; } catch (Exception irre) { WinAuthForm.ErrorDialog(this.Owner, "Unable to import the authenticator. The private key is probably invalid.", irre); return(false); } } return(true); }