/// <summary>
        /// 生成用户可扫描的谷歌认证初始码
        /// </summary>
        /// <param name="issuer">发行者</param>
        /// <param name="accountTitleNoSpaces">帐户名</param>
        /// <param name="accountSecretKey">共享密钥</param>
        /// <returns>SetupCode object</returns>
        public SetupCode GenerateSetupCode(string issuer, string accountTitleNoSpaces, string accountSecretKey)
        {
            if (string.IsNullOrEmpty(accountTitleNoSpaces))
            {
                throw new NullReferenceException("Account Title is null");
            }

            accountTitleNoSpaces = accountTitleNoSpaces.Replace(" ", "");

            SetupCode sC = new SetupCode();

            sC.Account          = accountTitleNoSpaces;
            sC.AccountSecretKey = accountSecretKey;

            //base32加密
            string encodedSecretKey = Base32Encode.Encode(accountSecretKey);

            sC.ManualEntryKey = encodedSecretKey;

            string provisionUrl = null;

            if (string.IsNullOrEmpty(issuer))
            {
                provisionUrl = String.Format("otpauth://totp/{0}?secret={1}", accountTitleNoSpaces, encodedSecretKey);
            }
            else
            {
                provisionUrl = String.Format("otpauth://totp/{0}?secret={1}&issuer={2}", accountTitleNoSpaces, encodedSecretKey, UrlEncode(issuer));
            }

            sC.QrCodeSetupUrl = provisionUrl;

            return(sC);
        }
        public bool ValidatePIN(string accountSecretKey, string pinCode, TimeSpan timeTolerance)
        {
            accountSecretKey = Base32Encode.Decode(accountSecretKey);
            var codes = GetCurrentPINs(accountSecretKey, timeTolerance);

            return(codes.Any(c => c == pinCode));
        }