Securing .NET Applications with mOTP (Mobile One-Time Password)
Two-Factor Authentication (2FA) is a mandatory requirement for modern enterprise applications. While Time-Based One-Time Password (TOTP) systems like Google Authenticator dominate the consumer market, the Mobile One-Time Password (mOTP) protocol remains a highly efficient, open-source alternative for custom infrastructure.
Implementing mOTP in the .NET ecosystem provides a lightweight, highly secure mechanism to safeguard user accounts without relying on proprietary third-party libraries or external paid APIs. What is mOTP?
The mOTP protocol is an open standard designed for creating cryptographically secure, time-synchronized one-time passwords on mobile devices. It differs slightly from standard RFC 6238 (TOTP) in its algorithm footprint and formatting. Core Components of mOTP Secret PIN: A numeric code known only to the user.
Secret Seed: A unique 16-character hexadecimal string shared between the server and the client app.
Epoch Time: The current Unix timestamp, rounded down to the nearest 10-second interval. How mOTP Works Under the Hood
The mOTP algorithm combines simplicity with strong cryptographic primitives.
Time Windowing: The current Unix epoch time in seconds is divided by 10. The resulting integer is converted to a string.
String Concatenation: The system concatenates the time string, the secret seed, and the user’s secret PIN.
MD5 Hashing: The concatenated string is hashed using the MD5 algorithm.
Trimming: The system extracts the first 6 characters of the resulting hexadecimal hash to create the final 6-digit OTP. Implementing mOTP in .NET
Implementing mOTP in native .NET requires no external dependencies beyond the standard System.Security.Cryptography namespace. Below is a production-ready implementation written in C#.
using System; using System.Security.Cryptography; using System.Text; public class MOtpAuthenticator { ///
public static string GenerateToken(string seed, string pin, DateTime utcTime) { // 1. Get Unix timestamp and divide by 10 for the 10-second window long unixTime = ((DateTimeOffset)utcTime).ToUnixTimeSeconds(); long timeWindow = unixTime / 10; // 2. Concatenate Time + Seed + PIN string inputString = $“{timeWindow}{seed}{pin}”; // 3. Compute MD5 Hash using (MD5 md5 = MD5.Create()) { byte[] inputBytes = Encoding.UTF8.GetBytes(inputString); byte[] hashBytes = md5.ComputeHash(inputBytes); // Convert hash bytes to a lowercase hex string StringBuilder sb = new StringBuilder(); foreach (byte b in hashBytes) { sb.Append(b.ToString(“x2”)); } // 4. Return the first 6 characters as the token return sb.ToString().Substring(0, 6); } } ///
public static bool ValidateToken(string seed, string pin, string providedToken, int windowSizeInSeconds = 30) { DateTime now = DateTime.UtcNow; // Account for network delay or minor device clock drift for (int i = -windowSizeInSeconds; i <= windowSizeInSeconds; i += 10) { DateTime checkTime = now.AddSeconds(i); string calculatedToken = GenerateToken(seed, pin, checkTime); if (string.Equals(calculatedToken, providedToken, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } Use code with caution. Integrating mOTP into ASP.NET Core Identity
To integrate this engine into a modern ASP.NET Core web app or API, you can wrap the logic inside a custom TwoFactorTokenProvider.
using Microsoft.AspNetCore.Identity; using System.Threading.Tasks; public class MOtpTokenProvider Use code with caution. Register the custom provider in your Program.cs file:
builder.Services.AddIdentity() .AddEntityFrameworkStores Use code with caution. Best Practices for Production Deployment 1. Secure Seed Storage
Never store mOTP seeds in plaintext. If an attacker gains read access to your database, they can compromise all user accounts. Encrypt seeds using a robust encryption standard like AES-256 before writing them to the database. 2. Implement Clock Drift Management
Mobile device clocks can drift out of sync with network time. The verification logic should check the current 10-second time window as well as the immediate preceding and succeeding windows to minimize false login rejections. 3. Prevent Replay Attacks
Once a token is successfully verified, flag that specific 10-second time window as “used” for that user id. Reject any subsequent validation attempts within that same window to block interception and replay attacks. Conclusion
Implementing mOTP in .NET offers an incredibly lightweight footprint for developers who want straightforward, offline, open-standard multi-factor authentication. By writing a native handler in C#, you avoid external licensing constraints while keeping full architectural control over your application’s security pipeline.
To help refine this implementation for your specific architecture, tell me: What version of .NET are you using for this project?
Do you intend to use this with an existing authentication framework (like ASP.NET Core Identity or Duende IdentityServer)?
Leave a Reply