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#的简单实现相关推荐

  1. TOTP 介绍及基于 C# 的简单实现

    TOTP 介绍及基于 C# 的简单实现 Intro TOTP 是基于时间的一次性密码生成算法,它由 RFC 6238 定义.和基于事件的一次性密码生成算法不同 HOTP,TOTP 是基于时间的,它和 ...

  2. springboot mysql行锁_SpringBoot基于数据库实现简单的分布式锁

    本文介绍SpringBoot基于数据库实现简单的分布式锁. 1.简介 分布式锁的方式有很多种,通常方案有: 基于mysql数据库 基于redis 基于ZooKeeper 网上的实现方式有很多,本文主要 ...

  3. mysql binlog update_mysql binlog 简单介绍与基于binlog数据恢复

    mysql binlog 简单介绍与基于binlog数据恢复 通过备份文件恢复 binlog(本节重点) binlog 二进制日志文件 show variables like 'log_bin'; 二 ...

  4. 基于Golang的简单web服务程序开发——CloudGo

    基于Golang的简单web服务程序开发--CloudGo[阅读时间:约10分钟] 一.概述 二.系统环境&项目介绍 1.系统环境 2.项目的任务要求 (1)基本要求 (2)扩展要求 三.具体 ...

  5. Microwindows及基于Nano-X的简单程序开发

    http://www.rdxx.com 05年09月13日 22:26 Blog.ChinaUnix.net Nano-X是一种图形编程接口,和Win32一样,在上面我们可以编写自己的应用程序,下面转 ...

  6. 基于RxJava2+Retrofit2简单易用的网络请求实现

    代码地址如下: http://www.demodashi.com/demo/13473.html 简介 基于RxJava2+Retrofit2实现简单易用的网络请求,结合android平台特性的网络封 ...

  7. iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)

    代码地址如下: http://www.demodashi.com/demo/11944.html 天道酬勤 前言 作为一名iOS开发者,每当使用APP的时候,总难免会情不自禁的去想想,这个怎么做的?该 ...

  8. 基于人人网的简单爬虫(一)——正则表达式

    应课程实验要求,要写一个基于人人网的简单爬虫.实验要求如下: 学会使用一种编程语言实现爬取人人网关系网络的程序.该程序功能如下: 1.  能够输入用户登陆所产生的cookie,允许爬虫对人人网进行爬取 ...

  9. python documents in chinese_基于 Python 的简单自然语言处理实践

    基于 Python 的简单自然语言处理 Twenty News Group 语料集处理 20 Newsgroup 数据集包含了约 20000 篇来自于不同的新闻组的文档,最早由 Ken Lang 搜集 ...

最新文章

  1. 动手使用ABAP Channel开发一些小工具,提升日常工作效率 1
  2. tkinter拦截关闭事件
  3. 对字符串数组中的M个字符串按长度由小到大进行排序
  4. [JoyOI] 1035 棋盘覆盖 (二分图匹配)
  5. 审计专业毕业论文有什么好写一点的论文选题吗?
  6. 手机双拼输入法下的智能纠错
  7. Matlab自定义颜色图
  8. java输入十个,键盘输入十个数,输出最大数
  9. 论Flutter开发如何改善套娃地狱问题
  10. 常用http请求解析
  11. ORBSLAM2论文翻译
  12. 墨者学院Tomcat 远程代码执行漏洞利用
  13. DeFi发币潮之下,散户真能赚到钱吗?
  14. C++ 类的简单使用
  15. 【BZOJ4802】【Pollard-Rho模板题】欧拉函数
  16. 【Java工具类】学会MVEL2.0,表达式解析再不怕
  17. CSS水平垂直居中的几种实现方式
  18. android微信支付都需要什么意思,Android开发微信APP支付功能的要点小结
  19. PSM倾向得分匹配法【python实操篇】
  20. c语言括号表示法画树怎么画,树的画法分类讲解

热门文章

  1. 佳文分享:CAP定理
  2. 解读 Oracle 12c 自适应执行计划一例
  3. oracle12c关闭pdb,oracle 12c pdb启动与关闭
  4. 【Vue实用功能】Vue实现tab页多页面切换
  5. 关于Python爬取热搜的另一种方法
  6. QtXlsx第三方库在Mac OS和Windows下的配置及简单使用
  7. PO(PageObject)模型
  8. 计算机网络方向研究课题,计算机网络安全技术方向论文选题 计算机网络安全技术论文题目如何定...
  9. 微信王者有ios的服务器吗,王者IOS微信区国服瑶多有钱?凌晨撒4W红包,点开头像傻眼...
  10. 从淘宝服务器IP地址服务获取IP地址信息的方法