Design

Design
asp.net mvc

2020年4月29日 星期三

[紀錄]HOTP TOTP計算邏輯

 
namespace OTP
{
    class Program
    {
        static void Main(string[] args)
        {
            //密鑰
            byte[] key = Encoding.ASCII.GetBytes("lnh_key");

            for (var i = 0; i < 100; i++)
            {
                //每十秒更變一次密碼
                var otp = TOTP(key, 10, 6);
                Console.WriteLine(otp);
                Thread.Sleep(1000);
            }
        }
        


        public static string HOTP(byte[] key, byte[] counter, int length = 6)
        {
          
            var hmac = ToHMACSHA1(counter, key);

            var offset = hmac[hmac.Length - 1] & 0xF;
           
            var b1 = (hmac[offset] & 0x7F) << 24;
            var b2 = (hmac[offset + 1] & 0xFF) << 16;
            var b3 = (hmac[offset + 2] & 0xFF) << 8;
            var b4 = (hmac[offset + 3] & 0xFF);

            var code = b1 | b2 | b3 | b4;

            var value = code % (int)Math.Pow(10, length);

            return value.ToString().PadLeft(length, '0');
        }


        public static string TOTP(byte[] key, int step = 60, int length = 6)
        {
            var unixTime = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
            var counter = ((int)unixTime) / step;
            var counterBytes = BitConverter.GetBytes(counter);
            return HOTP(key, counterBytes, length);
        }


        public static byte[] ToHMACSHA1(byte[] value, byte[] key)
        {
            if (value == null || value.Length == 0)
            {
                throw new ArgumentNullException(nameof(value));
            }
            if (key == null || key.Length == 0)
            {
                throw new ArgumentNullException(nameof(key));
            }
            using (var macAlgorithm = new HMACSHA1())
            {
                macAlgorithm.Key = key;
                return macAlgorithm.ComputeHash(value);
            }
        }

    }

}