Hi kannabrindava...,
I have verified the code and i didn't find any issue with the code.
Please follow the below steps to create the 2 factor authentication and validate the otp using Microsoft Authenticator App.
Install OtpSharp and QRCoder Libraries
First install the OtpSharp and QRCoder library using the following commands from Nuget.
Install-Package OtpSharp.Core -Version 1.0.0
Install-Package QRCoder -Version 1.5.1
HTML
The HTML Markup consists of following controls.
Image - For generate and display QRCode image.
TextBox - For entering the OTP.
Button - For validating the OTP entered in the TextBox.
Label - For displaying the message.
<asp:Image ID="imgQRCode" runat="server" Width="200" Height="200" />
<br />
<asp:Label ID="lblsecretKey" runat="server" Style="display: none"></asp:Label>
<br />
<asp:TextBox ID="txtOTP" runat="server" placeholder="Enter OTP"></asp:TextBox>
<asp:Button ID="btnValidate" runat="server" Text="Validate OTP" OnClick="btnValidate_Click" />
<br />
<asp:Label ID="lblOTPValidation" runat="server" Text=""></asp:Label>
Namespaces
Inherit the following namespaces.
using System.IO;
using System.Text;
using System.Drawing;
using System.Security.Cryptography;
using OtpSharp;
using QRCoder;
Code
private string secretKey;
private OtpHashMode HashType { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
HashType = OtpHashMode.Sha1;
// Generate a random secret key if it's not already generated
if (string.IsNullOrEmpty(secretKey))
{
secretKey = GenerateRandomKey(20);
// Store the secret key securely for later use
}
string encodedSecretKey = ToBase32String(Encoding.UTF8.GetBytes(secretKey));
lblsecretKey.Text = secretKey;
string issuer = "PAOTPAdmin";
string account = "abc@yahoo.com";
string encodedIssuer = HttpUtility.UrlEncode(issuer);
string encodedAccount = HttpUtility.UrlEncode(account);
string otpAuthUri = $"otpauth://totp/{issuer}:{account}?secret={encodedSecretKey.Trim('=')}&{secretKey}&issuer={encodedIssuer}{(HashType == OtpHashMode.Sha1 ? "" : $"&algorithm={HashType}")}";
// Generate the QR code image
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode(otpAuthUri, QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData);
Bitmap qrCodeImage = qrCode.GetGraphic(20);
// Convert the QR code image to a byte array
using (MemoryStream stream = new MemoryStream())
{
qrCodeImage.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
byte[] imageBytes = stream.ToArray();
string base64String = Convert.ToBase64String(imageBytes);
// Display the QR code
imgQRCode.ImageUrl = "data:image/png;base64," + base64String;
}
}
}
protected void btnValidate_Click(object sender, EventArgs e)
{
secretKey = lblsecretKey.Text;
byte[] secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
string otpEnteredByUser = txtOTP.Text.Trim();
// Validate the OTP
Totp totp = new Totp(secretKeyBytes, step: 30, mode: OtpHashMode.Sha1, totpSize: 6);
//var topt = totp.ComputeTotp();
bool isValid = totp.VerifyTotp(otpEnteredByUser, out long timeStepMatched, null);
// Display the validation result
lblOTPValidation.Text = isValid ? "OTP is valid" : "OTP is invalid";
}
private string GenerateRandomKey(int length)
{
using (var rng = new RNGCryptoServiceProvider())
{
byte[] key = new byte[length];
rng.GetBytes(key);
return Convert.ToBase64String(key);
}
}
public byte[] ConvertStringToByteArray(string secretKey)
{
// Convert the string to a byte array using UTF-8 encoding
byte[] byteArray = Encoding.UTF8.GetBytes(secretKey);
return byteArray;
}
private static string ToBase32String(byte[] data)
{
const string base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; // Base32 character set
StringBuilder result = new StringBuilder((data.Length * 8 + 4) / 5);
int buffer = data[0];
int next = 1;
int bitsLeft = 8;
while (bitsLeft > 0 || next < data.Length)
{
if (bitsLeft < 5)
{
if (next < data.Length)
{
buffer <<= 8;
buffer |= data[next++] & 0xFF;
bitsLeft += 8;
}
else
{
int pad = 5 - bitsLeft;
buffer <<= pad;
bitsLeft += pad;
}
}
int index = 0x1F & (buffer >> (bitsLeft - 5));
bitsLeft -= 5;
result.Append(base32Chars[index]);
}
return result.ToString();
}
Now, run the project and open the Microsoft Authenticator app.
Scan the generated QRCode using the Other account in the Add account window.
Then open the added account and test the generated One-time password code.
Screenshot