daegalus / dart-otp

RFC6238 Time-Based One-Time Password / Google Authenticator Library
MIT License
101 stars 25 forks source link

Both methods for HOTP or TOTP code generation generates the same result #10

Closed OttoChamo closed 5 years ago

OttoChamo commented 5 years ago

Is it an expected behavior that both methods for OTP generation keep generating the same value even when we set a time interval?

daegalus commented 5 years ago

Can you provide an example piece.of code on how you test this and got this result? Only way I can see reproducing this is if you pass time into the HOTP function

OttoChamo commented 5 years ago

I do pass time to both of the functions while I've been testing them, I have tried with different values for the time parameter even with 0 and It is not changing the value in every way.

This snippet of code is just having a FAB on the screen which will call the _generateToken function for each tap and display it on the screen.

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _token = 0;

  void _generateToken() {
    setState(() {
      _token = otpGenerated();
      print(_token);
    });
  }

  int otpGenerated() {
    return OTP.generateTOTPCode(
       "aRandOMSECRET", 0,
        interval: 30, length: 6, algorithm: Algorithm.SHA1); // I don't k
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('your token \n$_token',
                  style: Theme.of(context).textTheme.display1),
            ],
          ),
        ),
        /*floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),*/
        floatingActionButton: FloatingActionButton(
            onPressed: _generateToken,
            tooltip: 'Generate Token',
            child: Icon(Icons
                .access_alarm))
        );
  }
}
amadejkastelic commented 5 years ago

Time parameter is in ms, interval parameter is in seconds. You're probably passing in the wrong value for time or just not waiting long enough, because code stays the same for 30 seconds in your case. Try to pass in DateTime.now().millisecondsSinceEpoch and set interval to 1 second.

daegalus commented 5 years ago

Well, if you pass 0, they will both return the same number. for HOTP tokens, you have to increment the value yourself every time, otherwise it will just keep generating the same number. the "time" and "count" parameters for TOTP and HOTP respectively are the seeds to the random number generator. If you pass in the same seed, you get the same result.

The only difference between TOTP and HOTP is that you use Time as the seed for TOTP, and I divide time by the interval (which defaults to 30 seconds). this is so that we get the same code for the whole 30 second slot.

If you set the Interval to 1 for TOTP and pass time into both functions, they will always be the same.

if you pass a time of 3 to TOTP and a count of 3 to HOTP (aka, the same seed), you should get different results, because the TOTP is divided by 1000 (to convert from milliseconds to seconds), then divided by the interval (default is 30), then floor(), which results in 0. while the HOTP will stay 3. which should give you 2 different codes.

30000 (30 seconds) for TOTP with default interval and 1 for HOTP will also give the same result.

since all the options are optional and have sane defaults, you can just do

int otpGenerated() {
    return OTP.generateTOTPCode("aRandOMSECRET", DateTime.now().millisecondsSinceEpoch)
}

To generate a new OTP every 30 seconds. If you need to generate 30 seconds before, and 30 seconds after for safety or server-side checking. you can just do DateTime.now().millisecondsSinceEpoch-30000 and DateTime.now().millisecondsSinceEpoch+30000 accordingly in your code if you ever need that.

But since this looks like a Flutter app, and is client side, you only need the current code.

I hope this helps.

daegalus commented 5 years ago

Havent heard a response in a while, I closing this. If its still an issue, please reopen.