using System; using System.Security.Cryptography; using vendorApproverBackend.Interfaces; public class OtpGenerate : IOtpGenerate { private const int OTP_LENGTH = 4; private const string OTP_NUMBERS_NON_ZERO = "123456789"; private static readonly string OTP_NUMBERS = "0" + OTP_NUMBERS_NON_ZERO; public string GetOtpCode(string key) { if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("key must not be empty", nameof(key)); return BuildOtp(); } private string BuildOtp() { Span buffer = stackalloc char[OTP_LENGTH]; var numbers = OTP_NUMBERS; using (var rng = RandomNumberGenerator.Create()) { for (int i = 0; i < OTP_LENGTH; i++) { var r = GetInt(rng, numbers.Length); buffer[i] = numbers[r]; } } var otp = new string(buffer); if (otp.StartsWith("0")) { char nonZero; using (var rng = RandomNumberGenerator.Create()) { nonZero = OTP_NUMBERS_NON_ZERO[GetInt(rng, OTP_NUMBERS_NON_ZERO.Length)]; } otp = nonZero + otp.Substring(1); } return otp; } private static int GetInt(RandomNumberGenerator rng, int maxExclusive) { if (maxExclusive <= 0) throw new ArgumentOutOfRangeException(nameof(maxExclusive)); var bytes = new byte[4]; int value; do { rng.GetBytes(bytes); value = BitConverter.ToInt32(bytes, 0) & int.MaxValue; } while (value >= (int.MaxValue - ((int.MaxValue % maxExclusive) + 1))); return value % maxExclusive; } }