I've a problem with Otp.NET lib for TOTP generation/verification. Due to some reasons I've a requirement where I need to generate totp codes valid up to some days.
But following test code does not work:
using OtpNet;
using System;
// Secret key for TOTP (must be consistent across all tests)
byte[] secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP");
// Create a Totp instance with an optional time offset
Totp totpGenerator = new Totp(secretKey);
// Simulate generating TOTP at different dates
DateTime generationTime = DateTime.Now;
string totpCode = totpGenerator.ComputeTotp(generationTime);
Console.WriteLine($"TOTP generated on {generationTime}: {totpCode}");
TestTotpValidity(totpCode, generationTime.AddDays(5)); // 5 days later. this should be valid but is invalid.
TestTotpValidity(totpCode, generationTime.AddDays(-5)); // 5 days earlier. this should be not valid but is valid.
TestTotpValidity(totpCode, generationTime.AddDays(7)); // 7 days later. this should be valid but is invalid.
TestTotpValidity(totpCode, generationTime.AddDays(-7)); // 7 days earlier. this should be not valid but is valid.
TestTotpValidity(totpCode, generationTime.AddDays(8)); // 8 days later. This should be invalid and is invalid.
TestTotpValidity(totpCode, generationTime.AddDays(-8)); // 8 days earlier. this should be not valid and is invalid.
void TestTotpValidity(string totpCode, DateTime verificationTime)
{
var validator = new Totp(secretKey);
long timeStepMatched;
bool isValid = validator.VerifyTotp(verificationTime, totpCode, out timeStepMatched, new VerificationWindow(previous: 2, future: 2880 * 7)); // Custom verification window. 2880 steps / day -> 4 days
Console.ForegroundColor = isValid ? ConsoleColor.DarkGreen : ConsoleColor.DarkRed;
Console.WriteLine($"Verifying TOTP on {verificationTime} (time step matched {timeStepMatched}): {isValid}");
Console.ResetColor();
}
This is the console output:
TOTP generated on 05/16/2024 10:08:22: 935002
39;49mVerifying TOTP on 05/21/2024 10:08:22 (time step matched 0): False
[39;49m[39;49mVerifying TOTP on 05/11/2024 10:08:22 (time step matched 57195136): True
[39;49m[39;49mVerifying TOTP on 05/23/2024 10:08:22 (time step matched 0): False
[39;49m[39;49mVerifying TOTP on 05/09/2024 10:08:22 (time step matched 57195136): True
[39;49m[39;49mVerifying TOTP on 05/24/2024 10:08:22 (time step matched 0): False
[39;49m[39;49mVerifying TOTP on 05/08/2024 10:08:22 (time step matched 0): False
[39;49m
I'm not understanding something from their doc or am I doing something wrong?
Please, some help about this would be worth.
Here you have dotnet fiddle: https://dotnetfiddle.net/A1dOEm
Edit: Now instances for generation and each validation are different so should be valid anytime. I want to accept only once but I would like to test that validation window is well defined. In this example, TOTP code generated today should be valid until 7 days ahead if I don't misunderstood something from documentation.
First of all, thanks to ralf comment above which is key.
As there a two times(creation,validation) here there might be a problem what previous/future means here.
Here you can find corrected fiddle with corrected VerificationWindow.
It was the opposite I understood before.
If you want your code to be valid from now to 7 days ahead, VerificationWindow must be 7 days past, not 7 days future.
using System;
using OtpNet;
byte[] secretKey = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP");
Totp totpGenerator = new Totp(secretKey);
// Generate TOTP code using the current time
DateTime generationTime = DateTime.Now;
string totpCode = totpGenerator.ComputeTotp();
Console.WriteLine($"TOTP generated on {generationTime}: {totpCode}");
// Test the validity of the TOTP code from 7 days in the past to 9 days in the future
for (var days = -7; days < 10; days++)
{
TestTotpValidity(totpCode, generationTime.AddDays(days));
}
void TestTotpValidity(string totpCode, DateTime verificationTime)
{
var validator = new Totp(secretKey);
long timeStepMatched;
// 2880 steps per day, window of 7 days in the past and 2 steps in the future
bool isValid = validator.VerifyTotp(verificationTime, totpCode, out timeStepMatched, new VerificationWindow(previous: 2880 * 7, future: 2));
Console.WriteLine($"Verifying TOTP on {verificationTime} (time step matched {timeStepMatched}): {isValid}");
}
TOTP generated on 05/16/2024 12:38:52: 065465
Verifying TOTP on 05/09/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/10/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/11/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/12/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/13/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/14/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/15/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/16/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/17/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/18/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/19/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/20/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/21/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/22/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/23/2024 12:38:52 (time step matched 57195437): True
Verifying TOTP on 05/24/2024 12:38:52 (time step matched 0): False
Verifying TOTP on 05/25/2024 12:38:52 (time step matched 0): False