When I was reviewing an application recently, I found a small piece of code that looked harmless at first. It was generating a six-digit OTP using C#’s Random() class.
The code worked. It generated a number. Everything looked fine.
But here’s the thing: it was not secure at all.
In login systems, password resets, or any feature where users depend on OTPs, the security of that number matters more than anything. So let’s break down the right way and wrong way to generate OTPs in C#.
![Secure OTP Generation in csharp]()
What Most Developers Do (But Shouldn’t)
A lot of people use this:
public int GenerateOTP()
{
Random rnd = new Random();
return rnd.Next(100000, 999999);
}
This looks simple, clean, and effective. But here’s the real problem:
✔ It’s NOT secure
✔ It’s predictable
✔ Attackers can guess the next OTP
C#’s Random() uses time-based seeds. If someone knows the approximate time your OTP was generated, they can recreate the same values. Even worse, if two OTPs generate within milliseconds, they might be identical.
This is why banks, fintech apps, and secure platforms never use Random() for OTPs.
The Right Way: RandomNumberGenerator (Secure)
Here’s how a secure OTP should be generated:
public int GenerateOTP()
{
byte[] bytes = new byte[4];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(bytes);
int num = Math.Abs(BitConverter.ToInt32(bytes, 0)) % 900000 + 100000;
return num;
}
Why this is better:
It is cryptographically secure
The OTP is not predictable
Attackers cannot reproduce or guess it
It follows the same principles used by banks, OTP services, and big tech companies
You get a truly random, secure six-digit code every time.
Why OTP Security Matters
Think of an OTP like a temporary password. If someone can guess it, predict it, or generate it through timing, then:
An OTP is often the last line of defense, so its randomness must be strong.
Random() vs RandomNumberGenerator: Simple Summary
| Feature | Random() | RandomNumberGenerator |
|---|
| Security | ❌ Not secure | ✔ Cryptographically secure |
| Predictability | High | Extremely low |
| Suitable for OTPs | No | Yes |
| Attack resistance | Weak | Strong |
| Based on | Time seed | Hardware-based entropy |
When Should You Use Random()?
Random() is still useful for:
Generating test data
Creating colors
Simulations
Games
But never for authentication, OTPs, tokens, or passwords.
Conclusion
I’ve seen this issue in so many applications now that it almost feels normal. Developers rush to build features and meet deadlines, and somewhere in the process, security gets ignored. It’s a good reminder of how easy it is to overlook safety in something as small as generating an OTP. Everything seems to work perfectly—until the day it doesn’t.
If you're building any user login, verification, or reset feature, make sure your OTP is generated using a secure method.
It takes the same amount of code, but gives you a lot more protection.
If you require any clarification/suggestions on the article, please leave your questions and thoughts in the comment section below. Follow C# Corner to learn more new and amazing things about .Net Core or to explore more technologies.
Thanks for reading, and I hope you like it.