ChristianRiesen/otp

OTP code lasts for 60s even if I set period to 30

Closed this issue · 3 comments

mig5 commented

Please help!

My 'verify' function has like this:

    public function verify($secret, $code, $period = 30, $digest = "sha1", $digits = 6)
    {
        $otp = new Otp();
        $otp->setPeriod($period);
        $otp->setDigits($digits);
        $otp->setAlgorithm($digest);
        return $otp->checkTotp(Encoding::base32DecodeUpper($secret), $code);
    }

The $secret is derived from your generateSecret() function, but with length of 64 (but I get the same with 16 so I know it's not that)

        $keys = array_merge(range('A','Z'), range(2,7)); // No padding char
        $secret = '';
        for ($i = 0; $i < 64; $i++) {
            $secret .= $keys[random_int(0, 31)];
        }
        return $secret;

When I get the OTP code in my authenticator, I run a script that calls the verify function with the $secret and the $code passed in (not overriding any other values), and it lasts for 60s:

$ while true; do date; ~/otp.sh 542566; echo ""; sleep 1; done
Thu Sep 21 06:35:33 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:35 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:37 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:40 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:42 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:44 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:46 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:49 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:51 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:53 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:56 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:35:58 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:00 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:03 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:05 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:07 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:10 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:12 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:14 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:16 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:19 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:21 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:23 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:26 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:28 UTC 2023
 
{"success":"1"}
Thu Sep 21 06:36:30 UTC 2023
 
{"error":{"message":"The code was invalid"}}
Thu Sep 21 06:36:33 UTC 2023

Why is this the case? What have I misunderstood?

Running Ubuntu 20.04 LTS. The server timezone is in UTC, and I was running the script on the same machine as the PHP app.

PHP 7.4.33 (cli) (built: Sep  2 2023 08:03:15) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.33, Copyright (c), by Zend Technologies
    with Xdebug v3.1.6, Copyright (c) 2002-2022, by Derick Rethans
mig5 commented

Sorry, I think I misunderstood the '1 code timedrift', or rather I read that as '1 second drift', not an entire 'code lifecycle'. My bad!

Thanks!

Hi. Here is the signature of checkTotp:
public function checkTotp($secret, $key, $timedrift = 1)

That last parameter $timedrift, is what you want to look at. The default is that it will accept a key one "off" from the actual current one, to ensure that even if a user is a bit slow in entering or the time syncs between user and server are not perfect, you still get a "valid" here. 1 means it will accept one before and one after from the current one, so technically 3 different codes are "valid". If you set it to 0, only the "current" one is valid.

In any case, you want to have some ephemeral storage in your application to make sure the same code can't be used within the time window (timedrift * 2 * 30 seconds + 30 seconds) withthe same user. I for example use redis to store that with a TTL setting that makes it expire.

Edit: You posted your closing comment just a bit before I was able to send this response, but I'll leave it here anyways for posterity and in case someone else comes across this :)

mig5 commented

Snap, thanks @ChristianRiesen , I realized this at exactly the same moment :) Thanks again!