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