示例#1
0
        /*****************************************************************************/
        /// <summary>
        /// Determine if verification code is valid. Allows for an extra step (30 sec) future grace period for clocks out of sync and a past grace period, i.e. expiration time
        ///   This version of the function is for unit testing only. Use the version with a datetime.
        /// </summary>
        /// <param name="verificationCode">Code sent to user's device and received from user</param>
        /// <param name="secret">Secret generated for code. Should come from storage</param>
        /// <param name="dtNow">Current data in utc, e.g. DateTime.UtcNow </param>
        /// <param name="gracePeriod">How long code should last (expires)</param>
        /// <returns>Returns true if code is valid</returns>
        public static bool IsValid(int verificationCode, byte[] secret, DateTime dtNow, int expires = TOTPGenerator.Step)
        {
            if (verificationCode == TOTPGenerator.GenerateTOTP(secret, dtNow))
            {
                return(true);
            }

            // One step grace period in future to account for clock's out of sync
            if (verificationCode == TOTPGenerator.GenerateTOTP(secret, dtNow.AddSeconds(TOTPGenerator.Step)))
            {
                return(true);
            }

            // Check up to expiration time
            var periods = expires / TOTPGenerator.Step;

            for (var i = 1; i <= periods; ++i)
            {
                if (verificationCode == TOTPGenerator.GenerateTOTP(secret, dtNow.AddSeconds(-(TOTPGenerator.Step * i))))
                {
                    return(true);
                }
            }

            return(false);
        }
示例#2
0
        /*****************************************************************************/
        /// <summary>
        /// Generates a time-based one-time password (TOTP)
        /// </summary>
        /// <returns>Returns a tuple with generated secret and code  (TOTP). Secret should be persisted (encrypted) for later validation and code should be sent to user's device, e.g. text message</returns>
        public static (byte[] Secret, int Code) GenerateCode()
        {
            var secret = PasswordHasher.CreateSalt(10);  // Create a random set of bytes for the secret
            var code   = TOTPGenerator.GenerateTOTP(secret, DateTime.UtcNow);

            return(secret, code);
        }