예제 #1
0
        /// <summary>
        /// Remove spaces and in case of BASE32 correct some characters that are misread often
        /// </summary>
        /// <param name="seed"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        private ProtectedString SanitizeSeed(ProtectedString seed, KPOTPEncoding encoding)
        {
            Dictionary <byte, byte> dReplace = new Dictionary <byte, byte>();

            dReplace[(byte)'0'] = (byte)'O';
            dReplace[(byte)'1'] = (byte)'L';
            dReplace[(byte)'8'] = (byte)'B';
            try
            {
                ProtectedString work = ProtectedString.EmptyEx;
                foreach (byte b in seed.ReadUtf8())
                {
                    if ((char)b == ' ')
                    {
                        SanitizeChanged = true;                         //Remember we changed something, important for .Equals
                        continue;
                    }
                    if ((encoding == KPOTPEncoding.BASE32) && dReplace.ContainsKey(b))
                    {
                        SanitizeChanged = true;                         //Remember we changed something, important for .Equals
                        work           += new ProtectedString(true, new byte[] { dReplace[b] });
                    }
                    else
                    {
                        work += new ProtectedString(true, new byte[] { b });
                    }
                }
                return(work);
            }
            catch { return(ProtectedString.EmptyEx); }
        }
예제 #2
0
        private void MigrateToKeePassOTP_Totp(bool bRemove, out int EntriesOverall, out int EntriesMigrated)
        {
            EntriesOverall = EntriesMigrated = 0;
            Dictionary <PwEntry, KPOTPEncoding> dEntries = new Dictionary <PwEntry, KPOTPEncoding>();

            foreach (KeyValuePair <KPOTPEncoding, string> kvp in m_dTotpStrings)
            {
                List <PwEntry> lHelp = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(kvp.Value)).ToList();
                foreach (PwEntry pe in lHelp)
                {
                    if (!dEntries.ContainsKey(pe))
                    {
                        dEntries[pe] = kvp.Key;
                    }
                }
            }
            EntriesOverall = dEntries.Count;
            if (dEntries.Count == 0)
            {
                return;
            }

            if (!OTPDAO.EnsureOTPSetupPossible(dEntries.Keys.First()))
            {
                return;
            }
            OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(dEntries.Keys.First());
            InitLogger("KeePass -> KeePassOTP (TOTP)", dEntries.Count);
            try
            {
                foreach (KeyValuePair <PwEntry, KPOTPEncoding> kvp in dEntries)
                {
                    IncreaseLogger();
                    KPOTPEncoding enc = kvp.Value;
                    PwEntry       pe  = kvp.Key;

                    var otp = OTPDAO.GetOTP(pe);
                    otp.Encoding = enc;
                    otp.OTPSeed  = new ProtectedString(true, MigrateString(pe.Strings.ReadSafe(m_dTotpStrings[enc])));

                    string hash = pe.Strings.ReadSafe(TOTPHASH).ToLowerInvariant();
                    if (hash.Contains("sha-512"))
                    {
                        otp.Hash = KPOTPHash.SHA512;
                    }
                    else if (hash.Contains("sha-256"))
                    {
                        otp.Hash = KPOTPHash.SHA256;
                    }
                    else
                    {
                        otp.Hash = KPOTPHash.SHA1;
                    }

                    otp.Length       = MigrateInt(pe.Strings.ReadSafe(TOTPLENGTH), 6);
                    otp.TOTPTimestep = MigrateInt(pe.Strings.ReadSafe(TOTPPERIOD), 30);

                    otp.HOTPCounter = MigrateInt(pe.Strings.ReadSafe(HOTP_COUNTER), 0);
                    if (otp.Valid)
                    {
                        EntriesMigrated++;
                        try
                        {
                            handler.IgnoreBuffer = true;
                            OTPDAO.SaveOTP(otp, pe);
                        }
                        finally { handler.IgnoreBuffer = false; }
                        if (bRemove)
                        {
                            pe.Strings.Remove(m_dTotpStrings[enc]);
                            pe.Strings.Remove(TOTPHASH);
                            pe.Strings.Remove(TOTPLENGTH);
                            pe.Strings.Remove(TOTPPERIOD);
                        }
                    }
                    else
                    {
                        PluginDebug.AddError("Migration of entry failed",
                                             "Uuid: " + pe.Uuid.ToHexString(),
                                             "OTP data: " + m_dHotpStrings[enc]);
                    }
                }
            }
            finally
            {
                EndLogger();
            }
            MigratePlaceholder(PLACEHOLDER_TOTP, Config.Placeholder);
        }
예제 #3
0
        private void SetOTPAuthString(ProtectedString value)
        {
            m_key  = null;
            m_seed = ProtectedString.EmptyEx;
            Issuer = PluginTranslation.PluginTranslate.PluginName;
            Label  = string.Empty;

            //otpauth strings contain all parameters and the seed
            //we do NOT want to remove protection from the seed

            int idx         = 0;
            int i           = 0;
            int secretstart = -1;

            char[] c = value.ReadChars();
            try
            {
                List <char> lSecret1 = new List <char>(("?secret=").ToCharArray());
                List <char> lSecret2 = new List <char>(("&secret=").ToCharArray());

                //Search for parameter 'secret'
                for (i = 0; i < c.Length; i++)
                {
                    char check = char.ToLower(c[i]);
                    if ((check != lSecret1[idx]) && (check != lSecret2[idx]))
                    {
                        idx = 0;
                        continue;
                    }
                    idx++;
                    if (idx == lSecret1.Count)
                    {
                        secretstart = i + 1;
                        break;
                    }
                }
                if (secretstart == -1)
                {
                    return;
                }
                idx = 0;
                for (i = secretstart; i < c.Length; i++)
                {
                    if (c[i] == '&')
                    {
                        break;
                    }
                    idx++;
                }
            }
            finally { MemUtil.ZeroArray(c); }

            ProtectedString seed = value.Remove(secretstart + idx, value.Length - secretstart - idx);

            seed = seed.Remove(0, secretstart);

            string s          = value.Remove(secretstart, idx).ReadString();
            Uri    u          = new Uri(s);
            var    parameters = System.Web.HttpUtility.ParseQueryString(u.Query);

            if (parameters.Count < 1)
            {
                return;
            }
            List <string> lKeys = parameters.AllKeys.ToList();

            string sLabelIssuer = u.AbsolutePath;

            if (!string.IsNullOrEmpty(sLabelIssuer))
            {
                List <string> lIssuer = sLabelIssuer.Split(new string[] { ":", "%3a", "%3A" }, StringSplitOptions.None).ToList();
                if (lIssuer.Count > 1)
                {
                    Label  = Decode(lIssuer[1]).Replace("/", string.Empty);
                    Issuer = Decode(lIssuer[0]).Replace("/", string.Empty);
                }
                else if (lIssuer.Count == 1)
                {
                    Label = Decode(lIssuer[0]).Replace("/", string.Empty);
                }
            }

            Type = u.Host.ToLowerInvariant() == "hotp" ? KPOTPType.HOTP : KPOTPType.TOTP;
            if (Type == KPOTPType.TOTP)
            {
                TOTPTimestep = MigrateInt(parameters.Get("period"), 30);
            }
            else
            {
                HOTPCounter = MigrateInt(parameters.Get("counter"), 0);
            }
            string hash = parameters.Get("algorithm");

            if (!string.IsNullOrEmpty(hash))
            {
                hash = hash.ToLowerInvariant();
            }
            Hash = KPOTPHash.SHA1;
            if (hash == "sha256")
            {
                Hash = KPOTPHash.SHA256;
            }
            else if (hash == "sha512")
            {
                Hash = KPOTPHash.SHA512;
            }
            Length = MigrateInt(parameters.Get("digits"), 6);

            string encoding = parameters.Get("encoding");

            if (!string.IsNullOrEmpty(encoding))
            {
                encoding = encoding.ToLowerInvariant();
            }
            Encoding = KPOTPEncoding.BASE32;
            if (encoding == "base64")
            {
                Encoding = KPOTPEncoding.BASE64;
            }
            else if (encoding == "hex")
            {
                Encoding = KPOTPEncoding.HEX;
            }
            else if (encoding == "utf8")
            {
                Encoding = KPOTPEncoding.UTF8;
            }

            string    encoder = parameters.Get("encoder");
            KPOTPType tType   = Type;

            if (Enum.TryParse(encoder, true, out tType))
            {
                Type = tType;
            }

            string sIssuerParameter = parameters.Get("issuer");

            if (!string.IsNullOrEmpty(sIssuerParameter))
            {
                Issuer = Decode(sIssuerParameter);
            }

            //Remove %3d / %3D at the end of the seed
            c   = seed.ReadChars();
            idx = c.Length - 3;
            i   = 0;
            while (idx > 0)
            {
                if ((c[idx] == '%') && (c[idx + 1] == '3') && (char.ToLowerInvariant(c[idx + 2]) == 'd'))
                {
                    i++;
                    idx -= 3;
                }
                else
                {
                    break;
                }
            }
            if (i > 0)
            {
                seed = seed.Remove(seed.Length - (i * 3), i * 3);
            }

            SetSeed(seed);
        }
예제 #4
0
        private void MigrateToKeePassOTP_Hotp(bool bRemove, out int EntriesOverall, out int EntriesMigrated)
        {
            EntriesOverall = EntriesMigrated = 0;
            List <PwEntry> lEntries = m_db.RootGroup.GetEntries(true).Where(x => x.Strings.Exists(HOTP_COUNTER)).ToList();

            EntriesOverall = lEntries.Count;
            if (lEntries.Count == 0)
            {
                return;
            }

            if (!OTPDAO.EnsureOTPSetupPossible(lEntries[0]))
            {
                return;
            }
            OTPDAO.OTPHandler_Base handler = OTPDAO.GetOTPHandler(lEntries[0]);
            InitLogger("KeePass -> KeePassOTP (HOTP)", lEntries.Count);
            try
            {
                foreach (PwEntry pe in lEntries)
                {
                    IncreaseLogger();
                    KPOTPEncoding enc    = KPOTPEncoding.BASE32;
                    bool          bFound = false;
                    string        seed   = null;
                    foreach (KeyValuePair <KPOTPEncoding, string> kvp in m_dHotpStrings)
                    {
                        if (pe.Strings.Exists(kvp.Value))
                        {
                            enc    = kvp.Key;
                            seed   = pe.Strings.ReadSafe(kvp.Value);
                            bFound = true;
                            break;
                        }
                    }
                    if (!bFound)
                    {
                        PluginDebug.AddError("Migration of entry failed",
                                             "Uuid: " + pe.Uuid.ToHexString(),
                                             "OTP data: not defined");
                        continue;
                    }
                    var otp = OTPDAO.GetOTP(pe);
                    otp.Type        = KPOTPType.HOTP;
                    otp.Encoding    = enc;
                    otp.OTPSeed     = new ProtectedString(true, MigrateString(seed));
                    otp.HOTPCounter = MigrateInt(pe.Strings.ReadSafe(HOTP_COUNTER), 0);
                    if (otp.Valid)
                    {
                        EntriesMigrated++;
                        try
                        {
                            handler.IgnoreBuffer = true;
                            OTPDAO.SaveOTP(otp, pe);
                        }
                        finally { handler.IgnoreBuffer = false; }
                        if (bRemove)
                        {
                            pe.Strings.Remove(m_dHotpStrings[enc]);
                            pe.Strings.Remove(HOTP_COUNTER);
                        }
                    }
                    else
                    {
                        PluginDebug.AddError("Migration of entry failed",
                                             "Uuid: " + pe.Uuid.ToHexString(),
                                             "OTP data: " + m_dHotpStrings[enc]);
                    }
                }
            }
            finally
            {
                EndLogger();
            }
            MigratePlaceholder(PLACEHOLDER_HOTP, Config.Placeholder);
        }