Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to match the code with a flutter library? #44

Open
tareq2 opened this issue Apr 26, 2023 · 2 comments
Open

How to match the code with a flutter library? #44

tareq2 opened this issue Apr 26, 2023 · 2 comments

Comments

@tareq2
Copy link

tareq2 commented Apr 26, 2023

Hello everyone,
I am using the library dart-otp in a flutter app that generate the code and i need to validate this code in c# but i couldn't validate this code nor generate the same code from the two libraries.
The code in flutter/dart is

var now = DateTime.now();
      now = DateTime(2023, 04, 26, 10, 10, 10);

      var code = OTP.generateTOTPCodeString(
          'DDXFM42476476545', now.millisecondsSinceEpoch,
          algorithm: Algorithm.SHA256, isGoogle: false);

      print(code);  // Out 667099

In C# the code is

string skey = "DDXFM42476476545";

            var  now = new DateTime(2023, 04, 26, 10, 10, 10);
            var totp = new Totp(Base32Encoding.ToBytes(skey),30,OtpHashMode.Sha256);
            var code = totp.ComputeTotp(now);
 //code = 734057

Can anyone help to figure this difference?

@exelix11
Copy link

exelix11 commented Sep 13, 2023

I just encountered this myself and had to investigate since i needed interoperability. The problem is that dart-otp has a different behavior due to the isGoogle flag. When it is false it does two weird things as seen here https://github.com/daegalus/dart-otp/blob/09597cd5277d3d602de2bb715102a07c7f387088/lib/otp.dart#L96-L105

  • First, it willl decode the secret as unicode bytes rather than as base32
  • Secondly, it will pad the secret by repeating it using a fixed key length, key padding code. algorithm key lengths

However this library hardcodes a zero-extension padding and always extends the key to a multiple of 16 bytes here:

_keyLength = key.Length;
var paddedKeyLength = (int)Math.Ceiling((decimal)key.Length / (decimal)16) * 16;
_keyData = new byte[paddedKeyLength];
Array.Copy(key, _keyData, key.Length);

in OP's case the fix is to set isGoogle to true, then dart produces the expected 734057 value. If like me you need compatibility with an isGoogle = false app then you'll have to do some convincing to get this library to work:

  • Use Encoding.ASCII.GetBytes instead of Base32Encoding.ToBytes
  • Maunally extend the secret string to the right length, in OP''s case sh256 uses 32 bytes so the key would be DDXFM42476476545DDXFM42476476545

This produces the OTP value 500288 which is different from what OP claims but i get the same result when running the first dart snippet, not sure why.

As i don't know the RFC standard i can't tell which library is wrong here, i can say that i also tested a nodejs library and with no additional tweaking it seems to agree with otp-dart, making this implementation the odd one out (at least as far as defaults go)

@mcessna
Copy link

mcessna commented Jan 23, 2024

@tareq2 Is the DateTime value passed to ComputeTotp in UTC format? It should be a UTC DateTime value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants