private static int CleanOTPDB(PwDatabase db) { //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h == null) { return(0); } { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } List <PwEntry> lEntries = otpdb.RootGroup.GetEntries(true).Where(x => !x.Strings.Exists(Config.OTPFIELD)).ToList(); foreach (PwEntry pe in lEntries) { otpdb.RootGroup.Entries.Remove(pe); } return(lEntries.Count); }
private static int SanitizeSeeds(PwDatabase db) { //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } int i = 0; foreach (PwEntry pe in otpdb.RootGroup.GetEntries(true)) { KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } otp.OTPSeed = otp.OTPSeed; if (otp.SanitizeChanged) { i++; pe.CreateBackup(otpdb); pe.Strings.Set(Config.OTPFIELD, otp.OTPAuthString); } } return(i); }
private void RefreshHandler(PwDatabase db) { Config.UseDBForOTPSeeds(db, cbUseDBForSeeds.Checked); Config.PreloadOTPDB(db, cbPreloadOTP.Checked); m_handler = OTPDAO.GetOTPHandler(db) as OTPDAO.OTPHandler_DB; if (m_handler == null) { m_handler = new OTPDAO.OTPHandler_DB(); m_handler.SetDB(db, false); } }
private void bMigrate_Click(object sender, EventArgs e) { PwDatabase db = m_dDB.ElementAt(lbDB.SelectedIndex).Key; bool bToKeePassOTP = cbMigrate.SelectedItem.ToString().EndsWith("KeePassOTP"); string sPlugin = PluginTranslate.PluginName; MigrationBase mBase = null; string sel = cbMigrate.SelectedItem.ToString(); foreach (KeyValuePair <string, MigrationBase> kvp in m_dMigration) { if (sel.Contains(kvp.Key)) { mBase = kvp.Value; if (bToKeePassOTP) { sPlugin = kvp.Key; } break; } } if (mBase == null) { return; } bool bRemove = Tools.AskYesNo(string.Format(PluginTranslate.MigrateOtherPlugins_Delete, sPlugin)) == DialogResult.Yes; int EntriesOverall; int EntriesMigrated; mBase.SetDB(db); if (bToKeePassOTP) { mBase.MigrateToKeePassOTP(bRemove, out EntriesOverall, out EntriesMigrated); } else { mBase.MigrateFromKeePassOTP(bRemove, out EntriesOverall, out EntriesMigrated); } if ((EntriesMigrated != -1) && (EntriesOverall != -1)) { OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(db) as OTPDAO.OTPHandler_DB; if (h != null) { h.OTPDB_SaveAfterMigration(); } Tools.ShowInfo(string.Format(PluginTranslate.MigrateOtherPlugins_Result, EntriesMigrated, EntriesOverall)); } }
private void cbUseDBForSeeds_CheckedChanged(object sender, EventArgs e) { PwDatabase db = m_dDB.ElementAt(lbDB.SelectedIndex).Key; if (!cbUseDBForSeeds.Checked) { OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(db); if ((h != null) && h.OTPDB_Exists) { DialogResult dr = DialogResult.None; if (!h.HasEntries()) { dr = DialogResult.Yes; } else { dr = MessageBox.Show(string.Format(PluginTranslate.ConfirmOTPDBDelete, DialogResult.Yes.ToString(), DialogResult.No.ToString()), PluginTranslate.PluginName, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); } if (dr == DialogResult.Cancel) { cbUseDBForSeeds.CheckedChanged -= cbUseDBForSeeds_CheckedChanged; cbUseDBForSeeds.Checked = true; cbUseDBForSeeds.CheckedChanged += cbUseDBForSeeds_CheckedChanged; return; } if (dr == DialogResult.Yes) { h.OTPDB_Remove(); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); OTPDAO.InitEntries(db); } else if (dr == DialogResult.No) { h.OTPDB_Close(); OTPDAO.RemoveHandler(db.IOConnectionInfo.Path, true); OTPDAO.InitEntries(db); } } } m_dDB[db].UseOTPDB = cbUseDBForSeeds.Checked; cbPreloadOTP.Enabled = cbUseDBForSeeds.Checked; DBAction_Init(db); }
private static int ProcessReferences(PwDatabase db) { //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } if (otpdb == null || !otpdb.IsOpen) { return(-1); } int i = 0; var b = new OTPHandler_Base(); foreach (PwEntry pe in otpdb.RootGroup.GetEntries(true)) { KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } if (!otp.Issuer.ToLowerInvariant().Contains("{ref:") && !otp.Label.ToLowerInvariant().EndsWith("{ref")) { continue; } PwEntry peMain = h is OTPHandler_DB ? (h as OTPHandler_DB).GetMainPwEntry(pe) : pe; b.InitIssuerLabel(otp, peMain); pe.CreateBackup(otpdb); pe.Strings.Set(Config.OTPFIELD, otp.OTPAuthString); i++; } return(i); }
private static int CheckOTPDataMigration(PwDatabase db) { const string SEED = "KeePassOTP.Seed"; const string SETTINGS = "KeePassOTP.Settings"; //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } List <PwEntry> lEntries = otpdb.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(SEED) && x.Strings.Exists(SETTINGS)).ToList(); int migrated = 0; foreach (PwEntry pe in lEntries) { ProtectedString seed = pe.Strings.Get(SEED); string settings = pe.Strings.ReadSafe(SETTINGS); string title = pe.Strings.ReadSafe(PwDefs.TitleField); string user = pe.Strings.ReadSafe(PwDefs.UserNameField); if (string.IsNullOrEmpty(title)) { title = PluginTranslation.PluginTranslate.PluginName; } if (!string.IsNullOrEmpty(user)) { user = "******" + user; } KPOTP otp = ConvertOTPSettings(settings); otp.OTPSeed = seed; otp.Issuer = title; otp.Label = user; ProtectedString result = otp.OTPAuthString; pe.CreateBackup(db); pe.Strings.Remove(SEED); pe.Strings.Remove(SETTINGS); pe.Strings.Set(Config.OTPFIELD, result); if (h == null) { pe.Touch(true); } migrated++; } if (migrated > 0) { db.Modified = true; if (h == null) { Program.MainForm.UpdateUI(false, null, false, null, false, null, db == Program.MainForm.ActiveDatabase); } } return(migrated); }
private static int OTPAuthFormatCorrection(PwDatabase db) { //Get DB to work on PwDatabase otpdb = db; OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { if (!h.EnsureOTPUsagePossible(null)) { return(-1); } otpdb = h.OTPDB; } int i = 0; foreach (PwEntry pe in otpdb.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(Config.OTPFIELD))) { //Don't compare strings because strings are not protected and will remain in memory char[] ps = pe.Strings.Get(Config.OTPFIELD).ReadChars(); try { if (ps.Length < 15) { continue; } bool bConvert = false; foreach (char[] check in lOTPAuthStart) { if (check.Length > ps.Length) { continue; } bConvert = true; for (int j = 0; j < check.Length; j++) { if (Char.ToLowerInvariant(check[j]) != Char.ToLowerInvariant(ps[j])) { bConvert = false; break; } } if (bConvert) { break; } } if (!bConvert) { break; } KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } i++; pe.CreateBackup(otpdb); pe.Strings.Set(Config.OTPFIELD, otp.OTPAuthString); } finally { MemUtil.ZeroArray(ps); } } return(i); }
/// <summary> /// Perform all kind of migrations between different KeePassOTP versions /// </summary> /// <param name="db"></param> /// <returns>true if something was migrated, false if nothing was done</returns> private static bool CheckAndMigrate(PwDatabase db, OTP_Migrations omFlags) { const string Migration_EntryDB = "KeePassOTP.MigrationStatus"; const string Migration_OTPDB = "KeePassOTPDB.MigrationStatus"; string sMigrationStatus = string.Empty; bool bMigrated = false; //Get DB to work on OTPDAO.OTPHandler_DB h = GetOTPHandler(db); if (h != null) { sMigrationStatus = Migration_OTPDB; } else { sMigrationStatus = Migration_EntryDB; } OTP_Migrations omStatusOld = OTP_Migrations.None; if (!OTP_Migrations.TryParse(db.CustomData.Get(sMigrationStatus), out omStatusOld)) { omStatusOld = OTP_Migrations.None; } OTP_Migrations omStatusNew = omStatusOld; if (MigrationRequired(OTP_Migrations.Entry2CustomData, omFlags, omStatusOld)) { if (!db.UseDBForOTPSeeds() || !db.CustomData.Exists(OTPDAO.OTPHandler_DB.DBNAME)) { PwEntry pe = OTPHandler_DB.GetOTPDBEntry(db); if (pe != null) { bMigrated = true; OTPDAO.MigrateToCustomdata(db, pe); } } omStatusNew |= OTP_Migrations.Entry2CustomData; } if (MigrationRequired(OTP_Migrations.KeePassOTP2OtpAuth, omFlags, omStatusOld)) { int r = CheckOTPDataMigration(db); bMigrated |= r > 0; if (r >= 0) { omStatusNew |= OTP_Migrations.KeePassOTP2OtpAuth; } } if (MigrationRequired(OTP_Migrations.SanitizeSeed, omFlags, omStatusOld)) { int r = SanitizeSeeds(db); bMigrated |= r > 0; if (r >= 0) { omStatusNew |= OTP_Migrations.SanitizeSeed; } } if (MigrationRequired(OTP_Migrations.OTPAuthFormatCorrection, omFlags, omStatusOld)) { int r = OTPAuthFormatCorrection(db); bMigrated |= r > 0; if (r >= 0) { omStatusNew |= OTP_Migrations.OTPAuthFormatCorrection; } } if ((omStatusNew != omStatusOld) || bMigrated) { db.CustomData.Set(sMigrationStatus, omStatusNew.ToString()); db.SettingsChanged = DateTime.UtcNow; db.Modified = true; Program.MainForm.UpdateUI(false, null, false, null, false, null, Program.MainForm.ActiveDatabase == db); } return(bMigrated); }
public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(m_db); if ((h != null) && !h.EnsureOTPUsagePossible(null)) { return; } PwObjectList <PwEntry> lEntries = m_db.RootGroup.GetEntries(true); if (lEntries.Count() == 0) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries.GetAt(0)); InitLogger("KeePassOTP -> KeeTrayTOTP", lEntries.Count()); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } EntriesOverall++; if (otp.Encoding != KPOTPEncoding.BASE32) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Encoding not supported: " + otp.Encoding.ToString()); continue; } if (otp.Hash != KPOTPHash.SHA1) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Hash not supported: " + otp.Hash.ToString()); continue; } if (otp.Type != KPOTPType.TOTP) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString()); continue; } string settings = otp.TOTPTimestep.ToString() + ";" + otp.Length.ToString(); if (otp.TimeCorrectionUrlOwn) { settings += ";" + pe.Strings.ReadSafe(PwDefs.UrlField); } else if (!string.IsNullOrEmpty(otp.TimeCorrectionUrl)) { settings += ";" + otp.TimeCorrectionUrl; } pe.Strings.Set("TOTP Seed", otp.OTPSeed); pe.Strings.Set("TOTP Settings", new ProtectedString(false, settings)); EntriesMigrated++; if (bRemove) { otp.OTPSeed = ProtectedString.EmptyEx; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } } } } finally { EndLogger(); } MigratePlaceholder(Config.Placeholder, OtherPluginPlaceholder, false); }
public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(m_db); if ((h != null) && !h.EnsureOTPUsagePossible(null)) { return; } PwObjectList <PwEntry> lEntries = m_db.RootGroup.GetEntries(true); if (lEntries.Count() == 0) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries.GetAt(0)); InitLogger("KeePassOTP -> KeeOTP", lEntries.Count()); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } EntriesOverall++; if (otp.Encoding != KPOTPEncoding.BASE32) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Encoding not supported: " + otp.Encoding.ToString()); continue; } if (otp.Hash != KPOTPHash.SHA1) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Hash not supported: " + otp.Hash.ToString()); continue; } if (otp.Type != KPOTPType.TOTP) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString()); continue; } string s = "key=" + otp.OTPSeed.ReadString(); if (otp.Length != 6) { s += "&size=" + otp.Length.ToString(); } if (otp.Type == KPOTPType.HOTP) { s += "&type=hotp"; if (otp.HOTPCounter > 0) { s += "&counter=" + otp.HOTPCounter.ToString(); } } if ((otp.Type == KPOTPType.TOTP) && (otp.TOTPTimestep != 30)) { s += "&step=" + otp.TOTPTimestep.ToString(); } pe.Strings.Set("otp", new ProtectedString(true, s)); if (pe.Strings.Exists("otp")) { EntriesMigrated++; } if (bRemove) { otp.OTPSeed = ProtectedString.EmptyEx; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } } } } finally { EndLogger(); } MigratePlaceholder(Config.Placeholder, OtherPluginPlaceholder, false); }
public override void MigrateFromKeePassOTP(bool bRemove, out int EntriesOverall, out int EntriesMigrated) { EntriesOverall = EntriesMigrated = -1; if (!m_bInitialized) { return; } EntriesOverall = EntriesMigrated = 0; OTPDAO.OTPHandler_DB h = OTPDAO.GetOTPHandler(m_db); if ((h != null) && !h.EnsureOTPUsagePossible(null)) { return; } PwObjectList <PwEntry> lEntries = m_db.RootGroup.GetEntries(true); if (lEntries.Count() == 0) { return; } OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries.GetAt(0)); InitLogger("KeePassOTP -> KeeTrayTOTP", lEntries.Count()); try { foreach (PwEntry pe in lEntries) { IncreaseLogger(); KPOTP otp = OTPDAO.GetOTP(pe); if (!otp.Valid) { continue; } EntriesOverall++; if (otp.Type != KPOTPType.HOTP && otp.Type != KPOTPType.TOTP) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString()); continue; } if (otp.Type == KPOTPType.TOTP) { if (Tools.KeePassVersion < m_vKeePass247) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Type not supported: " + otp.Type.ToString(), "Minimum required KeePass version: " + m_vKeePass247.ToString()); } foreach (var line in m_dTotpStrings) { if (line.Key == otp.Encoding) { pe.Strings.Set(line.Value, otp.OTPSeed); } else { pe.Strings.Remove(line.Value); } } if (otp.TOTPTimestep == 30) { pe.Strings.Remove(TOTPPERIOD); } else { pe.Strings.Set(TOTPPERIOD, new ProtectedString(false, otp.TOTPTimestep.ToString())); } if (otp.Length == 6) { pe.Strings.Remove(TOTPLENGTH); } else { pe.Strings.Set(TOTPLENGTH, new ProtectedString(false, otp.Length.ToString())); } if (otp.Hash == KPOTPHash.SHA1) { pe.Strings.Remove(TOTPHASH); } else if (otp.Hash == KPOTPHash.SHA256) { pe.Strings.Set(TOTPHASH, new ProtectedString(false, "HMAC-SHA-256")); } else if (otp.Hash == KPOTPHash.SHA512) { pe.Strings.Set(TOTPHASH, new ProtectedString(false, "HMAC-SHA-512")); } bool bDummy; MigratePlaceholder(Config.Placeholder, PLACEHOLDER_TOTP, pe, out bDummy); } else if (otp.Type == KPOTPType.HOTP) { if (otp.Length != 6) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Length not supported: " + otp.Length.ToString()); continue; } if (otp.Hash != KPOTPHash.SHA1) { PluginDebug.AddError("Migration of entry failed", "Uuid: " + pe.Uuid.ToHexString(), "Hash not supported: " + otp.Hash.ToString()); continue; } foreach (var line in m_dHotpStrings) { if (line.Key == otp.Encoding) { pe.Strings.Set(line.Value, otp.OTPSeed); } else { pe.Strings.Remove(line.Value); } } pe.Strings.Set(HOTP_COUNTER, new ProtectedString(false, otp.HOTPCounter.ToString())); bool bDummy; MigratePlaceholder(Config.Placeholder, PLACEHOLDER_HOTP, pe, out bDummy); } EntriesMigrated++; if (bRemove) { otp.OTPSeed = ProtectedString.EmptyEx; try { handler.IgnoreBuffer = true; OTPDAO.SaveOTP(otp, pe); } finally { handler.IgnoreBuffer = false; } } } } finally { EndLogger(); } MigratePlaceholder(Config.Placeholder, PLACEHOLDER_TOTP); //In case something is defined on group level (could be right, could be wrong, ...) }