Otp.NET icon indicating copy to clipboard operation
Otp.NET copied to clipboard

How to match the code with a flutter library?

Open tareq2 opened this issue 2 years ago • 2 comments

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?

tareq2 avatar Apr 26 '23 13:04 tareq2

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: https://github.com/kspearrin/Otp.NET/blob/0ac3c315d3d64aa7a89361167fe2e8be8b512ff7/src/Otp.NET/InMemoryKey.cs#L71-L74

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)

exelix11 avatar Sep 13 '23 13:09 exelix11

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

mcessna avatar Jan 23 '24 21:01 mcessna