Home > Net >  What is a way to generate OTP 6-digit pin in C# .NET WCF? (without using Random())
What is a way to generate OTP 6-digit pin in C# .NET WCF? (without using Random())

Time:11-14

I would like to generate an OTP 6-digit pin in my C# .NET Application. However, for security reasons, I heard that using the Random() package to perform this action might not be the most appropriate. Are there any other methods available?

CodePudding user response:

One way to generate a 6-digit OTP is to use a cryptographically secure pseudorandom number generator (CSPRNG). A CSPRNG is a random number generator that is designed to be resistant to attackers trying to predict the numbers that will be generated.

One popular CSPRNG is the Microsoft Cryptographic Service Provider (CSP) Random Number Generator. To use this CSPRNG, you can call the System.Security.Cryptography.RNGCryptoServiceProvider.GetBytes method, passing in the number of bytes you want to generate. This method will return an array of bytes, which you can then convert into a 6-digit string by taking the first 6 bytes and converting them to hexadecimal.

Another option is to use the System.Random class, but you should only do this if you are sure that the seed value you are using is truly random and cannot be predicted by an attacker.

CodePudding user response:

You definitely want to use something in the System.Security.Cryptography namespace if you want something more secure than System.Random.

Here's a handy implementation written by Eric Lippert in his fabulous Fixing Random series.

public static class BetterRandom
{
    private static readonly ThreadLocal<System.Security.Cryptography.RandomNumberGenerator> crng = new ThreadLocal<System.Security.Cryptography.RandomNumberGenerator>(System.Security.Cryptography.RandomNumberGenerator.Create);
    private static readonly ThreadLocal<byte[]> bytes = new ThreadLocal<byte[]>(() => new byte[sizeof(int)]);
    public static int NextInt()
    {
        crng.Value.GetBytes(bytes.Value);
        return BitConverter.ToInt32(bytes.Value, 0) & int.MaxValue;
    }
    public static double NextDouble()
    {
        while (true)
        {
            long x = NextInt() & 0x001FFFFF;
            x <<= 31;
            x |= (long)NextInt();
            double n = x;
            const double d = 1L << 52;
            double q = n / d;
            if (q != 1.0)
                return q;
        }
    }
}

Now you can easily create a OTP string:

string otp = (BetterRandom.NextInt() % 1000000).ToString("000000");

CodePudding user response:

This worked for me:

 public static string GetRandomOneTimePin()
{
    char[] chars = new char[10];
    chars = "1234567890".ToCharArray();
    byte[] data = new byte[1];
    using(var crypto = RandomNumberGenerator.Create())
    {
        crypto.GetNonZeroBytes(data);
        data = new byte[6];
        crypto.GetNonZeroBytes(data);
    }

    StringBuilder result = new StringBuilder(6);
    foreach(byte b in data)
    {
        result.Append(chars[b % (chars.Length)]);
    }

    return result.ToString();
}

Would however recommend to have the OTP assigned to the specific destination, ie. cellphone number/email, which you can do extra validation on. Then also have a short expiry assigned to the OTP.

  • Related