TOTP 介绍及基于C#的简单实现
生活随笔
收集整理的這篇文章主要介紹了
TOTP 介绍及基于C#的简单实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
TOTP 介紹及基于C#的簡單實現
Intro
TOTP 是基于時間的一次性密碼生成算法,它由?RFC 6238?定義。和基于事件的一次性密碼生成算法不同?HOTP,TOTP 是基于時間的,它和 HOTP 具有如下關系:
TOTP = HOTP(K, T) HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))其中:
- T:T = (Current Unix time - T0) / X, T0 = 0,X = 30
- K:客戶端和服務端的共享密鑰,不同的客戶端的密鑰各不相同。
- HOTP:該算法請參考 RFC,也可參考?理解 HMAC-Based One-Time Password Algorithm
TOTP 算法是基于 HOTP 的,對于 HOTP 算法來說,HOTP 的輸入一致時始終輸出相同的值,而 TOTP 是基于時間來算出來的一個值,可以在一段時間內(官方推薦是30s)保證這個值是固定以實現,在一段時間內始終是同一個值,以此來達到基于時間的一次性密碼生成算法,使用下來整體還不錯,有個小問題,如果需要實現一個密碼只能驗證一次需要自己在業務邏輯里實現,只能自己實現,TOTP 只負責生成和驗證。
C# 實現 TOTP
實現代碼
using System; using System.Security.Cryptography; using System.Text;namespace WeihanLi.Totp {public class Totp{private readonly OtpHashAlgorithm _hashAlgorithm;private readonly int _codeSize;public Totp() : this(OtpHashAlgorithm.SHA1, 6){}public Totp(OtpHashAlgorithm otpHashAlgorithm, int codeSize){_hashAlgorithm = otpHashAlgorithm;// valid input parameterif (codeSize <= 0 || codeSize > 10){throw new ArgumentOutOfRangeException(nameof(codeSize), codeSize, "length must between 1 and 9");}_codeSize = codeSize;}private static readonly Encoding Encoding = new UTF8Encoding(false, true);public virtual string Compute(string securityToken) => Compute(Encoding.GetBytes(securityToken));public virtual string Compute(byte[] securityToken) => Compute(securityToken, GetCurrentTimeStepNumber());private string Compute(byte[] securityToken, long counter){HMAC hmac;switch (_hashAlgorithm){case OtpHashAlgorithm.SHA1:hmac = new HMACSHA1(securityToken);break;case OtpHashAlgorithm.SHA256:hmac = new HMACSHA256(securityToken);break;case OtpHashAlgorithm.SHA512:hmac = new HMACSHA512(securityToken);break;default:throw new ArgumentOutOfRangeException(nameof(_hashAlgorithm), _hashAlgorithm, null);}using (hmac){var stepBytes = BitConverter.GetBytes(counter);if (BitConverter.IsLittleEndian){Array.Reverse(stepBytes); // need BigEndian}// See https://tools.ietf.org/html/rfc4226var hashResult = hmac.ComputeHash(stepBytes);var offset = hashResult[hashResult.Length - 1] & 0xf;var p = "";for (var i = 0; i < 4; i++){p += hashResult[offset + i].ToString("X2");}var num = Convert.ToInt64(p, 16) & 0x7FFFFFFF;//var binaryCode = (hashResult[offset] & 0x7f) << 24// | (hashResult[offset + 1] & 0xff) << 16// | (hashResult[offset + 2] & 0xff) << 8// | (hashResult[offset + 3] & 0xff);return (num % (int)Math.Pow(10, _codeSize)).ToString();}}public virtual bool Verify(string securityToken, string code) => Verify(Encoding.GetBytes(securityToken), code);public virtual bool Verify(string securityToken, string code, TimeSpan timeToleration) => Verify(Encoding.GetBytes(securityToken), code, timeToleration);public virtual bool Verify(byte[] securityToken, string code) => Verify(securityToken, code, TimeSpan.Zero);public virtual bool Verify(byte[] securityToken, string code, TimeSpan timeToleration){var futureStep = (int)(timeToleration.TotalSeconds / 30);var step = GetCurrentTimeStepNumber();for (int i = -futureStep; i <= futureStep; i++){if (step + i < 0){continue;}var totp = Compute(securityToken, step + i);if (totp == code){return true;}}return false;}private static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);/// <summary>/// timestep/// 30s(Recommend)/// </summary>private static readonly long _timeStepTicks = TimeSpan.TicksPerSecond * 30;// More info: https://tools.ietf.org/html/rfc6238#section-4private static long GetCurrentTimeStepNumber(){var delta = DateTime.UtcNow - _unixEpoch;return delta.Ticks / _timeStepTicks;}} }使用方式:
var otp = new Totp(OtpHashAlgorithm.SHA1, 4); // 使用 SHA1算法,輸出4位var secretKey = "12345678901234567890";var output = otp.Compute(secretKey);Console.WriteLine($"output: {output}");Thread.Sleep(1000 * 30);var verifyResult = otp.Verify(secretKey, output); // 使用默認的驗證方式,30s內有效Console.WriteLine($"Verify result: {verifyResult}");verifyResult = otp.Verify(secretKey, output, TimeSpan.FromSeconds(60)); // 指定可容忍的時間差,60s內有效Console.WriteLine($"Verify result: {verifyResult}");輸出示例:
Reference
- https://tools.ietf.org/html/rfc4226
- https://tools.ietf.org/html/rfc6238
- http://wsfdl.com/algorithm/2016/04/05/%E7%90%86%E8%A7%A3HOTP.html
- http://wsfdl.com/algorithm/2016/04/14/%E7%90%86%E8%A7%A3TOTP.html
- https://www.cnblogs.com/voipman/p/6216328.html
轉載于:https://www.cnblogs.com/weihanli/p/simple-implement-on-totp-via-csharp.html
總結
以上是生活随笔為你收集整理的TOTP 介绍及基于C#的简单实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS多线程理解告别生硬
- 下一篇: 中国兰花怎么养 中国兰花养殖方法及注意事